1# 2# CDDL HEADER START 3# 4# The contents of this file are subject to the terms of the 5# Common Development and Distribution License (the "License"). 6# You may not use this file except in compliance with the License. 7# 8# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9# or http://www.opensolaris.org/os/licensing. 10# See the License for the specific language governing permissions 11# and limitations under the License. 12# 13# When distributing Covered Code, include this CDDL HEADER in each 14# file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15# If applicable, add the following below this CDDL HEADER, with the 16# fields enclosed by brackets "[]" replaced with your own identifying 17# information: Portions Copyright [yyyy] [name of copyright owner] 18# 19# CDDL HEADER END 20# 21# 22# Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23# Use is subject to license terms. 24# 25#pragma ident "%Z%%M% %I% %E% SMI" 26 27########### 28## 29## Standard printer interface program. 30########### 31 32##### 33# 34# Until we get to the point below where the printer port 35# and physical printer are initialized, we can't do much 36# except exit if the Spooler/Scheduler cancels us. 37##### 38trap 'exit' 15 39 40##### 41# 42# We can be clever about getting a hangup or interrupt, though, at least 43# until the filter runs. Do this early, even though $LPTELL 44# isn't defined, so that we're covered. 45##### 46catch_hangup () { 47 if [ -n "${LPTELL}" ] 48 then 49 echo \ 50"The connection to the printer dropped; perhaps the printer went off-line?" \ 51 | ${LPTELL} ${printer} 52 fi 53 return 0 54} 55catch_interrupt () { 56 if [ -n "${LPTELL}" ] 57 then 58 echo \ 59"Received an interrupt from the printer. The reason is unknown, 60although a common cause is that the baud rate is too high." \ 61 | ${LPTELL} ${printer} 62 fi 63 return 0 64} 65trap 'catch_hangup; exit_code=129 exit 129' 1 66trap 'catch_interrupt; exit_code=129 exit 129' 2 3 67 68##### 69# 70# Most of the time we don't want the standard error to be captured 71# by the Spooler, mainly to avoid "Terminated" messages that the 72# shell puts out when we get a SIGTERM. We'll save the standard 73# error channel under another number, so we can use it when it 74# should be captured. 75# 76# Open another channel to the printer port, for use when the 77# regular standard output won't be directed there, such as in 78# command substitution (`cmd`). 79##### 80exec 5>&2 2>/dev/null 3>&1 81 82##### 83# 84# Set some globally used variables and functions. 85##### 86 87: ${TMPDIR:=/tmp} 88: ${SPOOLDIR:=/usr/spool/lp} 89: ${TERMINFO:=/usr/lib/terminfo} 90: ${CHARSETDIR:=/usr/lib/charsets} 91 92: ${LOCALPATH:=${SPOOLDIR}/bin} 93PATH="/bin:/usr/bin:${LOCALPATH}" 94 95MAX_COLS_SMALL_BANNER=40 96 97##### 98# 99# On the 3.2 release of the 386unix product, the parallel port does 100# not support any ioctl calls. As a result, we cannot set the opost 101# and onlcr attributes to have <NL>'s expanded to <CR><NL>. This 102# "filter" gets the job done for us. 103##### 104: ${FIX386BD:=${LOCALPATH}/386parallel} 105if [ -n "${FIX386BD}" -a -x "${FIX386BD}" ] 106then 107 FIX386BD="| ${FIX386BD}" 108else 109 FIX386BD="" 110fi 111 112##### 113# Use ${TMPPREFIX} as the prefix for all temporary files, so 114# that cleanup is easy. The prefix may be up to 13 characters 115# long, so you only have space for one more character to make 116# a file name. If necessary, make a directory using this prefix 117# for better management of unique temporary file names. 118##### 119TMPPREFIX=${TMPDIR}/`uname -n`$$ 120 121##### 122# Before exiting, set ${exit_code} to the value with which to exit. 123# Otherwise, the exit from this script will be 0. 124##### 125trap 'rm -fr ${TMPPREFIX}*; exit ${exit_code}' 0 126 127##### 128# ${LPTELL} is the name of a program that will send its 129# standard input to the Spooler. It is used to forward 130# the description of a printer fault to the Spooler, 131# which uses it in an alert to the administrator. 132##### 133if [ ! -x "${LPTELL:=${LOCALPATH}/lp.tell}" ] 134then 135 fake_lptell () { 136 header="no" 137 while read line 138 do 139 if [ "no" = "${header}" ] 140 then 141 errmsg ERROR ${E_IP_UNKNOWN} \ 142 "unknown printer/interface failure" \ 143 "consult your system administrator; 144 reasons for failure (if any) follow:" 145 header=yes 146 fi 147 echo "${line}" >&2 148 done 149 return 1 150 } 151 LPTELL=fake_lptell 152fi 153 154##### 155# ${DRAIN} is the name of a program that will wait 156# long enough for data sent to the printer to print. 157##### 158if [ -x "${LOCALPATH}/drain.output" ] 159then 160 DRAIN="${LOCALPATH}/drain.output 5" # wait only five seconds 161else 162 DRAIN= 163fi 164 165##### 166# ${LPTSOLSEPARATOR} is the name of a program to put banner and trailer 167# pages around the job. 168##### 169if [ -x ${LOCALPATH}/lp.tsol_separator ] 170then 171 LPTSOLSEPARATOR=${LOCALPATH}/lp.tsol_separator 172else 173 echo "${LOCALPATH}/lp.tsol_separator not found." >&2 174 exit 1 175fi 176 177##### 178# ${LPCAT} is the name of a program to use as a default 179# filter. Minimally it should copy its standard input to 180# the standard output, but it should also trap printer 181# faults. The current LPCAT traps hangups (DCD dropping, SIGHUP), 182# interrupts (SIGINT, SIGQUIT), broken pipe (SIGPIPE), and 183# excess delays in sending data to the printer, interpreting all 184# as printer faults. 185##### 186if [ ! -x "${LPCAT:=${LOCALPATH}/lp.cat}" ] 187then 188 LPCAT="cat" 189fi 190 191##### 192# ${LPSET} is the name of a program that will set the 193# character pitch, line pitch, page width, page length, 194# and character set. It helps to have this in a single 195# binary program so that (1) it's faster than calls 196# to "tput"; and (2) it can access the new Terminfo 197# capabilities for printers (on pre SVR3.2 machines, tput can't). 198##### 199if [ ! -x "${LPSET:=${LOCALPATH}/lp.set}" ] 200then 201 fake_lpset () { 202 echo H V W L S >&2 203 false 204 } 205 LPSET=fake_lpset 206fi 207 208internal_lpset () { 209 ##### 210 # 211 # The funny business with the "2>&1 1>&3" is to let us capture 212 # the standard ERROR, not the standard OUTPUT as is the usual case 213 # with foo=`cmd`. The standard output will go to the printer. 214 ##### 215 [ -n "${stty1}" ] && stty ${stty1} 0<&1 216 chk=`${LPSET} "$1" "$2" "$3" "$4" "$5" 2>&1 1>&3` 217 [ -n "${stty2}" ] && stty ${stty2} 0<&1 218 219 ##### 220 # 221 # The standard error of the delivered ${LPSET} program 222 # is a string of letters, H, V, W, L, S, which correspond 223 # to cpi, lpi, width, length, and character set. A letter 224 # is present only if the corresponding attribute could not 225 # be set. 226 ##### 227 for err in ${chk} 228 do 229 case ${err} in 230 H ) 231 errmsg WARNING ${E_IP_BADCPI} \ 232 "can't select the character pitch \"${cpi}\"" \ 233 "check the valid pitches for the printer, 234 or consult your system administrator; 235 printing continues" 236 ;; 237 V ) 238 errmsg WARNING ${E_IP_BADLPI} \ 239 "can't select the line pitch \"${lpi}\"" \ 240 "check the valid pitches for the printer, 241 or consult your system administrator; 242 printing continues" 243 ;; 244 W ) 245 width=${cols} 246 errmsg WARNING ${E_IP_BADWIDTH} \ 247 "can't select the page width \"${width}\"" \ 248 "check the valid widths for the printer, 249 or consult your system administrator; 250 printing continues" 251 ;; 252 L ) 253 length=${lines} 254 errmsg WARNING ${E_IP_BADLENGTH} \ 255 "can't select the page length \"${length}\"" \ 256 "check the valid lengths for the printer, 257 or consult your system administrator; 258 printing continues" 259 ;; 260 S ) 261 errmsg WARNING ${E_IP_BADCHARSET} \ 262 "can't select the character set \"${CHARSET}\"" \ 263 "check the name given in the -S option, 264 or consult your system administrator; 265 printing continues" 266 ;; 267 esac 268 done 269} 270 271 272##### 273# ${TPUT} is "tput" IF it works. We'll disable it if we get an 274# ugly error message the first time we use it. See the TERM variable 275# later in the script. 276# 277# NOTE: The check we use to see if "tput" works is to use an OLD 278# Terminfo capability, like "lines". If it works with that it may 279# still fail with some of the newer capabilities like "init" (SVR3.0) 280# or "swidm" (SVR3.2), because the version of "tput" we have on your 281# machine is older. Thus, on some of the code where ${TPUT} is used 282# you'll see "2>/dev/null" being used to avoid ugly error messages. 283##### 284TPUT=tput 285 286##### 287# Error message formatter: 288# 289# Invoke as 290# 291# errmsg severity message-number problem help 292# 293# where severity is "ERROR" or "WARNING", message-number is 294# a unique identifier, problem is a short description of the 295# problem, and help is a short suggestion for fixing the problem. 296##### 297 298LP_ERR_LABEL="UX:lp" 299 300E_IP_ARGS=1 301E_IP_OPTS=2 302#E_IP_FILTER=3 303E_IP_STTY=4 304E_IP_UNKNOWN=5 305E_IP_BADFILE=6 306E_IP_BADCHARSET=7 307E_IP_BADCPI=8 308E_IP_BADLPI=9 309E_IP_BADWIDTH=10 310E_IP_BADLENGTH=11 311E_IP_ERRORS=12 # (in slow.filter) 312 313errmsg () { 314 case $1 in 315 ERROR ) 316 sev=" ERROR"; 317 ;; 318 WARNING ) 319 sev="WARNING"; 320 ;; 321 esac 322# tag=`expr "${LP_ERR_LABEL}" : "\(.*\):"``expr "${LP_ERR_LABEL}" : ".*:\(.*\)"` 323 echo "${LP_ERR_LABEL}: ${sev}: $3 324 TO FIX: $4" >&5 325} 326 327 328########### 329## 330## Check arguments 331########### 332 333parse () { 334 echo "`expr \"$1\" : \"^[^=]*=\(.*\)\"`" 335} 336 337##### 338# 339# This program is invoked as 340# 341# ${SPOOLDIR}/.../printer request-id user title copies options files... 342# 343# The first three arguments are simply reprinted on the banner page, 344# the fourth (copies) is used to control the number of copies to print, 345# the fifth (options) is a blank separated list (in a single argument) 346# of user or Spooler supplied options (without the -o prefix), 347# and the last arguments are the files to print. 348##### 349 350if [ $# -lt 5 ] 351then 352 errmsg ERROR ${E_IP_ARGS} \ 353 "wrong number of arguments to interface program" \ 354 "consult your system administrator" 355 exit 1 356fi 357 358printer=`basename $0` 359request_id=$1 360user_name=$2 361title=$3 362copies=$4 363option_list=$5 364 365shift 5 366files="$*" 367 368nobanner="no" 369nofilebreak="no" 370nolabels="no" 371stty= 372 373inlist= 374for i in ${option_list} 375do 376 case "${inlist}${i}" in 377 378 379 nobanner ) 380 nobanner="yes" 381 ;; 382 383 nofilebreak ) 384 nofilebreak="yes" 385 ;; 386 387 nolabels ) 388 nolabels="yes" 389 ;; 390 391 ##### 392 # 393 # If you want to add simple options (e.g. -o simple) 394 # identify them here. 395 ##### 396# simple ) 397# simple="yes" 398# ;; 399 400 401 cpi=pica ) 402 cpi=10 403 ;; 404 cpi=elite ) 405 cpi=12 406 ;; 407 cpi=* ) 408 cpi=`parse ${i}` 409 ;; 410 411 lpi=* ) 412 lpi=`parse ${i}` 413 ;; 414 415 length=* ) 416 length=`parse ${i}` 417 ;; 418 419 width=* ) 420 width=`parse ${i}` 421 ;; 422 423 ##### 424 # 425 # If you want to add simple-value options (e.g. -o value=a) 426 # identify them here. 427 ##### 428# value=* ) 429# value=`parse ${i}` 430# ;; 431 432 433 ##### 434 # 435 # If you want to add options that, like "stty", 436 # take a list (e.g. -o lopt='a b c'), identify 437 # them here and below (look for LOPT). 438 ##### 439 stty=* | flist=* | lpd=* ) 440#LOPT stty=* | flist=* | lpd=* | lopt=* ) 441 442 inlist=`expr "${inlist}${i}" : "^\([^=]*=\)"` 443 case "${i}" in 444 ${inlist}\'*\' ) 445 item=`expr "${i}" : "^[^=]*='*\(.*\)'\$"` 446 ;; 447 ${inlist}\' ) 448 continue 449 ;; 450 ${inlist}\'* ) 451 item=`expr "${i}" : "^[^=]*='*\(.*\)\$"` 452 ;; 453 ${inlist}* ) 454 item=`expr "${i}" : "^[^=]*=\(.*\)\$"` 455 ;; 456 *\' ) 457 item=`expr "${i}" : "^\(.*\)'\$"` 458 ;; 459 * ) 460 item="${i}" 461 ;; 462 esac 463 464 ##### 465 # 466 # We don't dare use "eval" because a clever user could 467 # put something in an option value that we'd end up 468 # exec'ing. 469 ##### 470 case "${inlist}" in 471 stty= ) 472 stty="${stty} ${item}" 473 ;; 474 flist= ) 475 flist="${flist} ${item}" 476 ;; 477 lpd= ) 478 lpd="${lpd} ${item}" 479 ;; 480#LOPT lopt= ) 481#LOPT lopt="${lopt} ${item}" 482#LOPT ;; 483 esac 484 485 case "${i}" in 486 ${inlist}\'*\' ) 487 inlist= 488 ;; 489 ${inlist}\'* ) 490 ;; 491 *\' | ${inlist}* ) 492 inlist= 493 ;; 494 esac 495 ;; 496 497 * ) 498 errmsg WARNING ${E_IP_OPTS} \ 499 "unrecognized \"-o ${i}\" option" \ 500 "check the option, resubmit if necessary 501 printing continues" 502 ;; 503 esac 504done 505 506##### 507# 508# Additional ``parameters'' are passed via Shell environment 509# variables: 510# 511# TERM The printer type (used for Terminfo access) 512# CHARSET The character set to choose 513# FILTER The filter to run 514##### 515 516##### 517# Set defaults for unset variables. 518##### 519 520: ${TERM:=unknown} 521tput lines 1>/dev/null 2>&1 || TPUT=: 522 523: ${CHARSET:=cs0} 524 525if [ -z "${FILTER}" ] 526then 527 ##### 528 # 529 # If no filter is being used, we have a little routine that 530 # will push the data to the printer. It traps hangups (loss 531 # of carrier) and checks for excessive delays in sending the 532 # data to the printer. The lesser of the print rate of the printer 533 # (obtained from Terminfo) or the baud rate is used to compute 534 # the expected delay. If neither of these is correct, you 535 # may be experiencing false alarms. If so, give the correct 536 # rate, in characters per second, as a single argument. 537 # An argument of 0 means don't check for delays. 538 # Give an -r option to get a printout of actual delays. 539 # (QUOTES ARE IMPORTANT!) 540 ##### 541 case "$TERM" in 542 PS ) 543 # make the "postscript" printers use postio to 544 # talk to the printer and periodically get a 545 # status from them 546 FILTER="/usr/lib/lp/postscript/postio" 547 ;; 548 PSR ) 549 # make the "reverse postscript" printers reverse the 550 # output and the use postio to talk to the printer 551 FILTER="/usr/lib/lp/postscript/postreverse | \ 552 /usr/lib/lp/postscript/postio" 553 ;; 554 * ) 555 # we don't know the type, so just assume that the 556 # input and output are the same 557 if [ `basename "${LPCAT}"` = "lp.cat" ] ; then 558 FILTER="${LPCAT} 0" # infinite delays 559 # FILTER="${LPCAT} 120" # e.g. 120 CPS 560 # FILTER="${LPCAT} -r 0 2>/tmp/delays" 561 # FILTER=${LPCAT} 562 fi 563 ;; 564 esac 565fi 566 567########### 568## 569## Initialize the printer port 570########### 571 572##### 573# 574# SERIAL PORTS: 575# Initialize everything. 576# 577# PARALLEL PORTS: 578# Don't initialize baud rate. 579# 580# It's not obvious how to tell if a port is parallel or serial. 581# However, by splitting the initialization into two steps and letting 582# the serial-only part fail nicely, it'll work. 583# 584# Another point: The output must be a ``tty'' device. If not, don't 585# bother with any of this. 586##### 587stty1= stty2= 588tty 0<&1 1>/dev/null 2>&1 && { 589 590 ##### 591 # 592 # First set the default parameters, 593 # then the requested parameters. 594 ##### 595 596 stty \ 597 9600 \ 598 0<&1 2>/dev/null 1>&2 599 stty \ 600 cs8 -cstopb -parenb -parodd \ 601 ixon -ixany \ 602 opost -olcuc onlcr -ocrnl -onocr -onlret -ofill \ 603 nl0 cr0 tab0 bs0 vt0 ff0 \ 604 0<&1 2>/dev/null 1>&2 605 606 if [ -n "${stty}" ] 607 then 608 if stty ${stty} 0<&1 1>/dev/null 2>&5 609 then 610 : 611 else 612 errmsg ERROR ${E_IP_STTY} \ 613 "stty option list failed" \ 614 "check the \"-o stty\" option you used, 615 or consult your system administrator" 616 exit 1 617 fi 618 fi 619 620 ##### 621 # 622 # Here you may want to add other port initialization code. 623 # Some examples: 624 # 625 # estty # for printer needing hardware flow control (3B2/EPORTS) 626 # fctty # for printer needing hardware flow control (3B15,3B20) 627 ##### 628 #estty 0<&1 629 #fctty 0<&1 630 631 632 ########## 633 # 634 # Find out if we have to turn off opost before initializing the 635 # printer and on after. Likewise, check clocal. 636 # 637 # Turning OFF opost (output postprocessing) keeps the UNIX system 638 # from changing what we try to send to the printer. Turning ON 639 # clocal keeps the UNIX system from dropping what we are trying to 640 # send if the printer drops DTR. An example of the former is the 641 # AT&T 479, which wants to send a linefeed (ASCII 10) when a page 642 # width of 10 is set; with opost on, this COULD BE turned into a 643 # carriage-return/linefeed pair. An example of the latter is the 644 # AT&T 455, which momentarily drops DTR when it gets the 645 # initialization string, is2; with clocal off, the UNIX system 646 # stops sending the rest of the initialization sequence at that 647 # point. 648 # 649 # THIS CODE MUST FOLLOW THE REST OF THE PORT INITIALIZATION CODE. 650 ########## 651 cur_stty=`stty -a 0<&3` 652 expr "${cur_stty}" : '.*-opost' 1>/dev/null 2>&1 \ 653 || stty1="${stty1} -opost" stty2="${stty2} opost" 654 expr "${cur_stty}" : '.*-clocal' 1>/dev/null 2>&1 \ 655 && stty1="${stty1} clocal" stty2="${stty2} -clocal" 656 expr "${cur_stty}" : '.* opost.*' 1>/dev/null 2>&1 \ 657 || banner_filter=${FIX386BD} 658 659} 660 661 662########### 663## 664## Initialize the physical printer (Part I). 665## Here we bring the printer to a sane state and set the page size. 666########### 667 668########## 669# 670# WARNING! The "echo" command will catch backslashes (\) and 671# try to interpret the characters following it. Thus, using 672# "echo" to print string values obtained from "tput" is dangerous. 673########## 674 675##### 676# We're confident that most printers don't have backslashes 677# in the control sequences for carriage return and form-feed. 678# We're also confident that these don't contain newlines. 679# We're also confident that most printers have a linefeed 680# in the control sequence for doing a newline (move to beginning 681# of next line), but we can't capture it like we do the 682# carriage return or form-feed. Thus we set it unconditionally. 683# We don't set form-feed if it isn't defined, however, because 684# maybe the printer doesn't have a formfeed. If not set, we're 685# out of luck. 686##### 687 688CR=`${TPUT} cr` 689[ -z "${CR}" ] && CR="\r" 690 691FF=`${TPUT} ff` 692 693NL="${CR}\n" 694 695lines=`${TPUT} lines` 696[ -z "${lines}" -o 0 -ge "${lines}" ] && lines=66 697 698cols=`${TPUT} cols` 699[ -z "${cols}" -o 0 -ge "${cols}" ] && cols=132 700 701##### 702# 703# Basic initialization. The ``else'' clause is equivalent, 704# but covers cases where old Terminal Information Utilities are present. 705##### 706[ -n "${stty1}" ] && stty ${stty1} 0<&1 707 708# 709# "tput init" will return an "^M" in many cases to "stdout", i.e., printer! 710# This creates problems for some PS printers 711# 712if [ "${TERM}" = "PS" -o "${TERM}" = "PSR" ] 713then 714 : 715elif ${TPUT} init 2>/dev/null 716then 717 : 718else 719 pgm=`${TPUT} iprog` 720 if [ -x "${pgm}" ] 721 then 722 eval ${pgm} 723 fi 724 725 ${TPUT} is1 726 ${TPUT} is2 727 728 tabset= 729 if [ "8" != "`${TPUT} it`" ] 730 then 731 stty tab3 0<&1 1>/dev/null 2>&1 732 733 elif `${TPUT} ht >/dev/null` 734 then 735 tabset="/usr/lib/tabset/${TERM}" 736 if [ -r ${tabset} ] 737 then 738 cat -s ${tabset} 739 fi 740 stty tab3 0<&1 1>/dev/null 2>&1 741 fi 742 743 file=`${TPUT} if` 744 if [ "${tabset}" != "${file}" -a -r "${file}" ] 745 then 746 cat -s "${file}" 747 fi 748 749 ${TPUT} is3 750 echo "${CR}\c" 751fi 752[ -n "${stty2}" ] && stty ${stty2} 0<&1 753 754##### 755# 756# Set the page size and print spacing, but not the character set. 757# We will be doing the character set later (after the header). 758##### 759internal_lpset "${cpi}" "${lpi}" "${width}" "${length}" "" 760 761##### 762# 763# The banner page (and cancellation page) will 764# use double width characters if they're available. 765##### 766WIDE_CS=`${TPUT} swidm 2>/dev/null` && NORM_CS=`${TPUT} rwidm 2>/dev/null` 767PAD="#####${NL}" 768 769##### 770# 771# Some printers need to have the banner page filtered. 772##### 773case "${TERM}" in 774 775PS | PSR ) 776 banner_filter="/usr/lib/lp/postscript/postprint | /usr/lib/lp/postscript/postio" 777 LPTELL_OPTS="-l" 778 ;; 779 780esac 781if [ -n "${banner_filter}" ] 782then 783 banner_filter="| ${banner_filter}" 784fi 785 786##### 787# 788# Now that the printer is ready for printing, we're able 789# to record on paper a cancellation. 790##### 791 792cancel_banner () { 793 echo "${PAD}${PAD}\c" 794 echo "#####${WIDE_CS} Job ${request_id}${NORM_CS}${NL}\c" 795 echo "#####${WIDE_CS} suspended or canceled${NORM_CS}${NL}\c" 796 echo "${PAD}${PAD}\c" 797} 798 799canceled () { 800 ${TPUT} scs 0 2>/dev/null 801 echo "${CR}\c" 802 if [ "${width:-${cols}}" -lt "${MAX_COLS_SMALL_BANNER}" ] 803 then 804 WIDE_CS= NORM_CS= 805 fi 806 cancel_banner 807 if [ -n "${FF}" ] 808 then 809 echo "${CR}${FF}\c" 810 fi 811} 812 813trap 'eval canceled ${banner_filter}; exit_code=0 exit' 15 814 815 816########### 817## 818## Print the banner page 819########### 820 821##### 822# 823# You may want to change the following code to get a custom banner. 824##### 825 826regular_banner () { 827 echo "${CR}\c" 828 echo "${PAD}${PAD}${PAD}${PAD}${PAD}\c" 829 echo "#####${WIDE_CS} User: ${user_name}${NORM_CS}${NL}\c" 830 if [ -n "$ALIAS_USERNAME" ] 831 then 832 echo "${PAD}\c" 833 echo "#####${WIDE_CS} Alias: ${ALIAS_USERNAME}${NORM_CS}${NL}\c" 834 fi 835 if [ -n "${title}" ] 836 then 837 echo "${PAD}\c" 838 echo "#####${WIDE_CS} Title: ${title}${NORM_CS}${NL}\c" 839 fi 840 echo "${PAD}\c" 841 echo "#####${WIDE_CS} Printed: `LANG=C date '+%a %H:%M %h %d, %Y'`${NORM_CS}${NL}\c" 842 echo "${PAD}\c" 843 echo "#####${WIDE_CS} Job number: ${request_id}${NORM_CS}${NL}\c" 844 echo "${PAD}${PAD}${PAD}${PAD}${PAD}\c" 845 if [ -n "${FF}" ] 846 then 847 echo "${CR}${FF}\c" 848 fi 849} 850 851small_banner () { 852 echo "${CR}\c" 853 echo "${PAD}\c" 854 echo "##### User: ${user_name}${NL}\c" 855 if [ -n "${title}" ] 856 then 857 echo "##### Title: ${title}${NL}\c" 858 fi 859 echo "##### Date: `LANG=C date '+%a %H:%M %h %d, %Y'`${NL}\c" 860 echo "##### Job: ${request_id}${NL}\c" 861 echo "${PAD}\c" 862 if [ -n "${FF}" ] 863 then 864 echo "${CR}${FF}\c" 865 fi 866} 867 868if [ "${width:-${cols}}" -lt "${MAX_COLS_SMALL_BANNER}" ] 869then 870 banner=small_banner 871else 872 banner=regular_banner 873fi 874 875## Skip this for PS/PSR in TSOL, since lp.tsol_separator handles the banners 876if [ "no" = "${nobanner}" -a "${TERM}" != "PSR" -a "${TERM}" != "PS" ] 877then 878 ( eval "${banner} ${banner_filter}" 2>&1 1>&3 ) \ 879 | ${LPTELL} ${LPTELL_OPTS} ${printer} 880fi 881 882########### 883## 884## Surround the job by PostScript code to produce banner 885## and trailerpages and page headers and footers. 886## 887########### 888 889BANNER_EXIT_CODE=${TMPPREFIX}.banner.exit_code 890echo 0 > ${BANNER_EXIT_CODE} 891TSOLSEPARATOR_LOG=${TMPPREFIX}.banner.errmsg 892 893tsol_bannerize () { 894 TSOLSEPARATOR_OPTS="-e ${TSOLSEPARATOR_LOG}" 895 896 if [ "yes" = "${nolabels}" ] 897 then 898 TSOLSEPARATOR_OPTS="${TSOLSEPARATOR_OPTS} -l" 899 fi 900 901 if [ "yes" = "${nobanner}" ] 902 then 903 TSOLSEPARATOR_OPTS="${TSOLSEPARATOR_OPTS} -t /dev/null -b /dev/null" 904 fi 905 906 if [ "${TERM}" = "PSR" ] 907 then 908 TSOLSEPARATOR_OPTS="${TSOLSEPARATOR_OPTS} -r" 909 fi 910 911 # Get rid of the #, TAB and NL characters in the title 912 tsol_title=`echo $title` 913 tsol_title=`echo $tsol_title | sed 's/#//g'` 914 915 LC_TIME=C ${LPTSOLSEPARATOR} ${TSOLSEPARATOR_OPTS} "${printer}" \ 916 "${request_id}" "${user_name}" "${tsol_title}" "${file}" 917 echo $? > ${BANNER_EXIT_CODE} 918 true 919} 920 921bannerize=tsol_bannerize 922 923if [ "yes" = "${nobanner}" -a "yes" = "${nolabels}" ] 924then 925 bannerize=cat 926fi 927 928if [ "${TERM}" != "PSR" -a "${TERM}" != "PS" ] 929then 930 bannerize=cat 931fi 932 933 934########### 935## 936## Initialize the physical printer (Part II) 937## Here we select the character set. 938## One could argue that this should be done before the banner is printed, 939## but we don't, to keep the banner page looking consistent for the 940## operator. You can move this code before the banner code if you 941## disagree. If you do, combine it with the other call to "internal_lpset" 942## to do everything in one shot. 943########### 944internal_lpset "" "" "" "" "${CHARSET}" 945 946########### 947## 948## Print some copies of the file(s) 949########### 950 951##### 952# 953# The protocol between the interface program and the Spooler 954# is fairly simple: 955# 956# All standard error output is assumed to indicate a 957# fault WITH THE REQUEST. The output is mailed to the 958# user who submitted the print request and the print 959# request is finished. 960# 961# If the interface program sets a zero exit code, 962# it is assumed that the file printed correctly. 963# If the interface program sets a non-zero exit code 964# less than 128, it is assumed that the file did not 965# print correctly, and the user will be notified. 966# In either case the print request is finished. 967# 968# If the interface program sets an exit code greater 969# than 128, it is assumed that the file did not print 970# because of a printer fault. If an alert isn't already 971# active (see below) one will be activated. (Exit code 972# 128 should not be used at all. The shell, which executes 973# this program, turns SIGTERM, used to kill this program 974# for a cancellation or disabling, into exit 128. The 975# Spooler thus interpretes 128 as SIGTERM.) 976# 977# A message sent to the standard input of the ${LPTELL} 978# program is assumed to describe a fault WITH THE PRINTER. 979# The output is used in an alert (if alerts are defined). 980# If the fault recovery is "wait" or "begin", the printer 981# is disabled (killing the interface program if need be), 982# and the print request is left on the queue. 983# If the fault recovery is "continue", the interface program 984# is allowed to wait for the printer fault to be cleared so 985# it can resume printing. 986# 987# This interface program relies on filters to detect printer faults. 988# In absence of a filter provided by the customer, it uses a simple 989# filter (${LPCAT}) to detect the class of faults that cause DCD 990# (``carrier'') drop. The protocol between the interface program and 991# the filter: 992# 993# The filter should exit with zero if printing was 994# successful and non-zero if printing failed because 995# of a printer fault. This interface program turns a 996# non-zero exit of the filter into an "exit 129" from 997# itself, thus telling the Spooler that a printer fault 998# (still) exists. 999# 1000# The filter should report printer faults via a message 1001# to its standard error. This interface program takes all 1002# standard error output from the filter and feeds it as 1003# standard input to the ${LPTELL} program. 1004# 1005# The filter should wait for a printer fault to clear, 1006# and should resume printing when the fault clears. 1007# Preferably it should resume at the top of the page 1008# that was being printed when the fault occurred. 1009# If it waits and finishes printing, it should exit 1010# with a 0 exit code. If it can't wait, it should exit 1011# with a non-zero exit code. 1012# 1013# The interface program expects that ANY message on the 1014# standard error from the filter indicates a printer fault. 1015# Therefore, a filter should not put user (input) error 1016# messages on the standard error, but on the standard output 1017# (where the user can read them when he or she examines 1018# the print-out). 1019# 1020##### 1021 1022badfileyet= 1023i=1 1024while [ $i -le $copies ] 1025do 1026 for file in ${files} 1027 do 1028 if [ -r "${file}" ] 1029 then 1030 ##### 1031 # 1032 # Here's where we set up the $LPTELL program to 1033 # capture fault messages, and... 1034 # 1035 # Here's where we print the file. 1036 # 1037 # We set up a pipeline to $LPTELL, but play a trick 1038 # to get the filter's standard ERROR piped instead of 1039 # its standard OUTPUT: Divert the standard error (#2) to 1040 # the standard output (#1) IN THE PIPELINE. The shell 1041 # will have changed #1 to be the pipe, not the 1042 # printer, so diverting #2 connects it to the pipe. 1043 # We then change the filter's #1 to a copy of the real 1044 # standard output (the printer port) made earlier, 1045 # so that is connected back to the printer again. 1046 # 1047 # We do all this inside a parenthesized expression 1048 # so that we can get the exit code; this is necessary 1049 # because the exit code of a pipeline is the exit 1050 # code of the right-most command, which isn't the 1051 # filter. 1052 # 1053 # These two tricks could be avoided by using a named 1054 # pipe to connect the standard error to $LPTELL. In 1055 # fact an early prototype of this script did just 1056 # that; however, the named pipe introduced a timing 1057 # problem. The processes that open a named pipe hang 1058 # until both ends of the pipe are opened. Cancelling 1059 # a request or disabling the printer often killed one 1060 # of the processes, causing the other process to hang 1061 # forever waiting for the other end of the pipe to 1062 # be opened. 1063 ##### 1064 EXIT_CODE=${TMPPREFIX}e 1065 trap '' 1 # Let the filter handle a hangup 1066 trap '' 2 3 # and interrupts 1067 ( 1068 ##### 1069 # Put the 0<${file} before the "eval" to keep 1070 # clever users from giving a file name that 1071 # evaluates as something to execute. 1072 ##### 1073 0<${file} $bannerize | eval ${FILTER} 2>&1 1>&3 1074 echo $? >${EXIT_CODE} 1075 ) | ${LPTELL} ${LPTELL_OPTS} ${printer} 1076 1077 # if lp.tsol_separator had an error, send its logged 1078 # error message to LPTELL. 1079 banner_exit_code=`cat ${BANNER_EXIT_CODE}` 1080 if [ -n "${banner_exit_code}" -a \ 1081 0 -ne "${banner_exit_code}" -a \ 1082 -n "${LPTELL}" -a \ 1083 -r "${TSOLSEPARATOR_LOG}" ] 1084 then 1085 cat ${TSOLSEPARATOR_LOG} | ${LPTELL} ${printer} 1086 echo 77 > ${EXIT_CODE} 1087 fi 1088 1089 trap 'catch_hangup; exit_code=129 exit 129' 1 1090 trap 'catch_interrupt; exit_code=129 exit 129' 2 3 1091 exit_code=`cat ${EXIT_CODE}` 1092 1093 if [ -n "${exit_code}" -a 0 -ne "${exit_code}" ] 1094 then 1095 trap '' 15 # Avoid dying from disable 1096 sleep 4 # Give $LPTELL a chance to tell 1097 exit ${exit_code} 1098 fi 1099 1100 if [ -n "${FF}" -a "no" = "${nofilebreak}" ] 1101 then 1102 echo "${CR}${FF}\c" 1103 fi 1104 1105 else 1106 1107 ##### 1108 # 1109 # Don't complain about not being able to read 1110 # a file on second and subsequent copies, unless 1111 # we've not complained yet. This removes repeated 1112 # messages about the same file yet reduces the 1113 # chance that the user can remove a file and not 1114 # know that we had trouble finding it. 1115 ##### 1116 if [ "${i}" -le 1 -o -z "${badfileyet}" ] 1117 then 1118 errmsg WARNING ${E_IP_BADFILE} \ 1119 "cannot read file \"${file}\"" \ 1120 "see if the file still exists and is readable, 1121 or consult your system administrator; 1122 printing continues" 1123 badfileyet=yes 1124 fi 1125 1126 fi 1127 1128 done 1129 i=`expr $i + 1` 1130 1131done 1132 1133# Skip this for TSOL, since lp.tsol_separator handles the banners 1134# 1135# if [ "no" = "${nobanner}" -a "${TERM}" = "PSR" ] 1136# then 1137# ( eval "${banner} ${banner_filter}" 2>&1 1>&3 ) \ 1138# | ${LPTELL} ${LPTELL_OPTS} ${printer} 1139# fi 1140 1141if [ -n "${exit_code}" -a 0 -ne "${exit_code}" ] 1142then 1143 exit ${exit_code} 1144fi 1145 1146##### 1147# 1148# Always ensure the complete job ends with a ``formfeed'', to 1149# let the next job start on a new page. (If someone wants to 1150# concatenate files, they can give them in one job.) 1151# So, if we haven't been putting out a ``formfeed'' between files, 1152# it means we haven't followed the last file with a formfeed, 1153# so we do it here. 1154##### 1155if [ -n "${FF}" -a "yes" = "${nofilebreak}" ] 1156then 1157 echo "${CR}${FF}\c" 1158fi 1159 1160${DRAIN} 1161 1162exit_code=0 exit 0 1163