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