1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 /*
31  *
32  * Conditionally compiled routines for setting up and reading the line. Things
33  * were getting out of hand with all the ifdefs, and even though this defeats
34  * part of the purpose of conditional complilation directives, I think it's easier
35  * to follow this way. Thanks to Alan Buckwalter for the System V DKHOST code.
36  *
37  * postio now can be run as separate read and write processes, but requires that
38  * you write a procedure called resetline() and perhaps modify readline() some.
39  * I've already tested the code on System V and it seems to work. Ninth Edition
40  * and BSD code may be missing.
41  *
42  * By request I've changed the way some of the setupline() procedures (eg. in the
43  * System V implementation) handle things when no line has been given. If line is
44  * NULL the new setupline() procedures try to continue, assuming whoever called
45  * postio connected stdout to the printer. Things will only work if we can read
46  * and write stdout!
47  *
48  */
49 
50 
51 #include <stdio.h>
52 #include <ctype.h>
53 #include <fcntl.h>
54 #include <signal.h>
55 #include <sys/types.h>
56 #include <errno.h>
57 
58 #include "ifdef.h"			/* conditional header file inclusion */
59 #include "gen.h"			/* general purpose definitions */
60 
61 FILE	*fp_ttyi = NULL, *fp_ttyo;
62 char	*ptr = mesg;
63 extern FILE *fp_log;
64 
65 
66 /*****************************************************************************/
67 
68 
69 #ifdef SYSV
70 void
setupline(void)71 setupline(void)
72 {
73     struct termio	termio;
74     struct termios	termios;
75     char buf[100];
76 
77 
78 /*
79  *
80  * Line initialization for SYSV. For now if no line is given (ie. line == NULL )
81  * we continue on as before using stdout as ttyi and ttyo. Doesn't work when we're
82  * running in interactive mode or forcing stuff that comes back from the printer
83  * to stdout. Both cases are now caught by a test that's been added to routine
84  * initialize(). The change is primarily for the version of lp that's available
85  * with SVR3.2.
86  *
87  */
88 
89 #ifdef DKHOST
90     if ( line != NULL && *line != '/' )  {
91 	if ( strncmp(line, "DK:", 3) == 0 )
92 	    line += 3;
93 	dkhost_connect();
94     } else
95 #endif
96 
97     if ( line == NULL ) {
98 	ttyi = fileno(stdout);
99     }
100     else if ( (ttyi = open(line, O_RDWR)) == -1 )
101 	error(FATAL, "can't open %s", line);
102 
103     if ( (ttyo = dup(ttyi)) == -1 ) {
104 	error(FATAL, "can't dup file descriptor for %s", line);
105     }
106 
107     if ( fcntl(ttyi, F_SETFL, O_NDELAY) == -1 ) {
108 	error(FATAL, "fcntl error - F_SETFL");
109     }
110 
111     if ( ioctl(ttyi, TCGETS, &termios) < 0 ) {
112     	if ( ioctl(ttyi, TCGETA, &termio) == -1 ) {
113 		error(FATAL, "ioctl error - TCGETA");
114     	}
115     	stopbits = (stopbits == 1) ? 0 : CSTOPB;
116 
117     	termio.c_iflag = IXON | IGNCR;
118     	termio.c_oflag = 0;
119     	termio.c_cflag = HUPCL | CREAD | CS8 | stopbits |
120 		((line != NULL) ? baudrate : (termio.c_cflag & CBAUD));
121     	termio.c_lflag = 0;
122     	termio.c_cc[VMIN] = termio.c_cc[VTIME] = 0;
123     	if ( ioctl(ttyi, TCSETA, &termio) == -1 ) {
124 		error(FATAL, "ioctl error - TCSETA");
125 	}
126     } else {
127     	stopbits = (stopbits == 1) ? 0 : CSTOPB;
128 
129     	termios.c_iflag = IXON | IGNCR;
130     	termios.c_oflag = 0;
131     	termios.c_cflag = HUPCL | CREAD | CS8 | stopbits |
132 		((line != NULL) ? baudrate : cfgetospeed(&termios));
133     	termios.c_lflag = 0;
134     	termios.c_cc[VMIN] = termios.c_cc[VTIME] = 0;
135     	if ( ioctl(ttyi, TCSETS, &termios) == -1 ) {
136 		error(FATAL, "ioctl error - TCSETS");
137 	}
138     }
139 
140     if ( ioctl(ttyi, TCFLSH, 2) == -1 ) {
141 	error(FATAL, "ioctl error - TCFLSH");
142     }
143     fp_ttyi = fdopen(ttyi, "r");
144 
145     if ( line == NULL ) {
146 	line = "stdout";
147     }
148 
149 }   /* End of setupline */
150 
151 
152 /*****************************************************************************/
153 
154 
155 int
resetline(void)156 resetline(void)
157 {
158 
159 
160     int			flags;		/* for turning O_NDELAY off */
161     struct termio	termio;		/* so we can reset flow control */
162 
163 
164 /*
165  *
166  * Only used if we're running the program as separate read and write processes.
167  * Called from split() after the initial connection has been made and returns
168  * TRUE if two processes should work. Don't know if the O_NDELAY stuff is really
169  * needed, but setting c_cc[VMIN] to 1 definitely is. If we leave it be (as a 0)
170  * the read in readline() won't block!
171  *
172  */
173 
174 
175     if ( (flags = fcntl(ttyi, F_GETFL, 0)) == -1 )
176 	error(FATAL, "fcntl error - F_GETFL");
177 
178     flags &= ~O_NDELAY;
179 
180     if ( fcntl(ttyi, F_SETFL, flags) == -1 )
181 	error(FATAL, "fcntl error - F_SETFL");
182 
183     if ( ioctl(ttyi, TCGETA, &termio) == -1 )
184 	error(FATAL, "ioctl error - TCGETA");
185 
186     termio.c_iflag &= ~IXANY;
187     termio.c_iflag |= IXON | IXOFF;
188     termio.c_cc[VMIN] = 1;
189     termio.c_cc[VTIME] = 0;
190 
191     if ( ioctl(ttyi, TCSETA, &termio) == -1 )
192 	error(FATAL, "ioctl error - TCSETA");
193 
194     return(TRUE);
195 
196 }   /* End of resetline */
197 
198 
199 /*****************************************************************************/
200 
201 
202 void
setupstdin(int mode)203 setupstdin(int mode)
204     /* what to do with stdin settings */
205 {
206     struct termio		termio;
207 
208     static int			saved = FALSE;
209     static struct termio	oldtermio;
210 
211 
212 /*
213  *
214  * Save (mode = 0), reset (mode = 1), or restore (mode = 2) the tty settings for
215  * stdin. Expect something like raw mode with no echo will be set up. Explicit
216  * code to ensure blocking reads probably isn't needed because blocksize is set
217  * to 1 when we're in interactive mode, but I've included it anyway.
218  *
219  */
220 
221 
222     if ( interactive == TRUE )
223 	switch ( mode )  {
224 	    case 0:
225 		if ( isatty(0) != 1 )
226 		    error(FATAL, "stdin not a terminal - can't run interactive mode");
227 		if ( ioctl(0, TCGETA, &oldtermio) == -1 )
228 		    error(FATAL, "can't save terminal settings");
229 		saved = TRUE;
230 		break;
231 
232 	    case 1:
233 		termio = oldtermio;
234 		termio.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL);
235 		termio.c_cc[VMIN] = 1;
236 		termio.c_cc[VTIME] = 0;
237 		ioctl(0, TCSETA, &termio);
238 		break;
239 
240 	    case 2:
241 		if ( saved == TRUE )
242 		    ioctl(0, TCSETA, &oldtermio);
243 		break;
244 	}   /* End switch */
245 
246 }   /* End of setupstdin */
247 
248 
249 /*****************************************************************************/
250 
251 
252 int
readline(void)253 readline(void)
254 {
255 
256 
257     int		n;			/* read() return value */
258     int		ch;			/* for interactive mode */
259 
260     static int	tries = 0;		/* consecutive times read returned 0 */
261 
262 
263 /*
264  *
265  * Reads characters coming back from the printer on ttyi up to a newline (or EOF)
266  * or until no more characters are available. Characters are put in mesg[], the
267  * string is terminated with '\0' when we're done with a line and TRUE is returned
268  * to the caller. If complete line wasn't available FALSE is returned. Interactive
269  * mode should loop here forever, except during start(), echoing characters to
270  * stdout. If it happens to leave FALSE should be returned. The non-blocking read
271  * gets us out until split() is called.
272  *
273  * Some users (apparently just on 3B2 DKHOST systems) have had problems with the
274  * two process implementation that's forced me to kludge things up some. When a
275  * printer (on those systems) is turned off while postio is transmitting files
276  * the write process hangs in writeblock() (postio.c) - it's typically in the
277  * middle of a write() call, while the read() call (below) continually returns 0.
278  * In the original code readline() returned FALSE when read() returned 0 and we
279  * get into a loop that never ends - because the write process is hung. In the
280  * one process implementation having read return 0 is legitimate because the line
281  * is opened for no delay, but with two processes the read() blocks and a return
282  * value of 0 should never occur. From my point of view the real problem is that
283  * the write() call hangs on 3B2 DKHOST systems and apparently doesn't anywhere
284  * else. If the write returned anything less than or equal to 0 writeblock() would
285  * shut things down. The kludge I've implemented counts the number of consecutive
286  * times read() returns a 0 and if it exceeds a limit (100) the read process will
287  * shut things down. In fact one return of 0 from read() when we're in the two
288  * process mode is undoubtedly sufficient and no counting should be necessary!!!
289  * Moving the check to getstatus() should also work and is probably where things
290  * belong.
291  *
292  */
293 
294     if ( interactive == FALSE )  {
295 	while ( (n = read(ttyi, ptr, 1)) != 0 )  {
296 	    if ( n < 0 )
297 		if ( errno == EINTR )
298 		    continue;
299 		else error(FATAL, "error reading %s", line);
300 	    tries = 0;
301 	    if ( *ptr == '\n' || *ptr == '\004' || ptr >= endmesg )  {
302 		*(ptr+1) = '\0';
303 		if ( *ptr == '\004' )
304 		    strcpy(ptr, "%%[ status: endofjob ]%%\n");
305 		ptr = mesg;
306 		return(TRUE);
307 	    }   /* End if */
308 	    ptr++;
309 	}   /* End while */
310 	if ( canread == TRUE && canwrite == FALSE )	/* read process kludge */
311 	    if ( ++tries > 100 )
312 		error(FATAL, "printer appears to be offline - shutting down");
313 	return(FALSE);
314     }	/* End if */
315 
316     if ( canwrite == TRUE )		/* don't block during start() */
317 	return(FALSE);
318 
319     while ( (ch = getc(fp_ttyi)) != EOF )
320 	putc(ch, stdout);
321     return(FALSE);
322 
323 }   /* End of readline */
324 #endif
325 
326 
327 /*****************************************************************************/
328 
329 
330 #ifdef V9
331 #include <ipc.h>
332 
333 char	tbuf[256];			/* temporary input buffer */
334 char	*nptr = tbuf;			/* next character comes from here */
335 char	*eptr = tbuf;			/* one past the last character in tbuf */
336 
337 
setupline()338 setupline()
339 
340 
341 {
342 
343 
344     struct sgttyb	sgtty;
345     struct ttydevb	ttydev;		/* for setting up the line */
346     static struct tchars	tchar = { '\377',	/* interrupt */
347 					  '\377',	/* quit */
348 					  '\021',	/* start output */
349 					  '\023',	/* stop output */
350 					  '\377',	/* end-of-file */
351 					  '\377'	/* input delimiter */
352 					};
353 
354 /*
355  *
356  * Line initialization for V9.
357  *
358  */
359 
360 
361     if ( line == NULL )  {
362 	ttyi = ttyo = 1;
363 	return;
364     }	/* End if */
365 
366     if ( strncmp(line, "/cs", 3) == 0 ) {
367 	if ((ttyi = ipcopen(line, "")) < 0) {
368 		sleep(5);	/* wait for Datakit to hangup */
369 		if ((ttyi = ipcopen(line, "")) < 0)
370 			error(FATAL, "can't ipcopen %s", line);
371 	}
372     } else if ( (ttyi = open(line, O_RDWR)) == -1 )
373 	error(FATAL, "can't open %s", line);
374 
375     if ( (ttyo = dup(ttyi)) == -1 )
376 	error(FATAL, "can't dup file descriptor for %s", line);
377 
378     if ( ioctl(ttyi, FIOPUSHLD, &tty_ld) == -1 )
379 	error(FATAL, "ioctl error - FIOPUSHLD");
380 
381     if ( ioctl(ttyi, TIOCGDEV, &ttydev) == -1 )
382 	error(FATAL, "ioctl error - TIOCGDEV");
383 
384     if ( ioctl(ttyi, TIOCGETP, &sgtty) == -1 )
385 	error(FATAL, "ioctl error - TIOCGETP");
386 
387     sgtty.sg_flags &= ~ECHO;
388     sgtty.sg_flags &= ~CRMOD;
389     sgtty.sg_flags |= CBREAK;
390     ttydev.ispeed = baudrate;
391     ttydev.ospeed = baudrate;
392 
393     if ( ioctl(ttyi, TIOCSDEV, &ttydev) == -1 )
394 	error(FATAL, "ioctl error - TIOCSDEV");
395 
396     if ( ioctl(ttyi, TIOCSETP, &sgtty) == -1 )
397 	error(FATAL, "ioctl error - TIOCSETP");
398 
399     if ( ioctl(ttyi, TIOCSETC, &tchar) == -1 )
400 	error(FATAL, "ioctl error - TIOCSETC");
401 
402     fp_ttyi = fdopen(ttyi, "r");
403 
404 }   /* End of setupline */
405 
406 
407 /*****************************************************************************/
408 
409 
resetline()410 resetline()
411 
412 
413 {
414 
415 
416     struct sgttyb	sgtty;
417 
418 
419 /*
420  *
421  * Only used if we're running the program as separate read and write processes.
422  * Called from split() after the initial connection has been made and returns
423  * TRUE if two processes should work. Haven't tested or even compiled the stuff
424  * for separate read and write processes on Ninth Edition systems - no guarantees
425  * even though we return TRUE!
426  *
427  */
428 
429 
430     if ( ioctl(ttyi, TIOCGETP, &sgtty) == -1 )
431 	error(FATAL, "ioctl error - TIOCGETP");
432 
433     sgtty.sg_flags |= TANDEM;
434 
435     if ( ioctl(ttyi, TIOCSETP, &sgtty) == -1 )
436 	error(FATAL, "ioctl error - TIOCSETP");
437 
438     return(TRUE);
439 
440 }   /* End of resetline */
441 
442 
443 /*****************************************************************************/
444 
445 
setupstdin(mode)446 setupstdin(mode)
447 
448 
449     int		mode;			/* what to do with stdin settings */
450 
451 
452 {
453 
454 
455     struct sgttyb		sgtty;
456 
457     static int			saved = FALSE;
458     static struct sgttyb	oldsgtty;
459 
460 
461 /*
462  *
463  * Save (mode = 0), reset (mode = 1), or restore (mode = 2) the tty settings for
464  * stdin. Expect something like raw mode with no echo will be set up. Need to make
465  * sure interrupt and quit still work - they're the only good way to exit when
466  * we're running interactive mode. I haven't tested or even compiled this code
467  * so there are no guarantees.
468  *
469  */
470 
471 
472     if ( interactive == TRUE )
473 	switch ( mode )  {
474 	    case 0:
475 		if ( ioctl(0, TIOCGETP, &oldsgtty) == -1 )
476 		    error(FATAL, "can't save terminal settings");
477 		saved = TRUE;
478 		break;
479 
480 	    case 1:
481 		sgtty = oldsgtty;
482 		sgtty.sg_flags &= ~ECHO;
483 		sgtty.sg_flags |= CBREAK;
484 		ioctl(0, TIOCSETP, &sgtty);
485 		break;
486 
487 	    case 2:
488 		if ( saved == TRUE )
489 		    ioctl(0, TIOCSETP, &oldsgtty);
490 		break;
491 	}   /* End switch */
492 
493 }   /* End of setupstdin */
494 
495 
496 /*****************************************************************************/
497 
498 
readline()499 readline()
500 
501 
502 {
503 
504 
505     int		n;			/* read() return value */
506     int		ch;			/* for interactive mode */
507 
508 
509 /*
510  *
511  * Reads characters coming back from the printer on ttyi up to a newline (or EOF)
512  * and transfers each line to the mesg[] array. Everything available on ttyi is
513  * initially stored in tbuf[] and a line at a time is transferred from there to
514  * mesg[]. The string in mesg[] is terminated with a '\0' and TRUE is returned to
515  * the caller when we find a newline, EOF, or reach the end of the mesg[] array.
516  * If nothing is available on ttyi we return FALSE if a single process is being
517  * used for reads and writes, while in the two process implementation we force a
518  * one character read. Interactive mode loops here forever, except during start(),
519  * echoing everything that comes back on ttyi to stdout. The performance of a
520  * simple getc/putc loop for interactive mode was unacceptable when run under mux
521  * and has been replaced by more complicated code. When layers wasn't involved
522  * the getc/putc loop worked well.
523  *
524  */
525 
526 
527     if ( interactive == FALSE )  {
528 	while ( 1 )  {
529 	    while ( nptr < eptr )  {	/* grab characters from tbuf */
530 		*ptr = *nptr++;
531 		if ( *ptr == '\r' ) continue;
532 		if ( *ptr == '\n' || *ptr == '\004' || ptr >= endmesg )  {
533 		    *(ptr+1) = '\0';
534 		    if ( *ptr == '\004' )
535 			strcpy(ptr, "%%[ status: endofjob ]%%\n");
536 		    ptr = mesg;
537 		    return(TRUE);
538 		}   /* End if */
539 		++ptr;
540 	    }	/* End for */
541 
542 	    nptr = eptr = tbuf;
543 	    if ( ioctl(ttyi, FIONREAD, &n) < 0 )
544 		if ( errno == EINTR )
545 		    continue;
546 		else error(FATAL, "ioctl error - FIONREAD");
547 	    if ( n <= 0 )
548 		if ( canwrite == TRUE )
549 		    return(FALSE);
550 	    n = ((n < 1) ? 1 : ((n < sizeof(tbuf)) ? n : sizeof(tbuf)));
551 	    if ( (n = read(ttyi, tbuf, n)) < 0 )
552 		if ( errno == EINTR )
553 		    continue;
554 		else error(FATAL, "error reading line %s", line);
555 	    else eptr = nptr + n;
556 	}   /* End while */
557     }	/* End if */
558 
559     if ( canwrite == TRUE )		/* don't block during start() */
560 	return(FALSE);
561 
562     while ( 1 )  {			/* only interactive mode gets here */
563 	if ( ioctl(ttyi, FIONREAD, &n) < 0 )
564 	    error(FATAL, "ioctl error - FIONREAD");
565 	n = ((n < 1) ? 1 : ((n < sizeof(tbuf)) ? n : sizeof(tbuf)));
566 	if ( (n = read(ttyi, tbuf, n)) < 0 )
567 	    error(FATAL, "error reading line %s", line);
568 	else if ( n == 0 )		/* should not happen */
569 	    error(FATAL, "end of file in interactive mode");
570 	if ( write(1, tbuf, n) != n )
571 	    error(FATAL, "error writing to stdout");
572     }	/* End while */
573 
574     return(FALSE);
575 
576 }   /* End of readline */
577 #endif
578 
579 
580 /*****************************************************************************/
581 
582 
583 #ifdef BSD4_2
setupline()584 setupline()
585 
586 
587 {
588 
589 
590     struct sgttyb	sgtty;
591     static struct tchars	tchar = { '\377',	/* interrupt */
592 					  '\377',	/* quit */
593 					  '\021',	/* start output */
594 					  '\023',	/* stop output */
595 					  '\377',	/* end-of-file */
596 					  '\377'	/* input delimiter */
597 					};
598     long	lmodes;
599     int		disc = NTTYDISC;
600 
601 
602 /*
603  *
604  * Line initialization for BSD4_2. As in the System V code, if no line is given
605  * (ie. line == NULL) we continue on as before using stdout as ttyi and ttyo.
606  *
607  */
608 
609 
610     if ( line == NULL )
611 	ttyi = fileno(stdout);
612     else if ( (ttyi = open(line, O_RDWR)) == -1 )
613 	error(FATAL, "can't open %s", line);
614 
615     if ( (ttyo = dup(ttyi)) == -1 )
616 	error(FATAL, "can't dup file descriptor for %s", line);
617 
618     if (ioctl(ttyi, TIOCSETD, &disc) == -1 )
619 	error(FATAL, "ioctl error - TIOCSETD");
620 
621     if ( ioctl(ttyi, TIOCGETP, &sgtty) == -1 )
622 	error(FATAL, "ioctl error - TIOCGETP");
623 
624     if ( ioctl(ttyi, TIOCLGET, &lmodes) == -1 )
625 	error(FATAL, "ioctl error - TIOCLGET");
626 
627     sgtty.sg_flags &= ~ECHO;
628     sgtty.sg_flags &= ~CRMOD;
629     sgtty.sg_flags |= CBREAK;
630     sgtty.sg_ispeed = baudrate;
631     sgtty.sg_ospeed = baudrate;
632     lmodes |= LDECCTQ;
633 
634     if ( ioctl(ttyi, TIOCSETP, &sgtty) == -1 )
635 	error(FATAL, "ioctl error - TIOCSETP");
636 
637     if ( ioctl(ttyi, TIOCSETC, &tchar) == -1 )
638 	error(FATAL, "ioctl error - TIOCSETC");
639 
640     if ( ioctl(ttyi, TIOCLSET, &lmodes) == -1 )
641 	error(FATAL, "ioctl error - TIOCLSET");
642 
643     fp_ttyi = fdopen(ttyi, "r");
644 
645 }   /* End of setupline */
646 
647 
648 /*****************************************************************************/
649 
650 
resetline()651 resetline()
652 
653 
654 {
655 
656 
657     struct sgttyb	sgtty;
658 
659 
660 /*
661  *
662  * Only used if we're running the program as separate read and write processes.
663  * Called from split() after the initial connection has been made and returns
664  * TRUE if two processes should work. Haven't tested or even compiled the stuff
665  * for separate read and write processes on Berkeley systems - no guarantees
666  * even though we return TRUE!
667  *
668  */
669 
670 
671     if ( ioctl(ttyi, TIOCGETP, &sgtty) == -1 )
672 	error(FATAL, "ioctl error - TIOCGETP");
673 
674     sgtty.sg_flags |= TANDEM;
675 
676     if ( ioctl(ttyi, TIOCSETP, &sgtty) == -1 )
677 	error(FATAL, "ioctl error - TIOCSETP");
678 
679     return(TRUE);
680 
681 }   /* End of resetline */
682 
683 
684 /*****************************************************************************/
685 
686 
setupstdin(mode)687 setupstdin(mode)
688 
689 
690     int		mode;			/* what to do with stdin settings */
691 
692 
693 {
694 
695 
696     struct sgttyb		sgtty;
697 
698     static int			saved = FALSE;
699     static struct sgttyb	oldsgtty;
700 
701 
702 /*
703  *
704  * Save (mode = 0), reset (mode = 1), or restore (mode = 2) the tty settings for
705  * stdin. Expect something like raw mode with no echo will be set up. Need to make
706  * sure interrupt and quit still work - they're the only good way to exit when
707  * we're running interactive mode. I haven't tested or even compiled this code
708  * so there are no guarantees.
709  *
710  */
711 
712 
713     if ( interactive == TRUE )
714 	switch ( mode )  {
715 	    case 0:
716 		if ( isatty(0) != 1 )
717 		    error(FATAL, "stdin not a terminal - can't run interactive mode");
718 		if ( ioctl(0, TIOCGETP, &oldsgtty) == -1 )
719 		    error(FATAL, "can't save terminal settings");
720 		saved = TRUE;
721 		break;
722 
723 	    case 1:
724 		sgtty = oldsgtty;
725 		sgtty.sg_flags &= ~ECHO;
726 		sgtty.sg_flags |= CBREAK;
727 		ioctl(0, TIOCSETP, &sgtty);
728 		break;
729 
730 	    case 2:
731 		if ( saved == TRUE )
732 		    ioctl(0, TIOCSETP, &oldsgtty);
733 		break;
734 	}   /* End switch */
735 
736 }   /* End of setupstdin */
737 
738 
739 /*****************************************************************************/
740 
741 
readline()742 readline()
743 
744 
745 {
746 
747 
748     int		n;			/* read() return value */
749     int		ch;			/* for interactive mode */
750 
751 
752 /*
753  *
754  * Reads characters coming back from the printer on ttyo up to a newline (or EOF)
755  * or until no more characters are available. Characters are put in mesg[], the
756  * string is terminated with '\0' when we're done with a line and TRUE is returned
757  * to the caller. If complete line wasn't available FALSE is returned. Interactive
758  * mode should loop here forever, except during start(), echoing characters to
759  * stdout. If it happens to leave FALSE should be returned. Probably should read
760  * everything available on ttyi into a temporary buffer and work from there rather
761  * than reading one character at a time.
762  *
763  */
764 
765 
766     if ( interactive == FALSE )  {
767 	while ( 1 )  {
768 	    if ( ioctl(ttyi, FIONREAD, &n) < 0 )
769 		if ( errno == EINTR )
770 		    continue;
771 		else error(FATAL, "ioctl error - FIONREAD");
772 	    if ( n <= 0 )
773 		if ( canwrite == TRUE )
774 		    return(FALSE);
775 		else n = 1;
776 	    for ( ; n > 0; n-- )  {
777 		/*if ( read(ttyi, ptr, 1) < 0 )*/
778 		if ( (*ptr = getc(fp_ttyi)) == EOF )
779 		    if ( errno == EINTR )
780 			continue;
781 		    else error(FATAL, "error reading %s", line);
782 		if ( *ptr == '\r' ) continue;
783 		if ( *ptr == '\n' || *ptr == '\004' || ptr >= endmesg )  {
784 		    *(ptr+1) = '\0';
785 		    if ( *ptr == '\004' )
786 			strcpy(ptr, "%%[ status: endofjob ]%%\n");
787 		    ptr = mesg;
788 		    return(TRUE);
789 		}   /* End if */
790 		++ptr;
791 	    }	/* End for */
792 	}   /* End while */
793     }	/* End if */
794 
795     if ( canwrite == TRUE )		/* don't block during start() */
796 	return(FALSE);
797 
798     while ( (ch = getc(fp_ttyi)) != EOF )
799 	putc(ch, stdout);
800     return(FALSE);
801 
802 }   /* End of readline */
803 
804 
805 /*****************************************************************************/
806 
807 
808 /*	@(#)strspn.c	1.2	*/
809 /*LINTLIBRARY*/
810 /*
811  * Return the number of characters in the maximum leading segment
812  * of string which consists solely of characters from charset.
813  */
814 int
strspn(string,charset)815 strspn(string, charset)
816 char	*string;
817 register char	*charset;
818 {
819 	register char *p, *q;
820 
821 	for(q=string; *q != '\0'; ++q) {
822 		for(p=charset; *p != '\0' && *p != *q; ++p)
823 			;
824 		if(*p == '\0')
825 			break;
826 	}
827 	return(q-string);
828 }
829 
830 /*	@(#)strpbrk.c	1.2	*/
831 /*LINTLIBRARY*/
832 /*
833  * Return ptr to first occurance of any character from `brkset'
834  * in the character string `string'; NULL if none exists.
835  */
836 
837 char *
strpbrk(string,brkset)838 strpbrk(string, brkset)
839 register char *string, *brkset;
840 {
841 	register char *p;
842 
843 	do {
844 		for(p=brkset; *p != '\0' && *p != *string; ++p)
845 			;
846 		if(*p != '\0')
847 			return(string);
848 	}
849 	while(*string++);
850 	return((char*)0);
851 }
852 
853 /*	@(#)strtok.c	1.2	*/
854 /*	3.0 SID #	1.2	*/
855 /*LINTLIBRARY*/
856 /*
857  * uses strpbrk and strspn to break string into tokens on
858  * sequentially subsequent calls.  returns NULL when no
859  * non-separator characters remain.
860  * `subsequent' calls are calls with first argument NULL.
861  */
862 
863 
864 extern int strspn();
865 extern char *strpbrk();
866 
867 char *
strtok(string,sepset)868 strtok(string, sepset)
869 char	*string, *sepset;
870 {
871 	register char	*p, *q, *r;
872 	static char	*savept;
873 
874 	/*first or subsequent call*/
875 	p = (string == (char*)0)? savept: string;
876 
877 	if(p == 0)		/* return if no tokens remaining */
878 		return((char*)0);
879 
880 	q = p + strspn(p, sepset);	/* skip leading separators */
881 
882 	if(*q == '\0')		/* return if no tokens remaining */
883 		return((char*)0);
884 
885 	if((r = strpbrk(q, sepset)) == (char*)0)	/* move past token */
886 		savept = 0;	/* indicate this is last token */
887 	else {
888 		*r = '\0';
889 		savept = ++r;
890 	}
891 	return(q);
892 }
893 #endif
894 
895 
896 /*****************************************************************************/
897 
898 
899 #ifdef DKHOST
900 
901 short	dkrmode[3] = {DKR_TIME, 0, 0};
902 
dkhost_connect()903 dkhost_connect()
904 
905 
906 {
907 
908 
909     int		ofd;			/* for saving and restoring stderr */
910     int		dfd;
911     int		retrytime = 5;
912 
913 
914 /*
915  *
916  * Tries to connect to a Datakit destination. The extra stuff I've added to save
917  * and later restore stderr is primarily for our spooling setup at Murray Hill.
918  * postio is usually called with stderr directed to a file that will be returned
919  * to the user when the job finishes printing. Problems encountered by dkdial(),
920  * like busy messages, go to stderr but don't belong in the user's mail. They'll
921  * be temporarily directed to the log file. After we've connected stderr will be
922  * restored.
923  *
924  */
925 
926 
927     if ( *line == '\0' )
928 	error(FATAL, "incomplete Datakit line");
929 
930     if ( fp_log != stderr )  {		/* save stderr - redirect dkdial errors */
931 	ofd = dup(2);
932 	close(2);
933 	dup(fileno(fp_log));
934     }	/* End if */
935 
936     while ( (dfd = ttyi = dkdial(line)) < 0 )  {
937 	if ( retrytime < 0 )
938 	    error(FATAL, "can't connect to %s", line);
939 	sleep(retrytime++);
940 	if ( retrytime > 60 )
941 	    retrytime = 60;
942     }	/* End while */
943 
944     if ( fp_log != stderr )  {		/* restore stderr */
945 	close(2);
946 	dup(ofd);
947 	close(ofd);
948     }	/* End if */
949 
950     if ( ioctl(ttyi, DIOCRMODE, dkrmode) == -1 )
951 	error(FATAL, "ioctl error - DIOCRMODE");
952 
953     line = dtnamer(dkminor(ttyi));
954 
955     if ( (ttyi = open(line, O_RDWR)) == -1 )
956 	error(FATAL, "can't open %s", line);
957 
958     close(dfd);
959 
960 }   /* End of dkhost_connect */
961 #endif
962 
963 
964 /*****************************************************************************/
965 
966