#!/bin/sh # # Usage: atprint job user title copies options [filename] # # Extract the Appletalk path name for this printer. # upon a device URI of "atprint://zone/printername/printertype"... # # Don't forget to adjust $devicetypes and $formfeed for your needs! # ############################################################################# # # author: Thomas Kaiser # url: http://users.phg-online.de/tk/MOSXS/atprint.gz # date: 22 Mar 2003 (v.0.1.0) # ############################################################################# # # Non-Warranty: # This script comes with absolutely no warranty. # # Use at your own risk! # ############################################################################# # # Customizable settings: # # The devicetype variable specifies for which devices, to look for # (eg. LaserWriter, DeskWriter, ImageWriter). If you want to lookup more than # one device at a time, write them separated with colons, ie. # # devicetypes="LaserWriter:DeskWriter" # # For all devicetypes use "=" instead. But be warned: this will also find # macs, servers, serial numbers and the like devicetypes="LaserWriter:AFPServer" # specify whether or not to send an additional form feed (DeskWriters # seem to need this. TRUE means send the ff formfeed=FALSE # When you want to use this with Netatalk, then specify the path to # the $BINDIR (do a search for nbplkup, eg.). You might also want to set # $FullDeviceDiscovery to TRUE to let CUPS guess the correct PPD for the # devices by asking them for their "Product" name... NetatalkBinDir=/usr/bin FullDeviceDiscovery=TRUE ############################################################################# # # Some functions main() { # Processing the CUPS request. There exist 2 possibilities: Either CUPS # is asking us about device capabilities we can provide or it want us to # handle a print request and send the print job to specific device CollectAccountingData "$@" PrepareRequest # No arguments means show available devices and exit... if test $# = 0; then echo "network ${protocol} \"Unknown\" \"AppleTalk Devices via ${protocol}\"" LookupDevices | sort | uniq exit 0 fi # Handle the print request. First check whether the device is available if PrinterAvailable "${PrinterName}" ; then if test $# = 5; then # Get print file from stdin; copies have already been handled... NotifyCUPS "INFO: Sending to ${PrinterName}" cat | PrintAndAccount "${PrinterName}" NotifyCUPS "PAGE: 1 1" # TO DO: send pagecount queries else # Print file is on command-line and we have to handle copies ourselve... SpoolFile=$6 while [ ${NeededCopies} -gt 0 ]; do ActualCopy=`expr $4 + 1 - ${NeededCopies}` NotifyCUPS "INFO: Sending copy ${ActualCopy} to ${PrinterName}" PrintAndAccount "${PrinterName}" < "${SpoolFile}" NotifyCUPS "PAGE: ${CountOfCopies} $4" # TO DO: send pagecount queries NeededCopies=`expr ${NeededCopies} - 1` done fi # Eventually send an additional form feed (some DeskWriters seem to # need that) type=`GetAppleTalkType "${PrinterName}"` if [ "X${type}" = "XDeskWriter" ]; then test "X${formfeed}" = "XTRUE" && printf "\f" | PrintAndAccount "${PrinterName}" fi else NotifyCUPS "ERROR: Unable to get printer status for \"${PrinterName}\"" exit 1 fi } PrepareRequest() { # How are we called? protocol=`basename $0` # Let's have a look whether we are using Netatalk's or Darwin's # AppleTalk implementation case `uname -s` in Darwin) ZoneLookup="/usr/bin/atlookup -z" PrinterAvailable() { /usr/bin/atstatus "$1" >/dev/null } PrintAndAccount() { /usr/bin/atprint "$1" } NBPLookup() { /usr/bin/atlookup -a "$1" | grep -v "^# Found" } ATPErrMsg="ATPsndreq\:\ Operation\ timed\ out" CheckProductName() { echo "Unknown" } TotalPages() { echo ${CUPS_PrintSettingsPMTotalBeginPages} } ;; *) ZoneLookup="${NetatalkBinDir}/getzones" PrinterAvailable() { ${NetatalkBinDir}/papstatus -p "$1" >/dev/null } PrintAndAccount() { ${NetatalkBinDir}/pap -p "$1" } NBPLookup() { ${NetatalkBinDir}/nbplkup "$1" | \ perl -ne 'chomp; next if /^$/; m|^\s+(.+)\s+\d+\.\d+:|; my $entry = $1; $entry =~ s/\s+$//; print "$entry\n"' } ATPErrMsg="atp_rresp\:\ Connection\ timed\ out" CheckProductName() { # We'll try to ask the printer for its so called # "Product name" to let CUPS automatically assign # the right PPD file for the printer GuessedDeviceType="Unknown" if [ "$2" = "LaserWriter" -a "${FullDeviceDiscovery}" = "TRUE" ]; then if ${NetatalkBinDir}/papstatus -p "$1:$2@$3" >/dev/null 2>&1 then DeviceLookup=`echo -e "%%?BeginFeatureQuery: *Product\nstatusdict begin\nproduct print\nend\n%%?EndFeatureQuery: Unknown\n%%EOF" | ${NetatalkBinDir}/pap -p "$1:$2@$3" | grep "^\"(" | sed 's|^\"(||;s|)\"$||;'` if [ -n "${DeviceLookup}" ]; then GuessedDeviceType="${DeviceLookup}" fi fi fi echo "${GuessedDeviceType}" } TotalPages=1 ;; esac # redefine the internal field separator to parse the zone list # correctly IFS=" " } GetAppleTalkType() { echo "$1" | cut -d: -f2 | cut -d@ -f1 } LookupDevices() { # Fetch the zone list and do a lookup in every single zone for occurences # of type $devicetype zonelist="`GetZoneList`" # get a list of AppleTalk Devicetypes to look for OIFS=$IFS IFS=":" set ${devicetypes} IFS=$OIFS for devicetype in $@; do echo "${zonelist}" | while read zone; do NBPLookup "=:${devicetype}@${zone}" | while read nbpentry ; do name=`echo $nbpentry | awk -F: '{print $1}'` type=`echo $nbpentry | awk -F: '{print $2}'` model=`CheckProductName "${name}" "${type}" "${zone}"` echo -e "network ${protocol}://`EncodeDeviceURI "${zone}/${name}/${type}"` \"${model}\" \"${name}@${zone} (${protocol})\"" done & done done } GetZoneList() { # check whether we have to deal with zones eval ${ZoneLookup} >/dev/null if [ $? -eq 0 ]; then # okay, zones are available eval ${ZoneLookup} 2>&1 | sed "s|${ATPErrMsg}|*|;" else echo '*' fi } EncodeDeviceURI() { # We'll have to quote the names with an URL encoding (RFC 2396) echo "$@" | perl -ple 's|([^\w=\-:/@])|sprintf( "%%%02x", ord( $1))|ge' } DecodeDeviceURI() { # Decode the Device-URI echo "$@" | perl -ple 's/%([0-9A-Fa-f]{2})/chr(hex($1))/eg' | awk -F/ '{print $4 ":" $5 "@" $3}' } NotifyCUPS () { # sending message on stderr to keep CUPS informed echo -e "$*" >&2 } CollectAccountingData () { PrinterName=`DecodeDeviceURI ${DEVICE_URI}` Owner="$2" Title="$3" NeededCopies=$4 # parse the options passed from CUPS eval ParseCUPSOptions $5 } ParseCUPSOptions() { # We parse the CUPS options, delete occurences of "com.apple.print" in # their names, preprend the variable names with "CUPS_", define # them as variables and export them i="com\.apple\.print\." while [ $# -ge 1 ]; do VarName=`echo $1 | cut -d"=" -f1 | sed "s|^$i||g;s|\.[nb]\.$||g;s|\.||g"` VarValue=`echo $1 | cut -d"=" -f2 | sed "s|\ |\\\\\ |g"` eval echo CUPS_${VarName}=${VarValue} >>/home/tk/atprint.txt eval CUPS_${VarName}=${VarValue} eval export CUPS_${VarName} shift done } ############################################################################# # # Let's start to process the CUPS requests main "$@" exit 0