1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * 32 * postio - RS-232 serial interface for PostScript printers 33 * 34 * A simple program that manages input and output for PostScript printers. Much 35 * has been added and changed from early versions of the program, but the basic 36 * philosophy is still the same. Don't send real data until we're certain we've 37 * connected to a PostScript printer that's in the idle state and try to hold 38 * the connection until the job is completely done. It's more work than you 39 * might expect is necessary, but should provide a reasonably reliable spooler 40 * interface that can return error indications to the caller via the program's 41 * exit status. 42 * 43 * I've added code that will let you split the program into separate read/write 44 * processes. Although it's not the default it should be useful if you have a 45 * file that will be returning useful data from the printer. The two process 46 * stuff was laid down on top of the single process code and both methods still 47 * work. The implementation isn't as good as it could be, but didn't require 48 * many changes to the original program (despite the fact that there are now 49 * many differences). 50 * 51 * By default the program still runs as a single process. The -R2 option forces 52 * separate read and write processes after the intial connection is made. If you 53 * want that as the default initialize splitme (below) to TRUE. In addition the 54 * -t option that's used to force stuff not recognized as status reports to 55 * stdout also tries to run as two processes (by setting splitme to TRUE). It 56 * will only work if the required code (ie. resetline() in ifdef.c) has been 57 * implemented for your Unix system. I've only tested the System V code. 58 * 59 * Code needed to support interactive mode has also been added, although again 60 * it's not as efficient as it could be. It depends on the system dependent 61 * procedures resetline() and setupstdin() (file ifdef.c) and for now is only 62 * guaranteed to work on System V. Can be requested using the -i option. 63 * 64 * Quiet mode (-q option) is also new, but was needed for some printers 65 * connected to RADIAN. If you're running in quiet mode no status requests will 66 * be sent to the printer while files are being transmitted (ie. in send()). 67 * 68 * The program expects to receive printer status lines that look like, 69 * 70 * %%[ status: idle; source: serial 25 ]%% 71 * %%[ status: waiting; source: serial 25 ]%% 72 * %%[ status: initializing; source: serial 25 ]%% 73 * %%[ status: busy; source: serial 25 ]%% 74 * %%[ status: printing; source: serial 25 ]%% 75 * %%[ status: PrinterError: out of paper; source: serial 25 ]%% 76 * %%[ status: PrinterError: no paper tray; source: serial 25 ]%% 77 * 78 * although this list isn't complete. Sending a '\024' (control T) character 79 * forces the return of a status report. PostScript errors detected on the 80 * printer result in the immediate transmission of special error messages that 81 * look like, 82 * 83 * %%[ Error: undefined; OffendingCommand: xxx ]%% 84 * %%[ Flushing: rest of job (to end-of-file) will be ignored ]%% 85 * 86 * although we only use the Error and Flushing keywords. Finally conditions, 87 * like being out of paper, result in other messages being sent back from the 88 * printer over the communications line. Typical PrinterError messages look 89 * like, 90 * 91 * %%[ PrinterError: out of paper; source: serial 25 ]%% 92 * %%[ PrinterError: paper jam; source: serial 25 ]%% 93 * 94 * although we only use the PrinterError keyword rather than trying to recognize 95 * all possible printer errors. 96 * 97 * The implications of using one process and only flow controlling data going to 98 * the printer are obvious. Job transmission should be reliable, but there can 99 * be data loss in stuff sent back from the printer. Usually that only caused 100 * problems with jobs designed to run on the printer and return useful data 101 * back over the communications line. If that's the kind of job you're sending 102 * call postio with the -t option. That should force the program to split into 103 * separate read and write processes and everything not bracketed by "%%[ " 104 * and " ]%%" strings goes to stdout. In otherwords the data you're expecting 105 * should be separated from the status stuff that goes to the log file (or 106 * stderr). The -R2 option does almost the same thing (ie. separate read and 107 * write processes), but everything that comes back from the printer goes to 108 * the log file (stderr by default) and you'll have to separate your data from 109 * any printer messages. 110 * 111 * A typical command line might be, 112 * 113 * postio -l /dev/tty01 -b 9600 -L log file1 file2 114 * 115 * where -l selects the line, -b sets the baud rate, and -L selects the printer 116 * log file. Since there's no default line, at least not right now, you'll 117 * always need to use the -l option, and if you don't choose a log file stderr 118 * will be used. If you have a program that will be returning data the command 119 * line might look like, 120 * 121 * postio -t -l/dev/tty01 -b9600 -Llog file >results 122 * 123 * Status stuff goes to file log while the data you're expecting back from the 124 * printer gets put in file results. 125 * 126 */ 127 128 #include <stdio.h> 129 #include <unistd.h> 130 #include <stdarg.h> 131 #include <stdlib.h> 132 #include <ctype.h> 133 #include <fcntl.h> 134 #include <signal.h> 135 #include <sys/types.h> 136 #include <sys/wait.h> 137 #include <errno.h> 138 #include <string.h> 139 #include <sys/ioccom.h> 140 #include <sys/ioctl.h> 141 #include <sys/bpp_io.h> 142 #include <sys/ecppsys.h> 143 144 #include "ifdef.h" /* conditional compilation stuff */ 145 #include "gen.h" /* general purpose definitions */ 146 #include "postio.h" /* some special definitions */ 147 148 static char **argv; /* global so everyone can use them */ 149 static int argc; 150 static char *prog_name = ""; /* really just for error messages */ 151 static int x_stat = 0; /* program exit status */ 152 static int debug = OFF; /* debug flag */ 153 static int ignore = OFF; /* what's done for FATAL errors */ 154 static Baud baudtable[] = BAUDTABLE; /* converts strings to termio values */ 155 static int quiet = FALSE; /* no status queries in send if TRUE */ 156 char *postbegin = POSTBEGIN; /* preceeds all the input files */ 157 static int useslowsend = FALSE; /* not recommended! */ 158 static int splitme = FALSE; /* into READ & WRITE procs if TRUE */ 159 static int whatami = READWRITE; /* a READ or WRITE process - or both */ 160 static int otherpid = -1; /* who gets signals if greater than 1 */ 161 static int joinsig = SIGTRAP; /* reader gets when writing is done */ 162 static int writedone = FALSE; /* and then sets this to TRUE */ 163 static char sbuf[MESGSIZE]; /* for parsing the message */ 164 static char *mesgptr = NULL; /* printer msg starts here in mesg[] */ 165 static Status status[] = STATUS; /* for converting status strings */ 166 static int nostatus = NOSTATUS; /* default getstatus() return value */ 167 static int tostdout = FALSE; /* non-status stuff goes to stdout? */ 168 static int currentstate = NOTCONNECTED; /* START, SEND, or DONE */ 169 170 char *line = NULL; /* printer is on this tty line */ 171 short baudrate = BAUDRATE; /* and running at this baud rate */ 172 int stopbits = 1; /* number of stop bits */ 173 int interactive = FALSE; /* interactive mode */ 174 char *block = NULL; /* input file buffer */ 175 int blocksize = BLOCKSIZE; /* and its size in bytes */ 176 int head = 0; /* block[head] is the next character */ 177 int tail = 0; /* one past the last byte in block[] */ 178 int canread = TRUE; /* allow reads */ 179 int canwrite = TRUE; /* and writes if TRUE */ 180 char mesg[MESGSIZE]; /* exactly what came back on ttyi */ 181 char *endmesg = NULL; /* end for readline() in mesg[] */ 182 int ttyi = 0; /* input */ 183 int ttyo = 2; /* and output file descriptors */ 184 FILE *fp_log = stderr; /* log file for stuff from printer */ 185 186 static void init_signals(void); 187 static void interrupt(int); 188 static void options(void); 189 static void initialize(void); 190 static void initialize_parallel(void); 191 static void start(void); 192 static void split(void); 193 static void arguments(void); 194 static void send(int, char *); 195 static void done(void); 196 static void cleanup(void); 197 static void clearline(void); 198 void logit(char *, ...); 199 static void quit(int sig); 200 static void Rest(int t); 201 static int parsemesg(void); 202 static int sendsignal(int); 203 static int writeblock(void); 204 static int Write(int, char *, int); 205 static short getbaud(char *); 206 static char *find(char *, char *); 207 208 void error(int, char *, ...); 209 int getstatus(int); 210 int readblock(int); 211 212 213 /* from parallel.c for parallel interfaces */ 214 extern int is_a_parallel_bpp(int); 215 extern int bpp_state(int); 216 extern int is_a_prnio(int); 217 extern int prnio_state(int); 218 extern int parallel_comm(int, int()); /* arg is bpp_state */ 219 220 /* from ifdef.c for serial interfaces */ 221 extern void setupline(void); 222 extern void setupstdin(int); 223 extern void slowsend(int); 224 extern int resetline(void); 225 extern int readline(void); 226 227 /* 228 * A simple program that manages input and output for PostScript printers. 229 * Can run as a single process or as separate read/write processes. What's 230 * done depends on the value assigned to splitme when split() is called. 231 */ 232 233 int nop(int fd) { return(0); } 234 235 236 int 237 main(int agc, char *agv[]) 238 { 239 argc = agc; 240 argv = agv; 241 prog_name = argv[0]; /* really just for error messages */ 242 243 /* is this a serial or parallel port? */ 244 245 init_signals(); /* sets up interrupt handling */ 246 options(); /* get command line options */ 247 248 setbuf(stderr, NULL); /* unbuffer io for stderr */ 249 250 251 if (line) { 252 close(1); 253 open(line, O_RDWR); 254 255 } 256 257 if (is_a_prnio(1)) { 258 initialize_parallel(); 259 x_stat = parallel_comm(1, prnio_state); 260 } else if (is_a_parallel_bpp(1) || 261 (get_ecpp_status(1) == ECPP_CENTRONICS)) { 262 initialize_parallel(); 263 x_stat = parallel_comm(1, bpp_state); 264 } else if (isatty(1)) { 265 initialize(); /* must be done after options() */ 266 start(); /* make sure the printer is ready */ 267 split(); /* into read/write processes - maybe */ 268 arguments(); /* then send each input file */ 269 done(); /* wait until the printer is finished */ 270 cleanup(); /* make sure the write process stops */ 271 } else { 272 initialize_parallel(); 273 x_stat = parallel_comm(1, nop); 274 } 275 276 277 return (x_stat); /* everything probably went OK */ 278 } 279 280 281 /* 282 * Makes sure we handle interrupts. The proper way to kill the program, if 283 * necessary, is to do a kill -15. That forces a call to interrupt(), which in 284 * turn tries to reset the printer and then exits with a non-zero status. If the 285 * program is running as two processes, sending SIGTERM to either the parent or 286 * child should clean things up. 287 */ 288 289 static void 290 init_signals(void) 291 { 292 if (signal(SIGINT, interrupt) == SIG_IGN) { 293 signal(SIGINT, SIG_IGN); 294 signal(SIGQUIT, SIG_IGN); 295 signal(SIGHUP, SIG_IGN); 296 } else { 297 signal(SIGHUP, interrupt); 298 signal(SIGQUIT, interrupt); 299 } 300 301 signal(SIGTERM, interrupt); 302 303 } 304 305 306 /* 307 * Reads and processes the command line options. The -R2, -t, and -i options all 308 * force separate read and write processes by eventually setting splitme to TRUE 309 * (check initialize()). The -S option is not recommended and should only be 310 * used as a last resort! 311 */ 312 313 static void 314 options(void) 315 { 316 int ch; /* return value from getopt() */ 317 char *optnames = "b:il:qs:tB:L:P:R:SDI"; 318 319 extern char *optarg; /* used by getopt() */ 320 extern int optind; 321 322 while ((ch = getopt(argc, argv, optnames)) != EOF) { 323 324 switch (ch) { 325 326 case 'b': /* baud rate string */ 327 baudrate = getbaud(optarg); 328 break; 329 330 case 'i': /* interactive mode */ 331 interactive = TRUE; 332 break; 333 334 case 'l': /* printer line */ 335 line = optarg; 336 break; 337 338 case 'q': /* no status queries - for RADIAN? */ 339 quiet = TRUE; 340 break; 341 342 case 's': /* use 2 stop bits - for UNISON? */ 343 if ((stopbits = atoi(optarg)) < 1 || stopbits > 2) 344 stopbits = 1; 345 break; 346 347 case 't': /* non-status stuff goes to stdout */ 348 tostdout = TRUE; 349 break; 350 351 case 'B': /* set the job buffer size */ 352 if ((blocksize = atoi(optarg)) <= 0) 353 blocksize = BLOCKSIZE; 354 break; 355 356 case 'L': /* printer log file */ 357 if ((fp_log = fopen(optarg, "w")) == NULL) { 358 fp_log = stderr; 359 error(NON_FATAL, "can't open log file %s", optarg); 360 } /* End if */ 361 break; 362 363 case 'P': /* initial PostScript code */ 364 postbegin = optarg; 365 break; 366 367 case 'R': /* run as one or two processes */ 368 if (atoi(optarg) == 2) 369 splitme = TRUE; 370 else splitme = FALSE; 371 break; 372 373 case 'S': /* slow and kludged up vers. of send */ 374 useslowsend = TRUE; 375 break; 376 377 case 'D': /* debug flag */ 378 debug = ON; 379 break; 380 381 case 'I': /* ignore FATAL errors */ 382 ignore = ON; 383 break; 384 385 case '?': /* don't understand the option */ 386 error(FATAL, ""); 387 break; 388 389 default: /* don't know what to do for ch */ 390 error(FATAL, "missing case for option %c\n", ch); 391 break; 392 393 } /* End switch */ 394 395 } /* End while */ 396 397 argc -= optind; /* get ready for non-option args */ 398 argv += optind; 399 400 } 401 402 403 /* 404 * Called from options() to convert a baud rate string into an appropriate 405 * termio value. *rate is looked up in baudtable[] and if it's found, the 406 * corresponding value is returned to the caller. 407 */ 408 409 static short 410 getbaud(char *rate) /* string representing the baud rate */ 411 { 412 int i; /* for looking through baudtable[] */ 413 414 for (i = 0; baudtable[i].rate != NULL; i++) 415 if (strcmp(rate, baudtable[i].rate) == 0) 416 return (baudtable[i].val); 417 418 error(FATAL, "don't recognize baud rate %s", rate); 419 /*NOTREACHED*/ 420 return (0); 421 422 } 423 424 425 /* 426 * Initialization, a few checks, and a call to setupline() (file ifdef.c) to 427 * open and configure the communications line. Settings for interactive mode 428 * always take precedence. The setupstdin() call with an argument of 0 saves 429 * the current terminal settings if interactive mode has been requested - 430 * otherwise nothing's done. Unbuffering stdout (via the setbuf() call) isn't 431 * really needed on System V since it's flushed whenever terminal input is 432 * requested. It's more efficient if we buffer the stdout (on System V) but 433 * safer (for other versions of Unix) if we include the setbuf() call. 434 */ 435 436 static void 437 initialize(void) 438 { 439 whatami = READWRITE; /* always run start() as one process */ 440 canread = canwrite = TRUE; 441 442 if (line == NULL) /* kludge for lp - they use -t option */ 443 tostdout = FALSE; 444 445 if (tostdout == TRUE) /* force separate read/write procs */ 446 splitme = TRUE; 447 448 if (interactive == TRUE) { /* interactive mode settings win */ 449 quiet = FALSE; 450 tostdout = FALSE; 451 splitme = TRUE; 452 blocksize = 1; 453 postbegin = NULL; 454 useslowsend = FALSE; 455 nostatus = INTERACTIVE; 456 setbuf(stdout, NULL); 457 } 458 459 if (useslowsend == TRUE) { /* last resort only - not recommended */ 460 quiet = FALSE; 461 splitme = FALSE; 462 if (blocksize > 1024) /* don't send too much all at once */ 463 blocksize = 1024; 464 } 465 466 if (line == NULL && (interactive == TRUE || tostdout == TRUE)) 467 error(FATAL, "a printer line must be supplied - use the -l option"); 468 469 if ((block = malloc(blocksize)) == NULL) 470 error(FATAL, "no memory"); 471 472 endmesg = mesg + sizeof mesg - 2; /* one byte from last pos. in mesg */ 473 474 setupline(); /* configure the communications line */ 475 setupstdin(0); /* save current stdin term settings */ 476 477 } 478 479 static void 480 initialize_parallel(void) 481 { 482 if ((block = malloc(blocksize)) == NULL) 483 error(FATAL, "no memory"); 484 } 485 486 487 /* 488 * Tries to put the printer in the IDLE state before anything important is sent. 489 * Run as a single process no matter what has been assigned to splitme. Separate 490 * read and write processes, if requested, will be created after we're done 491 * here. 492 */ 493 494 static void 495 start(void) 496 { 497 int longwait = 0; 498 499 logit("printer startup\n"); 500 501 currentstate = START; 502 clearline(); 503 504 for (;;) 505 switch (getstatus(1)) { 506 507 case IDLE: 508 case INTERACTIVE: 509 if (postbegin != NULL && *postbegin != '\0') 510 Write(ttyo, postbegin, strlen(postbegin)); 511 clearline(); 512 return; 513 514 case BUSY: 515 Write(ttyo, "\003", 1); 516 Rest(1); 517 break; 518 519 /* 03/24/95 - bob golden 520 * The HP LJ3 starts in waiting mode and needs the EOF to move 521 * from waiting to idle. To see what would happen, code was added 522 * to send the INTR on waiting and later changed to INTR/EOF. 523 * The INTR by itself had no effect. The INTR/EOF put the 524 * the printer in a busy status loop from which the only 525 * recovery was to reset the printer. Until further testing 526 * testing is done, do not send an INTR to a HPLJ3 in waiting 527 * state. WAITING moved to a separate case to eliminate the 528 * INTR write. 529 */ 530 case WAITING: 531 Write(ttyo, "\004", 1); 532 Rest(1); 533 break; 534 535 /* 03/24/95 - bob golden 536 * The HP LJ3 seems to process INTR at later times. All the 537 * longwaits are increaased to reduce the number of INTRs sent. 538 */ 539 case ERROR: 540 case FLUSHING: 541 Write(ttyo, "\004", 1); 542 if (longwait++ == 5) { 543 Write(ttyo, "\003", 1); 544 Rest(5); 545 longwait = 0; 546 } 547 Rest(1); 548 break; 549 550 case PRINTERERROR: 551 Rest(15); 552 break; 553 554 case DISCONNECT: 555 error(FATAL, "Disconnected - printer may be offline"); 556 break; 557 558 /* 03/24/95 - bob golden 559 * The ENDJOB case has been removed. The HP LJ3 echoes all EOFs 560 * sent so the ENDJOB has no real meaning. 561 */ 562 case UNKNOWN: 563 clearline(); 564 break; 565 566 default: 567 Rest(1); 568 break; 569 570 } /* End switch */ 571 572 } /* End of start */ 573 574 575 /* 576 * 577 * If splitme is TRUE we fork a process, make the parent handle reading, and let 578 * the child take care of writing. resetline() (file ifdef.c) contains all the 579 * system dependent code needed to reset the communications line for separate 580 * read and write processes. For now it's expected to return TRUE or FALSE and 581 * that value controls whether we try the fork. I've only tested the two process 582 * stuff for System V. Other versions of resetline() may just be dummy 583 * procedures that always return FALSE. If the fork() failed previous versions 584 * continued as a single process, although the implementation wasn't quite 585 * right, but I've now decided to quit. The main reason is a Datakit channel 586 * may be configured to flow control data in both directions, and if we run 587 * postio over that channel as a single process we likely will end up in 588 * deadlock. 589 */ 590 591 static void 592 split(void) 593 { 594 int pid; 595 596 if (splitme == TRUE) 597 if (resetline() == TRUE) { 598 pid = getpid(); 599 signal(joinsig, interrupt); 600 if ((otherpid = fork()) == -1) 601 error(FATAL, "can't fork"); 602 else if (otherpid == 0) { 603 whatami = WRITE; 604 nostatus = WRITEPROCESS; 605 otherpid = pid; 606 setupstdin(1); 607 } else 608 whatami = READ; 609 } else if (interactive == TRUE || tostdout == TRUE) 610 error(FATAL, 611 "can't create two process - check resetline()"); 612 else 613 error(NON_FATAL, 614 "running as a single process - check resetline()"); 615 616 canread = (whatami & READ) ? TRUE : FALSE; 617 canwrite = (whatami & WRITE) ? TRUE : FALSE; 618 } 619 620 621 /* 622 * Makes sure all the non-option command line arguments are processed. If there 623 * aren't any arguments left when we get here we'll send stdin. Input files are 624 * only read and sent to the printer if canwrite is TRUE. Checking it here means 625 * we won't have to do it in send(). If interactive mode is TRUE we'll stay here 626 * forever sending stdin when we run out of files - exit with a break. Actually 627 * the loop is bogus and used at most once when we're in interactive mode 628 * because stdin is in a pseudo raw mode and the read() in readblock() should 629 * never see the end of file. 630 */ 631 632 static void 633 arguments(void) 634 { 635 int fd_in; /* next input file */ 636 637 if (canwrite == TRUE) 638 do /* loop is for interactive mode */ 639 if (argc < 1) 640 send(fileno(stdin), "pipe.end"); 641 else { 642 while (argc > 0) { 643 if ((fd_in = open(*argv, O_RDONLY)) == -1) 644 error(FATAL, "can't open %s", *argv); 645 send(fd_in, *argv); 646 close(fd_in); 647 argc--; 648 argv++; 649 } 650 } 651 while (interactive == TRUE); 652 } 653 654 /* 655 * Sends file *name to the printer. There's nothing left here that depends on 656 * sending and receiving status reports, although it can be reassuring to know 657 * the printer is responding and processing our job. Only the writer gets here 658 * in the two process implementation, and in that case split() has reset 659 * nostatus to WRITEPROCESS and that's what getstatus() always returns. For 660 * now we accept the IDLE state and ENDOFJOB as legitimate and ignore the 661 * INITIALIZING state. 662 * 663 * fd_in next input file 664 * name it's pathname 665 */ 666 667 static void 668 send(int fd_in, char *name) 669 { 670 if (interactive == FALSE) 671 logit("sending file %s\n", name); 672 673 currentstate = SEND; 674 675 if (useslowsend == TRUE) { 676 slowsend(fd_in); 677 return; 678 } 679 680 while (readblock(fd_in)) 681 682 switch (getstatus(0)) { 683 684 case IDLE: 685 case BUSY: 686 case WAITING: 687 case PRINTING: 688 case ENDOFJOB: 689 case PRINTERERROR: 690 case UNKNOWN: 691 case NOSTATUS: 692 case WRITEPROCESS: 693 case INTERACTIVE: 694 writeblock(); 695 break; 696 697 case ERROR: 698 fprintf(stderr, "%s", mesg); /* for csw */ 699 error(USER_FATAL, "PostScript Error"); 700 break; 701 702 case FLUSHING: 703 error(USER_FATAL, "Flushing Job"); 704 break; 705 706 case DISCONNECT: 707 error(FATAL, "Disconnected - printer may be offline"); 708 break; 709 710 } 711 712 } 713 714 715 /* 716 * Tries to stay connected to the printer until we're reasonably sure the job is 717 * complete. It's the only way we can recover error messages or data generated 718 * by the PostScript program and returned over the communication line. Actually 719 * doing it correctly for all possible PostScript jobs is more difficult that it 720 * might seem. For example if we've sent several jobs, each with their own EOF 721 * mark, then waiting for ENDOFJOB won't guarantee all the jobs have completed. 722 * Even waiting for IDLE isn't good enough. Checking for the WAITING state after 723 * all the files have been sent and then sending an EOF may be the best 724 * approach, but even that won't work all the time - we could miss it or might 725 * not get there. Even sending our own special PostScript job after all the 726 * input files has it's own different set of problems, but probably could work 727 * (perhaps by printing a fake status message or just not timing out). Anyway 728 * it's probably not worth the trouble so for now we'll quit if writedone is 729 * TRUE and we get ENDOFJOB or IDLE. 730 * 731 * If we're running separate read and write processes the reader gets here after 732 * after split() while the writer goes to send() and only gets here after all 733 * the input files have been transmitted. When they're both here the writer 734 * sends the reader signal joinsig and that forces writedone to TRUE in the 735 * reader. At that point the reader can begin looking for an indication of the 736 * end of the job. The writer hangs around until the reader kills it (usually 737 * in cleanup()) sending occasional status requests. 738 */ 739 740 static void 741 done(void) 742 { 743 int sleeptime = 15; /* for 'out of paper' etc. */ 744 int longwait = 0; 745 746 if (canwrite == TRUE) 747 logit("waiting for end of job\n"); 748 749 currentstate = DONE; 750 writedone = (whatami == READWRITE) ? TRUE : FALSE; 751 752 for (;;) { 753 754 switch (getstatus(1)) { 755 case WRITEPROCESS: 756 if (writedone == FALSE) { 757 sendsignal(joinsig); 758 Write(ttyo, "\004", 1); 759 writedone = TRUE; 760 sleeptime = 1; 761 } 762 Rest(sleeptime++); 763 break; 764 765 /* 03/24/95 - bob golden 766 * For the HP LJ3 INTR sent while in the waiting state have 767 * either had no effect or put the printer into a unrecoverable 768 * loop. Further testing may reveal this to not be the case 769 * but for now, remove the send INTR. 770 */ 771 case WAITING: 772 Write(ttyo, "\004", 1); 773 Rest(1); 774 sleeptime = 15; 775 break; 776 777 /* 03/24/95 - bob golden 778 * ENDOFJOB case removed here. The HP LJ 3 echoes all EOFs sent so 779 * the ENDOFJOB case is meaningless. 780 */ 781 case IDLE: 782 if (writedone == TRUE) { 783 logit("job complete\n"); 784 return; 785 } 786 break; 787 788 /* 03/24/95 - bob golden 789 * During print data transmission, the HP LJ3 stays in 790 * status busy. So give it a rest. 791 * 792 */ 793 case BUSY: 794 case PRINTING: 795 Rest(1); 796 sleeptime = 15; 797 break; 798 799 case INTERACTIVE: 800 Write(ttyo, "\004", 1); 801 sleeptime = 15; 802 break; 803 804 case PRINTERERROR: 805 Rest(sleeptime++); 806 break; 807 808 case ERROR: 809 Write(ttyo, "\004", 1); 810 fprintf(stderr, "%s", mesg); /* for csw */ 811 error(USER_FATAL, "PostScript Error"); 812 return; 813 814 case FLUSHING: 815 Write(ttyo, "\004", 1); 816 error(USER_FATAL, "Flushing Job"); 817 return; 818 819 case DISCONNECT: 820 error(FATAL, "Disconnected - printer may be offline"); 821 return; 822 823 /* 03/24/95 - bob golden 824 * These cases are ignored without a EOF being sent 825 */ 826 case ENDOFJOB: 827 case NOSTATUS: 828 Rest(1); 829 break; 830 831 default: 832 Write(ttyo, "\004", 1); 833 Rest(1); 834 break; 835 836 } 837 838 if (sleeptime > 60) 839 sleeptime = 60; 840 841 } 842 843 } 844 845 846 /* 847 * Only needed if we're running separate read and write processes. Makes sure 848 * the write process is killed after the read process has successfully finished 849 * with all the jobs. sendsignal() returns a -1 if there's nobody to signal so 850 * things work when we're running a single process. 851 */ 852 853 static void 854 cleanup(void) 855 { 856 int w; 857 858 while (sendsignal(SIGKILL) != -1 && (w = wait((int *)0)) != otherpid && 859 w != -1); 860 if ( currentstate != NOTCONNECTED ) 861 Write(ttyo, "\004", 1); 862 } 863 864 865 /* 866 * Fills the input buffer with the next block, provided we're all done with the 867 * last one. Blocks from fd_in are stored in array block[]. head is the index 868 * of the next byte in block[] that's supposed to go to the printer. tail points 869 * one past the last byte in the current block. head is adjusted in writeblock() 870 * after each successful write, while head and tail are reset here each time 871 * a new block is read. Returns the number of bytes left in the current block. 872 * Read errors cause the program to abort. The fake status message that's put 873 * out in quiet mode is only so you can look at the log file and know 874 * something's happening - take it out if you want. 875 */ 876 877 int 878 readblock(int fd_in) 879 { 880 static long blocknum = 1; 881 882 if (head >= tail) { /* done with the last block */ 883 if ((tail = read(fd_in, block, blocksize)) == -1) 884 error(FATAL, "error reading input file"); 885 if (quiet == TRUE && tail > 0) /* put out a fake message? */ 886 logit("%%%%[ status: busy; block: %d ]%%%%\n", blocknum++); 887 head = 0; 888 } 889 890 return (tail - head); 891 892 } 893 894 895 /* 896 * Called from send() when it's OK to send the next block to the printer. head 897 * is adjusted after the write, and the number of bytes that were successfully 898 * written is returned to the caller. 899 */ 900 901 static int 902 writeblock(void) 903 { 904 int count; /* bytes successfully written */ 905 906 if ((count = write(ttyo, &block[head], tail - head)) == -1) 907 error(FATAL, "error writing to %s", line); 908 else if (count == 0) 909 error(FATAL, "printer appears to be offline"); 910 911 head += count; 912 return (count); 913 914 } 915 916 917 /* 918 * Looks for things coming back from the printer on the communications line, 919 * parses complete lines retrieved by readline(), and returns an integer 920 * representation of the current printer status to the caller. If nothing was 921 * available a status request (control T) is sent to the printer and nostatus 922 * is returned to the caller (provided quiet isn't TRUE). Interactive mode 923 * either never returns from readline() or returns FALSE. 924 */ 925 926 int 927 getstatus(int t) /* sleep time after sending '\024' */ 928 { 929 int state = nostatus; /* the current state */ 930 static int laststate = NOSTATUS; /* last state recognized */ 931 932 933 if (canread == TRUE && readline() == TRUE) { 934 state = parsemesg(); 935 if (state != laststate || mesgptr != mesg || debug == ON) 936 logit("%s", mesg); 937 938 if (tostdout == TRUE && currentstate != START) { 939 *mesgptr = '\0'; 940 fprintf(stdout, "%s", mesg); 941 } 942 return (laststate = state); 943 } 944 945 if ((quiet == FALSE || currentstate != SEND) && interactive == FALSE) { 946 if (Write(ttyo, "\024", 1) != 1) 947 error(FATAL, "printer appears to be offline"); 948 if (t > 0) Rest(t); 949 } 950 951 return (nostatus); 952 } 953 954 955 /* 956 * 957 * Parsing the lines that readline() stores in mesg[] is messy, and what's done 958 * here isn't completely correct nor as fast as it could be. The general format 959 * of lines that come back from the printer (assuming no data loss) is: 960 * 961 * str%%[ key: val; key: val; key: val ]%%\n 962 * 963 * where str can be most anything not containing a newline and printer reports 964 * (eg. status or error messages) are bracketed by "%%[ " and " ]%%" strings and 965 * end with a newline. Usually we'll have the string or printer report but not 966 * both. For most jobs the leading string will be empty, but could be anything 967 * generated on a printer and returned over the communications line using the 968 * PostScript print operator. I'll assume PostScript jobs are well behaved and 969 * never bracket their messages with "%%[ " and " ]%%" strings that delimit 970 * status or error messages. 971 * 972 * Printer reports consist of one or more key/val pairs, and what we're 973 * interested in (status or error indications) may not be the first pair in the 974 * list. In addition we'll sometimes want the value associated with a keyword 975 * (eg. when key = status) and other times we'll want the keyword (eg. when 976 * key = Error or Flushing). The last pair isn't terminated by a semicolon and 977 * a value string often contains many space separated words and it can even 978 * include colons in meaningful places. I've also decided to continue 979 * converting things to lower case before doing the lookup in status[]. The 980 * isupper() test is for Berkeley systems. 981 */ 982 983 static int 984 parsemesg(void) 985 { 986 char *e; /* end of printer message in mesg[] */ 987 char *key, *val; /* keyword/value strings in sbuf[] */ 988 char *p; /* for converting to lower case etc. */ 989 int i; /* where *key was found in status[] */ 990 991 if (*(mesgptr = find("%%[ ", mesg)) != '\0' && 992 *(e = find(" ]%%", mesgptr+4)) != '\0') { 993 994 strcpy(sbuf, mesgptr+4); /* don't change mesg[] */ 995 sbuf[e-mesgptr-4] = '\0'; /* ignore the trailing " ]%%" */ 996 997 for (key = strtok(sbuf, " :"); key != NULL; 998 key = strtok(NULL, " :")) { 999 if ((val = strtok(NULL, ";")) != NULL && 1000 strcmp(key, "status") == 0) 1001 key = val; 1002 1003 for (; *key == ' '; key++); /* skip leading space */ 1004 for (p = key; *p; p++) /* conv to lower case */ 1005 if (*p == ':' || *p == ',') { 1006 *p = '\0'; 1007 break; 1008 } else if (isupper(*p)) 1009 *p = tolower(*p); 1010 1011 for (i = 0; status[i].state != NULL; i++) 1012 if (strcmp(status[i].state, key) == 0) 1013 return (status[i].val); 1014 } 1015 } else if (strcmp(mesg, "CONVERSATION ENDED.\n") == 0) 1016 return (DISCONNECT); 1017 1018 return (nostatus); 1019 } 1020 1021 1022 /* 1023 * Looks for *str1 in string *str2. Returns a pointer to the start of the 1024 * substring if it's found or to the end of string str2 otherwise. 1025 */ 1026 1027 static char * 1028 find(char *str1, char *str2) 1029 { 1030 char *s1, *s2; /* can't change str1 or str2 too fast */ 1031 1032 for (; *str2 != '\0'; str2++) { 1033 for (s1 = str1, s2 = str2; *s1 != '\0' && *s1 == *s2; s1++, s2++); 1034 if (*s1 == '\0') 1035 break; 1036 } 1037 1038 return (str2); 1039 1040 } 1041 1042 1043 /* 1044 * Reads characters from the input line until nothing's left. Don't do 1045 * anything if we're currently running separate read and write processes. 1046 */ 1047 1048 static void 1049 clearline(void) 1050 { 1051 if (whatami == READWRITE) 1052 while (readline() != FALSE); 1053 1054 } 1055 1056 1057 /* 1058 * Sends signal sig to the other process if we're running as separate read and 1059 * write processes. Returns the result of the kill if there's someone else to 1060 * signal or -1 if we're running alone. 1061 * 1062 */ 1063 1064 static int 1065 sendsignal(int sig) 1066 { 1067 if (whatami != READWRITE && otherpid > 1) 1068 return (kill(otherpid, sig)); 1069 1070 return (-1); 1071 } 1072 1073 1074 /* 1075 * Caught a signal - all except joinsig cause the program to quit. joinsig is 1076 * the signal sent by the writer to the reader after all the jobs have been 1077 * transmitted. Used to tell the read process when it can start looking for 1078 * the end of the job. 1079 */ 1080 1081 static void 1082 interrupt(int sig) 1083 { 1084 signal(sig, SIG_IGN); 1085 1086 if (sig != joinsig) { 1087 x_stat |= FATAL; 1088 if (canread == TRUE) 1089 if (interactive == FALSE) 1090 error(NON_FATAL, "signal %d abort", sig); 1091 else error(NON_FATAL, "quitting"); 1092 quit(sig); 1093 } 1094 1095 writedone = TRUE; 1096 signal(joinsig, interrupt); 1097 } 1098 1099 1100 /* 1101 * Simple routine that's used to write a message to the log file. 1102 */ 1103 1104 void 1105 logit(char *mesg, ...) 1106 { 1107 va_list ap; 1108 1109 va_start(ap, mesg); 1110 vfprintf(fp_log, mesg, ap); 1111 va_end(ap); 1112 1113 fflush(fp_log); 1114 1115 } 1116 1117 /* 1118 * Called when we've run into some kind of program error. First *mesg is 1119 * printed. If kind is FATAL and we're not ignoring errors the program 1120 * will be terminated. If mesg is NULL or *mesg is the NULL string nothing 1121 * will be printed. 1122 */ 1123 1124 void 1125 error(int kind, char *mesg, ...) 1126 { 1127 va_list ap; 1128 1129 if (mesg != NULL && *mesg != '\0') { 1130 fprintf(fp_log, "%s: ", prog_name); 1131 1132 va_start(ap, mesg); 1133 vfprintf(fp_log, mesg, ap); 1134 va_end(ap); 1135 1136 putc('\n', fp_log); 1137 } 1138 1139 x_stat |= kind; 1140 1141 if (kind != NON_FATAL && ignore == OFF) 1142 quit(SIGTERM); 1143 1144 } 1145 1146 1147 /* 1148 * 1149 * Makes sure everything is properly cleaned up if there's a signal or FATAL 1150 * error that should cause the program to terminate. The sleep by the write 1151 * process is to help give the reset sequence a chance to reach the printer 1152 * before we break the connection - primarily for printers connected to Datakit. 1153 * There's a very slight chance the reset sequence that's sent to the printer 1154 * could get us stuck here. Simplest solution is don't bother to send it - 1155 * everything works without it. Flushing ttyo would be better, but means yet 1156 * another system dependent procedure in ifdef.c! I'll leave things be for now. 1157 */ 1158 1159 static void 1160 quit(int sig) 1161 { 1162 int w; 1163 1164 signal(sig, SIG_IGN); 1165 ignore = ON; 1166 1167 while (sendsignal(sig) != -1 && (w = wait((int *)0)) != otherpid && 1168 w != -1); 1169 1170 setupstdin(2); 1171 1172 if (currentstate != NOTCONNECTED) 1173 Write(ttyo, "\003\004", 2); 1174 alarm(0); /* prevents sleep() loop on V9 systems */ 1175 Rest(2); 1176 1177 exit(x_stat); 1178 1179 } 1180 1181 1182 /* 1183 * Used to replace sleep() calls. Only needed if we're running the program as 1184 * a read and write process and don't want to have the read process sleep. Most 1185 * sleeps are in the code because of the non-blocking read used by the single 1186 * process implementation. Probably should be a macro. 1187 */ 1188 1189 static void 1190 Rest(int t) 1191 { 1192 if (t > 0 && canwrite == TRUE) 1193 sleep(t); 1194 1195 } 1196 1197 1198 /* 1199 * Used to replace some of the read() calls. Only needed if we're running 1200 * separate read and write processes. Should only be used to replace read calls 1201 * on ttyi. Always returns 0 to the caller if the process doesn't have its 1202 * READ flag set. Probably should be a macro. 1203 */ 1204 1205 #ifdef NEVER 1206 1207 static int 1208 Read(int fd, char *buf, int n) 1209 { 1210 int count; 1211 1212 if (canread == TRUE) { 1213 if ((count = read(fd, buf, n)) == -1 && errno == EINTR) 1214 count = 0; 1215 } else count = 0; 1216 1217 return (count); 1218 1219 } 1220 1221 #endif /* NEVER */ 1222 1223 1224 /* 1225 * 1226 * Used to replace some of the write() calls. Again only needed if we're running 1227 * separate read and write processes. Should only be used to replace write calls 1228 * on ttyo. Always returns n to the caller if the process doesn't have its WRITE 1229 * flag set. Should also probably be a macro. 1230 * 1231 */ 1232 1233 static int 1234 Write(int fd, char *buf, int n) 1235 { 1236 int count; 1237 1238 if (canwrite == TRUE) { 1239 if ((count = write(fd, buf, n)) == -1 && errno == EINTR) 1240 count = n; 1241 } else count = n; 1242 1243 return (count); 1244 } 1245