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