#!/bin/bash
#
# /usr/sbin/lprsetup
#
# Setup for lpdfilter entries in /etc/printcap
#
# Copyright (c) 2001 SuSE Gmbh Nuernberg, Germany.
#
# Author: Werner Fink <feedback@suse.de>

#
# Remove buildin printf and use the real one.
#
enable -n printf &> /dev/null

#
# Get our environment
#
type -p readpc &> /dev/null || export PATH=/usr/lib/lpdfilter/bin:${PATH}
type -p sed    &> /dev/null || { echo "The sed stream editor is required for lprsetup" 2>&1; exit 1; }
type -p zgrep  &> /dev/null || { echo "The zgrep pattern matching tool is required for lprsetup" 2>&1; exit 1; }
type -p zcat   &> /dev/null || { echo "The zcat expand compressed files tool is required for lprsetup" 2>&1; exit 1; }

interactive=false
date=$(date +%Y%m%d)

# Options
    daemon="LPRng"
     entry=""
    device=""
      host=""
	rp=""
      port=""
  redirect=""
      post=""
       pre=""
    driver=""
     model=""
       own=""
  gsdevice=""
drvpreload=""
     dvips=""
      size=""
    method="auto"
       dpi=""
     color=""
        br=""
        ty=""
        sf=""
    delete=""
  printcap="/etc/printcap"

# Some characters
TAB="$(echo -ne '\t')"

if test $# -gt 0 ; then
    function usage ()
    {
	echo "${0##*/}: Help and Usage of ${0##*/}
Operations:
       -add <entry>	add a new printer entry to $printcap
    -delete <entry>	delete a printer entry from $printcap
 -overwrite <entry>	overwrite a printer within $printcap

Daemons:
       -plp		PLP is used as printer daemon
       -bsd		BSDlpr is used as printer daemon
     -lprng		(default) the famous LPRng is used as printer daemon

Devices:
    -device <dev>	physical device file (like /dev/lp1)
  -redirect <name/file>	redirect to an other printer entry or
			full path to script file.
      -host <host>	the printer is a remote printer
        -rp <queue>	the queue name of the remote printer on port 515
      -port <port>	remote printer is not lpd but directly on port <port>

        -br <baud>	In case of a serial printer the baud rate <baud>
        -ty <string>	stty options to initialize serial printer device

Printer:
    -driver <name>	three types of drivers: upp, PS, <ghostscript-device>
       -own		in case of driver type upp, you have our own upp
			at /etc/lpdfilter/<entry>/
     -model <name>	in case of <ghostscript-device>: sub device or sub model
  -gsdevice <gs-device>	in case of upp, the used <ghostscript-device>
-drvpreload <file>	in case a preload file is required (e.g. stcolor.ps)
       -dpi <resol>	the resolution <resol>

Others:
      -size <paper>	Paper size which should be used
     -ascii		all input is given as ASCII
      -auto		determine the type of input
       -raw		send input directly to the printer
      -post <post> 	Path to post processing filter (after ghostscript)
       -pre <pre>	Path to pre processing filter (before ghostscript)
     -dvips <mode>	MetaFont mode for dvips
     -color		yes this is a color printer
        -sf		suppress form feed between jobs (default: do form feed)
	" 1>&2
    }
    function error ()
    {
	echo "${0##*/}: $@" 1>&2
	echo "${0##*/}: For a description use option -help" 1>&2
	exit 1
    }
    while test -n "$1" ; do
	case "$1" in
	--*)		a=$1; shift; set -- ${a#-} $@ ; continue ;;
	-plp)		daemon=PLP		; shift ;;
	-bsd)		daemon=BSDlpr		; shift ;;
	-lprng)		daemon=LPRng		; shift ;;
	-add)		entry=${2}	; shift ; shift ;;
	-delete)	delete=${2}	; shift ; shift ;;
	-overwrite)	delete=${2}	; shift ; shift ;
			entry=$delete			;;
	-device)	device=${2}	; shift ; shift ;;
	-host)		host=${2}	; shift ; shift ;;
	-rp)		rp=${2}		; shift ; shift ;;
	-port)		port=${2}	; shift ; shift ;;
	-redirect)	redirect=${2}	; shift ; shift ;;
	-post)		post=${2}	; shift ; shift ;;
	-pre)		pre=${2}	; shift ; shift ;;
	-driver)	driver=${2}	; shift ; shift ;;
	-own)		own=yes			; shift ;;
	-model)		model=${2}	; shift ; shift ;;
	-gsdevice)	gsdevice=${2}	; shift ; shift ;;
	-drvpreload)	drvpreload=${2}	; shift ; shift ;;
	-dvips)		dvips=${2}	; shift ; shift ;;
	-size)		size=${2}	; shift ; shift ;;
	-dpi)		dpi=${2}	; shift ; shift ;;
	-color)		color=yes	;	  shift ;;
	-br)		br=${2}		; shift ; shift ;;
	-ty)		ty=${2}		; shift ; shift ;;
	-sf)		sf=yes			; shift ;;
	-method)	method=${2}	; shift ; shift ;;
	-ascii)		method=ascii		; shift ;;
	-auto)		method=auto		; shift ;;
	-raw)		method=raw		; shift ;;
	-printcap)	printcap=${2}	; shift ; shift ;;
	-help)		usage		; exit 0; shift ;;
	*)		error "Unknown option $1"
	esac
    done
    # Check some options
    test -z "$entry" -a -z "$delete"			&& error "What should be done: -add | -overwrite | -delete"
    if test -n "$entry" ; then
	test "$own" = "yes" -a "$driver" != "upp"	&& error "\`-own' requires \`-driver upp'"
	test -z "$own" -a "$driver" = "upp" -a -z "$gsdevice" \
							&& error "\`-driver upp' requires \`-own' or \`-gsdevice <gs device>'"
	test -n "$device" -a -n "$host"			&& error "Please \`-device $device' OR \`-host $host'"
	test -z "$redirect" -a -z "$device" -a -z "$host" \
							&& error "\`-device <device>' OR \`-host <host>' required"
	test -n "$br" -a -z "$ty"			&& error "Serial interface: \`-ty \"<stty settings>\"' is required"
	test -n "$host" -a \( -z "$rp" -a -z "$port" \)	&& error "\`-host $host' requires remote printer queue \`rp <queue>
                     or remote printer port \`port <port>'"
	if test -z "$own" -a "$method" != "raw" ; then
	    test -z "$size"				&& error "Printer paper size is required, use \`-size <size>'"
	    test -z "$dpi"				&& error "Printer resolution is required, use \`-dpi <dpi>'"
	fi
    fi
else
    # No optin means interactive
    interactive=true

    # Load sh.lib
    . /usr/lib/lpdfilter/global/sh.lib
    . /usr/lib/lpdfilter/global/setup.lib

    # Run geometry check first
    set_geometry
    trap "set_geometry" SIGWINCH

    # Temporary text file
    tmpfile=$(mktemp ${TMPDIR:-/tmp}/lprsetup.XXXXXX) ||  exit 1

    # Alternated screen
    alternate_screen_on "rm -f $tmpfile"

    # Greetings
    greetings
fi

while true ; do
    all=""
    entries=""
    while read -r line ; do
	line=${line%%[:|]*}
	test -z "$all" && all="$line" || all="$all${TAB}$line"
    done < <(grep -a -E "^[^#$TAB]" $printcap 2>/dev/null)
    for e in $all ; do
	x="$(readpc $e $printcap 2> /dev/null)"
	case "$x" in
	*:cm=lpdfilter*:*) test -z "$entries" && entries=$e || entries="$entries${TAB}$e"
	esac
    done
    unset e x line

    if test $interactive = true ; then
	run_dialog --menu "\\nHandle lpdfilter entries\\n" \
	    13 $((COLS-10)) 4 \
	    "EXIT"	'Exit lprsetup' \
	    "LISTING"	'List all entries for lpdfilter' \
	    "ENTRY"	'Handle a (new) lpdfilter entry' \
	    "DELETE"	'Remove a lpdfilter entry' || exit 0

	case $result in
	LISTING)	listing ;;
	ENTRY)		handle  ;;
	DELETE)		delete  ;;
	*)		exit 0  ;;
	esac
    fi

    # Check if we have an entry
    for found in $entries ; do
	test "$found" = "$delete" && break
	found=""
    done

    # Here we delete choosen lpdfilter entry
    if test -n "$delete" ; then
	if test -z "$found" ; then
	    if test $interactive != true ; then
		echo "No lpdfilter entry $delete found in $printcap" 2>&1
		exit 1
	    else
		continue;
	    fi
	fi
	touch $printcap || { echo "No access to $printcap" 2>&1; exit 1; }
	chown root:lp $printcap || { echo "No access to $printcap" 2>&1; exit 1; }
	chmod 0644    $printcap || { echo "No access to $printcap" 2>&1; exit 1; }
	tmppc=$(mktemp ${TMPDIR:-/tmp}/printcap.XXXXXX) || exit 1
	sed "/^$delete[:|]/,/^${TAB}:.*:\$/d" < $printcap > $tmppc
	cp $printcap $printcap-$date
	cat $tmppc > $printcap
	rm -f $tmppc
	test -n "$delete" && rm -rf /etc/lpdfilter/$delete
	test -n "$delete" && rm -rf /var/spool/lpd/$delete
    fi

    # Check if we have an entry
    for found in $all ; do
	test "$found" = "$entry" && break
	found=""
    done
    test "$delete" = "$found" && found=""

    if test -n "$entry" -a -z "$found" ; then
	# Create configured directories
	mkdir -p /etc/lpdfilter/$entry
	mkdir -p /var/spool/lpd/$entry

	if test -n "$redirect" ; then
	    device=/dev/null
	    case "$redirect" in
	    /*) test -x "$redirect" || { echo "Warning: script $redirect does not exist." 1>&2; }
		# LPRng versus BSDlpr
		case "$daemon" in
		LPRng|PLP)
		    device="|$redirect"
		    redirect=""
		    ;;
		BSDlpr)
		    ln -sf "$redirect"  /etc/lpdfilter/${entry}/
		    redirect=""
		esac
	    esac
	fi
	if test -n "$post" ; then
	    ln -sf /usr/lib/lpdfilter/post/$post /etc/lpdfilter/${entry}/post
	fi
	if test -n "$pre" ; then
	    ln -sf /usr/lib/lpdfilter/pre/$pre	 /etc/lpdfilter/${entry}/pre
	fi

	# Handle ghostscript driver/device
	if test "$driver" = "upp" ; then
	    if test -z "$own" ; then
		# Here we use the upp file as information for gs
		echo "-sDEVICE=$gsdevice"	    >  /etc/lpdfilter/${entry}/upp
		test -n "$model" && echo "${model}" >> /etc/lpdfilter/${entry}/upp
		test -n "$drvpreload" && \
		echo "-c \"(${drvpreload}) findlibfile { pop run } if\"" \
						    >> /etc/lpdfilter/${entry}/upp
		test -n "$size"  && echo "-sPAPERSIZE=${size}" \
						    >> /etc/lpdfilter/${entry}/upp
		test -n "$dpi"   && echo "-r$dpi"   >> /etc/lpdfilter/${entry}/upp
		drvpreload=""
		size=""
		dpi=""
	    fi
	else
	    # Here we use the cm entry in printcap
	    model=${model#*=}
	    driver="${driver}${model:+_$model}"
	fi
	if test "$color" = "color" -o "$color" = "yes" ; then
	    color=yes
	else
	    color=no
	fi

	# Handle printcap
	touch $printcap || { echo "No access to $printcap" 2>&1; exit 1; }
	chown root:lp $printcap || { echo "No access to $printcap" 2>&1; exit 1; }
	chmod 0644    $printcap || { echo "No access to $printcap" 2>&1; exit 1; }
	tmppc=$(mktemp ${TMPDIR:-/tmp}/printcap.XXXXXX) || exit 1
	cat $printcap > $tmppc

	# Remember original stdout and set stdout to our new printcap
	exec 3>&1 1>>$tmppc

	echo    "$entry:\\"
	echo -n "${TAB}:cm=lpdfilter"
	echo -n     "${driver:+" drv=$driver"}"
	if test "$driver" != "upp" ; then
	    echo -n     "${size:+" size=$size"}"
	    echo -n     "${dpi:+" dpi=$dpi"}"
	    echo -n     "${drvpreload:+" drvpreload=$dpi"}"
	fi
	echo -n     "${method:+" method=$method"}"
	echo -n     "${feature:+" feature=$feature"}"
	echo -n     "${color:+" color=$color"}"
	echo -n     "${duplex:+" duplex=$duplex "}"
	echo -n     "${redirect:+" redirect=$redirect"}"
	echo -n     "${banner:+" banner=$banner"}"
	echo -n     "${acct:+" acct=$acct"}"
	echo -n     "${dvips:+" dvips=$dvips"}"
	echo    ":\\"
	if test -n "$host" ; then
	    # LPRng versus BSDlpr
	    case "$daemon" in
	    LPRng)
		if test -n "$port" ; then
		    echo "${TAB}:lp=${host}%${port}:\\"
		else
		    echo "${TAB}:lp=${rp:-lp}@${host}:\\"
		fi
		;;
	    BSDlpr|PLP)
		test -z "$port" || { echo "Warning: BSDlpr/PLP do not support port tag." 1>&2; }
		echo "${TAB}:lp=:\\"
		echo "${TAB}:rm=${host}:\\"
		echo "${TAB}:rp=${rp:-lp}:\\"
	    esac
	else
	    echo "${TAB}:lp=$device:\\"
	    if test -n "$br" ; then
		 echo "${TAB}:br#${br}:\\"
		 echo "${TAB}:ty=${ty:-"ixon -imaxbel -ixany -ixoff -crtscts"}:\\"
	    fi
	fi
	echo    "${TAB}:sd=/var/spool/lpd/$entry:\\"
	echo    "${TAB}:lf=/var/spool/lpd/$entry/log:\\"
	echo    "${TAB}:af=/var/spool/lpd/$entry/acct:\\"
	case "$daemon" in
	LPRng)
	    if test -n "$host" ; then
		if test "$method" != "raw" ; then
		    echo "${TAB}:if=/usr/lib/lpdfilter/bin/if:\\"
		    echo "${TAB}:ar:lpd_bounce:lpr_bounce:force_localhost@:\\"
		else
		    echo "${TAB}:ar:force_localhost@:\\"
		fi
	    else
		echo "${TAB}:if=/usr/lib/lpdfilter/bin/if:\\"
		echo "${TAB}:la@:\\"
	    fi
	    ;;
	BSDlpr|PLP)
	    if test -n "$host" ; then
		echo "${TAB}:ar:bk:mx#0:\\"
	    else
		echo "${TAB}:if=/usr/lib/lpdfilter/bin/if:\\"
		echo "${TAB}:la@:mx#0:\\"
	    fi
	    ;;
	esac
	# last line and NO backslash
	case "$daemon" in
	LPRng)
	    # LPRng suppresses ff by default
	    if test "$sf" = "yes" ; then
		echo "${TAB}:tr=:cl:lk:sh:"
	    else
		echo "${TAB}:tr=:cl:lk:sh:ff_separator:fq:"
	    fi
	    ;;
	BSDlpr|PLP)
	    if test "$sf" = "yes" ; then
		echo "${TAB}:tr=:cl:sh:sf:"
	    else
		echo "${TAB}:tr=:cl:sh:"
	    fi
	    ;;
	esac
	# Close new printcap and set stdout back
	exec 1>&- 1>&3 3>&-

	# Handle printcap
	test -s $printcap-$date || cp $printcap $printcap-$date
	cat $tmppc > $printcap
	rm -f $tmppc

	# Generate spool files
	: > /var/spool/lpd/$entry/log
	: > /var/spool/lpd/$entry/acct
	: > /var/spool/lpd/$entry/lock
	: > /var/spool/lpd/$entry/status
	chown -R lp:lp	/var/spool/lpd/$entry
	case "$daemon" in
	LPRng)
	    chmod 0700	/var/spool/lpd/$entry
	    chmod 0600	/var/spool/lpd/$entry/log
	    chmod 0600	/var/spool/lpd/$entry/acct
	    chmod 0600	/var/spool/lpd/$entry/lock
	    chmod 0600	/var/spool/lpd/$entry/status
	    ;;
	BSDlpr|PLP)
	    chmod 0750	/var/spool/lpd/$entry
	    chmod 0660	/var/spool/lpd/$entry/log
	    chmod 0660	/var/spool/lpd/$entry/acct
	    chmod 0640	/var/spool/lpd/$entry/lock
	    chmod 0640	/var/spool/lpd/$entry/status
	    ;;
	esac

	chown root:lp /etc/lpdfilter/$entry
	chmod 0755    /etc/lpdfilter/$entry
	if test ! -s  /etc/lpdfilter/$entry/conf ; then
	    cp /usr/lib/lpdfilter/global/optional.options /etc/lpdfilter/$entry/conf
	    chmod 0644 /etc/lpdfilter/$entry/conf
	fi
    fi
    #
    # Handle a (new) delete printer entry or delete one
    #
    test $interactive != true && break

     entry=""
    device=""
     model=""
      host=""
        rp=""
      port=""
  redirect=""
      post=""
       pre=""
    driver=""
  gsdevice=""
drvpreload=""
     dvips=""
      size=""
    method="auto"
       dpi=""
     color=""
        br=""
        ty=""
        sf=""
    delete=""
done
