xref: /csrg-svn/usr.bin/telnet/sys_bsd.c (revision 46808)
132147Sminshall /*
245233Sborman  * Copyright (c) 1988, 1990 Regents of the University of California.
333685Sbostic  * All rights reserved.
433685Sbostic  *
542770Sbostic  * %sccs.include.redist.c%
633685Sbostic  */
733685Sbostic 
833685Sbostic #ifndef lint
9*46808Sdab static char sccsid[] = "@(#)sys_bsd.c	5.2 (Berkeley) 03/01/91";
1033685Sbostic #endif /* not lint */
1133685Sbostic 
1233685Sbostic /*
1332147Sminshall  * The following routines try to encapsulate what is system dependent
1432147Sminshall  * (at least between 4.x and dos) which is used in telnet.c.
1532147Sminshall  */
1632147Sminshall 
1732147Sminshall 
1836274Sminshall #include <fcntl.h>
1932381Sminshall #include <sys/types.h>
2032147Sminshall #include <sys/time.h>
2132531Sminshall #include <sys/socket.h>
2232147Sminshall #include <signal.h>
2332531Sminshall #include <errno.h>
2438689Sborman #include <arpa/telnet.h>
2532147Sminshall 
2632381Sminshall #include "ring.h"
2732381Sminshall 
2832657Sminshall #include "fdset.h"
2932657Sminshall 
3032147Sminshall #include "defines.h"
3132147Sminshall #include "externs.h"
3232147Sminshall #include "types.h"
3332147Sminshall 
3445233Sborman #if	defined(CRAY) || (defined(USE_TERMIO) && !defined(SYSV_TERMIO))
3540245Sborman #define	SIG_FUNC_RET	void
3640245Sborman #else
3740245Sborman #define	SIG_FUNC_RET	int
3840245Sborman #endif
3940245Sborman 
4032147Sminshall int
4132531Sminshall 	tout,			/* Output file descriptor */
4232531Sminshall 	tin,			/* Input file descriptor */
4336242Sminshall 	net;
4432147Sminshall 
4538689Sborman #ifndef	USE_TERMIO
4638689Sborman struct	tchars otc = { 0 }, ntc = { 0 };
4738689Sborman struct	ltchars oltc = { 0 }, nltc = { 0 };
4838689Sborman struct	sgttyb ottyb = { 0 }, nttyb = { 0 };
4938909Sborman int	olmode = 0;
5045233Sborman # define cfgetispeed(ptr)	(ptr)->sg_ispeed
5145233Sborman # define cfgetospeed(ptr)	(ptr)->sg_ospeed
5245233Sborman # define old_tc ottyb
5332147Sminshall 
5438689Sborman #else	/* USE_TERMIO */
5538689Sborman struct	termio old_tc = { 0 };
5638689Sborman extern struct termio new_tc;
5738689Sborman 
5845233Sborman # ifndef	TCSANOW
5945233Sborman #  ifdef TCSETS
6045233Sborman #   define	TCSANOW		TCSETS
6145233Sborman #   define	TCSADRAIN	TCSETSW
62*46808Sdab #   define	tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
6345233Sborman #  else
6445233Sborman #   ifdef TCSETA
6545233Sborman #    define	TCSANOW		TCSETA
6645233Sborman #    define	TCSADRAIN	TCSETAW
67*46808Sdab #    define	tcgetattr(f, t) ioctl(f, TCGETA, (char *)t)
6845233Sborman #   else
6945233Sborman #    define	TCSANOW		TIOCSETA
7045233Sborman #    define	TCSADRAIN	TIOCSETAW
71*46808Sdab #    define	tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t)
7245233Sborman #   endif
7345233Sborman #  endif
74*46808Sdab #  define	tcsetattr(f, a, t) ioctl(f, a, (char *)t)
7545233Sborman #  define	cfgetospeed(ptr)	((ptr)->c_cflag&CBAUD)
7645233Sborman #  ifdef CIBAUD
7745233Sborman #   define	cfgetispeed(ptr)	(((ptr)->c_cflag&CIBAUD) >> IBSHIFT)
7845233Sborman #  else
7945233Sborman #   define	cfgetispeed(ptr)	cfgetospeed(ptr)
8045233Sborman #  endif
8145233Sborman # endif /* TCSANOW */
8238689Sborman #endif	/* USE_TERMIO */
8338689Sborman 
8432531Sminshall static fd_set ibits, obits, xbits;
8532147Sminshall 
8632531Sminshall 
87*46808Sdab     void
8832531Sminshall init_sys()
8932531Sminshall {
9032531Sminshall     tout = fileno(stdout);
9132531Sminshall     tin = fileno(stdin);
9232531Sminshall     FD_ZERO(&ibits);
9332531Sminshall     FD_ZERO(&obits);
9432531Sminshall     FD_ZERO(&xbits);
9532531Sminshall 
9632531Sminshall     errno = 0;
9732531Sminshall }
9832531Sminshall 
9932531Sminshall 
100*46808Sdab     int
10133286Sminshall TerminalWrite(buf, n)
102*46808Sdab     char *buf;
103*46808Sdab     int  n;
10432147Sminshall {
10533286Sminshall     return write(tout, buf, n);
10632147Sminshall }
10732147Sminshall 
108*46808Sdab     int
10933286Sminshall TerminalRead(buf, n)
110*46808Sdab     char *buf;
111*46808Sdab     int  n;
11232147Sminshall {
11333286Sminshall     return read(tin, buf, n);
11432147Sminshall }
11532147Sminshall 
11632147Sminshall /*
11732147Sminshall  *
11832147Sminshall  */
11932147Sminshall 
120*46808Sdab     int
12132553Sminshall TerminalAutoFlush()
12232147Sminshall {
12332147Sminshall #if	defined(LNOFLSH)
12432147Sminshall     int flush;
12532147Sminshall 
12632147Sminshall     ioctl(0, TIOCLGET, (char *)&flush);
12732147Sminshall     return !(flush&LNOFLSH);	/* if LNOFLSH, no autoflush */
12832147Sminshall #else	/* LNOFLSH */
12932147Sminshall     return 1;
13032147Sminshall #endif	/* LNOFLSH */
13132147Sminshall }
13232147Sminshall 
13338689Sborman #ifdef	KLUDGELINEMODE
13438689Sborman extern int kludgelinemode;
13538689Sborman #endif
13632147Sminshall /*
13732147Sminshall  * TerminalSpecialChars()
13832147Sminshall  *
13932147Sminshall  * Look at an input character to see if it is a special character
14032147Sminshall  * and decide what to do.
14132147Sminshall  *
14232147Sminshall  * Output:
14332147Sminshall  *
14432147Sminshall  *	0	Don't add this character.
14532147Sminshall  *	1	Do add this character
14632147Sminshall  */
14732147Sminshall 
148*46808Sdab     int
14932553Sminshall TerminalSpecialChars(c)
150*46808Sdab     int	c;
15132147Sminshall {
15232553Sminshall     void xmitAO(), xmitEL(), xmitEC(), intp(), sendbrk();
15332147Sminshall 
15438689Sborman     if (c == termIntChar) {
15532147Sminshall 	intp();
15632147Sminshall 	return 0;
15738689Sborman     } else if (c == termQuitChar) {
15838689Sborman #ifdef	KLUDGELINEMODE
15938689Sborman 	if (kludgelinemode)
16038689Sborman 	    sendbrk();
16138689Sborman 	else
16238689Sborman #endif
16338689Sborman 	    sendabort();
16432147Sminshall 	return 0;
16538689Sborman     } else if (c == termEofChar) {
16638689Sborman 	if (my_want_state_is_will(TELOPT_LINEMODE)) {
16738689Sborman 	    sendeof();
16838689Sborman 	    return 0;
16938689Sborman 	}
17038689Sborman 	return 1;
17138689Sborman     } else if (c == termSuspChar) {
17238689Sborman 	sendsusp();
17338689Sborman 	return(0);
17438689Sborman     } else if (c == termFlushChar) {
17532147Sminshall 	xmitAO();		/* Transmit Abort Output */
17632147Sminshall 	return 0;
17732147Sminshall     } else if (!MODE_LOCAL_CHARS(globalmode)) {
17838689Sborman 	if (c == termKillChar) {
17932147Sminshall 	    xmitEL();
18032147Sminshall 	    return 0;
18138689Sborman 	} else if (c == termEraseChar) {
18232147Sminshall 	    xmitEC();		/* Transmit Erase Character */
18332147Sminshall 	    return 0;
18432147Sminshall 	}
18532147Sminshall     }
18632147Sminshall     return 1;
18732147Sminshall }
18832147Sminshall 
18932147Sminshall 
19032147Sminshall /*
19132147Sminshall  * Flush output to the terminal
19232147Sminshall  */
19332147Sminshall 
194*46808Sdab     void
19532553Sminshall TerminalFlushOutput()
19632147Sminshall {
19739529Sborman #ifdef	TIOCFLUSH
19832147Sminshall     (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0);
19938689Sborman #else
20038689Sborman     (void) ioctl(fileno(stdout), TCFLSH, (char *) 0);
20138689Sborman #endif
20232147Sminshall }
20332147Sminshall 
204*46808Sdab     void
20532553Sminshall TerminalSaveState()
20632147Sminshall {
20738689Sborman #ifndef	USE_TERMIO
20832147Sminshall     ioctl(0, TIOCGETP, (char *)&ottyb);
20932147Sminshall     ioctl(0, TIOCGETC, (char *)&otc);
21032147Sminshall     ioctl(0, TIOCGLTC, (char *)&oltc);
21138909Sborman     ioctl(0, TIOCLGET, (char *)&olmode);
21232147Sminshall 
21332147Sminshall     ntc = otc;
21432147Sminshall     nltc = oltc;
21532147Sminshall     nttyb = ottyb;
21632254Sminshall 
21738689Sborman #else	/* USE_TERMIO */
21845233Sborman     tcgetattr(0, &old_tc);
21938689Sborman 
22038689Sborman     new_tc = old_tc;
22138689Sborman 
22245233Sborman #ifndef	VDISCARD
22344361Sborman     termFlushChar = CONTROL('O');
22445233Sborman #endif
22545233Sborman #ifndef	VWERASE
22644361Sborman     termWerasChar = CONTROL('W');
22745233Sborman #endif
22845233Sborman #ifndef	VREPRINT
22944361Sborman     termRprntChar = CONTROL('R');
23045233Sborman #endif
23145233Sborman #ifndef	VLNEXT
23244361Sborman     termLiteralNextChar = CONTROL('V');
23345233Sborman #endif
23445233Sborman #ifndef	VSTART
23544361Sborman     termStartChar = CONTROL('Q');
23645233Sborman #endif
23745233Sborman #ifndef	VSTOP
23844361Sborman     termStopChar = CONTROL('S');
23945233Sborman #endif
24045233Sborman #ifndef	VSTATUS
24145233Sborman     termAytChar = CONTROL('T');
24245233Sborman #endif
24338689Sborman #endif	/* USE_TERMIO */
24432147Sminshall }
24532147Sminshall 
246*46808Sdab     cc_t *
24738689Sborman tcval(func)
248*46808Sdab     register int func;
24938689Sborman {
25038689Sborman     switch(func) {
25140245Sborman     case SLC_IP:	return(&termIntChar);
25240245Sborman     case SLC_ABORT:	return(&termQuitChar);
25340245Sborman     case SLC_EOF:	return(&termEofChar);
25440245Sborman     case SLC_EC:	return(&termEraseChar);
25540245Sborman     case SLC_EL:	return(&termKillChar);
25640245Sborman     case SLC_XON:	return(&termStartChar);
25740245Sborman     case SLC_XOFF:	return(&termStopChar);
25844361Sborman     case SLC_FORW1:	return(&termForw1Char);
25945233Sborman #ifdef	USE_TERMIO
26045233Sborman     case SLC_FORW2:	return(&termForw2Char);
26145233Sborman # ifdef	VDISCARD
26240245Sborman     case SLC_AO:	return(&termFlushChar);
26345233Sborman # endif
26445233Sborman # ifdef	VSUSP
26540245Sborman     case SLC_SUSP:	return(&termSuspChar);
26645233Sborman # endif
26745233Sborman # ifdef	VWERASE
26840245Sborman     case SLC_EW:	return(&termWerasChar);
26945233Sborman # endif
27045233Sborman # ifdef	VREPRINT
27140245Sborman     case SLC_RP:	return(&termRprntChar);
27245233Sborman # endif
27345233Sborman # ifdef	VLNEXT
27440245Sborman     case SLC_LNEXT:	return(&termLiteralNextChar);
27545233Sborman # endif
27645233Sborman # ifdef	VSTATUS
27745233Sborman     case SLC_AYT:	return(&termAytChar);
27845233Sborman # endif
27944361Sborman #endif
28038689Sborman 
28138689Sborman     case SLC_SYNCH:
28238689Sborman     case SLC_BRK:
28338689Sborman     case SLC_EOR:
28438689Sborman     default:
28540245Sborman 	return((cc_t *)0);
28638689Sborman     }
28738689Sborman }
28838689Sborman 
289*46808Sdab     void
29038689Sborman TerminalDefaultChars()
29138689Sborman {
29238689Sborman #ifndef	USE_TERMIO
29338689Sborman     ntc = otc;
29438689Sborman     nltc = oltc;
29538689Sborman     nttyb.sg_kill = ottyb.sg_kill;
29638689Sborman     nttyb.sg_erase = ottyb.sg_erase;
29738689Sborman #else	/* USE_TERMIO */
29838689Sborman     memcpy(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc));
29945233Sborman # ifndef	VDISCARD
30044361Sborman     termFlushChar = CONTROL('O');
30139529Sborman # endif
30239529Sborman # ifndef	VWERASE
30344361Sborman     termWerasChar = CONTROL('W');
30439529Sborman # endif
30539529Sborman # ifndef	VREPRINT
30644361Sborman     termRprntChar = CONTROL('R');
30739529Sborman # endif
30839529Sborman # ifndef	VLNEXT
30944361Sborman     termLiteralNextChar = CONTROL('V');
31039529Sborman # endif
31139529Sborman # ifndef	VSTART
31244361Sborman     termStartChar = CONTROL('Q');
31339529Sborman # endif
31439529Sborman # ifndef	VSTOP
31544361Sborman     termStopChar = CONTROL('S');
31639529Sborman # endif
31745233Sborman # ifndef	VSTATUS
31845233Sborman     termAytChar = CONTROL('T');
31945233Sborman # endif
32038689Sborman #endif	/* USE_TERMIO */
32138689Sborman }
32238689Sborman 
32344361Sborman #ifdef notdef
32438689Sborman void
32532553Sminshall TerminalRestoreState()
32632147Sminshall {
32732147Sminshall }
32844361Sborman #endif
32932147Sminshall 
33032147Sminshall /*
33132147Sminshall  * TerminalNewMode - set up terminal to a specific mode.
33238689Sborman  *	MODE_ECHO: do local terminal echo
33338689Sborman  *	MODE_FLOW: do local flow control
33438689Sborman  *	MODE_TRAPSIG: do local mapping to TELNET IAC sequences
33538689Sborman  *	MODE_EDIT: do local line editing
33638689Sborman  *
33738689Sborman  *	Command mode:
33838689Sborman  *		MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG
33938689Sborman  *		local echo
34038689Sborman  *		local editing
34138689Sborman  *		local xon/xoff
34238689Sborman  *		local signal mapping
34338689Sborman  *
34438689Sborman  *	Linemode:
34538689Sborman  *		local/no editing
34638689Sborman  *	Both Linemode and Single Character mode:
34738689Sborman  *		local/remote echo
34838689Sborman  *		local/no xon/xoff
34938689Sborman  *		local/no signal mapping
35032147Sminshall  */
35132147Sminshall 
35232147Sminshall 
353*46808Sdab     void
35433286Sminshall TerminalNewMode(f)
355*46808Sdab     register int f;
35632147Sminshall {
35732147Sminshall     static int prevmode = 0;
35838689Sborman #ifndef	USE_TERMIO
35938689Sborman     struct tchars tc;
36038689Sborman     struct ltchars ltc;
36132147Sminshall     struct sgttyb sb;
36238909Sborman     int lmode;
36338689Sborman #else	/* USE_TERMIO */
36438689Sborman     struct termio tmp_tc;
36538689Sborman #endif	/* USE_TERMIO */
36632147Sminshall     int onoff;
36732147Sminshall     int old;
368*46808Sdab     cc_t esc;
36932147Sminshall 
37038689Sborman     globalmode = f&~MODE_FORCE;
37132147Sminshall     if (prevmode == f)
37232147Sminshall 	return;
37338689Sborman 
37438689Sborman     /*
37538689Sborman      * Write any outstanding data before switching modes
37638689Sborman      * ttyflush() returns 0 only when there is no more data
37738689Sborman      * left to write out, it returns -1 if it couldn't do
37838689Sborman      * anything at all, otherwise it returns 1 + the number
37938689Sborman      * of characters left to write.
38045233Sborman #ifndef	USE_TERMIO
38145233Sborman      * We would really like ask the kernel to wait for the output
38245233Sborman      * to drain, like we can do with the TCSADRAIN, but we don't have
38345233Sborman      * that option.  The only ioctl that waits for the output to
38445233Sborman      * drain, TIOCSETP, also flushes the input queue, which is NOT
38545233Sborman      * what we want (TIOCSETP is like TCSADFLUSH).
38645233Sborman #endif
38738689Sborman      */
38838689Sborman     old = ttyflush(SYNCHing|flushout);
38938689Sborman     if (old < 0 || old > 1) {
39045233Sborman #ifdef	USE_TERMIO
391*46808Sdab 	tcgetattr(tin, &tmp_tc);
39238689Sborman #endif	/* USE_TERMIO */
39338689Sborman 	do {
39438689Sborman 	    /*
39538689Sborman 	     * Wait for data to drain, then flush again.
39638689Sborman 	     */
39745233Sborman #ifdef	USE_TERMIO
398*46808Sdab 	    tcsetattr(tin, TCSADRAIN, &tmp_tc);
39938689Sborman #endif	/* USE_TERMIO */
40038689Sborman 	    old = ttyflush(SYNCHing|flushout);
40138689Sborman 	} while (old < 0 || old > 1);
40238689Sborman     }
40338689Sborman 
40432147Sminshall     old = prevmode;
40538689Sborman     prevmode = f&~MODE_FORCE;
40638689Sborman #ifndef	USE_TERMIO
40732147Sminshall     sb = nttyb;
40838689Sborman     tc = ntc;
40938689Sborman     ltc = nltc;
41038909Sborman     lmode = olmode;
41138689Sborman #else
41238689Sborman     tmp_tc = new_tc;
41338689Sborman #endif
41432147Sminshall 
41538689Sborman     if (f&MODE_ECHO) {
41638689Sborman #ifndef	USE_TERMIO
41738689Sborman 	sb.sg_flags |= ECHO;
41838689Sborman #else
41938689Sborman 	tmp_tc.c_lflag |= ECHO;
42038689Sborman 	tmp_tc.c_oflag |= ONLCR;
421*46808Sdab 	if (crlf)
422*46808Sdab 		tmp_tc.c_iflag |= ICRNL;
42338689Sborman #endif
42438689Sborman     } else {
42538689Sborman #ifndef	USE_TERMIO
42638689Sborman 	sb.sg_flags &= ~ECHO;
42738689Sborman #else
42838689Sborman 	tmp_tc.c_lflag &= ~ECHO;
42938689Sborman 	tmp_tc.c_oflag &= ~ONLCR;
43039529Sborman # ifdef notdef
431*46808Sdab 	if (crlf)
432*46808Sdab 		tmp_tc.c_iflag &= ~ICRNL;
43339529Sborman # endif
43438689Sborman #endif
43538689Sborman     }
43632147Sminshall 
43738689Sborman     if ((f&MODE_FLOW) == 0) {
43838689Sborman #ifndef	USE_TERMIO
43945233Sborman 	tc.t_startc = _POSIX_VDISABLE;
44045233Sborman 	tc.t_stopc = _POSIX_VDISABLE;
44138689Sborman #else
44238689Sborman 	tmp_tc.c_iflag &= ~(IXANY|IXOFF|IXON);
44338689Sborman     } else {
44438689Sborman 	tmp_tc.c_iflag |= IXANY|IXOFF|IXON;
44538689Sborman #endif
44638689Sborman     }
44732147Sminshall 
44838689Sborman     if ((f&MODE_TRAPSIG) == 0) {
44938689Sborman #ifndef	USE_TERMIO
45045233Sborman 	tc.t_intrc = _POSIX_VDISABLE;
45145233Sborman 	tc.t_quitc = _POSIX_VDISABLE;
45245233Sborman 	tc.t_eofc = _POSIX_VDISABLE;
45345233Sborman 	ltc.t_suspc = _POSIX_VDISABLE;
45445233Sborman 	ltc.t_dsuspc = _POSIX_VDISABLE;
45538689Sborman #else
45638689Sborman 	tmp_tc.c_lflag &= ~ISIG;
45738689Sborman #endif
45838689Sborman 	localchars = 0;
45938689Sborman     } else {
46038689Sborman #ifdef	USE_TERMIO
46138689Sborman 	tmp_tc.c_lflag |= ISIG;
46238689Sborman #endif
46338689Sborman 	localchars = 1;
46438689Sborman     }
46538689Sborman 
46638689Sborman     if (f&MODE_EDIT) {
46738689Sborman #ifndef	USE_TERMIO
46838689Sborman 	sb.sg_flags &= ~CBREAK;
46938689Sborman 	sb.sg_flags |= CRMOD;
47038689Sborman #else
47138689Sborman 	tmp_tc.c_lflag |= ICANON;
47238689Sborman #endif
47338689Sborman     } else {
47438689Sborman #ifndef	USE_TERMIO
47538689Sborman 	sb.sg_flags |= CBREAK;
47638689Sborman 	if (f&MODE_ECHO)
47732147Sminshall 	    sb.sg_flags |= CRMOD;
47838689Sborman 	else
47938689Sborman 	    sb.sg_flags &= ~CRMOD;
48038689Sborman #else
48138689Sborman 	tmp_tc.c_lflag &= ~ICANON;
48238689Sborman 	tmp_tc.c_iflag &= ~ICRNL;
48338689Sborman 	tmp_tc.c_cc[VMIN] = 1;
48438689Sborman 	tmp_tc.c_cc[VTIME] = 0;
48538689Sborman #endif
48638689Sborman     }
48732147Sminshall 
48844361Sborman     if ((f&(MODE_EDIT|MODE_TRAPSIG)) == 0) {
48944361Sborman #ifndef	USE_TERMIO
49045233Sborman 	ltc.t_lnextc = _POSIX_VDISABLE;
49144361Sborman #else
49244361Sborman # ifdef VLNEXT
49345233Sborman 	tmp_tc.c_cc[VLNEXT] = (cc_t)(_POSIX_VDISABLE);
49444361Sborman # endif
49544361Sborman #endif
49644361Sborman     }
49744361Sborman 
49844361Sborman     if (f&MODE_SOFT_TAB) {
49944361Sborman #ifndef USE_TERMIO
50044361Sborman 	sb.sg_flags |= XTABS;
50144361Sborman #else
50244361Sborman # ifdef	OXTABS
50344361Sborman 	tmp_tc.c_oflag |= OXTABS;
50444361Sborman # endif
50544361Sborman # ifdef	TABDLY
50644361Sborman 	tmp_tc.c_oflag &= ~TABDLY;
50744361Sborman 	tmp_tc.c_oflag |= TAB3;
50844361Sborman # endif
50944361Sborman #endif
51044361Sborman     } else {
51144361Sborman #ifndef USE_TERMIO
51244361Sborman 	sb.sg_flags &= ~XTABS;
51344361Sborman #else
51444361Sborman # ifdef	OXTABS
51544361Sborman 	tmp_tc.c_oflag &= ~OXTABS;
51644361Sborman # endif
51744361Sborman # ifdef	TABDLY
51844361Sborman 	tmp_tc.c_oflag &= ~TABDLY;
51944361Sborman # endif
52044361Sborman #endif
52144361Sborman     }
52244361Sborman 
52344361Sborman     if (f&MODE_LIT_ECHO) {
52444361Sborman #ifndef USE_TERMIO
525*46808Sdab 	lmode &= ~LCTLECH;
52644361Sborman #else
52744361Sborman # ifdef	ECHOCTL
52844361Sborman 	tmp_tc.c_lflag &= ~ECHOCTL;
52944361Sborman # endif
53044361Sborman #endif
53144361Sborman     } else {
53244361Sborman #ifndef USE_TERMIO
533*46808Sdab 	lmode |= LCTLECH;
53444361Sborman #else
53544361Sborman # ifdef	ECHOCTL
53644361Sborman 	tmp_tc.c_lflag |= ECHOCTL;
53744361Sborman # endif
53844361Sborman #endif
53944361Sborman     }
54044361Sborman 
54138689Sborman     if (f == -1) {
54238689Sborman 	onoff = 0;
54338689Sborman     } else {
54438909Sborman #ifndef	USE_TERMIO
54539529Sborman 	if (f & MODE_OUTBIN)
54638909Sborman 		lmode |= LLITOUT;
54738909Sborman 	else
54838909Sborman 		lmode &= ~LLITOUT;
54939529Sborman 
55039529Sborman 	if (f & MODE_INBIN)
55138909Sborman 		lmode |= LPASS8;
55238909Sborman 	else
55338909Sborman 		lmode &= ~LPASS8;
55438909Sborman #else
55545233Sborman 	if (f & MODE_INBIN)
55645233Sborman 		tmp_tc.c_iflag &= ~ISTRIP;
55738909Sborman 	else
55845233Sborman 		tmp_tc.c_iflag |= ISTRIP;
55945233Sborman 	if (f & MODE_OUTBIN) {
56039529Sborman 		tmp_tc.c_cflag &= ~(CSIZE|PARENB);
56139529Sborman 		tmp_tc.c_cflag |= CS8;
56245233Sborman 		tmp_tc.c_oflag &= ~OPOST;
56339529Sborman 	} else {
56445233Sborman 		tmp_tc.c_cflag &= ~(CSIZE|PARENB);
56545233Sborman 		tmp_tc.c_cflag |= old_tc.c_cflag & (CSIZE|PARENB);
56645233Sborman 		tmp_tc.c_oflag |= OPOST;
56739529Sborman 	}
56838909Sborman #endif
56938689Sborman 	onoff = 1;
57032147Sminshall     }
57138689Sborman 
57238689Sborman     if (f != -1) {
57339529Sborman #ifdef	SIGTSTP
57445233Sborman 	static SIG_FUNC_RET susp();
57545233Sborman #endif	/* SIGTSTP */
57645233Sborman #ifdef	SIGINFO
57745233Sborman 	static SIG_FUNC_RET ayt();
57845233Sborman #endif	SIGINFO
57938689Sborman 
58045233Sborman #ifdef	SIGTSTP
58145233Sborman 	(void) signal(SIGTSTP, susp);
58239529Sborman #endif	/* SIGTSTP */
58345233Sborman #ifdef	SIGINFO
58445233Sborman 	(void) signal(SIGINFO, ayt);
58545233Sborman #endif	SIGINFO
58645233Sborman #if	defined(USE_TERMIO) && defined(NOKERNINFO)
58745233Sborman 	tmp_tc.c_lflag |= NOKERNINFO;
58845233Sborman #endif
58944361Sborman 	/*
59044361Sborman 	 * We don't want to process ^Y here.  It's just another
59144361Sborman 	 * character that we'll pass on to the back end.  It has
59244361Sborman 	 * to process it because it will be processed when the
59344361Sborman 	 * user attempts to read it, not when we send it.
59444361Sborman 	 */
59544361Sborman #ifndef	USE_TERMIO
59645233Sborman 	ltc.t_dsuspc = _POSIX_VDISABLE;
59744361Sborman #else
59844361Sborman # ifdef	VDSUSP
59945233Sborman 	tmp_tc.c_cc[VDSUSP] = (cc_t)(_POSIX_VDISABLE);
60044361Sborman # endif
60144361Sborman #endif
60240245Sborman #ifdef	USE_TERMIO
60340245Sborman 	/*
60440245Sborman 	 * If the VEOL character is already set, then use VEOL2,
60540245Sborman 	 * otherwise use VEOL.
60640245Sborman 	 */
607*46808Sdab 	esc = (rlogin != _POSIX_VDISABLE) ? rlogin : escape;
608*46808Sdab 	if ((tmp_tc.c_cc[VEOL] != esc)
60944361Sborman # ifdef	VEOL2
610*46808Sdab 	    && (tmp_tc.c_cc[VEOL2] != esc)
61144361Sborman # endif
612*46808Sdab 	    ) {
61345233Sborman 		if (tmp_tc.c_cc[VEOL] == (cc_t)(_POSIX_VDISABLE))
614*46808Sdab 		    tmp_tc.c_cc[VEOL] = esc;
61545233Sborman # ifdef	VEOL2
61645233Sborman 		else if (tmp_tc.c_cc[VEOL2] == (cc_t)(_POSIX_VDISABLE))
617*46808Sdab 		    tmp_tc.c_cc[VEOL2] = esc;
61845233Sborman # endif
61945233Sborman 	}
62040245Sborman #else
62145233Sborman 	if (tc.t_brkc == (cc_t)(_POSIX_VDISABLE))
622*46808Sdab 		tc.t_brkc = esc;
62340245Sborman #endif
62438689Sborman     } else {
62545233Sborman #ifdef	SIGINFO
62645233Sborman 	SIG_FUNC_RET ayt_status();
62745233Sborman 
62845233Sborman 	(void) signal(SIGINFO, ayt_status);
62945233Sborman #endif	SIGINFO
63039529Sborman #ifdef	SIGTSTP
63138689Sborman 	(void) signal(SIGTSTP, SIG_DFL);
63244361Sborman 	(void) sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
63339529Sborman #endif	/* SIGTSTP */
63439529Sborman #ifndef USE_TERMIO
63539529Sborman 	ltc = oltc;
63639529Sborman 	tc = otc;
63739529Sborman 	sb = ottyb;
63844361Sborman 	lmode = olmode;
63944361Sborman #else
64044361Sborman 	tmp_tc = old_tc;
64139529Sborman #endif
64238689Sborman     }
64339529Sborman #ifndef USE_TERMIO
64439529Sborman     ioctl(tin, TIOCLSET, (char *)&lmode);
64539529Sborman     ioctl(tin, TIOCSLTC, (char *)&ltc);
64639529Sborman     ioctl(tin, TIOCSETC, (char *)&tc);
64745233Sborman     ioctl(tin, TIOCSETN, (char *)&sb);
64839529Sborman #else
64945233Sborman     if (tcsetattr(tin, TCSADRAIN, &tmp_tc) < 0)
65045233Sborman 	tcsetattr(tin, TCSANOW, &tmp_tc);
65139529Sborman #endif
65239529Sborman 
65332147Sminshall #if	(!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR))
65433286Sminshall     ioctl(tin, FIONBIO, (char *)&onoff);
65533286Sminshall     ioctl(tout, FIONBIO, (char *)&onoff);
65632147Sminshall #endif	/* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */
65732147Sminshall #if	defined(TN3270)
65836242Sminshall     if (noasynchtty == 0) {
65933286Sminshall 	ioctl(tin, FIOASYNC, (char *)&onoff);
66032147Sminshall     }
66132147Sminshall #endif	/* defined(TN3270) */
662*46808Sdab 
66332147Sminshall }
66432147Sminshall 
66539529Sborman #ifndef	B19200
66639529Sborman # define B19200 B9600
66739529Sborman #endif
66839529Sborman 
66939529Sborman #ifndef	B38400
67039529Sborman # define B38400 B19200
67139529Sborman #endif
67239529Sborman 
67339529Sborman /*
67439529Sborman  * This code assumes that the values B0, B50, B75...
67539529Sborman  * are in ascending order.  They do not have to be
67639529Sborman  * contiguous.
67739529Sborman  */
67839529Sborman struct termspeeds {
67939529Sborman 	long speed;
68039529Sborman 	long value;
68139529Sborman } termspeeds[] = {
68239529Sborman 	{ 0,     B0 },     { 50,    B50 },   { 75,    B75 },
68339529Sborman 	{ 110,   B110 },   { 134,   B134 },  { 150,   B150 },
68439529Sborman 	{ 200,   B200 },   { 300,   B300 },  { 600,   B600 },
68539529Sborman 	{ 1200,  B1200 },  { 1800,  B1800 }, { 2400,  B2400 },
68639529Sborman 	{ 4800,  B4800 },  { 9600,  B9600 }, { 19200, B19200 },
68739529Sborman 	{ 38400, B38400 }, { -1,    B38400 }
68839529Sborman };
68939529Sborman 
690*46808Sdab     void
69137219Sminshall TerminalSpeeds(ispeed, ospeed)
692*46808Sdab     long *ispeed;
693*46808Sdab     long *ospeed;
69437219Sminshall {
69539529Sborman     register struct termspeeds *tp;
69645233Sborman     register long in, out;
69732147Sminshall 
698*46808Sdab     out = cfgetospeed(&old_tc);
69945233Sborman     in = cfgetispeed(&old_tc);
700*46808Sdab     if (in == 0)
701*46808Sdab 	in = out;
70245233Sborman 
70339529Sborman     tp = termspeeds;
70445233Sborman     while ((tp->speed != -1) && (tp->value < in))
70539529Sborman 	tp++;
70639529Sborman     *ispeed = tp->speed;
70739529Sborman 
70839529Sborman     tp = termspeeds;
70945233Sborman     while ((tp->speed != -1) && (tp->value < out))
71039529Sborman 	tp++;
71139529Sborman     *ospeed = tp->speed;
71237219Sminshall }
71337219Sminshall 
714*46808Sdab     int
71537219Sminshall TerminalWindowSize(rows, cols)
716*46808Sdab     long *rows, *cols;
71737219Sminshall {
71838689Sborman #ifdef	TIOCGWINSZ
71937219Sminshall     struct winsize ws;
72037219Sminshall 
72138689Sborman     if (ioctl(fileno(stdin), TIOCGWINSZ, (char *)&ws) >= 0) {
72238689Sborman 	*rows = ws.ws_row;
72338689Sborman 	*cols = ws.ws_col;
72438689Sborman 	return 1;
72537219Sminshall     }
72638810Sborman #endif	/* TIOCGWINSZ */
72738689Sborman     return 0;
72837219Sminshall }
72937219Sminshall 
730*46808Sdab     int
73135417Sminshall NetClose(fd)
732*46808Sdab     int	fd;
73332147Sminshall {
73435417Sminshall     return close(fd);
73532147Sminshall }
73632147Sminshall 
73732147Sminshall 
738*46808Sdab     void
73932553Sminshall NetNonblockingIO(fd, onoff)
740*46808Sdab     int fd;
741*46808Sdab     int onoff;
74232147Sminshall {
74332147Sminshall     ioctl(fd, FIONBIO, (char *)&onoff);
74432147Sminshall }
74532147Sminshall 
74634849Sminshall #if	defined(TN3270)
747*46808Sdab     void
74832553Sminshall NetSigIO(fd, onoff)
749*46808Sdab     int fd;
750*46808Sdab     int onoff;
75132147Sminshall {
75232147Sminshall     ioctl(fd, FIOASYNC, (char *)&onoff);	/* hear about input */
75332147Sminshall }
75432147Sminshall 
755*46808Sdab     void
75632553Sminshall NetSetPgrp(fd)
757*46808Sdab     int fd;
75832147Sminshall {
75932147Sminshall     int myPid;
76032147Sminshall 
76132147Sminshall     myPid = getpid();
76236274Sminshall     fcntl(fd, F_SETOWN, myPid);
76332147Sminshall }
76434849Sminshall #endif	/*defined(TN3270)*/
76532553Sminshall 
76632553Sminshall /*
76732553Sminshall  * Various signal handling routines.
76832553Sminshall  */
76932147Sminshall 
770*46808Sdab     /* ARGSUSED */
771*46808Sdab     static SIG_FUNC_RET
77245233Sborman deadpeer(sig)
773*46808Sdab     int sig;
77432553Sminshall {
77532553Sminshall 	setcommandmode();
77632553Sminshall 	longjmp(peerdied, -1);
77732553Sminshall }
77832147Sminshall 
779*46808Sdab     /* ARGSUSED */
780*46808Sdab     static SIG_FUNC_RET
78145233Sborman intr(sig)
782*46808Sdab     int sig;
78332553Sminshall {
78432553Sminshall     if (localchars) {
78532553Sminshall 	intp();
78632553Sminshall 	return;
78732553Sminshall     }
78832553Sminshall     setcommandmode();
78932553Sminshall     longjmp(toplevel, -1);
79032553Sminshall }
79132553Sminshall 
792*46808Sdab     /* ARGSUSED */
793*46808Sdab     static SIG_FUNC_RET
79445233Sborman intr2(sig)
795*46808Sdab     int sig;
79632553Sminshall {
79732553Sminshall     if (localchars) {
79838689Sborman #ifdef	KLUDGELINEMODE
79938689Sborman 	if (kludgelinemode)
80038689Sborman 	    sendbrk();
80138689Sborman 	else
80238689Sborman #endif
80338689Sborman 	    sendabort();
80432553Sminshall 	return;
80532553Sminshall     }
80632553Sminshall }
80732553Sminshall 
80845233Sborman #ifdef	SIGTSTP
809*46808Sdab     /* ARGSUSED */
810*46808Sdab     static SIG_FUNC_RET
81145233Sborman susp(sig)
812*46808Sdab     int sig;
81340245Sborman {
814*46808Sdab     if ((rlogin != _POSIX_VDISABLE) && rlogin_susp())
815*46808Sdab 	return;
81640245Sborman     if (localchars)
81740245Sborman 	sendsusp();
81840245Sborman }
81945233Sborman #endif
82040245Sborman 
82145233Sborman #ifdef	SIGWINCH
822*46808Sdab     /* ARGSUSED */
823*46808Sdab     static SIG_FUNC_RET
82445233Sborman sendwin(sig)
825*46808Sdab     int sig;
82637219Sminshall {
82737219Sminshall     if (connected) {
82837219Sminshall 	sendnaws();
82937219Sminshall     }
83037219Sminshall }
83145233Sborman #endif
83237219Sminshall 
83345233Sborman #ifdef	SIGINFO
834*46808Sdab     /* ARGSUSED */
835*46808Sdab     static SIG_FUNC_RET
83645233Sborman ayt(sig)
837*46808Sdab     int sig;
83845233Sborman {
83945233Sborman     if (connected)
84045233Sborman 	sendayt();
84145233Sborman     else
84245233Sborman 	ayt_status();
84345233Sborman }
84445233Sborman #endif
84545233Sborman 
84632553Sminshall 
847*46808Sdab     void
84832531Sminshall sys_telnet_init()
84932531Sminshall {
85045233Sborman     (void) signal(SIGINT, intr);
85145233Sborman     (void) signal(SIGQUIT, intr2);
85245233Sborman     (void) signal(SIGPIPE, deadpeer);
85338689Sborman #ifdef	SIGWINCH
85445233Sborman     (void) signal(SIGWINCH, sendwin);
85538689Sborman #endif
85640245Sborman #ifdef	SIGTSTP
85745233Sborman     (void) signal(SIGTSTP, susp);
85840245Sborman #endif
85945233Sborman #ifdef	SIGINFO
86045233Sborman     (void) signal(SIGINFO, ayt);
86145233Sborman #endif
86232553Sminshall 
86338689Sborman     setconnmode(0);
86432531Sminshall 
86532531Sminshall     NetNonblockingIO(net, 1);
86632531Sminshall 
86732531Sminshall #if	defined(TN3270)
86836242Sminshall     if (noasynchnet == 0) {			/* DBX can't handle! */
86932531Sminshall 	NetSigIO(net, 1);
87032531Sminshall 	NetSetPgrp(net);
87132531Sminshall     }
87232531Sminshall #endif	/* defined(TN3270) */
87332531Sminshall 
87432531Sminshall #if	defined(SO_OOBINLINE)
87534849Sminshall     if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) {
87634849Sminshall 	perror("SetSockOpt");
87734849Sminshall     }
87832531Sminshall #endif	/* defined(SO_OOBINLINE) */
87932531Sminshall }
88032531Sminshall 
88132531Sminshall /*
88232531Sminshall  * Process rings -
88332531Sminshall  *
88432531Sminshall  *	This routine tries to fill up/empty our various rings.
88532531Sminshall  *
88632531Sminshall  *	The parameter specifies whether this is a poll operation,
88732531Sminshall  *	or a block-until-something-happens operation.
88832531Sminshall  *
88932531Sminshall  *	The return value is 1 if something happened, 0 if not.
89032531Sminshall  */
89132531Sminshall 
892*46808Sdab     int
89332531Sminshall process_rings(netin, netout, netex, ttyin, ttyout, poll)
894*46808Sdab     int poll;		/* If 0, then block until something to do */
89532531Sminshall {
89632531Sminshall     register int c;
89732531Sminshall 		/* One wants to be a bit careful about setting returnValue
89832531Sminshall 		 * to one, since a one implies we did some useful work,
89932531Sminshall 		 * and therefore probably won't be called to block next
90032531Sminshall 		 * time (TN3270 mode only).
90132531Sminshall 		 */
90232531Sminshall     int returnValue = 0;
90332531Sminshall     static struct timeval TimeValue = { 0 };
90432531Sminshall 
90532531Sminshall     if (netout) {
90632531Sminshall 	FD_SET(net, &obits);
90732531Sminshall     }
90832531Sminshall     if (ttyout) {
90932531Sminshall 	FD_SET(tout, &obits);
91032531Sminshall     }
91132531Sminshall #if	defined(TN3270)
91232531Sminshall     if (ttyin) {
91332531Sminshall 	FD_SET(tin, &ibits);
91432531Sminshall     }
91532531Sminshall #else	/* defined(TN3270) */
91632531Sminshall     if (ttyin) {
91732531Sminshall 	FD_SET(tin, &ibits);
91832531Sminshall     }
91932531Sminshall #endif	/* defined(TN3270) */
92032531Sminshall #if	defined(TN3270)
92132531Sminshall     if (netin) {
92232531Sminshall 	FD_SET(net, &ibits);
92332531Sminshall     }
92432531Sminshall #   else /* !defined(TN3270) */
92532531Sminshall     if (netin) {
92632531Sminshall 	FD_SET(net, &ibits);
92732531Sminshall     }
92832531Sminshall #   endif /* !defined(TN3270) */
92932531Sminshall     if (netex) {
93032531Sminshall 	FD_SET(net, &xbits);
93132531Sminshall     }
93232531Sminshall     if ((c = select(16, &ibits, &obits, &xbits,
93332531Sminshall 			(poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) {
93432531Sminshall 	if (c == -1) {
93532531Sminshall 		    /*
93632531Sminshall 		     * we can get EINTR if we are in line mode,
93732531Sminshall 		     * and the user does an escape (TSTP), or
93832531Sminshall 		     * some other signal generator.
93932531Sminshall 		     */
94032531Sminshall 	    if (errno == EINTR) {
94132531Sminshall 		return 0;
94232531Sminshall 	    }
94332531Sminshall #	    if defined(TN3270)
94432531Sminshall 		    /*
94532531Sminshall 		     * we can get EBADF if we were in transparent
94632531Sminshall 		     * mode, and the transcom process died.
94732531Sminshall 		    */
94832531Sminshall 	    if (errno == EBADF) {
94932531Sminshall 			/*
95032531Sminshall 			 * zero the bits (even though kernel does it)
95132531Sminshall 			 * to make sure we are selecting on the right
95232531Sminshall 			 * ones.
95332531Sminshall 			*/
95432531Sminshall 		FD_ZERO(&ibits);
95532531Sminshall 		FD_ZERO(&obits);
95632531Sminshall 		FD_ZERO(&xbits);
95732531Sminshall 		return 0;
95832531Sminshall 	    }
95932531Sminshall #	    endif /* defined(TN3270) */
96032531Sminshall 		    /* I don't like this, does it ever happen? */
96132531Sminshall 	    printf("sleep(5) from telnet, after select\r\n");
96232531Sminshall 	    sleep(5);
96332531Sminshall 	}
96432531Sminshall 	return 0;
96532531Sminshall     }
96632531Sminshall 
96732531Sminshall     /*
96832531Sminshall      * Any urgent data?
96932531Sminshall      */
97032531Sminshall     if (FD_ISSET(net, &xbits)) {
97132531Sminshall 	FD_CLR(net, &xbits);
97232531Sminshall 	SYNCHing = 1;
97344361Sborman 	(void) ttyflush(1);	/* flush already enqueued data */
97432531Sminshall     }
97532531Sminshall 
97632531Sminshall     /*
97732531Sminshall      * Something to read from the network...
97832531Sminshall      */
97932531Sminshall     if (FD_ISSET(net, &ibits)) {
98032531Sminshall 	int canread;
98132531Sminshall 
98232531Sminshall 	FD_CLR(net, &ibits);
98332531Sminshall 	canread = ring_empty_consecutive(&netiring);
98432531Sminshall #if	!defined(SO_OOBINLINE)
98532531Sminshall 	    /*
98632531Sminshall 	     * In 4.2 (and some early 4.3) systems, the
98732531Sminshall 	     * OOB indication and data handling in the kernel
98832531Sminshall 	     * is such that if two separate TCP Urgent requests
98932531Sminshall 	     * come in, one byte of TCP data will be overlaid.
99032531Sminshall 	     * This is fatal for Telnet, but we try to live
99132531Sminshall 	     * with it.
99232531Sminshall 	     *
99332531Sminshall 	     * In addition, in 4.2 (and...), a special protocol
99432531Sminshall 	     * is needed to pick up the TCP Urgent data in
99532531Sminshall 	     * the correct sequence.
99632531Sminshall 	     *
99732531Sminshall 	     * What we do is:  if we think we are in urgent
99832531Sminshall 	     * mode, we look to see if we are "at the mark".
99932531Sminshall 	     * If we are, we do an OOB receive.  If we run
100032531Sminshall 	     * this twice, we will do the OOB receive twice,
100132531Sminshall 	     * but the second will fail, since the second
100232531Sminshall 	     * time we were "at the mark", but there wasn't
100332531Sminshall 	     * any data there (the kernel doesn't reset
100432531Sminshall 	     * "at the mark" until we do a normal read).
100532531Sminshall 	     * Once we've read the OOB data, we go ahead
100632531Sminshall 	     * and do normal reads.
100732531Sminshall 	     *
100832531Sminshall 	     * There is also another problem, which is that
100932531Sminshall 	     * since the OOB byte we read doesn't put us
101032531Sminshall 	     * out of OOB state, and since that byte is most
101132531Sminshall 	     * likely the TELNET DM (data mark), we would
101232531Sminshall 	     * stay in the TELNET SYNCH (SYNCHing) state.
101332531Sminshall 	     * So, clocks to the rescue.  If we've "just"
101432531Sminshall 	     * received a DM, then we test for the
101532531Sminshall 	     * presence of OOB data when the receive OOB
101632531Sminshall 	     * fails (and AFTER we did the normal mode read
101732531Sminshall 	     * to clear "at the mark").
101832531Sminshall 	     */
101932531Sminshall 	if (SYNCHing) {
102032531Sminshall 	    int atmark;
102139652Sborman 	    static int bogus_oob = 0, first = 1;
102232531Sminshall 
102332531Sminshall 	    ioctl(net, SIOCATMARK, (char *)&atmark);
102432531Sminshall 	    if (atmark) {
102532531Sminshall 		c = recv(net, netiring.supply, canread, MSG_OOB);
102632531Sminshall 		if ((c == -1) && (errno == EINVAL)) {
102732531Sminshall 		    c = recv(net, netiring.supply, canread, 0);
102832531Sminshall 		    if (clocks.didnetreceive < clocks.gotDM) {
102932531Sminshall 			SYNCHing = stilloob(net);
103032531Sminshall 		    }
103139652Sborman 		} else if (first && c > 0) {
103239652Sborman 		    /*
103339652Sborman 		     * Bogosity check.  Systems based on 4.2BSD
103439652Sborman 		     * do not return an error if you do a second
103539652Sborman 		     * recv(MSG_OOB).  So, we do one.  If it
103639652Sborman 		     * succeeds and returns exactly the same
103739652Sborman 		     * data, then assume that we are running
103839652Sborman 		     * on a broken system and set the bogus_oob
103939652Sborman 		     * flag.  (If the data was different, then
104039652Sborman 		     * we probably got some valid new data, so
104139652Sborman 		     * increment the count...)
104239652Sborman 		     */
104339652Sborman 		    int i;
104439652Sborman 		    i = recv(net, netiring.supply + c, canread - c, MSG_OOB);
104539652Sborman 		    if (i == c &&
104639652Sborman 			  bcmp(netiring.supply, netiring.supply + c, i) == 0) {
104739652Sborman 			bogus_oob = 1;
104839652Sborman 			first = 0;
104939652Sborman 		    } else if (i < 0) {
105039652Sborman 			bogus_oob = 0;
105139652Sborman 			first = 0;
105239652Sborman 		    } else
105339652Sborman 			c += i;
105432531Sminshall 		}
105539652Sborman 		if (bogus_oob && c > 0) {
105639652Sborman 		    int i;
105739652Sborman 		    /*
105839652Sborman 		     * Bogosity.  We have to do the read
105939652Sborman 		     * to clear the atmark to get out of
106039652Sborman 		     * an infinate loop.
106139652Sborman 		     */
106239652Sborman 		    i = read(net, netiring.supply + c, canread - c);
106339652Sborman 		    if (i > 0)
106439652Sborman 			c += i;
106539652Sborman 		}
106632531Sminshall 	    } else {
106732531Sminshall 		c = recv(net, netiring.supply, canread, 0);
106832531Sminshall 	    }
106932531Sminshall 	} else {
107032531Sminshall 	    c = recv(net, netiring.supply, canread, 0);
107132531Sminshall 	}
107232531Sminshall 	settimer(didnetreceive);
107332531Sminshall #else	/* !defined(SO_OOBINLINE) */
107432531Sminshall 	c = recv(net, netiring.supply, canread, 0);
107532531Sminshall #endif	/* !defined(SO_OOBINLINE) */
107632531Sminshall 	if (c < 0 && errno == EWOULDBLOCK) {
107732531Sminshall 	    c = 0;
107832531Sminshall 	} else if (c <= 0) {
107932531Sminshall 	    return -1;
108032531Sminshall 	}
108132531Sminshall 	if (netdata) {
108232531Sminshall 	    Dump('<', netiring.supply, c);
108332531Sminshall 	}
108432667Sminshall 	if (c)
108532667Sminshall 	    ring_supplied(&netiring, c);
108632531Sminshall 	returnValue = 1;
108732531Sminshall     }
108832531Sminshall 
108932531Sminshall     /*
109032531Sminshall      * Something to read from the tty...
109132531Sminshall      */
109232531Sminshall     if (FD_ISSET(tin, &ibits)) {
109332531Sminshall 	FD_CLR(tin, &ibits);
109433286Sminshall 	c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring));
109532531Sminshall 	if (c < 0 && errno == EWOULDBLOCK) {
109632531Sminshall 	    c = 0;
109732531Sminshall 	} else {
109832531Sminshall 	    /* EOF detection for line mode!!!! */
109933281Sminshall 	    if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && isatty(tin)) {
110032531Sminshall 			/* must be an EOF... */
110132531Sminshall 		*ttyiring.supply = termEofChar;
110232531Sminshall 		c = 1;
110332531Sminshall 	    }
110432531Sminshall 	    if (c <= 0) {
110532531Sminshall 		return -1;
110632531Sminshall 	    }
110738208Sminshall 	    if (termdata) {
110838208Sminshall 		Dump('<', ttyiring.supply, c);
110938208Sminshall 	    }
111032667Sminshall 	    ring_supplied(&ttyiring, c);
111132531Sminshall 	}
111232531Sminshall 	returnValue = 1;		/* did something useful */
111332531Sminshall     }
111432531Sminshall 
111532531Sminshall     if (FD_ISSET(net, &obits)) {
111632531Sminshall 	FD_CLR(net, &obits);
111732531Sminshall 	returnValue |= netflush();
111832531Sminshall     }
111932531Sminshall     if (FD_ISSET(tout, &obits)) {
112032531Sminshall 	FD_CLR(tout, &obits);
112138689Sborman 	returnValue |= (ttyflush(SYNCHing|flushout) > 0);
112232531Sminshall     }
112332531Sminshall 
112432531Sminshall     return returnValue;
112532531Sminshall }
1126