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