157416Smarkm/*
257416Smarkm * Copyright (c) 1988, 1990, 1993
357416Smarkm *	The Regents of the University of California.  All rights reserved.
457416Smarkm *
557416Smarkm * Redistribution and use in source and binary forms, with or without
657416Smarkm * modification, are permitted provided that the following conditions
757416Smarkm * are met:
857416Smarkm * 1. Redistributions of source code must retain the above copyright
957416Smarkm *    notice, this list of conditions and the following disclaimer.
1057416Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1157416Smarkm *    notice, this list of conditions and the following disclaimer in the
1257416Smarkm *    documentation and/or other materials provided with the distribution.
1357416Smarkm * 3. All advertising materials mentioning features or use of this software
1457416Smarkm *    must display the following acknowledgement:
1557416Smarkm *	This product includes software developed by the University of
1657416Smarkm *	California, Berkeley and its contributors.
1757416Smarkm * 4. Neither the name of the University nor the names of its contributors
1857416Smarkm *    may be used to endorse or promote products derived from this software
1957416Smarkm *    without specific prior written permission.
2057416Smarkm *
2157416Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2257416Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2357416Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2457416Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2557416Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2657416Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2757416Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2857416Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2957416Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3057416Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3157416Smarkm * SUCH DAMAGE.
3257416Smarkm */
3357416Smarkm
3457416Smarkm#include "telnet_locl.h"
3557416Smarkm
36178825SdfrRCSID("$Id: sys_bsd.c 10941 2002-04-18 16:18:43Z joda $");
3757416Smarkm
3857416Smarkm/*
3957416Smarkm * The following routines try to encapsulate what is system dependent
4057416Smarkm * (at least between 4.x and dos) which is used in telnet.c.
4157416Smarkm */
4257416Smarkm
4357416Smarkmint
4457416Smarkm	tout,			/* Output file descriptor */
4557416Smarkm	tin,			/* Input file descriptor */
4657416Smarkm	net;
4757416Smarkm
4857416Smarkmstruct	termios old_tc = { 0 };
4957416Smarkmextern struct termios new_tc;
5057416Smarkm
5157416Smarkm# ifndef	TCSANOW
5257416Smarkm#  ifdef TCSETS
5357416Smarkm#   define	TCSANOW		TCSETS
5457416Smarkm#   define	TCSADRAIN	TCSETSW
5557416Smarkm#   define	tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
5657416Smarkm#  else
5757416Smarkm#   ifdef TCSETA
5857416Smarkm#    define	TCSANOW		TCSETA
5957416Smarkm#    define	TCSADRAIN	TCSETAW
6057416Smarkm#    define	tcgetattr(f, t) ioctl(f, TCGETA, (char *)t)
6157416Smarkm#   else
6257416Smarkm#    define	TCSANOW		TIOCSETA
6357416Smarkm#    define	TCSADRAIN	TIOCSETAW
6457416Smarkm#    define	tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t)
6557416Smarkm#   endif
6657416Smarkm#  endif
6757416Smarkm#  define	tcsetattr(f, a, t) ioctl(f, a, (char *)t)
6857416Smarkm#  define	cfgetospeed(ptr)	((ptr)->c_cflag&CBAUD)
6957416Smarkm#  ifdef CIBAUD
7057416Smarkm#   define	cfgetispeed(ptr)	(((ptr)->c_cflag&CIBAUD) >> IBSHIFT)
7157416Smarkm#  else
7257416Smarkm#   define	cfgetispeed(ptr)	cfgetospeed(ptr)
7357416Smarkm#  endif
7457416Smarkm# endif /* TCSANOW */
7557416Smarkm
7657416Smarkmstatic fd_set ibits, obits, xbits;
7757416Smarkm
7857416Smarkm
7957416Smarkmvoid
8057416Smarkminit_sys(void)
8157416Smarkm{
8257416Smarkm    tout = fileno(stdout);
8357416Smarkm    tin = fileno(stdin);
8457416Smarkm    FD_ZERO(&ibits);
8557416Smarkm    FD_ZERO(&obits);
8657416Smarkm    FD_ZERO(&xbits);
8757416Smarkm
8857416Smarkm    errno = 0;
8957416Smarkm}
9057416Smarkm
9157416Smarkm
9257416Smarkmint
9357416SmarkmTerminalWrite(char *buf, int n)
9457416Smarkm{
9557416Smarkm    return write(tout, buf, n);
9657416Smarkm}
9757416Smarkm
9857416Smarkmint
9957416SmarkmTerminalRead(unsigned char *buf, int n)
10057416Smarkm{
10157416Smarkm    return read(tin, buf, n);
10257416Smarkm}
10357416Smarkm
10457416Smarkm/*
10557416Smarkm *
10657416Smarkm */
10757416Smarkm
10857416Smarkmint
10957416SmarkmTerminalAutoFlush(void)
11057416Smarkm{
11157416Smarkm#if	defined(LNOFLSH)
11257416Smarkm    int flush;
11357416Smarkm
11457416Smarkm    ioctl(0, TIOCLGET, (char *)&flush);
11557416Smarkm    return !(flush&LNOFLSH);	/* if LNOFLSH, no autoflush */
11657416Smarkm#else	/* LNOFLSH */
11757416Smarkm    return 1;
11857416Smarkm#endif	/* LNOFLSH */
11957416Smarkm}
12057416Smarkm
12157416Smarkm/*
12257416Smarkm * TerminalSpecialChars()
12357416Smarkm *
12457416Smarkm * Look at an input character to see if it is a special character
12557416Smarkm * and decide what to do.
12657416Smarkm *
12757416Smarkm * Output:
12857416Smarkm *
12957416Smarkm *	0	Don't add this character.
13057416Smarkm *	1	Do add this character
13157416Smarkm */
13257416Smarkm
13357416Smarkmint
13457416SmarkmTerminalSpecialChars(int c)
13557416Smarkm{
13657416Smarkm    if (c == termIntChar) {
13757416Smarkm	intp();
13857416Smarkm	return 0;
13957416Smarkm    } else if (c == termQuitChar) {
14057416Smarkm#ifdef	KLUDGELINEMODE
14157416Smarkm	if (kludgelinemode)
14257416Smarkm	    sendbrk();
14357416Smarkm	else
14457416Smarkm#endif
14557416Smarkm	    sendabort();
14657416Smarkm	return 0;
14757416Smarkm    } else if (c == termEofChar) {
14857416Smarkm	if (my_want_state_is_will(TELOPT_LINEMODE)) {
14957416Smarkm	    sendeof();
15057416Smarkm	    return 0;
15157416Smarkm	}
15257416Smarkm	return 1;
15357416Smarkm    } else if (c == termSuspChar) {
15457416Smarkm	sendsusp();
15557416Smarkm	return(0);
15657416Smarkm    } else if (c == termFlushChar) {
15757416Smarkm	xmitAO();		/* Transmit Abort Output */
15857416Smarkm	return 0;
15957416Smarkm    } else if (!MODE_LOCAL_CHARS(globalmode)) {
16057416Smarkm	if (c == termKillChar) {
16157416Smarkm	    xmitEL();
16257416Smarkm	    return 0;
16357416Smarkm	} else if (c == termEraseChar) {
16457416Smarkm	    xmitEC();		/* Transmit Erase Character */
16557416Smarkm	    return 0;
16657416Smarkm	}
16757416Smarkm    }
16857416Smarkm    return 1;
16957416Smarkm}
17057416Smarkm
17157416Smarkm
17257416Smarkm/*
17357416Smarkm * Flush output to the terminal
17457416Smarkm */
17557416Smarkm
17657416Smarkmvoid
17757416SmarkmTerminalFlushOutput(void)
17857416Smarkm{
17957416Smarkm#ifdef	TIOCFLUSH
18057416Smarkm    ioctl(fileno(stdout), TIOCFLUSH, (char *) 0);
18157416Smarkm#else
18257416Smarkm    ioctl(fileno(stdout), TCFLSH, (char *) 0);
18357416Smarkm#endif
18457416Smarkm}
18557416Smarkm
18657416Smarkmvoid
18757416SmarkmTerminalSaveState(void)
18857416Smarkm{
18957416Smarkm    tcgetattr(0, &old_tc);
19057416Smarkm
19157416Smarkm    new_tc = old_tc;
19257416Smarkm
19357416Smarkm#ifndef	VDISCARD
19457416Smarkm    termFlushChar = CONTROL('O');
19557416Smarkm#endif
19657416Smarkm#ifndef	VWERASE
19757416Smarkm    termWerasChar = CONTROL('W');
19857416Smarkm#endif
19957416Smarkm#ifndef	VREPRINT
20057416Smarkm    termRprntChar = CONTROL('R');
20157416Smarkm#endif
20257416Smarkm#ifndef	VLNEXT
20357416Smarkm    termLiteralNextChar = CONTROL('V');
20457416Smarkm#endif
20557416Smarkm#ifndef	VSTART
20657416Smarkm    termStartChar = CONTROL('Q');
20757416Smarkm#endif
20857416Smarkm#ifndef	VSTOP
20957416Smarkm    termStopChar = CONTROL('S');
21057416Smarkm#endif
21157416Smarkm#ifndef	VSTATUS
21257416Smarkm    termAytChar = CONTROL('T');
21357416Smarkm#endif
21457416Smarkm}
21557416Smarkm
21657416Smarkmcc_t*
21757416Smarkmtcval(int func)
21857416Smarkm{
21957416Smarkm    switch(func) {
22057416Smarkm    case SLC_IP:	return(&termIntChar);
22157416Smarkm    case SLC_ABORT:	return(&termQuitChar);
22257416Smarkm    case SLC_EOF:	return(&termEofChar);
22357416Smarkm    case SLC_EC:	return(&termEraseChar);
22457416Smarkm    case SLC_EL:	return(&termKillChar);
22557416Smarkm    case SLC_XON:	return(&termStartChar);
22657416Smarkm    case SLC_XOFF:	return(&termStopChar);
22757416Smarkm    case SLC_FORW1:	return(&termForw1Char);
22857416Smarkm    case SLC_FORW2:	return(&termForw2Char);
22957416Smarkm# ifdef	VDISCARD
23057416Smarkm    case SLC_AO:	return(&termFlushChar);
23157416Smarkm# endif
23257416Smarkm# ifdef	VSUSP
23357416Smarkm    case SLC_SUSP:	return(&termSuspChar);
23457416Smarkm# endif
23557416Smarkm# ifdef	VWERASE
23657416Smarkm    case SLC_EW:	return(&termWerasChar);
23757416Smarkm# endif
23857416Smarkm# ifdef	VREPRINT
23957416Smarkm    case SLC_RP:	return(&termRprntChar);
24057416Smarkm# endif
24157416Smarkm# ifdef	VLNEXT
24257416Smarkm    case SLC_LNEXT:	return(&termLiteralNextChar);
24357416Smarkm# endif
24457416Smarkm# ifdef	VSTATUS
24557416Smarkm    case SLC_AYT:	return(&termAytChar);
24657416Smarkm# endif
24757416Smarkm
24857416Smarkm    case SLC_SYNCH:
24957416Smarkm    case SLC_BRK:
25057416Smarkm    case SLC_EOR:
25157416Smarkm    default:
25257416Smarkm	return((cc_t *)0);
25357416Smarkm    }
25457416Smarkm}
25557416Smarkm
25657416Smarkmvoid
25757416SmarkmTerminalDefaultChars(void)
25857416Smarkm{
25957416Smarkm    memmove(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc));
26057416Smarkm# ifndef	VDISCARD
26157416Smarkm    termFlushChar = CONTROL('O');
26257416Smarkm# endif
26357416Smarkm# ifndef	VWERASE
26457416Smarkm    termWerasChar = CONTROL('W');
26557416Smarkm# endif
26657416Smarkm# ifndef	VREPRINT
26757416Smarkm    termRprntChar = CONTROL('R');
26857416Smarkm# endif
26957416Smarkm# ifndef	VLNEXT
27057416Smarkm    termLiteralNextChar = CONTROL('V');
27157416Smarkm# endif
27257416Smarkm# ifndef	VSTART
27357416Smarkm    termStartChar = CONTROL('Q');
27457416Smarkm# endif
27557416Smarkm# ifndef	VSTOP
27657416Smarkm    termStopChar = CONTROL('S');
27757416Smarkm# endif
27857416Smarkm# ifndef	VSTATUS
27957416Smarkm    termAytChar = CONTROL('T');
28057416Smarkm# endif
28157416Smarkm}
28257416Smarkm
28357416Smarkm#ifdef notdef
28457416Smarkmvoid
28557416SmarkmTerminalRestoreState()
28657416Smarkm{
28757416Smarkm}
28857416Smarkm#endif
28957416Smarkm
29057416Smarkm/*
29157416Smarkm * TerminalNewMode - set up terminal to a specific mode.
29257416Smarkm *	MODE_ECHO: do local terminal echo
29357416Smarkm *	MODE_FLOW: do local flow control
29457416Smarkm *	MODE_TRAPSIG: do local mapping to TELNET IAC sequences
29557416Smarkm *	MODE_EDIT: do local line editing
29657416Smarkm *
29757416Smarkm *	Command mode:
29857416Smarkm *		MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG
29957416Smarkm *		local echo
30057416Smarkm *		local editing
30157416Smarkm *		local xon/xoff
30257416Smarkm *		local signal mapping
30357416Smarkm *
30457416Smarkm *	Linemode:
30557416Smarkm *		local/no editing
30657416Smarkm *	Both Linemode and Single Character mode:
30757416Smarkm *		local/remote echo
30857416Smarkm *		local/no xon/xoff
30957416Smarkm *		local/no signal mapping
31057416Smarkm */
31157416Smarkm
31257416Smarkm
31357416Smarkm#ifdef	SIGTSTP
31472445Sassarstatic RETSIGTYPE susp(int);
31557416Smarkm#endif	/* SIGTSTP */
31657416Smarkm#ifdef	SIGINFO
31772445Sassarstatic RETSIGTYPE ayt(int);
31857416Smarkm#endif
31957416Smarkm
32057416Smarkmvoid
32157416SmarkmTerminalNewMode(int f)
32257416Smarkm{
32357416Smarkm    static int prevmode = 0;
32457416Smarkm    struct termios tmp_tc;
32557416Smarkm    int onoff;
32657416Smarkm    int old;
32757416Smarkm    cc_t esc;
32857416Smarkm
32957416Smarkm    globalmode = f&~MODE_FORCE;
33057416Smarkm    if (prevmode == f)
33157416Smarkm	return;
33257416Smarkm
33357416Smarkm    /*
33457416Smarkm     * Write any outstanding data before switching modes
33557416Smarkm     * ttyflush() returns 0 only when there is no more data
33657416Smarkm     * left to write out, it returns -1 if it couldn't do
33757416Smarkm     * anything at all, otherwise it returns 1 + the number
33857416Smarkm     * of characters left to write.
33957416Smarkm     */
34057416Smarkm    old = ttyflush(SYNCHing|flushout);
34157416Smarkm    if (old < 0 || old > 1) {
34257416Smarkm	tcgetattr(tin, &tmp_tc);
34357416Smarkm	do {
34457416Smarkm	    /*
34557416Smarkm	     * Wait for data to drain, then flush again.
34657416Smarkm	     */
34757416Smarkm	    tcsetattr(tin, TCSADRAIN, &tmp_tc);
34857416Smarkm	    old = ttyflush(SYNCHing|flushout);
34957416Smarkm	} while (old < 0 || old > 1);
35057416Smarkm    }
35157416Smarkm
35257416Smarkm    old = prevmode;
35357416Smarkm    prevmode = f&~MODE_FORCE;
35457416Smarkm    tmp_tc = new_tc;
35557416Smarkm
35657416Smarkm    if (f&MODE_ECHO) {
35757416Smarkm	tmp_tc.c_lflag |= ECHO;
35857416Smarkm	tmp_tc.c_oflag |= ONLCR;
35957416Smarkm	if (crlf)
36057416Smarkm		tmp_tc.c_iflag |= ICRNL;
36157416Smarkm    } else {
36257416Smarkm	tmp_tc.c_lflag &= ~ECHO;
36357416Smarkm	tmp_tc.c_oflag &= ~ONLCR;
36457416Smarkm# ifdef notdef
36557416Smarkm	if (crlf)
36657416Smarkm		tmp_tc.c_iflag &= ~ICRNL;
36757416Smarkm# endif
36857416Smarkm    }
36957416Smarkm
37057416Smarkm    if ((f&MODE_FLOW) == 0) {
37157416Smarkm	tmp_tc.c_iflag &= ~(IXOFF|IXON);	/* Leave the IXANY bit alone */
37257416Smarkm    } else {
37357416Smarkm	if (restartany < 0) {
37457416Smarkm		tmp_tc.c_iflag |= IXOFF|IXON;	/* Leave the IXANY bit alone */
37557416Smarkm	} else if (restartany > 0) {
37657416Smarkm		tmp_tc.c_iflag |= IXOFF|IXON|IXANY;
37757416Smarkm	} else {
37857416Smarkm		tmp_tc.c_iflag |= IXOFF|IXON;
37957416Smarkm		tmp_tc.c_iflag &= ~IXANY;
38057416Smarkm	}
38157416Smarkm    }
38257416Smarkm
38357416Smarkm    if ((f&MODE_TRAPSIG) == 0) {
38457416Smarkm	tmp_tc.c_lflag &= ~ISIG;
38557416Smarkm	localchars = 0;
38657416Smarkm    } else {
38757416Smarkm	tmp_tc.c_lflag |= ISIG;
38857416Smarkm	localchars = 1;
38957416Smarkm    }
39057416Smarkm
39157416Smarkm    if (f&MODE_EDIT) {
39257416Smarkm	tmp_tc.c_lflag |= ICANON;
39357416Smarkm    } else {
39457416Smarkm	tmp_tc.c_lflag &= ~ICANON;
39557416Smarkm	tmp_tc.c_iflag &= ~ICRNL;
39657416Smarkm	tmp_tc.c_cc[VMIN] = 1;
39757416Smarkm	tmp_tc.c_cc[VTIME] = 0;
39857416Smarkm    }
39957416Smarkm
40057416Smarkm    if ((f&(MODE_EDIT|MODE_TRAPSIG)) == 0) {
40157416Smarkm# ifdef VLNEXT
40257416Smarkm	tmp_tc.c_cc[VLNEXT] = (cc_t)(_POSIX_VDISABLE);
40357416Smarkm# endif
40457416Smarkm    }
40557416Smarkm
40657416Smarkm    if (f&MODE_SOFT_TAB) {
40757416Smarkm# ifdef	OXTABS
40857416Smarkm	tmp_tc.c_oflag |= OXTABS;
40957416Smarkm# endif
41057416Smarkm# ifdef	TABDLY
41157416Smarkm	tmp_tc.c_oflag &= ~TABDLY;
41257416Smarkm	tmp_tc.c_oflag |= TAB3;
41357416Smarkm# endif
41457416Smarkm    } else {
41557416Smarkm# ifdef	OXTABS
41657416Smarkm	tmp_tc.c_oflag &= ~OXTABS;
41757416Smarkm# endif
41857416Smarkm# ifdef	TABDLY
41957416Smarkm	tmp_tc.c_oflag &= ~TABDLY;
42057416Smarkm# endif
42157416Smarkm    }
42257416Smarkm
42357416Smarkm    if (f&MODE_LIT_ECHO) {
42457416Smarkm# ifdef	ECHOCTL
42557416Smarkm	tmp_tc.c_lflag &= ~ECHOCTL;
42657416Smarkm# endif
42757416Smarkm    } else {
42857416Smarkm# ifdef	ECHOCTL
42957416Smarkm	tmp_tc.c_lflag |= ECHOCTL;
43057416Smarkm# endif
43157416Smarkm    }
43257416Smarkm
43357416Smarkm    if (f == -1) {
43457416Smarkm	onoff = 0;
43557416Smarkm    } else {
43657416Smarkm	if (f & MODE_INBIN)
43757416Smarkm		tmp_tc.c_iflag &= ~ISTRIP;
43857416Smarkm	else
43957416Smarkm		tmp_tc.c_iflag |= ISTRIP;
44057416Smarkm	if ((f & MODE_OUTBIN) || (f & MODE_OUT8)) {
44157416Smarkm		tmp_tc.c_cflag &= ~(CSIZE|PARENB);
44257416Smarkm		tmp_tc.c_cflag |= CS8;
44357416Smarkm		if(f & MODE_OUTBIN)
44457416Smarkm		    tmp_tc.c_oflag &= ~OPOST;
44557416Smarkm		else
44657416Smarkm		    tmp_tc.c_oflag |= OPOST;
44757416Smarkm	} else {
44857416Smarkm		tmp_tc.c_cflag &= ~(CSIZE|PARENB);
44957416Smarkm		tmp_tc.c_cflag |= old_tc.c_cflag & (CSIZE|PARENB);
45057416Smarkm		tmp_tc.c_oflag |= OPOST;
45157416Smarkm	}
45257416Smarkm	onoff = 1;
45357416Smarkm    }
45457416Smarkm
45557416Smarkm    if (f != -1) {
45657416Smarkm
45757416Smarkm#ifdef	SIGTSTP
45857416Smarkm	signal(SIGTSTP, susp);
45957416Smarkm#endif	/* SIGTSTP */
46057416Smarkm#ifdef	SIGINFO
46157416Smarkm	signal(SIGINFO, ayt);
46257416Smarkm#endif
46357416Smarkm#ifdef NOKERNINFO
46457416Smarkm	tmp_tc.c_lflag |= NOKERNINFO;
46557416Smarkm#endif
46657416Smarkm	/*
46757416Smarkm	 * We don't want to process ^Y here.  It's just another
46857416Smarkm	 * character that we'll pass on to the back end.  It has
46957416Smarkm	 * to process it because it will be processed when the
47057416Smarkm	 * user attempts to read it, not when we send it.
47157416Smarkm	 */
47257416Smarkm# ifdef	VDSUSP
47357416Smarkm	tmp_tc.c_cc[VDSUSP] = (cc_t)(_POSIX_VDISABLE);
47457416Smarkm# endif
47557416Smarkm	/*
47657416Smarkm	 * If the VEOL character is already set, then use VEOL2,
47757416Smarkm	 * otherwise use VEOL.
47857416Smarkm	 */
47957416Smarkm	esc = (rlogin != _POSIX_VDISABLE) ? rlogin : escape;
48057416Smarkm	if ((tmp_tc.c_cc[VEOL] != esc)
48157416Smarkm# ifdef	VEOL2
48257416Smarkm	    && (tmp_tc.c_cc[VEOL2] != esc)
48357416Smarkm# endif
48457416Smarkm	    ) {
48557416Smarkm		if (tmp_tc.c_cc[VEOL] == (cc_t)(_POSIX_VDISABLE))
48657416Smarkm		    tmp_tc.c_cc[VEOL] = esc;
48757416Smarkm# ifdef	VEOL2
48857416Smarkm		else if (tmp_tc.c_cc[VEOL2] == (cc_t)(_POSIX_VDISABLE))
48957416Smarkm		    tmp_tc.c_cc[VEOL2] = esc;
49057416Smarkm# endif
49157416Smarkm	}
49257416Smarkm    } else {
49357416Smarkm        sigset_t sm;
49490926Snectar
49557416Smarkm#ifdef	SIGINFO
49657416Smarkm	signal(SIGINFO, ayt_status);
49757416Smarkm#endif
49857416Smarkm#ifdef	SIGTSTP
49957416Smarkm	signal(SIGTSTP, SIG_DFL);
50057416Smarkm	sigemptyset(&sm);
50157416Smarkm	sigaddset(&sm, SIGTSTP);
50257416Smarkm	sigprocmask(SIG_UNBLOCK, &sm, NULL);
50357416Smarkm#endif	/* SIGTSTP */
50457416Smarkm	tmp_tc = old_tc;
50557416Smarkm    }
50657416Smarkm    if (tcsetattr(tin, TCSADRAIN, &tmp_tc) < 0)
50757416Smarkm	tcsetattr(tin, TCSANOW, &tmp_tc);
50857416Smarkm
50957416Smarkm    ioctl(tin, FIONBIO, (char *)&onoff);
51057416Smarkm    ioctl(tout, FIONBIO, (char *)&onoff);
51157416Smarkm
51257416Smarkm}
51357416Smarkm
51457416Smarkm/*
51557416Smarkm * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD).
51657416Smarkm */
51757416Smarkm#if B4800 != 4800
51857416Smarkm#define	DECODE_BAUD
51957416Smarkm#endif
52057416Smarkm
52157416Smarkm#ifdef	DECODE_BAUD
52257416Smarkm#ifndef	B7200
52357416Smarkm#define B7200   B4800
52457416Smarkm#endif
52557416Smarkm
52657416Smarkm#ifndef	B14400
52757416Smarkm#define B14400  B9600
52857416Smarkm#endif
52957416Smarkm
53057416Smarkm#ifndef	B19200
53157416Smarkm# define B19200 B14400
53257416Smarkm#endif
53357416Smarkm
53457416Smarkm#ifndef	B28800
53557416Smarkm#define B28800  B19200
53657416Smarkm#endif
53757416Smarkm
53857416Smarkm#ifndef	B38400
53957416Smarkm# define B38400 B28800
54057416Smarkm#endif
54157416Smarkm
54257416Smarkm#ifndef B57600
54357416Smarkm#define B57600  B38400
54457416Smarkm#endif
54557416Smarkm
54657416Smarkm#ifndef B76800
54757416Smarkm#define B76800  B57600
54857416Smarkm#endif
54957416Smarkm
55057416Smarkm#ifndef B115200
55157416Smarkm#define B115200 B76800
55257416Smarkm#endif
55357416Smarkm
55457416Smarkm#ifndef B230400
55557416Smarkm#define B230400 B115200
55657416Smarkm#endif
55757416Smarkm
55857416Smarkm
55957416Smarkm/*
56057416Smarkm * This code assumes that the values B0, B50, B75...
56157416Smarkm * are in ascending order.  They do not have to be
56257416Smarkm * contiguous.
56357416Smarkm */
56457416Smarkmstruct termspeeds {
56557416Smarkm	long speed;
56657416Smarkm	long value;
56757416Smarkm} termspeeds[] = {
56857416Smarkm	{ 0,      B0 },      { 50,    B50 },    { 75,     B75 },
56957416Smarkm	{ 110,    B110 },    { 134,   B134 },   { 150,    B150 },
57057416Smarkm	{ 200,    B200 },    { 300,   B300 },   { 600,    B600 },
57157416Smarkm	{ 1200,   B1200 },   { 1800,  B1800 },  { 2400,   B2400 },
57257416Smarkm	{ 4800,   B4800 },   { 7200,  B7200 },  { 9600,   B9600 },
57357416Smarkm	{ 14400,  B14400 },  { 19200, B19200 }, { 28800,  B28800 },
57457416Smarkm	{ 38400,  B38400 },  { 57600, B57600 }, { 115200, B115200 },
57557416Smarkm	{ 230400, B230400 }, { -1,    B230400 }
57657416Smarkm};
57757416Smarkm#endif	/* DECODE_BAUD */
57857416Smarkm
57957416Smarkmvoid
58057416SmarkmTerminalSpeeds(long *input_speed, long *output_speed)
58157416Smarkm{
58257416Smarkm#ifdef	DECODE_BAUD
58357416Smarkm    struct termspeeds *tp;
58457416Smarkm#endif	/* DECODE_BAUD */
58557416Smarkm    long in, out;
58657416Smarkm
58757416Smarkm    out = cfgetospeed(&old_tc);
58857416Smarkm    in = cfgetispeed(&old_tc);
58957416Smarkm    if (in == 0)
59057416Smarkm	in = out;
59157416Smarkm
59257416Smarkm#ifdef	DECODE_BAUD
59357416Smarkm    tp = termspeeds;
59457416Smarkm    while ((tp->speed != -1) && (tp->value < in))
59557416Smarkm	tp++;
59657416Smarkm    *input_speed = tp->speed;
59757416Smarkm
59857416Smarkm    tp = termspeeds;
59957416Smarkm    while ((tp->speed != -1) && (tp->value < out))
60057416Smarkm	tp++;
60157416Smarkm    *output_speed = tp->speed;
60257416Smarkm#else	/* DECODE_BAUD */
60357416Smarkm	*input_speed = in;
60457416Smarkm	*output_speed = out;
60557416Smarkm#endif	/* DECODE_BAUD */
60657416Smarkm}
60757416Smarkm
60857416Smarkmint
60957416SmarkmTerminalWindowSize(long *rows, long *cols)
61057416Smarkm{
61157416Smarkm    struct winsize ws;
61257416Smarkm
61357416Smarkm    if (get_window_size (STDIN_FILENO, &ws) == 0) {
61457416Smarkm	*rows = ws.ws_row;
61557416Smarkm	*cols = ws.ws_col;
61657416Smarkm	return 1;
61757416Smarkm    } else
61857416Smarkm	return 0;
61957416Smarkm}
62057416Smarkm
62157416Smarkmint
62257416SmarkmNetClose(int fd)
62357416Smarkm{
62457416Smarkm    return close(fd);
62557416Smarkm}
62657416Smarkm
62757416Smarkm
62857416Smarkmvoid
62957416SmarkmNetNonblockingIO(int fd, int onoff)
63057416Smarkm{
63157416Smarkm    ioctl(fd, FIONBIO, (char *)&onoff);
63257416Smarkm}
63357416Smarkm
63457416Smarkm
63557416Smarkm/*
63657416Smarkm * Various signal handling routines.
63757416Smarkm */
63857416Smarkm
63957416Smarkmstatic RETSIGTYPE deadpeer(int),
64057416Smarkm  intr(int), intr2(int), susp(int), sendwin(int);
64157416Smarkm#ifdef SIGINFO
64257416Smarkmstatic RETSIGTYPE ayt(int);
64357416Smarkm#endif
64457416Smarkm
64557416Smarkm
64657416Smarkm    /* ARGSUSED */
64757416Smarkmstatic RETSIGTYPE
64857416Smarkmdeadpeer(int sig)
64957416Smarkm{
65057416Smarkm	setcommandmode();
65157416Smarkm	longjmp(peerdied, -1);
65257416Smarkm}
65357416Smarkm
65490926Snectarint intr_happened = 0;
65590926Snectarint intr_waiting = 0;
65690926Snectar
65757416Smarkm    /* ARGSUSED */
65857416Smarkmstatic RETSIGTYPE
65957416Smarkmintr(int sig)
66057416Smarkm{
66190926Snectar    if (intr_waiting) {
66290926Snectar	intr_happened = 1;
66390926Snectar	return;
66490926Snectar    }
66557416Smarkm    if (localchars) {
66657416Smarkm	intp();
66757416Smarkm	return;
66857416Smarkm    }
66957416Smarkm    setcommandmode();
67057416Smarkm    longjmp(toplevel, -1);
67157416Smarkm}
67257416Smarkm
67357416Smarkm    /* ARGSUSED */
67457416Smarkmstatic RETSIGTYPE
67557416Smarkmintr2(int sig)
67657416Smarkm{
67757416Smarkm    if (localchars) {
67857416Smarkm#ifdef	KLUDGELINEMODE
67957416Smarkm	if (kludgelinemode)
68057416Smarkm	    sendbrk();
68157416Smarkm	else
68257416Smarkm#endif
68357416Smarkm	    sendabort();
68457416Smarkm	return;
68557416Smarkm    }
68657416Smarkm}
68757416Smarkm
68857416Smarkm#ifdef	SIGTSTP
68957416Smarkm    /* ARGSUSED */
69057416Smarkmstatic RETSIGTYPE
69157416Smarkmsusp(int sig)
69257416Smarkm{
69357416Smarkm    if ((rlogin != _POSIX_VDISABLE) && rlogin_susp())
69457416Smarkm	return;
69557416Smarkm    if (localchars)
69657416Smarkm	sendsusp();
69757416Smarkm}
69857416Smarkm#endif
69957416Smarkm
70057416Smarkm#ifdef	SIGWINCH
70157416Smarkm    /* ARGSUSED */
70257416Smarkmstatic RETSIGTYPE
70357416Smarkmsendwin(int sig)
70457416Smarkm{
70557416Smarkm    if (connected) {
70657416Smarkm	sendnaws();
70757416Smarkm    }
70857416Smarkm}
70957416Smarkm#endif
71057416Smarkm
71157416Smarkm#ifdef	SIGINFO
71257416Smarkm    /* ARGSUSED */
71357416Smarkmstatic RETSIGTYPE
71457416Smarkmayt(int sig)
71557416Smarkm{
71657416Smarkm    if (connected)
71757416Smarkm	sendayt();
71857416Smarkm    else
71957416Smarkm	ayt_status(sig);
72057416Smarkm}
72157416Smarkm#endif
72257416Smarkm
72357416Smarkm
72457416Smarkmvoid
72557416Smarkmsys_telnet_init(void)
72657416Smarkm{
72757416Smarkm    signal(SIGINT, intr);
72857416Smarkm    signal(SIGQUIT, intr2);
72957416Smarkm    signal(SIGPIPE, deadpeer);
73057416Smarkm#ifdef	SIGWINCH
73157416Smarkm    signal(SIGWINCH, sendwin);
73257416Smarkm#endif
73357416Smarkm#ifdef	SIGTSTP
73457416Smarkm    signal(SIGTSTP, susp);
73557416Smarkm#endif
73657416Smarkm#ifdef	SIGINFO
73757416Smarkm    signal(SIGINFO, ayt);
73857416Smarkm#endif
73957416Smarkm
74057416Smarkm    setconnmode(0);
74157416Smarkm
74257416Smarkm    NetNonblockingIO(net, 1);
74357416Smarkm
74457416Smarkm
74557416Smarkm#if	defined(SO_OOBINLINE)
746102644Snectar    if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1)
747102644Snectar	perror("setsockopt (SO_OOBINLINE) (ignored)");
74857416Smarkm#endif	/* defined(SO_OOBINLINE) */
74957416Smarkm}
75057416Smarkm
75157416Smarkm/*
75257416Smarkm * Process rings -
75357416Smarkm *
75457416Smarkm *	This routine tries to fill up/empty our various rings.
75557416Smarkm *
75657416Smarkm *	The parameter specifies whether this is a poll operation,
75757416Smarkm *	or a block-until-something-happens operation.
75857416Smarkm *
75957416Smarkm *	The return value is 1 if something happened, 0 if not.
76057416Smarkm */
76157416Smarkm
76257416Smarkmint
76357416Smarkmprocess_rings(int netin,
76457416Smarkm	      int netout,
76557416Smarkm	      int netex,
76657416Smarkm	      int ttyin,
76757416Smarkm	      int ttyout,
76857416Smarkm	      int poll) /* If 0, then block until something to do */
76957416Smarkm{
77057416Smarkm    int c;
77157416Smarkm		/* One wants to be a bit careful about setting returnValue
77257416Smarkm		 * to one, since a one implies we did some useful work,
77357416Smarkm		 * and therefore probably won't be called to block next
77457416Smarkm		 * time (TN3270 mode only).
77557416Smarkm		 */
77657416Smarkm    int returnValue = 0;
77757416Smarkm    static struct timeval TimeValue = { 0 };
77857416Smarkm
77972445Sassar    if (net >= FD_SETSIZE
78072445Sassar	|| tout >= FD_SETSIZE
78172445Sassar	|| tin >= FD_SETSIZE)
78272445Sassar	errx (1, "fd too large");
78372445Sassar
78457416Smarkm    if (netout) {
78557416Smarkm	FD_SET(net, &obits);
78657416Smarkm    }
78757416Smarkm    if (ttyout) {
78857416Smarkm	FD_SET(tout, &obits);
78957416Smarkm    }
79057416Smarkm    if (ttyin) {
79157416Smarkm	FD_SET(tin, &ibits);
79257416Smarkm    }
79357416Smarkm    if (netin) {
79457416Smarkm	FD_SET(net, &ibits);
79557416Smarkm    }
79657416Smarkm#if !defined(SO_OOBINLINE)
79757416Smarkm    if (netex) {
79857416Smarkm	FD_SET(net, &xbits);
79957416Smarkm    }
80057416Smarkm#endif
80172445Sassar    if ((c = select(FD_SETSIZE, &ibits, &obits, &xbits,
80257416Smarkm			(poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) {
80357416Smarkm	if (c == -1) {
80457416Smarkm		    /*
80557416Smarkm		     * we can get EINTR if we are in line mode,
80657416Smarkm		     * and the user does an escape (TSTP), or
80757416Smarkm		     * some other signal generator.
80857416Smarkm		     */
80957416Smarkm	    if (errno == EINTR) {
81057416Smarkm		return 0;
81157416Smarkm	    }
81257416Smarkm		    /* I don't like this, does it ever happen? */
81357416Smarkm	    printf("sleep(5) from telnet, after select\r\n");
81457416Smarkm	    sleep(5);
81557416Smarkm	}
81657416Smarkm	return 0;
81757416Smarkm    }
81857416Smarkm
81957416Smarkm    /*
82057416Smarkm     * Any urgent data?
82157416Smarkm     */
82257416Smarkm    if (FD_ISSET(net, &xbits)) {
82357416Smarkm	FD_CLR(net, &xbits);
82457416Smarkm	SYNCHing = 1;
82557416Smarkm	ttyflush(1);	/* flush already enqueued data */
82657416Smarkm    }
82757416Smarkm
82857416Smarkm    /*
82957416Smarkm     * Something to read from the network...
83057416Smarkm     */
83157416Smarkm    if (FD_ISSET(net, &ibits)) {
83257416Smarkm	int canread;
83357416Smarkm
83457416Smarkm	FD_CLR(net, &ibits);
83557416Smarkm	canread = ring_empty_consecutive(&netiring);
83657416Smarkm#if	!defined(SO_OOBINLINE)
83757416Smarkm	    /*
83857416Smarkm	     * In 4.2 (and some early 4.3) systems, the
83957416Smarkm	     * OOB indication and data handling in the kernel
84057416Smarkm	     * is such that if two separate TCP Urgent requests
84157416Smarkm	     * come in, one byte of TCP data will be overlaid.
84257416Smarkm	     * This is fatal for Telnet, but we try to live
84357416Smarkm	     * with it.
84457416Smarkm	     *
84557416Smarkm	     * In addition, in 4.2 (and...), a special protocol
84657416Smarkm	     * is needed to pick up the TCP Urgent data in
84757416Smarkm	     * the correct sequence.
84857416Smarkm	     *
84957416Smarkm	     * What we do is:  if we think we are in urgent
85057416Smarkm	     * mode, we look to see if we are "at the mark".
85157416Smarkm	     * If we are, we do an OOB receive.  If we run
85257416Smarkm	     * this twice, we will do the OOB receive twice,
85357416Smarkm	     * but the second will fail, since the second
85457416Smarkm	     * time we were "at the mark", but there wasn't
85557416Smarkm	     * any data there (the kernel doesn't reset
85657416Smarkm	     * "at the mark" until we do a normal read).
85757416Smarkm	     * Once we've read the OOB data, we go ahead
85857416Smarkm	     * and do normal reads.
85957416Smarkm	     *
86057416Smarkm	     * There is also another problem, which is that
86157416Smarkm	     * since the OOB byte we read doesn't put us
86257416Smarkm	     * out of OOB state, and since that byte is most
86357416Smarkm	     * likely the TELNET DM (data mark), we would
86457416Smarkm	     * stay in the TELNET SYNCH (SYNCHing) state.
86557416Smarkm	     * So, clocks to the rescue.  If we've "just"
86657416Smarkm	     * received a DM, then we test for the
86757416Smarkm	     * presence of OOB data when the receive OOB
86857416Smarkm	     * fails (and AFTER we did the normal mode read
86957416Smarkm	     * to clear "at the mark").
87057416Smarkm	     */
87157416Smarkm	if (SYNCHing) {
87257416Smarkm	    int atmark;
87357416Smarkm	    static int bogus_oob = 0, first = 1;
87457416Smarkm
87557416Smarkm	    ioctl(net, SIOCATMARK, (char *)&atmark);
87657416Smarkm	    if (atmark) {
87757416Smarkm		c = recv(net, netiring.supply, canread, MSG_OOB);
87857416Smarkm		if ((c == -1) && (errno == EINVAL)) {
87957416Smarkm		    c = recv(net, netiring.supply, canread, 0);
88057416Smarkm		    if (clocks.didnetreceive < clocks.gotDM) {
88157416Smarkm			SYNCHing = stilloob();
88257416Smarkm		    }
88357416Smarkm		} else if (first && c > 0) {
88457416Smarkm		    /*
88557416Smarkm		     * Bogosity check.  Systems based on 4.2BSD
88657416Smarkm		     * do not return an error if you do a second
88757416Smarkm		     * recv(MSG_OOB).  So, we do one.  If it
88857416Smarkm		     * succeeds and returns exactly the same
88957416Smarkm		     * data, then assume that we are running
89057416Smarkm		     * on a broken system and set the bogus_oob
89157416Smarkm		     * flag.  (If the data was different, then
89257416Smarkm		     * we probably got some valid new data, so
89357416Smarkm		     * increment the count...)
89457416Smarkm		     */
89557416Smarkm		    int i;
89657416Smarkm		    i = recv(net, netiring.supply + c, canread - c, MSG_OOB);
89757416Smarkm		    if (i == c &&
89857416Smarkm			 memcmp(netiring.supply, netiring.supply + c, i) == 0) {
89957416Smarkm			bogus_oob = 1;
90057416Smarkm			first = 0;
90157416Smarkm		    } else if (i < 0) {
90257416Smarkm			bogus_oob = 0;
90357416Smarkm			first = 0;
90457416Smarkm		    } else
90557416Smarkm			c += i;
90657416Smarkm		}
90757416Smarkm		if (bogus_oob && c > 0) {
90857416Smarkm		    int i;
90957416Smarkm		    /*
91057416Smarkm		     * Bogosity.  We have to do the read
91157416Smarkm		     * to clear the atmark to get out of
91257416Smarkm		     * an infinate loop.
91357416Smarkm		     */
91457416Smarkm		    i = read(net, netiring.supply + c, canread - c);
91557416Smarkm		    if (i > 0)
91657416Smarkm			c += i;
91757416Smarkm		}
91857416Smarkm	    } else {
91957416Smarkm		c = recv(net, netiring.supply, canread, 0);
92057416Smarkm	    }
92157416Smarkm	} else {
92257416Smarkm	    c = recv(net, netiring.supply, canread, 0);
92357416Smarkm	}
92457416Smarkm	settimer(didnetreceive);
92557416Smarkm#else	/* !defined(SO_OOBINLINE) */
92657416Smarkm	c = recv(net, (char *)netiring.supply, canread, 0);
92757416Smarkm#endif	/* !defined(SO_OOBINLINE) */
92857416Smarkm	if (c < 0 && errno == EWOULDBLOCK) {
92957416Smarkm	    c = 0;
93057416Smarkm	} else if (c <= 0) {
93157416Smarkm	    return -1;
93257416Smarkm	}
93357416Smarkm	if (netdata) {
93457416Smarkm	    Dump('<', netiring.supply, c);
93557416Smarkm	}
93657416Smarkm	if (c)
93757416Smarkm	    ring_supplied(&netiring, c);
93857416Smarkm	returnValue = 1;
93957416Smarkm    }
94057416Smarkm
94157416Smarkm    /*
94257416Smarkm     * Something to read from the tty...
94357416Smarkm     */
94457416Smarkm    if (FD_ISSET(tin, &ibits)) {
94557416Smarkm	FD_CLR(tin, &ibits);
94657416Smarkm	c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring));
94757416Smarkm	if (c < 0 && errno == EIO)
94857416Smarkm	    c = 0;
94957416Smarkm	if (c < 0 && errno == EWOULDBLOCK) {
95057416Smarkm	    c = 0;
95157416Smarkm	} else {
95257416Smarkm	    /* EOF detection for line mode!!!! */
95357416Smarkm	    if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && isatty(tin)) {
95457416Smarkm			/* must be an EOF... */
95557416Smarkm		*ttyiring.supply = termEofChar;
95657416Smarkm		c = 1;
95757416Smarkm	    }
95857416Smarkm	    if (c <= 0) {
95957416Smarkm		return -1;
96057416Smarkm	    }
96157416Smarkm	    if (termdata) {
96257416Smarkm		Dump('<', ttyiring.supply, c);
96357416Smarkm	    }
96457416Smarkm	    ring_supplied(&ttyiring, c);
96557416Smarkm	}
96657416Smarkm	returnValue = 1;		/* did something useful */
96757416Smarkm    }
96857416Smarkm
96957416Smarkm    if (FD_ISSET(net, &obits)) {
97057416Smarkm	FD_CLR(net, &obits);
97157416Smarkm	returnValue |= netflush();
97257416Smarkm    }
97357416Smarkm    if (FD_ISSET(tout, &obits)) {
97457416Smarkm	FD_CLR(tout, &obits);
97557416Smarkm	returnValue |= (ttyflush(SYNCHing|flushout) > 0);
97657416Smarkm    }
97757416Smarkm
97857416Smarkm    return returnValue;
97957416Smarkm}
980