sys_bsd.c revision 29088
129088Smarkm/*
229088Smarkm * Copyright (c) 1988, 1990, 1993
329088Smarkm *	The Regents of the University of California.  All rights reserved.
429088Smarkm *
529088Smarkm * Redistribution and use in source and binary forms, with or without
629088Smarkm * modification, are permitted provided that the following conditions
729088Smarkm * are met:
829088Smarkm * 1. Redistributions of source code must retain the above copyright
929088Smarkm *    notice, this list of conditions and the following disclaimer.
1029088Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1129088Smarkm *    notice, this list of conditions and the following disclaimer in the
1229088Smarkm *    documentation and/or other materials provided with the distribution.
1329088Smarkm * 3. All advertising materials mentioning features or use of this software
1429088Smarkm *    must display the following acknowledgement:
1529088Smarkm *	This product includes software developed by the University of
1629088Smarkm *	California, Berkeley and its contributors.
1729088Smarkm * 4. Neither the name of the University nor the names of its contributors
1829088Smarkm *    may be used to endorse or promote products derived from this software
1929088Smarkm *    without specific prior written permission.
2029088Smarkm *
2129088Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2229088Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2329088Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2429088Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2529088Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2629088Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2729088Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2829088Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2929088Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3029088Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3129088Smarkm * SUCH DAMAGE.
3229088Smarkm */
3329088Smarkm
3429088Smarkm#ifndef lint
3529088Smarkmstatic char sccsid[] = "@(#)sys_bsd.c	8.4 (Berkeley) 5/30/95";
3629088Smarkm#endif /* not lint */
3729088Smarkm
3829088Smarkm/*
3929088Smarkm * The following routines try to encapsulate what is system dependent
4029088Smarkm * (at least between 4.x and dos) which is used in telnet.c.
4129088Smarkm */
4229088Smarkm
4329088Smarkm
4429088Smarkm#include <fcntl.h>
4529088Smarkm#include <sys/types.h>
4629088Smarkm#include <sys/time.h>
4729088Smarkm#include <sys/socket.h>
4829088Smarkm#include <signal.h>
4929088Smarkm#include <errno.h>
5029088Smarkm#include <arpa/telnet.h>
5129088Smarkm
5229088Smarkm#include "ring.h"
5329088Smarkm
5429088Smarkm#include "fdset.h"
5529088Smarkm
5629088Smarkm#include "defines.h"
5729088Smarkm#include "externs.h"
5829088Smarkm#include "types.h"
5929088Smarkm
6029088Smarkm#if	defined(CRAY) || (defined(USE_TERMIO) && !defined(SYSV_TERMIO))
6129088Smarkm#define	SIG_FUNC_RET	void
6229088Smarkm#else
6329088Smarkm#define	SIG_FUNC_RET	int
6429088Smarkm#endif
6529088Smarkm
6629088Smarkm#ifdef	SIGINFO
6729088Smarkmextern SIG_FUNC_RET ayt_status();
6829088Smarkm#endif
6929088Smarkm
7029088Smarkmint
7129088Smarkm	tout,			/* Output file descriptor */
7229088Smarkm	tin,			/* Input file descriptor */
7329088Smarkm	net;
7429088Smarkm
7529088Smarkm#ifndef	USE_TERMIO
7629088Smarkmstruct	tchars otc = { 0 }, ntc = { 0 };
7729088Smarkmstruct	ltchars oltc = { 0 }, nltc = { 0 };
7829088Smarkmstruct	sgttyb ottyb = { 0 }, nttyb = { 0 };
7929088Smarkmint	olmode = 0;
8029088Smarkm# define cfgetispeed(ptr)	(ptr)->sg_ispeed
8129088Smarkm# define cfgetospeed(ptr)	(ptr)->sg_ospeed
8229088Smarkm# define old_tc ottyb
8329088Smarkm
8429088Smarkm#else	/* USE_TERMIO */
8529088Smarkmstruct	termio old_tc = { 0 };
8629088Smarkmextern struct termio new_tc;
8729088Smarkm
8829088Smarkm# ifndef	TCSANOW
8929088Smarkm#  ifdef TCSETS
9029088Smarkm#   define	TCSANOW		TCSETS
9129088Smarkm#   define	TCSADRAIN	TCSETSW
9229088Smarkm#   define	tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
9329088Smarkm#  else
9429088Smarkm#   ifdef TCSETA
9529088Smarkm#    define	TCSANOW		TCSETA
9629088Smarkm#    define	TCSADRAIN	TCSETAW
9729088Smarkm#    define	tcgetattr(f, t) ioctl(f, TCGETA, (char *)t)
9829088Smarkm#   else
9929088Smarkm#    define	TCSANOW		TIOCSETA
10029088Smarkm#    define	TCSADRAIN	TIOCSETAW
10129088Smarkm#    define	tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t)
10229088Smarkm#   endif
10329088Smarkm#  endif
10429088Smarkm#  define	tcsetattr(f, a, t) ioctl(f, a, (char *)t)
10529088Smarkm#  define	cfgetospeed(ptr)	((ptr)->c_cflag&CBAUD)
10629088Smarkm#  ifdef CIBAUD
10729088Smarkm#   define	cfgetispeed(ptr)	(((ptr)->c_cflag&CIBAUD) >> IBSHIFT)
10829088Smarkm#  else
10929088Smarkm#   define	cfgetispeed(ptr)	cfgetospeed(ptr)
11029088Smarkm#  endif
11129088Smarkm# endif /* TCSANOW */
11229088Smarkm# ifdef	sysV88
11329088Smarkm# define TIOCFLUSH TC_PX_DRAIN
11429088Smarkm# endif
11529088Smarkm#endif	/* USE_TERMIO */
11629088Smarkm
11729088Smarkmstatic fd_set ibits, obits, xbits;
11829088Smarkm
11929088Smarkm
12029088Smarkm    void
12129088Smarkminit_sys()
12229088Smarkm{
12329088Smarkm    tout = fileno(stdout);
12429088Smarkm    tin = fileno(stdin);
12529088Smarkm    FD_ZERO(&ibits);
12629088Smarkm    FD_ZERO(&obits);
12729088Smarkm    FD_ZERO(&xbits);
12829088Smarkm
12929088Smarkm    errno = 0;
13029088Smarkm}
13129088Smarkm
13229088Smarkm
13329088Smarkm    int
13429088SmarkmTerminalWrite(buf, n)
13529088Smarkm    char *buf;
13629088Smarkm    int  n;
13729088Smarkm{
13829088Smarkm    return write(tout, buf, n);
13929088Smarkm}
14029088Smarkm
14129088Smarkm    int
14229088SmarkmTerminalRead(buf, n)
14329088Smarkm    unsigned char *buf;
14429088Smarkm    int  n;
14529088Smarkm{
14629088Smarkm    return read(tin, buf, n);
14729088Smarkm}
14829088Smarkm
14929088Smarkm/*
15029088Smarkm *
15129088Smarkm */
15229088Smarkm
15329088Smarkm    int
15429088SmarkmTerminalAutoFlush()
15529088Smarkm{
15629088Smarkm#if	defined(LNOFLSH)
15729088Smarkm    int flush;
15829088Smarkm
15929088Smarkm    ioctl(0, TIOCLGET, (char *)&flush);
16029088Smarkm    return !(flush&LNOFLSH);	/* if LNOFLSH, no autoflush */
16129088Smarkm#else	/* LNOFLSH */
16229088Smarkm    return 1;
16329088Smarkm#endif	/* LNOFLSH */
16429088Smarkm}
16529088Smarkm
16629088Smarkm#ifdef	KLUDGELINEMODE
16729088Smarkmextern int kludgelinemode;
16829088Smarkm#endif
16929088Smarkm/*
17029088Smarkm * TerminalSpecialChars()
17129088Smarkm *
17229088Smarkm * Look at an input character to see if it is a special character
17329088Smarkm * and decide what to do.
17429088Smarkm *
17529088Smarkm * Output:
17629088Smarkm *
17729088Smarkm *	0	Don't add this character.
17829088Smarkm *	1	Do add this character
17929088Smarkm */
18029088Smarkm
18129088Smarkmextern void xmitAO(), xmitEL(), xmitEC(), intp(), sendbrk();
18229088Smarkm
18329088Smarkm    int
18429088SmarkmTerminalSpecialChars(c)
18529088Smarkm    int	c;
18629088Smarkm{
18729088Smarkm    if (c == termIntChar) {
18829088Smarkm	intp();
18929088Smarkm	return 0;
19029088Smarkm    } else if (c == termQuitChar) {
19129088Smarkm#ifdef	KLUDGELINEMODE
19229088Smarkm	if (kludgelinemode)
19329088Smarkm	    sendbrk();
19429088Smarkm	else
19529088Smarkm#endif
19629088Smarkm	    sendabort();
19729088Smarkm	return 0;
19829088Smarkm    } else if (c == termEofChar) {
19929088Smarkm	if (my_want_state_is_will(TELOPT_LINEMODE)) {
20029088Smarkm	    sendeof();
20129088Smarkm	    return 0;
20229088Smarkm	}
20329088Smarkm	return 1;
20429088Smarkm    } else if (c == termSuspChar) {
20529088Smarkm	sendsusp();
20629088Smarkm	return(0);
20729088Smarkm    } else if (c == termFlushChar) {
20829088Smarkm	xmitAO();		/* Transmit Abort Output */
20929088Smarkm	return 0;
21029088Smarkm    } else if (!MODE_LOCAL_CHARS(globalmode)) {
21129088Smarkm	if (c == termKillChar) {
21229088Smarkm	    xmitEL();
21329088Smarkm	    return 0;
21429088Smarkm	} else if (c == termEraseChar) {
21529088Smarkm	    xmitEC();		/* Transmit Erase Character */
21629088Smarkm	    return 0;
21729088Smarkm	}
21829088Smarkm    }
21929088Smarkm    return 1;
22029088Smarkm}
22129088Smarkm
22229088Smarkm
22329088Smarkm/*
22429088Smarkm * Flush output to the terminal
22529088Smarkm */
22629088Smarkm
22729088Smarkm    void
22829088SmarkmTerminalFlushOutput()
22929088Smarkm{
23029088Smarkm#ifdef	TIOCFLUSH
23129088Smarkm    (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0);
23229088Smarkm#else
23329088Smarkm    (void) ioctl(fileno(stdout), TCFLSH, (char *) 0);
23429088Smarkm#endif
23529088Smarkm}
23629088Smarkm
23729088Smarkm    void
23829088SmarkmTerminalSaveState()
23929088Smarkm{
24029088Smarkm#ifndef	USE_TERMIO
24129088Smarkm    ioctl(0, TIOCGETP, (char *)&ottyb);
24229088Smarkm    ioctl(0, TIOCGETC, (char *)&otc);
24329088Smarkm    ioctl(0, TIOCGLTC, (char *)&oltc);
24429088Smarkm    ioctl(0, TIOCLGET, (char *)&olmode);
24529088Smarkm
24629088Smarkm    ntc = otc;
24729088Smarkm    nltc = oltc;
24829088Smarkm    nttyb = ottyb;
24929088Smarkm
25029088Smarkm#else	/* USE_TERMIO */
25129088Smarkm    tcgetattr(0, &old_tc);
25229088Smarkm
25329088Smarkm    new_tc = old_tc;
25429088Smarkm
25529088Smarkm#ifndef	VDISCARD
25629088Smarkm    termFlushChar = CONTROL('O');
25729088Smarkm#endif
25829088Smarkm#ifndef	VWERASE
25929088Smarkm    termWerasChar = CONTROL('W');
26029088Smarkm#endif
26129088Smarkm#ifndef	VREPRINT
26229088Smarkm    termRprntChar = CONTROL('R');
26329088Smarkm#endif
26429088Smarkm#ifndef	VLNEXT
26529088Smarkm    termLiteralNextChar = CONTROL('V');
26629088Smarkm#endif
26729088Smarkm#ifndef	VSTART
26829088Smarkm    termStartChar = CONTROL('Q');
26929088Smarkm#endif
27029088Smarkm#ifndef	VSTOP
27129088Smarkm    termStopChar = CONTROL('S');
27229088Smarkm#endif
27329088Smarkm#ifndef	VSTATUS
27429088Smarkm    termAytChar = CONTROL('T');
27529088Smarkm#endif
27629088Smarkm#endif	/* USE_TERMIO */
27729088Smarkm}
27829088Smarkm
27929088Smarkm    cc_t *
28029088Smarkmtcval(func)
28129088Smarkm    register int func;
28229088Smarkm{
28329088Smarkm    switch(func) {
28429088Smarkm    case SLC_IP:	return(&termIntChar);
28529088Smarkm    case SLC_ABORT:	return(&termQuitChar);
28629088Smarkm    case SLC_EOF:	return(&termEofChar);
28729088Smarkm    case SLC_EC:	return(&termEraseChar);
28829088Smarkm    case SLC_EL:	return(&termKillChar);
28929088Smarkm    case SLC_XON:	return(&termStartChar);
29029088Smarkm    case SLC_XOFF:	return(&termStopChar);
29129088Smarkm    case SLC_FORW1:	return(&termForw1Char);
29229088Smarkm#ifdef	USE_TERMIO
29329088Smarkm    case SLC_FORW2:	return(&termForw2Char);
29429088Smarkm# ifdef	VDISCARD
29529088Smarkm    case SLC_AO:	return(&termFlushChar);
29629088Smarkm# endif
29729088Smarkm# ifdef	VSUSP
29829088Smarkm    case SLC_SUSP:	return(&termSuspChar);
29929088Smarkm# endif
30029088Smarkm# ifdef	VWERASE
30129088Smarkm    case SLC_EW:	return(&termWerasChar);
30229088Smarkm# endif
30329088Smarkm# ifdef	VREPRINT
30429088Smarkm    case SLC_RP:	return(&termRprntChar);
30529088Smarkm# endif
30629088Smarkm# ifdef	VLNEXT
30729088Smarkm    case SLC_LNEXT:	return(&termLiteralNextChar);
30829088Smarkm# endif
30929088Smarkm# ifdef	VSTATUS
31029088Smarkm    case SLC_AYT:	return(&termAytChar);
31129088Smarkm# endif
31229088Smarkm#endif
31329088Smarkm
31429088Smarkm    case SLC_SYNCH:
31529088Smarkm    case SLC_BRK:
31629088Smarkm    case SLC_EOR:
31729088Smarkm    default:
31829088Smarkm	return((cc_t *)0);
31929088Smarkm    }
32029088Smarkm}
32129088Smarkm
32229088Smarkm    void
32329088SmarkmTerminalDefaultChars()
32429088Smarkm{
32529088Smarkm#ifndef	USE_TERMIO
32629088Smarkm    ntc = otc;
32729088Smarkm    nltc = oltc;
32829088Smarkm    nttyb.sg_kill = ottyb.sg_kill;
32929088Smarkm    nttyb.sg_erase = ottyb.sg_erase;
33029088Smarkm#else	/* USE_TERMIO */
33129088Smarkm    memmove(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc));
33229088Smarkm# ifndef	VDISCARD
33329088Smarkm    termFlushChar = CONTROL('O');
33429088Smarkm# endif
33529088Smarkm# ifndef	VWERASE
33629088Smarkm    termWerasChar = CONTROL('W');
33729088Smarkm# endif
33829088Smarkm# ifndef	VREPRINT
33929088Smarkm    termRprntChar = CONTROL('R');
34029088Smarkm# endif
34129088Smarkm# ifndef	VLNEXT
34229088Smarkm    termLiteralNextChar = CONTROL('V');
34329088Smarkm# endif
34429088Smarkm# ifndef	VSTART
34529088Smarkm    termStartChar = CONTROL('Q');
34629088Smarkm# endif
34729088Smarkm# ifndef	VSTOP
34829088Smarkm    termStopChar = CONTROL('S');
34929088Smarkm# endif
35029088Smarkm# ifndef	VSTATUS
35129088Smarkm    termAytChar = CONTROL('T');
35229088Smarkm# endif
35329088Smarkm#endif	/* USE_TERMIO */
35429088Smarkm}
35529088Smarkm
35629088Smarkm#ifdef notdef
35729088Smarkmvoid
35829088SmarkmTerminalRestoreState()
35929088Smarkm{
36029088Smarkm}
36129088Smarkm#endif
36229088Smarkm
36329088Smarkm/*
36429088Smarkm * TerminalNewMode - set up terminal to a specific mode.
36529088Smarkm *	MODE_ECHO: do local terminal echo
36629088Smarkm *	MODE_FLOW: do local flow control
36729088Smarkm *	MODE_TRAPSIG: do local mapping to TELNET IAC sequences
36829088Smarkm *	MODE_EDIT: do local line editing
36929088Smarkm *
37029088Smarkm *	Command mode:
37129088Smarkm *		MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG
37229088Smarkm *		local echo
37329088Smarkm *		local editing
37429088Smarkm *		local xon/xoff
37529088Smarkm *		local signal mapping
37629088Smarkm *
37729088Smarkm *	Linemode:
37829088Smarkm *		local/no editing
37929088Smarkm *	Both Linemode and Single Character mode:
38029088Smarkm *		local/remote echo
38129088Smarkm *		local/no xon/xoff
38229088Smarkm *		local/no signal mapping
38329088Smarkm */
38429088Smarkm
38529088Smarkm
38629088Smarkm    void
38729088SmarkmTerminalNewMode(f)
38829088Smarkm    register int f;
38929088Smarkm{
39029088Smarkm    static int prevmode = 0;
39129088Smarkm#ifndef	USE_TERMIO
39229088Smarkm    struct tchars tc;
39329088Smarkm    struct ltchars ltc;
39429088Smarkm    struct sgttyb sb;
39529088Smarkm    int lmode;
39629088Smarkm#else	/* USE_TERMIO */
39729088Smarkm    struct termio tmp_tc;
39829088Smarkm#endif	/* USE_TERMIO */
39929088Smarkm    int onoff;
40029088Smarkm    int old;
40129088Smarkm    cc_t esc;
40229088Smarkm
40329088Smarkm    globalmode = f&~MODE_FORCE;
40429088Smarkm    if (prevmode == f)
40529088Smarkm	return;
40629088Smarkm
40729088Smarkm    /*
40829088Smarkm     * Write any outstanding data before switching modes
40929088Smarkm     * ttyflush() returns 0 only when there is no more data
41029088Smarkm     * left to write out, it returns -1 if it couldn't do
41129088Smarkm     * anything at all, otherwise it returns 1 + the number
41229088Smarkm     * of characters left to write.
41329088Smarkm#ifndef	USE_TERMIO
41429088Smarkm     * We would really like ask the kernel to wait for the output
41529088Smarkm     * to drain, like we can do with the TCSADRAIN, but we don't have
41629088Smarkm     * that option.  The only ioctl that waits for the output to
41729088Smarkm     * drain, TIOCSETP, also flushes the input queue, which is NOT
41829088Smarkm     * what we want (TIOCSETP is like TCSADFLUSH).
41929088Smarkm#endif
42029088Smarkm     */
42129088Smarkm    old = ttyflush(SYNCHing|flushout);
42229088Smarkm    if (old < 0 || old > 1) {
42329088Smarkm#ifdef	USE_TERMIO
42429088Smarkm	tcgetattr(tin, &tmp_tc);
42529088Smarkm#endif	/* USE_TERMIO */
42629088Smarkm	do {
42729088Smarkm	    /*
42829088Smarkm	     * Wait for data to drain, then flush again.
42929088Smarkm	     */
43029088Smarkm#ifdef	USE_TERMIO
43129088Smarkm	    tcsetattr(tin, TCSADRAIN, &tmp_tc);
43229088Smarkm#endif	/* USE_TERMIO */
43329088Smarkm	    old = ttyflush(SYNCHing|flushout);
43429088Smarkm	} while (old < 0 || old > 1);
43529088Smarkm    }
43629088Smarkm
43729088Smarkm    old = prevmode;
43829088Smarkm    prevmode = f&~MODE_FORCE;
43929088Smarkm#ifndef	USE_TERMIO
44029088Smarkm    sb = nttyb;
44129088Smarkm    tc = ntc;
44229088Smarkm    ltc = nltc;
44329088Smarkm    lmode = olmode;
44429088Smarkm#else
44529088Smarkm    tmp_tc = new_tc;
44629088Smarkm#endif
44729088Smarkm
44829088Smarkm    if (f&MODE_ECHO) {
44929088Smarkm#ifndef	USE_TERMIO
45029088Smarkm	sb.sg_flags |= ECHO;
45129088Smarkm#else
45229088Smarkm	tmp_tc.c_lflag |= ECHO;
45329088Smarkm	tmp_tc.c_oflag |= ONLCR;
45429088Smarkm	if (crlf)
45529088Smarkm		tmp_tc.c_iflag |= ICRNL;
45629088Smarkm#endif
45729088Smarkm    } else {
45829088Smarkm#ifndef	USE_TERMIO
45929088Smarkm	sb.sg_flags &= ~ECHO;
46029088Smarkm#else
46129088Smarkm	tmp_tc.c_lflag &= ~ECHO;
46229088Smarkm	tmp_tc.c_oflag &= ~ONLCR;
46329088Smarkm# ifdef notdef
46429088Smarkm	if (crlf)
46529088Smarkm		tmp_tc.c_iflag &= ~ICRNL;
46629088Smarkm# endif
46729088Smarkm#endif
46829088Smarkm    }
46929088Smarkm
47029088Smarkm    if ((f&MODE_FLOW) == 0) {
47129088Smarkm#ifndef	USE_TERMIO
47229088Smarkm	tc.t_startc = _POSIX_VDISABLE;
47329088Smarkm	tc.t_stopc = _POSIX_VDISABLE;
47429088Smarkm#else
47529088Smarkm	tmp_tc.c_iflag &= ~(IXOFF|IXON);	/* Leave the IXANY bit alone */
47629088Smarkm    } else {
47729088Smarkm	if (restartany < 0) {
47829088Smarkm		tmp_tc.c_iflag |= IXOFF|IXON;	/* Leave the IXANY bit alone */
47929088Smarkm	} else if (restartany > 0) {
48029088Smarkm		tmp_tc.c_iflag |= IXOFF|IXON|IXANY;
48129088Smarkm	} else {
48229088Smarkm		tmp_tc.c_iflag |= IXOFF|IXON;
48329088Smarkm		tmp_tc.c_iflag &= ~IXANY;
48429088Smarkm	}
48529088Smarkm#endif
48629088Smarkm    }
48729088Smarkm
48829088Smarkm    if ((f&MODE_TRAPSIG) == 0) {
48929088Smarkm#ifndef	USE_TERMIO
49029088Smarkm	tc.t_intrc = _POSIX_VDISABLE;
49129088Smarkm	tc.t_quitc = _POSIX_VDISABLE;
49229088Smarkm	tc.t_eofc = _POSIX_VDISABLE;
49329088Smarkm	ltc.t_suspc = _POSIX_VDISABLE;
49429088Smarkm	ltc.t_dsuspc = _POSIX_VDISABLE;
49529088Smarkm#else
49629088Smarkm	tmp_tc.c_lflag &= ~ISIG;
49729088Smarkm#endif
49829088Smarkm	localchars = 0;
49929088Smarkm    } else {
50029088Smarkm#ifdef	USE_TERMIO
50129088Smarkm	tmp_tc.c_lflag |= ISIG;
50229088Smarkm#endif
50329088Smarkm	localchars = 1;
50429088Smarkm    }
50529088Smarkm
50629088Smarkm    if (f&MODE_EDIT) {
50729088Smarkm#ifndef	USE_TERMIO
50829088Smarkm	sb.sg_flags &= ~CBREAK;
50929088Smarkm	sb.sg_flags |= CRMOD;
51029088Smarkm#else
51129088Smarkm	tmp_tc.c_lflag |= ICANON;
51229088Smarkm#endif
51329088Smarkm    } else {
51429088Smarkm#ifndef	USE_TERMIO
51529088Smarkm	sb.sg_flags |= CBREAK;
51629088Smarkm	if (f&MODE_ECHO)
51729088Smarkm	    sb.sg_flags |= CRMOD;
51829088Smarkm	else
51929088Smarkm	    sb.sg_flags &= ~CRMOD;
52029088Smarkm#else
52129088Smarkm	tmp_tc.c_lflag &= ~ICANON;
52229088Smarkm	tmp_tc.c_iflag &= ~ICRNL;
52329088Smarkm	tmp_tc.c_cc[VMIN] = 1;
52429088Smarkm	tmp_tc.c_cc[VTIME] = 0;
52529088Smarkm#endif
52629088Smarkm    }
52729088Smarkm
52829088Smarkm    if ((f&(MODE_EDIT|MODE_TRAPSIG)) == 0) {
52929088Smarkm#ifndef	USE_TERMIO
53029088Smarkm	ltc.t_lnextc = _POSIX_VDISABLE;
53129088Smarkm#else
53229088Smarkm# ifdef VLNEXT
53329088Smarkm	tmp_tc.c_cc[VLNEXT] = (cc_t)(_POSIX_VDISABLE);
53429088Smarkm# endif
53529088Smarkm#endif
53629088Smarkm    }
53729088Smarkm
53829088Smarkm    if (f&MODE_SOFT_TAB) {
53929088Smarkm#ifndef USE_TERMIO
54029088Smarkm	sb.sg_flags |= XTABS;
54129088Smarkm#else
54229088Smarkm# ifdef	OXTABS
54329088Smarkm	tmp_tc.c_oflag |= OXTABS;
54429088Smarkm# endif
54529088Smarkm# ifdef	TABDLY
54629088Smarkm	tmp_tc.c_oflag &= ~TABDLY;
54729088Smarkm	tmp_tc.c_oflag |= TAB3;
54829088Smarkm# endif
54929088Smarkm#endif
55029088Smarkm    } else {
55129088Smarkm#ifndef USE_TERMIO
55229088Smarkm	sb.sg_flags &= ~XTABS;
55329088Smarkm#else
55429088Smarkm# ifdef	OXTABS
55529088Smarkm	tmp_tc.c_oflag &= ~OXTABS;
55629088Smarkm# endif
55729088Smarkm# ifdef	TABDLY
55829088Smarkm	tmp_tc.c_oflag &= ~TABDLY;
55929088Smarkm# endif
56029088Smarkm#endif
56129088Smarkm    }
56229088Smarkm
56329088Smarkm    if (f&MODE_LIT_ECHO) {
56429088Smarkm#ifndef USE_TERMIO
56529088Smarkm	lmode &= ~LCTLECH;
56629088Smarkm#else
56729088Smarkm# ifdef	ECHOCTL
56829088Smarkm	tmp_tc.c_lflag &= ~ECHOCTL;
56929088Smarkm# endif
57029088Smarkm#endif
57129088Smarkm    } else {
57229088Smarkm#ifndef USE_TERMIO
57329088Smarkm	lmode |= LCTLECH;
57429088Smarkm#else
57529088Smarkm# ifdef	ECHOCTL
57629088Smarkm	tmp_tc.c_lflag |= ECHOCTL;
57729088Smarkm# endif
57829088Smarkm#endif
57929088Smarkm    }
58029088Smarkm
58129088Smarkm    if (f == -1) {
58229088Smarkm	onoff = 0;
58329088Smarkm    } else {
58429088Smarkm#ifndef	USE_TERMIO
58529088Smarkm	if (f & MODE_OUTBIN)
58629088Smarkm		lmode |= LLITOUT;
58729088Smarkm	else
58829088Smarkm		lmode &= ~LLITOUT;
58929088Smarkm
59029088Smarkm	if (f & MODE_INBIN)
59129088Smarkm		lmode |= LPASS8;
59229088Smarkm	else
59329088Smarkm		lmode &= ~LPASS8;
59429088Smarkm#else
59529088Smarkm	if (f & MODE_INBIN)
59629088Smarkm		tmp_tc.c_iflag &= ~ISTRIP;
59729088Smarkm	else
59829088Smarkm		tmp_tc.c_iflag |= ISTRIP;
59929088Smarkm	if (f & MODE_OUTBIN) {
60029088Smarkm		tmp_tc.c_cflag &= ~(CSIZE|PARENB);
60129088Smarkm		tmp_tc.c_cflag |= CS8;
60229088Smarkm		tmp_tc.c_oflag &= ~OPOST;
60329088Smarkm	} else {
60429088Smarkm		tmp_tc.c_cflag &= ~(CSIZE|PARENB);
60529088Smarkm		tmp_tc.c_cflag |= old_tc.c_cflag & (CSIZE|PARENB);
60629088Smarkm		tmp_tc.c_oflag |= OPOST;
60729088Smarkm	}
60829088Smarkm#endif
60929088Smarkm	onoff = 1;
61029088Smarkm    }
61129088Smarkm
61229088Smarkm    if (f != -1) {
61329088Smarkm#ifdef	SIGTSTP
61429088Smarkm	SIG_FUNC_RET susp();
61529088Smarkm#endif	/* SIGTSTP */
61629088Smarkm#ifdef	SIGINFO
61729088Smarkm	SIG_FUNC_RET ayt();
61829088Smarkm#endif
61929088Smarkm
62029088Smarkm#ifdef	SIGTSTP
62129088Smarkm	(void) signal(SIGTSTP, susp);
62229088Smarkm#endif	/* SIGTSTP */
62329088Smarkm#ifdef	SIGINFO
62429088Smarkm	(void) signal(SIGINFO, ayt);
62529088Smarkm#endif
62629088Smarkm#if	defined(USE_TERMIO) && defined(NOKERNINFO)
62729088Smarkm	tmp_tc.c_lflag |= NOKERNINFO;
62829088Smarkm#endif
62929088Smarkm	/*
63029088Smarkm	 * We don't want to process ^Y here.  It's just another
63129088Smarkm	 * character that we'll pass on to the back end.  It has
63229088Smarkm	 * to process it because it will be processed when the
63329088Smarkm	 * user attempts to read it, not when we send it.
63429088Smarkm	 */
63529088Smarkm#ifndef	USE_TERMIO
63629088Smarkm	ltc.t_dsuspc = _POSIX_VDISABLE;
63729088Smarkm#else
63829088Smarkm# ifdef	VDSUSP
63929088Smarkm	tmp_tc.c_cc[VDSUSP] = (cc_t)(_POSIX_VDISABLE);
64029088Smarkm# endif
64129088Smarkm#endif
64229088Smarkm#ifdef	USE_TERMIO
64329088Smarkm	/*
64429088Smarkm	 * If the VEOL character is already set, then use VEOL2,
64529088Smarkm	 * otherwise use VEOL.
64629088Smarkm	 */
64729088Smarkm	esc = (rlogin != _POSIX_VDISABLE) ? rlogin : escape;
64829088Smarkm	if ((tmp_tc.c_cc[VEOL] != esc)
64929088Smarkm# ifdef	VEOL2
65029088Smarkm	    && (tmp_tc.c_cc[VEOL2] != esc)
65129088Smarkm# endif
65229088Smarkm	    ) {
65329088Smarkm		if (tmp_tc.c_cc[VEOL] == (cc_t)(_POSIX_VDISABLE))
65429088Smarkm		    tmp_tc.c_cc[VEOL] = esc;
65529088Smarkm# ifdef	VEOL2
65629088Smarkm		else if (tmp_tc.c_cc[VEOL2] == (cc_t)(_POSIX_VDISABLE))
65729088Smarkm		    tmp_tc.c_cc[VEOL2] = esc;
65829088Smarkm# endif
65929088Smarkm	}
66029088Smarkm#else
66129088Smarkm	if (tc.t_brkc == (cc_t)(_POSIX_VDISABLE))
66229088Smarkm		tc.t_brkc = esc;
66329088Smarkm#endif
66429088Smarkm    } else {
66529088Smarkm#ifdef	SIGINFO
66629088Smarkm	SIG_FUNC_RET ayt_status();
66729088Smarkm
66829088Smarkm	(void) signal(SIGINFO, ayt_status);
66929088Smarkm#endif
67029088Smarkm#ifdef	SIGTSTP
67129088Smarkm	(void) signal(SIGTSTP, SIG_DFL);
67229088Smarkm# ifndef SOLARIS
67329088Smarkm	(void) sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
67429088Smarkm# else	SOLARIS
67529088Smarkm	(void) sigrelse(SIGTSTP);
67629088Smarkm# endif	SOLARIS
67729088Smarkm#endif	/* SIGTSTP */
67829088Smarkm#ifndef USE_TERMIO
67929088Smarkm	ltc = oltc;
68029088Smarkm	tc = otc;
68129088Smarkm	sb = ottyb;
68229088Smarkm	lmode = olmode;
68329088Smarkm#else
68429088Smarkm	tmp_tc = old_tc;
68529088Smarkm#endif
68629088Smarkm    }
68729088Smarkm#ifndef USE_TERMIO
68829088Smarkm    ioctl(tin, TIOCLSET, (char *)&lmode);
68929088Smarkm    ioctl(tin, TIOCSLTC, (char *)&ltc);
69029088Smarkm    ioctl(tin, TIOCSETC, (char *)&tc);
69129088Smarkm    ioctl(tin, TIOCSETN, (char *)&sb);
69229088Smarkm#else
69329088Smarkm    if (tcsetattr(tin, TCSADRAIN, &tmp_tc) < 0)
69429088Smarkm	tcsetattr(tin, TCSANOW, &tmp_tc);
69529088Smarkm#endif
69629088Smarkm
69729088Smarkm#if	(!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR))
69829088Smarkm# if	!defined(sysV88)
69929088Smarkm    ioctl(tin, FIONBIO, (char *)&onoff);
70029088Smarkm    ioctl(tout, FIONBIO, (char *)&onoff);
70129088Smarkm# endif
70229088Smarkm#endif	/* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */
70329088Smarkm#if	defined(TN3270)
70429088Smarkm    if (noasynchtty == 0) {
70529088Smarkm	ioctl(tin, FIOASYNC, (char *)&onoff);
70629088Smarkm    }
70729088Smarkm#endif	/* defined(TN3270) */
70829088Smarkm
70929088Smarkm}
71029088Smarkm
71129088Smarkm/*
71229088Smarkm * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD).
71329088Smarkm */
71429088Smarkm#if B4800 != 4800
71529088Smarkm#define	DECODE_BAUD
71629088Smarkm#endif
71729088Smarkm
71829088Smarkm#ifdef	DECODE_BAUD
71929088Smarkm#ifndef	B7200
72029088Smarkm#define B7200   B4800
72129088Smarkm#endif
72229088Smarkm
72329088Smarkm#ifndef	B14400
72429088Smarkm#define B14400  B9600
72529088Smarkm#endif
72629088Smarkm
72729088Smarkm#ifndef	B19200
72829088Smarkm# define B19200 B14400
72929088Smarkm#endif
73029088Smarkm
73129088Smarkm#ifndef	B28800
73229088Smarkm#define B28800  B19200
73329088Smarkm#endif
73429088Smarkm
73529088Smarkm#ifndef	B38400
73629088Smarkm# define B38400 B28800
73729088Smarkm#endif
73829088Smarkm
73929088Smarkm#ifndef B57600
74029088Smarkm#define B57600  B38400
74129088Smarkm#endif
74229088Smarkm
74329088Smarkm#ifndef B76800
74429088Smarkm#define B76800  B57600
74529088Smarkm#endif
74629088Smarkm
74729088Smarkm#ifndef B115200
74829088Smarkm#define B115200 B76800
74929088Smarkm#endif
75029088Smarkm
75129088Smarkm#ifndef B230400
75229088Smarkm#define B230400 B115200
75329088Smarkm#endif
75429088Smarkm
75529088Smarkm
75629088Smarkm/*
75729088Smarkm * This code assumes that the values B0, B50, B75...
75829088Smarkm * are in ascending order.  They do not have to be
75929088Smarkm * contiguous.
76029088Smarkm */
76129088Smarkmstruct termspeeds {
76229088Smarkm	long speed;
76329088Smarkm	long value;
76429088Smarkm} termspeeds[] = {
76529088Smarkm	{ 0,      B0 },      { 50,    B50 },    { 75,     B75 },
76629088Smarkm	{ 110,    B110 },    { 134,   B134 },   { 150,    B150 },
76729088Smarkm	{ 200,    B200 },    { 300,   B300 },   { 600,    B600 },
76829088Smarkm	{ 1200,   B1200 },   { 1800,  B1800 },  { 2400,   B2400 },
76929088Smarkm	{ 4800,   B4800 },   { 7200,  B7200 },  { 9600,   B9600 },
77029088Smarkm	{ 14400,  B14400 },  { 19200, B19200 }, { 28800,  B28800 },
77129088Smarkm	{ 38400,  B38400 },  { 57600, B57600 }, { 115200, B115200 },
77229088Smarkm	{ 230400, B230400 }, { -1,    B230400 }
77329088Smarkm};
77429088Smarkm#endif	/* DECODE_BAUD */
77529088Smarkm
77629088Smarkm    void
77729088SmarkmTerminalSpeeds(ispeed, ospeed)
77829088Smarkm    long *ispeed;
77929088Smarkm    long *ospeed;
78029088Smarkm{
78129088Smarkm#ifdef	DECODE_BAUD
78229088Smarkm    register struct termspeeds *tp;
78329088Smarkm#endif	/* DECODE_BAUD */
78429088Smarkm    register long in, out;
78529088Smarkm
78629088Smarkm    out = cfgetospeed(&old_tc);
78729088Smarkm    in = cfgetispeed(&old_tc);
78829088Smarkm    if (in == 0)
78929088Smarkm	in = out;
79029088Smarkm
79129088Smarkm#ifdef	DECODE_BAUD
79229088Smarkm    tp = termspeeds;
79329088Smarkm    while ((tp->speed != -1) && (tp->value < in))
79429088Smarkm	tp++;
79529088Smarkm    *ispeed = tp->speed;
79629088Smarkm
79729088Smarkm    tp = termspeeds;
79829088Smarkm    while ((tp->speed != -1) && (tp->value < out))
79929088Smarkm	tp++;
80029088Smarkm    *ospeed = tp->speed;
80129088Smarkm#else	/* DECODE_BAUD */
80229088Smarkm	*ispeed = in;
80329088Smarkm	*ospeed = out;
80429088Smarkm#endif	/* DECODE_BAUD */
80529088Smarkm}
80629088Smarkm
80729088Smarkm    int
80829088SmarkmTerminalWindowSize(rows, cols)
80929088Smarkm    long *rows, *cols;
81029088Smarkm{
81129088Smarkm#ifdef	TIOCGWINSZ
81229088Smarkm    struct winsize ws;
81329088Smarkm
81429088Smarkm    if (ioctl(fileno(stdin), TIOCGWINSZ, (char *)&ws) >= 0) {
81529088Smarkm	*rows = ws.ws_row;
81629088Smarkm	*cols = ws.ws_col;
81729088Smarkm	return 1;
81829088Smarkm    }
81929088Smarkm#endif	/* TIOCGWINSZ */
82029088Smarkm    return 0;
82129088Smarkm}
82229088Smarkm
82329088Smarkm    int
82429088SmarkmNetClose(fd)
82529088Smarkm    int	fd;
82629088Smarkm{
82729088Smarkm    return close(fd);
82829088Smarkm}
82929088Smarkm
83029088Smarkm
83129088Smarkm    void
83229088SmarkmNetNonblockingIO(fd, onoff)
83329088Smarkm    int fd;
83429088Smarkm    int onoff;
83529088Smarkm{
83629088Smarkm    ioctl(fd, FIONBIO, (char *)&onoff);
83729088Smarkm}
83829088Smarkm
83929088Smarkm#if	defined(TN3270)
84029088Smarkm    void
84129088SmarkmNetSigIO(fd, onoff)
84229088Smarkm    int fd;
84329088Smarkm    int onoff;
84429088Smarkm{
84529088Smarkm    ioctl(fd, FIOASYNC, (char *)&onoff);	/* hear about input */
84629088Smarkm}
84729088Smarkm
84829088Smarkm    void
84929088SmarkmNetSetPgrp(fd)
85029088Smarkm    int fd;
85129088Smarkm{
85229088Smarkm    int myPid;
85329088Smarkm
85429088Smarkm    myPid = getpid();
85529088Smarkm    fcntl(fd, F_SETOWN, myPid);
85629088Smarkm}
85729088Smarkm#endif	/*defined(TN3270)*/
85829088Smarkm
85929088Smarkm/*
86029088Smarkm * Various signal handling routines.
86129088Smarkm */
86229088Smarkm
86329088Smarkm    /* ARGSUSED */
86429088Smarkm    SIG_FUNC_RET
86529088Smarkmdeadpeer(sig)
86629088Smarkm    int sig;
86729088Smarkm{
86829088Smarkm	setcommandmode();
86929088Smarkm	longjmp(peerdied, -1);
87029088Smarkm}
87129088Smarkm
87229088Smarkm    /* ARGSUSED */
87329088Smarkm    SIG_FUNC_RET
87429088Smarkmintr(sig)
87529088Smarkm    int sig;
87629088Smarkm{
87729088Smarkm    if (localchars) {
87829088Smarkm	intp();
87929088Smarkm	return;
88029088Smarkm    }
88129088Smarkm    setcommandmode();
88229088Smarkm    longjmp(toplevel, -1);
88329088Smarkm}
88429088Smarkm
88529088Smarkm    /* ARGSUSED */
88629088Smarkm    SIG_FUNC_RET
88729088Smarkmintr2(sig)
88829088Smarkm    int sig;
88929088Smarkm{
89029088Smarkm    if (localchars) {
89129088Smarkm#ifdef	KLUDGELINEMODE
89229088Smarkm	if (kludgelinemode)
89329088Smarkm	    sendbrk();
89429088Smarkm	else
89529088Smarkm#endif
89629088Smarkm	    sendabort();
89729088Smarkm	return;
89829088Smarkm    }
89929088Smarkm}
90029088Smarkm
90129088Smarkm#ifdef	SIGTSTP
90229088Smarkm    /* ARGSUSED */
90329088Smarkm    SIG_FUNC_RET
90429088Smarkmsusp(sig)
90529088Smarkm    int sig;
90629088Smarkm{
90729088Smarkm    if ((rlogin != _POSIX_VDISABLE) && rlogin_susp())
90829088Smarkm	return;
90929088Smarkm    if (localchars)
91029088Smarkm	sendsusp();
91129088Smarkm}
91229088Smarkm#endif
91329088Smarkm
91429088Smarkm#ifdef	SIGWINCH
91529088Smarkm    /* ARGSUSED */
91629088Smarkm    SIG_FUNC_RET
91729088Smarkmsendwin(sig)
91829088Smarkm    int sig;
91929088Smarkm{
92029088Smarkm    if (connected) {
92129088Smarkm	sendnaws();
92229088Smarkm    }
92329088Smarkm}
92429088Smarkm#endif
92529088Smarkm
92629088Smarkm#ifdef	SIGINFO
92729088Smarkm    /* ARGSUSED */
92829088Smarkm    SIG_FUNC_RET
92929088Smarkmayt(sig)
93029088Smarkm    int sig;
93129088Smarkm{
93229088Smarkm    if (connected)
93329088Smarkm	sendayt();
93429088Smarkm    else
93529088Smarkm	ayt_status();
93629088Smarkm}
93729088Smarkm#endif
93829088Smarkm
93929088Smarkm
94029088Smarkm    void
94129088Smarkmsys_telnet_init()
94229088Smarkm{
94329088Smarkm    (void) signal(SIGINT, intr);
94429088Smarkm    (void) signal(SIGQUIT, intr2);
94529088Smarkm    (void) signal(SIGPIPE, deadpeer);
94629088Smarkm#ifdef	SIGWINCH
94729088Smarkm    (void) signal(SIGWINCH, sendwin);
94829088Smarkm#endif
94929088Smarkm#ifdef	SIGTSTP
95029088Smarkm    (void) signal(SIGTSTP, susp);
95129088Smarkm#endif
95229088Smarkm#ifdef	SIGINFO
95329088Smarkm    (void) signal(SIGINFO, ayt);
95429088Smarkm#endif
95529088Smarkm
95629088Smarkm    setconnmode(0);
95729088Smarkm
95829088Smarkm    NetNonblockingIO(net, 1);
95929088Smarkm
96029088Smarkm#if	defined(TN3270)
96129088Smarkm    if (noasynchnet == 0) {			/* DBX can't handle! */
96229088Smarkm	NetSigIO(net, 1);
96329088Smarkm	NetSetPgrp(net);
96429088Smarkm    }
96529088Smarkm#endif	/* defined(TN3270) */
96629088Smarkm
96729088Smarkm#if	defined(SO_OOBINLINE)
96829088Smarkm    if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) {
96929088Smarkm	perror("SetSockOpt");
97029088Smarkm    }
97129088Smarkm#endif	/* defined(SO_OOBINLINE) */
97229088Smarkm}
97329088Smarkm
97429088Smarkm/*
97529088Smarkm * Process rings -
97629088Smarkm *
97729088Smarkm *	This routine tries to fill up/empty our various rings.
97829088Smarkm *
97929088Smarkm *	The parameter specifies whether this is a poll operation,
98029088Smarkm *	or a block-until-something-happens operation.
98129088Smarkm *
98229088Smarkm *	The return value is 1 if something happened, 0 if not.
98329088Smarkm */
98429088Smarkm
98529088Smarkm    int
98629088Smarkmprocess_rings(netin, netout, netex, ttyin, ttyout, poll)
98729088Smarkm    int poll;		/* If 0, then block until something to do */
98829088Smarkm{
98929088Smarkm    register int c;
99029088Smarkm		/* One wants to be a bit careful about setting returnValue
99129088Smarkm		 * to one, since a one implies we did some useful work,
99229088Smarkm		 * and therefore probably won't be called to block next
99329088Smarkm		 * time (TN3270 mode only).
99429088Smarkm		 */
99529088Smarkm    int returnValue = 0;
99629088Smarkm    static struct timeval TimeValue = { 0 };
99729088Smarkm
99829088Smarkm    if (netout) {
99929088Smarkm	FD_SET(net, &obits);
100029088Smarkm    }
100129088Smarkm    if (ttyout) {
100229088Smarkm	FD_SET(tout, &obits);
100329088Smarkm    }
100429088Smarkm#if	defined(TN3270)
100529088Smarkm    if (ttyin) {
100629088Smarkm	FD_SET(tin, &ibits);
100729088Smarkm    }
100829088Smarkm#else	/* defined(TN3270) */
100929088Smarkm    if (ttyin) {
101029088Smarkm	FD_SET(tin, &ibits);
101129088Smarkm    }
101229088Smarkm#endif	/* defined(TN3270) */
101329088Smarkm#if	defined(TN3270)
101429088Smarkm    if (netin) {
101529088Smarkm	FD_SET(net, &ibits);
101629088Smarkm    }
101729088Smarkm#   else /* !defined(TN3270) */
101829088Smarkm    if (netin) {
101929088Smarkm	FD_SET(net, &ibits);
102029088Smarkm    }
102129088Smarkm#   endif /* !defined(TN3270) */
102229088Smarkm    if (netex) {
102329088Smarkm	FD_SET(net, &xbits);
102429088Smarkm    }
102529088Smarkm    if ((c = select(16, &ibits, &obits, &xbits,
102629088Smarkm			(poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) {
102729088Smarkm	if (c == -1) {
102829088Smarkm		    /*
102929088Smarkm		     * we can get EINTR if we are in line mode,
103029088Smarkm		     * and the user does an escape (TSTP), or
103129088Smarkm		     * some other signal generator.
103229088Smarkm		     */
103329088Smarkm	    if (errno == EINTR) {
103429088Smarkm		return 0;
103529088Smarkm	    }
103629088Smarkm#	    if defined(TN3270)
103729088Smarkm		    /*
103829088Smarkm		     * we can get EBADF if we were in transparent
103929088Smarkm		     * mode, and the transcom process died.
104029088Smarkm		    */
104129088Smarkm	    if (errno == EBADF) {
104229088Smarkm			/*
104329088Smarkm			 * zero the bits (even though kernel does it)
104429088Smarkm			 * to make sure we are selecting on the right
104529088Smarkm			 * ones.
104629088Smarkm			*/
104729088Smarkm		FD_ZERO(&ibits);
104829088Smarkm		FD_ZERO(&obits);
104929088Smarkm		FD_ZERO(&xbits);
105029088Smarkm		return 0;
105129088Smarkm	    }
105229088Smarkm#	    endif /* defined(TN3270) */
105329088Smarkm		    /* I don't like this, does it ever happen? */
105429088Smarkm	    printf("sleep(5) from telnet, after select\r\n");
105529088Smarkm	    sleep(5);
105629088Smarkm	}
105729088Smarkm	return 0;
105829088Smarkm    }
105929088Smarkm
106029088Smarkm    /*
106129088Smarkm     * Any urgent data?
106229088Smarkm     */
106329088Smarkm    if (FD_ISSET(net, &xbits)) {
106429088Smarkm	FD_CLR(net, &xbits);
106529088Smarkm	SYNCHing = 1;
106629088Smarkm	(void) ttyflush(1);	/* flush already enqueued data */
106729088Smarkm    }
106829088Smarkm
106929088Smarkm    /*
107029088Smarkm     * Something to read from the network...
107129088Smarkm     */
107229088Smarkm    if (FD_ISSET(net, &ibits)) {
107329088Smarkm	int canread;
107429088Smarkm
107529088Smarkm	FD_CLR(net, &ibits);
107629088Smarkm	canread = ring_empty_consecutive(&netiring);
107729088Smarkm#if	!defined(SO_OOBINLINE)
107829088Smarkm	    /*
107929088Smarkm	     * In 4.2 (and some early 4.3) systems, the
108029088Smarkm	     * OOB indication and data handling in the kernel
108129088Smarkm	     * is such that if two separate TCP Urgent requests
108229088Smarkm	     * come in, one byte of TCP data will be overlaid.
108329088Smarkm	     * This is fatal for Telnet, but we try to live
108429088Smarkm	     * with it.
108529088Smarkm	     *
108629088Smarkm	     * In addition, in 4.2 (and...), a special protocol
108729088Smarkm	     * is needed to pick up the TCP Urgent data in
108829088Smarkm	     * the correct sequence.
108929088Smarkm	     *
109029088Smarkm	     * What we do is:  if we think we are in urgent
109129088Smarkm	     * mode, we look to see if we are "at the mark".
109229088Smarkm	     * If we are, we do an OOB receive.  If we run
109329088Smarkm	     * this twice, we will do the OOB receive twice,
109429088Smarkm	     * but the second will fail, since the second
109529088Smarkm	     * time we were "at the mark", but there wasn't
109629088Smarkm	     * any data there (the kernel doesn't reset
109729088Smarkm	     * "at the mark" until we do a normal read).
109829088Smarkm	     * Once we've read the OOB data, we go ahead
109929088Smarkm	     * and do normal reads.
110029088Smarkm	     *
110129088Smarkm	     * There is also another problem, which is that
110229088Smarkm	     * since the OOB byte we read doesn't put us
110329088Smarkm	     * out of OOB state, and since that byte is most
110429088Smarkm	     * likely the TELNET DM (data mark), we would
110529088Smarkm	     * stay in the TELNET SYNCH (SYNCHing) state.
110629088Smarkm	     * So, clocks to the rescue.  If we've "just"
110729088Smarkm	     * received a DM, then we test for the
110829088Smarkm	     * presence of OOB data when the receive OOB
110929088Smarkm	     * fails (and AFTER we did the normal mode read
111029088Smarkm	     * to clear "at the mark").
111129088Smarkm	     */
111229088Smarkm	if (SYNCHing) {
111329088Smarkm	    int atmark;
111429088Smarkm	    static int bogus_oob = 0, first = 1;
111529088Smarkm
111629088Smarkm	    ioctl(net, SIOCATMARK, (char *)&atmark);
111729088Smarkm	    if (atmark) {
111829088Smarkm		c = recv(net, netiring.supply, canread, MSG_OOB);
111929088Smarkm		if ((c == -1) && (errno == EINVAL)) {
112029088Smarkm		    c = recv(net, netiring.supply, canread, 0);
112129088Smarkm		    if (clocks.didnetreceive < clocks.gotDM) {
112229088Smarkm			SYNCHing = stilloob(net);
112329088Smarkm		    }
112429088Smarkm		} else if (first && c > 0) {
112529088Smarkm		    /*
112629088Smarkm		     * Bogosity check.  Systems based on 4.2BSD
112729088Smarkm		     * do not return an error if you do a second
112829088Smarkm		     * recv(MSG_OOB).  So, we do one.  If it
112929088Smarkm		     * succeeds and returns exactly the same
113029088Smarkm		     * data, then assume that we are running
113129088Smarkm		     * on a broken system and set the bogus_oob
113229088Smarkm		     * flag.  (If the data was different, then
113329088Smarkm		     * we probably got some valid new data, so
113429088Smarkm		     * increment the count...)
113529088Smarkm		     */
113629088Smarkm		    int i;
113729088Smarkm		    i = recv(net, netiring.supply + c, canread - c, MSG_OOB);
113829088Smarkm		    if (i == c &&
113929088Smarkm			 memcmp(netiring.supply, netiring.supply + c, i) == 0) {
114029088Smarkm			bogus_oob = 1;
114129088Smarkm			first = 0;
114229088Smarkm		    } else if (i < 0) {
114329088Smarkm			bogus_oob = 0;
114429088Smarkm			first = 0;
114529088Smarkm		    } else
114629088Smarkm			c += i;
114729088Smarkm		}
114829088Smarkm		if (bogus_oob && c > 0) {
114929088Smarkm		    int i;
115029088Smarkm		    /*
115129088Smarkm		     * Bogosity.  We have to do the read
115229088Smarkm		     * to clear the atmark to get out of
115329088Smarkm		     * an infinate loop.
115429088Smarkm		     */
115529088Smarkm		    i = read(net, netiring.supply + c, canread - c);
115629088Smarkm		    if (i > 0)
115729088Smarkm			c += i;
115829088Smarkm		}
115929088Smarkm	    } else {
116029088Smarkm		c = recv(net, netiring.supply, canread, 0);
116129088Smarkm	    }
116229088Smarkm	} else {
116329088Smarkm	    c = recv(net, netiring.supply, canread, 0);
116429088Smarkm	}
116529088Smarkm	settimer(didnetreceive);
116629088Smarkm#else	/* !defined(SO_OOBINLINE) */
116729088Smarkm	c = recv(net, (char *)netiring.supply, canread, 0);
116829088Smarkm#endif	/* !defined(SO_OOBINLINE) */
116929088Smarkm	if (c < 0 && errno == EWOULDBLOCK) {
117029088Smarkm	    c = 0;
117129088Smarkm	} else if (c <= 0) {
117229088Smarkm	    return -1;
117329088Smarkm	}
117429088Smarkm	if (netdata) {
117529088Smarkm	    Dump('<', netiring.supply, c);
117629088Smarkm	}
117729088Smarkm	if (c)
117829088Smarkm	    ring_supplied(&netiring, c);
117929088Smarkm	returnValue = 1;
118029088Smarkm    }
118129088Smarkm
118229088Smarkm    /*
118329088Smarkm     * Something to read from the tty...
118429088Smarkm     */
118529088Smarkm    if (FD_ISSET(tin, &ibits)) {
118629088Smarkm	FD_CLR(tin, &ibits);
118729088Smarkm	c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring));
118829088Smarkm	if (c < 0 && errno == EIO)
118929088Smarkm	    c = 0;
119029088Smarkm	if (c < 0 && errno == EWOULDBLOCK) {
119129088Smarkm	    c = 0;
119229088Smarkm	} else {
119329088Smarkm	    /* EOF detection for line mode!!!! */
119429088Smarkm	    if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && isatty(tin)) {
119529088Smarkm			/* must be an EOF... */
119629088Smarkm		*ttyiring.supply = termEofChar;
119729088Smarkm		c = 1;
119829088Smarkm	    }
119929088Smarkm	    if (c <= 0) {
120029088Smarkm		return -1;
120129088Smarkm	    }
120229088Smarkm	    if (termdata) {
120329088Smarkm		Dump('<', ttyiring.supply, c);
120429088Smarkm	    }
120529088Smarkm	    ring_supplied(&ttyiring, c);
120629088Smarkm	}
120729088Smarkm	returnValue = 1;		/* did something useful */
120829088Smarkm    }
120929088Smarkm
121029088Smarkm    if (FD_ISSET(net, &obits)) {
121129088Smarkm	FD_CLR(net, &obits);
121229088Smarkm	returnValue |= netflush();
121329088Smarkm    }
121429088Smarkm    if (FD_ISSET(tout, &obits)) {
121529088Smarkm	FD_CLR(tout, &obits);
121629088Smarkm	returnValue |= (ttyflush(SYNCHing|flushout) > 0);
121729088Smarkm    }
121829088Smarkm
121929088Smarkm    return returnValue;
122029088Smarkm}
1221