]> arthur.barton.de Git - netatalk.git/blob - bin/pap/pap.c
Remove bdb env on exit
[netatalk.git] / bin / pap / pap.c
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 */
35 static void updatestatus(char *s, int len);
36 static int send_file(int fd, ATP atp, int lastfile);
37
38 static 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
64 static char *
65 paprc(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
91 static char                     *printer = NULL;
92 static char                     *status = NULL;
93 static int                      noeof = 0;
94 static int                      waitforprinter = 0;
95
96 static unsigned char            connid, quantum, oquantum = PAP_MAXQUANTUM;
97 static struct sockaddr_at       sat;
98
99 static char                     cbuf[ 8 ];
100 static struct nbpnve            nn;
101 static ATP                      satp;
102
103 static char             fbuf[ PAP_MAXQUANTUM ][ 4 + PAP_MAXDATA ];
104 static 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
115 static 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
126 static char             nbuf[ PAP_MAXQUANTUM ][ 4 + PAP_MAXDATA ];
127 static 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
138 static 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 static int debug;
150
151 int 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
465 static int              data = 0;
466 static unsigned char    port;
467 static u_int16_t        seq = 0;
468
469 static 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
843 static 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 }