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