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