8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / lp / model / tsol_standard
blobfe972a41484b903225d0caa2b7923086a71889a0
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 # Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23 # Use is subject to license terms.
25 #pragma ident   "%Z%%M% %I%     %E% SMI"
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 # ${LPTSOLSEPARATOR} is the name of a program to put banner and trailer
167 # pages around the job.
168 #####
169 if [ -x ${LOCALPATH}/lp.tsol_separator ]
170 then
171         LPTSOLSEPARATOR=${LOCALPATH}/lp.tsol_separator
172 else
173         echo "${LOCALPATH}/lp.tsol_separator not found." >&2
174         exit 1
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 #####
186 if [ ! -x "${LPCAT:=${LOCALPATH}/lp.cat}" ]
187 then
188         LPCAT="cat"
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 #####
199 if [ ! -x "${LPSET:=${LOCALPATH}/lp.set}" ]
200 then
201         fake_lpset () {
202                 echo H V W L S >&2
203                 false
204         }
205         LPSET=fake_lpset
208 internal_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
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
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.
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 #####
284 TPUT=tput
286 #####
287 # Error message formatter:
289 # Invoke as
291 #       errmsg severity message-number problem help
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 #####
298 LP_ERR_LABEL="UX:lp"
300 E_IP_ARGS=1
301 E_IP_OPTS=2
302 #E_IP_FILTER=3
303 E_IP_STTY=4
304 E_IP_UNKNOWN=5
305 E_IP_BADFILE=6
306 E_IP_BADCHARSET=7
307 E_IP_BADCPI=8
308 E_IP_BADLPI=9
309 E_IP_BADWIDTH=10
310 E_IP_BADLENGTH=11
311 E_IP_ERRORS=12          # (in slow.filter)
313 errmsg () {
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
328 ###########
330 ## Check arguments
331 ###########
333 parse () {
334         echo "`expr \"$1\" : \"^[^=]*=\(.*\)\"`"
337 #####
339 # This program is invoked as
341 # ${SPOOLDIR}/.../printer request-id user title copies options files...
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 #####
350 if [ $# -lt 5 ]
351 then
352         errmsg ERROR ${E_IP_ARGS} \
353                 "wrong number of arguments to interface program" \
354                 "consult your system administrator"
355         exit 1
358 printer=`basename $0`
359 request_id=$1
360 user_name=$2
361 title=$3
362 copies=$4
363 option_list=$5
365 shift 5
366 files="$*"
368 nobanner="no"
369 nofilebreak="no"
370 nolabels="no"
371 stty=
373 inlist=
374 for i in ${option_list}
376         case "${inlist}${i}" in
379         nobanner )
380                 nobanner="yes"
381                 ;;
383         nofilebreak )
384                 nofilebreak="yes"
385                 ;;
387         nolabels )
388                 nolabels="yes"
389                 ;;
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 #               ;;
401         cpi=pica )
402                 cpi=10
403                 ;;
404         cpi=elite )
405                 cpi=12
406                 ;;
407         cpi=* )
408                 cpi=`parse ${i}`
409                 ;;
411         lpi=* )
412                 lpi=`parse ${i}`
413                 ;;
415         length=* )
416                 length=`parse ${i}`
417                 ;;
419         width=* )
420                 width=`parse ${i}`
421                 ;;
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 #               ;;
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=* )
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
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
485                 case "${i}" in
486                 ${inlist}\'*\' )
487                         inlist=
488                         ;;
489                 ${inlist}\'* )
490                         ;;
491                 *\' | ${inlist}* )
492                         inlist=
493                         ;;
494                 esac
495                 ;;
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
504 done
506 #####
508 # Additional ``parameters'' are passed via Shell environment
509 # variables:
511 #       TERM    The printer type (used for Terminfo access)
512 #       CHARSET The character set to choose
513 #       FILTER  The filter to run
514 #####
516 #####
517 # Set defaults for unset variables.
518 #####
520 : ${TERM:=unknown}
521 tput lines 1>/dev/null 2>&1 || TPUT=:
523 : ${CHARSET:=cs0}
525 if [ -z "${FILTER}" ]
526 then
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
567 ###########
569 ## Initialize the printer port
570 ###########
572 #####
574 # SERIAL PORTS:
575 # Initialize everything.
577 # PARALLEL PORTS:
578 # Don't initialize baud rate.
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.
584 # Another point: The output must be a ``tty'' device. If not, don't
585 # bother with any of this.
586 #####
587 stty1= stty2=
588 tty 0<&1 1>/dev/null 2>&1 && {
590         #####
591         #
592         # First set the default parameters,
593         # then the requested parameters.
594         #####
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
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
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
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}
662 ###########
664 ## Initialize the physical printer (Part I).
665 ## Here we bring the printer to a sane state and set the page size.
666 ###########
668 ##########
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 ##########
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 #####
688 CR=`${TPUT} cr`
689 [ -z "${CR}" ] && CR="\r"
691 FF=`${TPUT} ff`
693 NL="${CR}\n"
695 lines=`${TPUT} lines`
696 [ -z "${lines}" -o 0 -ge "${lines}" ] && lines=66
698 cols=`${TPUT} cols`
699 [ -z "${cols}" -o 0 -ge "${cols}" ] && cols=132
701 #####
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
709 # "tput init" will return an "^M" in many cases to "stdout", i.e., printer!
710 # This creates problems for some PS printers
712 if [ "${TERM}" = "PS" -o "${TERM}" = "PSR" ]
713 then
714         :
715 elif ${TPUT} init 2>/dev/null
716 then
717         :
718 else
719         pgm=`${TPUT} iprog`
720         if [ -x "${pgm}" ]
721         then
722                 eval ${pgm}
723         fi
725         ${TPUT} is1
726         ${TPUT} is2
728         tabset=
729         if [ "8" != "`${TPUT} it`" ]
730         then
731                 stty tab3 0<&1 1>/dev/null 2>&1
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
743         file=`${TPUT} if`
744         if [ "${tabset}" != "${file}" -a -r "${file}" ]
745         then
746                 cat -s "${file}"
747         fi
749         ${TPUT} is3
750         echo "${CR}\c"
752 [ -n "${stty2}" ] && stty ${stty2} 0<&1
754 #####
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 #####
759 internal_lpset "${cpi}" "${lpi}" "${width}" "${length}" ""
761 #####
763 # The banner page (and cancellation page) will
764 # use double width characters if they're available.
765 #####
766 WIDE_CS=`${TPUT} swidm 2>/dev/null` && NORM_CS=`${TPUT} rwidm 2>/dev/null`
767 PAD="#####${NL}"
769 #####
771 # Some printers need to have the banner page filtered.
772 #####
773 case "${TERM}" in
775 PS | PSR )
776         banner_filter="/usr/lib/lp/postscript/postprint | /usr/lib/lp/postscript/postio"
777         LPTELL_OPTS="-l"
778         ;;
780 esac
781 if [ -n "${banner_filter}" ]
782 then
783         banner_filter="| ${banner_filter}"
786 #####
788 # Now that the printer is ready for printing, we're able
789 # to record on paper a cancellation.
790 #####
792 cancel_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"
799 canceled () {
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
813 trap 'eval canceled ${banner_filter}; exit_code=0 exit' 15
816 ###########
818 ## Print the banner page
819 ###########
821 #####
823 # You may want to change the following code to get a custom banner.
824 #####
826 regular_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
851 small_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
868 if [ "${width:-${cols}}" -lt "${MAX_COLS_SMALL_BANNER}" ]
869 then
870         banner=small_banner
871 else
872         banner=regular_banner
875 ## Skip this for PS/PSR in TSOL, since lp.tsol_separator handles the banners
876 if [ "no" = "${nobanner}" -a "${TERM}" != "PSR" -a "${TERM}" != "PS" ]
877 then
878         ( eval "${banner} ${banner_filter}" 2>&1 1>&3 ) \
879                 | ${LPTELL} ${LPTELL_OPTS} ${printer}
882 ###########
884 ## Surround the job by PostScript code to produce banner 
885 ## and trailerpages and page headers and footers.
887 ###########
889 BANNER_EXIT_CODE=${TMPPREFIX}.banner.exit_code
890 echo 0 > ${BANNER_EXIT_CODE}
891 TSOLSEPARATOR_LOG=${TMPPREFIX}.banner.errmsg
893 tsol_bannerize () {
894         TSOLSEPARATOR_OPTS="-e ${TSOLSEPARATOR_LOG}"
896         if [ "yes" = "${nolabels}" ]
897         then
898                 TSOLSEPARATOR_OPTS="${TSOLSEPARATOR_OPTS} -l"
899         fi
901         if [ "yes" = "${nobanner}" ]
902         then
903                 TSOLSEPARATOR_OPTS="${TSOLSEPARATOR_OPTS} -t /dev/null -b /dev/null"
904         fi
906         if [ "${TERM}" = "PSR" ]
907         then
908                 TSOLSEPARATOR_OPTS="${TSOLSEPARATOR_OPTS} -r"
909         fi
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'`
915         LC_TIME=C ${LPTSOLSEPARATOR} ${TSOLSEPARATOR_OPTS} "${printer}" \
916             "${request_id}" "${user_name}" "${tsol_title}" "${file}"
917         echo $? > ${BANNER_EXIT_CODE}
918         true
921 bannerize=tsol_bannerize
923 if [ "yes" = "${nobanner}" -a  "yes" = "${nolabels}" ]
924 then
925         bannerize=cat
928 if [ "${TERM}" != "PSR" -a "${TERM}" != "PS" ]
929 then
930         bannerize=cat
934 ###########
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 ###########
944 internal_lpset "" "" "" "" "${CHARSET}"
946 ###########
948 ## Print some copies of the file(s)
949 ###########
951 #####
953 # The protocol between the interface program and the Spooler
954 # is fairly simple:
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.
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.
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.)
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.
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:
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.
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.
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.
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).
1020 #####
1022 badfileyet=
1024 while [ $i -le $copies ]
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}
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
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}`
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
1100                         if [ -n "${FF}" -a "no" = "${nofilebreak}" ]
1101                         then
1102                                 echo "${CR}${FF}\c"
1103                         fi
1105                 else
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
1126                 fi
1128         done
1129         i=`expr $i + 1`
1131 done
1133 # Skip this for TSOL, since lp.tsol_separator handles the banners
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
1141 if [ -n "${exit_code}" -a 0 -ne "${exit_code}" ]
1142 then
1143         exit ${exit_code}
1146 #####
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 #####
1155 if [ -n "${FF}" -a "yes" = "${nofilebreak}" ]
1156 then
1157         echo "${CR}${FF}\c"
1160 ${DRAIN}
1162 exit_code=0 exit 0