17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate * with the License.
87c478bd9Sstevel@tonic-gate *
97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate * and limitations under the License.
137c478bd9Sstevel@tonic-gate *
147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate *
207c478bd9Sstevel@tonic-gate * CDDL HEADER END
217c478bd9Sstevel@tonic-gate */
227c478bd9Sstevel@tonic-gate /*
23f928ce67Sceastha * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
247c478bd9Sstevel@tonic-gate * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate */
267c478bd9Sstevel@tonic-gate
277c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
287c478bd9Sstevel@tonic-gate /* All Rights Reserved */
297c478bd9Sstevel@tonic-gate
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate *
327c478bd9Sstevel@tonic-gate * postio - RS-232 serial interface for PostScript printers
337c478bd9Sstevel@tonic-gate *
347c478bd9Sstevel@tonic-gate * A simple program that manages input and output for PostScript printers. Much
357c478bd9Sstevel@tonic-gate * has been added and changed from early versions of the program, but the basic
367c478bd9Sstevel@tonic-gate * philosophy is still the same. Don't send real data until we're certain we've
377c478bd9Sstevel@tonic-gate * connected to a PostScript printer that's in the idle state and try to hold
387c478bd9Sstevel@tonic-gate * the connection until the job is completely done. It's more work than you
397c478bd9Sstevel@tonic-gate * might expect is necessary, but should provide a reasonably reliable spooler
407c478bd9Sstevel@tonic-gate * interface that can return error indications to the caller via the program's
417c478bd9Sstevel@tonic-gate * exit status.
427c478bd9Sstevel@tonic-gate *
437c478bd9Sstevel@tonic-gate * I've added code that will let you split the program into separate read/write
447c478bd9Sstevel@tonic-gate * processes. Although it's not the default it should be useful if you have a
457c478bd9Sstevel@tonic-gate * file that will be returning useful data from the printer. The two process
467c478bd9Sstevel@tonic-gate * stuff was laid down on top of the single process code and both methods still
477c478bd9Sstevel@tonic-gate * work. The implementation isn't as good as it could be, but didn't require
487c478bd9Sstevel@tonic-gate * many changes to the original program (despite the fact that there are now
497c478bd9Sstevel@tonic-gate * many differences).
507c478bd9Sstevel@tonic-gate *
517c478bd9Sstevel@tonic-gate * By default the program still runs as a single process. The -R2 option forces
527c478bd9Sstevel@tonic-gate * separate read and write processes after the intial connection is made. If you
537c478bd9Sstevel@tonic-gate * want that as the default initialize splitme (below) to TRUE. In addition the
547c478bd9Sstevel@tonic-gate * -t option that's used to force stuff not recognized as status reports to
557c478bd9Sstevel@tonic-gate * stdout also tries to run as two processes (by setting splitme to TRUE). It
567c478bd9Sstevel@tonic-gate * will only work if the required code (ie. resetline() in ifdef.c) has been
577c478bd9Sstevel@tonic-gate * implemented for your Unix system. I've only tested the System V code.
587c478bd9Sstevel@tonic-gate *
597c478bd9Sstevel@tonic-gate * Code needed to support interactive mode has also been added, although again
607c478bd9Sstevel@tonic-gate * it's not as efficient as it could be. It depends on the system dependent
617c478bd9Sstevel@tonic-gate * procedures resetline() and setupstdin() (file ifdef.c) and for now is only
627c478bd9Sstevel@tonic-gate * guaranteed to work on System V. Can be requested using the -i option.
637c478bd9Sstevel@tonic-gate *
647c478bd9Sstevel@tonic-gate * Quiet mode (-q option) is also new, but was needed for some printers
657c478bd9Sstevel@tonic-gate * connected to RADIAN. If you're running in quiet mode no status requests will
667c478bd9Sstevel@tonic-gate * be sent to the printer while files are being transmitted (ie. in send()).
677c478bd9Sstevel@tonic-gate *
687c478bd9Sstevel@tonic-gate * The program expects to receive printer status lines that look like,
697c478bd9Sstevel@tonic-gate *
707c478bd9Sstevel@tonic-gate * %%[ status: idle; source: serial 25 ]%%
717c478bd9Sstevel@tonic-gate * %%[ status: waiting; source: serial 25 ]%%
727c478bd9Sstevel@tonic-gate * %%[ status: initializing; source: serial 25 ]%%
737c478bd9Sstevel@tonic-gate * %%[ status: busy; source: serial 25 ]%%
747c478bd9Sstevel@tonic-gate * %%[ status: printing; source: serial 25 ]%%
757c478bd9Sstevel@tonic-gate * %%[ status: PrinterError: out of paper; source: serial 25 ]%%
767c478bd9Sstevel@tonic-gate * %%[ status: PrinterError: no paper tray; source: serial 25 ]%%
777c478bd9Sstevel@tonic-gate *
787c478bd9Sstevel@tonic-gate * although this list isn't complete. Sending a '\024' (control T) character
797c478bd9Sstevel@tonic-gate * forces the return of a status report. PostScript errors detected on the
807c478bd9Sstevel@tonic-gate * printer result in the immediate transmission of special error messages that
817c478bd9Sstevel@tonic-gate * look like,
827c478bd9Sstevel@tonic-gate *
837c478bd9Sstevel@tonic-gate * %%[ Error: undefined; OffendingCommand: xxx ]%%
847c478bd9Sstevel@tonic-gate * %%[ Flushing: rest of job (to end-of-file) will be ignored ]%%
857c478bd9Sstevel@tonic-gate *
867c478bd9Sstevel@tonic-gate * although we only use the Error and Flushing keywords. Finally conditions,
877c478bd9Sstevel@tonic-gate * like being out of paper, result in other messages being sent back from the
887c478bd9Sstevel@tonic-gate * printer over the communications line. Typical PrinterError messages look
897c478bd9Sstevel@tonic-gate * like,
907c478bd9Sstevel@tonic-gate *
917c478bd9Sstevel@tonic-gate * %%[ PrinterError: out of paper; source: serial 25 ]%%
927c478bd9Sstevel@tonic-gate * %%[ PrinterError: paper jam; source: serial 25 ]%%
937c478bd9Sstevel@tonic-gate *
947c478bd9Sstevel@tonic-gate * although we only use the PrinterError keyword rather than trying to recognize
957c478bd9Sstevel@tonic-gate * all possible printer errors.
967c478bd9Sstevel@tonic-gate *
977c478bd9Sstevel@tonic-gate * The implications of using one process and only flow controlling data going to
987c478bd9Sstevel@tonic-gate * the printer are obvious. Job transmission should be reliable, but there can
997c478bd9Sstevel@tonic-gate * be data loss in stuff sent back from the printer. Usually that only caused
1007c478bd9Sstevel@tonic-gate * problems with jobs designed to run on the printer and return useful data
1017c478bd9Sstevel@tonic-gate * back over the communications line. If that's the kind of job you're sending
1027c478bd9Sstevel@tonic-gate * call postio with the -t option. That should force the program to split into
1037c478bd9Sstevel@tonic-gate * separate read and write processes and everything not bracketed by "%%[ "
1047c478bd9Sstevel@tonic-gate * and " ]%%" strings goes to stdout. In otherwords the data you're expecting
1057c478bd9Sstevel@tonic-gate * should be separated from the status stuff that goes to the log file (or
1067c478bd9Sstevel@tonic-gate * stderr). The -R2 option does almost the same thing (ie. separate read and
1077c478bd9Sstevel@tonic-gate * write processes), but everything that comes back from the printer goes to
1087c478bd9Sstevel@tonic-gate * the log file (stderr by default) and you'll have to separate your data from
1097c478bd9Sstevel@tonic-gate * any printer messages.
1107c478bd9Sstevel@tonic-gate *
1117c478bd9Sstevel@tonic-gate * A typical command line might be,
1127c478bd9Sstevel@tonic-gate *
1137c478bd9Sstevel@tonic-gate * postio -l /dev/tty01 -b 9600 -L log file1 file2
1147c478bd9Sstevel@tonic-gate *
1157c478bd9Sstevel@tonic-gate * where -l selects the line, -b sets the baud rate, and -L selects the printer
1167c478bd9Sstevel@tonic-gate * log file. Since there's no default line, at least not right now, you'll
1177c478bd9Sstevel@tonic-gate * always need to use the -l option, and if you don't choose a log file stderr
1187c478bd9Sstevel@tonic-gate * will be used. If you have a program that will be returning data the command
1197c478bd9Sstevel@tonic-gate * line might look like,
1207c478bd9Sstevel@tonic-gate *
1217c478bd9Sstevel@tonic-gate * postio -t -l/dev/tty01 -b9600 -Llog file >results
1227c478bd9Sstevel@tonic-gate *
1237c478bd9Sstevel@tonic-gate * Status stuff goes to file log while the data you're expecting back from the
1247c478bd9Sstevel@tonic-gate * printer gets put in file results.
1257c478bd9Sstevel@tonic-gate *
1267c478bd9Sstevel@tonic-gate */
1277c478bd9Sstevel@tonic-gate
1287c478bd9Sstevel@tonic-gate #include <stdio.h>
1297c478bd9Sstevel@tonic-gate #include <unistd.h>
1307c478bd9Sstevel@tonic-gate #include <stdarg.h>
1317c478bd9Sstevel@tonic-gate #include <stdlib.h>
1327c478bd9Sstevel@tonic-gate #include <ctype.h>
1337c478bd9Sstevel@tonic-gate #include <fcntl.h>
1347c478bd9Sstevel@tonic-gate #include <signal.h>
1357c478bd9Sstevel@tonic-gate #include <sys/types.h>
1367c478bd9Sstevel@tonic-gate #include <sys/wait.h>
1377c478bd9Sstevel@tonic-gate #include <errno.h>
1387c478bd9Sstevel@tonic-gate #include <string.h>
1397c478bd9Sstevel@tonic-gate #include <sys/ioccom.h>
1407c478bd9Sstevel@tonic-gate #include <sys/ioctl.h>
1417c478bd9Sstevel@tonic-gate #include <sys/bpp_io.h>
1427c478bd9Sstevel@tonic-gate #include <sys/ecppsys.h>
1437c478bd9Sstevel@tonic-gate
1447c478bd9Sstevel@tonic-gate #include "ifdef.h" /* conditional compilation stuff */
1457c478bd9Sstevel@tonic-gate #include "gen.h" /* general purpose definitions */
1467c478bd9Sstevel@tonic-gate #include "postio.h" /* some special definitions */
1477c478bd9Sstevel@tonic-gate
1487c478bd9Sstevel@tonic-gate static char **argv; /* global so everyone can use them */
1497c478bd9Sstevel@tonic-gate static int argc;
1507c478bd9Sstevel@tonic-gate static char *prog_name = ""; /* really just for error messages */
1517c478bd9Sstevel@tonic-gate static int x_stat = 0; /* program exit status */
1527c478bd9Sstevel@tonic-gate static int debug = OFF; /* debug flag */
1537c478bd9Sstevel@tonic-gate static int ignore = OFF; /* what's done for FATAL errors */
1547c478bd9Sstevel@tonic-gate static Baud baudtable[] = BAUDTABLE; /* converts strings to termio values */
1557c478bd9Sstevel@tonic-gate static int quiet = FALSE; /* no status queries in send if TRUE */
1567c478bd9Sstevel@tonic-gate char *postbegin = POSTBEGIN; /* preceeds all the input files */
1577c478bd9Sstevel@tonic-gate static int useslowsend = FALSE; /* not recommended! */
1587c478bd9Sstevel@tonic-gate static int splitme = FALSE; /* into READ & WRITE procs if TRUE */
1597c478bd9Sstevel@tonic-gate static int whatami = READWRITE; /* a READ or WRITE process - or both */
1607c478bd9Sstevel@tonic-gate static int otherpid = -1; /* who gets signals if greater than 1 */
1617c478bd9Sstevel@tonic-gate static int joinsig = SIGTRAP; /* reader gets when writing is done */
1627c478bd9Sstevel@tonic-gate static int writedone = FALSE; /* and then sets this to TRUE */
1637c478bd9Sstevel@tonic-gate static char sbuf[MESGSIZE]; /* for parsing the message */
1647c478bd9Sstevel@tonic-gate static char *mesgptr = NULL; /* printer msg starts here in mesg[] */
1657c478bd9Sstevel@tonic-gate static Status status[] = STATUS; /* for converting status strings */
1667c478bd9Sstevel@tonic-gate static int nostatus = NOSTATUS; /* default getstatus() return value */
1677c478bd9Sstevel@tonic-gate static int tostdout = FALSE; /* non-status stuff goes to stdout? */
1687c478bd9Sstevel@tonic-gate static int currentstate = NOTCONNECTED; /* START, SEND, or DONE */
1697c478bd9Sstevel@tonic-gate
1707c478bd9Sstevel@tonic-gate char *line = NULL; /* printer is on this tty line */
1717c478bd9Sstevel@tonic-gate short baudrate = BAUDRATE; /* and running at this baud rate */
1727c478bd9Sstevel@tonic-gate int stopbits = 1; /* number of stop bits */
1737c478bd9Sstevel@tonic-gate int interactive = FALSE; /* interactive mode */
1747c478bd9Sstevel@tonic-gate char *block = NULL; /* input file buffer */
1757c478bd9Sstevel@tonic-gate int blocksize = BLOCKSIZE; /* and its size in bytes */
1767c478bd9Sstevel@tonic-gate int head = 0; /* block[head] is the next character */
1777c478bd9Sstevel@tonic-gate int tail = 0; /* one past the last byte in block[] */
1787c478bd9Sstevel@tonic-gate int canread = TRUE; /* allow reads */
1797c478bd9Sstevel@tonic-gate int canwrite = TRUE; /* and writes if TRUE */
1807c478bd9Sstevel@tonic-gate char mesg[MESGSIZE]; /* exactly what came back on ttyi */
1817c478bd9Sstevel@tonic-gate char *endmesg = NULL; /* end for readline() in mesg[] */
1827c478bd9Sstevel@tonic-gate int ttyi = 0; /* input */
1837c478bd9Sstevel@tonic-gate int ttyo = 2; /* and output file descriptors */
1847c478bd9Sstevel@tonic-gate FILE *fp_log = stderr; /* log file for stuff from printer */
1857c478bd9Sstevel@tonic-gate
1867c478bd9Sstevel@tonic-gate static void init_signals(void);
1877c478bd9Sstevel@tonic-gate static void interrupt(int);
1887c478bd9Sstevel@tonic-gate static void options(void);
1897c478bd9Sstevel@tonic-gate static void initialize(void);
1907c478bd9Sstevel@tonic-gate static void initialize_parallel(void);
1917c478bd9Sstevel@tonic-gate static void start(void);
1927c478bd9Sstevel@tonic-gate static void split(void);
1937c478bd9Sstevel@tonic-gate static void arguments(void);
1947c478bd9Sstevel@tonic-gate static void send(int, char *);
1957c478bd9Sstevel@tonic-gate static void done(void);
1967c478bd9Sstevel@tonic-gate static void cleanup(void);
1977c478bd9Sstevel@tonic-gate static void clearline(void);
1987c478bd9Sstevel@tonic-gate void logit(char *, ...);
1997c478bd9Sstevel@tonic-gate static void quit(int sig);
2007c478bd9Sstevel@tonic-gate static void Rest(int t);
2017c478bd9Sstevel@tonic-gate static int parsemesg(void);
2027c478bd9Sstevel@tonic-gate static int sendsignal(int);
2037c478bd9Sstevel@tonic-gate static int writeblock(void);
2047c478bd9Sstevel@tonic-gate static int Write(int, char *, int);
2057c478bd9Sstevel@tonic-gate static short getbaud(char *);
2067c478bd9Sstevel@tonic-gate static char *find(char *, char *);
2077c478bd9Sstevel@tonic-gate
2087c478bd9Sstevel@tonic-gate void error(int, char *, ...);
2097c478bd9Sstevel@tonic-gate int getstatus(int);
2107c478bd9Sstevel@tonic-gate int readblock(int);
2117c478bd9Sstevel@tonic-gate
2127c478bd9Sstevel@tonic-gate
2137c478bd9Sstevel@tonic-gate /* from parallel.c for parallel interfaces */
2147c478bd9Sstevel@tonic-gate extern int is_a_parallel_bpp(int);
2157c478bd9Sstevel@tonic-gate extern int bpp_state(int);
2167c478bd9Sstevel@tonic-gate extern int is_a_prnio(int);
2177c478bd9Sstevel@tonic-gate extern int prnio_state(int);
2187c478bd9Sstevel@tonic-gate extern int parallel_comm(int, int()); /* arg is bpp_state */
2197c478bd9Sstevel@tonic-gate
2207c478bd9Sstevel@tonic-gate /* from ifdef.c for serial interfaces */
2217c478bd9Sstevel@tonic-gate extern void setupline(void);
2227c478bd9Sstevel@tonic-gate extern void setupstdin(int);
2237c478bd9Sstevel@tonic-gate extern void slowsend(int);
2247c478bd9Sstevel@tonic-gate extern int resetline(void);
2257c478bd9Sstevel@tonic-gate extern int readline(void);
2267c478bd9Sstevel@tonic-gate
2277c478bd9Sstevel@tonic-gate /*
2287c478bd9Sstevel@tonic-gate * A simple program that manages input and output for PostScript printers.
2297c478bd9Sstevel@tonic-gate * Can run as a single process or as separate read/write processes. What's
2307c478bd9Sstevel@tonic-gate * done depends on the value assigned to splitme when split() is called.
2317c478bd9Sstevel@tonic-gate */
2327c478bd9Sstevel@tonic-gate
nop(int fd)2337c478bd9Sstevel@tonic-gate int nop(int fd) { return(0); }
2347c478bd9Sstevel@tonic-gate
2357c478bd9Sstevel@tonic-gate
2367c478bd9Sstevel@tonic-gate int
main(int agc,char * agv[])2377c478bd9Sstevel@tonic-gate main(int agc, char *agv[])
2387c478bd9Sstevel@tonic-gate {
2397c478bd9Sstevel@tonic-gate argc = agc;
2407c478bd9Sstevel@tonic-gate argv = agv;
2417c478bd9Sstevel@tonic-gate prog_name = argv[0]; /* really just for error messages */
2427c478bd9Sstevel@tonic-gate
2437c478bd9Sstevel@tonic-gate /* is this a serial or parallel port? */
2447c478bd9Sstevel@tonic-gate
2457c478bd9Sstevel@tonic-gate init_signals(); /* sets up interrupt handling */
2467c478bd9Sstevel@tonic-gate options(); /* get command line options */
2477c478bd9Sstevel@tonic-gate
2487c478bd9Sstevel@tonic-gate setbuf(stderr, NULL); /* unbuffer io for stderr */
249*2a8bcb4eSToomas Soome
2507c478bd9Sstevel@tonic-gate
2517c478bd9Sstevel@tonic-gate if (line) {
2527c478bd9Sstevel@tonic-gate close(1);
2537c478bd9Sstevel@tonic-gate open(line, O_RDWR);
2547c478bd9Sstevel@tonic-gate
2557c478bd9Sstevel@tonic-gate }
2567c478bd9Sstevel@tonic-gate
2577c478bd9Sstevel@tonic-gate if (is_a_prnio(1)) {
2587c478bd9Sstevel@tonic-gate initialize_parallel();
2597c478bd9Sstevel@tonic-gate x_stat = parallel_comm(1, prnio_state);
2607c478bd9Sstevel@tonic-gate } else if (is_a_parallel_bpp(1) ||
2617c478bd9Sstevel@tonic-gate (get_ecpp_status(1) == ECPP_CENTRONICS)) {
2627c478bd9Sstevel@tonic-gate initialize_parallel();
2637c478bd9Sstevel@tonic-gate x_stat = parallel_comm(1, bpp_state);
2647c478bd9Sstevel@tonic-gate } else if (isatty(1)) {
2657c478bd9Sstevel@tonic-gate initialize(); /* must be done after options() */
2667c478bd9Sstevel@tonic-gate start(); /* make sure the printer is ready */
2677c478bd9Sstevel@tonic-gate split(); /* into read/write processes - maybe */
2687c478bd9Sstevel@tonic-gate arguments(); /* then send each input file */
2697c478bd9Sstevel@tonic-gate done(); /* wait until the printer is finished */
2707c478bd9Sstevel@tonic-gate cleanup(); /* make sure the write process stops */
2717c478bd9Sstevel@tonic-gate } else {
2727c478bd9Sstevel@tonic-gate initialize_parallel();
2737c478bd9Sstevel@tonic-gate x_stat = parallel_comm(1, nop);
2747c478bd9Sstevel@tonic-gate }
275*2a8bcb4eSToomas Soome
2767c478bd9Sstevel@tonic-gate
2777c478bd9Sstevel@tonic-gate return (x_stat); /* everything probably went OK */
2787c478bd9Sstevel@tonic-gate }
2797c478bd9Sstevel@tonic-gate
2807c478bd9Sstevel@tonic-gate
2817c478bd9Sstevel@tonic-gate /*
2827c478bd9Sstevel@tonic-gate * Makes sure we handle interrupts. The proper way to kill the program, if
2837c478bd9Sstevel@tonic-gate * necessary, is to do a kill -15. That forces a call to interrupt(), which in
2847c478bd9Sstevel@tonic-gate * turn tries to reset the printer and then exits with a non-zero status. If the
2857c478bd9Sstevel@tonic-gate * program is running as two processes, sending SIGTERM to either the parent or
2867c478bd9Sstevel@tonic-gate * child should clean things up.
2877c478bd9Sstevel@tonic-gate */
2887c478bd9Sstevel@tonic-gate
2897c478bd9Sstevel@tonic-gate static void
init_signals(void)2907c478bd9Sstevel@tonic-gate init_signals(void)
2917c478bd9Sstevel@tonic-gate {
2927c478bd9Sstevel@tonic-gate if (signal(SIGINT, interrupt) == SIG_IGN) {
2937c478bd9Sstevel@tonic-gate signal(SIGINT, SIG_IGN);
2947c478bd9Sstevel@tonic-gate signal(SIGQUIT, SIG_IGN);
2957c478bd9Sstevel@tonic-gate signal(SIGHUP, SIG_IGN);
2967c478bd9Sstevel@tonic-gate } else {
2977c478bd9Sstevel@tonic-gate signal(SIGHUP, interrupt);
2987c478bd9Sstevel@tonic-gate signal(SIGQUIT, interrupt);
2997c478bd9Sstevel@tonic-gate }
3007c478bd9Sstevel@tonic-gate
3017c478bd9Sstevel@tonic-gate signal(SIGTERM, interrupt);
3027c478bd9Sstevel@tonic-gate
3037c478bd9Sstevel@tonic-gate }
3047c478bd9Sstevel@tonic-gate
3057c478bd9Sstevel@tonic-gate
3067c478bd9Sstevel@tonic-gate /*
3077c478bd9Sstevel@tonic-gate * Reads and processes the command line options. The -R2, -t, and -i options all
3087c478bd9Sstevel@tonic-gate * force separate read and write processes by eventually setting splitme to TRUE
3097c478bd9Sstevel@tonic-gate * (check initialize()). The -S option is not recommended and should only be
3107c478bd9Sstevel@tonic-gate * used as a last resort!
3117c478bd9Sstevel@tonic-gate */
3127c478bd9Sstevel@tonic-gate
3137c478bd9Sstevel@tonic-gate static void
options(void)3147c478bd9Sstevel@tonic-gate options(void)
3157c478bd9Sstevel@tonic-gate {
3167c478bd9Sstevel@tonic-gate int ch; /* return value from getopt() */
3177c478bd9Sstevel@tonic-gate char *optnames = "b:il:qs:tB:L:P:R:SDI";
3187c478bd9Sstevel@tonic-gate
3197c478bd9Sstevel@tonic-gate extern char *optarg; /* used by getopt() */
3207c478bd9Sstevel@tonic-gate extern int optind;
3217c478bd9Sstevel@tonic-gate
3227c478bd9Sstevel@tonic-gate while ((ch = getopt(argc, argv, optnames)) != EOF) {
3237c478bd9Sstevel@tonic-gate
3247c478bd9Sstevel@tonic-gate switch (ch) {
3257c478bd9Sstevel@tonic-gate
3267c478bd9Sstevel@tonic-gate case 'b': /* baud rate string */
3277c478bd9Sstevel@tonic-gate baudrate = getbaud(optarg);
3287c478bd9Sstevel@tonic-gate break;
3297c478bd9Sstevel@tonic-gate
3307c478bd9Sstevel@tonic-gate case 'i': /* interactive mode */
3317c478bd9Sstevel@tonic-gate interactive = TRUE;
3327c478bd9Sstevel@tonic-gate break;
3337c478bd9Sstevel@tonic-gate
3347c478bd9Sstevel@tonic-gate case 'l': /* printer line */
3357c478bd9Sstevel@tonic-gate line = optarg;
3367c478bd9Sstevel@tonic-gate break;
3377c478bd9Sstevel@tonic-gate
3387c478bd9Sstevel@tonic-gate case 'q': /* no status queries - for RADIAN? */
3397c478bd9Sstevel@tonic-gate quiet = TRUE;
3407c478bd9Sstevel@tonic-gate break;
3417c478bd9Sstevel@tonic-gate
3427c478bd9Sstevel@tonic-gate case 's': /* use 2 stop bits - for UNISON? */
3437c478bd9Sstevel@tonic-gate if ((stopbits = atoi(optarg)) < 1 || stopbits > 2)
3447c478bd9Sstevel@tonic-gate stopbits = 1;
3457c478bd9Sstevel@tonic-gate break;
3467c478bd9Sstevel@tonic-gate
3477c478bd9Sstevel@tonic-gate case 't': /* non-status stuff goes to stdout */
3487c478bd9Sstevel@tonic-gate tostdout = TRUE;
3497c478bd9Sstevel@tonic-gate break;
3507c478bd9Sstevel@tonic-gate
3517c478bd9Sstevel@tonic-gate case 'B': /* set the job buffer size */
3527c478bd9Sstevel@tonic-gate if ((blocksize = atoi(optarg)) <= 0)
3537c478bd9Sstevel@tonic-gate blocksize = BLOCKSIZE;
3547c478bd9Sstevel@tonic-gate break;
3557c478bd9Sstevel@tonic-gate
3567c478bd9Sstevel@tonic-gate case 'L': /* printer log file */
3577c478bd9Sstevel@tonic-gate if ((fp_log = fopen(optarg, "w")) == NULL) {
3587c478bd9Sstevel@tonic-gate fp_log = stderr;
3597c478bd9Sstevel@tonic-gate error(NON_FATAL, "can't open log file %s", optarg);
3607c478bd9Sstevel@tonic-gate } /* End if */
3617c478bd9Sstevel@tonic-gate break;
3627c478bd9Sstevel@tonic-gate
3637c478bd9Sstevel@tonic-gate case 'P': /* initial PostScript code */
3647c478bd9Sstevel@tonic-gate postbegin = optarg;
3657c478bd9Sstevel@tonic-gate break;
3667c478bd9Sstevel@tonic-gate
3677c478bd9Sstevel@tonic-gate case 'R': /* run as one or two processes */
3687c478bd9Sstevel@tonic-gate if (atoi(optarg) == 2)
3697c478bd9Sstevel@tonic-gate splitme = TRUE;
3707c478bd9Sstevel@tonic-gate else splitme = FALSE;
3717c478bd9Sstevel@tonic-gate break;
3727c478bd9Sstevel@tonic-gate
3737c478bd9Sstevel@tonic-gate case 'S': /* slow and kludged up vers. of send */
3747c478bd9Sstevel@tonic-gate useslowsend = TRUE;
3757c478bd9Sstevel@tonic-gate break;
3767c478bd9Sstevel@tonic-gate
3777c478bd9Sstevel@tonic-gate case 'D': /* debug flag */
3787c478bd9Sstevel@tonic-gate debug = ON;
3797c478bd9Sstevel@tonic-gate break;
3807c478bd9Sstevel@tonic-gate
3817c478bd9Sstevel@tonic-gate case 'I': /* ignore FATAL errors */
3827c478bd9Sstevel@tonic-gate ignore = ON;
3837c478bd9Sstevel@tonic-gate break;
3847c478bd9Sstevel@tonic-gate
3857c478bd9Sstevel@tonic-gate case '?': /* don't understand the option */
3867c478bd9Sstevel@tonic-gate error(FATAL, "");
3877c478bd9Sstevel@tonic-gate break;
3887c478bd9Sstevel@tonic-gate
3897c478bd9Sstevel@tonic-gate default: /* don't know what to do for ch */
3907c478bd9Sstevel@tonic-gate error(FATAL, "missing case for option %c\n", ch);
3917c478bd9Sstevel@tonic-gate break;
3927c478bd9Sstevel@tonic-gate
3937c478bd9Sstevel@tonic-gate } /* End switch */
3947c478bd9Sstevel@tonic-gate
3957c478bd9Sstevel@tonic-gate } /* End while */
3967c478bd9Sstevel@tonic-gate
3977c478bd9Sstevel@tonic-gate argc -= optind; /* get ready for non-option args */
3987c478bd9Sstevel@tonic-gate argv += optind;
3997c478bd9Sstevel@tonic-gate
4007c478bd9Sstevel@tonic-gate }
4017c478bd9Sstevel@tonic-gate
4027c478bd9Sstevel@tonic-gate
4037c478bd9Sstevel@tonic-gate /*
4047c478bd9Sstevel@tonic-gate * Called from options() to convert a baud rate string into an appropriate
4057c478bd9Sstevel@tonic-gate * termio value. *rate is looked up in baudtable[] and if it's found, the
4067c478bd9Sstevel@tonic-gate * corresponding value is returned to the caller.
4077c478bd9Sstevel@tonic-gate */
4087c478bd9Sstevel@tonic-gate
4097c478bd9Sstevel@tonic-gate static short
getbaud(char * rate)4107c478bd9Sstevel@tonic-gate getbaud(char *rate) /* string representing the baud rate */
4117c478bd9Sstevel@tonic-gate {
4127c478bd9Sstevel@tonic-gate int i; /* for looking through baudtable[] */
4137c478bd9Sstevel@tonic-gate
4147c478bd9Sstevel@tonic-gate for (i = 0; baudtable[i].rate != NULL; i++)
4157c478bd9Sstevel@tonic-gate if (strcmp(rate, baudtable[i].rate) == 0)
4167c478bd9Sstevel@tonic-gate return (baudtable[i].val);
4177c478bd9Sstevel@tonic-gate
4187c478bd9Sstevel@tonic-gate error(FATAL, "don't recognize baud rate %s", rate);
419f928ce67Sceastha /*NOTREACHED*/
420f928ce67Sceastha return (0);
4217c478bd9Sstevel@tonic-gate
4227c478bd9Sstevel@tonic-gate }
4237c478bd9Sstevel@tonic-gate
4247c478bd9Sstevel@tonic-gate
4257c478bd9Sstevel@tonic-gate /*
4267c478bd9Sstevel@tonic-gate * Initialization, a few checks, and a call to setupline() (file ifdef.c) to
4277c478bd9Sstevel@tonic-gate * open and configure the communications line. Settings for interactive mode
4287c478bd9Sstevel@tonic-gate * always take precedence. The setupstdin() call with an argument of 0 saves
4297c478bd9Sstevel@tonic-gate * the current terminal settings if interactive mode has been requested -
4307c478bd9Sstevel@tonic-gate * otherwise nothing's done. Unbuffering stdout (via the setbuf() call) isn't
4317c478bd9Sstevel@tonic-gate * really needed on System V since it's flushed whenever terminal input is
4327c478bd9Sstevel@tonic-gate * requested. It's more efficient if we buffer the stdout (on System V) but
4337c478bd9Sstevel@tonic-gate * safer (for other versions of Unix) if we include the setbuf() call.
4347c478bd9Sstevel@tonic-gate */
4357c478bd9Sstevel@tonic-gate
4367c478bd9Sstevel@tonic-gate static void
initialize(void)4377c478bd9Sstevel@tonic-gate initialize(void)
4387c478bd9Sstevel@tonic-gate {
4397c478bd9Sstevel@tonic-gate whatami = READWRITE; /* always run start() as one process */
4407c478bd9Sstevel@tonic-gate canread = canwrite = TRUE;
4417c478bd9Sstevel@tonic-gate
4427c478bd9Sstevel@tonic-gate if (line == NULL) /* kludge for lp - they use -t option */
4437c478bd9Sstevel@tonic-gate tostdout = FALSE;
4447c478bd9Sstevel@tonic-gate
4457c478bd9Sstevel@tonic-gate if (tostdout == TRUE) /* force separate read/write procs */
4467c478bd9Sstevel@tonic-gate splitme = TRUE;
4477c478bd9Sstevel@tonic-gate
4487c478bd9Sstevel@tonic-gate if (interactive == TRUE) { /* interactive mode settings win */
4497c478bd9Sstevel@tonic-gate quiet = FALSE;
4507c478bd9Sstevel@tonic-gate tostdout = FALSE;
4517c478bd9Sstevel@tonic-gate splitme = TRUE;
4527c478bd9Sstevel@tonic-gate blocksize = 1;
4537c478bd9Sstevel@tonic-gate postbegin = NULL;
4547c478bd9Sstevel@tonic-gate useslowsend = FALSE;
4557c478bd9Sstevel@tonic-gate nostatus = INTERACTIVE;
4567c478bd9Sstevel@tonic-gate setbuf(stdout, NULL);
4577c478bd9Sstevel@tonic-gate }
4587c478bd9Sstevel@tonic-gate
4597c478bd9Sstevel@tonic-gate if (useslowsend == TRUE) { /* last resort only - not recommended */
4607c478bd9Sstevel@tonic-gate quiet = FALSE;
4617c478bd9Sstevel@tonic-gate splitme = FALSE;
4627c478bd9Sstevel@tonic-gate if (blocksize > 1024) /* don't send too much all at once */
4637c478bd9Sstevel@tonic-gate blocksize = 1024;
4647c478bd9Sstevel@tonic-gate }
4657c478bd9Sstevel@tonic-gate
4667c478bd9Sstevel@tonic-gate if (line == NULL && (interactive == TRUE || tostdout == TRUE))
4677c478bd9Sstevel@tonic-gate error(FATAL, "a printer line must be supplied - use the -l option");
4687c478bd9Sstevel@tonic-gate
4697c478bd9Sstevel@tonic-gate if ((block = malloc(blocksize)) == NULL)
4707c478bd9Sstevel@tonic-gate error(FATAL, "no memory");
4717c478bd9Sstevel@tonic-gate
4727c478bd9Sstevel@tonic-gate endmesg = mesg + sizeof mesg - 2; /* one byte from last pos. in mesg */
4737c478bd9Sstevel@tonic-gate
4747c478bd9Sstevel@tonic-gate setupline(); /* configure the communications line */
4757c478bd9Sstevel@tonic-gate setupstdin(0); /* save current stdin term settings */
4767c478bd9Sstevel@tonic-gate
4777c478bd9Sstevel@tonic-gate }
4787c478bd9Sstevel@tonic-gate
4797c478bd9Sstevel@tonic-gate static void
initialize_parallel(void)4807c478bd9Sstevel@tonic-gate initialize_parallel(void)
4817c478bd9Sstevel@tonic-gate {
4827c478bd9Sstevel@tonic-gate if ((block = malloc(blocksize)) == NULL)
4837c478bd9Sstevel@tonic-gate error(FATAL, "no memory");
4847c478bd9Sstevel@tonic-gate }
4857c478bd9Sstevel@tonic-gate
4867c478bd9Sstevel@tonic-gate
4877c478bd9Sstevel@tonic-gate /*
4887c478bd9Sstevel@tonic-gate * Tries to put the printer in the IDLE state before anything important is sent.
4897c478bd9Sstevel@tonic-gate * Run as a single process no matter what has been assigned to splitme. Separate
4907c478bd9Sstevel@tonic-gate * read and write processes, if requested, will be created after we're done
4917c478bd9Sstevel@tonic-gate * here.
4927c478bd9Sstevel@tonic-gate */
4937c478bd9Sstevel@tonic-gate
4947c478bd9Sstevel@tonic-gate static void
start(void)4957c478bd9Sstevel@tonic-gate start(void)
4967c478bd9Sstevel@tonic-gate {
4977c478bd9Sstevel@tonic-gate int longwait = 0;
4987c478bd9Sstevel@tonic-gate
4997c478bd9Sstevel@tonic-gate logit("printer startup\n");
5007c478bd9Sstevel@tonic-gate
5017c478bd9Sstevel@tonic-gate currentstate = START;
5027c478bd9Sstevel@tonic-gate clearline();
5037c478bd9Sstevel@tonic-gate
5047c478bd9Sstevel@tonic-gate for (;;)
5057c478bd9Sstevel@tonic-gate switch (getstatus(1)) {
5067c478bd9Sstevel@tonic-gate
5077c478bd9Sstevel@tonic-gate case IDLE:
5087c478bd9Sstevel@tonic-gate case INTERACTIVE:
5097c478bd9Sstevel@tonic-gate if (postbegin != NULL && *postbegin != '\0')
5107c478bd9Sstevel@tonic-gate Write(ttyo, postbegin, strlen(postbegin));
5117c478bd9Sstevel@tonic-gate clearline();
5127c478bd9Sstevel@tonic-gate return;
5137c478bd9Sstevel@tonic-gate
5147c478bd9Sstevel@tonic-gate case BUSY:
5157c478bd9Sstevel@tonic-gate Write(ttyo, "\003", 1);
5167c478bd9Sstevel@tonic-gate Rest(1);
5177c478bd9Sstevel@tonic-gate break;
5187c478bd9Sstevel@tonic-gate
5197c478bd9Sstevel@tonic-gate /* 03/24/95 - bob golden
5207c478bd9Sstevel@tonic-gate * The HP LJ3 starts in waiting mode and needs the EOF to move
5217c478bd9Sstevel@tonic-gate * from waiting to idle. To see what would happen, code was added
5227c478bd9Sstevel@tonic-gate * to send the INTR on waiting and later changed to INTR/EOF.
5237c478bd9Sstevel@tonic-gate * The INTR by itself had no effect. The INTR/EOF put the
5247c478bd9Sstevel@tonic-gate * the printer in a busy status loop from which the only
5257c478bd9Sstevel@tonic-gate * recovery was to reset the printer. Until further testing
5267c478bd9Sstevel@tonic-gate * testing is done, do not send an INTR to a HPLJ3 in waiting
5277c478bd9Sstevel@tonic-gate * state. WAITING moved to a separate case to eliminate the
5287c478bd9Sstevel@tonic-gate * INTR write.
5297c478bd9Sstevel@tonic-gate */
5307c478bd9Sstevel@tonic-gate case WAITING:
5317c478bd9Sstevel@tonic-gate Write(ttyo, "\004", 1);
5327c478bd9Sstevel@tonic-gate Rest(1);
5337c478bd9Sstevel@tonic-gate break;
5347c478bd9Sstevel@tonic-gate
5357c478bd9Sstevel@tonic-gate /* 03/24/95 - bob golden
5367c478bd9Sstevel@tonic-gate * The HP LJ3 seems to process INTR at later times. All the
5377c478bd9Sstevel@tonic-gate * longwaits are increaased to reduce the number of INTRs sent.
5387c478bd9Sstevel@tonic-gate */
5397c478bd9Sstevel@tonic-gate case ERROR:
5407c478bd9Sstevel@tonic-gate case FLUSHING:
5417c478bd9Sstevel@tonic-gate Write(ttyo, "\004", 1);
5427c478bd9Sstevel@tonic-gate if (longwait++ == 5) {
5437c478bd9Sstevel@tonic-gate Write(ttyo, "\003", 1);
5447c478bd9Sstevel@tonic-gate Rest(5);
5457c478bd9Sstevel@tonic-gate longwait = 0;
5467c478bd9Sstevel@tonic-gate }
5477c478bd9Sstevel@tonic-gate Rest(1);
5487c478bd9Sstevel@tonic-gate break;
5497c478bd9Sstevel@tonic-gate
5507c478bd9Sstevel@tonic-gate case PRINTERERROR:
5517c478bd9Sstevel@tonic-gate Rest(15);
5527c478bd9Sstevel@tonic-gate break;
5537c478bd9Sstevel@tonic-gate
5547c478bd9Sstevel@tonic-gate case DISCONNECT:
5557c478bd9Sstevel@tonic-gate error(FATAL, "Disconnected - printer may be offline");
5567c478bd9Sstevel@tonic-gate break;
5577c478bd9Sstevel@tonic-gate
5587c478bd9Sstevel@tonic-gate /* 03/24/95 - bob golden
5597c478bd9Sstevel@tonic-gate * The ENDJOB case has been removed. The HP LJ3 echoes all EOFs
5607c478bd9Sstevel@tonic-gate * sent so the ENDJOB has no real meaning.
5617c478bd9Sstevel@tonic-gate */
5627c478bd9Sstevel@tonic-gate case UNKNOWN:
5637c478bd9Sstevel@tonic-gate clearline();
5647c478bd9Sstevel@tonic-gate break;
5657c478bd9Sstevel@tonic-gate
5667c478bd9Sstevel@tonic-gate default:
5677c478bd9Sstevel@tonic-gate Rest(1);
5687c478bd9Sstevel@tonic-gate break;
5697c478bd9Sstevel@tonic-gate
5707c478bd9Sstevel@tonic-gate } /* End switch */
5717c478bd9Sstevel@tonic-gate
5727c478bd9Sstevel@tonic-gate } /* End of start */
5737c478bd9Sstevel@tonic-gate
5747c478bd9Sstevel@tonic-gate
5757c478bd9Sstevel@tonic-gate /*
5767c478bd9Sstevel@tonic-gate *
5777c478bd9Sstevel@tonic-gate * If splitme is TRUE we fork a process, make the parent handle reading, and let
5787c478bd9Sstevel@tonic-gate * the child take care of writing. resetline() (file ifdef.c) contains all the
5797c478bd9Sstevel@tonic-gate * system dependent code needed to reset the communications line for separate
5807c478bd9Sstevel@tonic-gate * read and write processes. For now it's expected to return TRUE or FALSE and
5817c478bd9Sstevel@tonic-gate * that value controls whether we try the fork. I've only tested the two process
5827c478bd9Sstevel@tonic-gate * stuff for System V. Other versions of resetline() may just be dummy
5837c478bd9Sstevel@tonic-gate * procedures that always return FALSE. If the fork() failed previous versions
5847c478bd9Sstevel@tonic-gate * continued as a single process, although the implementation wasn't quite
5857c478bd9Sstevel@tonic-gate * right, but I've now decided to quit. The main reason is a Datakit channel
5867c478bd9Sstevel@tonic-gate * may be configured to flow control data in both directions, and if we run
5877c478bd9Sstevel@tonic-gate * postio over that channel as a single process we likely will end up in
5887c478bd9Sstevel@tonic-gate * deadlock.
5897c478bd9Sstevel@tonic-gate */
5907c478bd9Sstevel@tonic-gate
5917c478bd9Sstevel@tonic-gate static void
split(void)5927c478bd9Sstevel@tonic-gate split(void)
5937c478bd9Sstevel@tonic-gate {
5947c478bd9Sstevel@tonic-gate int pid;
5957c478bd9Sstevel@tonic-gate
5967c478bd9Sstevel@tonic-gate if (splitme == TRUE)
5977c478bd9Sstevel@tonic-gate if (resetline() == TRUE) {
5987c478bd9Sstevel@tonic-gate pid = getpid();
5997c478bd9Sstevel@tonic-gate signal(joinsig, interrupt);
6007c478bd9Sstevel@tonic-gate if ((otherpid = fork()) == -1)
6017c478bd9Sstevel@tonic-gate error(FATAL, "can't fork");
6027c478bd9Sstevel@tonic-gate else if (otherpid == 0) {
6037c478bd9Sstevel@tonic-gate whatami = WRITE;
6047c478bd9Sstevel@tonic-gate nostatus = WRITEPROCESS;
6057c478bd9Sstevel@tonic-gate otherpid = pid;
6067c478bd9Sstevel@tonic-gate setupstdin(1);
6077c478bd9Sstevel@tonic-gate } else
6087c478bd9Sstevel@tonic-gate whatami = READ;
6097c478bd9Sstevel@tonic-gate } else if (interactive == TRUE || tostdout == TRUE)
6107c478bd9Sstevel@tonic-gate error(FATAL,
6117c478bd9Sstevel@tonic-gate "can't create two process - check resetline()");
6127c478bd9Sstevel@tonic-gate else
6137c478bd9Sstevel@tonic-gate error(NON_FATAL,
6147c478bd9Sstevel@tonic-gate "running as a single process - check resetline()");
6157c478bd9Sstevel@tonic-gate
6167c478bd9Sstevel@tonic-gate canread = (whatami & READ) ? TRUE : FALSE;
6177c478bd9Sstevel@tonic-gate canwrite = (whatami & WRITE) ? TRUE : FALSE;
6187c478bd9Sstevel@tonic-gate }
6197c478bd9Sstevel@tonic-gate
6207c478bd9Sstevel@tonic-gate
6217c478bd9Sstevel@tonic-gate /*
6227c478bd9Sstevel@tonic-gate * Makes sure all the non-option command line arguments are processed. If there
6237c478bd9Sstevel@tonic-gate * aren't any arguments left when we get here we'll send stdin. Input files are
6247c478bd9Sstevel@tonic-gate * only read and sent to the printer if canwrite is TRUE. Checking it here means
6257c478bd9Sstevel@tonic-gate * we won't have to do it in send(). If interactive mode is TRUE we'll stay here
6267c478bd9Sstevel@tonic-gate * forever sending stdin when we run out of files - exit with a break. Actually
6277c478bd9Sstevel@tonic-gate * the loop is bogus and used at most once when we're in interactive mode
6287c478bd9Sstevel@tonic-gate * because stdin is in a pseudo raw mode and the read() in readblock() should
6297c478bd9Sstevel@tonic-gate * never see the end of file.
6307c478bd9Sstevel@tonic-gate */
6317c478bd9Sstevel@tonic-gate
6327c478bd9Sstevel@tonic-gate static void
arguments(void)6337c478bd9Sstevel@tonic-gate arguments(void)
6347c478bd9Sstevel@tonic-gate {
6357c478bd9Sstevel@tonic-gate int fd_in; /* next input file */
6367c478bd9Sstevel@tonic-gate
6377c478bd9Sstevel@tonic-gate if (canwrite == TRUE)
6387c478bd9Sstevel@tonic-gate do /* loop is for interactive mode */
6397c478bd9Sstevel@tonic-gate if (argc < 1)
6407c478bd9Sstevel@tonic-gate send(fileno(stdin), "pipe.end");
6417c478bd9Sstevel@tonic-gate else {
6427c478bd9Sstevel@tonic-gate while (argc > 0) {
6437c478bd9Sstevel@tonic-gate if ((fd_in = open(*argv, O_RDONLY)) == -1)
6447c478bd9Sstevel@tonic-gate error(FATAL, "can't open %s", *argv);
6457c478bd9Sstevel@tonic-gate send(fd_in, *argv);
6467c478bd9Sstevel@tonic-gate close(fd_in);
6477c478bd9Sstevel@tonic-gate argc--;
6487c478bd9Sstevel@tonic-gate argv++;
6497c478bd9Sstevel@tonic-gate }
6507c478bd9Sstevel@tonic-gate }
6517c478bd9Sstevel@tonic-gate while (interactive == TRUE);
6527c478bd9Sstevel@tonic-gate }
6537c478bd9Sstevel@tonic-gate
6547c478bd9Sstevel@tonic-gate /*
6557c478bd9Sstevel@tonic-gate * Sends file *name to the printer. There's nothing left here that depends on
6567c478bd9Sstevel@tonic-gate * sending and receiving status reports, although it can be reassuring to know
6577c478bd9Sstevel@tonic-gate * the printer is responding and processing our job. Only the writer gets here
6587c478bd9Sstevel@tonic-gate * in the two process implementation, and in that case split() has reset
6597c478bd9Sstevel@tonic-gate * nostatus to WRITEPROCESS and that's what getstatus() always returns. For
6607c478bd9Sstevel@tonic-gate * now we accept the IDLE state and ENDOFJOB as legitimate and ignore the
6617c478bd9Sstevel@tonic-gate * INITIALIZING state.
6627c478bd9Sstevel@tonic-gate *
6637c478bd9Sstevel@tonic-gate * fd_in next input file
6647c478bd9Sstevel@tonic-gate * name it's pathname
6657c478bd9Sstevel@tonic-gate */
6667c478bd9Sstevel@tonic-gate
6677c478bd9Sstevel@tonic-gate static void
send(int fd_in,char * name)6687c478bd9Sstevel@tonic-gate send(int fd_in, char *name)
6697c478bd9Sstevel@tonic-gate {
6707c478bd9Sstevel@tonic-gate if (interactive == FALSE)
6717c478bd9Sstevel@tonic-gate logit("sending file %s\n", name);
6727c478bd9Sstevel@tonic-gate
6737c478bd9Sstevel@tonic-gate currentstate = SEND;
6747c478bd9Sstevel@tonic-gate
6757c478bd9Sstevel@tonic-gate if (useslowsend == TRUE) {
6767c478bd9Sstevel@tonic-gate slowsend(fd_in);
6777c478bd9Sstevel@tonic-gate return;
6787c478bd9Sstevel@tonic-gate }
6797c478bd9Sstevel@tonic-gate
6807c478bd9Sstevel@tonic-gate while (readblock(fd_in))
6817c478bd9Sstevel@tonic-gate
6827c478bd9Sstevel@tonic-gate switch (getstatus(0)) {
6837c478bd9Sstevel@tonic-gate
6847c478bd9Sstevel@tonic-gate case IDLE:
6857c478bd9Sstevel@tonic-gate case BUSY:
6867c478bd9Sstevel@tonic-gate case WAITING:
6877c478bd9Sstevel@tonic-gate case PRINTING:
6887c478bd9Sstevel@tonic-gate case ENDOFJOB:
6897c478bd9Sstevel@tonic-gate case PRINTERERROR:
6907c478bd9Sstevel@tonic-gate case UNKNOWN:
6917c478bd9Sstevel@tonic-gate case NOSTATUS:
6927c478bd9Sstevel@tonic-gate case WRITEPROCESS:
6937c478bd9Sstevel@tonic-gate case INTERACTIVE:
6947c478bd9Sstevel@tonic-gate writeblock();
6957c478bd9Sstevel@tonic-gate break;
6967c478bd9Sstevel@tonic-gate
6977c478bd9Sstevel@tonic-gate case ERROR:
6987c478bd9Sstevel@tonic-gate fprintf(stderr, "%s", mesg); /* for csw */
6997c478bd9Sstevel@tonic-gate error(USER_FATAL, "PostScript Error");
7007c478bd9Sstevel@tonic-gate break;
7017c478bd9Sstevel@tonic-gate
7027c478bd9Sstevel@tonic-gate case FLUSHING:
7037c478bd9Sstevel@tonic-gate error(USER_FATAL, "Flushing Job");
7047c478bd9Sstevel@tonic-gate break;
7057c478bd9Sstevel@tonic-gate
7067c478bd9Sstevel@tonic-gate case DISCONNECT:
7077c478bd9Sstevel@tonic-gate error(FATAL, "Disconnected - printer may be offline");
7087c478bd9Sstevel@tonic-gate break;
7097c478bd9Sstevel@tonic-gate
7107c478bd9Sstevel@tonic-gate }
7117c478bd9Sstevel@tonic-gate
7127c478bd9Sstevel@tonic-gate }
7137c478bd9Sstevel@tonic-gate
7147c478bd9Sstevel@tonic-gate
7157c478bd9Sstevel@tonic-gate /*
7167c478bd9Sstevel@tonic-gate * Tries to stay connected to the printer until we're reasonably sure the job is
7177c478bd9Sstevel@tonic-gate * complete. It's the only way we can recover error messages or data generated
7187c478bd9Sstevel@tonic-gate * by the PostScript program and returned over the communication line. Actually
7197c478bd9Sstevel@tonic-gate * doing it correctly for all possible PostScript jobs is more difficult that it
7207c478bd9Sstevel@tonic-gate * might seem. For example if we've sent several jobs, each with their own EOF
7217c478bd9Sstevel@tonic-gate * mark, then waiting for ENDOFJOB won't guarantee all the jobs have completed.
7227c478bd9Sstevel@tonic-gate * Even waiting for IDLE isn't good enough. Checking for the WAITING state after
7237c478bd9Sstevel@tonic-gate * all the files have been sent and then sending an EOF may be the best
7247c478bd9Sstevel@tonic-gate * approach, but even that won't work all the time - we could miss it or might
7257c478bd9Sstevel@tonic-gate * not get there. Even sending our own special PostScript job after all the
7267c478bd9Sstevel@tonic-gate * input files has it's own different set of problems, but probably could work
7277c478bd9Sstevel@tonic-gate * (perhaps by printing a fake status message or just not timing out). Anyway
7287c478bd9Sstevel@tonic-gate * it's probably not worth the trouble so for now we'll quit if writedone is
7297c478bd9Sstevel@tonic-gate * TRUE and we get ENDOFJOB or IDLE.
7307c478bd9Sstevel@tonic-gate *
7317c478bd9Sstevel@tonic-gate * If we're running separate read and write processes the reader gets here after
7327c478bd9Sstevel@tonic-gate * after split() while the writer goes to send() and only gets here after all
7337c478bd9Sstevel@tonic-gate * the input files have been transmitted. When they're both here the writer
7347c478bd9Sstevel@tonic-gate * sends the reader signal joinsig and that forces writedone to TRUE in the
7357c478bd9Sstevel@tonic-gate * reader. At that point the reader can begin looking for an indication of the
7367c478bd9Sstevel@tonic-gate * end of the job. The writer hangs around until the reader kills it (usually
7377c478bd9Sstevel@tonic-gate * in cleanup()) sending occasional status requests.
7387c478bd9Sstevel@tonic-gate */
7397c478bd9Sstevel@tonic-gate
7407c478bd9Sstevel@tonic-gate static void
done(void)7417c478bd9Sstevel@tonic-gate done(void)
7427c478bd9Sstevel@tonic-gate {
7437c478bd9Sstevel@tonic-gate int sleeptime = 15; /* for 'out of paper' etc. */
7447c478bd9Sstevel@tonic-gate int longwait = 0;
7457c478bd9Sstevel@tonic-gate
7467c478bd9Sstevel@tonic-gate if (canwrite == TRUE)
7477c478bd9Sstevel@tonic-gate logit("waiting for end of job\n");
7487c478bd9Sstevel@tonic-gate
7497c478bd9Sstevel@tonic-gate currentstate = DONE;
7507c478bd9Sstevel@tonic-gate writedone = (whatami == READWRITE) ? TRUE : FALSE;
7517c478bd9Sstevel@tonic-gate
7527c478bd9Sstevel@tonic-gate for (;;) {
7537c478bd9Sstevel@tonic-gate
7547c478bd9Sstevel@tonic-gate switch (getstatus(1)) {
7557c478bd9Sstevel@tonic-gate case WRITEPROCESS:
7567c478bd9Sstevel@tonic-gate if (writedone == FALSE) {
7577c478bd9Sstevel@tonic-gate sendsignal(joinsig);
7587c478bd9Sstevel@tonic-gate Write(ttyo, "\004", 1);
7597c478bd9Sstevel@tonic-gate writedone = TRUE;
7607c478bd9Sstevel@tonic-gate sleeptime = 1;
7617c478bd9Sstevel@tonic-gate }
7627c478bd9Sstevel@tonic-gate Rest(sleeptime++);
7637c478bd9Sstevel@tonic-gate break;
7647c478bd9Sstevel@tonic-gate
7657c478bd9Sstevel@tonic-gate /* 03/24/95 - bob golden
7667c478bd9Sstevel@tonic-gate * For the HP LJ3 INTR sent while in the waiting state have
7677c478bd9Sstevel@tonic-gate * either had no effect or put the printer into a unrecoverable
7687c478bd9Sstevel@tonic-gate * loop. Further testing may reveal this to not be the case
7697c478bd9Sstevel@tonic-gate * but for now, remove the send INTR.
7707c478bd9Sstevel@tonic-gate */
7717c478bd9Sstevel@tonic-gate case WAITING:
7727c478bd9Sstevel@tonic-gate Write(ttyo, "\004", 1);
7737c478bd9Sstevel@tonic-gate Rest(1);
7747c478bd9Sstevel@tonic-gate sleeptime = 15;
7757c478bd9Sstevel@tonic-gate break;
7767c478bd9Sstevel@tonic-gate
7777c478bd9Sstevel@tonic-gate /* 03/24/95 - bob golden
7787c478bd9Sstevel@tonic-gate * ENDOFJOB case removed here. The HP LJ 3 echoes all EOFs sent so
7797c478bd9Sstevel@tonic-gate * the ENDOFJOB case is meaningless.
7807c478bd9Sstevel@tonic-gate */
7817c478bd9Sstevel@tonic-gate case IDLE:
7827c478bd9Sstevel@tonic-gate if (writedone == TRUE) {
7837c478bd9Sstevel@tonic-gate logit("job complete\n");
7847c478bd9Sstevel@tonic-gate return;
7857c478bd9Sstevel@tonic-gate }
7867c478bd9Sstevel@tonic-gate break;
7877c478bd9Sstevel@tonic-gate
7887c478bd9Sstevel@tonic-gate /* 03/24/95 - bob golden
7897c478bd9Sstevel@tonic-gate * During print data transmission, the HP LJ3 stays in
7907c478bd9Sstevel@tonic-gate * status busy. So give it a rest.
791*2a8bcb4eSToomas Soome *
7927c478bd9Sstevel@tonic-gate */
7937c478bd9Sstevel@tonic-gate case BUSY:
7947c478bd9Sstevel@tonic-gate case PRINTING:
7957c478bd9Sstevel@tonic-gate Rest(1);
7967c478bd9Sstevel@tonic-gate sleeptime = 15;
7977c478bd9Sstevel@tonic-gate break;
7987c478bd9Sstevel@tonic-gate
7997c478bd9Sstevel@tonic-gate case INTERACTIVE:
8007c478bd9Sstevel@tonic-gate Write(ttyo, "\004", 1);
8017c478bd9Sstevel@tonic-gate sleeptime = 15;
8027c478bd9Sstevel@tonic-gate break;
8037c478bd9Sstevel@tonic-gate
8047c478bd9Sstevel@tonic-gate case PRINTERERROR:
8057c478bd9Sstevel@tonic-gate Rest(sleeptime++);
8067c478bd9Sstevel@tonic-gate break;
8077c478bd9Sstevel@tonic-gate
8087c478bd9Sstevel@tonic-gate case ERROR:
8097c478bd9Sstevel@tonic-gate Write(ttyo, "\004", 1);
8107c478bd9Sstevel@tonic-gate fprintf(stderr, "%s", mesg); /* for csw */
8117c478bd9Sstevel@tonic-gate error(USER_FATAL, "PostScript Error");
8127c478bd9Sstevel@tonic-gate return;
8137c478bd9Sstevel@tonic-gate
8147c478bd9Sstevel@tonic-gate case FLUSHING:
8157c478bd9Sstevel@tonic-gate Write(ttyo, "\004", 1);
8167c478bd9Sstevel@tonic-gate error(USER_FATAL, "Flushing Job");
8177c478bd9Sstevel@tonic-gate return;
8187c478bd9Sstevel@tonic-gate
8197c478bd9Sstevel@tonic-gate case DISCONNECT:
8207c478bd9Sstevel@tonic-gate error(FATAL, "Disconnected - printer may be offline");
8217c478bd9Sstevel@tonic-gate return;
8227c478bd9Sstevel@tonic-gate
8237c478bd9Sstevel@tonic-gate /* 03/24/95 - bob golden
8247c478bd9Sstevel@tonic-gate * These cases are ignored without a EOF being sent
8257c478bd9Sstevel@tonic-gate */
8267c478bd9Sstevel@tonic-gate case ENDOFJOB:
8277c478bd9Sstevel@tonic-gate case NOSTATUS:
8287c478bd9Sstevel@tonic-gate Rest(1);
8297c478bd9Sstevel@tonic-gate break;
8307c478bd9Sstevel@tonic-gate
8317c478bd9Sstevel@tonic-gate default:
8327c478bd9Sstevel@tonic-gate Write(ttyo, "\004", 1);
8337c478bd9Sstevel@tonic-gate Rest(1);
8347c478bd9Sstevel@tonic-gate break;
8357c478bd9Sstevel@tonic-gate
8367c478bd9Sstevel@tonic-gate }
8377c478bd9Sstevel@tonic-gate
8387c478bd9Sstevel@tonic-gate if (sleeptime > 60)
8397c478bd9Sstevel@tonic-gate sleeptime = 60;
8407c478bd9Sstevel@tonic-gate
8417c478bd9Sstevel@tonic-gate }
8427c478bd9Sstevel@tonic-gate
8437c478bd9Sstevel@tonic-gate }
8447c478bd9Sstevel@tonic-gate
8457c478bd9Sstevel@tonic-gate
8467c478bd9Sstevel@tonic-gate /*
8477c478bd9Sstevel@tonic-gate * Only needed if we're running separate read and write processes. Makes sure
8487c478bd9Sstevel@tonic-gate * the write process is killed after the read process has successfully finished
8497c478bd9Sstevel@tonic-gate * with all the jobs. sendsignal() returns a -1 if there's nobody to signal so
8507c478bd9Sstevel@tonic-gate * things work when we're running a single process.
8517c478bd9Sstevel@tonic-gate */
8527c478bd9Sstevel@tonic-gate
8537c478bd9Sstevel@tonic-gate static void
cleanup(void)8547c478bd9Sstevel@tonic-gate cleanup(void)
8557c478bd9Sstevel@tonic-gate {
8567c478bd9Sstevel@tonic-gate int w;
8577c478bd9Sstevel@tonic-gate
8587c478bd9Sstevel@tonic-gate while (sendsignal(SIGKILL) != -1 && (w = wait((int *)0)) != otherpid &&
8597c478bd9Sstevel@tonic-gate w != -1);
8607c478bd9Sstevel@tonic-gate if ( currentstate != NOTCONNECTED )
8617c478bd9Sstevel@tonic-gate Write(ttyo, "\004", 1);
8627c478bd9Sstevel@tonic-gate }
8637c478bd9Sstevel@tonic-gate
8647c478bd9Sstevel@tonic-gate
8657c478bd9Sstevel@tonic-gate /*
8667c478bd9Sstevel@tonic-gate * Fills the input buffer with the next block, provided we're all done with the
8677c478bd9Sstevel@tonic-gate * last one. Blocks from fd_in are stored in array block[]. head is the index
8687c478bd9Sstevel@tonic-gate * of the next byte in block[] that's supposed to go to the printer. tail points
8697c478bd9Sstevel@tonic-gate * one past the last byte in the current block. head is adjusted in writeblock()
8707c478bd9Sstevel@tonic-gate * after each successful write, while head and tail are reset here each time
8717c478bd9Sstevel@tonic-gate * a new block is read. Returns the number of bytes left in the current block.
8727c478bd9Sstevel@tonic-gate * Read errors cause the program to abort. The fake status message that's put
8737c478bd9Sstevel@tonic-gate * out in quiet mode is only so you can look at the log file and know
8747c478bd9Sstevel@tonic-gate * something's happening - take it out if you want.
8757c478bd9Sstevel@tonic-gate */
8767c478bd9Sstevel@tonic-gate
8777c478bd9Sstevel@tonic-gate int
readblock(int fd_in)8787c478bd9Sstevel@tonic-gate readblock(int fd_in)
8797c478bd9Sstevel@tonic-gate {
8807c478bd9Sstevel@tonic-gate static long blocknum = 1;
8817c478bd9Sstevel@tonic-gate
8827c478bd9Sstevel@tonic-gate if (head >= tail) { /* done with the last block */
8837c478bd9Sstevel@tonic-gate if ((tail = read(fd_in, block, blocksize)) == -1)
8847c478bd9Sstevel@tonic-gate error(FATAL, "error reading input file");
8857c478bd9Sstevel@tonic-gate if (quiet == TRUE && tail > 0) /* put out a fake message? */
8867c478bd9Sstevel@tonic-gate logit("%%%%[ status: busy; block: %d ]%%%%\n", blocknum++);
8877c478bd9Sstevel@tonic-gate head = 0;
8887c478bd9Sstevel@tonic-gate }
8897c478bd9Sstevel@tonic-gate
8907c478bd9Sstevel@tonic-gate return (tail - head);
8917c478bd9Sstevel@tonic-gate
8927c478bd9Sstevel@tonic-gate }
8937c478bd9Sstevel@tonic-gate
8947c478bd9Sstevel@tonic-gate
8957c478bd9Sstevel@tonic-gate /*
8967c478bd9Sstevel@tonic-gate * Called from send() when it's OK to send the next block to the printer. head
8977c478bd9Sstevel@tonic-gate * is adjusted after the write, and the number of bytes that were successfully
8987c478bd9Sstevel@tonic-gate * written is returned to the caller.
8997c478bd9Sstevel@tonic-gate */
9007c478bd9Sstevel@tonic-gate
9017c478bd9Sstevel@tonic-gate static int
writeblock(void)9027c478bd9Sstevel@tonic-gate writeblock(void)
9037c478bd9Sstevel@tonic-gate {
9047c478bd9Sstevel@tonic-gate int count; /* bytes successfully written */
9057c478bd9Sstevel@tonic-gate
9067c478bd9Sstevel@tonic-gate if ((count = write(ttyo, &block[head], tail - head)) == -1)
9077c478bd9Sstevel@tonic-gate error(FATAL, "error writing to %s", line);
9087c478bd9Sstevel@tonic-gate else if (count == 0)
9097c478bd9Sstevel@tonic-gate error(FATAL, "printer appears to be offline");
9107c478bd9Sstevel@tonic-gate
9117c478bd9Sstevel@tonic-gate head += count;
9127c478bd9Sstevel@tonic-gate return (count);
9137c478bd9Sstevel@tonic-gate
9147c478bd9Sstevel@tonic-gate }
9157c478bd9Sstevel@tonic-gate
9167c478bd9Sstevel@tonic-gate
9177c478bd9Sstevel@tonic-gate /*
9187c478bd9Sstevel@tonic-gate * Looks for things coming back from the printer on the communications line,
9197c478bd9Sstevel@tonic-gate * parses complete lines retrieved by readline(), and returns an integer
9207c478bd9Sstevel@tonic-gate * representation of the current printer status to the caller. If nothing was
9217c478bd9Sstevel@tonic-gate * available a status request (control T) is sent to the printer and nostatus
9227c478bd9Sstevel@tonic-gate * is returned to the caller (provided quiet isn't TRUE). Interactive mode
9237c478bd9Sstevel@tonic-gate * either never returns from readline() or returns FALSE.
9247c478bd9Sstevel@tonic-gate */
9257c478bd9Sstevel@tonic-gate
9267c478bd9Sstevel@tonic-gate int
getstatus(int t)9277c478bd9Sstevel@tonic-gate getstatus(int t) /* sleep time after sending '\024' */
9287c478bd9Sstevel@tonic-gate {
9297c478bd9Sstevel@tonic-gate int state = nostatus; /* the current state */
9307c478bd9Sstevel@tonic-gate static int laststate = NOSTATUS; /* last state recognized */
9317c478bd9Sstevel@tonic-gate
9327c478bd9Sstevel@tonic-gate
9337c478bd9Sstevel@tonic-gate if (canread == TRUE && readline() == TRUE) {
9347c478bd9Sstevel@tonic-gate state = parsemesg();
9357c478bd9Sstevel@tonic-gate if (state != laststate || mesgptr != mesg || debug == ON)
9367c478bd9Sstevel@tonic-gate logit("%s", mesg);
9377c478bd9Sstevel@tonic-gate
9387c478bd9Sstevel@tonic-gate if (tostdout == TRUE && currentstate != START) {
9397c478bd9Sstevel@tonic-gate *mesgptr = '\0';
9407c478bd9Sstevel@tonic-gate fprintf(stdout, "%s", mesg);
9417c478bd9Sstevel@tonic-gate }
9427c478bd9Sstevel@tonic-gate return (laststate = state);
9437c478bd9Sstevel@tonic-gate }
9447c478bd9Sstevel@tonic-gate
9457c478bd9Sstevel@tonic-gate if ((quiet == FALSE || currentstate != SEND) && interactive == FALSE) {
9467c478bd9Sstevel@tonic-gate if (Write(ttyo, "\024", 1) != 1)
9477c478bd9Sstevel@tonic-gate error(FATAL, "printer appears to be offline");
9487c478bd9Sstevel@tonic-gate if (t > 0) Rest(t);
9497c478bd9Sstevel@tonic-gate }
9507c478bd9Sstevel@tonic-gate
9517c478bd9Sstevel@tonic-gate return (nostatus);
9527c478bd9Sstevel@tonic-gate }
9537c478bd9Sstevel@tonic-gate
9547c478bd9Sstevel@tonic-gate
9557c478bd9Sstevel@tonic-gate /*
9567c478bd9Sstevel@tonic-gate *
9577c478bd9Sstevel@tonic-gate * Parsing the lines that readline() stores in mesg[] is messy, and what's done
9587c478bd9Sstevel@tonic-gate * here isn't completely correct nor as fast as it could be. The general format
9597c478bd9Sstevel@tonic-gate * of lines that come back from the printer (assuming no data loss) is:
9607c478bd9Sstevel@tonic-gate *
9617c478bd9Sstevel@tonic-gate * str%%[ key: val; key: val; key: val ]%%\n
9627c478bd9Sstevel@tonic-gate *
9637c478bd9Sstevel@tonic-gate * where str can be most anything not containing a newline and printer reports
9647c478bd9Sstevel@tonic-gate * (eg. status or error messages) are bracketed by "%%[ " and " ]%%" strings and
9657c478bd9Sstevel@tonic-gate * end with a newline. Usually we'll have the string or printer report but not
9667c478bd9Sstevel@tonic-gate * both. For most jobs the leading string will be empty, but could be anything
9677c478bd9Sstevel@tonic-gate * generated on a printer and returned over the communications line using the
9687c478bd9Sstevel@tonic-gate * PostScript print operator. I'll assume PostScript jobs are well behaved and
9697c478bd9Sstevel@tonic-gate * never bracket their messages with "%%[ " and " ]%%" strings that delimit
9707c478bd9Sstevel@tonic-gate * status or error messages.
9717c478bd9Sstevel@tonic-gate *
9727c478bd9Sstevel@tonic-gate * Printer reports consist of one or more key/val pairs, and what we're
9737c478bd9Sstevel@tonic-gate * interested in (status or error indications) may not be the first pair in the
9747c478bd9Sstevel@tonic-gate * list. In addition we'll sometimes want the value associated with a keyword
9757c478bd9Sstevel@tonic-gate * (eg. when key = status) and other times we'll want the keyword (eg. when
9767c478bd9Sstevel@tonic-gate * key = Error or Flushing). The last pair isn't terminated by a semicolon and
9777c478bd9Sstevel@tonic-gate * a value string often contains many space separated words and it can even
9787c478bd9Sstevel@tonic-gate * include colons in meaningful places. I've also decided to continue
9797c478bd9Sstevel@tonic-gate * converting things to lower case before doing the lookup in status[]. The
9807c478bd9Sstevel@tonic-gate * isupper() test is for Berkeley systems.
9817c478bd9Sstevel@tonic-gate */
9827c478bd9Sstevel@tonic-gate
9837c478bd9Sstevel@tonic-gate static int
parsemesg(void)9847c478bd9Sstevel@tonic-gate parsemesg(void)
9857c478bd9Sstevel@tonic-gate {
9867c478bd9Sstevel@tonic-gate char *e; /* end of printer message in mesg[] */
9877c478bd9Sstevel@tonic-gate char *key, *val; /* keyword/value strings in sbuf[] */
9887c478bd9Sstevel@tonic-gate char *p; /* for converting to lower case etc. */
9897c478bd9Sstevel@tonic-gate int i; /* where *key was found in status[] */
9907c478bd9Sstevel@tonic-gate
9917c478bd9Sstevel@tonic-gate if (*(mesgptr = find("%%[ ", mesg)) != '\0' &&
9927c478bd9Sstevel@tonic-gate *(e = find(" ]%%", mesgptr+4)) != '\0') {
9937c478bd9Sstevel@tonic-gate
9947c478bd9Sstevel@tonic-gate strcpy(sbuf, mesgptr+4); /* don't change mesg[] */
9957c478bd9Sstevel@tonic-gate sbuf[e-mesgptr-4] = '\0'; /* ignore the trailing " ]%%" */
9967c478bd9Sstevel@tonic-gate
9977c478bd9Sstevel@tonic-gate for (key = strtok(sbuf, " :"); key != NULL;
9987c478bd9Sstevel@tonic-gate key = strtok(NULL, " :")) {
9997c478bd9Sstevel@tonic-gate if ((val = strtok(NULL, ";")) != NULL &&
10007c478bd9Sstevel@tonic-gate strcmp(key, "status") == 0)
10017c478bd9Sstevel@tonic-gate key = val;
10027c478bd9Sstevel@tonic-gate
10037c478bd9Sstevel@tonic-gate for (; *key == ' '; key++); /* skip leading space */
10047c478bd9Sstevel@tonic-gate for (p = key; *p; p++) /* conv to lower case */
10057c478bd9Sstevel@tonic-gate if (*p == ':' || *p == ',') {
10067c478bd9Sstevel@tonic-gate *p = '\0';
10077c478bd9Sstevel@tonic-gate break;
10087c478bd9Sstevel@tonic-gate } else if (isupper(*p))
10097c478bd9Sstevel@tonic-gate *p = tolower(*p);
10107c478bd9Sstevel@tonic-gate
10117c478bd9Sstevel@tonic-gate for (i = 0; status[i].state != NULL; i++)
10127c478bd9Sstevel@tonic-gate if (strcmp(status[i].state, key) == 0)
10137c478bd9Sstevel@tonic-gate return (status[i].val);
10147c478bd9Sstevel@tonic-gate }
10157c478bd9Sstevel@tonic-gate } else if (strcmp(mesg, "CONVERSATION ENDED.\n") == 0)
10167c478bd9Sstevel@tonic-gate return (DISCONNECT);
10177c478bd9Sstevel@tonic-gate
10187c478bd9Sstevel@tonic-gate return (nostatus);
10197c478bd9Sstevel@tonic-gate }
10207c478bd9Sstevel@tonic-gate
10217c478bd9Sstevel@tonic-gate
10227c478bd9Sstevel@tonic-gate /*
10237c478bd9Sstevel@tonic-gate * Looks for *str1 in string *str2. Returns a pointer to the start of the
10247c478bd9Sstevel@tonic-gate * substring if it's found or to the end of string str2 otherwise.
10257c478bd9Sstevel@tonic-gate */
10267c478bd9Sstevel@tonic-gate
10277c478bd9Sstevel@tonic-gate static char *
find(char * str1,char * str2)10287c478bd9Sstevel@tonic-gate find(char *str1, char *str2)
10297c478bd9Sstevel@tonic-gate {
10307c478bd9Sstevel@tonic-gate char *s1, *s2; /* can't change str1 or str2 too fast */
10317c478bd9Sstevel@tonic-gate
10327c478bd9Sstevel@tonic-gate for (; *str2 != '\0'; str2++) {
10337c478bd9Sstevel@tonic-gate for (s1 = str1, s2 = str2; *s1 != '\0' && *s1 == *s2; s1++, s2++);
10347c478bd9Sstevel@tonic-gate if (*s1 == '\0')
10357c478bd9Sstevel@tonic-gate break;
10367c478bd9Sstevel@tonic-gate }
10377c478bd9Sstevel@tonic-gate
10387c478bd9Sstevel@tonic-gate return (str2);
10397c478bd9Sstevel@tonic-gate
10407c478bd9Sstevel@tonic-gate }
10417c478bd9Sstevel@tonic-gate
10427c478bd9Sstevel@tonic-gate
10437c478bd9Sstevel@tonic-gate /*
10447c478bd9Sstevel@tonic-gate * Reads characters from the input line until nothing's left. Don't do
10457c478bd9Sstevel@tonic-gate * anything if we're currently running separate read and write processes.
10467c478bd9Sstevel@tonic-gate */
10477c478bd9Sstevel@tonic-gate
10487c478bd9Sstevel@tonic-gate static void
clearline(void)10497c478bd9Sstevel@tonic-gate clearline(void)
10507c478bd9Sstevel@tonic-gate {
10517c478bd9Sstevel@tonic-gate if (whatami == READWRITE)
10527c478bd9Sstevel@tonic-gate while (readline() != FALSE);
10537c478bd9Sstevel@tonic-gate
10547c478bd9Sstevel@tonic-gate }
10557c478bd9Sstevel@tonic-gate
10567c478bd9Sstevel@tonic-gate
10577c478bd9Sstevel@tonic-gate /*
10587c478bd9Sstevel@tonic-gate * Sends signal sig to the other process if we're running as separate read and
10597c478bd9Sstevel@tonic-gate * write processes. Returns the result of the kill if there's someone else to
10607c478bd9Sstevel@tonic-gate * signal or -1 if we're running alone.
10617c478bd9Sstevel@tonic-gate *
10627c478bd9Sstevel@tonic-gate */
10637c478bd9Sstevel@tonic-gate
10647c478bd9Sstevel@tonic-gate static int
sendsignal(int sig)10657c478bd9Sstevel@tonic-gate sendsignal(int sig)
10667c478bd9Sstevel@tonic-gate {
10677c478bd9Sstevel@tonic-gate if (whatami != READWRITE && otherpid > 1)
10687c478bd9Sstevel@tonic-gate return (kill(otherpid, sig));
10697c478bd9Sstevel@tonic-gate
10707c478bd9Sstevel@tonic-gate return (-1);
10717c478bd9Sstevel@tonic-gate }
10727c478bd9Sstevel@tonic-gate
10737c478bd9Sstevel@tonic-gate
10747c478bd9Sstevel@tonic-gate /*
10757c478bd9Sstevel@tonic-gate * Caught a signal - all except joinsig cause the program to quit. joinsig is
10767c478bd9Sstevel@tonic-gate * the signal sent by the writer to the reader after all the jobs have been
10777c478bd9Sstevel@tonic-gate * transmitted. Used to tell the read process when it can start looking for
10787c478bd9Sstevel@tonic-gate * the end of the job.
10797c478bd9Sstevel@tonic-gate */
10807c478bd9Sstevel@tonic-gate
10817c478bd9Sstevel@tonic-gate static void
interrupt(int sig)10827c478bd9Sstevel@tonic-gate interrupt(int sig)
10837c478bd9Sstevel@tonic-gate {
10847c478bd9Sstevel@tonic-gate signal(sig, SIG_IGN);
10857c478bd9Sstevel@tonic-gate
10867c478bd9Sstevel@tonic-gate if (sig != joinsig) {
10877c478bd9Sstevel@tonic-gate x_stat |= FATAL;
10887c478bd9Sstevel@tonic-gate if (canread == TRUE)
10897c478bd9Sstevel@tonic-gate if (interactive == FALSE)
10907c478bd9Sstevel@tonic-gate error(NON_FATAL, "signal %d abort", sig);
10917c478bd9Sstevel@tonic-gate else error(NON_FATAL, "quitting");
10927c478bd9Sstevel@tonic-gate quit(sig);
10937c478bd9Sstevel@tonic-gate }
10947c478bd9Sstevel@tonic-gate
10957c478bd9Sstevel@tonic-gate writedone = TRUE;
10967c478bd9Sstevel@tonic-gate signal(joinsig, interrupt);
10977c478bd9Sstevel@tonic-gate }
10987c478bd9Sstevel@tonic-gate
10997c478bd9Sstevel@tonic-gate
11007c478bd9Sstevel@tonic-gate /*
11017c478bd9Sstevel@tonic-gate * Simple routine that's used to write a message to the log file.
11027c478bd9Sstevel@tonic-gate */
11037c478bd9Sstevel@tonic-gate
11047c478bd9Sstevel@tonic-gate void
logit(char * mesg,...)11057c478bd9Sstevel@tonic-gate logit(char *mesg, ...)
11067c478bd9Sstevel@tonic-gate {
11077c478bd9Sstevel@tonic-gate va_list ap;
11087c478bd9Sstevel@tonic-gate
11097c478bd9Sstevel@tonic-gate va_start(ap, mesg);
11107c478bd9Sstevel@tonic-gate vfprintf(fp_log, mesg, ap);
11117c478bd9Sstevel@tonic-gate va_end(ap);
11127c478bd9Sstevel@tonic-gate
11137c478bd9Sstevel@tonic-gate fflush(fp_log);
11147c478bd9Sstevel@tonic-gate
11157c478bd9Sstevel@tonic-gate }
11167c478bd9Sstevel@tonic-gate
11177c478bd9Sstevel@tonic-gate /*
11187c478bd9Sstevel@tonic-gate * Called when we've run into some kind of program error. First *mesg is
11197c478bd9Sstevel@tonic-gate * printed. If kind is FATAL and we're not ignoring errors the program
11207c478bd9Sstevel@tonic-gate * will be terminated. If mesg is NULL or *mesg is the NULL string nothing
11217c478bd9Sstevel@tonic-gate * will be printed.
11227c478bd9Sstevel@tonic-gate */
11237c478bd9Sstevel@tonic-gate
11247c478bd9Sstevel@tonic-gate void
error(int kind,char * mesg,...)11257c478bd9Sstevel@tonic-gate error(int kind, char *mesg, ...)
11267c478bd9Sstevel@tonic-gate {
11277c478bd9Sstevel@tonic-gate va_list ap;
11287c478bd9Sstevel@tonic-gate
11297c478bd9Sstevel@tonic-gate if (mesg != NULL && *mesg != '\0') {
11307c478bd9Sstevel@tonic-gate fprintf(fp_log, "%s: ", prog_name);
11317c478bd9Sstevel@tonic-gate
11327c478bd9Sstevel@tonic-gate va_start(ap, mesg);
11337c478bd9Sstevel@tonic-gate vfprintf(fp_log, mesg, ap);
11347c478bd9Sstevel@tonic-gate va_end(ap);
11357c478bd9Sstevel@tonic-gate
11367c478bd9Sstevel@tonic-gate putc('\n', fp_log);
11377c478bd9Sstevel@tonic-gate }
11387c478bd9Sstevel@tonic-gate
11397c478bd9Sstevel@tonic-gate x_stat |= kind;
11407c478bd9Sstevel@tonic-gate
11417c478bd9Sstevel@tonic-gate if (kind != NON_FATAL && ignore == OFF)
11427c478bd9Sstevel@tonic-gate quit(SIGTERM);
11437c478bd9Sstevel@tonic-gate
11447c478bd9Sstevel@tonic-gate }
11457c478bd9Sstevel@tonic-gate
11467c478bd9Sstevel@tonic-gate
11477c478bd9Sstevel@tonic-gate /*
11487c478bd9Sstevel@tonic-gate *
11497c478bd9Sstevel@tonic-gate * Makes sure everything is properly cleaned up if there's a signal or FATAL
11507c478bd9Sstevel@tonic-gate * error that should cause the program to terminate. The sleep by the write
11517c478bd9Sstevel@tonic-gate * process is to help give the reset sequence a chance to reach the printer
11527c478bd9Sstevel@tonic-gate * before we break the connection - primarily for printers connected to Datakit.
11537c478bd9Sstevel@tonic-gate * There's a very slight chance the reset sequence that's sent to the printer
11547c478bd9Sstevel@tonic-gate * could get us stuck here. Simplest solution is don't bother to send it -
11557c478bd9Sstevel@tonic-gate * everything works without it. Flushing ttyo would be better, but means yet
11567c478bd9Sstevel@tonic-gate * another system dependent procedure in ifdef.c! I'll leave things be for now.
11577c478bd9Sstevel@tonic-gate */
11587c478bd9Sstevel@tonic-gate
11597c478bd9Sstevel@tonic-gate static void
quit(int sig)11607c478bd9Sstevel@tonic-gate quit(int sig)
11617c478bd9Sstevel@tonic-gate {
11627c478bd9Sstevel@tonic-gate int w;
11637c478bd9Sstevel@tonic-gate
11647c478bd9Sstevel@tonic-gate signal(sig, SIG_IGN);
11657c478bd9Sstevel@tonic-gate ignore = ON;
11667c478bd9Sstevel@tonic-gate
11677c478bd9Sstevel@tonic-gate while (sendsignal(sig) != -1 && (w = wait((int *)0)) != otherpid &&
11687c478bd9Sstevel@tonic-gate w != -1);
11697c478bd9Sstevel@tonic-gate
11707c478bd9Sstevel@tonic-gate setupstdin(2);
11717c478bd9Sstevel@tonic-gate
11727c478bd9Sstevel@tonic-gate if (currentstate != NOTCONNECTED)
11737c478bd9Sstevel@tonic-gate Write(ttyo, "\003\004", 2);
11747c478bd9Sstevel@tonic-gate alarm(0); /* prevents sleep() loop on V9 systems */
11757c478bd9Sstevel@tonic-gate Rest(2);
11767c478bd9Sstevel@tonic-gate
11777c478bd9Sstevel@tonic-gate exit(x_stat);
11787c478bd9Sstevel@tonic-gate
11797c478bd9Sstevel@tonic-gate }
11807c478bd9Sstevel@tonic-gate
11817c478bd9Sstevel@tonic-gate
11827c478bd9Sstevel@tonic-gate /*
11837c478bd9Sstevel@tonic-gate * Used to replace sleep() calls. Only needed if we're running the program as
11847c478bd9Sstevel@tonic-gate * a read and write process and don't want to have the read process sleep. Most
11857c478bd9Sstevel@tonic-gate * sleeps are in the code because of the non-blocking read used by the single
11867c478bd9Sstevel@tonic-gate * process implementation. Probably should be a macro.
11877c478bd9Sstevel@tonic-gate */
11887c478bd9Sstevel@tonic-gate
11897c478bd9Sstevel@tonic-gate static void
Rest(int t)11907c478bd9Sstevel@tonic-gate Rest(int t)
11917c478bd9Sstevel@tonic-gate {
11927c478bd9Sstevel@tonic-gate if (t > 0 && canwrite == TRUE)
11937c478bd9Sstevel@tonic-gate sleep(t);
11947c478bd9Sstevel@tonic-gate
11957c478bd9Sstevel@tonic-gate }
11967c478bd9Sstevel@tonic-gate
11977c478bd9Sstevel@tonic-gate
11987c478bd9Sstevel@tonic-gate /*
11997c478bd9Sstevel@tonic-gate * Used to replace some of the read() calls. Only needed if we're running
12007c478bd9Sstevel@tonic-gate * separate read and write processes. Should only be used to replace read calls
12017c478bd9Sstevel@tonic-gate * on ttyi. Always returns 0 to the caller if the process doesn't have its
12027c478bd9Sstevel@tonic-gate * READ flag set. Probably should be a macro.
12037c478bd9Sstevel@tonic-gate */
12047c478bd9Sstevel@tonic-gate
12057c478bd9Sstevel@tonic-gate #ifdef NEVER
12067c478bd9Sstevel@tonic-gate
12077c478bd9Sstevel@tonic-gate static int
Read(int fd,char * buf,int n)12087c478bd9Sstevel@tonic-gate Read(int fd, char *buf, int n)
12097c478bd9Sstevel@tonic-gate {
12107c478bd9Sstevel@tonic-gate int count;
12117c478bd9Sstevel@tonic-gate
12127c478bd9Sstevel@tonic-gate if (canread == TRUE) {
12137c478bd9Sstevel@tonic-gate if ((count = read(fd, buf, n)) == -1 && errno == EINTR)
12147c478bd9Sstevel@tonic-gate count = 0;
12157c478bd9Sstevel@tonic-gate } else count = 0;
12167c478bd9Sstevel@tonic-gate
12177c478bd9Sstevel@tonic-gate return (count);
12187c478bd9Sstevel@tonic-gate
12197c478bd9Sstevel@tonic-gate }
12207c478bd9Sstevel@tonic-gate
1221f928ce67Sceastha #endif /* NEVER */
12227c478bd9Sstevel@tonic-gate
12237c478bd9Sstevel@tonic-gate
12247c478bd9Sstevel@tonic-gate /*
12257c478bd9Sstevel@tonic-gate *
12267c478bd9Sstevel@tonic-gate * Used to replace some of the write() calls. Again only needed if we're running
12277c478bd9Sstevel@tonic-gate * separate read and write processes. Should only be used to replace write calls
12287c478bd9Sstevel@tonic-gate * on ttyo. Always returns n to the caller if the process doesn't have its WRITE
12297c478bd9Sstevel@tonic-gate * flag set. Should also probably be a macro.
12307c478bd9Sstevel@tonic-gate *
12317c478bd9Sstevel@tonic-gate */
12327c478bd9Sstevel@tonic-gate
12337c478bd9Sstevel@tonic-gate static int
Write(int fd,char * buf,int n)12347c478bd9Sstevel@tonic-gate Write(int fd, char *buf, int n)
12357c478bd9Sstevel@tonic-gate {
12367c478bd9Sstevel@tonic-gate int count;
12377c478bd9Sstevel@tonic-gate
12387c478bd9Sstevel@tonic-gate if (canwrite == TRUE) {
12397c478bd9Sstevel@tonic-gate if ((count = write(fd, buf, n)) == -1 && errno == EINTR)
12407c478bd9Sstevel@tonic-gate count = n;
12417c478bd9Sstevel@tonic-gate } else count = n;
12427c478bd9Sstevel@tonic-gate
12437c478bd9Sstevel@tonic-gate return (count);
12447c478bd9Sstevel@tonic-gate }
1245