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