2
* $Id: pap.c,v 1.8.2.1 2002/11/25 01:37:21 jmarcus Exp $
4
* Copyright (c) 1990,1994 Regents of The University of Michigan.
5
* All Rights Reserved. See COPYRIGHT.
10
#endif /* HAVE_CONFIG_H */
12
#include <sys/types.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>
23
#endif /* HAVE_FCNTL_H */
32
#define _PATH_PAPRC ".paprc"
33
char *nbpfailure = "AppleTalk printer offline";
35
/* Forward Declarations */
36
void updatestatus(char *s, int len);
37
int send_file(int fd, ATP atp, int lastfile);
44
if (( p = strrchr( path, '/' )) == NULL ) {
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"
69
static char s[ 32 + 1 + 32 + 1 + 32 ];
73
if (( f = fopen( _PATH_PAPRC, "r" )) == NULL ) {
74
if ( errno == ENOENT ) {
77
perror( _PATH_PAPRC );
81
while ( fgets( s, sizeof( s ), f ) != NULL ) {
82
s[ strlen( s ) - 1 ] = '\0'; /* remove trailing newline */
96
int waitforprinter = 0;
98
unsigned char connid, quantum, oquantum = PAP_MAXQUANTUM;
99
struct sockaddr_at sat;
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 },
116
struct iovec sniov[ PAP_MAXQUANTUM ] = {
127
char nbuf[ PAP_MAXQUANTUM ][ 4 + PAP_MAXDATA ];
128
struct iovec rniov[ PAP_MAXQUANTUM ] = {
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 },
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 ];
162
unsigned short waiting, result;
163
int connattempts = 10;
170
memset(&addr, 0, sizeof(addr));
171
while (( c = getopt( ac, av, "dWwcep:s:EA:" )) != EOF ) {
183
/* enable debugging */
192
case 'e' : /* send stdout to stderr */
209
if (!atalk_aton(optarg, &addr)) {
210
fprintf(stderr, "Bad address.\n");
222
if ( printer == NULL && (( printer = paprc()) == NULL )) {
223
fprintf( stderr, "No printer specified and ./.paprc not found.\n" );
230
if ( nbp_name( printer, &obj, &type, &zone ) < 0 ) {
231
fprintf( stderr, "%s: Bad name\n", printer );
235
fprintf( stderr, "%s: Bad name\n", printer );
239
if ( nbp_lookup( obj, type, zone, &nn, 1, &addr ) <= 0 ) {
241
perror( "nbp_lookup" );
244
fprintf( stderr, "%s:%s@%s: NBP Lookup failed\n", obj, type, zone );
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 );
253
if (( atp = atp_open( ATADDR_ANYPORT, &addr )) == NULL ) {
254
perror( "atp_open" );
257
if (( satp = atp_open( ATADDR_ANYPORT, &addr )) == NULL ) {
258
perror( "atp_open" );
262
while ( waitforidle ) {
263
char st_buf[ 1024 ]; /* XXX too big */
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" );
278
if(debug){ printf( "SENDSTATUS >\n" ), fflush( stdout );}
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" );
289
#ifndef NONZEROSTATUS
291
* The stinking LaserWriter IINTX puts crap in this
294
if ( ((char *)rniov[ 0 ].iov_base)[ 0 ] != 0 ) {
295
fprintf( stderr, "Bad status response!\n" );
298
#endif /* NONZEROSTATUS */
300
if ( ((char *)rniov[ 0 ].iov_base)[ 1 ] != PAP_STATUS ||
301
atpb.atp_rresiovcnt != 1 ) {
302
fprintf( stderr, "Bad status response!\n" );
306
if(debug){ printf( "< STATUS\n" ), fflush( stdout );}
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 ) {
314
updatestatus( (char *) rniov[ 0 ].iov_base + 9,
315
((char *)rniov[ 0 ].iov_base)[ 8 ] );
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" );
333
if ( gettimeofday( &tv, 0 ) < 0 ) {
334
perror( "gettimeofday" );
337
waiting = htons( tv.tv_sec - stv.tv_sec );
339
memcpy(cbuf + 6, &waiting, sizeof( waiting ));
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" );
351
if(debug){ printf( "OPEN >\n" ), fflush( stdout );}
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" );
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... */
373
if(debug){ printf( "< OPENREPLY\n" ), fflush( stdout );}
376
printf( "%.*s\n", (int)iov.iov_len - 9, (char *) iov.iov_base + 9 );
378
updatestatus( (char *) iov.iov_base + 9, iov.iov_len - 9 );
380
memcpy( &result, rbuf + 6, sizeof( result ));
384
memcpy( &sat, &nn.nn_sat, sizeof( struct sockaddr_at ));
385
sat.sat_port = rbuf[ 4 ];
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 );
398
if ( optind == ac ) {
399
send_file( 0, atp, 1 );
401
for (; optind < ac; optind++ ) {
402
if ( strcmp( av[ optind ], "-" ) == 0 ) {
404
} else if (( fd = open( av[ optind ], O_RDONLY )) < 0 ) {
405
perror( av[ optind ] );
408
send_file( fd, atp, ( optind == ac - 1 ) ? 1 : 0 );
419
cbuf[ 1 ] = PAP_CLOSE;
420
cbuf[ 2 ] = cbuf[ 3 ] = 0;
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" );
432
if(debug){ printf( "CLOSE >\n" ), fflush( stdout );}
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" );
444
if ( iov.iov_len != 4 || rbuf[ 1 ] != PAP_CLOSEREPLY ) {
445
fprintf( stderr, "Bad response!\n" );
451
* The AGFA Viper Rip doesn't have the connection id in the close request.
453
if ((unsigned char)rbuf[ 0 ] != connid ) {
454
fprintf( stderr, "Bad connid in close!\n" );
457
#endif /* ZEROCONNID */
459
if(debug){ printf( "< CLOSEREPLY\n" ), fflush( stdout );}
462
printf( "Connection closed.\n" );
469
u_int16_t seq = 0, rseq = 1;
471
int send_file( fd, atp, lastfile )
476
struct timeval stv, tv;
477
struct sockaddr_at ssat;
478
struct atp_block atpb;
480
int fiovcnt = 0, eof = 0, senteof = 0, to = 0;
482
unsigned short netseq;
484
if ( gettimeofday( &stv, 0 ) < 0 ) {
485
perror( "gettimeofday" );
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" );
507
if(debug){ printf( "READ %d >\n", seq ), fflush( stdout );}
510
if ( gettimeofday( &tv, 0 ) < 0 ) {
511
perror( "gettimeofday" );
515
if (( tv.tv_sec - stv.tv_sec ) >= 60 ) {
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" );
534
if(debug){ printf( "TICKLE >\n" ), fflush( stdout );}
537
tv.tv_sec = stv.tv_sec + 60 - tv.tv_sec;
541
if ( !waitforprinter && !eof && fiovcnt == 0 ) {
544
FD_SET( atp_fileno( atp ), &fds );
546
if (( cc = select( FD_SETSIZE, &fds, 0, 0, &tv )) < 0 ) {
552
* A timeout has occured. Keep track of it.
556
fprintf( stderr, "Connection timed out.\n" );
565
if ( !fiovcnt && FD_ISSET( fd, &fds )) {
566
for ( i = 0; i < quantum; i++ ) {
567
rfiov[ i ].iov_len = PAP_MAXDATA;
569
if (( cc = readv( fd, rfiov, quantum )) < 0 ) {
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;
583
if ( FD_ISSET( atp_fileno( atp ), &fds )) {
585
ssat.sat_port = ATADDR_ANYPORT;
586
switch( atp_rsel( atp, &ssat, ATP_TRESP | 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" );
596
if ( (unsigned char)cbuf[ 0 ] != connid ) {
600
/* reset timeout counter for all valid requests */
603
switch ( cbuf[ 1 ] ) {
605
memcpy( cbuf + 2, &netseq, sizeof( netseq ));
606
if(debug){ printf( "< READ %d\n", ntohs( netseq )), fflush( stdout );}
609
if ( rseq != ntohs( netseq )) {
610
if(debug){ printf( "| DUP %d\n", rseq ), fflush( stdout );}
613
if ( rseq++ == 0xffff ) rseq = 1;
618
port = ssat.sat_port;
623
if(debug){ printf( "< CLOSE\n" ), fflush( stdout );}
626
* Respond to the close request, and fail.
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" );
640
if(debug){ printf( "CLOSEREPLY >\n" ), fflush( stdout );}
642
fprintf( stderr, "Connection closed by foreign host.\n" );
647
if(debug){ printf( "< TICKLE\n" ), fflush( stdout );}
651
fprintf( stderr, "Bad PAP request!\n" );
657
/* reset timeout counter for all valid requests */
660
atpb.atp_saddr = &ssat;
661
for ( i = 0; i < oquantum; i++ ) {
662
rniov[ i ].iov_len = PAP_MAXDATA + 4;
664
atpb.atp_rresiov = rniov;
665
atpb.atp_rresiovcnt = oquantum;
666
if ( atp_rresp( atp, &atpb ) < 0 ) {
667
perror( "atp_rresp" );
673
* The HP LJIIISI w/ BridgePort LocalTalk card sends
674
* zero instead of the connid.
676
if ( ((unsigned char *)rniov[ 0 ].iov_base)[ 0 ] != connid ) {
677
fprintf( stderr, "Bad data response!\n" );
680
#endif /* ZEROCONNID */
681
if ( ((char *)rniov[ 0 ].iov_base)[ 1 ] != PAP_DATA ) {
682
fprintf( stderr, "Bad data response!\n" );
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;
690
if ( cc && writev( 1, sfiov, atpb.atp_rresiovcnt ) < cc ) {
696
if ( ((char *)rniov[ 0 ].iov_base)[ 2 ] ) {
698
if(debug){ printf( "< DATA (eof)\n" ), fflush( stdout );}
703
if(debug){ printf( "< DATA\n" ), fflush( stdout );}
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" );
724
if(debug){ printf( "READ %d >\n", seq ), fflush( stdout );}
730
if(debug){ printf( "| RETRANS\n" ), fflush( stdout );}
735
perror( "atp_rsel" );
741
* Send whatever is pending.
743
if ( !waitforprinter && !senteof && data && ( fiovcnt || eof )) {
744
ssat.sat_port = port;
745
atpb.atp_saddr = &ssat;
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;
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;
761
atpb.atp_sresiov = sniov;
762
atpb.atp_sresiovcnt = fiovcnt ? fiovcnt : 1;
763
if ( atp_sresp( atp, &atpb ) < 0 ) {
764
perror( "atp_sresp" );
769
if(debug){ printf( "DATA %s\n", eof ? "(eof) >" : ">" ), fflush( stdout );}
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.
777
if ( eof && noeof && lastfile ) {
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.
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" );
799
if(debug){ printf( "SENDSTATUS >\n" ), fflush( stdout );}
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" );
810
#ifndef NONZEROSTATUS
812
* The stinking LaserWriter IINTX puts crap in this
815
if ( ((char *)rniov[ 0 ].iov_base)[ 0 ] != 0 ) {
816
fprintf( stderr, "Bad status response!\n" );
819
#endif /* NONZEROSTATUS */
821
if ( ((char *)rniov[ 0 ].iov_base)[ 1 ] != PAP_STATUS ||
822
atpb.atp_rresiovcnt != 1 ) {
823
fprintf( stderr, "Bad status response!\n" );
827
if(debug){ printf( "< STATUS\n" ), fflush( stdout );}
830
if ( waitforprinter ) {
831
char st_buf[ 1024 ]; /* XXX too big */
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 ) {
842
updatestatus( (char *) rniov[ 0 ].iov_base + 9,
843
((char *)rniov[ 0 ].iov_base)[ 8 ] );
848
void updatestatus( s, len )
853
struct iovec iov[ 3 ];
856
if (( fd = open( status, O_WRONLY|O_TRUNC )) < 0 ) {
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;
873
writev( fd, iov, 3 );