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