OpenSolaris_b135/cmd/lp/model/tsol_netstandard

#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
# Use is subject to license terms.
#
#pragma ident	"%Z%%M%	%I%	%E% SMI"

###########
##
## Network Standard printer interface program.
##
###########

#####
# We can't do much except exit if spooler/scheduler
# cancels us.
#####
trap 'eval exit_clean 15' 15

####
#
# Send standard error messages to /dev/null rather than to
# the spooler. Avoids "Terminated" messages that shell puts out
# when gets SIGTERM. Save standard error so it can be used
# when we need it
####
exec 5>&2 2>/dev/null 3>&1

####
# set some global variables
####

: ${LPTMPDIR:=/tmp}
: ${SPOOLDIR:=/usr/spool/lp}
: ${LOCALPATH:=${SPOOLDIR}/bin}
PATH="/bin:/usr/bin:${LOCALPATH}"
exit_code=0


# ${LPTELL} is the name of a program that will send its
# standard input to the Spooler. It is used to forward
# the description of a printer fault to the Spooler,
# which uses it in an alert to the administrator.
#####
if [ ! -x "${LPTELL:=${LOCALPATH}/lp.tell}" ]
then
        fake_lptell () {
                header="no"
                while read line
                do
                        if [ "no" = "${header}" ]
                        then
                                errmsg ERROR ${E_IP_UNKNOWN} \
                "unknown printer/interface failure" \
                "consult your system administrator;
                reasons for failure (if any) follow:"
                                header=yes
                        fi
                        echo "${line}" >&2
                done
                return 1
        }
        LPTELL=fake_lptell
fi       
 
#####
# ${LPTSOLSEPARATOR} is the name of a program to put banner and trailer
# pages around the job.
#####
if [ -x ${LOCALPATH}/lp.tsol_separator ]
then
	LPTSOLSEPARATOR=${LOCALPATH}/lp.tsol_separator
else
	echo "${LOCALPATH}/lp.tsol_separator not found." >&2
	exit 1
fi

#####
# Error message formatter:
#
# Invoke as
#
#       errmsg severity message-number problem help
#                                                   
# where severity is "ERROR" or "WARNING", message-number is
# a unique identifier, problem is a short description of the
# problem, and help is a short suggestion for fixing the problem.
#####
 
LP_ERR_LABEL="UX:lp"
E_IP_ARGS=1
E_IP_OPTS=2
#E_IP_FILTER=3
E_IP_UNKNOWN=5
E_IP_BADFILE=6
E_IP_ERRORS=12 	# (in slow.filter)
 
errmsg () {

        case $1 in
        ERROR )
                sev="  ERROR";
                ;;
        WARNING )
                sev="WARNING";
                ;;
        esac

        echo "${LP_ERR_LABEL}:$2 ${sev}: $3
        TO FIX: $4" >&5
}                       
 
###########
##
## Check arguments
###########
 
parse () {
        echo "`expr \"$1\" : \"^[^=]*=\(.*\)\"`"
}         
 
#####
##
## Error Cleanup and Exit
##
#####

exit_clean()
{

	if [ -f "${LPTMPDIR}/pr_eexit_code.$$" ]
	then
		/bin/rm ${LPTMPDIR}/pr_eexit_code.$$
	fi

	if [ -f "${LPTMPDIR}/small_banner.$$" ]
	then
		/bin/rm ${LPTMPDIR}/small_banner.$$
	fi

	if [ -f "${LPTMPDIR}/banner.exit_code.$$" ]
	then
		/bin/rm ${LPTMPDIR}/banner.exit_code.$$
	fi

	if [ -f "${LPTMPDIR}/banner.errmsg.$$" ]
	then
		/bin/rm ${LPTMPDIR}/banner.errmsg.$$
	fi

	if [ -f "${tmpfile}" ]
	then
		/bin/rm "${tmpfile}"
	fi

	exit $1
}

#####
#
# This program is invoked as
#
# ${SPOOLDIR}/.../printer request-id user title copies options files...
#
# The first three arguments are simply reprinted on the banner page,
# the fourth (copies) is used to control the number of copies to print,
# the fifth (options) is a blank separated list (in a single argument)
# of user or Spooler supplied options (without the -o prefix),
# and the last arguments are the files to print.
#####
 
if [ $# -lt 5 ]
then

        errmsg ERROR ${E_IP_ARGS} \
                "wrong number of arguments to interface program" \
                "consult your system administrator"
        exit 1
fi      
 
printer=`basename $0`
request_id=$1
user_name=$2
title=$3
copies=$4
option_list=$5
 
shift 5
files="$*"


#
# debug sent to file if defined in /etc/syslog.conf
# syslog.conf entry: 
#	lpr.debug	/path/filename
#
logger -p lpr.debug -t "tsol_netstandard: ${request_id}" " "
logger -p lpr.debug -t "tsol_netstandard: ${request_id}" "INPUT"
logger -p lpr.debug -t "tsol_netstandard: ${request_id}" "    \
    printer : ${printer}"
logger -p lpr.debug -t "tsol_netstandard: ${request_id}" "    \
    request_id : ${request_id}"
logger -p lpr.debug -t "tsol_netstandard: ${request_id}" "    \
    user_name : ${user_name}"
logger -p lpr.debug -t "tsol_netstandard: ${request_id}" "    title : ${title}"
logger -p lpr.debug -t "tsol_netstandard: ${request_id}" "    \
    copies : ${copies}"
logger -p lpr.debug -t "tsol_netstandard: ${request_id}" "    \
    option_list : ${option_list}"
logger -p lpr.debug -t "tsol_netstandard: ${request_id}" "    files : ${files}"
logger -p lpr.debug -t "tsol_netstandard: ${request_id}" "	 \
    spooler_key ${SPOOLER_KEY}"

####
# default: do print a banner
####
nobanner=no
nolabels="no"
nofilebreak="no"
inlist=
data_file_flag=

for i in ${option_list}
do
        case "${inlist}${i}" in

        nobanner )
                nobanner="yes"
                ;;

        nofilebreak )
                nofilebreak="yes"
                ;;

	nolabels )
		nolabels="yes"
		;;

        #####
        #
        # If you want to add simple options (e.g. -o simple)
        # identify them here.
        #####
#       simple )
#               simple="yes"
# 		;;
                   
        cpi=pica )
                cpi=10
                ;;
        cpi=elite )
                cpi=12
                ;; 
        cpi=* )
                cpi=`parse ${i}`
                ;;
 
        lpi=* )
                lpi=`parse ${i}`
                ;;
 
        length=* )
                length=`parse ${i}`
                ;;
 
        width=* )
                width=`parse ${i}`
                ;;
        dest=* )
                dest="-d `parse ${i}`"
                ;;

        protocol=* )
                protocol="-P `parse ${i}`"
                ;;
        bsdctrl=* )
		controlfile="-c `parse ${i}`"
                ;;
        timeout=* )
                timeout="-t `parse ${i}`"
                ;;

        data-file-type=* )
                data_file_flag="-f `parse ${i}`"
                ;;

        #####
        #
        # If you want to add simple-value options (e.g. -o value=a)
        # identify them here.
        #####
#       value=* )
#		value=`parse ${i}`
#		;;

        #####
        #
        # If you want to add options that, 
        # take a list (e.g. -o lopt='a b c'), identif
        # them here and below (look for LOPT).
        #####
                                   
#	flist=* | lpd=* | options=* )
        flist=* | lpd=* )
#LOPT   stty=* | flist=* | lpd=* | lopt=* )    

                inlist=`expr "${inlist}${i}" : "^\([^=]*=\)"`
                case "${i}" in
                ${inlist}\'*\' )
                        item=`expr "${i}" : "^[^=]*='*\(.*\)'\$"`
                        ;;
                ${inlist}\' )
                        continue
                        ;;
                ${inlist}\'* )
                        item=`expr "${i}" : "^[^=]*='*\(.*\)\$"`
                        ;;
                ${inlist}* )
                        item=`expr "${i}" : "^[^=]*=\(.*\)\$"`
                        ;;
                *\' )
                        item=`expr "${i}" : "^\(.*\)'\$"`
                        ;;
                * )
                        item="${i}"
                        ;;
                esac

                #####
                #
                # We don't dare use "eval" because a clever user could
                # put something in an option value that we'd end up
                # exec'ing.
                #####
                case "${inlist}" in
                flist= )
                        flist="${flist} ${item}"
                        ;;
                lpd= )
                        lpd="${lpd} ${item}"
                        ;;
#LOPT		lopt= )
#LOPT                   lopt="${lopt} ${item}"
#LOPT			;;
#		options= )
#			options="${options} ${item}"
#			;;
                esac
                     
                case "${i}" in
                ${inlist}\'*\' )
                        inlist=
                        ;;
                ${inlist}\'* )
                        ;;
                *\' | ${inlist}* )
                        inlist=
                        ;;
                esac
                ;;

        * )
                errmsg WARNING ${E_IP_OPTS} \
                        "unrecognized \"-o ${i}\" option" \
                        "check the option, resubmit if necessary
                printing continues"
                ;;
        esac
done         

logger -p lpr.debug -t "tsol_netstandard: ${request_id}"  "term : ${TERM}"

if [ -z "${FILTER}" ]
then
        #####
        #
        # If no filter is being used, we use netpr to push the
	# file to the printer.
        # (QUOTES ARE IMPORTANT!)
        #####

        case "$TERM" in
                PS )
                        # make the "postscript" printers use cat
			# (TSOL banners are added during filtering, so we have
			# to use some filter.)
                        FILTER=/bin/cat
                ;;
                PSR )
                        # make the "reverse postscript" printers reverse the
                        # output and the use postio to talk to the printer
                        #FILTER="/usr/lib/lp/postscript/postreverse "
                        #FILTER=
                        FILTER="/usr/lib/lp/postscript/postreverse "
                ;;
                * )
                        # We don't know the type, so just assume that the
                        # input and output are the same. Use netpr.
                        #FILTER=/bin/cat
			FILTER=
                ;;
        esac
fi
 
####
# sets default value for ordering of data and control files with
# bsd protocol. Default: data files first. Administrator
# may set to control file first with lpadmin -o bsdctrl=first
####

banner_flag=""
case "${nobanner}" in
	yes )
		banner_flag="-b"
	;;
esac

NETPR="/usr/lib/lp/bin/netpr ${banner_flag} ${data_file_flag} \
	-I ${request_id} -U ${user_name} \
	-p ${printer} ${dest} -T \"${title}\"  \
	${timeout}  ${protocol} ${controlfile} "
LPTELL_OPTS="-l"        # netpr sends LaserWriter style messages back

logger -p lpr.debug -t "tsol_netstandard: ${request_id}" "NETPR= ${NETPR}"
logger -p lpr.debug -t "tsol_netstandard: ${request_id}" "filter : ${FILTER}"

node=`uname -n`
pid=$$
tmpfile=${LPTMPDIR}/${node}.${pid}

logger -p lpr.debug -t "tsol_netstandard: ${request_id}" "tmpfile : ${tmpfile}"
 
#####
#
# Set up filter for banner page
#
#####
banner_filter=
case "${TERM}" in
PS | PSR )
	banner_filter=" | /usr/lib/lp/postscript/postprint "
	LPTELL_OPTS="-l"
	;;
esac 

#####
#
# Build temporary file that is the banner page
#
#####
PAD="#####${NL}"
CR="\r"
NL="${CR}\n"
FF=

small_banner() {
        echo "${CR}\c"
        echo "${PAD}\c"
        echo "#####  User: ${user_name}${NL}\c"
        if [ -n "${title}" ]
        then
                echo "##### Title: ${title}${NL}\c"
        fi
        echo "#####  Date: `LANG=C date '+%a %H:%M %h %d, %Y'`${NL}\c"
        echo "#####   Job: ${request_id}${NL}\c"
        echo "${PAD}\c"
        if [ -n "${FF}" ]
        then
                echo "${CR}${FF}\c"
        fi
}

#####
#
# Doing small banner as we don't know what printer is out there
#
#####
banner=small_banner

## Skip this for PS/PSR printers, since lp.tsol_separator handles the banners
if [ "no" = "${nobanner}" -a "${TERM}" != "PSR" -a "${TERM}" != "PS" ]
then
	eval "${banner} ${banner_filter}" 2>&1 1>${LPTMPDIR}/small_banner.$$ 
fi

###########
##
## Surround the job by PostScript code to produce banner 
## and trailerpages and page headers and footers.
##
###########

BANNER_EXIT_CODE=${LPTMPDIR}/banner.exit_code.$$
echo 0 > ${BANNER_EXIT_CODE}
TSOLSEPARATOR_LOG=${LPTMPDIR}/banner.errmsg.$$

tsol_bannerize () {
	TSOLSEPARATOR_OPTS="-e ${TSOLSEPARATOR_LOG}"

	if [ "yes" = "${nolabels}" ]
	then
		TSOLSEPARATOR_OPTS="${TSOLSEPARATOR_OPTS} -l"
	fi

	if [ "yes" = "${nobanner}" ]
	then
		TSOLSEPARATOR_OPTS="${TSOLSEPARATOR_OPTS} -t /dev/null -b /dev/null"
	fi

	if [ "${TERM}" = "PSR" ]
	then
		TSOLSEPARATOR_OPTS="${TSOLSEPARATOR_OPTS} -r"
	fi

	# Get rid of the #, TAB and NL characters in the title
	tsol_title=`echo $title`
	tsol_title=`echo $tsol_title | sed 's/#//g'`

	logger -p lpr.debug -t "tsol_netstandard: ${request_id}" \
	    "banner command: ${LPTSOLSEPARATOR} ${TSOLSEPARATOR_OPTS} \
	    ${printer} ${request_id} ${user_name} \"${tsol_title}\" ${file}"
	${LPTSOLSEPARATOR} ${TSOLSEPARATOR_OPTS} ${printer} \
	    ${request_id} ${user_name} "${tsol_title}" ${file}

	echo $? > ${BANNER_EXIT_CODE}
	true
}

bannerize=tsol_bannerize

if [ "yes" = "${nobanner}" -a  "yes" = "${nolabels}" ]
then
	bannerize=cat
fi

if [ "${TERM}" != "PSR" -a "${TERM}" != "PS" ]
then
	bannerize=cat
fi

#####
#
# Print banner page before job unless PS or PSR.
#
#####

if [ "no" = "${nobanner}" -a "${TERM}" != "PSR" -a "${TERM}" != "PS" ]
then
	(
		eval ${NETPR} ${LPTMPDIR}/small_banner.$$ 2>&1
		echo $? > ${LPTMPDIR}/pr_eexit_code.$$
	) | ${LPTELL} ${LPTELL_OPTS} ${printer}

	exit_code=`cat ${LPTMPDIR}/pr_eexit_code.$$`
	logger -p lpr.debug -t "tsol_netstandard: ${request_id}"	\
		"banner page exit code : ${exit_code}"

fi

i=1
while [ $i -le $copies ]
do
        for file in ${files}
        do
                if [ -r "${file}" ]
                then

			if [ ! -z "${FILTER}" ]
			then
 				(
					#####
					# There is a filter, use it
					#
					# Put 0<${file} before the "eval" to keep
					# clever users from giving a file name that
					# evaluates as something to execute.
					# Redirect stderr to stdout so LPTELL will
					# get error messages from pipe. 
					#####
					0<${file} $bannerize | eval ${FILTER} 2>&1 1>${tmpfile}
					echo $? > ${LPTMPDIR}/pr_eexit_code.$$
				) | ${LPTELL} ${LPTELL_OPTS} ${printer}

				# if lp.tsol_separator had an error, send its logged
				# error message to LPTELL.
				banner_exit_code=`cat ${BANNER_EXIT_CODE}`
				if [ -n "${banner_exit_code}" -a \
					0 -ne "${banner_exit_code}" -a \
					 -n "${LPTELL}" -a \
					-r "${TSOLSEPARATOR_LOG}" ]
				then
					cat ${TSOLSEPARATOR_LOG} | ${LPTELL} ${printer}
					echo 77 > ${LPTMPDIR}/pr_eexit_code
				fi

				exit_code=`cat ${LPTMPDIR}/pr_eexit_code.$$` 
				logger -p lpr.debug \
				    -t "tsol_netstandard: ${request_id}" \
					"filter exit_code : ${exit_code}"

 			 	if [ -n "${exit_code}" ]
 				then
					if [ "${exit_code}" -eq 0 ]
					then
						printfile=${tmpfile}
					else
						####
						# The filter did not succeed, so don't try to print
						####
							printfile=
					fi
				fi

			else
				printfile=${file}
			fi

			logger -p lpr.debug \
			    -t "tsol_netstandard: ${request_id}" \
				"printfile : ${printfile}"
			
			#####
			# Print the file
			#####

			if [ -r "${printfile}" ]
			then
				(
					eval ${NETPR} ${printfile} 2>&1
					echo $? > ${LPTMPDIR}/pr_eexit_code.$$
				) | ${LPTELL} ${LPTELL_OPTS} ${printer}

				exit_code=`cat ${LPTMPDIR}/pr_eexit_code.$$` 
				logger -p lpr.debug \
				    -t "tsol_netstandard: ${request_id}" \
					"netpr exit_code : ${exit_code}"

#				if [ -f "${tmpfile}" ]
#				then
#					/bin/rm "${tmpfile}"
#				fi

				if [ -n "${exit_code}" ]
				then
					if [ "${exit_code}" -eq 0 ]
					then
						printone=yes
					else
						if [ "${exit_code}" -lt 128 ]
						then
							noprint=yes
						else
							retry=yes
						fi
					fi
				fi
				

			else	

				errmsg WARNING ${E_IP_BADFILE} \
				"cannot read temporary file \"${printfile}\""\
					"see if file still exists,
			or consult your system administrator;
			printing continues"

			fi
		else

                        #####
                        #
                        # Don't complain about not being able to read
                        # a file on second and subsequent copies, unless
                        # we've not complained yet. This removes repeated
                        # messages about the same file yet reduces the
                        # chance that the user can remove a file and not
                        # know that we had trouble finding it.
                        #####

                        if [ "${i}" -le 1 -o -z "${badfileyet}" ]
                        then
                                errmsg WARNING ${E_IP_BADFILE} \
                                        "cannot read file \"${file}\"" \
                                        "see if the file still exists and is readable,
                or consult your system administrator;
                printing continues"
                                badfileyet=yes
                        fi

		fi

# for file in ${files}
	done
	i=`expr $i + 1`
done

#####
#
# If printing in reverse order, print the banner page now
# Skip this for TSOL, since lp.tsol_separator handles the banners
#
#####

# 
# if [ "no" = "${nobanner}" -a "${TERM}" = "PSR" ]
# then
# (
# 	eval ${NETPR} ${LPTMPDIR}/small_banner.$$ 2>&1
#	echo $? > ${LPTMPDIR}/pr_eexit_code.$$
# ) | ${LPTELL} ${LPTELL_OPTS} ${printer}
# fi

exit_code=`cat ${LPTMPDIR}/pr_eexit_code.$$`
logger -p lpr.debug -t "tsol_netstandard: ${request_id}"     \
                "banner page exit code : ${exit_code}"

if [ -n "${printone}" -a -z "${retry}" -a -z "${noprint}" ]
then
       	exit_code=`expr 0`
else
        if [ -n "${retry}" -a -z "${printone}" -a -z "${noprint}" ]
        then
                exit_code=`expr 129`
        else
		exit_code=`expr 1`
	fi
fi

logger -p lpr.debug -t "tsol_netstandard: ${request_id}" \
	"FINAL exit_code : ${exit_code}"

exit_clean ${exit_code}