[comp.sources.misc] v08i013: Updated servercomm

allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (08/24/89)

Posting-number: Volume 8, Issue 13
Submitted-by: dinah@krebs.bcm.tmc.edu (Dinah Anderson)
Archive-name: servercomm2

Here is an updated version of servercomm. I modified the make file
to not make the spool directories and modify the printcap since the
make file wanted to do this everytime you installed the software. I
also fixed the program to work correctly with the Sun pty's and a bridge
comm. terminal server. The previous version did not work with SunOS 4.0 and
postscript files properly.


#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	Makefile
#	README
#	example
#	hello.ps
#	servercomm.8l
#	servercomm.c
# This archive created: Wed Aug 23 12:04:23 1989
export PATH; PATH=/bin:$PATH
echo shar: extracting "'Makefile'" '(4422 characters)'
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
sed 's/^	X//' << \SHAR_EOF > 'Makefile'
	X#
	X# Wright State University Remote LaserWriter Kit
	X# John Sloan <jsloan%SPOTS.Wright.EDU@@Relay.CS.NET>
	X# $Revision: 1.3 $
	X# $Date: 89/08/06 02:27:15 $
	X#
	X# Modified by Dinah Anderson <dinah@bcm.tmc.edu>
	X# Baylor College of Medicine
	X# 89/8/23
	X#
	X
	X# C Compiler flags (if any)
	XCFLAGS=-DBRIDGE
	X
	X# Printcap name of remote LaserWriter
	XPRINTER=motc
	X
	X# Local LaserWriter spool directory (must differ from NEWSPOOLDIR)
	XPSSPOOLDIR=/usr/spool/lpd/local
	X
	X# New remote LaserWriter spool directory (must differ from PSSPOOLDIR)
	XNEWSPOOLDIR=/usr/spool/lpd/motc
	X
	X# Original Transcript software directory (must differ from NEWLIBDIR)
	XPSLIBDIR=/usr/local/lib/ps
	X
	X# New remote Transcript filters directory (must differ from PSLIBDIR)
	XNEWLIBDIR=/usr/motc
	X
	X# Network name of host computer handling spooling to communication server
	X# This is the computer on which you are installing this software
	XHOST="`hostname`"
	X
	X# Network name of host communications server
	XSERVER=128.249.4.40
	X
	X# Port number for LaserWriter on host
	XPORT=23
	X
	X# Master pseudo-terminal (typically /dev/ptyXX, where XX=[pqrs][0-f])
	X# You may roll your own (as we do) with /etc/mknod
	X# Owner should be daemon and mode should be 666
	X# Device should not appear in /etc/ttys as login enabled (with getty)
	XPTY=/dev/ptyr4
	X
	X# Slave pseudo-terminal (typically /dev/ttyXX)
	X# You may roll your own (as we do) with /etc/mknod
	X# Owner should be daemon and mode should be 666
	X# Device should not appear in /etc/ttys as login enabled (with getty)
	XTTY=/dev/ttyr4
	X
	X# Location of servercomm(8l) man page
	XMANDIR=/usr/man/manl
	X
	X#########################################################################
	X
	Xall:	servercomm filters printcap printcap.remote 
	X
	Xinstall: all ${NEWLIBDIR}/servercomm ${MANDIR} servercomm.8l
	X	cp /dev/null ${NEWLIBDIR}/${PRINTER}
	X	cp servercomm.8l ${MANDIR}
	X	chmod 644 ${MANDIR}/servercomm.8l
	X
	Xclean:
	X	rm -if diffs printcap printcap.remote 
	X
	Xbackout: clean
	X	rm -rif ${NEWSPOOLDIR} ${NEWLIBDIR}
	X
	Xservercomm:	servercomm.c
	X	cc ${CFLAGS} -O -o servercomm servercomm.c
	X
	X${NEWLIBDIR}/servercomm: servercomm
	X	strip servercomm
	X	mv servercomm ${NEWLIBDIR}
	X	chmod 755 ${NEWLIBDIR}/servercomm
	X
	Xtest:	debug hello.ps
	X	debug -v -x -h ${SERVER} -p ${PORT} -t ${PTY} ${TTY} -f ${NEWLIBDIR}/pscomm -P ${PRINTER} -p psif /dev/tty < hello.ps
	X#debug -v -x -h ${SERVER} -p ${PORT} -t ${PTY} ${TTY} -f ${PSLIBDIR}/pscomm -P ${PRINTER} -p psif /dev/tty < hello.ps
	X	
	Xdebug:	servercomm.c
	X	cc ${CFLAGS} -g -DDEBUG -DDUMP -o debug servercomm.c
	X
	Xfilters: ${NEWLIBDIR} ${NEWLIBDIR}/psint.sh
	X	ln ${NEWLIBDIR}/psint.sh ${NEWLIBDIR}/psof
	X	ln ${NEWLIBDIR}/psint.sh ${NEWLIBDIR}/psif
	X	ln ${NEWLIBDIR}/psint.sh ${NEWLIBDIR}/psgf
	X	ln ${NEWLIBDIR}/psint.sh ${NEWLIBDIR}/psnf
	X	ln ${NEWLIBDIR}/psint.sh ${NEWLIBDIR}/pstf
	X	ln ${NEWLIBDIR}/psint.sh ${NEWLIBDIR}/psrf
	X	ln ${NEWLIBDIR}/psint.sh ${NEWLIBDIR}/psvf
	X	ln ${NEWLIBDIR}/psint.sh ${NEWLIBDIR}/pscf
	X	ln ${NEWLIBDIR}/psint.sh ${NEWLIBDIR}/psdf
	X
	X${NEWLIBDIR}/psint.sh: ${PSLIBDIR}/psint.sh ${NEWLIBDIR} diffs
	X	cp ${PSLIBDIR}/psint.sh ${NEWLIBDIR}
	X	chmod 755 ${NEWLIBDIR}/psint.sh
	X	patch ${NEWLIBDIR}/psint.sh diffs
	X
	X${NEWLIBDIR}:
	X	mkdir ${NEWLIBDIR}
	X	chmod 755 ${NEWLIBDIR}
	X
	Xdiffs:
	X	echo "67c67,68" > diffs
	X	echo "< comm=\"\$$PSCOMM -P \$$pname -p \$$prog -n \$$user -h \$$host \$$afile\"" >> diffs
	X	echo "---" >> diffs
	X	echo "> filter=\"\$$PSCOMM -P \$$pname -p \$$prog -n \$$user -h \$$host \$$afile\"" >> diffs
	X	echo "> comm=\"servercomm -h ${SERVER} -p ${PORT} -t ${PTY} ${TTY} -f \$$filter\"" >> diffs
	X
	Xprintcap:
	X	echo "${PRINTER}|LaserWriter on communication server ${SERVER} Port ${PORT}:\\" > printcap
	X	echo "	:lp=${NEWLIBDIR}/${PRINTER}:sd=${NEWSPOOLDIR}:\\" >> printcap
	X	echo "	:lf=${NEWSPOOLDIR}/lw-log:af=/usr/adm/lw.acct:\\" >> printcap
	X	echo "	:mx#0:sf:sb:\\" >> printcap
	X	echo "	:if=${NEWLIBDIR}/psif:\\" >> printcap
	X	echo "	:of=${NEWLIBDIR}/psof:gf=${NEWLIBDIR}/psgf:\\" >> printcap
	X	echo "	:nf=${NEWLIBDIR}/psnf:tf=${NEWLIBDIR}/pstf:\\" >> printcap
	X	echo "	:rf=${NEWLIBDIR}/psrf:vf=${NEWLIBDIR}/psvf:\\" >> printcap
	X	echo "	:cf=${NEWLIBDIR}/pscf:df=${NEWLIBDIR}/psdf:" >> printcap
	X
	X
	Xprintcap.remote:
	X	echo "${PRINTER}|Remote LaserWriter on Host ${HOST} communication server ${SERVER} Port ${PORT}:\\" > printcap.remote
	X	echo "	:lp=:rm=${HOST}:rp=${PRINTER}:sd=${NEWSPOOLDIR}:" >> printcap.remote
	X
	Xsharfile:	README Makefile servercomm.8l servercomm.c hello.ps example
	X	shar README Makefile servercomm.8l servercomm.c hello.ps example > sharfile
SHAR_EOF
if test 4422 -ne "`wc -c < 'Makefile'`"
then
	echo shar: error transmitting "'Makefile'" '(should have been 4422 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'README'" '(3390 characters)'
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
sed 's/^	X//' << \SHAR_EOF > 'README'
	XManifest
	X--------
	X
	XMakefile		installation makefile
	Xservercomm.8l		manual page
	Xservercomm.c		source code
	Xhello.ps		Postscript "Hello, World" test file
	Xexample			Sample output from configuration of 3com Comm Server
	XREADME			This file
	X
	XTroubleshooting the connection to the server
	X--------------------------------------------
	X
	X0) You may want to do this first, before doing the software installation.
	X
	X1) Kill the lpd daemon servicing your Laserwriter on the server, if
	Xyou're troubleshooting after installing this kit.
	X
	X2) Provided you've already setup the port on the communications server
	Xfor your Laserwriter, telnet to the port.
	X
	X3) If you get through the port to the Laserwriter, type the Postscript
	Xcommand "executive" and see what the Laserwriter says. You should see a
	X"PS>" prompt.  If the Laserwriter responds, then the physical
	Xconnection at least is good. Type "quit" to get out of executive mode
	Xon the Laserwriter.
	X
	X4) As usual, check the modes and ownerships of the directories and
	Xespecially the pseudo master and slave terminals in /dev.
	X
	X5) Edit the Makefile, setting the various variables to meaningful
	Xvalues. Then, "make test", and the Makefile will compile a version of
	Xservercomm in the current directory with the debugging code in, and then
	Xrun the debug version in verbose mode. Watch the output carefully and
	Xlook for complaints from servercomm. You do not have to have the spool
	Xdirectory, new print filters, or printcap built to do this step. You DO
	Xhave to have the variables in the Makefile set appropriately for your
	Xsite.
	X
	XInstallation Steps for Bridge Server and TRANSCRIPT
	X---------------------------------------------------
	X0) Use the Makefile as a model of what to do. The easiest thing is to
	Xset the Makefile variables to meaningful values, and then use the
	XMakefile just to make some ancillary files that you will find useful in
	Xa moment. "make printcap" and  "make diffs" will not change
	Xanything in your system, just make some files in the current
	Xdirectory.
	X
	X1) Compile servercomm. (Type "make")
	X
	X2) Create a spool directory for the remote printer. 
	X
	X3) Create a new directory to hold the modified Transcript filter.
	XAlthough there appears to be several filters, they are in fact all hard
	Xlinks to the same shell script. Copy the Transcript filter psint.sh into
	Xthis directory, make the indicated changes in "diffs" (they are quite
	Xsmall), and establish all the requisite hard links. Since the filters
	Xare all in fact sybolic links to a single file, the overhead in maintaining
	Xa separate directory for every such remote printer is not high. Copy servercomm
	Xto this new directory. (Type "make filters")
	X
	X4) Make up a printcap entry for the remote printer and install it in
	Xthe /etc/printcap file. Use "printcap", produced by the Makefile, as an
	Xexample. The filters should point to your new modified filters. The
	Xspool area should point to your new spool directory. The device should
	Xpoint to a null file (and not a real device), since servercomm handles
	Xall the I/O.
	X
	X5) Set up the Bridge server by assigning an IP address to a port and
	Xsetting the port parameters to those in the "example" file.
	X
	X6) Hook your Laserwriter up to the Bridge server to the port you just 
	Xsetup.
	X
	X7) Try printing using the usual Berkeley lpr commands.  Look in lw-log
	Xin the spool directory for errors. Under SunOS 4.0, you may find these
	Xerrors in /usr/adm/lpd-errors.
SHAR_EOF
if test 3390 -ne "`wc -c < 'README'`"
then
	echo shar: error transmitting "'README'" '(should have been 3390 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'example'" '(1026 characters)'
if test -f 'example'
then
	echo shar: will not over-write existing file "'example'"
else
sed 's/^	X//' << \SHAR_EOF > 'example'
	X 
	Xcs/1t# sh (!63) dp
	XDefaultParameters  for PortId !63
	X...................Port Transmission and VTP Characteristics...................
	XAUToDisconnect = 60 AUtoLogoff = OFF    BUffersize = 82
	XDeVice = ( Host, Glass, DeFault )       PermanentVC = ""
	X.........................Port Physical Characteristics.........................
	XBAud = 9600         BSPad = None        CRPad = None        FFPad = None
	XLFPad = None        TabPad = None       DataBits = 7        DUplex = Full
	XLinePRotocol = ASynchronous             PARIty = AutoParity StopBits = 1
	XUseDCDout = ( AlwaysAssert, NoToggle )  UseDTRin = AsDTR (by DTE)
	X.................Session Transmission and VTP Characteristics..................
	XBReakAction = IGnore                    DIsconnectAction = None
	XDataForward = None  ECHOData = OFF
	XECHOMask = ( AlphaNum, CR, Term, Punct )                    NetAScii = UseLF
	XFlowControlFrom = ( Xon_Xoff )          FlowControlTo = ( Xon_Xoff )
	XIdleTimer = 2       LongBReakAction = IGnore                XOFF = ^S
	XXON = ^Q
	Xcs/1t# 
SHAR_EOF
if test 1026 -ne "`wc -c < 'example'`"
then
	echo shar: error transmitting "'example'" '(should have been 1026 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'hello.ps'" '(4967 characters)'
if test -f 'hello.ps'
then
	echo shar: will not over-write existing file "'hello.ps'"
else
sed 's/^	X//' << \SHAR_EOF > 'hello.ps'
	X%!PS-Adobe-1.0
	X%%Creator: odin:jsloan (John Sloan,407 Fawcett,2987,5134268082)
	X%%Title: stdin
	X%%CreationDate: Tue Jun 21 11:41:28 1988
	X%%DocumentFonts: Times-Roman Times-Italic Times-Bold Symbol Times-Roman
	X%%Pages: (atend)
	X%%EndComments
	X% lib/pscat.pro -- prolog for pscat (troff) files
	X% Copyright (C) 1985 Adobe Systems, Inc.
	X% Added defs for Manual Feed 
	Xsave /pscatsave exch def
	X/$pscat 50 dict def
	X$pscat begin
	X/fm [1 0 0 1 0 0] def
	X/xo 0 def /yo 0 def
	X/M /moveto load def
	X/R /show load def
	X/S {exch currentpoint exch pop moveto show}def
	X/T {exch currentpoint pop exch moveto show}def
	X/U {3 1 roll moveto show}def
	X/siz 0 def
	X/font 0 def
	X/Z {/siz exch def SF}def
	X/F {/font exch def SF}def
	X/SF{font 0 ne
	X    {catfonts font 1 sub get fm 0 siz put fm 3 siz neg put 
	X     fm makefont setfont}if}def
	X/BP{save/catsv exch def 0 792 translate 72 432 div dup neg scale 
	X  xo yo translate 0 0 moveto}def
	X/BPL{save/catsv exch def 72 8.25 mul 792 translate -90 rotate
	X  72 432 div dup neg scale xo yo translate 0 0 moveto}def
	X/EP{catsv restore showpage}def
	X/SetStTime{statusdict /manualfeedtimeout 120 put} def
	X/SetStatus{statusdict /manualfeed true put
	X   statusdict /product get (LaserWriter) eq 
	X   {version (23.0) eq  % Don't redefine EP if printer is not "Classic LW"
	X     {/EP {catsv restore
	X	 {statusdict /printerstatus get exec 16#22000000 and 0 eq{exit}if}loop
	X	 showpage}def}if }if}def
	X% definitions for PPROC callback functions
	X% each PPROC is called with the following number on the stack:
	X% pointsize charcode railmag pswidth pschar x y wid
	X/$pprocs 50 dict def
	X/fractm [.65 0 0 .6 0 0] def
	X% fractions
	X/PS1{gsave $pprocs begin
	X    /wid exch def pop pop pop pop pop /ch exch def /size exch def
	X    /pair $pprocs ch get def /cf currentfont def
	X    cf fractm makefont setfont
	X    0 .3 size mul 6 mul 2 copy neg rmoveto pair 0 get show rmoveto
	X    currentfont cf setfont (\244) show setfont
	X    pair 1 get show grestore wid .06 div 0 rmoveto end}def
	X$pprocs begin
	X8#34 [(1)(4)] def
	X8#36 [(1)(2)] def
	X8#46 [(3)(4)] def
	Xend
	X% boxes
	X/PS2{gsave /wid exch def pop pop /char exch def pop pop pop /size exch def
	X    /len size 3.5 mul def % length of a side
	X    len 0 rlineto 0 len neg rlineto len neg 0 rlineto closepath
	X    char 3 eq {fill}{size 5 mul .07 mul setlinewidth stroke}ifelse
	X    grestore wid .06 div 0 rmoveto}def
	X/PS3/PS2 load def		% boxes are the same...
	X% circle
	X/PS4{gsave /wid exch def pop pop pop pop pop pop /size exch def
	X    wid .8333 mul size 2.5 mul neg rmoveto currentpoint	% center
	X    newpath size 1.8 mul 0 360 arc size .2 mul setlinewidth stroke
	X    grestore wid .06 div 0 rmoveto}def
	X/bb{$pprocs begin /wid exch def pop pop pop pop pop pop /size exch 6 mul def
	X    /s2 size 2 div def /s4 size 4 div def gsave 
	X    currentpoint newpath transform round exch round exch itransform translate
	X    size 16 div setlinewidth 2 setlinejoin 0 setgray}def
	X$pprocs begin
	X/mrr{moveto rlineto rlineto}def
	X/be{stroke grestore wid .06 div 0 rmoveto end}def
	Xend
	X% leftfloor
	X/PS6 {bb s4 0 0 size s4 size -.8 mul mrr be}def
	X% rightfloor
	X/PS7 {bb s4 neg 0 0 size s4 size -.8 mul mrr be}def
	X% leftceil
	X/PS8 {bb s4 0 0 size neg s4 size .2 mul mrr be}def
	X% rightceil
	X/PS9 {bb s4 neg 0 0 size neg s4 size .2 mul mrr be}def
	X% boldvert
	X/PS5 {bb 0 0 0 size neg s4 size .2 mul mrr be}def
	X% box rule
	X/PS32 {bb /sw size 24 div def sw 2 div size 4.5 div moveto
	X       0 size neg rlineto sw setlinewidth be}def
	X% rule (roman, bold and italic)
	X/PS16 {gsave $pprocs begin
	X    /wid exch def pop pop pop pop pop pop /size exch 6 mul def
	X    /sw size 14 div def currentpoint exch sw 2 div sub exch
	X    newpath transform round exch round exch itransform translate
	X    0 0 moveto size 2 div 0 rlineto sw setlinewidth be}def
	X% lefttopcurl    
	X/PS20 {bb s4 size .2 mul moveto 0 size -.55 mul rlineto currentpoint 
	X    pop size -.8 mul 2 copy exch s4 add exch s4 arcto pop pop pop pop be}def
	X% leftbotcurl
	X/PS21 {bb s4 size -.8 mul moveto 0 size .55 mul rlineto currentpoint 
	X    pop size .2 mul 2 copy exch s4 add exch s4 arcto pop pop pop pop be}def
	X% righttopcurl
	X/PS22 {bb s4 size .2 mul moveto 0 size -.55 mul rlineto currentpoint
	X     pop size -.8 mul 2 copy exch s4 sub exch s4 arcto pop pop pop pop be}def
	X% rightbotcurl
	X/PS23 {bb s4 size -.8 mul moveto 0 size .55 mul rlineto currentpoint
	X     pop size .2 mul 2 copy exch s4 sub exch s4 arcto pop pop pop pop be}def
	X% rightmidcurl
	X/PS25 {bb /s3 size -.3 mul def s4 size -.8 mul moveto s4 s3 s2 s3
	X    s4 arcto pop pop size add s4 s3 4 2 roll
	X    s4 arcto pop pop pop pop s4 size .2 mul lineto be}def
	X% leftmidcurl
	X/PS24 {bb /s3 size -.3 mul def s4 size -.8 mul moveto s4 s3 0 s3
	X    s4 arcto pop pop size add s4 s3 4 2 roll s4 arcto pop pop pop pop 
	X    s4 size .2 mul lineto be}def
	X/catfonts [
	X	/Times-Roman findfont
	X	/Times-Italic findfont
	X	/Times-Bold findfont
	X	/Symbol findfont
	X	/Times-Roman findfont
	X	] def
	X%%EndProlog
	X%%Page: ? 1
	XBP
	X1 F
	X60 Z
	X432 165(Hello,)U
	X601(World!)S
	XEP
	X%%Trailer
	Xpscatsave end restore
	X%%Pages: 1
SHAR_EOF
if test 4967 -ne "`wc -c < 'hello.ps'`"
then
	echo shar: error transmitting "'hello.ps'" '(should have been 4967 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'servercomm.8l'" '(4271 characters)'
if test -f 'servercomm.8l'
then
	echo shar: will not over-write existing file "'servercomm.8l'"
else
sed 's/^	X//' << \SHAR_EOF > 'servercomm.8l'
	X.TH SERVERCOMM 8 "8 JULY 1989"
	X\" $Header$
	X.ds TS T\s-2RAN\s+2S\s-2CRIPT\s+2
	X.SH NAME
	Xservercomm \- spool to a printer on a terminal server
	X.SH SYNOPSIS
	X.B servercomm
	X[ \fB\-v\fR ]
	X[ \fB\-x\fR ]
	X[ \fB\-d\fI device\fR ]
	X[ \fB\-h\fI host\fR [ \fB\-p\fI port\fR ] ]
	X[ \fB\-t\fI ptydevice ttydevice\fR ]
	X[ \fB\-f\fI filter\fR ]
	X.SH DESCRIPTION
	X.I servercomm
	Xis an program that provides an interface between a typical Berkeley
	X.I lpd
	Xfilter (such as those provided in the Adobe \*(TS package) and
	Xa printer (such as a LaserWriter) connected to a serial port on a
	Xterminal server manufactured by 3com (Bridge), cisco systems, or
	XXylogics (Annex). 
	X.I Servercomm
	Xmakes a TCP/IP TELNET connection to the specified serial port of the
	Xspecified terminal server. It then forks and execs the normal filter
	X(as specified).
	XSince filters expect to talk to a physical device, a /dev/tty??, so
	X.I servercomm
	Xobliges by communicating with filters
	Xthrough the master and slave portions of a network pseudo-terminal pair,
	X/dev/pty?? and /dev/tty??. 
	X.I Servercomm
	Xhandles the interchange of data between the pseudo-terminal and the
	Xcommunications server. 
	X.I Lpd
	Xand any filters behave as if they were communicating with a directly-attached
	Xprinter.
	X.SH OPTIONS
	X.LP
	X.IP "\fB\-v\fR"
	XTurn on the debugging output to stderr, if the option was enabled at
	Xcompile time through the use of the -DDEBUG cc switch.
	X.IP "\fB\-x\fR"
	XTurn on the dump output to stderr, if the option was enabled at compile
	Xtime through the use of the -DDUMP cc switch.
	X.IP "\fB\-d\fI device\fR"
	XSpecify a device, such as /dev/lp, to use instead of the terminal server.
	XThis is useful for debugging the filter with a hardwired printer. Omitted
	Xif the \fB\-h\fR switch is used.
	X.IP "\fB\-h\fI host\fR"
	XSpecify the host name of the terminal server [or port on a terminal server]
	Xthat the printer is attached to.
	XOmitted if the \fB\-d\fR switch is used.
	X.IP "\fB\-p\fI port\fR"
	XSpecify the number of the serial port that the printer is attached
	Xto. Omitted if the \fB\-d\fR switch is used. This switch is unneeded with
	Xthe 3com or cisco terminal servers.
	X.IP "\fB\-t\fI ptydevice ttydevice\fR"
	XIndicate the master-slave pseudo-terminal pair to be used to communicate
	Xwith the filter. The tty name could be intuited from the pty name, provided
	Xthe standard names are used, but the user should be able to name the
	Xpair something else, like /dev/plp and /dev/tlp.
	X.IP "\fB\-f\fI filter\fR"
	XProvide the complete command line for the filter to be invoked.
	XTypically, this is 
	X.I pscomm
	Xfrom the \*(TS package, but it could be something else.
	X.SH "NOTES for \*(TS "
	XBriefly, the Berkeley line printer daemon, 
	X.I lpd,
	Xinvokes filters to handle communications with a printer attached to a
	Xserial port on the host computer. If these filters are modified to start
	X.I servercomm
	Xinstead of calling the usual communications filter, 
	X.I pscomm,
	Xthen
	X.I servercomm 
	Xwill initialize the connection and start
	X.I pscomm
	Xto output the information.
	X.br
	XTo install
	X.I servercomm,
	Xcopy it in the the directory where
	X.I pscomm
	Xis located. Make a copy of the 
	X.I psint.sh
	Xshell script and edit it to make the following changes.
	X.br
	XChange the line the begins
	X.B comm=
	Xto begin with
	X.B filter=
	Xand then add this line:
	X.br
	Xcomm=servercomm -h
	X.B hostname
	X-p
	X.B portid
	X-t
	X.B tty-names
	X-f $filter
	X.br
	X.sp
	X.B hostname,
	X.B portid,
	Xand
	X.B psudo-tty-name
	Xare described above.
	XIf you replace the 
	X.I psint.sh
	Xscript with this modified one, then your changes are complete. However, if
	Xyou have more than one printer, you will need a version of
	X.I psint.sh
	Xfor each one.
	X.SH FILES
	X.nf
	X/etc/printcap	printer capabilities data base
	X/usr/lib/lpd*	line printer daemons
	X/usr/spool/*	directories used for spooling
	X.fi
	X.SH "SEE ALSO"
	Xprintcap(5),
	Xlpc(8),
	Xlpd(8),
	Xpscomm(8),
	Xpsif(8)
	X.SH DIAGNOSTICS
	XThere are many possible fatal diagnostic messages. Each indicates which
	Xroutine in 
	X.I servercomm
	Xhad the fatal error. In most cases,
	X.I servercomm
	Xreturns an LPD_ABORT code to 
	X.I lpd.
	XIf the specified filter (typically 
	X.I pscomm
	X) fails, 
	X.I servercomm
	Xreturns the exit code of the filter to
	X.I lpd.
	X.SH NOTES
	X\*(TS is a trademark of Adobe Systems Incorporated.
	X.br
	XAnnex is a trademark of Xylogics Incorporated.
	X.br
	XLaserWriter is a trademark of Apple Computer.
SHAR_EOF
if test 4271 -ne "`wc -c < 'servercomm.8l'`"
then
	echo shar: error transmitting "'servercomm.8l'" '(should have been 4271 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'servercomm.c'" '(16356 characters)'
if test -f 'servercomm.c'
then
	echo shar: will not over-write existing file "'servercomm.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'servercomm.c'
	X/*
	X**	S E R V E R C O M M
	X**
	X**	Title:		    servercomm (formerly annexf)
	X**	Original Author:    John Sloan (internet: jsloan@SPOTS.Wright.Edu)
	X**	System:		    SunOS 
	X**	Language:	    C
	X**	Date:		    April 1988
	X**	Abstract
	X**
	X**	Servercomm is a filter for the Berkeley spooler daemon that
	X**	establishes a bidirectional TCP/IP/TELNET connection to
	X**	a serial port on an terminal server made by popular makers
	X**	so that printouts can be spooled to a serial printer connected
	X**	to the server. It is intended to be used with an Apple
	X**	Laserwriter and the Adobe Transcript package, but could
	X**	be used for other things as well. It can also be configured
	X**	at run time to talk to a /dev device instead of the terminal server
	X++
	X++	Modified by Jim Warner to work with the service listener
	X++	port on Bridge Communications terminal servers.  The dialog
	X++	in handshake() is unnecessary.  The "port" number was the physical
	X++	connector on the back of the annex.  For Bridge (and Cisco, I bet)
	X++	this is the tcp-port number to use instead of telnet=23.  For
	X++	Bridge, we're going to need an IP address per printer.
	X++						Jan 2 1989
	X==
	X==	Modified by Dinah Anderson <dinah@bcm.tmc.edu> to use the 
	X==	sys/termios.h data structure instead of the sys/ioctl.h.
	X==	Also set the ptys characteristics explicitly since most postscript
	X==	files would not print. We tested this using a Bridge server.
	X==	8/23/89.
	X**
	X**	Disclaimer
	X**
	X**	This software is supplied as is, and no warranty is expressed or
	X**	implied as to its correctness, functionality, or suitability
	X**	for any application, anywhere, at anytime, by anyone.
	X**
	X**	Acknowledgements
	X**
	X**	Much of this code was inspired by telnet.c from UCB and aprint.c
	X**	from Encore Computer. No code borrowed, but a lot of questions
	X**	were answered by perusing these examples. Also, many thanks to
	X**	Ken Yap <ken@cs.rochester.edu>, who suggested using a pty/tty
	X**	pair to communicate with pscomm. I was working on that when I
	X**	received his email, and it was encouraging to hear someone else
	X**	that thought it should work.
	X**
	X**	Compile Time Flags
	X**
	X**	DEBUG		Compiles in debugging code to make
	X**			useful remarks on stderr. Use the
	X**			-v run time flag to activate.
	X**
	X**	DUMP		Compiles in code to dump data to stderr
	X**			as it's being processed. Very verbose,
	X**			but useful in debugging. Use the -x run
	X**			time flag to activate.
	X**
	X**	BRIDGE		Compiles in code to support CISCO or BRIDGE
	X**			communications servers.
	X**
	X*/
	X/*
	X**	To do:
	X**	    The pseudottys should not have to be specified. The program
	X**	    should find the first available ones and use them.
	X**
	X*/
	X#include <stdio.h>
	X#include <sys/types.h>
	X#include <sys/file.h>
	X#include <sys/termios.h>
	X#include <ctype.h>
	X#include <errno.h>
	X#include <fcntl.h>
	X#include <setjmp.h>
	X#include <signal.h>
	X#include <netdb.h>
	X#include <netinet/in.h>
	X#define	TELOPTS
	X#include <arpa/telnet.h>
	X#include <arpa/inet.h>
	X#include <sys/socket.h>
	X#include <sys/wait.h>
	X#include <strings.h>
	X
	X#define LPD_OK 0		/* lpd filter exit codes */
	X#define LPD_RETRY 1
	X#define LPD_ABORT 2
	X#define BUFFER 512		/* spooler buffer size in bytes */
	X#define CR '\015'
	X#define PROMPT ':'
	X
	X#ifdef DEBUG
	X#define DPRINTF(s)	if (debugon) fprintf s
	X#else
	X#define DPRINTF(s)
	X#endif
	X
	X/*
	X**	Identification
	X*/
	Xstatic char id[]="$Header: /home/crick/vpit/sob/src/servercomm/RCS/servercomm.c,v 1.1 89/08/06 00:10:36 sob Exp Locker: sob $";
	X
	X/*
	X**	Must be static (used by network code).
	X*/
	Xstruct servent *srvc;
	Xstruct hostent *host;
	Xstruct sockaddr_in sock;
	Xstruct sockaddr dev;
	Xstruct termios ttycb;
	Xjmp_buf context;
	X
	X/*
	X**	Must be global (used by interrupt service routines).
	X*/
	X#ifndef errno
	Xextern int errno;	/* warner: not needed for Sun OS */
	X#endif
	Xchar *pgmname;
	Xint filterpid,prodpid,conspid;
	Xint netfd,ptyfd,ttyfd;
	Xint debugon,dumpon;
	X
	Xvoid setup(),cleanup(),handshake(),trigger(),rendezvous();
	Xvoid spool(),transmit(),usage(),bailout(),fatal();
	Xvoid lost(),interrupted(),finished();
	X#ifdef DEBUG
	Xvoid pargs();
	X#endif
	X
	Xmain(argc,argv)
	Xint argc;
	Xchar *argv[];
	X	{
	X	int nargc,rc;
	X	char *host,*port,*device,*filter,*pty,*tty,**nargv;
	X
	X	pgmname=rindex(argv[0],'/');
	X	pgmname=pgmname?pgmname+1:argv[0];
	X	setup(argc,argv,&debugon,&dumpon,&host,&port,&device,&pty,&tty,&filter,&nargc,&nargv);
	X	filterpid=0;
	X	prodpid=0;
	X	conspid=0;
	X	if (pty!=NULL)
	X		{
	X		ptyfd=acquire(pty);
	X		ttyfd=acquire(tty);
	X		if ((rc=ioctl(ttyfd,TCGETS,&ttycb))<0)
	X			fatal(rc,"main ioctl getp failed",LPD_ABORT);
	X		ttycb.c_cflag = (B9600 | CS7 | CREAD );
	X		ttycb.c_oflag = (OPOST | OCRNL );
	X		ttycb.c_iflag = (ISTRIP );
	X		ttycb.c_lflag = (0 );
	X		if ((rc=ioctl(ttyfd,TCSETS,&ttycb))<0)
	X			fatal(rc,"main ioctl setp failed",LPD_ABORT);
	X		}
	X	else
	X		ptyfd=0;
	X	if (host!=NULL)
	X		netfd=establish(host,port);
	X	else if (device!=NULL)
	X		netfd=acquire(device);
	X	else
	X		usage(0);
	X	if (rc=setjmp(context))
	X		bailout(rc);
	X	if (port!=NULL)
	X		handshake(netfd,port);
	X	if (filter!=NULL)
	X		{
	X		/*
	X		** Fork off producer and consumer processes
	X		** ahead of the filter so that they are ready
	X		** to handle the filter's I/O immediately. This
	X		** scheme is process intensive (makes several
	X		** processes) but is simpler than using non-blocking
	X		** I/O, which was the original implementation.
	X		*/
	X		spool(netfd,ptyfd,&prodpid,&conspid);
	X		filterpid=attach(filter,nargc,nargv,ttyfd);
	X		/*
	X		** Don't let children inherit our interrupt
	X		** service routines. This naively assumes that
	X		** nothing interesting will happen prior to now.
	X		*/
	X		signal(SIGPIPE,lost);
	X		signal(SIGINT,interrupted);
	X		/*
	X		** Wait for something interesting to happen.
	X		*/
	X		rendezvous(filterpid,prodpid,conspid);
	X		DPRINTF((stderr,"%s: main complete\n",pgmname));
	X		exit(LPD_OK);
	X		}
	X	}
	X
	X/*
	X**	Setup: parses argument list.
	X*/
	Xvoid
	Xsetup(argc,argv,dbgon,dmpon,host,port,device,pty,tty,filter,nargc,nargv)
	Xint argc,*dbgon,*dmpon,*nargc;
	Xchar *argv[],**host,**port,**device,**pty,**tty,**filter,***nargv;
	X	{
	X
	X	*dbgon=0;
	X	*dmpon=0;
	X	*host=NULL;
	X	*port=NULL;
	X	*device=NULL;
	X	*pty=NULL;
	X	*tty=NULL;
	X	*filter=NULL;
	X	*nargc=0;
	X	*nargv=NULL;
	X	while (argc>0)
	X		{
	X		if (argv[0][0]=='-')
	X			{
	X			switch (argv[0][1])
	X				{
	X			case 'v':
	X				*dbgon=1;
	X				DPRINTF((stderr,"%s: debug on\n",pgmname));
	X				break;
	X			case 'x':
	X				*dmpon=1;
	X				DPRINTF((stderr,"%s: dump on\n",pgmname));
	X				break;
	X			case 'h':
	X				usage(--argc);
	X				*host=(*++argv);
	X				DPRINTF((stderr,"%s: setup host=%s\n",pgmname,*host));
	X				break;
	X			case 'p':
	X				usage(--argc);
	X				*port=(*++argv);
	X				DPRINTF((stderr,"%s: setup port=%s\n",pgmname,*port));
	X				break;
	X			case 'd':
	X				usage(--argc);
	X				*device=(*++argv);
	X				DPRINTF((stderr,"%s: setup device=%s\n",pgmname,*device));
	X				break;
	X			case 't':
	X				usage(--argc);
	X				*pty=(*++argv);
	X				usage(--argc);
	X				*tty=(*++argv);
	X				DPRINTF((stderr,"%s: setup pty=%s, tty=%s\n",pgmname,*pty,*tty));
	X				break;
	X			case 'f':
	X				usage(--argc);
	X				*filter=(*++argv);
	X				*nargv=argv;
	X				*nargc=argc;
	X				argc=0;
	X				DPRINTF((stderr,"%s: setup filter=%s, argc=%d\n",pgmname,*filter,*nargc));
	X				break;
	X			default:
	X				usage(0);
	X				}
	X			}
	X		argv++;
	X		argc--;
	X		}
	X	}
	X
	X/*
	X**	Cleanup: Shutdown child processes, close files, do anything else
	X**	necessary to gracefully complete in the event of an error.
	X*/
	Xvoid
	Xcleanup()
	X	{
	X	/*
	X	** Filter may not have been started up yet.
	X	*/
	X	if (filterpid)
	X		{
	X		kill(filterpid,SIGTERM);
	X		DPRINTF((stderr,"%s: cleanup killed filter %d\n",pgmname,filterpid));
	X		}
	X	/*
	X	** Producer may not have been started up yet.
	X	*/
	X	if (prodpid)
	X		{
	X		kill(prodpid,SIGTERM);
	X		DPRINTF((stderr,"%s: cleanup killed spooler %d\n",pgmname,prodpid));
	X		}
	X	/*
	X	** Consumer may not have been started up yet.
	X	*/
	X	if (conspid)
	X		{
	X		kill(conspid,SIGTERM);
	X		DPRINTF((stderr,"%s: cleanup killed spooler %d\n",pgmname,conspid));
	X		}
	X	/*
	X	** These may be already closed, in which case close returns an
	X	** error we can safely ignore.
	X	*/
	X	close(ptyfd);
	X	close(ttyfd);
	X	close(netfd);
	X	}
	X
	X/*
	X**	Establish: Given a host name or an IP address, establish a real
	X**	time TCP/IP/TELNET connection to the specified Annex.
	X*/
	Xint
	Xestablish(hostname,port)
	Xchar *hostname, *port;
	X	{
	X	char *name;
	X	int rc,netfd;
	X
	X	if ((srvc=getservbyname("telnet","tcp"))==0)
	X		fatal(srvc,"establish getservbyname failed",LPD_ABORT);
	X	if (host=gethostbyname(hostname))
	X		{
	X		/*
	X		** hostname is an alphanumeric name in /etc/hosts
	X		*/
	X		DPRINTF((stderr,"%s: got hostname\n",pgmname));
	X		sock.sin_family=host->h_addrtype;
	X		bcopy(host->h_addr,(caddr_t)&sock.sin_addr,host->h_length);
	X		name=host->h_name;
	X		}
	X	else if ((sock.sin_addr.s_addr=inet_addr(hostname))!=-1)
	X		{
	X		/*
	X		** hostname is a numeric IP address
	X		*/
	X		DPRINTF((stderr,"%s: got IP address\n",pgmname));
	X		sock.sin_family=AF_INET;
	X		name=hostname;
	X		}
	X	else
	X		/*
	X		** hostname is not anything useful
	X		*/
	X		fatal(sock.sin_addr.s_addr,"establish hostname failed",LPD_ABORT);
	X#ifndef BRIDGE
	X	sock.sin_port=srvc->s_port;
	X#else
	X	sock.sin_port= htons ( atoi (port));
	X	DPRINTF ((stderr,"%s:  tcp port %d\n",pgmname, atoi (port) ));  
	X#endif
	X	if ((netfd=socket(AF_INET,SOCK_STREAM,0,0))<0)
	X		fatal(netfd,"establish socket failed",LPD_ABORT);
	X	if ((rc=connect(netfd,(caddr_t)&sock,sizeof(sock),0))<0)
	X		fatal(rc,"establish connect failed",LPD_ABORT);
	X	DPRINTF((stderr,"%s: establish host=%s, socket=%d\n",pgmname,name,netfd));
	X	return(netfd);
	X	}
	X
	X/*
	X**	Handshake: Given a TCP/IP/TELNET connection to an Annex,
	X**	carry out handshaking necessary to connect to the specified
	X**	serial port. This is clearly kludgy, and should be replaced
	X**	with Encore's Annex R4.0.
	X**
	X*/
	Xvoid
	Xhandshake(netfd,port)
	Xint netfd;
	Xchar *port;
	X	{
	X	int rc;
	X
	X	DPRINTF((stderr,"%s: handshake fd=%d, port=%s\n",pgmname,netfd,port));
	X#ifndef BRIDGE
	X	transmit(netfd,"\r",1);
	X	trigger(netfd,':');
	X	trigger(netfd,':');
	X	transmit(netfd,port,strlen(port));
	X	transmit(netfd,"\r",1);
	X	trigger(netfd,'\n');
	X	trigger(netfd,'\n');
	X#endif
	X	}
	X
	X/*
	X**	Trigger: Scan the data from a specified file descriptor until
	X**	the given trigger character is encountered. Hey, is this kludgey
	X**	or what? But it keeps handshake and the comm server synchronized
	X**	(providing no characters are lost), and keeps pscomm from seeing
	X**	any of the prompts from the annex. Both trigger and handshake
	X**	will be obsolesced by Encore's Annex R4.0, which has a better
	X**	reverse telnet mechanism.
	X*/
	Xvoid
	Xtrigger(fd,ch)
	Xint fd;
	Xchar ch;
	X	{
	X	int count;
	X	char buf;
	X
	X	do
	X		{
	X		if ((count=receive(fd,&buf,1))!=1)
	X			fatal(count,"trigger receive would block",LPD_ABORT);
	X#ifdef DEBUG
	X		if (debugon) putc(buf,stderr);
	X#endif
	X		}
	X	while (buf!=ch);
	X	}
	X
	X/*
	X**	Attach: Given a connection to a particular serial port on an
	X**	terminal server, invoke an appropriate printer filter to handle the
	X**	input/output.
	X*/
	Xint
	Xattach(filter,argc,argv,prtfd)
	Xint argc,prtfd;
	Xchar *filter,**argv;
	X	{
	X	int rc,pid;
	X
	X	if ((pid=fork())<0)
	X		fatal(pid,"attach fork failed",LPD_ABORT);
	X	else
	X		if (pid)
	X			{
	X			/*
	X			** Child owns the prtfd now.
	X			*/
	X			close(prtfd);
	X			DPRINTF((stderr,"%s: attach filter=%s, prtfd=%d, pid=%d\n",pgmname,filter,prtfd,pid));
	X#ifdef DEBUG
	X			if (debugon) pargs(argc,argv);
	X#endif
	X			return(pid);
	X			}
	X		else
	X			{
	X			/*
	X			** stdout gets connected to the tty end of pty
	X			** so pscomm sees a tty devices as its output.
	X			** stdin remains connected to lpd output.
	X			*/
	X			close(1);
	X			if ((rc=dup2(prtfd,1))==-1)
	X				fatal(rc,"attach dup2 failed",LPD_ABORT);
	X			if ((rc=execvp(filter,argv))==-1)
	X				fatal(rc,"attach execvp failed",LPD_ABORT);
	X			/*
	X			** Never reached.
	X			*/
	X			}
	X	}
	X
	X/*
	X**	Rendezvous: waits for the child process (the true printer
	X**	filter) to complete.
	X*/
	Xvoid
	Xrendezvous(filterpid,prodpid,conspid)
	Xint filterpid,prodpid,conspid;
	X	{
	X	int wpid,rc;
	X	union wait status;
	X
	X	do
	X		wpid=wait(&status);
	X	while ((wpid!=filterpid)&&(wpid!=-1));
	X	if (wpid==-1)
	X		fatal(wpid,"rendezvous wait failed",LPD_ABORT);
	X	rc=status.w_retcode;
	X	if (rc!=LPD_OK)
	X		fatal(rc,"rendezvous filter failed",rc);
	X	DPRINTF((stderr,"%s: rendezvous wpid=%d, retcode=%d\n",pgmname,wpid,rc));
	X	/*
	X	** These may have already returned, in which case the kill
	X	** returns an error we can safely ignore.
	X	*/
	X	kill(prodpid,SIGTERM);
	X	kill(conspid,SIGTERM);
	X	}
	X
	X/*
	X**	Acquire: open a device and return the file descriptor.
	X*/
	Xint
	Xacquire(dev)
	Xchar *dev;
	X	{
	X	int fd;
	X
	X	if ((fd=open(dev,O_RDWR))==-1)
	X		fatal(fd,"acquire open failed",LPD_ABORT);
	X	DPRINTF((stderr,"%s: acquire dev=%s, fd=%d\n",pgmname,dev,fd));
	X	return(fd);
	X	}
	X
	X/*
	X**	Spool: set up the net and pty connections and fork off
	X**	children to do the actual work.
	X*/
	Xvoid
	Xspool(netfd,ptyfd,prodpid,conspid)
	Xint netfd,ptyfd,*prodpid,*conspid;
	X	{
	X	int rc;
	X
	X	if ((*conspid=fork())<0)
	X		fatal(*conspid,"spool consumer fork failed",LPD_ABORT);
	X	if (!*conspid)
	X		{
	X		rc=process(netfd,ptyfd);
	X		/*
	X		** Release fds now that consumer is complete.
	X		*/
	X		close(netfd);
	X		close(ptyfd);
	X		exit(rc);
	X		}
	X	DPRINTF((stderr,"%s: spool %d->%d=%d\n",pgmname,netfd,ptyfd,*conspid));
	X	if ((*prodpid=fork())<0)
	X		fatal(*prodpid,"spool producer fork failed",LPD_ABORT);
	X	if (!*prodpid)
	X		{
	X		rc=process(ptyfd,netfd);
	X		/*
	X		** Release fds now that producer is complete.
	X		*/
	X		close(ptyfd);
	X		close(netfd);
	X		exit(rc);
	X		}
	X	/*
	X	** Producer and consumer children own the fds now.
	X	*/
	X	close(ptyfd);
	X	close(netfd);
	X	DPRINTF((stderr,"%s: spool %d->%d=%d\n",pgmname,ptyfd,netfd,*prodpid));
	X	}
	X
	X/*
	X**	Process: copy from input fd to output fd until end of file.
	X*/
	Xint
	Xprocess(infd,outfd)
	X	{
	X	int len;
	X	char buf[BUFFER+1];
	X
	X	do
	X		if ((len=receive(infd,buf,sizeof(buf)))>0)
	X			{
	X			transmit(outfd,buf,len);
	X#ifdef DUMP
	X			if (dumpon)
	X				{
	X				buf[len]='\0';
	X				fputs(buf,stderr);
	X				}
	X#endif
	X			}
	X	while (len>0);
	X	DPRINTF((stderr,"%s: process %d->%d=%d\n",pgmname,infd,outfd,len));
	X	return(len);
	X	}
	X
	X/*
	X**	Transmit: send a buffer of a given length to a
	X**	specified file descriptor.
	X*/
	Xvoid
	Xtransmit(fd,buf,len)
	Xint fd,len;
	Xchar *buf;
	X	{
	X	int count;
	X
	X	while (len>0)
	X		if ((count=write(fd,buf,len))<0)
	X			{
	X			if (errno!=EWOULDBLOCK)
	X				fatal(count,"transmit write failed",LPD_ABORT);
	X			}
	X		else
	X			{
	X			buf+=count;
	X			len-=count;
	X			}
	X	}
	X
	X/*
	X**	Receive: Receive a specified amount of data from a given
	X**	file descriptor and place it in the specied buffer.
	X*/
	Xint
	Xreceive(fd,buf,len)
	Xint fd,len;
	Xchar *buf;
	X	{
	X	int count;
	X
	X	if (len<=0)
	X		return(len);
	X	if ((count=read(fd,buf,len))<0)
	X		{
	X		if (errno!=EWOULDBLOCK)
	X			fatal(count,"receive read failed",LPD_ABORT);
	X		}
	X	else
	X		if (count>len)
	X			fatal(count,"receive read overflow",LPD_ABORT);
	X	return(count);
	X	}
	X
	X/*
	X**	Bailout: handle interrupts while attempting to exit
	X**	as gracefully and politely as possible.
	X*/
	Xvoid
	Xbailout(rc)
	Xint rc;
	X	{
	X	switch(rc)
	X		{
	X	case 1:
	X		signal(SIGPIPE,SIG_DFL);
	X		fatal(rc,"broken pipe",LPD_ABORT);
	X		break;
	X	case 2:
	X		signal(SIGINT,SIG_DFL);
	X		fatal(rc,"aborted",LPD_ABORT);
	X		break;
	X	default:
	X		fatal(rc,"unknown signal",LPD_ABORT);
	X		}
	X	}
	X
	X/*
	X**	Fatal: Prints the system error message, prints a user
	X**	error message, and exits with the specified code.
	X*/
	Xvoid
	Xfatal(rc,msg,xit)
	Xint rc,xit;
	Xchar *msg;
	X	{
	X	/*
	X	** Naively assume that if rc<=0, it's a system call
	X	** return, and perror is valid; otherwise, perror is
	X	** misleading.
	X	*/
	X	if (rc<=0)
	X		perror("annexf");
	X	fprintf(stderr,"%s: %s (%d)\n",pgmname,msg,rc);
	X	cleanup();
	X	exit(xit);
	X	}
	X
	X/*
	X**	Usage: check argc, and report usage error.
	X*/
	Xvoid
	Xusage(argc)
	Xint argc;
	X	{
	X	if (argc <= 0)
	X		{
	X		fprintf(stderr,"usage: %s [-v] [-x] [[-h host [-p port]]|[-d device]] [-t pty tty] [-f filter [args]]\n",pgmname);
	X		cleanup();
	X		exit(LPD_ABORT);
	X		}
	X	}
	X
	X/*
	X**	Lost: Interrupt service routine which is invoked when
	X**	a pipe breaks and a connection is lost.
	X*/
	Xvoid
	Xlost()
	X	{
	X	longjmp(context,1);
	X	}
	X
	X/*
	X**	Interrupted: Interrupt service routine which is invoked
	X**	when a interrupt signal is received from another process
	X**	(typically the line printer spooler daemon).
	X*/
	Xvoid
	Xinterrupted()
	X	{
	X	longjmp(context,2);
	X	}
	X
	X/*
	X**	Finished: Interrupt service routine which is invoked
	X**	when the parent receives end of file and signals the
	X**	child process to terminate.
	X*/
	Xvoid
	Xfinished()
	X	{
	X	longjmp(context,3);
	X	}
	X
	X#ifdef DEBUG
	X/*
	X**	Pargs: prints argc and argv argument lists for debugging.
	X*/
	Xvoid
	Xpargs(argc,argv)
	Xint argc;
	Xchar **argv;
	X	{
	X	int nargc;
	X
	X	fprintf(stderr,"%s:",pgmname);
	X	for (nargc=0;argc>0;argc--,nargc++,argv++)
	X		{
	X		putc(' ',stderr);
	X		fputs(*argv,stderr);
	X		}
	X	putc('\n',stderr);
	X	}
	X#endif
SHAR_EOF
if test 16356 -ne "`wc -c < 'servercomm.c'`"
then
	echo shar: error transmitting "'servercomm.c'" '(should have been 16356 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0