xref: /csrg-svn/usr.bin/telnet/sys_bsd.c (revision 39652)
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*39652Sborman static char sccsid[] = "@(#)sys_bsd.c	1.23 (Berkeley) 11/28/89";
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 
4432147Sminshall int
4532531Sminshall 	tout,			/* Output file descriptor */
4632531Sminshall 	tin,			/* Input file descriptor */
4736242Sminshall 	net;
4832147Sminshall 
4938689Sborman #ifndef	USE_TERMIO
5038689Sborman struct	tchars otc = { 0 }, ntc = { 0 };
5138689Sborman struct	ltchars oltc = { 0 }, nltc = { 0 };
5238689Sborman struct	sgttyb ottyb = { 0 }, nttyb = { 0 };
5338909Sborman int	olmode = 0;
5432147Sminshall 
5538689Sborman #else	/* USE_TERMIO */
5638689Sborman struct	termio old_tc = { 0 };
5738689Sborman extern struct termio new_tc;
5838689Sborman 
5938689Sborman #endif	/* USE_TERMIO */
6038689Sborman 
6132531Sminshall static fd_set ibits, obits, xbits;
6232147Sminshall 
6332531Sminshall 
6432531Sminshall init_sys()
6532531Sminshall {
6632531Sminshall     tout = fileno(stdout);
6732531Sminshall     tin = fileno(stdin);
6832531Sminshall     FD_ZERO(&ibits);
6932531Sminshall     FD_ZERO(&obits);
7032531Sminshall     FD_ZERO(&xbits);
7132531Sminshall 
7232531Sminshall     errno = 0;
7332531Sminshall }
7432531Sminshall 
7532531Sminshall 
7633286Sminshall TerminalWrite(buf, n)
7732147Sminshall char	*buf;
7832147Sminshall int	n;
7932147Sminshall {
8033286Sminshall     return write(tout, buf, n);
8132147Sminshall }
8232147Sminshall 
8333286Sminshall TerminalRead(buf, n)
8432147Sminshall char	*buf;
8532147Sminshall int	n;
8632147Sminshall {
8733286Sminshall     return read(tin, buf, n);
8832147Sminshall }
8932147Sminshall 
9032147Sminshall /*
9132147Sminshall  *
9232147Sminshall  */
9332147Sminshall 
9432147Sminshall int
9532553Sminshall TerminalAutoFlush()
9632147Sminshall {
9732147Sminshall #if	defined(LNOFLSH)
9832147Sminshall     int flush;
9932147Sminshall 
10032147Sminshall     ioctl(0, TIOCLGET, (char *)&flush);
10132147Sminshall     return !(flush&LNOFLSH);	/* if LNOFLSH, no autoflush */
10232147Sminshall #else	/* LNOFLSH */
10332147Sminshall     return 1;
10432147Sminshall #endif	/* LNOFLSH */
10532147Sminshall }
10632147Sminshall 
10738689Sborman #ifdef	KLUDGELINEMODE
10838689Sborman extern int kludgelinemode;
10938689Sborman #endif
11032147Sminshall /*
11132147Sminshall  * TerminalSpecialChars()
11232147Sminshall  *
11332147Sminshall  * Look at an input character to see if it is a special character
11432147Sminshall  * and decide what to do.
11532147Sminshall  *
11632147Sminshall  * Output:
11732147Sminshall  *
11832147Sminshall  *	0	Don't add this character.
11932147Sminshall  *	1	Do add this character
12032147Sminshall  */
12132147Sminshall 
12232147Sminshall int
12332553Sminshall TerminalSpecialChars(c)
12432147Sminshall int	c;
12532147Sminshall {
12632553Sminshall     void xmitAO(), xmitEL(), xmitEC(), intp(), sendbrk();
12732147Sminshall 
12838689Sborman     if (c == termIntChar) {
12932147Sminshall 	intp();
13032147Sminshall 	return 0;
13138689Sborman     } else if (c == termQuitChar) {
13238689Sborman #ifdef	KLUDGELINEMODE
13338689Sborman 	if (kludgelinemode)
13438689Sborman 	    sendbrk();
13538689Sborman 	else
13638689Sborman #endif
13738689Sborman 	    sendabort();
13832147Sminshall 	return 0;
13938689Sborman     } else if (c == termEofChar) {
14038689Sborman 	if (my_want_state_is_will(TELOPT_LINEMODE)) {
14138689Sborman 	    sendeof();
14238689Sborman 	    return 0;
14338689Sborman 	}
14438689Sborman 	return 1;
14538689Sborman     } else if (c == termSuspChar) {
14638689Sborman 	sendsusp();
14738689Sborman 	return(0);
14838689Sborman     } else if (c == termFlushChar) {
14932147Sminshall 	xmitAO();		/* Transmit Abort Output */
15032147Sminshall 	return 0;
15132147Sminshall     } else if (!MODE_LOCAL_CHARS(globalmode)) {
15238689Sborman 	if (c == termKillChar) {
15332147Sminshall 	    xmitEL();
15432147Sminshall 	    return 0;
15538689Sborman 	} else if (c == termEraseChar) {
15632147Sminshall 	    xmitEC();		/* Transmit Erase Character */
15732147Sminshall 	    return 0;
15832147Sminshall 	}
15932147Sminshall     }
16032147Sminshall     return 1;
16132147Sminshall }
16232147Sminshall 
16332147Sminshall 
16432147Sminshall /*
16532147Sminshall  * Flush output to the terminal
16632147Sminshall  */
16732147Sminshall 
16832147Sminshall void
16932553Sminshall TerminalFlushOutput()
17032147Sminshall {
17139529Sborman #ifdef	TIOCFLUSH
17232147Sminshall     (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0);
17338689Sborman #else
17438689Sborman     (void) ioctl(fileno(stdout), TCFLSH, (char *) 0);
17538689Sborman #endif
17632147Sminshall }
17732147Sminshall 
17832147Sminshall void
17932553Sminshall TerminalSaveState()
18032147Sminshall {
18138689Sborman #ifndef	USE_TERMIO
18232147Sminshall     ioctl(0, TIOCGETP, (char *)&ottyb);
18332147Sminshall     ioctl(0, TIOCGETC, (char *)&otc);
18432147Sminshall     ioctl(0, TIOCGLTC, (char *)&oltc);
18538909Sborman     ioctl(0, TIOCLGET, (char *)&olmode);
18632147Sminshall 
18732147Sminshall     ntc = otc;
18832147Sminshall     nltc = oltc;
18932147Sminshall     nttyb = ottyb;
19032254Sminshall 
19138689Sborman #else	/* USE_TERMIO */
19238689Sborman     ioctl(0, TCGETA, &old_tc);
19338689Sborman 
19438689Sborman     new_tc = old_tc;
19538689Sborman 
19638689Sborman     termFlushChar = 'O'&0x37;
19738689Sborman     termWerasChar = 'W'&0x37;
19838689Sborman     termRprntChar = 'R'&0x37;
19938689Sborman     termLiteralNextChar = 'V'&0x37;
20038689Sborman     termStartChar = 'Q'&0x37;
20138689Sborman     termStopChar = 'S'&0x37;
20238689Sborman #endif	/* USE_TERMIO */
20332147Sminshall }
20432147Sminshall 
20539529Sborman unsigned
20638689Sborman char *
20738689Sborman tcval(func)
20838689Sborman register int func;
20938689Sborman {
21038689Sborman     switch(func) {
21139529Sborman     case SLC_IP:	return((unsigned char *)&termIntChar);
21239529Sborman     case SLC_ABORT:	return((unsigned char *)&termQuitChar);
21339529Sborman     case SLC_EOF:	return((unsigned char *)&termEofChar);
21439529Sborman     case SLC_EC:	return((unsigned char *)&termEraseChar);
21539529Sborman     case SLC_EL:	return((unsigned char *)&termKillChar);
21639529Sborman     case SLC_XON:	return((unsigned char *)&termStartChar);
21739529Sborman     case SLC_XOFF:	return((unsigned char *)&termStopChar);
21839529Sborman #ifndef	SYSV_TERMIO
21939529Sborman     case SLC_AO:	return((unsigned char *)&termFlushChar);
22039529Sborman     case SLC_SUSP:	return((unsigned char *)&termSuspChar);
22139529Sborman     case SLC_EW:	return((unsigned char *)&termWerasChar);
22239529Sborman     case SLC_RP:	return((unsigned char *)&termRprntChar);
22339529Sborman     case SLC_LNEXT:	return((unsigned char *)&termLiteralNextChar);
22439529Sborman #endif	/* SYSV_TERMIO */
22538689Sborman 
22638689Sborman     case SLC_SYNCH:
22738689Sborman     case SLC_BRK:
22838689Sborman     case SLC_AYT:
22938689Sborman     case SLC_EOR:
23038689Sborman     case SLC_FORW1:
23138689Sborman     case SLC_FORW2:
23238689Sborman     default:
23339529Sborman 	return((unsigned char *)0);
23438689Sborman     }
23538689Sborman }
23638689Sborman 
23732147Sminshall void
23838689Sborman TerminalDefaultChars()
23938689Sborman {
24038689Sborman #ifndef	USE_TERMIO
24138689Sborman     ntc = otc;
24238689Sborman     nltc = oltc;
24338689Sborman     nttyb.sg_kill = ottyb.sg_kill;
24438689Sborman     nttyb.sg_erase = ottyb.sg_erase;
24538689Sborman #else	/* USE_TERMIO */
24638689Sborman     memcpy(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc));
24739529Sborman # ifndef	VFLUSHO
24838689Sborman     termFlushChar = 'O'&0x37;
24939529Sborman # endif
25039529Sborman # ifndef	VWERASE
25138689Sborman     termWerasChar = 'W'&0x37;
25239529Sborman # endif
25339529Sborman # ifndef	VREPRINT
25438689Sborman     termRprntChar = 'R'&0x37;
25539529Sborman # endif
25639529Sborman # ifndef	VLNEXT
25738689Sborman     termLiteralNextChar = 'V'&0x37;
25839529Sborman # endif
25939529Sborman # ifndef	VSTART
26038689Sborman     termStartChar = 'Q'&0x37;
26139529Sborman # endif
26239529Sborman # ifndef	VSTOP
26338689Sborman     termStopChar = 'S'&0x37;
26439529Sborman # endif
26538689Sborman #endif	/* USE_TERMIO */
26638689Sborman }
26738689Sborman 
26838689Sborman void
26932553Sminshall TerminalRestoreState()
27032147Sminshall {
27132147Sminshall }
27232147Sminshall 
27332147Sminshall /*
27432147Sminshall  * TerminalNewMode - set up terminal to a specific mode.
27538689Sborman  *	MODE_ECHO: do local terminal echo
27638689Sborman  *	MODE_FLOW: do local flow control
27738689Sborman  *	MODE_TRAPSIG: do local mapping to TELNET IAC sequences
27838689Sborman  *	MODE_EDIT: do local line editing
27938689Sborman  *
28038689Sborman  *	Command mode:
28138689Sborman  *		MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG
28238689Sborman  *		local echo
28338689Sborman  *		local editing
28438689Sborman  *		local xon/xoff
28538689Sborman  *		local signal mapping
28638689Sborman  *
28738689Sborman  *	Linemode:
28838689Sborman  *		local/no editing
28938689Sborman  *	Both Linemode and Single Character mode:
29038689Sborman  *		local/remote echo
29138689Sborman  *		local/no xon/xoff
29238689Sborman  *		local/no signal mapping
29332147Sminshall  */
29432147Sminshall 
29532147Sminshall 
29632147Sminshall void
29733286Sminshall TerminalNewMode(f)
29832147Sminshall register int f;
29932147Sminshall {
30032147Sminshall     static int prevmode = 0;
30138689Sborman #ifndef	USE_TERMIO
30238689Sborman     struct tchars tc;
30338689Sborman     struct ltchars ltc;
30432147Sminshall     struct sgttyb sb;
30538909Sborman     int lmode;
30638689Sborman #else	/* USE_TERMIO */
30738689Sborman     struct termio tmp_tc;
30838689Sborman #endif	/* USE_TERMIO */
30932147Sminshall     int onoff;
31032147Sminshall     int old;
31132147Sminshall 
31238689Sborman     globalmode = f&~MODE_FORCE;
31332147Sminshall     if (prevmode == f)
31432147Sminshall 	return;
31538689Sborman 
31638689Sborman     /*
31738689Sborman      * Write any outstanding data before switching modes
31838689Sborman      * ttyflush() returns 0 only when there is no more data
31938689Sborman      * left to write out, it returns -1 if it couldn't do
32038689Sborman      * anything at all, otherwise it returns 1 + the number
32138689Sborman      * of characters left to write.
32238689Sborman      */
32338689Sborman     old = ttyflush(SYNCHing|flushout);
32438689Sborman     if (old < 0 || old > 1) {
32538689Sborman #ifndef	USE_TERMIO
32638689Sborman 	ioctl(tin, TIOCGETP, (char *)&sb);
32738689Sborman #else	/* USE_TERMIO */
32838689Sborman 	ioctl(tin, TCGETA, (char *)&tmp_tc);
32938689Sborman #endif	/* USE_TERMIO */
33038689Sborman 	do {
33138689Sborman 	    /*
33238689Sborman 	     * Wait for data to drain, then flush again.
33338689Sborman 	     */
33438689Sborman #ifndef	USE_TERMIO
33538689Sborman 	    ioctl(tin, TIOCSETP, (char *)&sb);
33638689Sborman #else	/* USE_TERMIO */
33738689Sborman 	    ioctl(tin, TCSETAW, (char *)&tmp_tc);
33838689Sborman #endif	/* USE_TERMIO */
33938689Sborman 	    old = ttyflush(SYNCHing|flushout);
34038689Sborman 	} while (old < 0 || old > 1);
34138689Sborman     }
34238689Sborman 
34332147Sminshall     old = prevmode;
34438689Sborman     prevmode = f&~MODE_FORCE;
34538689Sborman #ifndef	USE_TERMIO
34632147Sminshall     sb = nttyb;
34738689Sborman     tc = ntc;
34838689Sborman     ltc = nltc;
34938909Sborman     lmode = olmode;
35038689Sborman #else
35138689Sborman     tmp_tc = new_tc;
35238689Sborman #endif
35332147Sminshall 
35438689Sborman     if (f&MODE_ECHO) {
35538689Sborman #ifndef	USE_TERMIO
35638689Sborman 	sb.sg_flags |= ECHO;
35738689Sborman #else
35838689Sborman 	tmp_tc.c_lflag |= ECHO;
35938689Sborman 	tmp_tc.c_oflag |= ONLCR;
36039529Sborman # ifdef notdef
36138689Sborman 	tmp_tc.c_iflag |= ICRNL;
36239529Sborman # endif
36338689Sborman #endif
36438689Sborman     } else {
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     }
37532147Sminshall 
37638689Sborman     if ((f&MODE_FLOW) == 0) {
37738689Sborman #ifndef	USE_TERMIO
37838689Sborman 	tc.t_startc = -1;
37938689Sborman 	tc.t_stopc = -1;
38038689Sborman #else
38138689Sborman 	tmp_tc.c_iflag &= ~(IXANY|IXOFF|IXON);
38238689Sborman     } else {
38338689Sborman 	tmp_tc.c_iflag |= IXANY|IXOFF|IXON;
38438689Sborman #endif
38538689Sborman     }
38632147Sminshall 
38738689Sborman     if ((f&MODE_TRAPSIG) == 0) {
38838689Sborman #ifndef	USE_TERMIO
38938689Sborman 	tc.t_intrc = -1;
39038689Sborman 	tc.t_quitc = -1;
39138689Sborman 	tc.t_eofc = -1;
39238689Sborman 	ltc.t_suspc = -1;
39338689Sborman 	ltc.t_dsuspc = -1;
39438689Sborman #else
39538689Sborman 	tmp_tc.c_lflag &= ~ISIG;
39638689Sborman #endif
39738689Sborman 	localchars = 0;
39838689Sborman     } else {
39938689Sborman #ifdef	USE_TERMIO
40038689Sborman 	tmp_tc.c_lflag |= ISIG;
40138689Sborman #endif
40238689Sborman 	localchars = 1;
40338689Sborman     }
40438689Sborman 
40538689Sborman     if (f&MODE_EDIT) {
40638689Sborman #ifndef	USE_TERMIO
40738689Sborman 	sb.sg_flags &= ~CBREAK;
40838689Sborman 	sb.sg_flags |= CRMOD;
40938689Sborman #else
41038689Sborman 	tmp_tc.c_lflag |= ICANON;
41138689Sborman #endif
41238689Sborman     } else {
41338689Sborman #ifndef	USE_TERMIO
41438689Sborman 	sb.sg_flags |= CBREAK;
41538689Sborman 	if (f&MODE_ECHO)
41632147Sminshall 	    sb.sg_flags |= CRMOD;
41738689Sborman 	else
41838689Sborman 	    sb.sg_flags &= ~CRMOD;
41938689Sborman #else
42038689Sborman 	tmp_tc.c_lflag &= ~ICANON;
42138689Sborman 	tmp_tc.c_iflag &= ~ICRNL;
42238689Sborman 	tmp_tc.c_cc[VMIN] = 1;
42338689Sborman 	tmp_tc.c_cc[VTIME] = 0;
42438689Sborman #endif
42538689Sborman     }
42632147Sminshall 
42738689Sborman     if (f == -1) {
42838689Sborman 	onoff = 0;
42938689Sborman     } else {
43038909Sborman #ifndef	USE_TERMIO
43139529Sborman 	if (f & MODE_OUTBIN)
43238909Sborman 		lmode |= LLITOUT;
43338909Sborman 	else
43438909Sborman 		lmode &= ~LLITOUT;
43539529Sborman 
43639529Sborman 	if (f & MODE_INBIN)
43738909Sborman 		lmode |= LPASS8;
43838909Sborman 	else
43938909Sborman 		lmode &= ~LPASS8;
44038909Sborman #else
44139529Sborman 	if (f & MODE_OUTBIN)
44239529Sborman 		tmp_tc.c_lflag &= ~ISTRIP;
44338909Sborman 	else
44439529Sborman 		tmp_tc.c_lflag |= ISTRIP;
44539529Sborman 	if (f & MODE_INBIN) {
44639529Sborman 		tmp_tc.c_cflag &= ~(CSIZE|PARENB);
44739529Sborman 		tmp_tc.c_cflag |= CS8;
44839529Sborman 		tmp_tc.c_cflag &= ~OPOST;
44939529Sborman 	} else {
45039529Sborman 		tmp_tc.c_cflag &= ~CSIZE;
45139529Sborman 		tmp_tc.c_cflag |= CS7|PARENB;
45239529Sborman 		tmp_tc.c_cflag |= OPOST;
45339529Sborman 	}
45438909Sborman #endif
45538689Sborman 	onoff = 1;
45632147Sminshall     }
45738689Sborman 
45838689Sborman     if (f != -1) {
45939529Sborman #ifdef	SIGTSTP
46038689Sborman 	if (f&MODE_EDIT) {
46138689Sborman 	    void doescape();
46238689Sborman 
46339529Sborman # ifndef USE_TERMIO
46438689Sborman 	    ltc.t_suspc = escape;
46539529Sborman # else
46639529Sborman 	    tmp_tc.c_cc[VSUSP] = escape;
46739529Sborman # endif
46838689Sborman 	    (void) signal(SIGTSTP, (int (*)())doescape);
46938689Sborman 	} else if (old&MODE_EDIT) {
47038689Sborman 	    (void) signal(SIGTSTP, SIG_DFL);
47138689Sborman 	    sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
47238689Sborman 	}
47339529Sborman #endif	/* SIGTSTP */
47438689Sborman     } else {
47539529Sborman #ifdef	SIGTSTP
47638689Sborman 	(void) signal(SIGTSTP, SIG_DFL);
47738689Sborman 	sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
47839529Sborman #endif	/* SIGTSTP */
47939529Sborman #ifndef USE_TERMIO
48039529Sborman 	ltc = oltc;
48139529Sborman 	tc = otc;
48239529Sborman 	sb = ottyb;
48339529Sborman #endif
48438689Sborman     }
48539529Sborman #ifndef USE_TERMIO
48639529Sborman     ioctl(tin, TIOCLSET, (char *)&lmode);
48739529Sborman     ioctl(tin, TIOCSLTC, (char *)&ltc);
48839529Sborman     ioctl(tin, TIOCSETC, (char *)&tc);
48939529Sborman     ioctl(tin, TIOCSETP, (char *)&sb);
49039529Sborman #else
49139529Sborman     if (ioctl(tin, TCSETAW, &tmp_tc) < 0)
49239529Sborman 	ioctl(tin, TCSETA, &tmp_tc);
49339529Sborman #endif
49439529Sborman 
49532147Sminshall #if	(!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR))
49633286Sminshall     ioctl(tin, FIONBIO, (char *)&onoff);
49733286Sminshall     ioctl(tout, FIONBIO, (char *)&onoff);
49832147Sminshall #endif	/* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */
49932147Sminshall #if	defined(TN3270)
50036242Sminshall     if (noasynchtty == 0) {
50133286Sminshall 	ioctl(tin, FIOASYNC, (char *)&onoff);
50232147Sminshall     }
50332147Sminshall #endif	/* defined(TN3270) */
50432147Sminshall }
50532147Sminshall 
50639529Sborman #ifndef	B19200
50739529Sborman # define B19200 B9600
50839529Sborman #endif
50939529Sborman 
51039529Sborman #ifndef	B38400
51139529Sborman # define B38400 B19200
51239529Sborman #endif
51339529Sborman 
51439529Sborman /*
51539529Sborman  * This code assumes that the values B0, B50, B75...
51639529Sborman  * are in ascending order.  They do not have to be
51739529Sborman  * contiguous.
51839529Sborman  */
51939529Sborman struct termspeeds {
52039529Sborman 	long speed;
52139529Sborman 	long value;
52239529Sborman } termspeeds[] = {
52339529Sborman 	{ 0,     B0 },     { 50,    B50 },   { 75,    B75 },
52439529Sborman 	{ 110,   B110 },   { 134,   B134 },  { 150,   B150 },
52539529Sborman 	{ 200,   B200 },   { 300,   B300 },  { 600,   B600 },
52639529Sborman 	{ 1200,  B1200 },  { 1800,  B1800 }, { 2400,  B2400 },
52739529Sborman 	{ 4800,  B4800 },  { 9600,  B9600 }, { 19200, B19200 },
52839529Sborman 	{ 38400, B38400 }, { -1,    B38400 }
52939529Sborman };
53039529Sborman 
53139529Sborman #ifndef	USE_TERMIO
53239529Sborman # define	ISPEED	ottyb.sg_ispeed
53339529Sborman # define	OSPEED	ottyb.sg_ospeed
53439529Sborman #else
53539529Sborman # ifdef	SYSV_TERMIO
53639529Sborman #  define	ISPEED	(old_tc.c_cflag&CBAUD)
53739529Sborman #  define	OSPEED	ISPEED
53839529Sborman # else
53939529Sborman #  define	ISPEED	old_tc.c_ispeed
54039529Sborman #  define OSPEED	old_tc.c_ospeed
54139529Sborman # endif
54239529Sborman #endif
54339529Sborman 
54437219Sminshall void
54537219Sminshall TerminalSpeeds(ispeed, ospeed)
54637219Sminshall long *ispeed;
54737219Sminshall long *ospeed;
54837219Sminshall {
54939529Sborman     register struct termspeeds *tp;
55032147Sminshall 
55139529Sborman     tp = termspeeds;
55239529Sborman     while ((tp->speed != -1) && (tp->value < ISPEED))
55339529Sborman 	tp++;
55439529Sborman     *ispeed = tp->speed;
55539529Sborman 
55639529Sborman     tp = termspeeds;
55739529Sborman     while ((tp->speed != -1) && (tp->value < OSPEED))
55839529Sborman 	tp++;
55939529Sborman     *ospeed = tp->speed;
56037219Sminshall }
56137219Sminshall 
56232147Sminshall int
56337219Sminshall TerminalWindowSize(rows, cols)
56437219Sminshall long *rows, *cols;
56537219Sminshall {
56638689Sborman #ifdef	TIOCGWINSZ
56737219Sminshall     struct winsize ws;
56837219Sminshall 
56938689Sborman     if (ioctl(fileno(stdin), TIOCGWINSZ, (char *)&ws) >= 0) {
57038689Sborman 	*rows = ws.ws_row;
57138689Sborman 	*cols = ws.ws_col;
57238689Sborman 	return 1;
57337219Sminshall     }
57438810Sborman #endif	/* TIOCGWINSZ */
57538689Sborman     return 0;
57637219Sminshall }
57737219Sminshall 
57837219Sminshall int
57935417Sminshall NetClose(fd)
58035417Sminshall int	fd;
58132147Sminshall {
58235417Sminshall     return close(fd);
58332147Sminshall }
58432147Sminshall 
58532147Sminshall 
58632147Sminshall void
58732553Sminshall NetNonblockingIO(fd, onoff)
58832147Sminshall int
58932147Sminshall 	fd,
59032147Sminshall 	onoff;
59132147Sminshall {
59232147Sminshall     ioctl(fd, FIONBIO, (char *)&onoff);
59332147Sminshall }
59432147Sminshall 
59534849Sminshall #if	defined(TN3270)
59632147Sminshall void
59732553Sminshall NetSigIO(fd, onoff)
59832147Sminshall int
59932147Sminshall 	fd,
60032147Sminshall 	onoff;
60132147Sminshall {
60232147Sminshall     ioctl(fd, FIOASYNC, (char *)&onoff);	/* hear about input */
60332147Sminshall }
60432147Sminshall 
60532147Sminshall void
60632553Sminshall NetSetPgrp(fd)
60732147Sminshall int fd;
60832147Sminshall {
60932147Sminshall     int myPid;
61032147Sminshall 
61132147Sminshall     myPid = getpid();
61236274Sminshall     fcntl(fd, F_SETOWN, myPid);
61332147Sminshall }
61434849Sminshall #endif	/*defined(TN3270)*/
61532553Sminshall 
61632553Sminshall /*
61732553Sminshall  * Various signal handling routines.
61832553Sminshall  */
61932147Sminshall 
62033286Sminshall static void
62132553Sminshall deadpeer()
62232553Sminshall {
62332553Sminshall 	setcommandmode();
62432553Sminshall 	longjmp(peerdied, -1);
62532553Sminshall }
62632147Sminshall 
62733286Sminshall static void
62832553Sminshall intr()
62932553Sminshall {
63032553Sminshall     if (localchars) {
63132553Sminshall 	intp();
63232553Sminshall 	return;
63332553Sminshall     }
63432553Sminshall     setcommandmode();
63532553Sminshall     longjmp(toplevel, -1);
63632553Sminshall }
63732553Sminshall 
63833286Sminshall static void
63932553Sminshall intr2()
64032553Sminshall {
64132553Sminshall     if (localchars) {
64238689Sborman #ifdef	KLUDGELINEMODE
64338689Sborman 	if (kludgelinemode)
64438689Sborman 	    sendbrk();
64538689Sborman 	else
64638689Sborman #endif
64738689Sborman 	    sendabort();
64832553Sminshall 	return;
64932553Sminshall     }
65032553Sminshall }
65132553Sminshall 
65233286Sminshall static void
65337219Sminshall sendwin()
65437219Sminshall {
65537219Sminshall     if (connected) {
65637219Sminshall 	sendnaws();
65737219Sminshall     }
65837219Sminshall }
65937219Sminshall 
66037219Sminshall static void
66132553Sminshall doescape()
66232553Sminshall {
66338689Sborman     command(0, 0, 0);
66432553Sminshall }
66532553Sminshall 
66632553Sminshall void
66732531Sminshall sys_telnet_init()
66832531Sminshall {
66939529Sborman #ifndef	VOID_SIGNAL
67034849Sminshall     (void) signal(SIGINT, (int (*)())intr);
67134849Sminshall     (void) signal(SIGQUIT, (int (*)())intr2);
67234849Sminshall     (void) signal(SIGPIPE, (int (*)())deadpeer);
67338689Sborman #else
67438689Sborman     (void) signal(SIGINT, (void (*)())intr);
67538689Sborman     (void) signal(SIGQUIT, (void (*)())intr2);
67638689Sborman     (void) signal(SIGPIPE, (void (*)())deadpeer);
67738689Sborman #endif
67838689Sborman #ifdef	SIGWINCH
67937219Sminshall     (void) signal(SIGWINCH, (int (*)())sendwin);
68038689Sborman #endif
68132553Sminshall 
68238689Sborman     setconnmode(0);
68332531Sminshall 
68432531Sminshall     NetNonblockingIO(net, 1);
68532531Sminshall 
68632531Sminshall #if	defined(TN3270)
68736242Sminshall     if (noasynchnet == 0) {			/* DBX can't handle! */
68832531Sminshall 	NetSigIO(net, 1);
68932531Sminshall 	NetSetPgrp(net);
69032531Sminshall     }
69132531Sminshall #endif	/* defined(TN3270) */
69232531Sminshall 
69332531Sminshall #if	defined(SO_OOBINLINE)
69434849Sminshall     if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) {
69534849Sminshall 	perror("SetSockOpt");
69634849Sminshall     }
69732531Sminshall #endif	/* defined(SO_OOBINLINE) */
69832531Sminshall }
69932531Sminshall 
70032531Sminshall /*
70132531Sminshall  * Process rings -
70232531Sminshall  *
70332531Sminshall  *	This routine tries to fill up/empty our various rings.
70432531Sminshall  *
70532531Sminshall  *	The parameter specifies whether this is a poll operation,
70632531Sminshall  *	or a block-until-something-happens operation.
70732531Sminshall  *
70832531Sminshall  *	The return value is 1 if something happened, 0 if not.
70932531Sminshall  */
71032531Sminshall 
71132531Sminshall int
71232531Sminshall process_rings(netin, netout, netex, ttyin, ttyout, poll)
71332531Sminshall int poll;		/* If 0, then block until something to do */
71432531Sminshall {
71532531Sminshall     register int c;
71632531Sminshall 		/* One wants to be a bit careful about setting returnValue
71732531Sminshall 		 * to one, since a one implies we did some useful work,
71832531Sminshall 		 * and therefore probably won't be called to block next
71932531Sminshall 		 * time (TN3270 mode only).
72032531Sminshall 		 */
72132531Sminshall     int returnValue = 0;
72232531Sminshall     static struct timeval TimeValue = { 0 };
72332531Sminshall 
72432531Sminshall     if (netout) {
72532531Sminshall 	FD_SET(net, &obits);
72632531Sminshall     }
72732531Sminshall     if (ttyout) {
72832531Sminshall 	FD_SET(tout, &obits);
72932531Sminshall     }
73032531Sminshall #if	defined(TN3270)
73132531Sminshall     if (ttyin) {
73232531Sminshall 	FD_SET(tin, &ibits);
73332531Sminshall     }
73432531Sminshall #else	/* defined(TN3270) */
73532531Sminshall     if (ttyin) {
73632531Sminshall 	FD_SET(tin, &ibits);
73732531Sminshall     }
73832531Sminshall #endif	/* defined(TN3270) */
73932531Sminshall #if	defined(TN3270)
74032531Sminshall     if (netin) {
74132531Sminshall 	FD_SET(net, &ibits);
74232531Sminshall     }
74332531Sminshall #   else /* !defined(TN3270) */
74432531Sminshall     if (netin) {
74532531Sminshall 	FD_SET(net, &ibits);
74632531Sminshall     }
74732531Sminshall #   endif /* !defined(TN3270) */
74832531Sminshall     if (netex) {
74932531Sminshall 	FD_SET(net, &xbits);
75032531Sminshall     }
75132531Sminshall     if ((c = select(16, &ibits, &obits, &xbits,
75232531Sminshall 			(poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) {
75332531Sminshall 	if (c == -1) {
75432531Sminshall 		    /*
75532531Sminshall 		     * we can get EINTR if we are in line mode,
75632531Sminshall 		     * and the user does an escape (TSTP), or
75732531Sminshall 		     * some other signal generator.
75832531Sminshall 		     */
75932531Sminshall 	    if (errno == EINTR) {
76032531Sminshall 		return 0;
76132531Sminshall 	    }
76232531Sminshall #	    if defined(TN3270)
76332531Sminshall 		    /*
76432531Sminshall 		     * we can get EBADF if we were in transparent
76532531Sminshall 		     * mode, and the transcom process died.
76632531Sminshall 		    */
76732531Sminshall 	    if (errno == EBADF) {
76832531Sminshall 			/*
76932531Sminshall 			 * zero the bits (even though kernel does it)
77032531Sminshall 			 * to make sure we are selecting on the right
77132531Sminshall 			 * ones.
77232531Sminshall 			*/
77332531Sminshall 		FD_ZERO(&ibits);
77432531Sminshall 		FD_ZERO(&obits);
77532531Sminshall 		FD_ZERO(&xbits);
77632531Sminshall 		return 0;
77732531Sminshall 	    }
77832531Sminshall #	    endif /* defined(TN3270) */
77932531Sminshall 		    /* I don't like this, does it ever happen? */
78032531Sminshall 	    printf("sleep(5) from telnet, after select\r\n");
78132531Sminshall 	    sleep(5);
78232531Sminshall 	}
78332531Sminshall 	return 0;
78432531Sminshall     }
78532531Sminshall 
78632531Sminshall     /*
78732531Sminshall      * Any urgent data?
78832531Sminshall      */
78932531Sminshall     if (FD_ISSET(net, &xbits)) {
79032531Sminshall 	FD_CLR(net, &xbits);
79132531Sminshall 	SYNCHing = 1;
79232531Sminshall 	ttyflush(1);	/* flush already enqueued data */
79332531Sminshall     }
79432531Sminshall 
79532531Sminshall     /*
79632531Sminshall      * Something to read from the network...
79732531Sminshall      */
79832531Sminshall     if (FD_ISSET(net, &ibits)) {
79932531Sminshall 	int canread;
80032531Sminshall 
80132531Sminshall 	FD_CLR(net, &ibits);
80232531Sminshall 	canread = ring_empty_consecutive(&netiring);
80332531Sminshall #if	!defined(SO_OOBINLINE)
80432531Sminshall 	    /*
80532531Sminshall 	     * In 4.2 (and some early 4.3) systems, the
80632531Sminshall 	     * OOB indication and data handling in the kernel
80732531Sminshall 	     * is such that if two separate TCP Urgent requests
80832531Sminshall 	     * come in, one byte of TCP data will be overlaid.
80932531Sminshall 	     * This is fatal for Telnet, but we try to live
81032531Sminshall 	     * with it.
81132531Sminshall 	     *
81232531Sminshall 	     * In addition, in 4.2 (and...), a special protocol
81332531Sminshall 	     * is needed to pick up the TCP Urgent data in
81432531Sminshall 	     * the correct sequence.
81532531Sminshall 	     *
81632531Sminshall 	     * What we do is:  if we think we are in urgent
81732531Sminshall 	     * mode, we look to see if we are "at the mark".
81832531Sminshall 	     * If we are, we do an OOB receive.  If we run
81932531Sminshall 	     * this twice, we will do the OOB receive twice,
82032531Sminshall 	     * but the second will fail, since the second
82132531Sminshall 	     * time we were "at the mark", but there wasn't
82232531Sminshall 	     * any data there (the kernel doesn't reset
82332531Sminshall 	     * "at the mark" until we do a normal read).
82432531Sminshall 	     * Once we've read the OOB data, we go ahead
82532531Sminshall 	     * and do normal reads.
82632531Sminshall 	     *
82732531Sminshall 	     * There is also another problem, which is that
82832531Sminshall 	     * since the OOB byte we read doesn't put us
82932531Sminshall 	     * out of OOB state, and since that byte is most
83032531Sminshall 	     * likely the TELNET DM (data mark), we would
83132531Sminshall 	     * stay in the TELNET SYNCH (SYNCHing) state.
83232531Sminshall 	     * So, clocks to the rescue.  If we've "just"
83332531Sminshall 	     * received a DM, then we test for the
83432531Sminshall 	     * presence of OOB data when the receive OOB
83532531Sminshall 	     * fails (and AFTER we did the normal mode read
83632531Sminshall 	     * to clear "at the mark").
83732531Sminshall 	     */
83832531Sminshall 	if (SYNCHing) {
83932531Sminshall 	    int atmark;
840*39652Sborman 	    static int bogus_oob = 0, first = 1;
84132531Sminshall 
84232531Sminshall 	    ioctl(net, SIOCATMARK, (char *)&atmark);
84332531Sminshall 	    if (atmark) {
84432531Sminshall 		c = recv(net, netiring.supply, canread, MSG_OOB);
84532531Sminshall 		if ((c == -1) && (errno == EINVAL)) {
84632531Sminshall 		    c = recv(net, netiring.supply, canread, 0);
84732531Sminshall 		    if (clocks.didnetreceive < clocks.gotDM) {
84832531Sminshall 			SYNCHing = stilloob(net);
84932531Sminshall 		    }
850*39652Sborman 		} else if (first && c > 0) {
851*39652Sborman 		    /*
852*39652Sborman 		     * Bogosity check.  Systems based on 4.2BSD
853*39652Sborman 		     * do not return an error if you do a second
854*39652Sborman 		     * recv(MSG_OOB).  So, we do one.  If it
855*39652Sborman 		     * succeeds and returns exactly the same
856*39652Sborman 		     * data, then assume that we are running
857*39652Sborman 		     * on a broken system and set the bogus_oob
858*39652Sborman 		     * flag.  (If the data was different, then
859*39652Sborman 		     * we probably got some valid new data, so
860*39652Sborman 		     * increment the count...)
861*39652Sborman 		     */
862*39652Sborman 		    int i;
863*39652Sborman 		    i = recv(net, netiring.supply + c, canread - c, MSG_OOB);
864*39652Sborman 		    if (i == c &&
865*39652Sborman 			  bcmp(netiring.supply, netiring.supply + c, i) == 0) {
866*39652Sborman 			bogus_oob = 1;
867*39652Sborman 			first = 0;
868*39652Sborman 		    } else if (i < 0) {
869*39652Sborman 			bogus_oob = 0;
870*39652Sborman 			first = 0;
871*39652Sborman 		    } else
872*39652Sborman 			c += i;
87332531Sminshall 		}
874*39652Sborman 		if (bogus_oob && c > 0) {
875*39652Sborman 		    int i;
876*39652Sborman 		    /*
877*39652Sborman 		     * Bogosity.  We have to do the read
878*39652Sborman 		     * to clear the atmark to get out of
879*39652Sborman 		     * an infinate loop.
880*39652Sborman 		     */
881*39652Sborman 		    i = read(net, netiring.supply + c, canread - c);
882*39652Sborman 		    if (i > 0)
883*39652Sborman 			c += i;
884*39652Sborman 		}
88532531Sminshall 	    } else {
88632531Sminshall 		c = recv(net, netiring.supply, canread, 0);
88732531Sminshall 	    }
88832531Sminshall 	} else {
88932531Sminshall 	    c = recv(net, netiring.supply, canread, 0);
89032531Sminshall 	}
89132531Sminshall 	settimer(didnetreceive);
89232531Sminshall #else	/* !defined(SO_OOBINLINE) */
89332531Sminshall 	c = recv(net, netiring.supply, canread, 0);
89432531Sminshall #endif	/* !defined(SO_OOBINLINE) */
89532531Sminshall 	if (c < 0 && errno == EWOULDBLOCK) {
89632531Sminshall 	    c = 0;
89732531Sminshall 	} else if (c <= 0) {
89832531Sminshall 	    return -1;
89932531Sminshall 	}
90032531Sminshall 	if (netdata) {
90132531Sminshall 	    Dump('<', netiring.supply, c);
90232531Sminshall 	}
90332667Sminshall 	if (c)
90432667Sminshall 	    ring_supplied(&netiring, c);
90532531Sminshall 	returnValue = 1;
90632531Sminshall     }
90732531Sminshall 
90832531Sminshall     /*
90932531Sminshall      * Something to read from the tty...
91032531Sminshall      */
91132531Sminshall     if (FD_ISSET(tin, &ibits)) {
91232531Sminshall 	FD_CLR(tin, &ibits);
91333286Sminshall 	c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring));
91432531Sminshall 	if (c < 0 && errno == EWOULDBLOCK) {
91532531Sminshall 	    c = 0;
91632531Sminshall 	} else {
91732531Sminshall 	    /* EOF detection for line mode!!!! */
91833281Sminshall 	    if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && isatty(tin)) {
91932531Sminshall 			/* must be an EOF... */
92032531Sminshall 		*ttyiring.supply = termEofChar;
92132531Sminshall 		c = 1;
92232531Sminshall 	    }
92332531Sminshall 	    if (c <= 0) {
92432531Sminshall 		return -1;
92532531Sminshall 	    }
92638208Sminshall 	    if (termdata) {
92738208Sminshall 		Dump('<', ttyiring.supply, c);
92838208Sminshall 	    }
92932667Sminshall 	    ring_supplied(&ttyiring, c);
93032531Sminshall 	}
93132531Sminshall 	returnValue = 1;		/* did something useful */
93232531Sminshall     }
93332531Sminshall 
93432531Sminshall     if (FD_ISSET(net, &obits)) {
93532531Sminshall 	FD_CLR(net, &obits);
93632531Sminshall 	returnValue |= netflush();
93732531Sminshall     }
93832531Sminshall     if (FD_ISSET(tout, &obits)) {
93932531Sminshall 	FD_CLR(tout, &obits);
94038689Sborman 	returnValue |= (ttyflush(SYNCHing|flushout) > 0);
94132531Sminshall     }
94232531Sminshall 
94332531Sminshall     return returnValue;
94432531Sminshall }
945