1/*
2 * $Id: pap.c,v 1.14 2009-10-16 01:10:59 didg Exp $
3 *
4 * Copyright (c) 1990,1994 Regents of The University of Michigan.
5 * All Rights Reserved.  See COPYRIGHT.
6 */
7
8#ifdef HAVE_CONFIG_H
9#include "config.h"
10#endif /* HAVE_CONFIG_H */
11
12#include <sys/types.h>
13#include <sys/time.h>
14#include <sys/uio.h>
15#include <netatalk/endian.h>
16#include <netatalk/at.h>
17#include <errno.h>
18#include <atalk/atp.h>
19#include <atalk/pap.h>
20#include <atalk/nbp.h>
21#include <atalk/util.h>
22#ifdef HAVE_FCNTL_H
23#include <fcntl.h>
24#endif /* HAVE_FCNTL_H */
25#include <stdio.h>
26#include <string.h>
27#include <string.h>
28#include <stdlib.h>
29
30#define FUCKED
31
32#define _PATH_PAPRC	".paprc"
33
34/* Forward Declarations */
35static void updatestatus(char *s, int len);
36static int send_file(int fd, ATP atp, int lastfile);
37
38static void usage(char *path)
39{
40    char	*p;
41
42    if (( p = strrchr( path, '/' )) == NULL ) {
43	p = path;
44    } else {
45	p++;
46    }
47    fprintf( stderr,
48	"Usage:\t%s [ -A address ] [ -c ] [ -d ] [ -e ] [ -E ] [ -p printer ]\n"
49	"    [ -s statusfile ] [ -w ] [ -W ] [ FILES ]\n"
50	"  -A address    - printer Appletalk address\n"
51	"  -c            - take cuts (lie about wait time)\n"
52	"  -d            - enable debug\n"
53	"  -e            - send stdout to stderr\n"
54	"  -E            - don't wait for EOF from printer\n"
55	"  -p printer    - printer name\n"
56	"  -s statusfile - put current printer status in statusfile\n"
57	"  -w            - wait for printer status = 'waiting'\n"
58	"  -W            - wait for printer status = 'idle'\n"
59	"  FILES         - send FILES to printer\n"
60	, p );
61    exit( 2 );
62}
63
64static char *
65paprc(void)
66{
67    static char	s[ 32 + 1 + 32 + 1 + 32 ];
68    char	*name = NULL;
69    FILE	*f;
70
71    if (( f = fopen( _PATH_PAPRC, "r" )) == NULL ) {
72	if ( errno == ENOENT ) {
73	    return( NULL );
74	} else {
75	    perror( _PATH_PAPRC );
76	    exit( 2 );
77	}
78    }
79    while ( fgets( s, sizeof( s ), f ) != NULL ) {
80	s[ strlen( s ) - 1 ] = '\0';	/* remove trailing newline */
81	if ( *s == '#' ) {
82	    continue;
83	}
84	name = s;
85	break;
86    }
87    fclose( f );
88    return( name );
89}
90
91static char			*printer = NULL;
92static char			*status = NULL;
93static int			noeof = 0;
94static int			waitforprinter = 0;
95
96static unsigned char		connid, quantum, oquantum = PAP_MAXQUANTUM;
97static struct sockaddr_at	sat;
98
99static char			cbuf[ 8 ];
100static struct nbpnve		nn;
101static ATP			satp;
102
103static char		fbuf[ PAP_MAXQUANTUM ][ 4 + PAP_MAXDATA ];
104static struct iovec	rfiov[ PAP_MAXQUANTUM ] = {
105    { fbuf[ 0 ] + 4,	0 },
106    { fbuf[ 1 ] + 4,	0 },
107    { fbuf[ 2 ] + 4,	0 },
108    { fbuf[ 3 ] + 4,	0 },
109    { fbuf[ 4 ] + 4,	0 },
110    { fbuf[ 5 ] + 4,	0 },
111    { fbuf[ 6 ] + 4,	0 },
112    { fbuf[ 7 ] + 4,	0 },
113};
114
115static struct iovec	sniov[ PAP_MAXQUANTUM ] = {
116    { fbuf[ 0 ],	0 },
117    { fbuf[ 1 ],	0 },
118    { fbuf[ 2 ],	0 },
119    { fbuf[ 3 ],	0 },
120    { fbuf[ 4 ],	0 },
121    { fbuf[ 5 ],	0 },
122    { fbuf[ 6 ],	0 },
123    { fbuf[ 7 ],	0 },
124};
125
126static char		nbuf[ PAP_MAXQUANTUM ][ 4 + PAP_MAXDATA ];
127static struct iovec	rniov[ PAP_MAXQUANTUM ] = {
128    { nbuf[ 0 ],	0 },
129    { nbuf[ 1 ],	0 },
130    { nbuf[ 2 ],	0 },
131    { nbuf[ 3 ],	0 },
132    { nbuf[ 4 ],	0 },
133    { nbuf[ 5 ],	0 },
134    { nbuf[ 6 ],	0 },
135    { nbuf[ 7 ],	0 },
136};
137
138static struct iovec	sfiov[ PAP_MAXQUANTUM ] = {
139    { nbuf[ 0 ] + 4,	0 },
140    { nbuf[ 1 ] + 4,	0 },
141    { nbuf[ 2 ] + 4,	0 },
142    { nbuf[ 3 ] + 4,	0 },
143    { nbuf[ 4 ] + 4,	0 },
144    { nbuf[ 5 ] + 4,	0 },
145    { nbuf[ 6 ] + 4,	0 },
146    { nbuf[ 7 ] + 4,	0 },
147};
148
149static int debug;
150
151int main( int ac, char	**av)
152{
153    ATP			atp;
154    struct atp_block	atpb;
155    int			c, err = 0, fd, cuts = 0;
156    char		*obj = NULL, *type = "LaserWriter", *zone = "*";
157    struct timeval	stv, tv;
158    char		rbuf[ ATP_MAXDATA ];
159    struct iovec	iov;
160    unsigned short	waiting, result;
161    int			connattempts = 10;
162    int			waitforidle = 0;
163    struct at_addr      addr;
164
165    extern char		*optarg;
166    extern int		optind;
167
168    memset(&addr, 0, sizeof(addr));
169    while (( c = getopt( ac, av, "dWwcep:s:EA:" )) != EOF ) {
170	switch ( c ) {
171#ifdef FUCKED
172	case 'w' :
173	    waitforprinter = 1;
174	    break;
175
176	case 'W' :
177	    waitforidle = 1;
178	    break;
179#endif /* FUCKED */
180
181	/* enable debugging */
182	case 'd' :
183	    debug++;
184	    break;
185
186	case 'c' :
187	    cuts++;
188	    break;
189
190	case 'e' :	/* send stdout to stderr */
191	    dup2( 2, 1 );
192	    break;
193
194	case 'p' :
195	    printer = optarg;
196	    break;
197
198	case 's' :
199	    status = optarg;
200	    break;
201
202	case 'E' :
203	    noeof = 1;
204	    break;
205
206	case 'A':
207	    if (!atalk_aton(optarg, &addr)) {
208	      fprintf(stderr, "Bad address.\n");
209	      exit(1);
210	    }
211	    break;
212
213	default :
214	    err++;
215	}
216    }
217    if ( err ) {
218	usage( *av );
219    }
220    if ( printer == NULL && (( printer = paprc()) == NULL )) {
221	fprintf( stderr, "No printer specified and ./.paprc not found.\n" );
222	exit( 2 );
223    }
224
225    /*
226     * Open connection.
227     */
228    if ( nbp_name( printer, &obj, &type, &zone ) < 0 ) {
229	fprintf( stderr, "%s: Bad name\n", printer );
230	exit( 2 );
231    }
232    if ( obj == NULL ) {
233	fprintf( stderr, "%s: Bad name\n", printer );
234	exit( 2 );
235    }
236
237    if ( nbp_lookup( obj, type, zone, &nn, 1, &addr ) <= 0 ) {
238	if ( errno != 0 ) {
239	    perror( "nbp_lookup" );
240	    exit( 2 );
241	}
242	fprintf( stderr, "%s:%s@%s: NBP Lookup failed\n", obj, type, zone );
243	exit( 1 );
244    }
245
246    if ( isatty( 1 )) {
247	printf( "Trying %u.%d:%d ...\n", ntohs( nn.nn_sat.sat_addr.s_net ),
248		nn.nn_sat.sat_addr.s_node, nn.nn_sat.sat_port );
249    }
250
251    if (( atp = atp_open( ATADDR_ANYPORT, &addr )) == NULL ) {
252	perror( "atp_open" );
253	exit( 2 );
254    }
255    if (( satp = atp_open( ATADDR_ANYPORT, &addr )) == NULL ) {
256	perror( "atp_open" );
257	exit( 2 );
258    }
259
260    while ( waitforidle ) {
261	char	st_buf[ 1024 ];	/* XXX too big */
262
263	cbuf[ 0 ] = 0;
264	cbuf[ 1 ] = PAP_SENDSTATUS;
265	cbuf[ 2 ] = cbuf[ 3 ] = 0;
266	atpb.atp_saddr = &nn.nn_sat;
267	atpb.atp_sreqdata = cbuf;
268	atpb.atp_sreqdlen = 4;	/* bytes in SendStatus request */
269	atpb.atp_sreqto = 2;		/* retry timer */
270	atpb.atp_sreqtries = 5;		/* retry count */
271	if ( atp_sreq( satp, &atpb, 1, 0 ) < 0 ) {
272	    perror( "atp_sreq" );
273	    exit( 1 );
274	}
275
276	if(debug){ printf( "SENDSTATUS >\n" ), fflush( stdout );}
277
278	atpb.atp_saddr = &nn.nn_sat;
279	rniov[ 0 ].iov_len = PAP_MAXDATA + 4;
280	atpb.atp_rresiov = rniov;
281	atpb.atp_rresiovcnt = 1;
282	if ( atp_rresp( satp, &atpb ) < 0 ) {
283	    perror( "atp_rresp" );
284	    continue;
285	}
286
287#ifndef NONZEROSTATUS
288	/*
289	 * The stinking LaserWriter IINTX puts crap in this
290	 * field.
291	 */
292	if ( ((char *)rniov[ 0 ].iov_base)[ 0 ] != 0 ) {
293	    fprintf( stderr, "Bad status response!\n" );
294	    exit( 1 );
295	}
296#endif /* NONZEROSTATUS */
297
298	if ( ((char *)rniov[ 0 ].iov_base)[ 1 ] != PAP_STATUS ||
299		atpb.atp_rresiovcnt != 1 ) {
300	    fprintf( stderr, "Bad status response!\n" );
301	    exit( 1 );
302	}
303
304	if(debug){ printf( "< STATUS\n" ), fflush( stdout );}
305
306	memcpy( st_buf, (char *) rniov[ 0 ].iov_base + 9,
307		((char *)rniov[ 0 ].iov_base)[ 8 ] );
308	st_buf[ (int) ((char *)rniov[ 0 ].iov_base)[ 8 ]] = '\0';
309	if ( strstr( st_buf, "idle" ) != NULL ) {
310	    waitforidle = 0;
311	} else {
312	    updatestatus( (char *) rniov[ 0 ].iov_base + 9,
313		    ((char *)rniov[ 0 ].iov_base)[ 8 ] );
314	    sleep( 5 );
315	}
316    }
317
318    cbuf[ 0 ] = connid = getpid() & 0xff;
319    cbuf[ 1 ] = PAP_OPEN;
320    cbuf[ 2 ] = cbuf[ 3 ] = 0;
321    cbuf[ 4 ] = atp_sockaddr( atp )->sat_port;
322    cbuf[ 5 ] = oquantum;	/* flow quantum */
323    if ( gettimeofday( &stv, NULL ) < 0 ) {
324	perror( "gettimeofday" );
325	exit( 2 );
326    }
327    for (;;) {
328	if ( cuts ) {
329	    waiting = 0xffff;
330	} else {
331	    if ( gettimeofday( &tv, NULL ) < 0 ) {
332		perror( "gettimeofday" );
333		exit( 2 );
334	    }
335	    waiting = htons( tv.tv_sec - stv.tv_sec );
336	}
337	memcpy(cbuf +  6, &waiting, sizeof( waiting ));
338
339	atpb.atp_saddr = &nn.nn_sat;
340	atpb.atp_sreqdata = cbuf;
341	atpb.atp_sreqdlen = 8;		/* bytes in OpenConn request */
342	atpb.atp_sreqto = 2;		/* retry timer */
343	atpb.atp_sreqtries = 5;		/* retry count */
344	if ( atp_sreq( atp, &atpb, 1, ATP_XO ) < 0 ) {
345	    perror( "atp_sreq" );
346	    exit( 1 );
347	}
348
349	if(debug){ printf( "OPEN >\n" ), fflush( stdout );}
350
351	iov.iov_base = rbuf;
352	iov.iov_len = sizeof( rbuf );
353	atpb.atp_rresiov = &iov;
354	atpb.atp_rresiovcnt = 1;
355	if ( atp_rresp( atp, &atpb ) < 0 ) {
356	    perror( "atp_rresp" );
357	    if ( connattempts-- <= 0 ) {
358		fprintf( stderr, "Can't connect!\n" );
359		exit( 1 );
360	    }
361	    continue;
362	}
363
364	/* sanity */
365	if ( iov.iov_len < 8 || (unsigned char)rbuf[ 0 ] != connid ||
366		rbuf[ 1 ] != PAP_OPENREPLY ) {
367	    fprintf( stderr, "Bad response!\n" );
368	    continue;	/* This is weird, since TIDs must match... */
369	}
370
371	if(debug){ printf( "< OPENREPLY\n" ), fflush( stdout );}
372
373	if ( isatty( 1 )) {
374	    printf( "%.*s\n", (int)iov.iov_len - 9, (char *) iov.iov_base + 9 );
375	}
376	updatestatus( (char *) iov.iov_base + 9, iov.iov_len - 9 );
377
378	memcpy( &result, rbuf +  6,  sizeof( result ));
379	if ( result != 0 ) {
380	    sleep( 2 );
381	} else {
382	    memcpy( &sat, &nn.nn_sat, sizeof( struct sockaddr_at ));
383	    sat.sat_port = rbuf[ 4 ];
384	    quantum = rbuf[ 5 ];
385	    break;
386	}
387    }
388
389    if ( isatty( 1 )) {
390	printf( "Connected to %.*s:%.*s@%.*s.\n",
391		nn.nn_objlen, nn.nn_obj,
392		nn.nn_typelen, nn.nn_type,
393		nn.nn_zonelen, nn.nn_zone );
394    }
395
396    if ( optind == ac ) {
397	send_file( 0, atp, 1 );
398    } else {
399	for (; optind < ac; optind++ ) {
400	    if ( strcmp( av[ optind ], "-" ) == 0 ) {
401		fd = 0;
402	    } else if (( fd = open( av[ optind ], O_RDONLY )) < 0 ) {
403		perror( av[ optind ] );
404		continue;
405	    }
406	    send_file( fd, atp, ( optind == ac - 1 ) ? 1 : 0 );
407	    if ( fd != 0 ) {
408		close( fd );
409	    }
410	}
411    }
412
413    /*
414     * Close connection.
415     */
416    cbuf[ 0 ] = connid;
417    cbuf[ 1 ] = PAP_CLOSE;
418    cbuf[ 2 ] = cbuf[ 3 ] = 0;
419
420    atpb.atp_saddr = &sat;
421    atpb.atp_sreqdata = cbuf;
422    atpb.atp_sreqdlen = 4;		/* bytes in CloseConn request */
423    atpb.atp_sreqto = 2;		/* retry timer */
424    atpb.atp_sreqtries = 5;		/* retry count */
425    if ( atp_sreq( atp, &atpb, 1, ATP_XO ) < 0 ) {
426	perror( "atp_sreq" );
427	exit( 1 );
428    }
429
430	if(debug){ printf( "CLOSE >\n" ), fflush( stdout );}
431
432    iov.iov_base = rbuf;
433    iov.iov_len = sizeof( rbuf );
434    atpb.atp_rresiov = &iov;
435    atpb.atp_rresiovcnt = 1;
436    if ( atp_rresp( atp, &atpb ) < 0 ) {
437	perror( "atp_rresp" );
438	exit( 1 );
439    }
440
441    /* sanity */
442    if ( iov.iov_len != 4 || rbuf[ 1 ] != PAP_CLOSEREPLY ) {
443	fprintf( stderr, "Bad response!\n" );
444	exit( 1 );
445    }
446
447#ifndef ZEROCONNID
448    /*
449     * The AGFA Viper Rip doesn't have the connection id in the close request.
450     */
451    if ((unsigned char)rbuf[ 0 ] != connid ) {
452	fprintf( stderr, "Bad connid in close!\n" );
453	exit( 1 );
454    }
455#endif /* ZEROCONNID */
456
457	if(debug){ printf( "< CLOSEREPLY\n" ), fflush( stdout );}
458
459    if ( isatty( 1 )) {
460	printf( "Connection closed.\n" );
461    }
462    exit( 0 );
463}
464
465static int		data = 0;
466static unsigned char	port;
467static u_int16_t	seq = 0;
468
469static int send_file( int fd, ATP atp, int lastfile)
470{
471    struct timeval	stv, tv;
472    struct sockaddr_at	ssat;
473    struct atp_block	atpb;
474    fd_set		fds;
475    int			fiovcnt = 0, eof = 0, senteof = 0, to = 0;
476    int			cc, i;
477    unsigned short	netseq;
478
479    if ( gettimeofday( &stv, NULL ) < 0 ) {
480	perror( "gettimeofday" );
481	exit( 2 );
482    }
483
484    /*
485     * Ask for more data.
486     */
487    cbuf[ 0 ] = connid;
488    cbuf[ 1 ] = PAP_READ;
489    if ( ++seq == 0 ) seq = 1;
490    netseq = htons( seq );
491    memcpy( cbuf +  2, &netseq, sizeof( netseq ));
492    atpb.atp_saddr = &sat;
493    atpb.atp_sreqdata = cbuf;
494    atpb.atp_sreqdlen = 4;		/* bytes in SendData request */
495    atpb.atp_sreqto = 15;		/* retry timer */
496    atpb.atp_sreqtries = -1;		/* retry count */
497    if ( atp_sreq( atp, &atpb, oquantum, ATP_XO ) < 0 ) {
498	perror( "atp_sreq" );
499	exit( 1 );
500    }
501
502	if(debug){ printf( "READ %d >\n", seq ), fflush( stdout );}
503
504    for (;;) {
505	if ( gettimeofday( &tv, NULL ) < 0 ) {
506	    perror( "gettimeofday" );
507	    exit( 2 );
508	}
509
510	if (( tv.tv_sec - stv.tv_sec ) >= 60 ) {
511	    stv = tv;
512
513	    /*
514	     * Send a tickle.
515	     */
516	    cbuf[ 0 ] = connid;
517	    cbuf[ 1 ] = PAP_TICKLE;
518	    cbuf[ 2 ] = cbuf[ 3 ] = 0;
519	    atpb.atp_saddr = &sat;
520	    atpb.atp_sreqdata = cbuf;
521	    atpb.atp_sreqdlen = 4;		/* bytes in Tickle request */
522	    atpb.atp_sreqto = 0;		/* retry timer */
523	    atpb.atp_sreqtries = 1;		/* retry count */
524	    if ( atp_sreq( satp, &atpb, 0, 0 ) < 0 ) {
525		perror( "atp_sreq" );
526		exit( 1 );
527	    }
528
529	if(debug){ printf( "TICKLE >\n" ), fflush( stdout );}
530	}
531
532	tv.tv_sec = stv.tv_sec + 60 - tv.tv_sec;
533	tv.tv_usec = 0;
534
535	FD_ZERO( &fds );
536	if ( !waitforprinter && !eof && fiovcnt == 0 ) {
537	    FD_SET( fd, &fds );
538	}
539	FD_SET( atp_fileno( atp ), &fds );
540
541	if (( cc = select( FD_SETSIZE, &fds, NULL, NULL, &tv )) < 0 ) {
542	    perror( "select" );
543	    exit( 2 );
544	}
545
546	/*
547	 * A timeout has occured. Keep track of it.
548	 */
549	if ( cc == 0 ) {
550	    if ( to++ > 2 ) {
551		fprintf( stderr, "Connection timed out.\n" );
552		exit( 1 );
553	    }
554	    continue;
555	}
556
557	/*
558	 * Read data.
559	 */
560	if ( !fiovcnt && FD_ISSET( fd, &fds )) {
561	    for ( i = 0; i < quantum; i++ ) {
562		rfiov[ i ].iov_len = PAP_MAXDATA;
563	    }
564	    if (( cc = readv( fd, rfiov, quantum )) < 0 ) {
565		perror( "readv" );
566		exit( 2 );
567	    }
568	    if ( cc == 0 ) {
569		eof = 1;
570	    }
571	    fiovcnt = cc / PAP_MAXDATA + ( cc % PAP_MAXDATA > 0 );
572	    for ( i = 0; cc > 0; i++ ) {
573		rfiov[ i ].iov_len = ( cc > PAP_MAXDATA ) ? PAP_MAXDATA : cc;
574		cc -= ( cc > PAP_MAXDATA ) ? PAP_MAXDATA : cc;
575	    }
576	}
577
578	if ( FD_ISSET( atp_fileno( atp ), &fds )) {
579	    ssat = sat;
580	    ssat.sat_port = ATADDR_ANYPORT;
581	    switch( atp_rsel( atp, &ssat, ATP_TRESP | ATP_TREQ )) {
582	    case ATP_TREQ :
583		atpb.atp_saddr = &ssat;
584		atpb.atp_rreqdata = cbuf;
585		atpb.atp_rreqdlen = sizeof( cbuf );
586		if ( atp_rreq( atp, &atpb ) < 0 ) {
587		    perror( "atp_rreq" );
588		    exit( 1 );
589		}
590
591		if ( (unsigned char)cbuf[ 0 ] != connid ) {
592		    break;
593		}
594
595		/* reset timeout counter for all valid requests */
596		to = 0;
597
598		switch ( cbuf[ 1 ] ) {
599		case PAP_READ :
600		    memcpy( cbuf +  2, &netseq, sizeof( netseq ));
601	if(debug){ printf( "< READ %d\n", ntohs( netseq )), fflush( stdout );}
602#ifdef notdef
603		    if ( netseq != 0 ) {
604			if ( rseq != ntohs( netseq )) {
605	if(debug){ printf( "| DUP %d\n", rseq ), fflush( stdout );}
606			    break;
607			}
608			if ( rseq++ == 0xffff ) rseq = 1;
609		    }
610#endif /* notdef */
611
612		    data = 1;
613		    port = ssat.sat_port;
614		    break;
615
616		case PAP_CLOSE :
617
618	if(debug){ printf( "< CLOSE\n" ), fflush( stdout );}
619
620		    /*
621		     * Respond to the close request, and fail.
622		     */
623		    sniov[ 0 ].iov_len = 4;
624		    ((char *)sniov[ 0 ].iov_base)[ 0 ] = connid;
625		    ((char *)sniov[ 0 ].iov_base)[ 1 ] = PAP_CLOSEREPLY;
626		    ((char *)sniov[ 0 ].iov_base)[ 2 ] =
627			    ((char *)sniov[ 0 ].iov_base)[ 3 ] = 0;
628		    atpb.atp_sresiov = sniov;
629		    atpb.atp_sresiovcnt = 1;
630		    if ( atp_sresp( atp, &atpb ) < 0 ) {
631			perror( "atp_sresp" );
632			exit( 1 );
633		    }
634
635	if(debug){ printf( "CLOSEREPLY >\n" ), fflush( stdout );}
636
637		    fprintf( stderr, "Connection closed by foreign host.\n" );
638		    exit( 1 );
639
640		case PAP_TICKLE :
641
642	if(debug){ printf( "< TICKLE\n" ), fflush( stdout );}
643
644		    break;
645		default :
646		    fprintf( stderr, "Bad PAP request!\n" );
647		    exit( 1 );
648		}
649		break;
650
651	    case ATP_TRESP :
652		/* reset timeout counter for all valid requests */
653		to = 0;
654
655		atpb.atp_saddr = &ssat;
656		for ( i = 0; i < oquantum; i++ ) {
657		    rniov[ i ].iov_len = PAP_MAXDATA + 4;
658		}
659		atpb.atp_rresiov = rniov;
660		atpb.atp_rresiovcnt = oquantum;
661		if ( atp_rresp( atp, &atpb ) < 0 ) {
662		    perror( "atp_rresp" );
663		    exit( 1 );
664		}
665
666#ifndef ZEROCONNID
667		/*
668		 * The HP LJIIISI w/ BridgePort LocalTalk card sends
669		 * zero instead of the connid.
670		 */
671		if ( ((unsigned char *)rniov[ 0 ].iov_base)[ 0 ] != connid ) {
672		    fprintf( stderr, "Bad data response!\n" );
673		    exit( 1 );
674		}
675#endif /* ZEROCONNID */
676		if ( ((char *)rniov[ 0 ].iov_base)[ 1 ] != PAP_DATA ) {
677		    fprintf( stderr, "Bad data response!\n" );
678		    exit( 1 );
679		}
680
681		for ( cc = 0, i = 0; i < atpb.atp_rresiovcnt; i++ ) {
682		    sfiov[ i ].iov_len = rniov[ i ].iov_len - 4;
683		    cc += sfiov[ i ].iov_len;
684		}
685		if ( cc && writev( 1, sfiov, atpb.atp_rresiovcnt ) < cc ) {
686		    perror( "writev" );
687		    exit( 2 );
688		}
689
690		/* eof */
691		if ( ((char *)rniov[ 0 ].iov_base)[ 2 ] ) {
692
693	if(debug){ printf( "< DATA (eof)\n" ), fflush( stdout );}
694
695		    return( 0 );
696		}
697
698	if(debug){ printf( "< DATA\n" ), fflush( stdout );}
699
700
701		/*
702		 * Ask for more data.
703		 */
704		cbuf[ 0 ] = connid;
705		cbuf[ 1 ] = PAP_READ;
706		if ( ++seq == 0 ) seq = 1;
707		netseq = htons( seq );
708		memcpy( cbuf +  2, &netseq, sizeof( netseq ));
709		atpb.atp_saddr = &sat;
710		atpb.atp_sreqdata = cbuf;
711		atpb.atp_sreqdlen = 4;		/* bytes in SendData request */
712		atpb.atp_sreqto = 15;		/* retry timer */
713		atpb.atp_sreqtries = -1;	/* retry count */
714		if ( atp_sreq( atp, &atpb, oquantum, ATP_XO ) < 0 ) {
715		    perror( "atp_sreq" );
716		    exit( 1 );
717		}
718
719	if(debug){ printf( "READ %d >\n", seq ), fflush( stdout );}
720
721		break;
722
723	    case 0:
724
725	if(debug){ printf( "| RETRANS\n" ), fflush( stdout );}
726
727		break;
728
729	    default:
730		perror( "atp_rsel" );
731		exit( 1 );
732	    }
733	}
734
735	/*
736	 * Send whatever is pending.
737	 */
738	if ( !waitforprinter && !senteof && data && ( fiovcnt || eof )) {
739	    ssat.sat_port = port;
740	    atpb.atp_saddr = &ssat;
741	    if ( fiovcnt ) {
742		for ( i = 0; i < fiovcnt; i++ ) {
743		    sniov[ i ].iov_len = rfiov[ i ].iov_len + 4;
744		    ((char *)sniov[ i ].iov_base)[ 0 ] = connid;
745		    ((char *)sniov[ i ].iov_base)[ 1 ] = PAP_DATA;
746		    senteof = ((char *)sniov[ i ].iov_base)[ 2 ] = eof;
747		    ((char *)sniov[ i ].iov_base)[ 3 ] = 0;
748		}
749	    } else {
750		sniov[ 0 ].iov_len = 4;
751		((char *)sniov[ 0 ].iov_base)[ 0 ] = connid;
752		((char *)sniov[ 0 ].iov_base)[ 1 ] = PAP_DATA;
753		senteof = ((char *)sniov[ 0 ].iov_base)[ 2 ] = eof;
754		((char *)sniov[ 0 ].iov_base)[ 3 ] = 0;
755	    }
756	    atpb.atp_sresiov = sniov;
757	    atpb.atp_sresiovcnt = fiovcnt ? fiovcnt : 1;
758	    if ( atp_sresp( atp, &atpb ) < 0 ) {
759		perror( "atp_sresp" );
760		exit( 1 );
761	    }
762	    data = fiovcnt = 0;
763
764	if(debug){ printf( "DATA %s\n", eof ? "(eof) >" : ">" ), fflush( stdout );}
765
766	    /*
767	     * The Apple LaserWriter IIf, the HP LWIIISi, and IV, don't
768	     * seem to send us an EOF on large jobs.  To work around
769	     * this heinous protocol violation, we won't wait for their
770	     * EOF before closing.
771	     */
772	    if ( eof && noeof && lastfile ) {
773		return( 0 );
774	    }
775	} else {
776	    /*
777	     * If we can't send data right now, go ahead and get the
778	     * status. This is cool, because we get here reliably
779	     * if there is a problem.
780	     */
781	    cbuf[ 0 ] = 0;
782	    cbuf[ 1 ] = PAP_SENDSTATUS;
783	    cbuf[ 2 ] = cbuf[ 3 ] = 0;
784	    atpb.atp_saddr = &nn.nn_sat;
785	    atpb.atp_sreqdata = cbuf;
786	    atpb.atp_sreqdlen = 4;	/* bytes in SendStatus request */
787	    atpb.atp_sreqto = 2;		/* retry timer */
788	    atpb.atp_sreqtries = 5;		/* retry count */
789	    if ( atp_sreq( satp, &atpb, 1, 0 ) < 0 ) {
790		perror( "atp_sreq" );
791		exit( 1 );
792	    }
793
794	if(debug){ printf( "SENDSTATUS >\n" ), fflush( stdout );}
795
796	    atpb.atp_saddr = &nn.nn_sat;
797	    rniov[ 0 ].iov_len = PAP_MAXDATA + 4;
798	    atpb.atp_rresiov = rniov;
799	    atpb.atp_rresiovcnt = 1;
800	    if ( atp_rresp( satp, &atpb ) < 0 ) {
801		perror( "atp_rresp" );
802		continue;
803	    }
804
805#ifndef NONZEROSTATUS
806	    /*
807	     * The stinking LaserWriter IINTX puts crap in this
808	     * field.
809	     */
810	    if ( ((char *)rniov[ 0 ].iov_base)[ 0 ] != 0 ) {
811		fprintf( stderr, "Bad status response!\n" );
812		exit( 1 );
813	    }
814#endif /* NONZEROSTATUS */
815
816	    if ( ((char *)rniov[ 0 ].iov_base)[ 1 ] != PAP_STATUS ||
817		    atpb.atp_rresiovcnt != 1 ) {
818		fprintf( stderr, "Bad status response!\n" );
819		exit( 1 );
820	    }
821
822	if(debug){ printf( "< STATUS\n" ), fflush( stdout );}
823
824#ifdef FUCKED
825	    if ( waitforprinter ) {
826		char	st_buf[ 1024 ];	/* XXX too big */
827
828		memcpy( st_buf, (char *) rniov[ 0 ].iov_base + 9,
829			((char *)rniov[ 0 ].iov_base)[ 8 ] );
830		st_buf[ (int) ((char *)rniov[ 0 ].iov_base)[ 8 ]] = '\0';
831		if ( strstr( st_buf, "waiting" ) != NULL ) {
832		    waitforprinter = 0;
833		}
834	    }
835#endif /* FUCKED */
836
837	    updatestatus( (char *) rniov[ 0 ].iov_base + 9,
838		    ((char *)rniov[ 0 ].iov_base)[ 8 ] );
839	}
840    }
841}
842
843static void updatestatus(char *s, int len)
844{
845    int			fd = -1;
846    struct iovec	iov[ 3 ];
847
848    if ( status ) {
849	if (( fd = open( status, O_WRONLY|O_TRUNC )) < 0 ) {
850	    perror( status );
851	    status = NULL;
852	}
853    }
854
855    if ( fd < 0 ) {
856	fd = 2;
857    }
858
859    iov[ 0 ].iov_base = "%%[ ";
860    iov[ 0 ].iov_len = 4;
861    iov[ 1 ].iov_base = s;
862    iov[ 1 ].iov_len = len;
863    iov[ 2 ].iov_base = " ]%%\n";
864    iov[ 2 ].iov_len = 5;
865
866    writev( fd, iov, 3 );
867    if ( status ) {
868	close( fd );
869    }
870}
871