8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / lp / model / standard
blob5823de6d6e9253b205a4d809ad9ddd5a27e17aa8
2 # Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
3 # Use is subject to license terms.
5 # CDDL HEADER START
7 # The contents of this file are subject to the terms of the
8 # Common Development and Distribution License, Version 1.0 only
9 # (the "License").  You may not use this file except in compliance
10 # with the License.
12 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
13 # or http://www.opensolaris.org/os/licensing.
14 # See the License for the specific language governing permissions
15 # and limitations under the License.
17 # When distributing Covered Code, include this CDDL HEADER in each
18 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
19 # If applicable, add the following below this CDDL HEADER, with the
20 # fields enclosed by brackets "[]" replaced with your own identifying
21 # information: Portions Copyright [yyyy] [name of copyright owner]
23 # CDDL HEADER END
25 #ident  "%Z%%M% %I%     %E% SMI"        /* SVr4.0 1.26  */
27 ###########
29 ## Standard printer interface program.
30 ###########
32 #####
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 #####
38 trap 'exit' 15
40 #####
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 #####
46 catch_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
55 catch_interrupt () {
56         if [ -n "${LPTELL}" ]
57         then
58                 echo \
59 "Received an interrupt from the printer.  The reason is unknown,
60 although a common cause is that the baud rate is too high." \
61                 | ${LPTELL} ${printer}
62         fi
63         return 0
65 trap 'catch_hangup; exit_code=129 exit 129' 1
66 trap 'catch_interrupt; exit_code=129 exit 129' 2 3
68 #####
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.
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 #####
80 exec 5>&2 2>/dev/null 3>&1
82 #####
84 # Set some globally used variables and functions.
85 #####
87 : ${TMPDIR:=/tmp}
88 : ${SPOOLDIR:=/usr/spool/lp}
89 : ${TERMINFO:=/usr/lib/terminfo}
90 : ${CHARSETDIR:=/usr/lib/charsets}
92 : ${LOCALPATH:=${SPOOLDIR}/bin}
93 PATH="/bin:/usr/bin:${LOCALPATH}"
95 MAX_COLS_SMALL_BANNER=40
97 #####
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}
105 if [ -n "${FIX386BD}" -a -x "${FIX386BD}" ]
106 then
107         FIX386BD="| ${FIX386BD}"
108 else
109         FIX386BD=""
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 #####
119 TMPPREFIX=${TMPDIR}/`uname -n`$$
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 #####
125 trap 'rm -fr ${TMPPREFIX}*; exit ${exit_code}' 0
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 #####
133 if [ ! -x "${LPTELL:=${LOCALPATH}/lp.tell}" ]
134 then
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
154 #####
155 # ${DRAIN} is the name of a program that will wait
156 # long enough for data sent to the printer to print.
157 #####
158 if [ -x "${LOCALPATH}/drain.output" ]
159 then
160         DRAIN="${LOCALPATH}/drain.output 5"     # wait only five seconds
161 else
162         DRAIN=
165 #####
166 # ${LPCAT} is the name of a program to use as a default
167 # filter. Minimally it should copy its standard input to
168 # the standard output, but it should also trap printer
169 # faults. The current LPCAT traps hangups (DCD dropping, SIGHUP),
170 # interrupts (SIGINT, SIGQUIT), broken pipe (SIGPIPE), and
171 # excess delays in sending data to the printer, interpreting all
172 # as printer faults.
173 #####
174 if [ ! -x "${LPCAT:=${LOCALPATH}/lp.cat}" ]
175 then
176         LPCAT="cat"
179 #####
180 # ${LPSET} is the name of a program that will set the
181 # character pitch, line pitch, page width, page length,
182 # and character set. It helps to have this in a single
183 # binary program so that (1) it's faster than calls
184 # to "tput"; and (2) it can access the new Terminfo
185 # capabilities for printers (on pre SVR3.2 machines, tput can't).
186 #####
187 if [ ! -x "${LPSET:=${LOCALPATH}/lp.set}" ]
188 then
189         fake_lpset () {
190                 echo H V W L S >&2
191                 false
192         }
193         LPSET=fake_lpset
196 internal_lpset () {
197         #####
198         #
199         # The funny business with the "2>&1 1>&3" is to let us capture
200         # the standard ERROR, not the standard OUTPUT as is the usual case
201         # with foo=`cmd`. The standard output will go to the printer.
202         #####
203         [ -n "${stty1}" ] && stty ${stty1} 0<&1
204         chk=`${LPSET} "$1" "$2" "$3" "$4" "$5" 2>&1 1>&3`
205         [ -n "${stty2}" ] && stty ${stty2} 0<&1
207         #####
208         #
209         # The standard error of the delivered ${LPSET} program
210         # is a string of letters, H, V, W, L, S, which correspond
211         # to cpi, lpi, width, length, and character set. A letter
212         # is present only if the corresponding attribute could not
213         # be set.
214         #####
215         for err in ${chk}
216         do
217                 case ${err} in
218                 H )
219                         errmsg WARNING ${E_IP_BADCPI} \
220                 "can't select the character pitch \"${cpi}\"" \
221                 "check the valid pitches for the printer,
222                 or consult your system administrator;
223                 printing continues"
224                         ;;
225                 V )
226                         errmsg WARNING ${E_IP_BADLPI} \
227                 "can't select the line pitch \"${lpi}\"" \
228                 "check the valid pitches for the printer,
229                 or consult your system administrator;
230                 printing continues"
231                         ;;
232                 W )
233                         width=${cols}
234                         errmsg WARNING ${E_IP_BADWIDTH} \
235                 "can't select the page width \"${width}\"" \
236                 "check the valid widths for the printer,
237                 or consult your system administrator;
238                 printing continues"
239                         ;;
240                 L )
241                         length=${lines}
242                         errmsg WARNING ${E_IP_BADLENGTH} \
243                 "can't select the page length \"${length}\"" \
244                 "check the valid lengths for the printer,
245                 or consult your system administrator;
246                 printing continues"
247                         ;;
248                 S )
249                         errmsg WARNING ${E_IP_BADCHARSET} \
250                 "can't select the character set \"${CHARSET}\"" \
251                 "check the name given in the -S option,
252                 or consult your system administrator;
253                 printing continues"
254                         ;;
255                 esac
256         done
260 #####
261 # ${TPUT} is "tput" IF it works. We'll disable it if we get an
262 # ugly error message the first time we use it. See the TERM variable
263 # later in the script.
265 # NOTE: The check we use to see if "tput" works is to use an OLD
266 # Terminfo capability, like "lines". If it works with that it may
267 # still fail with some of the newer capabilities like "init" (SVR3.0)
268 # or "swidm" (SVR3.2), because the version of "tput" we have on your
269 # machine is older. Thus, on some of the code where ${TPUT} is used
270 # you'll see "2>/dev/null" being used to avoid ugly error messages.
271 #####
272 TPUT=tput
274 #####
275 # Error message formatter:
277 # Invoke as
279 #       errmsg severity message-number problem help
281 # where severity is "ERROR" or "WARNING", message-number is
282 # a unique identifier, problem is a short description of the
283 # problem, and help is a short suggestion for fixing the problem.
284 #####
286 LP_ERR_LABEL="UX:lp"
288 E_IP_ARGS=1
289 E_IP_OPTS=2
290 #E_IP_FILTER=3
291 E_IP_STTY=4
292 E_IP_UNKNOWN=5
293 E_IP_BADFILE=6
294 E_IP_BADCHARSET=7
295 E_IP_BADCPI=8
296 E_IP_BADLPI=9
297 E_IP_BADWIDTH=10
298 E_IP_BADLENGTH=11
299 E_IP_ERRORS=12          # (in slow.filter)
301 errmsg () {
302         case $1 in
303         ERROR )
304                 sev="  ERROR";
305                 ;;
306         WARNING )
307                 sev="WARNING";
308                 ;;
309         esac
310 #       tag=`expr "${LP_ERR_LABEL}" : "\(.*\):"``expr "${LP_ERR_LABEL}" : ".*:\(.*\)"`
311         echo "${LP_ERR_LABEL}: ${sev}: $3
312         TO FIX: $4" >&5
316 ###########
318 ## Check arguments
319 ###########
321 parse () {
322         echo "`expr \"$1\" : \"^[^=]*=\(.*\)\"`"
325 #####
327 # This program is invoked as
329 # ${SPOOLDIR}/.../printer request-id user title copies options files...
331 # The first three arguments are simply reprinted on the banner page,
332 # the fourth (copies) is used to control the number of copies to print,
333 # the fifth (options) is a blank separated list (in a single argument)
334 # of user or Spooler supplied options (without the -o prefix),
335 # and the last arguments are the files to print.
336 #####
338 if [ $# -lt 5 ]
339 then
340         errmsg ERROR ${E_IP_ARGS} \
341                 "wrong number of arguments to interface program" \
342                 "consult your system administrator"
343         exit 1
346 printer=`basename $0`
347 request_id=$1
348 user_name=$2
349 title=$3
350 copies=$4
351 option_list=$5
353 shift 5
354 files="$*"
356 nobanner="no"
357 nofilebreak="no"
358 stty=
360 inlist=
361 for i in ${option_list}
363         case "${inlist}${i}" in
366         nobanner )
367                 nobanner="yes"
368                 ;;
370         nofilebreak )
371                 nofilebreak="yes"
372                 ;;
374         #####
375         #
376         # If you want to add simple options (e.g. -o simple)
377         # identify them here.
378         #####
379 #       simple )
380 #               simple="yes"
381 #               ;;
384         cpi=pica )
385                 cpi=10
386                 ;;
387         cpi=elite )
388                 cpi=12
389                 ;;
390         cpi=* )
391                 cpi=`parse ${i}`
392                 ;;
394         lpi=* )
395                 lpi=`parse ${i}`
396                 ;;
398         length=* )
399                 length=`parse ${i}`
400                 ;;
402         width=* )
403                 width=`parse ${i}`
404                 ;;
406         #####
407         #
408         # If you want to add simple-value options (e.g. -o value=a)
409         # identify them here.
410         #####
411 #       value=* )
412 #               value=`parse ${i}`
413 #               ;;
416         #####
417         #
418         # If you want to add options that, like "stty",
419         # take a list (e.g. -o lopt='a b c'), identify
420         # them here and below (look for LOPT).
421         #####
422         stty=* | flist=* | lpd=* )
423 #LOPT   stty=* | flist=* | lpd=* | lopt=* )
425                 inlist=`expr "${inlist}${i}" : "^\([^=]*=\)"`
426                 case "${i}" in
427                 ${inlist}\'*\' )
428                         item=`expr "${i}" : "^[^=]*='*\(.*\)'\$"`
429                         ;;
430                 ${inlist}\' )
431                         continue
432                         ;;
433                 ${inlist}\'* )
434                         item=`expr "${i}" : "^[^=]*='*\(.*\)\$"`
435                         ;;
436                 ${inlist}* )
437                         item=`expr "${i}" : "^[^=]*=\(.*\)\$"`
438                         ;;
439                 *\' )
440                         item=`expr "${i}" : "^\(.*\)'\$"`
441                         ;;
442                 * )
443                         item="${i}"
444                         ;;
445                 esac
447                 #####
448                 #
449                 # We don't dare use "eval" because a clever user could
450                 # put something in an option value that we'd end up
451                 # exec'ing.
452                 #####
453                 case "${inlist}" in
454                 stty= )
455                         stty="${stty} ${item}"
456                         ;;
457                 flist= )
458                         flist="${flist} ${item}"
459                         ;;
460                 lpd= )
461                         lpd="${lpd} ${item}"
462                         ;;
463 #LOPT           lopt= )
464 #LOPT                   lopt="${lopt} ${item}"
465 #LOPT                   ;;
466                 esac
468                 case "${i}" in
469                 ${inlist}\'*\' )
470                         inlist=
471                         ;;
472                 ${inlist}\'* )
473                         ;;
474                 *\' | ${inlist}* )
475                         inlist=
476                         ;;
477                 esac
478                 ;;
480         * )
481                 errmsg WARNING ${E_IP_OPTS} \
482                         "unrecognized \"-o ${i}\" option" \
483                         "check the option, resubmit if necessary
484                 printing continues"
485                 ;;
486         esac
487 done
489 #####
491 # Additional ``parameters'' are passed via Shell environment
492 # variables:
494 #       TERM    The printer type (used for Terminfo access)
495 #       CHARSET The character set to choose
496 #       FILTER  The filter to run
497 #####
499 #####
500 # Set defaults for unset variables.
501 #####
503 : ${TERM:=unknown}
504 tput lines 1>/dev/null 2>&1 || TPUT=:
506 : ${CHARSET:=cs0}
508 if [ -z "${FILTER}" ]
509 then
510         #####
511         #
512         # If no filter is being used, we have a little routine that
513         # will push the data to the printer. It traps hangups (loss
514         # of carrier) and checks for excessive delays in sending the
515         # data to the printer. The lesser of the print rate of the printer
516         # (obtained from Terminfo) or the baud rate is used to compute
517         # the expected delay. If neither of these is correct, you
518         # may be experiencing false alarms. If so, give the correct
519         # rate, in characters per second, as a single argument.
520         # An argument of 0 means don't check for delays.
521         # Give an -r option to get a printout of actual delays.
522         # (QUOTES ARE IMPORTANT!)
523         #####
524         case "$TERM" in
525                 PS )
526                         # make the "postscript" printers use postio to
527                         # talk to the printer and periodically get a 
528                         # status from them
529                         FILTER="/usr/lib/lp/postscript/postio"
530                 ;;
531                 PSR )
532                         # make the "reverse postscript" printers reverse the
533                         # output and the use postio to talk to the printer
534                         FILTER="/usr/lib/lp/postscript/postreverse | \
535                                 /usr/lib/lp/postscript/postio"
536                 ;;
537                 * )
538                         # we don't know the type, so just assume that the
539                         # input and output are the same
540                         if [ `basename "${LPCAT}"` = "lp.cat" ] ; then
541                                 FILTER="${LPCAT} 0"     # infinite delays
542                                 # FILTER="${LPCAT} 120" # e.g. 120 CPS
543                                 # FILTER="${LPCAT} -r 0 2>/tmp/delays"
544                                 # FILTER=${LPCAT}
545                         fi
546                 ;;
547         esac
550 ###########
552 ## Initialize the printer port
553 ###########
555 #####
557 # SERIAL PORTS:
558 # Initialize everything.
560 # PARALLEL PORTS:
561 # Don't initialize baud rate.
563 # It's not obvious how to tell if a port is parallel or serial.
564 # However, by splitting the initialization into two steps and letting
565 # the serial-only part fail nicely, it'll work.
567 # Another point: The output must be a ``tty'' device. If not, don't
568 # bother with any of this.
569 #####
570 stty1= stty2=
571 tty 0<&1 1>/dev/null 2>&1 && {
573         #####
574         #
575         # First set the default parameters,
576         # then the requested parameters.
577         #####
579         stty \
580                 9600 \
581                         0<&1 2>/dev/null 1>&2
582         stty \
583                 cs8 -cstopb -parenb -parodd \
584                 ixon -ixany \
585                 opost -olcuc onlcr -ocrnl -onocr -onlret -ofill \
586                 nl0 cr0 tab0 bs0 vt0 ff0 \
587                         0<&1 2>/dev/null 1>&2
589         if [ -n "${stty}" ]
590         then
591                 if stty ${stty} 0<&1 1>/dev/null 2>&5
592                 then
593                         :
594                 else
595                         errmsg ERROR ${E_IP_STTY} \
596                                 "stty option list failed" \
597                                 "check the \"-o stty\" option you used,
598                 or consult your system administrator"
599                         exit 1
600                 fi
601         fi
603         #####
604         #
605         # Here you may want to add other port initialization code.
606         # Some examples:
607         #
608         # estty # for printer needing hardware flow control (3B2/EPORTS)
609         # fctty # for printer needing hardware flow control (3B15,3B20)
610         #####
611         #estty 0<&1
612         #fctty 0<&1
615         ##########
616         #
617         # Find out if we have to turn off opost before initializing the
618         # printer and on after. Likewise, check clocal.
619         #
620         # Turning OFF opost (output postprocessing) keeps the UNIX system
621         # from changing what we try to send to the printer. Turning ON
622         # clocal keeps the UNIX system from dropping what we are trying to
623         # send if the printer drops DTR. An example of the former is the
624         # AT&T 479, which wants to send a linefeed (ASCII 10) when a page
625         # width of 10 is set; with opost on, this COULD BE turned into a
626         # carriage-return/linefeed pair. An example of the latter is the
627         # AT&T 455, which momentarily drops DTR when it gets the
628         # initialization string, is2; with clocal off, the UNIX system
629         # stops sending the rest of the initialization sequence at that
630         # point.
631         #
632         # THIS CODE MUST FOLLOW THE REST OF THE PORT INITIALIZATION CODE.
633         ##########
634         cur_stty=`stty -a 0<&3`
635         expr "${cur_stty}" : '.*-opost' 1>/dev/null 2>&1 \
636                 || stty1="${stty1} -opost" stty2="${stty2} opost"
637         expr "${cur_stty}" : '.*-clocal' 1>/dev/null 2>&1 \
638                 && stty1="${stty1} clocal" stty2="${stty2} -clocal"
639         expr "${cur_stty}" : '.* opost.*' 1>/dev/null 2>&1 \
640                 || banner_filter=${FIX386BD}
645 ###########
647 ## Initialize the physical printer (Part I).
648 ## Here we bring the printer to a sane state and set the page size.
649 ###########
651 ##########
653 # WARNING! The "echo" command will catch backslashes (\) and
654 # try to interpret the characters following it. Thus, using
655 # "echo" to print string values obtained from "tput" is dangerous.
656 ##########
658 #####
659 # We're confident that most printers don't have backslashes
660 # in the control sequences for carriage return and form-feed.
661 # We're also confident that these don't contain newlines.
662 # We're also confident that most printers have a linefeed
663 # in the control sequence for doing a newline (move to beginning
664 # of next line), but we can't capture it like we do the
665 # carriage return or form-feed. Thus we set it unconditionally.
666 # We don't set form-feed if it isn't defined, however, because
667 # maybe the printer doesn't have a formfeed. If not set, we're
668 # out of luck.
669 #####
671 CR=`${TPUT} cr`
672 [ -z "${CR}" ] && CR="\r"
674 FF=`${TPUT} ff`
676 NL="${CR}\n"
678 lines=`${TPUT} lines`
679 [ -z "${lines}" -o 0 -ge "${lines}" ] && lines=66
681 cols=`${TPUT} cols`
682 [ -z "${cols}" -o 0 -ge "${cols}" ] && cols=132
684 #####
686 # Basic initialization. The ``else'' clause is equivalent,
687 # but covers cases where old Terminal Information Utilities are present.
688 #####
689 [ -n "${stty1}" ] && stty ${stty1} 0<&1
692 # "tput init" will return an "^M" in many cases to "stdout", i.e., printer!
693 # This creates problems for some PS printers
695 if [ "${TERM}" = "PS" -o "${TERM}" = "PSR" ]
696 then
697         :
698 elif ${TPUT} init 2>/dev/null
699 then
700         :
701 else
702         pgm=`${TPUT} iprog`
703         if [ -x "${pgm}" ]
704         then
705                 eval ${pgm}
706         fi
708         ${TPUT} is1
709         ${TPUT} is2
711         tabset=
712         if [ "8" != "`${TPUT} it`" ]
713         then
714                 stty tab3 0<&1 1>/dev/null 2>&1
716         elif `${TPUT} ht >/dev/null`
717         then
718                 tabset="/usr/lib/tabset/${TERM}"
719                 if [ -r ${tabset} ]
720                 then
721                         cat -s ${tabset}
722                 fi
723                 stty tab3 0<&1 1>/dev/null 2>&1
724         fi
726         file=`${TPUT} if`
727         if [ "${tabset}" != "${file}" -a -r "${file}" ]
728         then
729                 cat -s "${file}"
730         fi
732         ${TPUT} is3
733         echo "${CR}\c"
735 [ -n "${stty2}" ] && stty ${stty2} 0<&1
737 #####
739 # Set the page size and print spacing, but not the character set.
740 # We will be doing the character set later (after the header).
741 #####
742 internal_lpset "${cpi}" "${lpi}" "${width}" "${length}" ""
744 #####
746 # The banner page (and cancellation page) will
747 # use double width characters if they're available.
748 #####
749 WIDE_CS=`${TPUT} swidm 2>/dev/null` && NORM_CS=`${TPUT} rwidm 2>/dev/null`
750 PAD="#####${NL}"
752 #####
754 # Some printers need to have the banner page filtered.
755 #####
756 case "${TERM}" in
758 PS | PSR )
759         banner_filter="/usr/lib/lp/postscript/postprint | /usr/lib/lp/postscript/postio"
760         LPTELL_OPTS="-l"
761         ;;
763 esac
764 if [ -n "${banner_filter}" ]
765 then
766         banner_filter="| ${banner_filter}"
769 #####
771 # Now that the printer is ready for printing, we're able
772 # to record on paper a cancellation.
773 #####
775 cancel_banner () {
776         echo "${PAD}${PAD}\c"
777         echo "#####${WIDE_CS} Job ${request_id}${NORM_CS}${NL}\c"
778         echo "#####${WIDE_CS} suspended or canceled${NORM_CS}${NL}\c"
779         echo "${PAD}${PAD}\c"
782 canceled () {
783         ${TPUT} scs 0 2>/dev/null
784         echo "${CR}\c"
785         if [ "${width:-${cols}}" -lt "${MAX_COLS_SMALL_BANNER}" ]
786         then
787                 WIDE_CS= NORM_CS=
788         fi
789         cancel_banner
790         if [ -n "${FF}" ]
791         then
792                 echo "${CR}${FF}\c"
793         fi
796 trap 'eval canceled ${banner_filter}; exit_code=0 exit' 15
799 ###########
801 ## Print the banner page
802 ###########
804 #####
806 # You may want to change the following code to get a custom banner.
807 #####
809 regular_banner () {
810         echo "${CR}\c"
811         echo "${PAD}${PAD}${PAD}${PAD}${PAD}\c"
812         echo "#####${WIDE_CS}       User: ${user_name}${NORM_CS}${NL}\c"
813         if [ -n "$ALIAS_USERNAME" ]
814         then
815                 echo "${PAD}\c"
816                 echo "#####${WIDE_CS}      Alias: ${ALIAS_USERNAME}${NORM_CS}${NL}\c"
817         fi
818         if [ -n "${title}" ]
819         then
820                 echo "${PAD}\c"
821                 echo "#####${WIDE_CS}      Title: ${title}${NORM_CS}${NL}\c"
822         fi
823         echo "${PAD}\c"
824         echo "#####${WIDE_CS}    Printed: `LANG=C date '+%a %H:%M %h %d, %Y'`${NORM_CS}${NL}\c"
825         echo "${PAD}\c"
826         echo "#####${WIDE_CS} Job number: ${request_id}${NORM_CS}${NL}\c"
827         echo "${PAD}${PAD}${PAD}${PAD}${PAD}\c"
828         if [ -n "${FF}" ]
829         then
830                 echo "${CR}${FF}\c"
831         fi
834 small_banner () {
835         echo "${CR}\c"
836         echo "${PAD}\c"
837         echo "#####  User: ${user_name}${NL}\c"
838         if [ -n "${title}" ]
839         then
840                 echo "##### Title: ${title}${NL}\c"
841         fi
842         echo "#####  Date: `LANG=C date '+%a %H:%M %h %d, %Y'`${NL}\c"
843         echo "#####   Job: ${request_id}${NL}\c"
844         echo "${PAD}\c"
845         if [ -n "${FF}" ]
846         then
847                 echo "${CR}${FF}\c"
848         fi
851 if [ "${width:-${cols}}" -lt "${MAX_COLS_SMALL_BANNER}" ]
852 then
853         banner=small_banner
854 else
855         banner=regular_banner
858 if [ "no" = "${nobanner}" -a "${TERM}" != "PSR" ]
859 then
860         ( eval "${banner} ${banner_filter}" 2>&1 1>&3 ) \
861                 | ${LPTELL} ${LPTELL_OPTS} ${printer}
865 ###########
867 ## Initialize the physical printer (Part II)
868 ## Here we select the character set.
869 ## One could argue that this should be done before the banner is printed,
870 ## but we don't, to keep the banner page looking consistent for the
871 ## operator. You can move this code before the banner code if you
872 ## disagree. If you do, combine it with the other call to "internal_lpset"
873 ## to do everything in one shot.
874 ###########
875 internal_lpset "" "" "" "" "${CHARSET}"
877 ###########
879 ## Print some copies of the file(s)
880 ###########
882 #####
884 # The protocol between the interface program and the Spooler
885 # is fairly simple:
887 #       All standard error output is assumed to indicate a
888 #       fault WITH THE REQUEST. The output is mailed to the
889 #       user who submitted the print request and the print
890 #       request is finished.
892 #       If the interface program sets a zero exit code,
893 #       it is assumed that the file printed correctly.
894 #       If the interface program sets a non-zero exit code
895 #       less than 128, it is assumed that the file did not
896 #       print correctly, and the user will be notified.
897 #       In either case the print request is finished.
899 #       If the interface program sets an exit code greater
900 #       than 128, it is assumed that the file did not print
901 #       because of a printer fault. If an alert isn't already
902 #       active (see below) one will be activated. (Exit code
903 #       128 should not be used at all. The shell, which executes
904 #       this program, turns SIGTERM, used to kill this program
905 #       for a cancellation or disabling, into exit 128. The
906 #       Spooler thus interpretes 128 as SIGTERM.)
908 #       A message sent to the standard input of the ${LPTELL}
909 #       program is assumed to describe a fault WITH THE PRINTER.
910 #       The output is used in an alert (if alerts are defined).
911 #       If the fault recovery is "wait" or "begin", the printer
912 #       is disabled (killing the interface program if need be),
913 #       and the print request is left on the queue.
914 #       If the fault recovery is "continue", the interface program
915 #       is allowed to wait for the printer fault to be cleared so
916 #       it can resume printing.
918 # This interface program relies on filters to detect printer faults.
919 # In absence of a filter provided by the customer, it uses a simple
920 # filter (${LPCAT}) to detect the class of faults that cause DCD
921 # (``carrier'') drop. The protocol between the interface program and
922 # the filter:
924 #       The filter should exit with zero if printing was
925 #       successful and non-zero if printing failed because
926 #       of a printer fault. This interface program turns a
927 #       non-zero exit of the filter into an "exit 129" from
928 #       itself, thus telling the Spooler that a printer fault
929 #       (still) exists.
931 #       The filter should report printer faults via a message
932 #       to its standard error. This interface program takes all
933 #       standard error output from the filter and feeds it as
934 #       standard input to the ${LPTELL} program.
936 #       The filter should wait for a printer fault to clear,
937 #       and should resume printing when the fault clears.
938 #       Preferably it should resume at the top of the page
939 #       that was being printed when the fault occurred.
940 #       If it waits and finishes printing, it should exit
941 #       with a 0 exit code. If it can't wait, it should exit
942 #       with a non-zero exit code.
944 #       The interface program expects that ANY message on the
945 #       standard error from the filter indicates a printer fault.
946 #       Therefore, a filter should not put user (input) error
947 #       messages on the standard error, but on the standard output
948 #       (where the user can read them when he or she examines
949 #       the print-out).
951 #####
953 badfileyet=
955 while [ $i -le $copies ]
957         for file in ${files}
958         do
959                 if [ -r "${file}" ]
960                 then
961                         #####
962                         #
963                         # Here's where we set up the $LPTELL program to
964                         # capture fault messages, and...
965                         #
966                         # Here's where we print the file.
967                         #
968                         # We set up a pipeline to $LPTELL, but play a trick
969                         # to get the filter's standard ERROR piped instead of
970                         # its standard OUTPUT: Divert the standard error (#2) to
971                         # the standard output (#1) IN THE PIPELINE. The shell
972                         # will have changed #1 to be the pipe, not the
973                         # printer, so diverting #2 connects it to the pipe.
974                         # We then change the filter's #1 to a copy of the real
975                         # standard output (the printer port) made earlier,
976                         # so that is connected back to the printer again.
977                         #
978                         # We do all this inside a parenthesized expression
979                         # so that we can get the exit code; this is necessary
980                         # because the exit code of a pipeline is the exit
981                         # code of the right-most command, which isn't the
982                         # filter.
983                         #
984                         # These two tricks could be avoided by using a named
985                         # pipe to connect the standard error to $LPTELL. In
986                         # fact an early prototype of this script did just
987                         # that; however, the named pipe introduced a timing
988                         # problem. The processes that open a named pipe hang
989                         # until both ends of the pipe are opened. Cancelling
990                         # a request or disabling the printer often killed one
991                         # of the processes, causing the other process to hang
992                         # forever waiting for the other end of the pipe to
993                         # be opened.
994                         #####
995                         EXIT_CODE=${TMPPREFIX}e
996                         trap '' 1       # Let the filter handle a hangup
997                         trap '' 2 3     # and interrupts
998                         (
999                                 #####
1000                                 # Put the 0<${file} before the "eval" to keep
1001                                 # clever users from giving a file name that
1002                                 # evaluates as something to execute.
1003                                 #####
1004                                 0<${file} eval ${FILTER} 2>&1 1>&3
1005                                 echo $? >${EXIT_CODE}
1006                         ) | ${LPTELL} ${LPTELL_OPTS} ${printer}
1007                         trap 'catch_hangup; exit_code=129 exit 129' 1
1008                         trap 'catch_interrupt; exit_code=129 exit 129' 2 3
1009                         exit_code=`cat ${EXIT_CODE}`
1011                         if [ -n "${exit_code}" -a 0 -ne "${exit_code}" ]
1012                         then
1013                                 trap '' 15  # Avoid dying from disable
1014                                 sleep 4     # Give $LPTELL a chance to tell
1015                                 exit ${exit_code}
1016                         fi
1018                         if [ -n "${FF}" -a "no" = "${nofilebreak}" ]
1019                         then
1020                                 echo "${CR}${FF}\c"
1021                         fi
1023                 else
1025                         #####
1026                         #
1027                         # Don't complain about not being able to read
1028                         # a file on second and subsequent copies, unless
1029                         # we've not complained yet. This removes repeated
1030                         # messages about the same file yet reduces the
1031                         # chance that the user can remove a file and not
1032                         # know that we had trouble finding it.
1033                         #####
1034                         if [ "${i}" -le 1 -o -z "${badfileyet}" ]
1035                         then
1036                                 errmsg WARNING ${E_IP_BADFILE} \
1037                                         "cannot read file \"${file}\"" \
1038                                         "see if the file still exists and is readable,
1039                 or consult your system administrator;
1040                 printing continues"
1041                                 badfileyet=yes
1042                         fi
1044                 fi
1046         done
1047         i=`expr $i + 1`
1049 done
1051 if [ "no" = "${nobanner}" -a "${TERM}" = "PSR" ]
1052 then
1053         ( eval "${banner} ${banner_filter}" 2>&1 1>&3 ) \
1054                 | ${LPTELL} ${LPTELL_OPTS} ${printer}
1057 if [ -n "${exit_code}" -a 0 -ne "${exit_code}" ]
1058 then
1059         exit ${exit_code}
1062 #####
1064 # Always ensure the complete job ends with a ``formfeed'', to
1065 # let the next job start on a new page. (If someone wants to
1066 # concatenate files, they can give them in one job.)
1067 # So, if we haven't been putting out a ``formfeed'' between files,
1068 # it means we haven't followed the last file with a formfeed,
1069 # so we do it here.
1070 #####
1071 if [ -n "${FF}" -a "yes" = "${nofilebreak}" ]
1072 then
1073         echo "${CR}${FF}\c"
1076 ${DRAIN}
1078 exit_code=0 exit 0