xref: /csrg-svn/usr.bin/telnet/sys_bsd.c (revision 40245)
132147Sminshall /*
233685Sbostic  * Copyright (c) 1988 Regents of the University of California.
333685Sbostic  * All rights reserved.
433685Sbostic  *
533685Sbostic  * Redistribution and use in source and binary forms are permitted
634898Sbostic  * provided that the above copyright notice and this paragraph are
734898Sbostic  * duplicated in all such forms and that any documentation,
834898Sbostic  * advertising materials, and other materials related to such
934898Sbostic  * distribution and use acknowledge that the software was developed
1034898Sbostic  * by the University of California, Berkeley.  The name of the
1134898Sbostic  * University may not be used to endorse or promote products derived
1234898Sbostic  * from this software without specific prior written permission.
1334898Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1434898Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1534898Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1633685Sbostic  */
1733685Sbostic 
1833685Sbostic #ifndef lint
19*40245Sborman static char sccsid[] = "@(#)sys_bsd.c	1.24 (Berkeley) 03/01/90";
2033685Sbostic #endif /* not lint */
2133685Sbostic 
2233685Sbostic /*
2332147Sminshall  * The following routines try to encapsulate what is system dependent
2432147Sminshall  * (at least between 4.x and dos) which is used in telnet.c.
2532147Sminshall  */
2632147Sminshall 
2732147Sminshall 
2836274Sminshall #include <fcntl.h>
2932381Sminshall #include <sys/types.h>
3032147Sminshall #include <sys/time.h>
3132531Sminshall #include <sys/socket.h>
3232147Sminshall #include <signal.h>
3332531Sminshall #include <errno.h>
3438689Sborman #include <arpa/telnet.h>
3532147Sminshall 
3632381Sminshall #include "ring.h"
3732381Sminshall 
3832657Sminshall #include "fdset.h"
3932657Sminshall 
4032147Sminshall #include "defines.h"
4132147Sminshall #include "externs.h"
4232147Sminshall #include "types.h"
4332147Sminshall 
44*40245Sborman #if	defined(CRAY)
45*40245Sborman #define	SIG_FUNC_RET	void
46*40245Sborman #else
47*40245Sborman #define	SIG_FUNC_RET	int
48*40245Sborman #endif
49*40245Sborman 
5032147Sminshall int
5132531Sminshall 	tout,			/* Output file descriptor */
5232531Sminshall 	tin,			/* Input file descriptor */
5336242Sminshall 	net;
5432147Sminshall 
5538689Sborman #ifndef	USE_TERMIO
5638689Sborman struct	tchars otc = { 0 }, ntc = { 0 };
5738689Sborman struct	ltchars oltc = { 0 }, nltc = { 0 };
5838689Sborman struct	sgttyb ottyb = { 0 }, nttyb = { 0 };
5938909Sborman int	olmode = 0;
6032147Sminshall 
6138689Sborman #else	/* USE_TERMIO */
6238689Sborman struct	termio old_tc = { 0 };
6338689Sborman extern struct termio new_tc;
6438689Sborman 
65*40245Sborman #ifndef	TCGETA
66*40245Sborman #define	TCGETA	TIOCGETA
67*40245Sborman #define	TCSETA	TIOCSETA
68*40245Sborman #define	TCSETAW	TIOCSETAW
69*40245Sborman #endif	/* TCGETA */
7038689Sborman #endif	/* USE_TERMIO */
7138689Sborman 
7232531Sminshall static fd_set ibits, obits, xbits;
7332147Sminshall 
7432531Sminshall 
7532531Sminshall init_sys()
7632531Sminshall {
7732531Sminshall     tout = fileno(stdout);
7832531Sminshall     tin = fileno(stdin);
7932531Sminshall     FD_ZERO(&ibits);
8032531Sminshall     FD_ZERO(&obits);
8132531Sminshall     FD_ZERO(&xbits);
8232531Sminshall 
8332531Sminshall     errno = 0;
8432531Sminshall }
8532531Sminshall 
8632531Sminshall 
8733286Sminshall TerminalWrite(buf, n)
8832147Sminshall char	*buf;
8932147Sminshall int	n;
9032147Sminshall {
9133286Sminshall     return write(tout, buf, n);
9232147Sminshall }
9332147Sminshall 
9433286Sminshall TerminalRead(buf, n)
9532147Sminshall char	*buf;
9632147Sminshall int	n;
9732147Sminshall {
9833286Sminshall     return read(tin, buf, n);
9932147Sminshall }
10032147Sminshall 
10132147Sminshall /*
10232147Sminshall  *
10332147Sminshall  */
10432147Sminshall 
10532147Sminshall int
10632553Sminshall TerminalAutoFlush()
10732147Sminshall {
10832147Sminshall #if	defined(LNOFLSH)
10932147Sminshall     int flush;
11032147Sminshall 
11132147Sminshall     ioctl(0, TIOCLGET, (char *)&flush);
11232147Sminshall     return !(flush&LNOFLSH);	/* if LNOFLSH, no autoflush */
11332147Sminshall #else	/* LNOFLSH */
11432147Sminshall     return 1;
11532147Sminshall #endif	/* LNOFLSH */
11632147Sminshall }
11732147Sminshall 
11838689Sborman #ifdef	KLUDGELINEMODE
11938689Sborman extern int kludgelinemode;
12038689Sborman #endif
12132147Sminshall /*
12232147Sminshall  * TerminalSpecialChars()
12332147Sminshall  *
12432147Sminshall  * Look at an input character to see if it is a special character
12532147Sminshall  * and decide what to do.
12632147Sminshall  *
12732147Sminshall  * Output:
12832147Sminshall  *
12932147Sminshall  *	0	Don't add this character.
13032147Sminshall  *	1	Do add this character
13132147Sminshall  */
13232147Sminshall 
13332147Sminshall int
13432553Sminshall TerminalSpecialChars(c)
13532147Sminshall int	c;
13632147Sminshall {
13732553Sminshall     void xmitAO(), xmitEL(), xmitEC(), intp(), sendbrk();
13832147Sminshall 
13938689Sborman     if (c == termIntChar) {
14032147Sminshall 	intp();
14132147Sminshall 	return 0;
14238689Sborman     } else if (c == termQuitChar) {
14338689Sborman #ifdef	KLUDGELINEMODE
14438689Sborman 	if (kludgelinemode)
14538689Sborman 	    sendbrk();
14638689Sborman 	else
14738689Sborman #endif
14838689Sborman 	    sendabort();
14932147Sminshall 	return 0;
15038689Sborman     } else if (c == termEofChar) {
15138689Sborman 	if (my_want_state_is_will(TELOPT_LINEMODE)) {
15238689Sborman 	    sendeof();
15338689Sborman 	    return 0;
15438689Sborman 	}
15538689Sborman 	return 1;
15638689Sborman     } else if (c == termSuspChar) {
15738689Sborman 	sendsusp();
15838689Sborman 	return(0);
15938689Sborman     } else if (c == termFlushChar) {
16032147Sminshall 	xmitAO();		/* Transmit Abort Output */
16132147Sminshall 	return 0;
16232147Sminshall     } else if (!MODE_LOCAL_CHARS(globalmode)) {
16338689Sborman 	if (c == termKillChar) {
16432147Sminshall 	    xmitEL();
16532147Sminshall 	    return 0;
16638689Sborman 	} else if (c == termEraseChar) {
16732147Sminshall 	    xmitEC();		/* Transmit Erase Character */
16832147Sminshall 	    return 0;
16932147Sminshall 	}
17032147Sminshall     }
17132147Sminshall     return 1;
17232147Sminshall }
17332147Sminshall 
17432147Sminshall 
17532147Sminshall /*
17632147Sminshall  * Flush output to the terminal
17732147Sminshall  */
17832147Sminshall 
17932147Sminshall void
18032553Sminshall TerminalFlushOutput()
18132147Sminshall {
18239529Sborman #ifdef	TIOCFLUSH
18332147Sminshall     (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0);
18438689Sborman #else
18538689Sborman     (void) ioctl(fileno(stdout), TCFLSH, (char *) 0);
18638689Sborman #endif
18732147Sminshall }
18832147Sminshall 
18932147Sminshall void
19032553Sminshall TerminalSaveState()
19132147Sminshall {
19238689Sborman #ifndef	USE_TERMIO
19332147Sminshall     ioctl(0, TIOCGETP, (char *)&ottyb);
19432147Sminshall     ioctl(0, TIOCGETC, (char *)&otc);
19532147Sminshall     ioctl(0, TIOCGLTC, (char *)&oltc);
19638909Sborman     ioctl(0, TIOCLGET, (char *)&olmode);
19732147Sminshall 
19832147Sminshall     ntc = otc;
19932147Sminshall     nltc = oltc;
20032147Sminshall     nttyb = ottyb;
20132254Sminshall 
20238689Sborman #else	/* USE_TERMIO */
20338689Sborman     ioctl(0, TCGETA, &old_tc);
20438689Sborman 
20538689Sborman     new_tc = old_tc;
20638689Sborman 
20738689Sborman     termFlushChar = 'O'&0x37;
20838689Sborman     termWerasChar = 'W'&0x37;
20938689Sborman     termRprntChar = 'R'&0x37;
21038689Sborman     termLiteralNextChar = 'V'&0x37;
21138689Sborman     termStartChar = 'Q'&0x37;
21238689Sborman     termStopChar = 'S'&0x37;
21338689Sborman #endif	/* USE_TERMIO */
21432147Sminshall }
21532147Sminshall 
216*40245Sborman cc_t *
21738689Sborman tcval(func)
21838689Sborman register int func;
21938689Sborman {
22038689Sborman     switch(func) {
221*40245Sborman     case SLC_IP:	return(&termIntChar);
222*40245Sborman     case SLC_ABORT:	return(&termQuitChar);
223*40245Sborman     case SLC_EOF:	return(&termEofChar);
224*40245Sborman     case SLC_EC:	return(&termEraseChar);
225*40245Sborman     case SLC_EL:	return(&termKillChar);
226*40245Sborman     case SLC_XON:	return(&termStartChar);
227*40245Sborman     case SLC_XOFF:	return(&termStopChar);
22839529Sborman #ifndef	SYSV_TERMIO
229*40245Sborman     case SLC_AO:	return(&termFlushChar);
230*40245Sborman     case SLC_SUSP:	return(&termSuspChar);
231*40245Sborman     case SLC_EW:	return(&termWerasChar);
232*40245Sborman     case SLC_RP:	return(&termRprntChar);
233*40245Sborman     case SLC_LNEXT:	return(&termLiteralNextChar);
23439529Sborman #endif	/* SYSV_TERMIO */
23538689Sborman 
23638689Sborman     case SLC_SYNCH:
23738689Sborman     case SLC_BRK:
23838689Sborman     case SLC_AYT:
23938689Sborman     case SLC_EOR:
24038689Sborman     case SLC_FORW1:
24138689Sborman     case SLC_FORW2:
24238689Sborman     default:
243*40245Sborman 	return((cc_t *)0);
24438689Sborman     }
24538689Sborman }
24638689Sborman 
24732147Sminshall void
24838689Sborman TerminalDefaultChars()
24938689Sborman {
25038689Sborman #ifndef	USE_TERMIO
25138689Sborman     ntc = otc;
25238689Sborman     nltc = oltc;
25338689Sborman     nttyb.sg_kill = ottyb.sg_kill;
25438689Sborman     nttyb.sg_erase = ottyb.sg_erase;
25538689Sborman #else	/* USE_TERMIO */
25638689Sborman     memcpy(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc));
25739529Sborman # ifndef	VFLUSHO
25838689Sborman     termFlushChar = 'O'&0x37;
25939529Sborman # endif
26039529Sborman # ifndef	VWERASE
26138689Sborman     termWerasChar = 'W'&0x37;
26239529Sborman # endif
26339529Sborman # ifndef	VREPRINT
26438689Sborman     termRprntChar = 'R'&0x37;
26539529Sborman # endif
26639529Sborman # ifndef	VLNEXT
26738689Sborman     termLiteralNextChar = 'V'&0x37;
26839529Sborman # endif
26939529Sborman # ifndef	VSTART
27038689Sborman     termStartChar = 'Q'&0x37;
27139529Sborman # endif
27239529Sborman # ifndef	VSTOP
27338689Sborman     termStopChar = 'S'&0x37;
27439529Sborman # endif
27538689Sborman #endif	/* USE_TERMIO */
27638689Sborman }
27738689Sborman 
27838689Sborman void
27932553Sminshall TerminalRestoreState()
28032147Sminshall {
28132147Sminshall }
28232147Sminshall 
28332147Sminshall /*
28432147Sminshall  * TerminalNewMode - set up terminal to a specific mode.
28538689Sborman  *	MODE_ECHO: do local terminal echo
28638689Sborman  *	MODE_FLOW: do local flow control
28738689Sborman  *	MODE_TRAPSIG: do local mapping to TELNET IAC sequences
28838689Sborman  *	MODE_EDIT: do local line editing
28938689Sborman  *
29038689Sborman  *	Command mode:
29138689Sborman  *		MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG
29238689Sborman  *		local echo
29338689Sborman  *		local editing
29438689Sborman  *		local xon/xoff
29538689Sborman  *		local signal mapping
29638689Sborman  *
29738689Sborman  *	Linemode:
29838689Sborman  *		local/no editing
29938689Sborman  *	Both Linemode and Single Character mode:
30038689Sborman  *		local/remote echo
30138689Sborman  *		local/no xon/xoff
30238689Sborman  *		local/no signal mapping
30332147Sminshall  */
30432147Sminshall 
30532147Sminshall 
30632147Sminshall void
30733286Sminshall TerminalNewMode(f)
30832147Sminshall register int f;
30932147Sminshall {
31032147Sminshall     static int prevmode = 0;
31138689Sborman #ifndef	USE_TERMIO
31238689Sborman     struct tchars tc;
31338689Sborman     struct ltchars ltc;
31432147Sminshall     struct sgttyb sb;
31538909Sborman     int lmode;
31638689Sborman #else	/* USE_TERMIO */
31738689Sborman     struct termio tmp_tc;
31838689Sborman #endif	/* USE_TERMIO */
31932147Sminshall     int onoff;
32032147Sminshall     int old;
32132147Sminshall 
32238689Sborman     globalmode = f&~MODE_FORCE;
32332147Sminshall     if (prevmode == f)
32432147Sminshall 	return;
32538689Sborman 
32638689Sborman     /*
32738689Sborman      * Write any outstanding data before switching modes
32838689Sborman      * ttyflush() returns 0 only when there is no more data
32938689Sborman      * left to write out, it returns -1 if it couldn't do
33038689Sborman      * anything at all, otherwise it returns 1 + the number
33138689Sborman      * of characters left to write.
33238689Sborman      */
33338689Sborman     old = ttyflush(SYNCHing|flushout);
33438689Sborman     if (old < 0 || old > 1) {
33538689Sborman #ifndef	USE_TERMIO
33638689Sborman 	ioctl(tin, TIOCGETP, (char *)&sb);
33738689Sborman #else	/* USE_TERMIO */
33838689Sborman 	ioctl(tin, TCGETA, (char *)&tmp_tc);
33938689Sborman #endif	/* USE_TERMIO */
34038689Sborman 	do {
34138689Sborman 	    /*
34238689Sborman 	     * Wait for data to drain, then flush again.
34338689Sborman 	     */
34438689Sborman #ifndef	USE_TERMIO
34538689Sborman 	    ioctl(tin, TIOCSETP, (char *)&sb);
34638689Sborman #else	/* USE_TERMIO */
34738689Sborman 	    ioctl(tin, TCSETAW, (char *)&tmp_tc);
34838689Sborman #endif	/* USE_TERMIO */
34938689Sborman 	    old = ttyflush(SYNCHing|flushout);
35038689Sborman 	} while (old < 0 || old > 1);
35138689Sborman     }
35238689Sborman 
35332147Sminshall     old = prevmode;
35438689Sborman     prevmode = f&~MODE_FORCE;
35538689Sborman #ifndef	USE_TERMIO
35632147Sminshall     sb = nttyb;
35738689Sborman     tc = ntc;
35838689Sborman     ltc = nltc;
35938909Sborman     lmode = olmode;
36038689Sborman #else
36138689Sborman     tmp_tc = new_tc;
36238689Sborman #endif
36332147Sminshall 
36438689Sborman     if (f&MODE_ECHO) {
36538689Sborman #ifndef	USE_TERMIO
36638689Sborman 	sb.sg_flags |= ECHO;
36738689Sborman #else
36838689Sborman 	tmp_tc.c_lflag |= ECHO;
36938689Sborman 	tmp_tc.c_oflag |= ONLCR;
37039529Sborman # ifdef notdef
37138689Sborman 	tmp_tc.c_iflag |= ICRNL;
37239529Sborman # endif
37338689Sborman #endif
37438689Sborman     } else {
37538689Sborman #ifndef	USE_TERMIO
37638689Sborman 	sb.sg_flags &= ~ECHO;
37738689Sborman #else
37838689Sborman 	tmp_tc.c_lflag &= ~ECHO;
37938689Sborman 	tmp_tc.c_oflag &= ~ONLCR;
38039529Sborman # ifdef notdef
38138689Sborman 	tmp_tc.c_iflag &= ~ICRNL;
38239529Sborman # endif
38338689Sborman #endif
38438689Sborman     }
38532147Sminshall 
38638689Sborman     if ((f&MODE_FLOW) == 0) {
38738689Sborman #ifndef	USE_TERMIO
38838689Sborman 	tc.t_startc = -1;
38938689Sborman 	tc.t_stopc = -1;
39038689Sborman #else
39138689Sborman 	tmp_tc.c_iflag &= ~(IXANY|IXOFF|IXON);
39238689Sborman     } else {
39338689Sborman 	tmp_tc.c_iflag |= IXANY|IXOFF|IXON;
39438689Sborman #endif
39538689Sborman     }
39632147Sminshall 
39738689Sborman     if ((f&MODE_TRAPSIG) == 0) {
39838689Sborman #ifndef	USE_TERMIO
39938689Sborman 	tc.t_intrc = -1;
40038689Sborman 	tc.t_quitc = -1;
40138689Sborman 	tc.t_eofc = -1;
40238689Sborman 	ltc.t_suspc = -1;
40338689Sborman 	ltc.t_dsuspc = -1;
40438689Sborman #else
40538689Sborman 	tmp_tc.c_lflag &= ~ISIG;
40638689Sborman #endif
40738689Sborman 	localchars = 0;
40838689Sborman     } else {
40938689Sborman #ifdef	USE_TERMIO
41038689Sborman 	tmp_tc.c_lflag |= ISIG;
41138689Sborman #endif
41238689Sborman 	localchars = 1;
41338689Sborman     }
41438689Sborman 
41538689Sborman     if (f&MODE_EDIT) {
41638689Sborman #ifndef	USE_TERMIO
41738689Sborman 	sb.sg_flags &= ~CBREAK;
41838689Sborman 	sb.sg_flags |= CRMOD;
41938689Sborman #else
42038689Sborman 	tmp_tc.c_lflag |= ICANON;
42138689Sborman #endif
42238689Sborman     } else {
42338689Sborman #ifndef	USE_TERMIO
42438689Sborman 	sb.sg_flags |= CBREAK;
42538689Sborman 	if (f&MODE_ECHO)
42632147Sminshall 	    sb.sg_flags |= CRMOD;
42738689Sborman 	else
42838689Sborman 	    sb.sg_flags &= ~CRMOD;
42938689Sborman #else
43038689Sborman 	tmp_tc.c_lflag &= ~ICANON;
43138689Sborman 	tmp_tc.c_iflag &= ~ICRNL;
43238689Sborman 	tmp_tc.c_cc[VMIN] = 1;
43338689Sborman 	tmp_tc.c_cc[VTIME] = 0;
43438689Sborman #endif
43538689Sborman     }
43632147Sminshall 
43738689Sborman     if (f == -1) {
43838689Sborman 	onoff = 0;
43938689Sborman     } else {
44038909Sborman #ifndef	USE_TERMIO
44139529Sborman 	if (f & MODE_OUTBIN)
44238909Sborman 		lmode |= LLITOUT;
44338909Sborman 	else
44438909Sborman 		lmode &= ~LLITOUT;
44539529Sborman 
44639529Sborman 	if (f & MODE_INBIN)
44738909Sborman 		lmode |= LPASS8;
44838909Sborman 	else
44938909Sborman 		lmode &= ~LPASS8;
45038909Sborman #else
45139529Sborman 	if (f & MODE_OUTBIN)
45239529Sborman 		tmp_tc.c_lflag &= ~ISTRIP;
45338909Sborman 	else
45439529Sborman 		tmp_tc.c_lflag |= ISTRIP;
45539529Sborman 	if (f & MODE_INBIN) {
45639529Sborman 		tmp_tc.c_cflag &= ~(CSIZE|PARENB);
45739529Sborman 		tmp_tc.c_cflag |= CS8;
45839529Sborman 		tmp_tc.c_cflag &= ~OPOST;
45939529Sborman 	} else {
46039529Sborman 		tmp_tc.c_cflag &= ~CSIZE;
46139529Sborman 		tmp_tc.c_cflag |= CS7|PARENB;
46239529Sborman 		tmp_tc.c_cflag |= OPOST;
46339529Sborman 	}
46438909Sborman #endif
46538689Sborman 	onoff = 1;
46632147Sminshall     }
46738689Sborman 
46838689Sborman     if (f != -1) {
46939529Sborman #ifdef	SIGTSTP
470*40245Sborman 	void susp();
47138689Sborman 
472*40245Sborman 	(void) signal(SIGTSTP, (SIG_FUNC_RET (*)())susp);
47339529Sborman #endif	/* SIGTSTP */
474*40245Sborman #ifdef	USE_TERMIO
475*40245Sborman #ifdef	VEOL2
476*40245Sborman 	/*
477*40245Sborman 	 * If the VEOL character is already set, then use VEOL2,
478*40245Sborman 	 * otherwise use VEOL.
479*40245Sborman 	 */
480*40245Sborman 	if (tmp_tc.c_cc[VEOL] != (cc_t)(-1))
481*40245Sborman 		tmp_tc.c_cc[VEOL2] = escape;
482*40245Sborman 	else
483*40245Sborman #endif
484*40245Sborman 		tmp_tc.c_cc[VEOL] = escape;
485*40245Sborman #else
486*40245Sborman 	tc.t_brkc = escape;
487*40245Sborman #endif
48838689Sborman     } else {
48939529Sborman #ifdef	SIGTSTP
49038689Sborman 	(void) signal(SIGTSTP, SIG_DFL);
49138689Sborman 	sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
49239529Sborman #endif	/* SIGTSTP */
49339529Sborman #ifndef USE_TERMIO
49439529Sborman 	ltc = oltc;
49539529Sborman 	tc = otc;
49639529Sborman 	sb = ottyb;
49739529Sborman #endif
49838689Sborman     }
49939529Sborman #ifndef USE_TERMIO
50039529Sborman     ioctl(tin, TIOCLSET, (char *)&lmode);
50139529Sborman     ioctl(tin, TIOCSLTC, (char *)&ltc);
50239529Sborman     ioctl(tin, TIOCSETC, (char *)&tc);
50339529Sborman     ioctl(tin, TIOCSETP, (char *)&sb);
50439529Sborman #else
50539529Sborman     if (ioctl(tin, TCSETAW, &tmp_tc) < 0)
50639529Sborman 	ioctl(tin, TCSETA, &tmp_tc);
50739529Sborman #endif
50839529Sborman 
50932147Sminshall #if	(!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR))
51033286Sminshall     ioctl(tin, FIONBIO, (char *)&onoff);
51133286Sminshall     ioctl(tout, FIONBIO, (char *)&onoff);
51232147Sminshall #endif	/* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */
51332147Sminshall #if	defined(TN3270)
51436242Sminshall     if (noasynchtty == 0) {
51533286Sminshall 	ioctl(tin, FIOASYNC, (char *)&onoff);
51632147Sminshall     }
51732147Sminshall #endif	/* defined(TN3270) */
51832147Sminshall }
51932147Sminshall 
52039529Sborman #ifndef	B19200
52139529Sborman # define B19200 B9600
52239529Sborman #endif
52339529Sborman 
52439529Sborman #ifndef	B38400
52539529Sborman # define B38400 B19200
52639529Sborman #endif
52739529Sborman 
52839529Sborman /*
52939529Sborman  * This code assumes that the values B0, B50, B75...
53039529Sborman  * are in ascending order.  They do not have to be
53139529Sborman  * contiguous.
53239529Sborman  */
53339529Sborman struct termspeeds {
53439529Sborman 	long speed;
53539529Sborman 	long value;
53639529Sborman } termspeeds[] = {
53739529Sborman 	{ 0,     B0 },     { 50,    B50 },   { 75,    B75 },
53839529Sborman 	{ 110,   B110 },   { 134,   B134 },  { 150,   B150 },
53939529Sborman 	{ 200,   B200 },   { 300,   B300 },  { 600,   B600 },
54039529Sborman 	{ 1200,  B1200 },  { 1800,  B1800 }, { 2400,  B2400 },
54139529Sborman 	{ 4800,  B4800 },  { 9600,  B9600 }, { 19200, B19200 },
54239529Sborman 	{ 38400, B38400 }, { -1,    B38400 }
54339529Sborman };
54439529Sborman 
54539529Sborman #ifndef	USE_TERMIO
54639529Sborman # define	ISPEED	ottyb.sg_ispeed
54739529Sborman # define	OSPEED	ottyb.sg_ospeed
54839529Sborman #else
54939529Sborman # ifdef	SYSV_TERMIO
55039529Sborman #  define	ISPEED	(old_tc.c_cflag&CBAUD)
55139529Sborman #  define	OSPEED	ISPEED
55239529Sborman # else
55339529Sborman #  define	ISPEED	old_tc.c_ispeed
55439529Sborman #  define OSPEED	old_tc.c_ospeed
55539529Sborman # endif
55639529Sborman #endif
55739529Sborman 
55837219Sminshall void
55937219Sminshall TerminalSpeeds(ispeed, ospeed)
56037219Sminshall long *ispeed;
56137219Sminshall long *ospeed;
56237219Sminshall {
56339529Sborman     register struct termspeeds *tp;
56432147Sminshall 
56539529Sborman     tp = termspeeds;
56639529Sborman     while ((tp->speed != -1) && (tp->value < ISPEED))
56739529Sborman 	tp++;
56839529Sborman     *ispeed = tp->speed;
56939529Sborman 
57039529Sborman     tp = termspeeds;
57139529Sborman     while ((tp->speed != -1) && (tp->value < OSPEED))
57239529Sborman 	tp++;
57339529Sborman     *ospeed = tp->speed;
57437219Sminshall }
57537219Sminshall 
57632147Sminshall int
57737219Sminshall TerminalWindowSize(rows, cols)
57837219Sminshall long *rows, *cols;
57937219Sminshall {
58038689Sborman #ifdef	TIOCGWINSZ
58137219Sminshall     struct winsize ws;
58237219Sminshall 
58338689Sborman     if (ioctl(fileno(stdin), TIOCGWINSZ, (char *)&ws) >= 0) {
58438689Sborman 	*rows = ws.ws_row;
58538689Sborman 	*cols = ws.ws_col;
58638689Sborman 	return 1;
58737219Sminshall     }
58838810Sborman #endif	/* TIOCGWINSZ */
58938689Sborman     return 0;
59037219Sminshall }
59137219Sminshall 
59237219Sminshall int
59335417Sminshall NetClose(fd)
59435417Sminshall int	fd;
59532147Sminshall {
59635417Sminshall     return close(fd);
59732147Sminshall }
59832147Sminshall 
59932147Sminshall 
60032147Sminshall void
60132553Sminshall NetNonblockingIO(fd, onoff)
60232147Sminshall int
60332147Sminshall 	fd,
60432147Sminshall 	onoff;
60532147Sminshall {
60632147Sminshall     ioctl(fd, FIONBIO, (char *)&onoff);
60732147Sminshall }
60832147Sminshall 
60934849Sminshall #if	defined(TN3270)
61032147Sminshall void
61132553Sminshall NetSigIO(fd, onoff)
61232147Sminshall int
61332147Sminshall 	fd,
61432147Sminshall 	onoff;
61532147Sminshall {
61632147Sminshall     ioctl(fd, FIOASYNC, (char *)&onoff);	/* hear about input */
61732147Sminshall }
61832147Sminshall 
61932147Sminshall void
62032553Sminshall NetSetPgrp(fd)
62132147Sminshall int fd;
62232147Sminshall {
62332147Sminshall     int myPid;
62432147Sminshall 
62532147Sminshall     myPid = getpid();
62636274Sminshall     fcntl(fd, F_SETOWN, myPid);
62732147Sminshall }
62834849Sminshall #endif	/*defined(TN3270)*/
62932553Sminshall 
63032553Sminshall /*
63132553Sminshall  * Various signal handling routines.
63232553Sminshall  */
63332147Sminshall 
63433286Sminshall static void
63532553Sminshall deadpeer()
63632553Sminshall {
63732553Sminshall 	setcommandmode();
63832553Sminshall 	longjmp(peerdied, -1);
63932553Sminshall }
64032147Sminshall 
64133286Sminshall static void
64232553Sminshall intr()
64332553Sminshall {
64432553Sminshall     if (localchars) {
64532553Sminshall 	intp();
64632553Sminshall 	return;
64732553Sminshall     }
64832553Sminshall     setcommandmode();
64932553Sminshall     longjmp(toplevel, -1);
65032553Sminshall }
65132553Sminshall 
65233286Sminshall static void
65332553Sminshall intr2()
65432553Sminshall {
65532553Sminshall     if (localchars) {
65638689Sborman #ifdef	KLUDGELINEMODE
65738689Sborman 	if (kludgelinemode)
65838689Sborman 	    sendbrk();
65938689Sborman 	else
66038689Sborman #endif
66138689Sborman 	    sendabort();
66232553Sminshall 	return;
66332553Sminshall     }
66432553Sminshall }
66532553Sminshall 
66633286Sminshall static void
667*40245Sborman susp()
668*40245Sborman {
669*40245Sborman     if (localchars)
670*40245Sborman 	sendsusp();
671*40245Sborman }
672*40245Sborman 
673*40245Sborman static void
67437219Sminshall sendwin()
67537219Sminshall {
67637219Sminshall     if (connected) {
67737219Sminshall 	sendnaws();
67837219Sminshall     }
67937219Sminshall }
68037219Sminshall 
68137219Sminshall static void
68232553Sminshall doescape()
68332553Sminshall {
68438689Sborman     command(0, 0, 0);
68532553Sminshall }
68632553Sminshall 
68732553Sminshall void
68832531Sminshall sys_telnet_init()
68932531Sminshall {
690*40245Sborman     (void) signal(SIGINT, (SIG_FUNC_RET (*)())intr);
691*40245Sborman     (void) signal(SIGQUIT, (SIG_FUNC_RET (*)())intr2);
692*40245Sborman     (void) signal(SIGPIPE, (SIG_FUNC_RET (*)())deadpeer);
69338689Sborman #ifdef	SIGWINCH
694*40245Sborman     (void) signal(SIGWINCH, (SIG_FUNC_RET (*)())sendwin);
69538689Sborman #endif
696*40245Sborman #ifdef	SIGTSTP
697*40245Sborman     (void) signal(SIGTSTP, (SIG_FUNC_RET (*)())susp);
698*40245Sborman #endif
69932553Sminshall 
70038689Sborman     setconnmode(0);
70132531Sminshall 
70232531Sminshall     NetNonblockingIO(net, 1);
70332531Sminshall 
70432531Sminshall #if	defined(TN3270)
70536242Sminshall     if (noasynchnet == 0) {			/* DBX can't handle! */
70632531Sminshall 	NetSigIO(net, 1);
70732531Sminshall 	NetSetPgrp(net);
70832531Sminshall     }
70932531Sminshall #endif	/* defined(TN3270) */
71032531Sminshall 
71132531Sminshall #if	defined(SO_OOBINLINE)
71234849Sminshall     if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) {
71334849Sminshall 	perror("SetSockOpt");
71434849Sminshall     }
71532531Sminshall #endif	/* defined(SO_OOBINLINE) */
71632531Sminshall }
71732531Sminshall 
71832531Sminshall /*
71932531Sminshall  * Process rings -
72032531Sminshall  *
72132531Sminshall  *	This routine tries to fill up/empty our various rings.
72232531Sminshall  *
72332531Sminshall  *	The parameter specifies whether this is a poll operation,
72432531Sminshall  *	or a block-until-something-happens operation.
72532531Sminshall  *
72632531Sminshall  *	The return value is 1 if something happened, 0 if not.
72732531Sminshall  */
72832531Sminshall 
72932531Sminshall int
73032531Sminshall process_rings(netin, netout, netex, ttyin, ttyout, poll)
73132531Sminshall int poll;		/* If 0, then block until something to do */
73232531Sminshall {
73332531Sminshall     register int c;
73432531Sminshall 		/* One wants to be a bit careful about setting returnValue
73532531Sminshall 		 * to one, since a one implies we did some useful work,
73632531Sminshall 		 * and therefore probably won't be called to block next
73732531Sminshall 		 * time (TN3270 mode only).
73832531Sminshall 		 */
73932531Sminshall     int returnValue = 0;
74032531Sminshall     static struct timeval TimeValue = { 0 };
74132531Sminshall 
74232531Sminshall     if (netout) {
74332531Sminshall 	FD_SET(net, &obits);
74432531Sminshall     }
74532531Sminshall     if (ttyout) {
74632531Sminshall 	FD_SET(tout, &obits);
74732531Sminshall     }
74832531Sminshall #if	defined(TN3270)
74932531Sminshall     if (ttyin) {
75032531Sminshall 	FD_SET(tin, &ibits);
75132531Sminshall     }
75232531Sminshall #else	/* defined(TN3270) */
75332531Sminshall     if (ttyin) {
75432531Sminshall 	FD_SET(tin, &ibits);
75532531Sminshall     }
75632531Sminshall #endif	/* defined(TN3270) */
75732531Sminshall #if	defined(TN3270)
75832531Sminshall     if (netin) {
75932531Sminshall 	FD_SET(net, &ibits);
76032531Sminshall     }
76132531Sminshall #   else /* !defined(TN3270) */
76232531Sminshall     if (netin) {
76332531Sminshall 	FD_SET(net, &ibits);
76432531Sminshall     }
76532531Sminshall #   endif /* !defined(TN3270) */
76632531Sminshall     if (netex) {
76732531Sminshall 	FD_SET(net, &xbits);
76832531Sminshall     }
76932531Sminshall     if ((c = select(16, &ibits, &obits, &xbits,
77032531Sminshall 			(poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) {
77132531Sminshall 	if (c == -1) {
77232531Sminshall 		    /*
77332531Sminshall 		     * we can get EINTR if we are in line mode,
77432531Sminshall 		     * and the user does an escape (TSTP), or
77532531Sminshall 		     * some other signal generator.
77632531Sminshall 		     */
77732531Sminshall 	    if (errno == EINTR) {
77832531Sminshall 		return 0;
77932531Sminshall 	    }
78032531Sminshall #	    if defined(TN3270)
78132531Sminshall 		    /*
78232531Sminshall 		     * we can get EBADF if we were in transparent
78332531Sminshall 		     * mode, and the transcom process died.
78432531Sminshall 		    */
78532531Sminshall 	    if (errno == EBADF) {
78632531Sminshall 			/*
78732531Sminshall 			 * zero the bits (even though kernel does it)
78832531Sminshall 			 * to make sure we are selecting on the right
78932531Sminshall 			 * ones.
79032531Sminshall 			*/
79132531Sminshall 		FD_ZERO(&ibits);
79232531Sminshall 		FD_ZERO(&obits);
79332531Sminshall 		FD_ZERO(&xbits);
79432531Sminshall 		return 0;
79532531Sminshall 	    }
79632531Sminshall #	    endif /* defined(TN3270) */
79732531Sminshall 		    /* I don't like this, does it ever happen? */
79832531Sminshall 	    printf("sleep(5) from telnet, after select\r\n");
79932531Sminshall 	    sleep(5);
80032531Sminshall 	}
80132531Sminshall 	return 0;
80232531Sminshall     }
80332531Sminshall 
80432531Sminshall     /*
80532531Sminshall      * Any urgent data?
80632531Sminshall      */
80732531Sminshall     if (FD_ISSET(net, &xbits)) {
80832531Sminshall 	FD_CLR(net, &xbits);
80932531Sminshall 	SYNCHing = 1;
81032531Sminshall 	ttyflush(1);	/* flush already enqueued data */
81132531Sminshall     }
81232531Sminshall 
81332531Sminshall     /*
81432531Sminshall      * Something to read from the network...
81532531Sminshall      */
81632531Sminshall     if (FD_ISSET(net, &ibits)) {
81732531Sminshall 	int canread;
81832531Sminshall 
81932531Sminshall 	FD_CLR(net, &ibits);
82032531Sminshall 	canread = ring_empty_consecutive(&netiring);
82132531Sminshall #if	!defined(SO_OOBINLINE)
82232531Sminshall 	    /*
82332531Sminshall 	     * In 4.2 (and some early 4.3) systems, the
82432531Sminshall 	     * OOB indication and data handling in the kernel
82532531Sminshall 	     * is such that if two separate TCP Urgent requests
82632531Sminshall 	     * come in, one byte of TCP data will be overlaid.
82732531Sminshall 	     * This is fatal for Telnet, but we try to live
82832531Sminshall 	     * with it.
82932531Sminshall 	     *
83032531Sminshall 	     * In addition, in 4.2 (and...), a special protocol
83132531Sminshall 	     * is needed to pick up the TCP Urgent data in
83232531Sminshall 	     * the correct sequence.
83332531Sminshall 	     *
83432531Sminshall 	     * What we do is:  if we think we are in urgent
83532531Sminshall 	     * mode, we look to see if we are "at the mark".
83632531Sminshall 	     * If we are, we do an OOB receive.  If we run
83732531Sminshall 	     * this twice, we will do the OOB receive twice,
83832531Sminshall 	     * but the second will fail, since the second
83932531Sminshall 	     * time we were "at the mark", but there wasn't
84032531Sminshall 	     * any data there (the kernel doesn't reset
84132531Sminshall 	     * "at the mark" until we do a normal read).
84232531Sminshall 	     * Once we've read the OOB data, we go ahead
84332531Sminshall 	     * and do normal reads.
84432531Sminshall 	     *
84532531Sminshall 	     * There is also another problem, which is that
84632531Sminshall 	     * since the OOB byte we read doesn't put us
84732531Sminshall 	     * out of OOB state, and since that byte is most
84832531Sminshall 	     * likely the TELNET DM (data mark), we would
84932531Sminshall 	     * stay in the TELNET SYNCH (SYNCHing) state.
85032531Sminshall 	     * So, clocks to the rescue.  If we've "just"
85132531Sminshall 	     * received a DM, then we test for the
85232531Sminshall 	     * presence of OOB data when the receive OOB
85332531Sminshall 	     * fails (and AFTER we did the normal mode read
85432531Sminshall 	     * to clear "at the mark").
85532531Sminshall 	     */
85632531Sminshall 	if (SYNCHing) {
85732531Sminshall 	    int atmark;
85839652Sborman 	    static int bogus_oob = 0, first = 1;
85932531Sminshall 
86032531Sminshall 	    ioctl(net, SIOCATMARK, (char *)&atmark);
86132531Sminshall 	    if (atmark) {
86232531Sminshall 		c = recv(net, netiring.supply, canread, MSG_OOB);
86332531Sminshall 		if ((c == -1) && (errno == EINVAL)) {
86432531Sminshall 		    c = recv(net, netiring.supply, canread, 0);
86532531Sminshall 		    if (clocks.didnetreceive < clocks.gotDM) {
86632531Sminshall 			SYNCHing = stilloob(net);
86732531Sminshall 		    }
86839652Sborman 		} else if (first && c > 0) {
86939652Sborman 		    /*
87039652Sborman 		     * Bogosity check.  Systems based on 4.2BSD
87139652Sborman 		     * do not return an error if you do a second
87239652Sborman 		     * recv(MSG_OOB).  So, we do one.  If it
87339652Sborman 		     * succeeds and returns exactly the same
87439652Sborman 		     * data, then assume that we are running
87539652Sborman 		     * on a broken system and set the bogus_oob
87639652Sborman 		     * flag.  (If the data was different, then
87739652Sborman 		     * we probably got some valid new data, so
87839652Sborman 		     * increment the count...)
87939652Sborman 		     */
88039652Sborman 		    int i;
88139652Sborman 		    i = recv(net, netiring.supply + c, canread - c, MSG_OOB);
88239652Sborman 		    if (i == c &&
88339652Sborman 			  bcmp(netiring.supply, netiring.supply + c, i) == 0) {
88439652Sborman 			bogus_oob = 1;
88539652Sborman 			first = 0;
88639652Sborman 		    } else if (i < 0) {
88739652Sborman 			bogus_oob = 0;
88839652Sborman 			first = 0;
88939652Sborman 		    } else
89039652Sborman 			c += i;
89132531Sminshall 		}
89239652Sborman 		if (bogus_oob && c > 0) {
89339652Sborman 		    int i;
89439652Sborman 		    /*
89539652Sborman 		     * Bogosity.  We have to do the read
89639652Sborman 		     * to clear the atmark to get out of
89739652Sborman 		     * an infinate loop.
89839652Sborman 		     */
89939652Sborman 		    i = read(net, netiring.supply + c, canread - c);
90039652Sborman 		    if (i > 0)
90139652Sborman 			c += i;
90239652Sborman 		}
90332531Sminshall 	    } else {
90432531Sminshall 		c = recv(net, netiring.supply, canread, 0);
90532531Sminshall 	    }
90632531Sminshall 	} else {
90732531Sminshall 	    c = recv(net, netiring.supply, canread, 0);
90832531Sminshall 	}
90932531Sminshall 	settimer(didnetreceive);
91032531Sminshall #else	/* !defined(SO_OOBINLINE) */
91132531Sminshall 	c = recv(net, netiring.supply, canread, 0);
91232531Sminshall #endif	/* !defined(SO_OOBINLINE) */
91332531Sminshall 	if (c < 0 && errno == EWOULDBLOCK) {
91432531Sminshall 	    c = 0;
91532531Sminshall 	} else if (c <= 0) {
91632531Sminshall 	    return -1;
91732531Sminshall 	}
91832531Sminshall 	if (netdata) {
91932531Sminshall 	    Dump('<', netiring.supply, c);
92032531Sminshall 	}
92132667Sminshall 	if (c)
92232667Sminshall 	    ring_supplied(&netiring, c);
92332531Sminshall 	returnValue = 1;
92432531Sminshall     }
92532531Sminshall 
92632531Sminshall     /*
92732531Sminshall      * Something to read from the tty...
92832531Sminshall      */
92932531Sminshall     if (FD_ISSET(tin, &ibits)) {
93032531Sminshall 	FD_CLR(tin, &ibits);
93133286Sminshall 	c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring));
93232531Sminshall 	if (c < 0 && errno == EWOULDBLOCK) {
93332531Sminshall 	    c = 0;
93432531Sminshall 	} else {
93532531Sminshall 	    /* EOF detection for line mode!!!! */
93633281Sminshall 	    if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && isatty(tin)) {
93732531Sminshall 			/* must be an EOF... */
93832531Sminshall 		*ttyiring.supply = termEofChar;
93932531Sminshall 		c = 1;
94032531Sminshall 	    }
94132531Sminshall 	    if (c <= 0) {
94232531Sminshall 		return -1;
94332531Sminshall 	    }
94438208Sminshall 	    if (termdata) {
94538208Sminshall 		Dump('<', ttyiring.supply, c);
94638208Sminshall 	    }
94732667Sminshall 	    ring_supplied(&ttyiring, c);
94832531Sminshall 	}
94932531Sminshall 	returnValue = 1;		/* did something useful */
95032531Sminshall     }
95132531Sminshall 
95232531Sminshall     if (FD_ISSET(net, &obits)) {
95332531Sminshall 	FD_CLR(net, &obits);
95432531Sminshall 	returnValue |= netflush();
95532531Sminshall     }
95632531Sminshall     if (FD_ISSET(tout, &obits)) {
95732531Sminshall 	FD_CLR(tout, &obits);
95838689Sborman 	returnValue |= (ttyflush(SYNCHing|flushout) > 0);
95932531Sminshall     }
96032531Sminshall 
96132531Sminshall     return returnValue;
96232531Sminshall }
963