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