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