Subject: PAP interim release

From: [email-masked]
Date: Tue, 08 Sep 92 17:25:59 -0400

The following shar file contains the version of pap which will likely
be included in the 1.3 release. It expects to be installed in bin/pap.
To unshar it, cd to your source area's bin directory, and run the file
below through sh.

wes

------ cut ------
#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  pap pap/README pap/Makefile pap/pap.c pap/papstatus.c
# Wrapped by [email-masked] on Tue Sep  8 17:20:46 1992
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test ! -d 'pap' ; then
    echo shar: Creating directory \"'pap'\"
    mkdir 'pap'
fi
if test -f 'pap/README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'pap/README'\"
else
echo shar: Extracting \"'pap/README'\" \(1596 characters\)
sed "s/^X//" >'pap/README' <<'END_OF_FILE'
XThis is an interim release of pap (between the official release of
X1.2.1 and 1.3). It is a complete rewrite of the pap found in 1.2.1.  It
Xexpects to be installed in the source bin directory, not in the source
Xetc/papd directory.  There are two changes you might want to make to
Xthe CFLAGS variable in the Makefile:
X
X    -DPRAGMATIC
X	This causes several bit of work-around code to be included.
X	Currently, there are three work-arounds:
X
X		HP LJIIISI w/ BridgePort LocalTalk card sends zero
X		instead of the connection ID in ATP Response packets.
X		The work-around is to not check that the connection ID
X		is correct.
X
X		The Apple LaserWriter IIf doesn't send EOF under
X		certain circumstance. There are probably several other
X		implementations which have this bug. The symptom is
X		that the job prints but leaves the job in the queue.
X		As a temporary fix, we don't wait for the printer's EOF
X		before sending our next file or closing. A better
X		solution would be to determine that the other side
X		wasn't going to send us EOF before giving up.
X
X		The LaserWriter IINTX puts the current connection ID in
X		status response packets. The offending field should be
X		0. The work around is to not check this field on status
X		response packets.
X
X	A general comment: there are lots of stinky PAP implementations
X	out there. It's not clear if this is because PAP is a stinky
X	protocol (it is), or there are a lot of stinky programmers
X	(there are).
X
X    -DEBUG
X	This causes various bits of debugging to be printed on stdout.
X	This is especially useful in conjunction with the debugging
X	version of ATP.
END_OF_FILE
if test 1596 -ne `wc -c <'pap/README'`; then
    echo shar: \"'pap/README'\" unpacked with wrong size!
fi
# end of 'pap/README'
fi
if test -f 'pap/Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'pap/Makefile'\"
else
echo shar: Extracting \"'pap/Makefile'\" \(1343 characters\)
sed "s/^X//" >'pap/Makefile' <<'END_OF_FILE'
XTARGETS=	pap papstatus
XSRC = pap.c papstatus.c
X
XINCPATH=	-I../../include
XCFLAGS=	${DEFS} ${OPTOPTS} ${INCPATH} -DPRAGMATIC
XLIBS=	${ADDLIBS} -latalk
XTAGSFILE=	tags
XCC=	cc
XINSTALL=	install
XLIBDIRS=	-L../../libatalk
X
Xall : ${TARGETS}
X
Xpap : pap.o ../../libatalk/libatalk.a
X	${CC} ${CFLAGS} -o pap pap.o ${LIBDIRS} ${LIBS}
X
Xpapstatus : papstatus.o ../../libatalk/libatalk.a
X	${CC} ${CFLAGS} -o papstatus papstatus.o ${LIBDIRS} ${LIBS}
X
Xinstall : all
X	for i in ${TARGETS}; do ${INSTALL} -c $$i ${DESTDIR}/bin; done
X
Xclean :
X	rm -f a.out core* *.o *.bak *[Ee]rrs tags
X	rm -f ${TARGETS}
X
Xtags : ${SRC}
X	cwd=`pwd`; \
X	for i in ${SRC}; do \
X	    ctags -t -a -f ${TAGSFILE} $$cwd/$$i; \
X	done
X
Xdepend :
X	for i in ${SRC} ; do \
X	    ${CC} -M ${DEFS} ${INCPATH} $$i | \
X	    awk ' { if ($$1 != prev) { print rec; rec = $$0; prev = $$1; } \
X		else { if (length(rec $$2) > 78) { print rec; rec = $$0; } \
X		else rec = rec " " $$2 } } \
X		END { print rec } ' >> makedep; done
X	sed -n '1,/^# DO NOT DELETE THIS LINE/p' Makefile > Makefile.tmp
X	cat makedep >> Makefile.tmp
X	rm makedep
X	echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile.tmp
X	echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile.tmp
X	echo '# see make depend above' >> Makefile.tmp
X	rm -f Makefile.bak
X	cp Makefile Makefile.bak
X	mv Makefile.tmp Makefile
X
X# DO NOT DELETE THIS LINE
X
END_OF_FILE
if test 1343 -ne `wc -c <'pap/Makefile'`; then
    echo shar: \"'pap/Makefile'\" unpacked with wrong size!
fi
# end of 'pap/Makefile'
fi
if test -f 'pap/pap.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'pap/pap.c'\"
else
echo shar: Extracting \"'pap/pap.c'\" \(15953 characters\)
sed "s/^X//" >'pap/pap.c' <<'END_OF_FILE'
X/*
X * Copyright (c) 1990,1991 Regents of The University of Michigan.
X * All Rights Reserved.
X *
X * Permission to use, copy, modify, and distribute this software and
X * its documentation for any purpose and without fee is hereby granted,
X * provided that the above copyright notice appears in all copies and
X * that both that copyright notice and this permission notice appear
X * in supporting documentation, and that the name of The University
X * of Michigan not be used in advertising or publicity pertaining to
X * distribution of the software without specific, written prior
X * permission. This software is supplied as is without expressed or
X * implied warranties of any kind.
X *
X *	Research Systems Unix Group
X *	The University of Michigan
X *	c/o Mike Clark
X *	535 W. William Street
X *	Ann Arbor, Michigan
X *	+1-313-763-0525
X *	[email-masked]
X */
X
X#include <sys/types.h>
X#include <sys/time.h>
X#include <sys/uio.h>
X#include <sys/file.h>
X#include <netatalk/endian.h>
X#include <netatalk/at.h>
X#include <atalk/atp.h>
X#include <atalk/pap.h>
X#include <atalk/nbp.h>
X#include <stdio.h>
X#include <strings.h>
X
X#define _PATH_PAPRC	".paprc"
X
Xusage( path )
X    char	*path;
X{
X    char	*p;
X
X    if (( p = rindex( path, '/' )) == NULL ) {
X	p = path;
X    } else {
X	p++;
X    }
X    fprintf( stderr,
X	"Usage:\t%s [ -p printername ] [ -s statusfile ] [ file ] ...\n", p );
X    exit( 1 );
X}
X
Xchar *
Xpaprc()
X{
X    static char	s[ 32 + 1 + 32 + 1 + 32 ];
X    char	*name = NULL;
X    FILE	*f;
X
X    if (( f = fopen( _PATH_PAPRC, "r" )) == NULL ) {
X	return( NULL );
X    }
X    while ( fgets( s, sizeof( s ), f ) != NULL ) {
X	s[ strlen( s ) - 1 ] = '\0';	/* remove trailing newline */
X	if ( *s == '#' ) {
X	    continue;
X	}
X	name = s;
X	break;
X    }
X    fclose( f );
X    return( name );
X}
X
Xchar			*printer = NULL;
Xchar			*status = NULL;
X
Xunsigned char		connid, quantum, oquantum = PAP_MAXQUANTUM;
Xstruct sockaddr_at	sat;
X
Xchar			cbuf[ 8 ];
Xstruct nbpnve		nn;
XATP			satp;
X
Xmain( ac, av )
X    int		ac;
X    char	**av;
X{
X    ATP			atp;
X    struct atp_block	atpb;
X    int			c, err = 0, fd;
X    char		*obj = NULL, *type = "LaserWriter", *zone = "*";
X    struct timeval	stv, tv;
X    char		rbuf[ ATP_MAXDATA ];
X    struct iovec	iov;
X    unsigned short	waiting, result;
X    extern char		*optarg;
X    extern int		optind;
X
X    while (( c = getopt( ac, av, "ep:s:" )) != EOF ) {
X	switch ( c ) {
X	case 'e' :	/* send stdout to stderr */
X	    dup2( 2, 1 );
X	    break;
X
X	case 'p' :
X	    printer = optarg;
X	    break;
X
X	case 's' :
X	    status = optarg;
X	    break;
X
X	default :
X	    fprintf( stderr, "Unknown option: '%c'\n", c );
X	    err++;
X	}
X    }
X    if ( err ) {
X	usage( *av );
X    }
X    if ( printer == NULL && (( printer = paprc()) == NULL )) {
X	usage( *av );
X    }
X
X    /*
X     * Open connection.
X     */
X    if ( nbp_name( printer, &obj, &type, &zone ) < 0 ) {
X	fprintf( stderr, "%s: Bad name\n", printer );
X	exit( 1 );
X    }
X    if ( obj == NULL ) {
X	fprintf( stderr, "%s: Bad name\n", printer );
X	exit( 1 );
X    }
X    if ( nbp_lookup( obj, type, zone, &nn, 1 ) <= 0 ) {
X	perror( "nbp_lookup" );
X	exit( 1 );
X    }
X    if ( isatty( 0 )) {
X	printf( "Trying %u.%d:%d ...\n", ntohs( nn.nn_sat.sat_addr.s_net ),
X		nn.nn_sat.sat_addr.s_node, nn.nn_sat.sat_port );
X    }
X
X    if (( atp = atp_open( 0 )) == NULL ) {
X	perror( "atp_open" );
X	exit( 1 );
X    }
X    if (( satp = atp_open( 0 )) == NULL ) {
X	perror( "atp_open" );
X	exit( 1 );
X    }
X
X    cbuf[ 0 ] = connid = getpid() & 0xff;
X    cbuf[ 1 ] = PAP_OPEN;
X    cbuf[ 2 ] = cbuf[ 3 ] = 0;
X    cbuf[ 4 ] = atp_sockaddr( atp )->sat_port;
X    cbuf[ 5 ] = oquantum;	/* flow quantum */
X    if ( gettimeofday( &stv, 0 ) < 0 ) {
X	perror( "gettimeofday" );
X	exit( 1 );
X    }
X    for (;;) {
X	if ( gettimeofday( &tv, 0 ) < 0 ) {
X	    perror( "gettimeofday" );
X	    exit( 1 );
X	}
X	waiting = htons( tv.tv_sec - stv.tv_sec );
X	bcopy( &waiting, &cbuf[ 6 ], sizeof( waiting ));
X
X	atpb.atp_saddr = &nn.nn_sat;
X	atpb.atp_sreqdata = cbuf;
X	atpb.atp_sreqdlen = 8;		/* bytes in OpenConn request */
X	atpb.atp_sreqto = 2;		/* retry timer */
X	atpb.atp_sreqtries = 5;		/* retry count */
X	if ( atp_sreq( atp, &atpb, 1, ATP_XO ) < 0 ) {
X	    perror( "atp_sreq" );
X	    exit( 1 );
X	}
X#ifdef EBUG
Xprintf( "> OPEN\n" );
X#endif EBUG
X
X	iov.iov_base = rbuf;
X	iov.iov_len = sizeof( rbuf );
X	atpb.atp_rresiov = &iov;
X	atpb.atp_rresiovcnt = 1;
X	if ( atp_rresp( atp, &atpb ) < 0 ) {
X	    perror( "atp_rresp" );
X	    exit( 1 );
X	}
X
X	/* sanity */
X	if ( iov.iov_len < 8 || (unsigned char)rbuf[ 0 ] != connid ||
X		rbuf[ 1 ] != PAP_OPENREPLY ) {
X	    fprintf( stderr, "Bad response!\n" );
X	    continue;	/* This is weird, since TIDs must match... */
X	}
X#ifdef EBUG
Xprintf( "< OPENREPLY\n" );
X#endif EBUG
X
X	if ( isatty( 1 )) {
X	    printf( "%.*s\n", iov.iov_len - 9, iov.iov_base + 9 );
X	}
X	updatestatus( iov.iov_base + 9, iov.iov_len - 9 );
X
X	bcopy( &rbuf[ 6 ], &result, sizeof( result ));
X	if ( result != 0 ) {
X	    sleep( 2 );
X	} else {
X	    bcopy( &nn.nn_sat, &sat, sizeof( struct sockaddr_at ));
X	    sat.sat_port = rbuf[ 4 ];
X	    quantum = rbuf[ 5 ];
X	    break;
X	}
X    }
X
X    if ( isatty( 1 )) {
X	printf( "Connected to %.*s:%.*s@%.*s.\n",
X		nn.nn_objlen, nn.nn_obj,
X		nn.nn_typelen, nn.nn_type,
X		nn.nn_zonelen, nn.nn_zone );
X    }
X
X    if ( optind == ac ) {
X	sendfile( 0, atp );
X    } else {
X	for (; optind < ac; optind++ ) {
X	    if ( strcmp( av[ optind ], "-" ) == 0 ) {
X		fd = 0;
X	    } else if (( fd = open( av[ optind ], O_RDONLY )) < 0 ) {
X		perror( av[ optind ] );
X		continue;
X	    }
X	    sendfile( fd, atp );
X	    if ( fd != 0 ) {
X		close( fd );
X	    }
X	}
X    }
X
X    /*
X     * Close connection.
X     */
X    cbuf[ 0 ] = connid;
X    cbuf[ 1 ] = PAP_CLOSE;
X    cbuf[ 2 ] = cbuf[ 3 ] = 0;
X
X    atpb.atp_saddr = &sat;
X    atpb.atp_sreqdata = cbuf;
X    atpb.atp_sreqdlen = 4;		/* bytes in CloseConn request */
X    atpb.atp_sreqto = 2;		/* retry timer */
X    atpb.atp_sreqtries = 5;		/* retry count */
X    if ( atp_sreq( atp, &atpb, 1, ATP_XO ) < 0 ) {
X	perror( "atp_sreq" );
X	exit( 1 );
X    }
X#ifdef EBUG
Xprintf( "> CLOSE\n" );
X#endif EBUG
X
X    iov.iov_base = rbuf;
X    iov.iov_len = sizeof( rbuf );
X    atpb.atp_rresiov = &iov;
X    atpb.atp_rresiovcnt = 1;
X    if ( atp_rresp( atp, &atpb ) < 0 ) {
X	perror( "atp_rresp" );
X	exit( 1 );
X    }
X
X    /* sanity */
X    if ( iov.iov_len != 4 || (unsigned char)rbuf[ 0 ] != connid ||
X	    rbuf[ 1 ] != PAP_CLOSEREPLY ) {
X	fprintf( stderr, "Bad response!\n" );
X	exit( 1 );	/* This is weird, since TIDs must match... */
X    }
X#ifdef EBUG
Xprintf( "< CLOSEREPLY\n" );
X#endif EBUG
X    if ( isatty( 1 )) {
X	printf( "Connection closed.\n" );
X    }
X    exit( 0 );
X}
X
Xchar		fbuf[ PAP_MAXQUANTUM ][ 4 + PAP_MAXDATA ];
Xstruct iovec	rfiov[ PAP_MAXQUANTUM ] = {
X    { fbuf[ 0 ] + 4,	0 },
X    { fbuf[ 1 ] + 4,	0 },
X    { fbuf[ 2 ] + 4,	0 },
X    { fbuf[ 3 ] + 4,	0 },
X    { fbuf[ 4 ] + 4,	0 },
X    { fbuf[ 5 ] + 4,	0 },
X    { fbuf[ 6 ] + 4,	0 },
X    { fbuf[ 7 ] + 4,	0 },
X};
Xstruct iovec	sniov[ PAP_MAXQUANTUM ] = {
X    { fbuf[ 0 ],	0 },
X    { fbuf[ 1 ],	0 },
X    { fbuf[ 2 ],	0 },
X    { fbuf[ 3 ],	0 },
X    { fbuf[ 4 ],	0 },
X    { fbuf[ 5 ],	0 },
X    { fbuf[ 6 ],	0 },
X    { fbuf[ 7 ],	0 },
X};
X
Xchar		nbuf[ PAP_MAXQUANTUM ][ 4 + PAP_MAXDATA ];
Xstruct iovec	rniov[ PAP_MAXQUANTUM ] = {
X    { nbuf[ 0 ],	0 },
X    { nbuf[ 1 ],	0 },
X    { nbuf[ 2 ],	0 },
X    { nbuf[ 3 ],	0 },
X    { nbuf[ 4 ],	0 },
X    { nbuf[ 5 ],	0 },
X    { nbuf[ 6 ],	0 },
X    { nbuf[ 7 ],	0 },
X};
Xstruct iovec	sfiov[ PAP_MAXQUANTUM ] = {
X    { nbuf[ 0 ] + 4,	0 },
X    { nbuf[ 1 ] + 4,	0 },
X    { nbuf[ 2 ] + 4,	0 },
X    { nbuf[ 3 ] + 4,	0 },
X    { nbuf[ 4 ] + 4,	0 },
X    { nbuf[ 5 ] + 4,	0 },
X    { nbuf[ 6 ] + 4,	0 },
X    { nbuf[ 7 ] + 4,	0 },
X};
X
Xint		data = 0;
Xunsigned char	port;
Xunsigned short	seq = 0;
X
Xsendfile( fd, atp )
X    int			fd;
X    ATP			atp;
X{
X    struct timeval	tv;
X    struct sockaddr_at	ssat;
X    struct atp_block	atpb;
X    fd_set		fds;
X    int			fiovcnt = 0, niovcnt = 0, eof = 0, senteof = 0, to = 0;
X    int			cc, i;
X
X    tv.tv_sec = 60;
X    tv.tv_usec = 0;
X
X    /*
X     * Ask for more data.
X     */
X    cbuf[ 0 ] = connid;
X    cbuf[ 1 ] = PAP_READ;
X    if ( ++seq == 0xffff ) seq = 1;
X    bcopy( &seq, &cbuf[ 2 ], sizeof( seq ));
X    atpb.atp_saddr = &sat;
X    atpb.atp_sreqdata = cbuf;
X    atpb.atp_sreqdlen = 4;		/* bytes in SendData request */
X    atpb.atp_sreqto = 15;		/* retry timer */
X    atpb.atp_sreqtries = -1;		/* retry count */
X    if ( atp_sreq( atp, &atpb, oquantum, ATP_XO ) < 0 ) {
X	perror( "atp_sreq" );
X	exit( 1 );
X    }
X#ifdef EBUG
Xprintf( "> READ %d\n", seq );
X#endif EBUG
X
X    for (;;) {
X	FD_ZERO( &fds );
X	if ( !eof && fiovcnt == 0 ) {
X	    FD_SET( fd, &fds );
X	}
X	FD_SET( atp_fileno( atp ), &fds );
X
X	if (( cc = select( FD_SETSIZE, &fds, 0, 0, &tv )) < 0 ) {
X	    perror( "select" );
X	    exit( 1 );
X	}
X
X	/*
X	 * A timeout has occured. Keep track of it, and go ahead and
X	 * send a tickle.
X	 */
X	if ( cc == 0 ) {
X	    if ( to++ > 2 ) {
X		fprintf( stderr, "Connection timed out.\n" );
X		exit( 1 );
X	    }
X
X	    /*
X	     * Send a tickle.
X	     */
X	    cbuf[ 0 ] = connid;
X	    cbuf[ 1 ] = PAP_TICKLE;
X	    cbuf[ 2 ] = cbuf[ 3 ] = 0;
X	    atpb.atp_saddr = &sat;
X	    atpb.atp_sreqdata = cbuf;
X	    atpb.atp_sreqdlen = 4;		/* bytes in Tickle request */
X	    atpb.atp_sreqto = 0;		/* retry timer */
X	    atpb.atp_sreqtries = 1;		/* retry count */
X	    if ( atp_sreq( satp, &atpb, 0, 0 ) < 0 ) {
X		perror( "atp_sreq" );
X		exit( 1 );
X	    }
X#ifdef EBUG
Xprintf( "> TICKLE\n" );
X#endif EBUG
X	} else {
X	    to = 0;
X	}
X
X	/*
X	 * Read data.
X	 */
X	if ( !fiovcnt && FD_ISSET( fd, &fds )) {
X	    for ( i = 0; i < quantum; i++ ) {
X		rfiov[ i ].iov_len = PAP_MAXDATA;
X	    }
X	    if (( cc = readv( fd, rfiov, quantum )) < 0 ) {
X		perror( "readv" );
X		exit( 1 );
X	    }
X	    if ( cc == 0 ) {
X		eof = 1;
X	    }
X	    fiovcnt = cc / PAP_MAXDATA + ( cc % PAP_MAXDATA > 0 );
X	    for ( i = 0; cc > 0; i++ ) {
X		rfiov[ i ].iov_len = ( cc > PAP_MAXDATA ) ? PAP_MAXDATA : cc;
X		cc -= ( cc > PAP_MAXDATA ) ? PAP_MAXDATA : cc;
X	    }
X	}
X
X	if ( FD_ISSET( atp_fileno( atp ), &fds )) {
X	    ssat = sat;
X	    ssat.sat_port = ATADDR_ANYPORT;
X	    switch( atp_rsel( atp, &ssat, ATP_TRESP | ATP_TREQ )) {
X	    case ATP_TREQ :
X		atpb.atp_saddr = &ssat;
X		atpb.atp_rreqdata = cbuf;
X		atpb.atp_rreqdlen = sizeof( cbuf );
X		if ( atp_rreq( atp, &atpb ) < 0 ) {
X		    perror( "atp_rreq" );
X		    exit( 1 );
X		}
X		/* sanity */
X		if ( (unsigned char)cbuf[ 0 ] != connid ) {
X		    fprintf( stderr, "Bad ATP request!\n" );
X		    exit( 1 );
X		}
X
X		switch ( cbuf[ 1 ] ) {
X		case PAP_READ :
X#ifdef EBUG
Xprintf( "< READ\n" );
X#endif EBUG
X		    data = 1;
X		    port = ssat.sat_port;
X		    break;
X
X		case PAP_CLOSE :
X#ifdef EBUG
Xprintf( "< CLOSE\n" );
X#endif EBUG
X		    /*
X		     * Respond to the close request, and fail.
X		     */
X		    sniov[ 0 ].iov_len = 4;
X		    sniov[ 0 ].iov_base[ 0 ] = connid;
X		    sniov[ 0 ].iov_base[ 1 ] = PAP_CLOSEREPLY;
X		    sniov[ 0 ].iov_base[ 2 ] = sniov[ 0 ].iov_base[ 3 ] = 0;
X		    atpb.atp_sresiov = sniov;
X		    atpb.atp_sresiovcnt = 1;
X		    if ( atp_sresp( atp, &atpb ) < 0 ) {
X			perror( "atp_sresp" );
X			exit( 1 );
X		    }
X#ifdef EBUG
Xprintf( "> CLOSEREPLY\n" );
X#endif EBUG
X		    fprintf( stderr, "Connection closed by foreign host.\n" );
X		    exit( 1 );
X
X		case PAP_TICKLE :
X#ifdef EBUG
Xprintf( "< TICKLE\n" );
X#endif EBUG
X		    break;
X		default :
X		    fprintf( stderr, "Bad PAP request!\n" );
X		    exit( 1 );
X		}
X		break;
X
X	    case ATP_TRESP :
X		atpb.atp_saddr = &ssat;
X		for ( i = 0; i < oquantum; i++ ) {
X		    rniov[ i ].iov_len = PAP_MAXDATA + 4;
X		}
X		atpb.atp_rresiov = rniov;
X		atpb.atp_rresiovcnt = oquantum;
X		if ( atp_rresp( atp, &atpb ) < 0 ) {
X		    perror( "atp_rresp" );
X		    exit( 1 );
X		}
X
X#ifndef PRAGMATIC
X		/*
X		 * The HP LJIIISI w/ BridgePort LocalTalk card sends
X		 * zero instead of the connid.
X		 */
X		if ( (unsigned char)rniov[ 0 ].iov_base[ 0 ] != connid ) {
X		    fprintf( stderr, "Bad data response!\n" );
X		    exit( 1 );
X		}
X#endif PRAGMATIC
X		if ( rniov[ 0 ].iov_base[ 1 ] != PAP_DATA ) {
X		    fprintf( stderr, "Bad data response!\n" );
X		    exit( 1 );
X		}
X#ifdef EBUG
Xprintf( "< DATA\n" );
X#endif EBUG
X
X		/* eof */
X		if ( rniov[ 0 ].iov_base[ 2 ] ) {
X		    return( 0 );
X		}
X
X		for ( cc = 0, i = 0; i < atpb.atp_rresiovcnt; i++ ) {
X		    cc += sfiov[ i ].iov_len = rniov[ i ].iov_len - 4;
X		}
X		if ( writev( 1, sfiov, atpb.atp_rresiovcnt ) < cc ) {
X		    perror( "writev" );
X		    exit( 1 );
X		}
X
X		/*
X		 * Ask for more data.
X		 */
X		cbuf[ 0 ] = connid;
X		cbuf[ 1 ] = PAP_READ;
X		if ( ++seq == 0xffff ) seq = 1;
X		bcopy( &seq, &cbuf[ 2 ], sizeof( seq ));
X		atpb.atp_saddr = &sat;
X		atpb.atp_sreqdata = cbuf;
X		atpb.atp_sreqdlen = 4;		/* bytes in SendData request */
X		atpb.atp_sreqto = 15;		/* retry timer */
X		atpb.atp_sreqtries = -1;	/* retry count */
X		if ( atp_sreq( atp, &atpb, oquantum, ATP_XO ) < 0 ) {
X		    perror( "atp_sreq" );
X		    exit( 1 );
X		}
X#ifdef EBUG
Xprintf( "> READ %d\n", seq );
X#endif EBUG
X		break;
X
X	    default:
X		perror( "atp_rsel" );
X		exit( 1 );
X	    }
X	}
X
X	/*
X	 * Send whatever is pending.
X	 */
X	if ( !senteof && data && ( fiovcnt || eof )) {
X	    ssat.sat_port = port;
X	    atpb.atp_saddr = &ssat;
X	    if ( fiovcnt ) {
X		for ( i = 0; i < fiovcnt; i++ ) {
X		    sniov[ i ].iov_len = rfiov[ i ].iov_len + 4;
X		    sniov[ i ].iov_base[ 0 ] = connid;
X		    sniov[ i ].iov_base[ 1 ] = PAP_DATA;
X		    senteof = sniov[ i ].iov_base[ 2 ] = eof;
X		    sniov[ i ].iov_base[ 3 ] = 0;
X		}
X	    } else {
X		sniov[ 0 ].iov_len = 4;
X		sniov[ 0 ].iov_base[ 0 ] = connid;
X		sniov[ 0 ].iov_base[ 1 ] = PAP_DATA;
X		senteof = sniov[ 0 ].iov_base[ 2 ] = eof;
X		sniov[ 0 ].iov_base[ 3 ] = 0;
X	    }
X	    atpb.atp_sresiov = sniov;
X	    atpb.atp_sresiovcnt = fiovcnt ? fiovcnt : 1;
X	    if ( atp_sresp( atp, &atpb ) < 0 ) {
X		perror( "atp_sresp" );
X		exit( 1 );
X	    }
X#ifdef EBUG
Xif ( eof ) {
Xprintf( "> DATA (eof)\n" );
X} else {
Xprintf( "> DATA\n" );
X}
X#endif EBUG
X	    data = fiovcnt = 0;
X#ifdef PRAGMATIC
X	    /*
X	     * The Apple LaserWriter IIf (and perhaps g) doesn't seem to
X	     * send us an EOF. To work around this heinous protocol
X	     * violation, we won't wait for their EOF before sending our
X	     * next file or closing.
X	     */
X	    if ( eof ) {
X		return( 0 );
X	    }
X#endif PRAGMATIC
X
X	} else {
X	    /*
X	     * If we can't send data right now, go ahead and get the
X	     * status. This is cool, because we get here reliable
X	     * if there is a problem.
X	     */
X	    cbuf[ 0 ] = 0;
X	    cbuf[ 1 ] = PAP_SENDSTATUS;
X	    cbuf[ 2 ] = cbuf[ 3 ] = 0;
X	    atpb.atp_saddr = &nn.nn_sat;
X	    atpb.atp_sreqdata = cbuf;
X	    atpb.atp_sreqdlen = 4;	/* bytes in SendStatus request */
X	    atpb.atp_sreqto = 2;		/* retry timer */
X	    atpb.atp_sreqtries = 5;		/* retry count */
X	    if ( atp_sreq( satp, &atpb, 1, 0 ) < 0 ) {
X		perror( "atp_sreq" );
X		exit( 1 );
X	    }
X#ifdef EBUG
Xprintf( "> SENDSTATUS\n" );
X#endif EBUG
X
X	    atpb.atp_saddr = &nn.nn_sat;
X	    rniov[ 0 ].iov_len = PAP_MAXDATA + 4;
X	    atpb.atp_rresiov = rniov;
X	    atpb.atp_rresiovcnt = 1;
X	    if ( atp_rresp( satp, &atpb ) < 0 ) {
X		perror( "atp_rresp" );
X		continue;
X	    }
X
X#ifndef PRAGMATIC
X	    /*
X	     * The stinking LaserWriter IINTX puts crap in this
X	     * field.
X	     */
X	    if ( rniov[ 0 ].iov_base[ 0 ] != 0 ) {
X		fprintf( stderr, "Bad status response!\n" );
X		exit( 1 );
X	    }
X#endif PRAGMATIC
X
X	    if ( rniov[ 0 ].iov_base[ 1 ] != PAP_STATUS ||
X		    atpb.atp_rresiovcnt != 1 ) {
X		fprintf( stderr, "Bad status response!\n" );
X		exit( 1 );
X	    }
X#ifdef EBUG
Xprintf( "< STATUS\n" );
X#endif EBUG
X	    updatestatus( rniov[ 0 ].iov_base + 9,
X		    rniov[ 0 ].iov_base[ 8 ] );
X	}
X    }
X}
X
Xupdatestatus( s, len )
X    char	*s;
X    int		len;
X{
X    int			fd;
X    struct iovec	iov[ 2 ];
X
X    if ( !status ) {
X	return;
X    }
X
X    if (( fd = open( status, O_WRONLY|O_TRUNC )) < 0 ) {
X	perror( status );
X	status = NULL;
X	return;
X    }
X    iov[ 0 ].iov_base = s;
X    iov[ 0 ].iov_len = len;
X    iov[ 1 ].iov_base = "\n";
X    iov[ 1 ].iov_len = 1;
X    writev( fd, iov, 2 );
X    close( fd );
X}
END_OF_FILE
if test 15953 -ne `wc -c <'pap/pap.c'`; then
    echo shar: \"'pap/pap.c'\" unpacked with wrong size!
fi
# end of 'pap/pap.c'
fi
if test -f 'pap/papstatus.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'pap/papstatus.c'\"
else
echo shar: Extracting \"'pap/papstatus.c'\" \(3965 characters\)
sed "s/^X//" >'pap/papstatus.c' <<'END_OF_FILE'
X/*
X * Copyright (c) 1990,1991 Regents of The University of Michigan.
X * All Rights Reserved.
X *
X * Permission to use, copy, modify, and distribute this software and
X * its documentation for any purpose and without fee is hereby granted,
X * provided that the above copyright notice appears in all copies and
X * that both that copyright notice and this permission notice appear
X * in supporting documentation, and that the name of The University
X * of Michigan not be used in advertising or publicity pertaining to
X * distribution of the software without specific, written prior
X * permission. This software is supplied as is without expressed or
X * implied warranties of any kind.
X *
X *	Research Systems Unix Group
X *	The University of Michigan
X *	c/o Mike Clark
X *	535 W. William Street
X *	Ann Arbor, Michigan
X *	+1-313-763-0525
X *	[email-masked]
X */
X
X#include <sys/types.h>
X#include <sys/time.h>
X#include <sys/uio.h>
X#include <sys/file.h>
X#include <netatalk/endian.h>
X#include <netatalk/at.h>
X#include <atalk/atp.h>
X#include <atalk/pap.h>
X#include <atalk/nbp.h>
X#include <stdio.h>
X#include <strings.h>
X
X#define _PATH_PAPRC	".paprc"
X
Xusage( path )
X    char	*path;
X{
X    char	*p;
X
X    if (( p = rindex( path, '/' )) == NULL ) {
X	p = path;
X    } else {
X	p++;
X    }
X    fprintf( stderr,
X	"Usage:\t%s [ -p printername ]\n", p );
X    exit( 1 );
X}
X
Xchar *
Xpaprc()
X{
X    static char	s[ 32 + 1 + 32 + 1 + 32 ];
X    char	*name = NULL;
X    FILE	*f;
X
X    if (( f = fopen( _PATH_PAPRC, "r" )) == NULL ) {
X	return( NULL );
X    }
X    while ( fgets( s, sizeof( s ), f ) != NULL ) {
X	s[ strlen( s ) - 1 ] = '\0';	/* remove trailing newline */
X	if ( *s == '#' ) {
X	    continue;
X	}
X	name = s;
X	break;
X    }
X    fclose( f );
X    return( name );
X}
X
Xchar			*printer = NULL;
X
Xchar			cbuf[ 8 ];
Xstruct nbpnve		nn;
X
Xmain( ac, av )
X    int		ac;
X    char	**av;
X{
X    ATP			atp;
X    int			wait, c, err = 0;
X    char		*obj = NULL, *type = "LaserWriter", *zone = "*";
X    extern char		*optarg;
X    extern int		optind;
X
X    while (( c = getopt( ac, av, "p:s:" )) != EOF ) {
X	switch ( c ) {
X	case 'p' :
X	    printer = optarg;
X	    break;
X
X	default :
X	    fprintf( stderr, "Unknown option: '%c'\n", c );
X	    err++;
X	}
X    }
X    if ( err ) {
X	usage( *av );
X    }
X    if ( printer == NULL && (( printer = paprc()) == NULL )) {
X	usage( *av );
X    }
X
X    /*
X     * Open connection.
X     */
X    if ( nbp_name( printer, &obj, &type, &zone ) < 0 ) {
X	fprintf( stderr, "%s: Bad name\n", printer );
X	exit( 1 );
X    }
X    if ( obj == NULL ) {
X	fprintf( stderr, "%s: Bad name\n", printer );
X	exit( 1 );
X    }
X    if ( nbp_lookup( obj, type, zone, &nn, 1 ) <= 0 ) {
X	perror( "nbp_lookup" );
X	exit( 1 );
X    }
X
X    if (( atp = atp_open( 0 )) == NULL ) {
X	perror( "atp_open" );
X	exit( 1 );
X    }
X
X    if ( optind == ac ) {
X	getstatus( atp, &nn.nn_sat );
X	exit( 0 );
X    }
X    if ( optind - ac > 1 ) {
X	usage( *av );
X    }
X    wait = atoi( av[ optind ] );
X    for (;;) {
X	getstatus( atp, &nn.nn_sat );
X	sleep( wait );
X    }
X}
X
Xgetstatus( atp, sat )
X    ATP			atp;
X    struct sockaddr_at	*sat;
X{
X    struct iovec	iov;
X    struct atp_block	atpb;
X    char		rbuf[ ATP_MAXDATA ];
X
X    cbuf[ 0 ] = 0;
X    cbuf[ 1 ] = PAP_SENDSTATUS;
X    cbuf[ 2 ] = cbuf[ 3 ] = 0;
X
X    atpb.atp_saddr = sat;
X    atpb.atp_sreqdata = cbuf;
X    atpb.atp_sreqdlen = 4;		/* bytes in SendStatus request */
X    atpb.atp_sreqto = 2;		/* retry timer */
X    atpb.atp_sreqtries = 5;		/* retry count */
X    if ( atp_sreq( atp, &atpb, 1, ATP_XO ) < 0 ) {
X	perror( "atp_sreq" );
X	exit( 1 );
X    }
X
X    iov.iov_base = rbuf;
X    iov.iov_len = sizeof( rbuf );
X    atpb.atp_rresiov = &iov;
X    atpb.atp_rresiovcnt = 1;
X    if ( atp_rresp( atp, &atpb ) < 0 ) {
X	perror( "atp_rresp" );
X	exit( 1 );
X    }
X
X    /* sanity */
X    if ( iov.iov_len < 8 ||
X	    rbuf[ 1 ] != PAP_STATUS ) {
X	fprintf( stderr, "Bad response!\n" );
X	return;	/* This is weird, since TIDs must match... */
X    }
X
X    printf( "%.*s\n", iov.iov_len - 9, iov.iov_base + 9 );
X}
END_OF_FILE
if test 3965 -ne `wc -c <'pap/papstatus.c'`; then
    echo shar: \"'pap/papstatus.c'\" unpacked with wrong size!
fi
# end of 'pap/papstatus.c'
fi
echo shar: End of shell archive.
exit 0