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