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