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