components/foomatic/filters/Solaris/netstandard_foomatic
author Vladimir Marek <Vladimir.Marek@oracle.com>
Wed, 22 Jun 2011 13:27:13 -0700
changeset 335 223d5bf98b72
permissions -rw-r--r--
7049357 Move foomatic-* stuff to Userland.

#
# 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 (c) 2011, Oracle and/or its affiliates. All rights reserved.
#

###########
##
## Network Standard printer interface program for foomatic.
##
###########

#####
# 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       
 
#####
# 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 "${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 "netstandard_foomatic: ${request_id}" " "
logger -p lpr.debug -t "netstandard_foomatic: ${request_id}" "INPUT"
logger -p lpr.debug -t "netstandard_foomatic: ${request_id}" "    printer : ${printer}"
logger -p lpr.debug -t "netstandard_foomatic: ${request_id}" "    request_id : ${request_id}"
logger -p lpr.debug -t "netstandard_foomatic: ${request_id}" "    user_name : ${user_name}"
logger -p lpr.debug -t "netstandard_foomatic: ${request_id}" "    title : ${title}"
logger -p lpr.debug -t "netstandard_foomatic: ${request_id}" "    copies : ${copies}"
logger -p lpr.debug -t "netstandard_foomatic: ${request_id}" "    option_list : ${option_list}"
logger -p lpr.debug -t "netstandard_foomatic: ${request_id}" "    files : ${files}"
logger -p lpr.debug -t "netstandard_foomatic: ${request_id}" "	 spooler_key ${SPOOLER_KEY}"

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

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

        nobanner )
                nobanner="yes"
                ;;

        nofilebreak )
                nofilebreak="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}`"
                ;;

	#
	# The IPP/PAPI attributes are handled by the foomatic-rip filter so
	# all we need to do here is ignore them so that they don't invoke the
	# "unrecognized option" message.
	#

	finishing=* | page-ranges=* | sides=* )
		;;
	number-up=* | orientation-requested=* | media=* )
		;;
	printer-resolution=* | print-quality=* )
		;;

        #####
        #
        # 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
                ;;

        * )
                ;;
        esac
done         

logger -p lpr.debug -t "netstandard_foomatic: ${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 netpr 
                        FILTER=
                ;;
                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
PPDFILTER=/usr/lib/lp/bin/foomatic-rip
PPDFILTERA="${PPDFILTER} ${request_id} ${user_name} \"${title}\" ${copies} \"${option_list}\""

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

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

logger -p lpr.debug -t "netstandard_foomatic: ${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

if [ "no" = "${nobanner}" ]
then
	eval "${banner} ${banner_filter}" 2>&1 1>${LPTMPDIR}/small_banner.$$ 
fi

#####
#
# Print banner page before job unless PSR
#
#####


if [ "no" = "${nobanner}" -a "${TERM}" != "PSR" ]
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 "netstandard_foomatic: ${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} eval ${FILTER} 2>&1 1>${tmpfile}
					echo $? > ${LPTMPDIR}/pr_eexit_code.$$
				) | ${LPTELL} ${LPTELL_OPTS} ${printer}

				exit_code=`cat ${LPTMPDIR}/pr_eexit_code.$$`
				logger -p lpr.debug -t "netstandard_foomatic: ${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 "netstandard_foomatic: ${request_id}" \
				"printfile : ${printfile}"
			
			#####
			# Print the file
			#####

			if [ -r "${printfile}" ]
			then
				(
logger -p lpr.debug -t "@1 netstandard_foomatic: printfile = ${printfile}" ""
logger -p lpr.debug -t "netstandard_foomatic: ${NETPR} ${printfile}" ""
					#eval ${NETPR} ${printfile} 2>&1
					cat ${printfile} | ${PPDFILTER} \
	      ${request_id} ${user_name} "${title}" ${copies} "${option_list}" \
						> ${tmpfilefoo} 2> /dev/null
					eval ${NETPR} ${tmpfilefoo} 2>&1
					echo $? > ${LPTMPDIR}/pr_eexit_code.$$
					/bin/rm -f ${tmpfilefoo}
				) | ${LPTELL} ${LPTELL_OPTS} ${printer}

				exit_code=`cat ${LPTMPDIR}/pr_eexit_code.$$`
				logger -p lpr.debug -t "@2 netstandard_foomatic: ${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
#
#####

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 "netstandard_foomatic: ${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 "netstandard_foomatic: ${request_id}" \
	"FINAL exit_code : ${exit_code}"

exit_clean ${exit_code}