xref: /plan9/sys/src/cmd/postscript/tcpostio/tcpostio.c (revision 14f51593fd82e19ba95969a8c07ff71131015979)
1*14f51593SDavid du Colombier #define _BSD_EXTENSION
2*14f51593SDavid du Colombier #define _NET_EXTENSION
3*14f51593SDavid du Colombier #define _POSIX_SOURCE
4*14f51593SDavid du Colombier 
57dd7cddfSDavid du Colombier #include <stdio.h>
67dd7cddfSDavid du Colombier #include <stdlib.h>
7*14f51593SDavid du Colombier #include <unistd.h>
8*14f51593SDavid du Colombier #include <fcntl.h>
97dd7cddfSDavid du Colombier #include <string.h>
10*14f51593SDavid du Colombier #include <ctype.h>
117dd7cddfSDavid du Colombier #include <signal.h>
127dd7cddfSDavid du Colombier #include <errno.h>
13*14f51593SDavid du Colombier #include <select.h>
147dd7cddfSDavid du Colombier #include <sys/types.h>
157dd7cddfSDavid du Colombier #include <sys/time.h>
167dd7cddfSDavid du Colombier #include <sys/socket.h>
17*14f51593SDavid du Colombier #include <sys/wait.h>
187dd7cddfSDavid du Colombier 
197dd7cddfSDavid du Colombier extern	int dial_debug;
207dd7cddfSDavid du Colombier extern	int dial(char*, char*, char*, int*);
217dd7cddfSDavid du Colombier 
227dd7cddfSDavid du Colombier 
237dd7cddfSDavid du Colombier /* debug = 0 for no debugging */
247dd7cddfSDavid du Colombier /* debug = 1 for readprinter debugging */
257dd7cddfSDavid du Colombier /* debug = 2 for sendprinter debugging */
267dd7cddfSDavid du Colombier /* debug = 3 for full debugging, its hard to read the messages */
277dd7cddfSDavid du Colombier 
287dd7cddfSDavid du Colombier int debug = 0;
297dd7cddfSDavid du Colombier #define READTIMEOUT	300
307dd7cddfSDavid du Colombier #define	RCVSELTIMEOUT	30
317dd7cddfSDavid du Colombier #define	SNDSELTIMEOUT	300
327dd7cddfSDavid du Colombier 
337dd7cddfSDavid du Colombier void
rdtmout(void)347dd7cddfSDavid du Colombier rdtmout(void) {
357dd7cddfSDavid du Colombier 	fprintf(stderr, "read timeout occurred, check printer\n");
367dd7cddfSDavid du Colombier }
377dd7cddfSDavid du Colombier 
387dd7cddfSDavid du Colombier int
getline(int fd,char * buf,int len)397dd7cddfSDavid du Colombier getline(int fd, char *buf, int len) {
407dd7cddfSDavid du Colombier 	char *bp, c;
417dd7cddfSDavid du Colombier 	int i = 0, n;
427dd7cddfSDavid du Colombier 
437dd7cddfSDavid du Colombier 	bp = buf;
447dd7cddfSDavid du Colombier 	while (alarm(READTIMEOUT),(n=read(fd, bp, 1)) == 1) {
457dd7cddfSDavid du Colombier 		alarm(0);
467dd7cddfSDavid du Colombier 		if (*bp == '\r') continue;
477dd7cddfSDavid du Colombier 		i += n;
487dd7cddfSDavid du Colombier 
497dd7cddfSDavid du Colombier 		c = *bp++;
507dd7cddfSDavid du Colombier 		if (c == '\n' || c == '\004' || i >= len-1)
517dd7cddfSDavid du Colombier 			break;
527dd7cddfSDavid du Colombier 	}
537dd7cddfSDavid du Colombier 	alarm(0);
547dd7cddfSDavid du Colombier 	if (n < 0)
557dd7cddfSDavid du Colombier 		return(n);
567dd7cddfSDavid du Colombier 	*bp = '\0';
577dd7cddfSDavid du Colombier 	return(i);
587dd7cddfSDavid du Colombier }
597dd7cddfSDavid du Colombier 
607dd7cddfSDavid du Colombier typedef struct {
617dd7cddfSDavid du Colombier 	char	*state;			/* printer's current status */
627dd7cddfSDavid du Colombier 	int	val;			/* value returned by getstatus() */
637dd7cddfSDavid du Colombier } Status;
647dd7cddfSDavid du Colombier 
657dd7cddfSDavid du Colombier /* printer states */
667dd7cddfSDavid du Colombier #define	INITIALIZING	0
677dd7cddfSDavid du Colombier #define	IDLE		1
687dd7cddfSDavid du Colombier #define	BUSY		2
697dd7cddfSDavid du Colombier #define	WAITING		3
707dd7cddfSDavid du Colombier #define	PRINTING	4
717dd7cddfSDavid du Colombier #define	PRINTERERROR	5
727dd7cddfSDavid du Colombier #define	ERROR		6
737dd7cddfSDavid du Colombier #define	FLUSHING	7
747dd7cddfSDavid du Colombier #define UNKNOWN		8
757dd7cddfSDavid du Colombier 
767dd7cddfSDavid du Colombier /* protocol requests and program states */
777dd7cddfSDavid du Colombier #define START	'S'
787dd7cddfSDavid du Colombier unsigned char Start[] = { START };
797dd7cddfSDavid du Colombier #define ID_LE		'L'
807dd7cddfSDavid du Colombier unsigned char Id_le[] = { ID_LE };
817dd7cddfSDavid du Colombier #define	REQ_STAT	'T'
827dd7cddfSDavid du Colombier unsigned char Req_stat[] = { REQ_STAT };
837dd7cddfSDavid du Colombier #define	SEND_DATA	'D'
847dd7cddfSDavid du Colombier unsigned char Send_data[] = { SEND_DATA };
857dd7cddfSDavid du Colombier #define	SENT_DATA	'A'
867dd7cddfSDavid du Colombier unsigned char Sent_data[] = { SENT_DATA };
877dd7cddfSDavid du Colombier #define	WAIT_FOR_EOJ	'W'
887dd7cddfSDavid du Colombier unsigned char Wait_for_eoj[] = { WAIT_FOR_EOJ };
897dd7cddfSDavid du Colombier #define END_OF_JOB	'E'
907dd7cddfSDavid du Colombier unsigned char End_of_job[] = { END_OF_JOB };
917dd7cddfSDavid du Colombier #define FATAL_ERROR	'F'
927dd7cddfSDavid du Colombier unsigned char Fatal_error[] = { FATAL_ERROR };
937dd7cddfSDavid du Colombier #define	WAIT_FOR_IDLE	'I'
947dd7cddfSDavid du Colombier unsigned char Wait_for_idle[] = { WAIT_FOR_IDLE };
957dd7cddfSDavid du Colombier #define	OVER_AND_OUT	'O'
967dd7cddfSDavid du Colombier unsigned char Over_and_out[] = { OVER_AND_OUT };
977dd7cddfSDavid du Colombier 
987dd7cddfSDavid du Colombier Status	statuslist[] = {
997dd7cddfSDavid du Colombier 	"initializing", INITIALIZING,
1007dd7cddfSDavid du Colombier 	"idle", IDLE,
1017dd7cddfSDavid du Colombier 	"busy", BUSY,
1027dd7cddfSDavid du Colombier 	"waiting", WAITING,
1037dd7cddfSDavid du Colombier 	"printing", PRINTING,
1047dd7cddfSDavid du Colombier 	"printererror", PRINTERERROR,
1057dd7cddfSDavid du Colombier 	"Error", ERROR,
1067dd7cddfSDavid du Colombier 	"flushing", FLUSHING,
1077dd7cddfSDavid du Colombier 	NULL, UNKNOWN
1087dd7cddfSDavid du Colombier };
1097dd7cddfSDavid du Colombier 
1107dd7cddfSDavid du Colombier 
1117dd7cddfSDavid du Colombier /* find returns a pointer to the location of string str2 in string str1,
1127dd7cddfSDavid du Colombier  * if it exists.  Otherwise, it points to the end of str1.
1137dd7cddfSDavid du Colombier  */
1147dd7cddfSDavid du Colombier char *
find(char * str1,char * str2)1157dd7cddfSDavid du Colombier find(char *str1, char *str2) {
1167dd7cddfSDavid du Colombier 	char *s1, *s2;
1177dd7cddfSDavid du Colombier 
1187dd7cddfSDavid du Colombier 	for (; *str1!='\0'; str1++) {
1197dd7cddfSDavid du Colombier 		for (s1=str1,s2=str2; *s2!='\0'&&*s1==*s2; s1++,s2++) ;
1207dd7cddfSDavid du Colombier 		if ( *s2 == '\0' )
1217dd7cddfSDavid du Colombier 	    		break;
1227dd7cddfSDavid du Colombier 	}
1237dd7cddfSDavid du Colombier 
1247dd7cddfSDavid du Colombier 	return(str1);
1257dd7cddfSDavid du Colombier }
1267dd7cddfSDavid du Colombier 
1277dd7cddfSDavid du Colombier #define	MESGSIZE	16384
1287dd7cddfSDavid du Colombier int blocksize = 1920;		/* 19200/10, with 1 sec delay between transfers
1297dd7cddfSDavid du Colombier 				 * this keeps the queues from building up.
1307dd7cddfSDavid du Colombier 				 */
1317dd7cddfSDavid du Colombier char	mesg[MESGSIZE];			/* exactly what came back on ttyi */
1327dd7cddfSDavid du Colombier 
1337dd7cddfSDavid du Colombier int
parsmesg(char * buf)1347dd7cddfSDavid du Colombier parsmesg(char *buf) {
1357dd7cddfSDavid du Colombier 	static char sbuf[MESGSIZE];
1367dd7cddfSDavid du Colombier 	char	*s;		/* start of printer messsage in mesg[] */
1377dd7cddfSDavid du Colombier 	char	*e;		/* end of printer message in mesg[] */
1387dd7cddfSDavid du Colombier 	char	*key, *val;	/* keyword/value strings in sbuf[] */
1397dd7cddfSDavid du Colombier 	char	*p;		/* for converting to lower case etc. */
1407dd7cddfSDavid du Colombier 	int	i;		/* where *key was found in statuslist[] */
1417dd7cddfSDavid du Colombier 
1427dd7cddfSDavid du Colombier 	if (*(s=find(buf, "%[ "))!='\0' && *(e=find(s, " ]%"))!='\0') {
1437dd7cddfSDavid du Colombier 		strcpy(sbuf, s+3);	/* don't change mesg[] */
1447dd7cddfSDavid du Colombier 		sbuf[e-(s+3)] = '\0';	/* ignore the trailing " ]%" */
1457dd7cddfSDavid du Colombier 
1467dd7cddfSDavid du Colombier 		for (key=strtok(sbuf, " :"); key != NULL; key=strtok(NULL, " :"))  {
1477dd7cddfSDavid du Colombier 			if (strcmp(key, "Error") == 0)
1487dd7cddfSDavid du Colombier 				return(ERROR);
1497dd7cddfSDavid du Colombier 			if ((val=strtok(NULL, ";")) != NULL && strcmp(key, "status") == 0)
1507dd7cddfSDavid du Colombier 				key = val;
1517dd7cddfSDavid du Colombier 
1527dd7cddfSDavid du Colombier 	    		for (; *key == ' '; key++) ;	/* skip any leading spaces */
1537dd7cddfSDavid du Colombier 			for (p = key; *p; p++)		/* convert to lower case */
1547dd7cddfSDavid du Colombier 				if (*p == ':')  {
1557dd7cddfSDavid du Colombier 					*p = '\0';
1567dd7cddfSDavid du Colombier 					break;
1577dd7cddfSDavid du Colombier 				} else if (isupper(*p)) *p = tolower(*p);
1587dd7cddfSDavid du Colombier 
1597dd7cddfSDavid du Colombier 			for (i=0; statuslist[i].state != NULL; i++) {
1607dd7cddfSDavid du Colombier 				if (strcmp(statuslist[i].state, key) == 0)
1617dd7cddfSDavid du Colombier 					return(statuslist[i].val);
1627dd7cddfSDavid du Colombier 			}
1637dd7cddfSDavid du Colombier 		}
1647dd7cddfSDavid du Colombier 	}
1657dd7cddfSDavid du Colombier 	return(UNKNOWN);
1667dd7cddfSDavid du Colombier }
1677dd7cddfSDavid du Colombier 
1687dd7cddfSDavid du Colombier char buf[MESGSIZE];
1697dd7cddfSDavid du Colombier fd_set readfds, writefds, exceptfds;
1707dd7cddfSDavid du Colombier struct timeval rcvtimeout = { RCVSELTIMEOUT, 0 };
1717dd7cddfSDavid du Colombier struct timeval sndtimeout = { SNDSELTIMEOUT, 0 };
1727dd7cddfSDavid du Colombier 
1737dd7cddfSDavid du Colombier int
readprinter(int printerfd,int pipefd)1747dd7cddfSDavid du Colombier readprinter(int printerfd, int pipefd)
1757dd7cddfSDavid du Colombier {
1767dd7cddfSDavid du Colombier 	unsigned char proto;
1777dd7cddfSDavid du Colombier 	int progstate = START;
1787dd7cddfSDavid du Colombier 	int print_wait_msg = 0;
1797dd7cddfSDavid du Colombier 	int tocount = 0;
1807dd7cddfSDavid du Colombier 	int c, printstat, lastprintstat, n, nfds;
1817dd7cddfSDavid du Colombier 
1827dd7cddfSDavid du Colombier 
1837dd7cddfSDavid du Colombier 	nfds = ((pipefd>printerfd)?pipefd:printerfd) + 1;
1847dd7cddfSDavid du Colombier 	printstat = 0;
1857dd7cddfSDavid du Colombier 	signal(SIGALRM, rdtmout);
1867dd7cddfSDavid du Colombier 	do {
1877dd7cddfSDavid du Colombier 
1887dd7cddfSDavid du Colombier reselect:
1897dd7cddfSDavid du Colombier 		/* ask sending process to request printer status */
1907dd7cddfSDavid du Colombier 		if (write(pipefd, Req_stat, 1) != 1) {
1917dd7cddfSDavid du Colombier 			fprintf(stderr, "request status failed\n");
1927dd7cddfSDavid du Colombier 			progstate = FATAL_ERROR;
1937dd7cddfSDavid du Colombier 			continue;
1947dd7cddfSDavid du Colombier 		}
1957dd7cddfSDavid du Colombier 		FD_ZERO(&readfds);	/* lets be anal */
1967dd7cddfSDavid du Colombier 		FD_SET(printerfd, &readfds);
1977dd7cddfSDavid du Colombier 		FD_SET(pipefd, &readfds);
1987dd7cddfSDavid du Colombier 		FD_ZERO(&exceptfds);
1997dd7cddfSDavid du Colombier 		FD_SET(printerfd, &exceptfds);
2007dd7cddfSDavid du Colombier 		FD_SET(pipefd, &exceptfds);
2017dd7cddfSDavid du Colombier 		n = select(nfds, &readfds, (fd_set *)0, &exceptfds, &rcvtimeout);
2027dd7cddfSDavid du Colombier 		if (debug&0x1) fprintf(stderr, "readprinter select returned %d\n", n);
2037dd7cddfSDavid du Colombier 		if (n == 0) {
2047dd7cddfSDavid du Colombier 			/* a timeout occurred */
2057dd7cddfSDavid du Colombier 			if (++tocount > 4) {
2067dd7cddfSDavid du Colombier 				fprintf(stderr, "printer appears to be offline.\nHP4m printers may be out of paper.\n");
2077dd7cddfSDavid du Colombier 				tocount = 0;
2087dd7cddfSDavid du Colombier 			}
2097dd7cddfSDavid du Colombier 			goto reselect;
2107dd7cddfSDavid du Colombier 		}
2117dd7cddfSDavid du Colombier 		if (n > 0 && FD_ISSET(printerfd, &exceptfds)) {
2127dd7cddfSDavid du Colombier 			/* printer problem */
2137dd7cddfSDavid du Colombier 			fprintf(stderr, "printer exception\n");
2147dd7cddfSDavid du Colombier 			if (write(pipefd, Fatal_error, 1) != 1) {
2157dd7cddfSDavid du Colombier 				fprintf(stderr, "'fatal error' write to pipe failed\n");
2167dd7cddfSDavid du Colombier 			}
2177dd7cddfSDavid du Colombier 			progstate = FATAL_ERROR;
2187dd7cddfSDavid du Colombier 			continue;
2197dd7cddfSDavid du Colombier 		}
2207dd7cddfSDavid du Colombier 		if (n > 0 && FD_ISSET(pipefd, &exceptfds)) {
2217dd7cddfSDavid du Colombier 			/* pipe problem */
2227dd7cddfSDavid du Colombier 			fprintf(stderr, "pipe exception\n");
2237dd7cddfSDavid du Colombier 			progstate = FATAL_ERROR;
2247dd7cddfSDavid du Colombier 			continue;
2257dd7cddfSDavid du Colombier 		}
2267dd7cddfSDavid du Colombier 		if (n > 0 && FD_ISSET(pipefd, &readfds)) {
2277dd7cddfSDavid du Colombier 			/* protocol pipe wants to be read */
2287dd7cddfSDavid du Colombier 			if (debug&0x1) fprintf(stderr, "pipe wants to be read\n");
2297dd7cddfSDavid du Colombier 			if (read(pipefd, &proto, 1) != 1) {
2307dd7cddfSDavid du Colombier 				fprintf(stderr, "read protocol pipe failed\n");
2317dd7cddfSDavid du Colombier 				progstate = FATAL_ERROR;
2327dd7cddfSDavid du Colombier 				continue;
2337dd7cddfSDavid du Colombier 			}
2347dd7cddfSDavid du Colombier 			if (debug&0x1) fprintf(stderr, "readprinter: proto=%c\n", proto);
2357dd7cddfSDavid du Colombier 			/* change state? */
2367dd7cddfSDavid du Colombier 			switch (proto) {
2377dd7cddfSDavid du Colombier 			case SENT_DATA:
2387dd7cddfSDavid du Colombier 				break;
2397dd7cddfSDavid du Colombier 			case WAIT_FOR_EOJ:
2407dd7cddfSDavid du Colombier 				if (!print_wait_msg) {
2417dd7cddfSDavid du Colombier 					print_wait_msg = 1;
2427dd7cddfSDavid du Colombier 					fprintf(stderr, "waiting for end of job\n");
2437dd7cddfSDavid du Colombier 				}
2447dd7cddfSDavid du Colombier 				progstate = proto;
2457dd7cddfSDavid du Colombier 				break;
2467dd7cddfSDavid du Colombier 			default:
2477dd7cddfSDavid du Colombier 				fprintf(stderr, "received unknown protocol request <%c> from sendfile\n", proto);
2487dd7cddfSDavid du Colombier 				break;
2497dd7cddfSDavid du Colombier 			}
2507dd7cddfSDavid du Colombier 			n--;
2517dd7cddfSDavid du Colombier 		}
2527dd7cddfSDavid du Colombier 		if (n > 0 && FD_ISSET(printerfd, &readfds)) {
2537dd7cddfSDavid du Colombier 			/* printer wants to be read */
2547dd7cddfSDavid du Colombier 			if (debug&0x1) fprintf(stderr, "printer wants to be read\n");
2557dd7cddfSDavid du Colombier 			if ((c=getline(printerfd, buf, MESGSIZE)) < 0) {
2567dd7cddfSDavid du Colombier 				fprintf(stderr, "read printer failed\n");
2577dd7cddfSDavid du Colombier 				progstate = FATAL_ERROR;
2587dd7cddfSDavid du Colombier 				continue;
2597dd7cddfSDavid du Colombier 			}
2607dd7cddfSDavid du Colombier 			if (debug&0x1) fprintf(stderr, "%s\n", buf);
2617dd7cddfSDavid du Colombier 			if (c==1 && *buf == '\004') {
2627dd7cddfSDavid du Colombier 				if (progstate == WAIT_FOR_EOJ) {
2637dd7cddfSDavid du Colombier 					if (debug&0x1) fprintf(stderr, "progstate=%c, ", progstate);
2647dd7cddfSDavid du Colombier 					fprintf(stderr, "%%[ status: endofjob ]%%\n");
2657dd7cddfSDavid du Colombier /*					progstate = WAIT_FOR_IDLE; */
2667dd7cddfSDavid du Colombier 					progstate = OVER_AND_OUT;
2677dd7cddfSDavid du Colombier 					if (write(pipefd, Over_and_out, 1) != 1) {
2687dd7cddfSDavid du Colombier 						fprintf(stderr, "'fatal error' write to pipe failed\n");
2697dd7cddfSDavid du Colombier 					}
2707dd7cddfSDavid du Colombier 					continue;
2717dd7cddfSDavid du Colombier 				} else {
2727dd7cddfSDavid du Colombier 					if (printstat == ERROR) {
2737dd7cddfSDavid du Colombier 						progstate = FATAL_ERROR;
2747dd7cddfSDavid du Colombier 						continue;
2757dd7cddfSDavid du Colombier 					}
2767dd7cddfSDavid du Colombier 					if (progstate != START && progstate != WAIT_FOR_IDLE)
2777dd7cddfSDavid du Colombier 						fprintf(stderr, "warning: EOF received; program status is '%c'\n", progstate);
2787dd7cddfSDavid du Colombier 
2797dd7cddfSDavid du Colombier 				}
2807dd7cddfSDavid du Colombier 				continue;
2817dd7cddfSDavid du Colombier 			}
2827dd7cddfSDavid du Colombier 
2837dd7cddfSDavid du Colombier 			/* figure out if it was a status line */
2847dd7cddfSDavid du Colombier 			lastprintstat = printstat;
2857dd7cddfSDavid du Colombier 			printstat = parsmesg(buf);
2867dd7cddfSDavid du Colombier 			if (printstat == UNKNOWN || printstat == ERROR
2877dd7cddfSDavid du Colombier 			    || lastprintstat != printstat) {
2887dd7cddfSDavid du Colombier 				/* print whatever it is that was read */
2897dd7cddfSDavid du Colombier 				fprintf(stderr, buf);
2907dd7cddfSDavid du Colombier 				fflush(stderr);
2917dd7cddfSDavid du Colombier 				if (printstat == UNKNOWN) {
2927dd7cddfSDavid du Colombier 					printstat = lastprintstat;
2937dd7cddfSDavid du Colombier 					continue;
2947dd7cddfSDavid du Colombier 				}
2957dd7cddfSDavid du Colombier 			}
2967dd7cddfSDavid du Colombier 			switch (printstat) {
2977dd7cddfSDavid du Colombier 			case UNKNOWN:
2987dd7cddfSDavid du Colombier 				continue;	/* shouldn't get here */
2997dd7cddfSDavid du Colombier 			case FLUSHING:
3007dd7cddfSDavid du Colombier 			case ERROR:
3017dd7cddfSDavid du Colombier 				progstate = FATAL_ERROR;
3027dd7cddfSDavid du Colombier 				/* ask sending process to die */
3037dd7cddfSDavid du Colombier 				if (write(pipefd, Fatal_error, 1) != 1) {
3047dd7cddfSDavid du Colombier 					fprintf(stderr, "Fatal_error mesg write to pipe failed\n");
3057dd7cddfSDavid du Colombier 				}
3067dd7cddfSDavid du Colombier 				continue;
3077dd7cddfSDavid du Colombier 			case INITIALIZING:
3087dd7cddfSDavid du Colombier 			case PRINTERERROR:
3097dd7cddfSDavid du Colombier 				sleep(1);
3107dd7cddfSDavid du Colombier 				break;
3117dd7cddfSDavid du Colombier 			case IDLE:
3127dd7cddfSDavid du Colombier 				if (progstate == WAIT_FOR_IDLE) {
3137dd7cddfSDavid du Colombier 					progstate = OVER_AND_OUT;
3147dd7cddfSDavid du Colombier 					if (write(pipefd, Over_and_out, 1) != 1) {
3157dd7cddfSDavid du Colombier 						fprintf(stderr, "'fatal error' write to pipe failed\n");
3167dd7cddfSDavid du Colombier 					}
3177dd7cddfSDavid du Colombier 					continue;
3187dd7cddfSDavid du Colombier 				}
3197dd7cddfSDavid du Colombier 				progstate = SEND_DATA;
3207dd7cddfSDavid du Colombier 
3217dd7cddfSDavid du Colombier 				goto dowait;
3227dd7cddfSDavid du Colombier 			case BUSY:
3237dd7cddfSDavid du Colombier 			case WAITING:
3247dd7cddfSDavid du Colombier 			default:
3257dd7cddfSDavid du Colombier 				sleep(1);
3267dd7cddfSDavid du Colombier dowait:
3277dd7cddfSDavid du Colombier 				switch (progstate) {
3287dd7cddfSDavid du Colombier 				case WAIT_FOR_IDLE:
3297dd7cddfSDavid du Colombier 				case WAIT_FOR_EOJ:
3307dd7cddfSDavid du Colombier 				case START:
3317dd7cddfSDavid du Colombier 					sleep(5);
3327dd7cddfSDavid du Colombier 					break;
3337dd7cddfSDavid du Colombier 
3347dd7cddfSDavid du Colombier 				case SEND_DATA:
3357dd7cddfSDavid du Colombier 					if (write(pipefd, Send_data, 1) != 1) {
3367dd7cddfSDavid du Colombier 						fprintf(stderr, "send data write to pipe failed\n");
3377dd7cddfSDavid du Colombier 						progstate = FATAL_ERROR;
3387dd7cddfSDavid du Colombier 						continue;
3397dd7cddfSDavid du Colombier 					}
3407dd7cddfSDavid du Colombier 					break;
3417dd7cddfSDavid du Colombier 				default:
3427dd7cddfSDavid du Colombier 					fprintf(stderr, "unexpected program state %c\n", progstate);
3437dd7cddfSDavid du Colombier 					exit(1);
3447dd7cddfSDavid du Colombier 				}
3457dd7cddfSDavid du Colombier 				break;
3467dd7cddfSDavid du Colombier 			}
3477dd7cddfSDavid du Colombier 			n--;
3487dd7cddfSDavid du Colombier 		}
3497dd7cddfSDavid du Colombier 		if (n > 0) {
3507dd7cddfSDavid du Colombier 			fprintf(stderr, "more fds selected than requested!\n");
3517dd7cddfSDavid du Colombier 			exit(1);
3527dd7cddfSDavid du Colombier 		};
3537dd7cddfSDavid du Colombier 	} while ((progstate != FATAL_ERROR) && (progstate != OVER_AND_OUT));
3547dd7cddfSDavid du Colombier 
3557dd7cddfSDavid du Colombier 	if (progstate == FATAL_ERROR)
3567dd7cddfSDavid du Colombier 		return(1);
3577dd7cddfSDavid du Colombier 	else
3587dd7cddfSDavid du Colombier 		return(0);
3597dd7cddfSDavid du Colombier }
3607dd7cddfSDavid du Colombier 
3617dd7cddfSDavid du Colombier int
sendfile(int infd,int printerfd,int pipefd)3627dd7cddfSDavid du Colombier sendfile(int infd, int printerfd, int pipefd)
3637dd7cddfSDavid du Colombier {
3647dd7cddfSDavid du Colombier 	unsigned char proto;
3657dd7cddfSDavid du Colombier 	int progstate = START;
3667dd7cddfSDavid du Colombier 	int i, n, nfds;
3677dd7cddfSDavid du Colombier 	int bytesread,  bytesent = 0;
3687dd7cddfSDavid du Colombier 
3697dd7cddfSDavid du Colombier 	nfds = ((pipefd>printerfd)?pipefd:printerfd) + 1;
3707dd7cddfSDavid du Colombier 
3717dd7cddfSDavid du Colombier 	if (write(printerfd, "\004", 1)!=1) {
3727dd7cddfSDavid du Colombier 		perror("sendfile:write:");
3737dd7cddfSDavid du Colombier 		progstate = FATAL_ERROR;
3747dd7cddfSDavid du Colombier 	}
3757dd7cddfSDavid du Colombier 	do {
3767dd7cddfSDavid du Colombier 		FD_ZERO(&readfds);	/* lets be anal */
3777dd7cddfSDavid du Colombier 		FD_SET(pipefd, &readfds);
3787dd7cddfSDavid du Colombier 		n = select(nfds, &readfds, (fd_set *)0, (fd_set *)0, &sndtimeout);
3797dd7cddfSDavid du Colombier 		if (debug&02) fprintf(stderr, "sendfile select returned %d\n", n);
3807dd7cddfSDavid du Colombier 		if (n > 0 && FD_ISSET(pipefd, &readfds)) {
3817dd7cddfSDavid du Colombier 			/* protocol pipe wants to be read */
3827dd7cddfSDavid du Colombier 			if (read(pipefd, &proto, 1) != 1) {
3837dd7cddfSDavid du Colombier 				fprintf(stderr, "read protocol pipe failed\n");
3847dd7cddfSDavid du Colombier 				return(1);
3857dd7cddfSDavid du Colombier 			}
3867dd7cddfSDavid du Colombier 			/* change state? */
3877dd7cddfSDavid du Colombier 			if (debug&02) fprintf(stderr, "sendfile command - <%c>\n", proto);
3887dd7cddfSDavid du Colombier 			switch (proto) {
3897dd7cddfSDavid du Colombier 			case OVER_AND_OUT:
3907dd7cddfSDavid du Colombier 			case END_OF_JOB:
3917dd7cddfSDavid du Colombier 				progstate = proto;
3927dd7cddfSDavid du Colombier 				break;
3937dd7cddfSDavid du Colombier 			case SEND_DATA:
3947dd7cddfSDavid du Colombier 				bytesread = 0;
3957dd7cddfSDavid du Colombier 				do {
3967dd7cddfSDavid du Colombier 					i = read(infd, &buf[bytesread], blocksize-bytesread);
3977dd7cddfSDavid du Colombier 					if (debug&02) fprintf(stderr, "read %d bytes\n", i);
3987dd7cddfSDavid du Colombier 					if (i > 0)
3997dd7cddfSDavid du Colombier 						bytesread += i;
4007dd7cddfSDavid du Colombier 				} while((i > 0) && (bytesread < blocksize));
4017dd7cddfSDavid du Colombier 				if (i < 0) {
4027dd7cddfSDavid du Colombier 					fprintf(stderr, "input file read error\n");
4037dd7cddfSDavid du Colombier 					progstate = FATAL_ERROR;
4047dd7cddfSDavid du Colombier 					break;	/* from switch */
4057dd7cddfSDavid du Colombier 				}
4067dd7cddfSDavid du Colombier 				if (bytesread > 0) {
4077dd7cddfSDavid du Colombier 					if (debug&02) fprintf(stderr, "writing %d bytes\n", bytesread);
4087dd7cddfSDavid du Colombier 					if (write(printerfd, buf, bytesread)!=bytesread) {
4097dd7cddfSDavid du Colombier 						perror("sendfile:write:");
4107dd7cddfSDavid du Colombier 						progstate = FATAL_ERROR;
4117dd7cddfSDavid du Colombier 					} else if (write(pipefd, Sent_data, 1)!=1) {
4127dd7cddfSDavid du Colombier 						perror("sendfile:write:");
4137dd7cddfSDavid du Colombier 						progstate = FATAL_ERROR;
4147dd7cddfSDavid du Colombier 					} else {
4157dd7cddfSDavid du Colombier 						bytesent += bytesread;
4167dd7cddfSDavid du Colombier 					}
4177dd7cddfSDavid du Colombier 					fprintf(stderr, "%d sent\n", bytesent);
4187dd7cddfSDavid du Colombier 					fflush(stderr);
4197dd7cddfSDavid du Colombier 
4207dd7cddfSDavid du Colombier 				/* we have reached the end of the input file */
4217dd7cddfSDavid du Colombier 				}
4227dd7cddfSDavid du Colombier 				if (i == 0) {
4237dd7cddfSDavid du Colombier 					if (progstate != WAIT_FOR_EOJ) {
4247dd7cddfSDavid du Colombier 						if (write(printerfd, "\004", 1)!=1) {
4257dd7cddfSDavid du Colombier 							perror("sendfile:write:");
4267dd7cddfSDavid du Colombier 							progstate = FATAL_ERROR;
4277dd7cddfSDavid du Colombier 						} else if (write(pipefd, Wait_for_eoj, 1)!=1) {
4287dd7cddfSDavid du Colombier 							perror("sendfile:write:");
4297dd7cddfSDavid du Colombier 							progstate = FATAL_ERROR;
4307dd7cddfSDavid du Colombier 						} else {
4317dd7cddfSDavid du Colombier 							progstate = WAIT_FOR_EOJ;
4327dd7cddfSDavid du Colombier 						}
4337dd7cddfSDavid du Colombier 					}
4347dd7cddfSDavid du Colombier 				}
4357dd7cddfSDavid du Colombier 				break;
4367dd7cddfSDavid du Colombier 			case REQ_STAT:
4377dd7cddfSDavid du Colombier 				if (write(printerfd, "\024", 1)!=1) {
4387dd7cddfSDavid du Colombier 					fprintf(stderr, "write to printer failed\n");
4397dd7cddfSDavid du Colombier 					progstate = FATAL_ERROR;
4407dd7cddfSDavid du Colombier 				}
4417dd7cddfSDavid du Colombier 				if (debug&02) fprintf(stderr, "^T");
4427dd7cddfSDavid du Colombier 				break;
4437dd7cddfSDavid du Colombier 			case FATAL_ERROR:
4447dd7cddfSDavid du Colombier 				progstate = FATAL_ERROR;
4457dd7cddfSDavid du Colombier 			}
4467dd7cddfSDavid du Colombier 		} else if (n < 0) {
4477dd7cddfSDavid du Colombier 			perror("sendfile:select:");
4487dd7cddfSDavid du Colombier 			progstate = FATAL_ERROR;
4497dd7cddfSDavid du Colombier 		} else if (n == 0) {
4507dd7cddfSDavid du Colombier 			sleep(1);
4517dd7cddfSDavid du Colombier 			fprintf(stderr, "sendfile timeout\n");
4527dd7cddfSDavid du Colombier 			progstate = FATAL_ERROR;
4537dd7cddfSDavid du Colombier 		}
4547dd7cddfSDavid du Colombier 	} while ((progstate != FATAL_ERROR) && (progstate != OVER_AND_OUT));
4557dd7cddfSDavid du Colombier 	if (write(printerfd, "\004", 1)!=1) {
4567dd7cddfSDavid du Colombier 		perror("sendfile:write:");
4577dd7cddfSDavid du Colombier 		progstate = FATAL_ERROR;
4587dd7cddfSDavid du Colombier 	}
4597dd7cddfSDavid du Colombier 
4607dd7cddfSDavid du Colombier 	if (debug&02) fprintf(stderr, "%d bytes sent\n", bytesent);
4617dd7cddfSDavid du Colombier 	if (progstate == FATAL_ERROR)
4627dd7cddfSDavid du Colombier 		return(1);
4637dd7cddfSDavid du Colombier 	else
4647dd7cddfSDavid du Colombier 		return(0);
4657dd7cddfSDavid du Colombier }
4667dd7cddfSDavid du Colombier 
main(int argc,char * argv[])4677dd7cddfSDavid du Colombier void main(int argc, char *argv[]) {
4687dd7cddfSDavid du Colombier 	int c, usgflg=0, infd, printerfd;
469*14f51593SDavid du Colombier 	int cpid, sprv;
4707dd7cddfSDavid du Colombier 	int pipefd[2];
4717dd7cddfSDavid du Colombier 	char *dialstr;
472*14f51593SDavid du Colombier 	unsigned long rprv;
4737dd7cddfSDavid du Colombier 
4747dd7cddfSDavid du Colombier 	dialstr = 0;
4757dd7cddfSDavid du Colombier 
4767dd7cddfSDavid du Colombier 	while ((c = getopt(argc, argv, "b:d:")) != -1)
4777dd7cddfSDavid du Colombier 		switch (c) {
4787dd7cddfSDavid du Colombier 		case 'b':
4797dd7cddfSDavid du Colombier 			blocksize = atoi(optarg)/10;
4807dd7cddfSDavid du Colombier 			if (blocksize > MESGSIZE || blocksize < 1)
4817dd7cddfSDavid du Colombier 				blocksize = MESGSIZE;
4827dd7cddfSDavid du Colombier 			break;
4837dd7cddfSDavid du Colombier 		case 'd':
4847dd7cddfSDavid du Colombier 			debug = atoi(optarg);
4857dd7cddfSDavid du Colombier 			dial_debug = debug;
4867dd7cddfSDavid du Colombier 			break;
4877dd7cddfSDavid du Colombier 		case '?':
4887dd7cddfSDavid du Colombier 			fprintf(stderr, "unknown option %c\n", c);
4897dd7cddfSDavid du Colombier 			usgflg++;
490*14f51593SDavid du Colombier 			break;
4917dd7cddfSDavid du Colombier 		}
4927dd7cddfSDavid du Colombier 	if (optind < argc)
4937dd7cddfSDavid du Colombier 		dialstr = argv[optind++];
494*14f51593SDavid du Colombier 	else
4957dd7cddfSDavid du Colombier 		usgflg++;
4967dd7cddfSDavid du Colombier 	if (usgflg) {
497*14f51593SDavid du Colombier 		fprintf(stderr, "usage: %s [-b baudrate] net!host!service [infile]\n",
498*14f51593SDavid du Colombier 			argv[0]);
4997dd7cddfSDavid du Colombier 		exit (2);
5007dd7cddfSDavid du Colombier 	}
5017dd7cddfSDavid du Colombier 	if (optind < argc) {
5027dd7cddfSDavid du Colombier 		infd = open(argv[optind], 0);
5037dd7cddfSDavid du Colombier 		if (infd < 0) {
5047dd7cddfSDavid du Colombier 			fprintf(stderr, "cannot open %s\n", argv[optind]);
5057dd7cddfSDavid du Colombier 			exit(1);
5067dd7cddfSDavid du Colombier 		}
5077dd7cddfSDavid du Colombier 		optind++;
5087dd7cddfSDavid du Colombier 	} else
5097dd7cddfSDavid du Colombier 		infd = 0;
5107dd7cddfSDavid du Colombier 
511*14f51593SDavid du Colombier 	if (debug & 02)
512*14f51593SDavid du Colombier 		fprintf(stderr, "blocksize=%d\n", blocksize);
513*14f51593SDavid du Colombier 	if (debug)
514*14f51593SDavid du Colombier 		fprintf(stderr, "dialing address=%s\n", dialstr);
5157dd7cddfSDavid du Colombier 	printerfd = dial(dialstr, 0, 0, 0);
516*14f51593SDavid du Colombier 	if (printerfd < 0)
517*14f51593SDavid du Colombier 		exit(1);
5187dd7cddfSDavid du Colombier 
5197dd7cddfSDavid du Colombier 	fprintf(stderr, "printer startup\n");
5207dd7cddfSDavid du Colombier 
5217dd7cddfSDavid du Colombier 	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipefd) < 0) {
5227dd7cddfSDavid du Colombier 		perror("socketpair");
5237dd7cddfSDavid du Colombier 		exit(1);
5247dd7cddfSDavid du Colombier 	}
5257dd7cddfSDavid du Colombier 	switch(cpid = fork()){
5267dd7cddfSDavid du Colombier 	case -1:
5277dd7cddfSDavid du Colombier 		perror("fork error");
5287dd7cddfSDavid du Colombier 		exit(1);
529*14f51593SDavid du Colombier 	case 0:				/* child - to printer */
5307dd7cddfSDavid du Colombier 		close(pipefd[1]);
531*14f51593SDavid du Colombier 		sprv = sendfile(infd, printerfd, pipefd[0]);
532*14f51593SDavid du Colombier 		if (debug)
533*14f51593SDavid du Colombier 			fprintf(stderr, "to remote - exiting\n");
5347dd7cddfSDavid du Colombier 		exit(sprv);
535*14f51593SDavid du Colombier 	default:			/* parent - from printer */
5367dd7cddfSDavid du Colombier 		close(pipefd[0]);
537*14f51593SDavid du Colombier 		rprv = readprinter(printerfd, pipefd[1]);
538*14f51593SDavid du Colombier 		if (debug)
539*14f51593SDavid du Colombier 			fprintf(stderr, "from remote - exiting\n");
540*14f51593SDavid du Colombier 		while(wait(&sprv) != cpid)
541*14f51593SDavid du Colombier 			;
5427dd7cddfSDavid du Colombier 		exit(rprv|sprv);
5437dd7cddfSDavid du Colombier 	}
5447dd7cddfSDavid du Colombier }
545