1 #define _BSD_EXTENSION 2 #define _NET_EXTENSION 3 #define _POSIX_SOURCE 4 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <unistd.h> 8 #include <fcntl.h> 9 #include <string.h> 10 #include <ctype.h> 11 #include <signal.h> 12 #include <errno.h> 13 #include <select.h> 14 #include <sys/types.h> 15 #include <sys/time.h> 16 #include <sys/socket.h> 17 #include <sys/wait.h> 18 19 extern int dial_debug; 20 extern int dial(char*, char*, char*, int*); 21 22 23 /* debug = 0 for no debugging */ 24 /* debug = 1 for readprinter debugging */ 25 /* debug = 2 for sendprinter debugging */ 26 /* debug = 3 for full debugging, its hard to read the messages */ 27 28 int debug = 0; 29 #define READTIMEOUT 300 30 #define RCVSELTIMEOUT 30 31 #define SNDSELTIMEOUT 300 32 33 void 34 rdtmout(void) { 35 fprintf(stderr, "read timeout occurred, check printer\n"); 36 } 37 38 int 39 getline(int fd, char *buf, int len) { 40 char *bp, c; 41 int i = 0, n; 42 43 bp = buf; 44 while (alarm(READTIMEOUT),(n=read(fd, bp, 1)) == 1) { 45 alarm(0); 46 if (*bp == '\r') continue; 47 i += n; 48 49 c = *bp++; 50 if (c == '\n' || c == '\004' || i >= len-1) 51 break; 52 } 53 alarm(0); 54 if (n < 0) 55 return(n); 56 *bp = '\0'; 57 return(i); 58 } 59 60 typedef struct { 61 char *state; /* printer's current status */ 62 int val; /* value returned by getstatus() */ 63 } Status; 64 65 /* printer states */ 66 #define INITIALIZING 0 67 #define IDLE 1 68 #define BUSY 2 69 #define WAITING 3 70 #define PRINTING 4 71 #define PRINTERERROR 5 72 #define ERROR 6 73 #define FLUSHING 7 74 #define UNKNOWN 8 75 76 /* protocol requests and program states */ 77 #define START 'S' 78 unsigned char Start[] = { START }; 79 #define ID_LE 'L' 80 unsigned char Id_le[] = { ID_LE }; 81 #define REQ_STAT 'T' 82 unsigned char Req_stat[] = { REQ_STAT }; 83 #define SEND_DATA 'D' 84 unsigned char Send_data[] = { SEND_DATA }; 85 #define SENT_DATA 'A' 86 unsigned char Sent_data[] = { SENT_DATA }; 87 #define WAIT_FOR_EOJ 'W' 88 unsigned char Wait_for_eoj[] = { WAIT_FOR_EOJ }; 89 #define END_OF_JOB 'E' 90 unsigned char End_of_job[] = { END_OF_JOB }; 91 #define FATAL_ERROR 'F' 92 unsigned char Fatal_error[] = { FATAL_ERROR }; 93 #define WAIT_FOR_IDLE 'I' 94 unsigned char Wait_for_idle[] = { WAIT_FOR_IDLE }; 95 #define OVER_AND_OUT 'O' 96 unsigned char Over_and_out[] = { OVER_AND_OUT }; 97 98 Status statuslist[] = { 99 "initializing", INITIALIZING, 100 "idle", IDLE, 101 "busy", BUSY, 102 "waiting", WAITING, 103 "printing", PRINTING, 104 "printererror", PRINTERERROR, 105 "Error", ERROR, 106 "flushing", FLUSHING, 107 NULL, UNKNOWN 108 }; 109 110 111 /* find returns a pointer to the location of string str2 in string str1, 112 * if it exists. Otherwise, it points to the end of str1. 113 */ 114 char * 115 find(char *str1, char *str2) { 116 char *s1, *s2; 117 118 for (; *str1!='\0'; str1++) { 119 for (s1=str1,s2=str2; *s2!='\0'&&*s1==*s2; s1++,s2++) ; 120 if ( *s2 == '\0' ) 121 break; 122 } 123 124 return(str1); 125 } 126 127 #define MESGSIZE 16384 128 int blocksize = 1920; /* 19200/10, with 1 sec delay between transfers 129 * this keeps the queues from building up. 130 */ 131 char mesg[MESGSIZE]; /* exactly what came back on ttyi */ 132 133 int 134 parsmesg(char *buf) { 135 static char sbuf[MESGSIZE]; 136 char *s; /* start of printer messsage in mesg[] */ 137 char *e; /* end of printer message in mesg[] */ 138 char *key, *val; /* keyword/value strings in sbuf[] */ 139 char *p; /* for converting to lower case etc. */ 140 int i; /* where *key was found in statuslist[] */ 141 142 if (*(s=find(buf, "%[ "))!='\0' && *(e=find(s, " ]%"))!='\0') { 143 strcpy(sbuf, s+3); /* don't change mesg[] */ 144 sbuf[e-(s+3)] = '\0'; /* ignore the trailing " ]%" */ 145 146 for (key=strtok(sbuf, " :"); key != NULL; key=strtok(NULL, " :")) { 147 if (strcmp(key, "Error") == 0) 148 return(ERROR); 149 if ((val=strtok(NULL, ";")) != NULL && strcmp(key, "status") == 0) 150 key = val; 151 152 for (; *key == ' '; key++) ; /* skip any leading spaces */ 153 for (p = key; *p; p++) /* convert to lower case */ 154 if (*p == ':') { 155 *p = '\0'; 156 break; 157 } else if (isupper(*p)) *p = tolower(*p); 158 159 for (i=0; statuslist[i].state != NULL; i++) { 160 if (strcmp(statuslist[i].state, key) == 0) 161 return(statuslist[i].val); 162 } 163 } 164 } 165 return(UNKNOWN); 166 } 167 168 char buf[MESGSIZE]; 169 fd_set readfds, writefds, exceptfds; 170 struct timeval rcvtimeout = { RCVSELTIMEOUT, 0 }; 171 struct timeval sndtimeout = { SNDSELTIMEOUT, 0 }; 172 173 int 174 readprinter(int printerfd, int pipefd) 175 { 176 unsigned char proto; 177 int progstate = START; 178 int print_wait_msg = 0; 179 int tocount = 0; 180 int c, printstat, lastprintstat, n, nfds; 181 182 183 nfds = ((pipefd>printerfd)?pipefd:printerfd) + 1; 184 printstat = 0; 185 signal(SIGALRM, rdtmout); 186 do { 187 188 reselect: 189 /* ask sending process to request printer status */ 190 if (write(pipefd, Req_stat, 1) != 1) { 191 fprintf(stderr, "request status failed\n"); 192 progstate = FATAL_ERROR; 193 continue; 194 } 195 FD_ZERO(&readfds); /* lets be anal */ 196 FD_SET(printerfd, &readfds); 197 FD_SET(pipefd, &readfds); 198 FD_ZERO(&exceptfds); 199 FD_SET(printerfd, &exceptfds); 200 FD_SET(pipefd, &exceptfds); 201 n = select(nfds, &readfds, (fd_set *)0, &exceptfds, &rcvtimeout); 202 if (debug&0x1) fprintf(stderr, "readprinter select returned %d\n", n); 203 if (n == 0) { 204 /* a timeout occurred */ 205 if (++tocount > 4) { 206 fprintf(stderr, "printer appears to be offline.\nHP4m printers may be out of paper.\n"); 207 tocount = 0; 208 } 209 goto reselect; 210 } 211 if (n > 0 && FD_ISSET(printerfd, &exceptfds)) { 212 /* printer problem */ 213 fprintf(stderr, "printer exception\n"); 214 if (write(pipefd, Fatal_error, 1) != 1) { 215 fprintf(stderr, "'fatal error' write to pipe failed\n"); 216 } 217 progstate = FATAL_ERROR; 218 continue; 219 } 220 if (n > 0 && FD_ISSET(pipefd, &exceptfds)) { 221 /* pipe problem */ 222 fprintf(stderr, "pipe exception\n"); 223 progstate = FATAL_ERROR; 224 continue; 225 } 226 if (n > 0 && FD_ISSET(pipefd, &readfds)) { 227 /* protocol pipe wants to be read */ 228 if (debug&0x1) fprintf(stderr, "pipe wants to be read\n"); 229 if (read(pipefd, &proto, 1) != 1) { 230 fprintf(stderr, "read protocol pipe failed\n"); 231 progstate = FATAL_ERROR; 232 continue; 233 } 234 if (debug&0x1) fprintf(stderr, "readprinter: proto=%c\n", proto); 235 /* change state? */ 236 switch (proto) { 237 case SENT_DATA: 238 break; 239 case WAIT_FOR_EOJ: 240 if (!print_wait_msg) { 241 print_wait_msg = 1; 242 fprintf(stderr, "waiting for end of job\n"); 243 } 244 progstate = proto; 245 break; 246 default: 247 fprintf(stderr, "received unknown protocol request <%c> from sendfile\n", proto); 248 break; 249 } 250 n--; 251 } 252 if (n > 0 && FD_ISSET(printerfd, &readfds)) { 253 /* printer wants to be read */ 254 if (debug&0x1) fprintf(stderr, "printer wants to be read\n"); 255 if ((c=getline(printerfd, buf, MESGSIZE)) < 0) { 256 fprintf(stderr, "read printer failed\n"); 257 progstate = FATAL_ERROR; 258 continue; 259 } 260 if (debug&0x1) fprintf(stderr, "%s\n", buf); 261 if (c==1 && *buf == '\004') { 262 if (progstate == WAIT_FOR_EOJ) { 263 if (debug&0x1) fprintf(stderr, "progstate=%c, ", progstate); 264 fprintf(stderr, "%%[ status: endofjob ]%%\n"); 265 /* progstate = WAIT_FOR_IDLE; */ 266 progstate = OVER_AND_OUT; 267 if (write(pipefd, Over_and_out, 1) != 1) { 268 fprintf(stderr, "'fatal error' write to pipe failed\n"); 269 } 270 continue; 271 } else { 272 if (printstat == ERROR) { 273 progstate = FATAL_ERROR; 274 continue; 275 } 276 if (progstate != START && progstate != WAIT_FOR_IDLE) 277 fprintf(stderr, "warning: EOF received; program status is '%c'\n", progstate); 278 279 } 280 continue; 281 } 282 283 /* figure out if it was a status line */ 284 lastprintstat = printstat; 285 printstat = parsmesg(buf); 286 if (printstat == UNKNOWN || printstat == ERROR 287 || lastprintstat != printstat) { 288 /* print whatever it is that was read */ 289 fprintf(stderr, buf); 290 fflush(stderr); 291 if (printstat == UNKNOWN) { 292 printstat = lastprintstat; 293 continue; 294 } 295 } 296 switch (printstat) { 297 case UNKNOWN: 298 continue; /* shouldn't get here */ 299 case FLUSHING: 300 case ERROR: 301 progstate = FATAL_ERROR; 302 /* ask sending process to die */ 303 if (write(pipefd, Fatal_error, 1) != 1) { 304 fprintf(stderr, "Fatal_error mesg write to pipe failed\n"); 305 } 306 continue; 307 case INITIALIZING: 308 case PRINTERERROR: 309 sleep(1); 310 break; 311 case IDLE: 312 if (progstate == WAIT_FOR_IDLE) { 313 progstate = OVER_AND_OUT; 314 if (write(pipefd, Over_and_out, 1) != 1) { 315 fprintf(stderr, "'fatal error' write to pipe failed\n"); 316 } 317 continue; 318 } 319 progstate = SEND_DATA; 320 321 goto dowait; 322 case BUSY: 323 case WAITING: 324 default: 325 sleep(1); 326 dowait: 327 switch (progstate) { 328 case WAIT_FOR_IDLE: 329 case WAIT_FOR_EOJ: 330 case START: 331 sleep(5); 332 break; 333 334 case SEND_DATA: 335 if (write(pipefd, Send_data, 1) != 1) { 336 fprintf(stderr, "send data write to pipe failed\n"); 337 progstate = FATAL_ERROR; 338 continue; 339 } 340 break; 341 default: 342 fprintf(stderr, "unexpected program state %c\n", progstate); 343 exit(1); 344 } 345 break; 346 } 347 n--; 348 } 349 if (n > 0) { 350 fprintf(stderr, "more fds selected than requested!\n"); 351 exit(1); 352 }; 353 } while ((progstate != FATAL_ERROR) && (progstate != OVER_AND_OUT)); 354 355 if (progstate == FATAL_ERROR) 356 return(1); 357 else 358 return(0); 359 } 360 361 int 362 sendfile(int infd, int printerfd, int pipefd) 363 { 364 unsigned char proto; 365 int progstate = START; 366 int i, n, nfds; 367 int bytesread, bytesent = 0; 368 369 nfds = ((pipefd>printerfd)?pipefd:printerfd) + 1; 370 371 if (write(printerfd, "\004", 1)!=1) { 372 perror("sendfile:write:"); 373 progstate = FATAL_ERROR; 374 } 375 do { 376 FD_ZERO(&readfds); /* lets be anal */ 377 FD_SET(pipefd, &readfds); 378 n = select(nfds, &readfds, (fd_set *)0, (fd_set *)0, &sndtimeout); 379 if (debug&02) fprintf(stderr, "sendfile select returned %d\n", n); 380 if (n > 0 && FD_ISSET(pipefd, &readfds)) { 381 /* protocol pipe wants to be read */ 382 if (read(pipefd, &proto, 1) != 1) { 383 fprintf(stderr, "read protocol pipe failed\n"); 384 return(1); 385 } 386 /* change state? */ 387 if (debug&02) fprintf(stderr, "sendfile command - <%c>\n", proto); 388 switch (proto) { 389 case OVER_AND_OUT: 390 case END_OF_JOB: 391 progstate = proto; 392 break; 393 case SEND_DATA: 394 bytesread = 0; 395 do { 396 i = read(infd, &buf[bytesread], blocksize-bytesread); 397 if (debug&02) fprintf(stderr, "read %d bytes\n", i); 398 if (i > 0) 399 bytesread += i; 400 } while((i > 0) && (bytesread < blocksize)); 401 if (i < 0) { 402 fprintf(stderr, "input file read error\n"); 403 progstate = FATAL_ERROR; 404 break; /* from switch */ 405 } 406 if (bytesread > 0) { 407 if (debug&02) fprintf(stderr, "writing %d bytes\n", bytesread); 408 if (write(printerfd, buf, bytesread)!=bytesread) { 409 perror("sendfile:write:"); 410 progstate = FATAL_ERROR; 411 } else if (write(pipefd, Sent_data, 1)!=1) { 412 perror("sendfile:write:"); 413 progstate = FATAL_ERROR; 414 } else { 415 bytesent += bytesread; 416 } 417 fprintf(stderr, "%d sent\n", bytesent); 418 fflush(stderr); 419 420 /* we have reached the end of the input file */ 421 } 422 if (i == 0) { 423 if (progstate != WAIT_FOR_EOJ) { 424 if (write(printerfd, "\004", 1)!=1) { 425 perror("sendfile:write:"); 426 progstate = FATAL_ERROR; 427 } else if (write(pipefd, Wait_for_eoj, 1)!=1) { 428 perror("sendfile:write:"); 429 progstate = FATAL_ERROR; 430 } else { 431 progstate = WAIT_FOR_EOJ; 432 } 433 } 434 } 435 break; 436 case REQ_STAT: 437 if (write(printerfd, "\024", 1)!=1) { 438 fprintf(stderr, "write to printer failed\n"); 439 progstate = FATAL_ERROR; 440 } 441 if (debug&02) fprintf(stderr, "^T"); 442 break; 443 case FATAL_ERROR: 444 progstate = FATAL_ERROR; 445 } 446 } else if (n < 0) { 447 perror("sendfile:select:"); 448 progstate = FATAL_ERROR; 449 } else if (n == 0) { 450 sleep(1); 451 fprintf(stderr, "sendfile timeout\n"); 452 progstate = FATAL_ERROR; 453 } 454 } while ((progstate != FATAL_ERROR) && (progstate != OVER_AND_OUT)); 455 if (write(printerfd, "\004", 1)!=1) { 456 perror("sendfile:write:"); 457 progstate = FATAL_ERROR; 458 } 459 460 if (debug&02) fprintf(stderr, "%d bytes sent\n", bytesent); 461 if (progstate == FATAL_ERROR) 462 return(1); 463 else 464 return(0); 465 } 466 467 void main(int argc, char *argv[]) { 468 int c, usgflg=0, infd, printerfd; 469 int cpid, sprv; 470 int pipefd[2]; 471 char *dialstr; 472 unsigned long rprv; 473 474 dialstr = 0; 475 476 while ((c = getopt(argc, argv, "b:d:")) != -1) 477 switch (c) { 478 case 'b': 479 blocksize = atoi(optarg)/10; 480 if (blocksize > MESGSIZE || blocksize < 1) 481 blocksize = MESGSIZE; 482 break; 483 case 'd': 484 debug = atoi(optarg); 485 dial_debug = debug; 486 break; 487 case '?': 488 fprintf(stderr, "unknown option %c\n", c); 489 usgflg++; 490 break; 491 } 492 if (optind < argc) 493 dialstr = argv[optind++]; 494 else 495 usgflg++; 496 if (usgflg) { 497 fprintf(stderr, "usage: %s [-b baudrate] net!host!service [infile]\n", 498 argv[0]); 499 exit (2); 500 } 501 if (optind < argc) { 502 infd = open(argv[optind], 0); 503 if (infd < 0) { 504 fprintf(stderr, "cannot open %s\n", argv[optind]); 505 exit(1); 506 } 507 optind++; 508 } else 509 infd = 0; 510 511 if (debug & 02) 512 fprintf(stderr, "blocksize=%d\n", blocksize); 513 if (debug) 514 fprintf(stderr, "dialing address=%s\n", dialstr); 515 printerfd = dial(dialstr, 0, 0, 0); 516 if (printerfd < 0) 517 exit(1); 518 519 fprintf(stderr, "printer startup\n"); 520 521 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipefd) < 0) { 522 perror("socketpair"); 523 exit(1); 524 } 525 switch(cpid = fork()){ 526 case -1: 527 perror("fork error"); 528 exit(1); 529 case 0: /* child - to printer */ 530 close(pipefd[1]); 531 sprv = sendfile(infd, printerfd, pipefd[0]); 532 if (debug) 533 fprintf(stderr, "to remote - exiting\n"); 534 exit(sprv); 535 default: /* parent - from printer */ 536 close(pipefd[0]); 537 rprv = readprinter(printerfd, pipefd[1]); 538 if (debug) 539 fprintf(stderr, "from remote - exiting\n"); 540 while(wait(&sprv) != cpid) 541 ; 542 exit(rprv|sprv); 543 } 544 } 545