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