xref: /csrg-svn/usr.bin/telnet/sys_bsd.c (revision 44361)
132147Sminshall /*
233685Sbostic  * Copyright (c) 1988 Regents of the University of California.
333685Sbostic  * All rights reserved.
433685Sbostic  *
542770Sbostic  * %sccs.include.redist.c%
633685Sbostic  */
733685Sbostic 
833685Sbostic #ifndef lint
9*44361Sborman static char sccsid[] = "@(#)sys_bsd.c	1.27 (Berkeley) 06/28/90";
1033685Sbostic #endif /* not lint */
1133685Sbostic 
1233685Sbostic /*
1332147Sminshall  * The following routines try to encapsulate what is system dependent
1432147Sminshall  * (at least between 4.x and dos) which is used in telnet.c.
1532147Sminshall  */
1632147Sminshall 
1732147Sminshall 
1836274Sminshall #include <fcntl.h>
1932381Sminshall #include <sys/types.h>
2032147Sminshall #include <sys/time.h>
2132531Sminshall #include <sys/socket.h>
2232147Sminshall #include <signal.h>
2332531Sminshall #include <errno.h>
2438689Sborman #include <arpa/telnet.h>
2532147Sminshall 
2632381Sminshall #include "ring.h"
2732381Sminshall 
2832657Sminshall #include "fdset.h"
2932657Sminshall 
3032147Sminshall #include "defines.h"
3132147Sminshall #include "externs.h"
3232147Sminshall #include "types.h"
3332147Sminshall 
3440245Sborman #if	defined(CRAY)
3540245Sborman #define	SIG_FUNC_RET	void
3640245Sborman #else
3740245Sborman #define	SIG_FUNC_RET	int
3840245Sborman #endif
3940245Sborman 
4032147Sminshall int
4132531Sminshall 	tout,			/* Output file descriptor */
4232531Sminshall 	tin,			/* Input file descriptor */
4336242Sminshall 	net;
4432147Sminshall 
4538689Sborman #ifndef	USE_TERMIO
4638689Sborman struct	tchars otc = { 0 }, ntc = { 0 };
4738689Sborman struct	ltchars oltc = { 0 }, nltc = { 0 };
4838689Sborman struct	sgttyb ottyb = { 0 }, nttyb = { 0 };
4938909Sborman int	olmode = 0;
5032147Sminshall 
5138689Sborman #else	/* USE_TERMIO */
5238689Sborman struct	termio old_tc = { 0 };
5338689Sborman extern struct termio new_tc;
5438689Sborman 
5540245Sborman #ifndef	TCGETA
56*44361Sborman # ifdef TCGETS
57*44361Sborman #  define	TCGETA	TCGETS
58*44361Sborman #  define	TCSETA	TCSETS
59*44361Sborman #  define	TCSETAW	TCSETSW
60*44361Sborman # else
61*44361Sborman #  define	TCGETA	TIOCGETA
62*44361Sborman #  define	TCSETA	TIOCSETA
63*44361Sborman #  define	TCSETAW	TIOCSETAW
64*44361Sborman # endif
6540245Sborman #endif	/* TCGETA */
6638689Sborman #endif	/* USE_TERMIO */
6738689Sborman 
6832531Sminshall static fd_set ibits, obits, xbits;
6932147Sminshall 
7032531Sminshall 
7132531Sminshall init_sys()
7232531Sminshall {
7332531Sminshall     tout = fileno(stdout);
7432531Sminshall     tin = fileno(stdin);
7532531Sminshall     FD_ZERO(&ibits);
7632531Sminshall     FD_ZERO(&obits);
7732531Sminshall     FD_ZERO(&xbits);
7832531Sminshall 
7932531Sminshall     errno = 0;
8032531Sminshall }
8132531Sminshall 
8232531Sminshall 
8333286Sminshall TerminalWrite(buf, n)
8432147Sminshall char	*buf;
8532147Sminshall int	n;
8632147Sminshall {
8733286Sminshall     return write(tout, buf, n);
8832147Sminshall }
8932147Sminshall 
9033286Sminshall TerminalRead(buf, n)
9132147Sminshall char	*buf;
9232147Sminshall int	n;
9332147Sminshall {
9433286Sminshall     return read(tin, buf, n);
9532147Sminshall }
9632147Sminshall 
9732147Sminshall /*
9832147Sminshall  *
9932147Sminshall  */
10032147Sminshall 
10132147Sminshall int
10232553Sminshall TerminalAutoFlush()
10332147Sminshall {
10432147Sminshall #if	defined(LNOFLSH)
10532147Sminshall     int flush;
10632147Sminshall 
10732147Sminshall     ioctl(0, TIOCLGET, (char *)&flush);
10832147Sminshall     return !(flush&LNOFLSH);	/* if LNOFLSH, no autoflush */
10932147Sminshall #else	/* LNOFLSH */
11032147Sminshall     return 1;
11132147Sminshall #endif	/* LNOFLSH */
11232147Sminshall }
11332147Sminshall 
11438689Sborman #ifdef	KLUDGELINEMODE
11538689Sborman extern int kludgelinemode;
11638689Sborman #endif
11732147Sminshall /*
11832147Sminshall  * TerminalSpecialChars()
11932147Sminshall  *
12032147Sminshall  * Look at an input character to see if it is a special character
12132147Sminshall  * and decide what to do.
12232147Sminshall  *
12332147Sminshall  * Output:
12432147Sminshall  *
12532147Sminshall  *	0	Don't add this character.
12632147Sminshall  *	1	Do add this character
12732147Sminshall  */
12832147Sminshall 
12932147Sminshall int
13032553Sminshall TerminalSpecialChars(c)
13132147Sminshall int	c;
13232147Sminshall {
13332553Sminshall     void xmitAO(), xmitEL(), xmitEC(), intp(), sendbrk();
13432147Sminshall 
13538689Sborman     if (c == termIntChar) {
13632147Sminshall 	intp();
13732147Sminshall 	return 0;
13838689Sborman     } else if (c == termQuitChar) {
13938689Sborman #ifdef	KLUDGELINEMODE
14038689Sborman 	if (kludgelinemode)
14138689Sborman 	    sendbrk();
14238689Sborman 	else
14338689Sborman #endif
14438689Sborman 	    sendabort();
14532147Sminshall 	return 0;
14638689Sborman     } else if (c == termEofChar) {
14738689Sborman 	if (my_want_state_is_will(TELOPT_LINEMODE)) {
14838689Sborman 	    sendeof();
14938689Sborman 	    return 0;
15038689Sborman 	}
15138689Sborman 	return 1;
15238689Sborman     } else if (c == termSuspChar) {
15338689Sborman 	sendsusp();
15438689Sborman 	return(0);
15538689Sborman     } else if (c == termFlushChar) {
15632147Sminshall 	xmitAO();		/* Transmit Abort Output */
15732147Sminshall 	return 0;
15832147Sminshall     } else if (!MODE_LOCAL_CHARS(globalmode)) {
15938689Sborman 	if (c == termKillChar) {
16032147Sminshall 	    xmitEL();
16132147Sminshall 	    return 0;
16238689Sborman 	} else if (c == termEraseChar) {
16332147Sminshall 	    xmitEC();		/* Transmit Erase Character */
16432147Sminshall 	    return 0;
16532147Sminshall 	}
16632147Sminshall     }
16732147Sminshall     return 1;
16832147Sminshall }
16932147Sminshall 
17032147Sminshall 
17132147Sminshall /*
17232147Sminshall  * Flush output to the terminal
17332147Sminshall  */
17432147Sminshall 
17532147Sminshall void
17632553Sminshall TerminalFlushOutput()
17732147Sminshall {
17839529Sborman #ifdef	TIOCFLUSH
17932147Sminshall     (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0);
18038689Sborman #else
18138689Sborman     (void) ioctl(fileno(stdout), TCFLSH, (char *) 0);
18238689Sborman #endif
18332147Sminshall }
18432147Sminshall 
18532147Sminshall void
18632553Sminshall TerminalSaveState()
18732147Sminshall {
18838689Sborman #ifndef	USE_TERMIO
18932147Sminshall     ioctl(0, TIOCGETP, (char *)&ottyb);
19032147Sminshall     ioctl(0, TIOCGETC, (char *)&otc);
19132147Sminshall     ioctl(0, TIOCGLTC, (char *)&oltc);
19238909Sborman     ioctl(0, TIOCLGET, (char *)&olmode);
19332147Sminshall 
19432147Sminshall     ntc = otc;
19532147Sminshall     nltc = oltc;
19632147Sminshall     nttyb = ottyb;
19732254Sminshall 
19838689Sborman #else	/* USE_TERMIO */
19938689Sborman     ioctl(0, TCGETA, &old_tc);
20038689Sborman 
20138689Sborman     new_tc = old_tc;
20238689Sborman 
203*44361Sborman     termFlushChar = CONTROL('O');
204*44361Sborman     termWerasChar = CONTROL('W');
205*44361Sborman     termRprntChar = CONTROL('R');
206*44361Sborman     termLiteralNextChar = CONTROL('V');
207*44361Sborman     termStartChar = CONTROL('Q');
208*44361Sborman     termStopChar = CONTROL('S');
20938689Sborman #endif	/* USE_TERMIO */
21032147Sminshall }
21132147Sminshall 
21240245Sborman cc_t *
21338689Sborman tcval(func)
21438689Sborman register int func;
21538689Sborman {
21638689Sborman     switch(func) {
21740245Sborman     case SLC_IP:	return(&termIntChar);
21840245Sborman     case SLC_ABORT:	return(&termQuitChar);
21940245Sborman     case SLC_EOF:	return(&termEofChar);
22040245Sborman     case SLC_EC:	return(&termEraseChar);
22140245Sborman     case SLC_EL:	return(&termKillChar);
22240245Sborman     case SLC_XON:	return(&termStartChar);
22340245Sborman     case SLC_XOFF:	return(&termStopChar);
224*44361Sborman     case SLC_FORW1:	return(&termForw1Char);
22539529Sborman #ifndef	SYSV_TERMIO
22640245Sborman     case SLC_AO:	return(&termFlushChar);
22740245Sborman     case SLC_SUSP:	return(&termSuspChar);
22840245Sborman     case SLC_EW:	return(&termWerasChar);
22940245Sborman     case SLC_RP:	return(&termRprntChar);
23040245Sborman     case SLC_LNEXT:	return(&termLiteralNextChar);
23139529Sborman #endif	/* SYSV_TERMIO */
232*44361Sborman #ifdef	USE_TERMIO
233*44361Sborman     case SLC_FORW2:	return(&termForw2Char);
234*44361Sborman #endif
23538689Sborman 
23638689Sborman     case SLC_SYNCH:
23738689Sborman     case SLC_BRK:
23838689Sborman     case SLC_AYT:
23938689Sborman     case SLC_EOR:
24038689Sborman     default:
24140245Sborman 	return((cc_t *)0);
24238689Sborman     }
24338689Sborman }
24438689Sborman 
24532147Sminshall void
24638689Sborman TerminalDefaultChars()
24738689Sborman {
24838689Sborman #ifndef	USE_TERMIO
24938689Sborman     ntc = otc;
25038689Sborman     nltc = oltc;
25138689Sborman     nttyb.sg_kill = ottyb.sg_kill;
25238689Sborman     nttyb.sg_erase = ottyb.sg_erase;
25338689Sborman #else	/* USE_TERMIO */
25438689Sborman     memcpy(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc));
255*44361Sborman # ifndef	VFLUSHO
256*44361Sborman     termFlushChar = CONTROL('O');
25739529Sborman # endif
25839529Sborman # ifndef	VWERASE
259*44361Sborman     termWerasChar = CONTROL('W');
26039529Sborman # endif
26139529Sborman # ifndef	VREPRINT
262*44361Sborman     termRprntChar = CONTROL('R');
26339529Sborman # endif
26439529Sborman # ifndef	VLNEXT
265*44361Sborman     termLiteralNextChar = CONTROL('V');
26639529Sborman # endif
26739529Sborman # ifndef	VSTART
268*44361Sborman     termStartChar = CONTROL('Q');
26939529Sborman # endif
27039529Sborman # ifndef	VSTOP
271*44361Sborman     termStopChar = CONTROL('S');
27239529Sborman # endif
27338689Sborman #endif	/* USE_TERMIO */
27438689Sborman }
27538689Sborman 
276*44361Sborman #ifdef notdef
27738689Sborman void
27832553Sminshall TerminalRestoreState()
27932147Sminshall {
28032147Sminshall }
281*44361Sborman #endif
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 
437*44361Sborman     if ((f&(MODE_EDIT|MODE_TRAPSIG)) == 0) {
438*44361Sborman #ifndef	USE_TERMIO
439*44361Sborman 	ltc.t_lnextc = -1;
440*44361Sborman #else
441*44361Sborman # ifdef VLNEXT
442*44361Sborman 	tmp_tc.c_cc[VLNEXT] = (cc_t)(-1);
443*44361Sborman # endif
444*44361Sborman #endif
445*44361Sborman     }
446*44361Sborman 
447*44361Sborman     if (f&MODE_SOFT_TAB) {
448*44361Sborman #ifndef USE_TERMIO
449*44361Sborman 	sb.sg_flags |= XTABS;
450*44361Sborman #else
451*44361Sborman # ifdef	OXTABS
452*44361Sborman 	tmp_tc.c_oflag |= OXTABS;
453*44361Sborman # endif
454*44361Sborman # ifdef	TABDLY
455*44361Sborman 	tmp_tc.c_oflag &= ~TABDLY;
456*44361Sborman 	tmp_tc.c_oflag |= TAB3;
457*44361Sborman # endif
458*44361Sborman #endif
459*44361Sborman     } else {
460*44361Sborman #ifndef USE_TERMIO
461*44361Sborman 	sb.sg_flags &= ~XTABS;
462*44361Sborman #else
463*44361Sborman # ifdef	OXTABS
464*44361Sborman 	tmp_tc.c_oflag &= ~OXTABS;
465*44361Sborman # endif
466*44361Sborman # ifdef	TABDLY
467*44361Sborman 	tmp_tc.c_oflag &= ~TABDLY;
468*44361Sborman # endif
469*44361Sborman #endif
470*44361Sborman     }
471*44361Sborman 
472*44361Sborman     if (f&MODE_LIT_ECHO) {
473*44361Sborman #ifndef USE_TERMIO
474*44361Sborman 	sb.sg_flags &= ~CTLECH;
475*44361Sborman #else
476*44361Sborman # ifdef	ECHOCTL
477*44361Sborman 	tmp_tc.c_lflag &= ~ECHOCTL;
478*44361Sborman # endif
479*44361Sborman #endif
480*44361Sborman     } else {
481*44361Sborman #ifndef USE_TERMIO
482*44361Sborman 	sb.sg_flags |= CTLECH;
483*44361Sborman #else
484*44361Sborman # ifdef	ECHOCTL
485*44361Sborman 	tmp_tc.c_lflag |= ECHOCTL;
486*44361Sborman # endif
487*44361Sborman #endif
488*44361Sborman     }
489*44361Sborman 
49038689Sborman     if (f == -1) {
49138689Sborman 	onoff = 0;
49238689Sborman     } else {
49338909Sborman #ifndef	USE_TERMIO
49439529Sborman 	if (f & MODE_OUTBIN)
49538909Sborman 		lmode |= LLITOUT;
49638909Sborman 	else
49738909Sborman 		lmode &= ~LLITOUT;
49839529Sborman 
49939529Sborman 	if (f & MODE_INBIN)
50038909Sborman 		lmode |= LPASS8;
50138909Sborman 	else
50238909Sborman 		lmode &= ~LPASS8;
50338909Sborman #else
50439529Sborman 	if (f & MODE_OUTBIN)
50539529Sborman 		tmp_tc.c_lflag &= ~ISTRIP;
50638909Sborman 	else
50739529Sborman 		tmp_tc.c_lflag |= ISTRIP;
50839529Sborman 	if (f & MODE_INBIN) {
50939529Sborman 		tmp_tc.c_cflag &= ~(CSIZE|PARENB);
51039529Sborman 		tmp_tc.c_cflag |= CS8;
51139529Sborman 		tmp_tc.c_cflag &= ~OPOST;
51239529Sborman 	} else {
51339529Sborman 		tmp_tc.c_cflag &= ~CSIZE;
51439529Sborman 		tmp_tc.c_cflag |= CS7|PARENB;
51539529Sborman 		tmp_tc.c_cflag |= OPOST;
51639529Sborman 	}
51738909Sborman #endif
51838689Sborman 	onoff = 1;
51932147Sminshall     }
52038689Sborman 
52138689Sborman     if (f != -1) {
52239529Sborman #ifdef	SIGTSTP
523*44361Sborman 	static void susp();
52438689Sborman 
52540245Sborman 	(void) signal(SIGTSTP, (SIG_FUNC_RET (*)())susp);
52639529Sborman #endif	/* SIGTSTP */
527*44361Sborman 	/*
528*44361Sborman 	 * We don't want to process ^Y here.  It's just another
529*44361Sborman 	 * character that we'll pass on to the back end.  It has
530*44361Sborman 	 * to process it because it will be processed when the
531*44361Sborman 	 * user attempts to read it, not when we send it.
532*44361Sborman 	 */
533*44361Sborman #ifndef	USE_TERMIO
534*44361Sborman 	ltc.t_dsuspc = -1;
535*44361Sborman #else
536*44361Sborman # ifdef	VDSUSP
537*44361Sborman 	tmp_tc.c_cc[VDSUSP] = (cc_t)(-1);
538*44361Sborman # endif
539*44361Sborman #endif
54040245Sborman #ifdef	USE_TERMIO
54140245Sborman 	/*
54240245Sborman 	 * If the VEOL character is already set, then use VEOL2,
54340245Sborman 	 * otherwise use VEOL.
54440245Sborman 	 */
545*44361Sborman 	if (tmp_tc.c_cc[VEOL] == (cc_t)(-1))
546*44361Sborman 		tmp_tc.c_cc[VEOL] = escape;
547*44361Sborman # ifdef	VEOL2
548*44361Sborman 	else if (tmp_tc.c_cc[VEOL2] == (cc_t)(-1))
54940245Sborman 		tmp_tc.c_cc[VEOL2] = escape;
550*44361Sborman # endif
55140245Sborman #else
552*44361Sborman 	if (tc.t_brkc == (cc_t)(-1))
553*44361Sborman 		tc.t_brkc = escape;
55440245Sborman #endif
55538689Sborman     } else {
55639529Sborman #ifdef	SIGTSTP
55738689Sborman 	(void) signal(SIGTSTP, SIG_DFL);
558*44361Sborman 	(void) sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
55939529Sborman #endif	/* SIGTSTP */
56039529Sborman #ifndef USE_TERMIO
56139529Sborman 	ltc = oltc;
56239529Sborman 	tc = otc;
56339529Sborman 	sb = ottyb;
564*44361Sborman 	lmode = olmode;
565*44361Sborman #else
566*44361Sborman 	tmp_tc = old_tc;
56739529Sborman #endif
56838689Sborman     }
56939529Sborman #ifndef USE_TERMIO
57039529Sborman     ioctl(tin, TIOCLSET, (char *)&lmode);
57139529Sborman     ioctl(tin, TIOCSLTC, (char *)&ltc);
57239529Sborman     ioctl(tin, TIOCSETC, (char *)&tc);
57339529Sborman     ioctl(tin, TIOCSETP, (char *)&sb);
57439529Sborman #else
57539529Sborman     if (ioctl(tin, TCSETAW, &tmp_tc) < 0)
57639529Sborman 	ioctl(tin, TCSETA, &tmp_tc);
57739529Sborman #endif
57839529Sborman 
57932147Sminshall #if	(!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR))
58033286Sminshall     ioctl(tin, FIONBIO, (char *)&onoff);
58133286Sminshall     ioctl(tout, FIONBIO, (char *)&onoff);
58232147Sminshall #endif	/* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */
58332147Sminshall #if	defined(TN3270)
58436242Sminshall     if (noasynchtty == 0) {
58533286Sminshall 	ioctl(tin, FIOASYNC, (char *)&onoff);
58632147Sminshall     }
58732147Sminshall #endif	/* defined(TN3270) */
58832147Sminshall }
58932147Sminshall 
59039529Sborman #ifndef	B19200
59139529Sborman # define B19200 B9600
59239529Sborman #endif
59339529Sborman 
59439529Sborman #ifndef	B38400
59539529Sborman # define B38400 B19200
59639529Sborman #endif
59739529Sborman 
59839529Sborman /*
59939529Sborman  * This code assumes that the values B0, B50, B75...
60039529Sborman  * are in ascending order.  They do not have to be
60139529Sborman  * contiguous.
60239529Sborman  */
60339529Sborman struct termspeeds {
60439529Sborman 	long speed;
60539529Sborman 	long value;
60639529Sborman } termspeeds[] = {
60739529Sborman 	{ 0,     B0 },     { 50,    B50 },   { 75,    B75 },
60839529Sborman 	{ 110,   B110 },   { 134,   B134 },  { 150,   B150 },
60939529Sborman 	{ 200,   B200 },   { 300,   B300 },  { 600,   B600 },
61039529Sborman 	{ 1200,  B1200 },  { 1800,  B1800 }, { 2400,  B2400 },
61139529Sborman 	{ 4800,  B4800 },  { 9600,  B9600 }, { 19200, B19200 },
61239529Sborman 	{ 38400, B38400 }, { -1,    B38400 }
61339529Sborman };
61439529Sborman 
61539529Sborman #ifndef	USE_TERMIO
61639529Sborman # define	ISPEED	ottyb.sg_ispeed
61739529Sborman # define	OSPEED	ottyb.sg_ospeed
61839529Sborman #else
619*44361Sborman # ifdef	CBAUD
62039529Sborman #  define	ISPEED	(old_tc.c_cflag&CBAUD)
62139529Sborman #  define	OSPEED	ISPEED
62239529Sborman # else
62339529Sborman #  define	ISPEED	old_tc.c_ispeed
62439529Sborman #  define OSPEED	old_tc.c_ospeed
62539529Sborman # endif
62639529Sborman #endif
62739529Sborman 
62837219Sminshall void
62937219Sminshall TerminalSpeeds(ispeed, ospeed)
63037219Sminshall long *ispeed;
63137219Sminshall long *ospeed;
63237219Sminshall {
63339529Sborman     register struct termspeeds *tp;
63432147Sminshall 
63539529Sborman     tp = termspeeds;
63639529Sborman     while ((tp->speed != -1) && (tp->value < ISPEED))
63739529Sborman 	tp++;
63839529Sborman     *ispeed = tp->speed;
63939529Sborman 
64039529Sborman     tp = termspeeds;
64139529Sborman     while ((tp->speed != -1) && (tp->value < OSPEED))
64239529Sborman 	tp++;
64339529Sborman     *ospeed = tp->speed;
64437219Sminshall }
64537219Sminshall 
64632147Sminshall int
64737219Sminshall TerminalWindowSize(rows, cols)
64837219Sminshall long *rows, *cols;
64937219Sminshall {
65038689Sborman #ifdef	TIOCGWINSZ
65137219Sminshall     struct winsize ws;
65237219Sminshall 
65338689Sborman     if (ioctl(fileno(stdin), TIOCGWINSZ, (char *)&ws) >= 0) {
65438689Sborman 	*rows = ws.ws_row;
65538689Sborman 	*cols = ws.ws_col;
65638689Sborman 	return 1;
65737219Sminshall     }
65838810Sborman #endif	/* TIOCGWINSZ */
65938689Sborman     return 0;
66037219Sminshall }
66137219Sminshall 
66237219Sminshall int
66335417Sminshall NetClose(fd)
66435417Sminshall int	fd;
66532147Sminshall {
66635417Sminshall     return close(fd);
66732147Sminshall }
66832147Sminshall 
66932147Sminshall 
67032147Sminshall void
67132553Sminshall NetNonblockingIO(fd, onoff)
67232147Sminshall int
67332147Sminshall 	fd,
67432147Sminshall 	onoff;
67532147Sminshall {
67632147Sminshall     ioctl(fd, FIONBIO, (char *)&onoff);
67732147Sminshall }
67832147Sminshall 
67934849Sminshall #if	defined(TN3270)
68032147Sminshall void
68132553Sminshall NetSigIO(fd, onoff)
68232147Sminshall int
68332147Sminshall 	fd,
68432147Sminshall 	onoff;
68532147Sminshall {
68632147Sminshall     ioctl(fd, FIOASYNC, (char *)&onoff);	/* hear about input */
68732147Sminshall }
68832147Sminshall 
68932147Sminshall void
69032553Sminshall NetSetPgrp(fd)
69132147Sminshall int fd;
69232147Sminshall {
69332147Sminshall     int myPid;
69432147Sminshall 
69532147Sminshall     myPid = getpid();
69636274Sminshall     fcntl(fd, F_SETOWN, myPid);
69732147Sminshall }
69834849Sminshall #endif	/*defined(TN3270)*/
69932553Sminshall 
70032553Sminshall /*
70132553Sminshall  * Various signal handling routines.
70232553Sminshall  */
70332147Sminshall 
70433286Sminshall static void
70532553Sminshall deadpeer()
70632553Sminshall {
70732553Sminshall 	setcommandmode();
70832553Sminshall 	longjmp(peerdied, -1);
70932553Sminshall }
71032147Sminshall 
71133286Sminshall static void
71232553Sminshall intr()
71332553Sminshall {
71432553Sminshall     if (localchars) {
71532553Sminshall 	intp();
71632553Sminshall 	return;
71732553Sminshall     }
71832553Sminshall     setcommandmode();
71932553Sminshall     longjmp(toplevel, -1);
72032553Sminshall }
72132553Sminshall 
72233286Sminshall static void
72332553Sminshall intr2()
72432553Sminshall {
72532553Sminshall     if (localchars) {
72638689Sborman #ifdef	KLUDGELINEMODE
72738689Sborman 	if (kludgelinemode)
72838689Sborman 	    sendbrk();
72938689Sborman 	else
73038689Sborman #endif
73138689Sborman 	    sendabort();
73232553Sminshall 	return;
73332553Sminshall     }
73432553Sminshall }
73532553Sminshall 
73633286Sminshall static void
73740245Sborman susp()
73840245Sborman {
73940245Sborman     if (localchars)
74040245Sborman 	sendsusp();
74140245Sborman }
74240245Sborman 
74340245Sborman static void
74437219Sminshall sendwin()
74537219Sminshall {
74637219Sminshall     if (connected) {
74737219Sminshall 	sendnaws();
74837219Sminshall     }
74937219Sminshall }
75037219Sminshall 
75132553Sminshall 
75232553Sminshall void
75332531Sminshall sys_telnet_init()
75432531Sminshall {
75540245Sborman     (void) signal(SIGINT, (SIG_FUNC_RET (*)())intr);
75640245Sborman     (void) signal(SIGQUIT, (SIG_FUNC_RET (*)())intr2);
75740245Sborman     (void) signal(SIGPIPE, (SIG_FUNC_RET (*)())deadpeer);
75838689Sborman #ifdef	SIGWINCH
75940245Sborman     (void) signal(SIGWINCH, (SIG_FUNC_RET (*)())sendwin);
76038689Sborman #endif
76140245Sborman #ifdef	SIGTSTP
76240245Sborman     (void) signal(SIGTSTP, (SIG_FUNC_RET (*)())susp);
76340245Sborman #endif
76432553Sminshall 
76538689Sborman     setconnmode(0);
76632531Sminshall 
76732531Sminshall     NetNonblockingIO(net, 1);
76832531Sminshall 
76932531Sminshall #if	defined(TN3270)
77036242Sminshall     if (noasynchnet == 0) {			/* DBX can't handle! */
77132531Sminshall 	NetSigIO(net, 1);
77232531Sminshall 	NetSetPgrp(net);
77332531Sminshall     }
77432531Sminshall #endif	/* defined(TN3270) */
77532531Sminshall 
77632531Sminshall #if	defined(SO_OOBINLINE)
77734849Sminshall     if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) {
77834849Sminshall 	perror("SetSockOpt");
77934849Sminshall     }
78032531Sminshall #endif	/* defined(SO_OOBINLINE) */
78132531Sminshall }
78232531Sminshall 
78332531Sminshall /*
78432531Sminshall  * Process rings -
78532531Sminshall  *
78632531Sminshall  *	This routine tries to fill up/empty our various rings.
78732531Sminshall  *
78832531Sminshall  *	The parameter specifies whether this is a poll operation,
78932531Sminshall  *	or a block-until-something-happens operation.
79032531Sminshall  *
79132531Sminshall  *	The return value is 1 if something happened, 0 if not.
79232531Sminshall  */
79332531Sminshall 
79432531Sminshall int
79532531Sminshall process_rings(netin, netout, netex, ttyin, ttyout, poll)
79632531Sminshall int poll;		/* If 0, then block until something to do */
79732531Sminshall {
79832531Sminshall     register int c;
79932531Sminshall 		/* One wants to be a bit careful about setting returnValue
80032531Sminshall 		 * to one, since a one implies we did some useful work,
80132531Sminshall 		 * and therefore probably won't be called to block next
80232531Sminshall 		 * time (TN3270 mode only).
80332531Sminshall 		 */
80432531Sminshall     int returnValue = 0;
80532531Sminshall     static struct timeval TimeValue = { 0 };
80632531Sminshall 
80732531Sminshall     if (netout) {
80832531Sminshall 	FD_SET(net, &obits);
80932531Sminshall     }
81032531Sminshall     if (ttyout) {
81132531Sminshall 	FD_SET(tout, &obits);
81232531Sminshall     }
81332531Sminshall #if	defined(TN3270)
81432531Sminshall     if (ttyin) {
81532531Sminshall 	FD_SET(tin, &ibits);
81632531Sminshall     }
81732531Sminshall #else	/* defined(TN3270) */
81832531Sminshall     if (ttyin) {
81932531Sminshall 	FD_SET(tin, &ibits);
82032531Sminshall     }
82132531Sminshall #endif	/* defined(TN3270) */
82232531Sminshall #if	defined(TN3270)
82332531Sminshall     if (netin) {
82432531Sminshall 	FD_SET(net, &ibits);
82532531Sminshall     }
82632531Sminshall #   else /* !defined(TN3270) */
82732531Sminshall     if (netin) {
82832531Sminshall 	FD_SET(net, &ibits);
82932531Sminshall     }
83032531Sminshall #   endif /* !defined(TN3270) */
83132531Sminshall     if (netex) {
83232531Sminshall 	FD_SET(net, &xbits);
83332531Sminshall     }
83432531Sminshall     if ((c = select(16, &ibits, &obits, &xbits,
83532531Sminshall 			(poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) {
83632531Sminshall 	if (c == -1) {
83732531Sminshall 		    /*
83832531Sminshall 		     * we can get EINTR if we are in line mode,
83932531Sminshall 		     * and the user does an escape (TSTP), or
84032531Sminshall 		     * some other signal generator.
84132531Sminshall 		     */
84232531Sminshall 	    if (errno == EINTR) {
84332531Sminshall 		return 0;
84432531Sminshall 	    }
84532531Sminshall #	    if defined(TN3270)
84632531Sminshall 		    /*
84732531Sminshall 		     * we can get EBADF if we were in transparent
84832531Sminshall 		     * mode, and the transcom process died.
84932531Sminshall 		    */
85032531Sminshall 	    if (errno == EBADF) {
85132531Sminshall 			/*
85232531Sminshall 			 * zero the bits (even though kernel does it)
85332531Sminshall 			 * to make sure we are selecting on the right
85432531Sminshall 			 * ones.
85532531Sminshall 			*/
85632531Sminshall 		FD_ZERO(&ibits);
85732531Sminshall 		FD_ZERO(&obits);
85832531Sminshall 		FD_ZERO(&xbits);
85932531Sminshall 		return 0;
86032531Sminshall 	    }
86132531Sminshall #	    endif /* defined(TN3270) */
86232531Sminshall 		    /* I don't like this, does it ever happen? */
86332531Sminshall 	    printf("sleep(5) from telnet, after select\r\n");
86432531Sminshall 	    sleep(5);
86532531Sminshall 	}
86632531Sminshall 	return 0;
86732531Sminshall     }
86832531Sminshall 
86932531Sminshall     /*
87032531Sminshall      * Any urgent data?
87132531Sminshall      */
87232531Sminshall     if (FD_ISSET(net, &xbits)) {
87332531Sminshall 	FD_CLR(net, &xbits);
87432531Sminshall 	SYNCHing = 1;
875*44361Sborman 	(void) ttyflush(1);	/* flush already enqueued data */
87632531Sminshall     }
87732531Sminshall 
87832531Sminshall     /*
87932531Sminshall      * Something to read from the network...
88032531Sminshall      */
88132531Sminshall     if (FD_ISSET(net, &ibits)) {
88232531Sminshall 	int canread;
88332531Sminshall 
88432531Sminshall 	FD_CLR(net, &ibits);
88532531Sminshall 	canread = ring_empty_consecutive(&netiring);
88632531Sminshall #if	!defined(SO_OOBINLINE)
88732531Sminshall 	    /*
88832531Sminshall 	     * In 4.2 (and some early 4.3) systems, the
88932531Sminshall 	     * OOB indication and data handling in the kernel
89032531Sminshall 	     * is such that if two separate TCP Urgent requests
89132531Sminshall 	     * come in, one byte of TCP data will be overlaid.
89232531Sminshall 	     * This is fatal for Telnet, but we try to live
89332531Sminshall 	     * with it.
89432531Sminshall 	     *
89532531Sminshall 	     * In addition, in 4.2 (and...), a special protocol
89632531Sminshall 	     * is needed to pick up the TCP Urgent data in
89732531Sminshall 	     * the correct sequence.
89832531Sminshall 	     *
89932531Sminshall 	     * What we do is:  if we think we are in urgent
90032531Sminshall 	     * mode, we look to see if we are "at the mark".
90132531Sminshall 	     * If we are, we do an OOB receive.  If we run
90232531Sminshall 	     * this twice, we will do the OOB receive twice,
90332531Sminshall 	     * but the second will fail, since the second
90432531Sminshall 	     * time we were "at the mark", but there wasn't
90532531Sminshall 	     * any data there (the kernel doesn't reset
90632531Sminshall 	     * "at the mark" until we do a normal read).
90732531Sminshall 	     * Once we've read the OOB data, we go ahead
90832531Sminshall 	     * and do normal reads.
90932531Sminshall 	     *
91032531Sminshall 	     * There is also another problem, which is that
91132531Sminshall 	     * since the OOB byte we read doesn't put us
91232531Sminshall 	     * out of OOB state, and since that byte is most
91332531Sminshall 	     * likely the TELNET DM (data mark), we would
91432531Sminshall 	     * stay in the TELNET SYNCH (SYNCHing) state.
91532531Sminshall 	     * So, clocks to the rescue.  If we've "just"
91632531Sminshall 	     * received a DM, then we test for the
91732531Sminshall 	     * presence of OOB data when the receive OOB
91832531Sminshall 	     * fails (and AFTER we did the normal mode read
91932531Sminshall 	     * to clear "at the mark").
92032531Sminshall 	     */
92132531Sminshall 	if (SYNCHing) {
92232531Sminshall 	    int atmark;
92339652Sborman 	    static int bogus_oob = 0, first = 1;
92432531Sminshall 
92532531Sminshall 	    ioctl(net, SIOCATMARK, (char *)&atmark);
92632531Sminshall 	    if (atmark) {
92732531Sminshall 		c = recv(net, netiring.supply, canread, MSG_OOB);
92832531Sminshall 		if ((c == -1) && (errno == EINVAL)) {
92932531Sminshall 		    c = recv(net, netiring.supply, canread, 0);
93032531Sminshall 		    if (clocks.didnetreceive < clocks.gotDM) {
93132531Sminshall 			SYNCHing = stilloob(net);
93232531Sminshall 		    }
93339652Sborman 		} else if (first && c > 0) {
93439652Sborman 		    /*
93539652Sborman 		     * Bogosity check.  Systems based on 4.2BSD
93639652Sborman 		     * do not return an error if you do a second
93739652Sborman 		     * recv(MSG_OOB).  So, we do one.  If it
93839652Sborman 		     * succeeds and returns exactly the same
93939652Sborman 		     * data, then assume that we are running
94039652Sborman 		     * on a broken system and set the bogus_oob
94139652Sborman 		     * flag.  (If the data was different, then
94239652Sborman 		     * we probably got some valid new data, so
94339652Sborman 		     * increment the count...)
94439652Sborman 		     */
94539652Sborman 		    int i;
94639652Sborman 		    i = recv(net, netiring.supply + c, canread - c, MSG_OOB);
94739652Sborman 		    if (i == c &&
94839652Sborman 			  bcmp(netiring.supply, netiring.supply + c, i) == 0) {
94939652Sborman 			bogus_oob = 1;
95039652Sborman 			first = 0;
95139652Sborman 		    } else if (i < 0) {
95239652Sborman 			bogus_oob = 0;
95339652Sborman 			first = 0;
95439652Sborman 		    } else
95539652Sborman 			c += i;
95632531Sminshall 		}
95739652Sborman 		if (bogus_oob && c > 0) {
95839652Sborman 		    int i;
95939652Sborman 		    /*
96039652Sborman 		     * Bogosity.  We have to do the read
96139652Sborman 		     * to clear the atmark to get out of
96239652Sborman 		     * an infinate loop.
96339652Sborman 		     */
96439652Sborman 		    i = read(net, netiring.supply + c, canread - c);
96539652Sborman 		    if (i > 0)
96639652Sborman 			c += i;
96739652Sborman 		}
96832531Sminshall 	    } else {
96932531Sminshall 		c = recv(net, netiring.supply, canread, 0);
97032531Sminshall 	    }
97132531Sminshall 	} else {
97232531Sminshall 	    c = recv(net, netiring.supply, canread, 0);
97332531Sminshall 	}
97432531Sminshall 	settimer(didnetreceive);
97532531Sminshall #else	/* !defined(SO_OOBINLINE) */
97632531Sminshall 	c = recv(net, netiring.supply, canread, 0);
97732531Sminshall #endif	/* !defined(SO_OOBINLINE) */
97832531Sminshall 	if (c < 0 && errno == EWOULDBLOCK) {
97932531Sminshall 	    c = 0;
98032531Sminshall 	} else if (c <= 0) {
98132531Sminshall 	    return -1;
98232531Sminshall 	}
98332531Sminshall 	if (netdata) {
98432531Sminshall 	    Dump('<', netiring.supply, c);
98532531Sminshall 	}
98632667Sminshall 	if (c)
98732667Sminshall 	    ring_supplied(&netiring, c);
98832531Sminshall 	returnValue = 1;
98932531Sminshall     }
99032531Sminshall 
99132531Sminshall     /*
99232531Sminshall      * Something to read from the tty...
99332531Sminshall      */
99432531Sminshall     if (FD_ISSET(tin, &ibits)) {
99532531Sminshall 	FD_CLR(tin, &ibits);
99633286Sminshall 	c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring));
99732531Sminshall 	if (c < 0 && errno == EWOULDBLOCK) {
99832531Sminshall 	    c = 0;
99932531Sminshall 	} else {
100032531Sminshall 	    /* EOF detection for line mode!!!! */
100133281Sminshall 	    if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && isatty(tin)) {
100232531Sminshall 			/* must be an EOF... */
100332531Sminshall 		*ttyiring.supply = termEofChar;
100432531Sminshall 		c = 1;
100532531Sminshall 	    }
100632531Sminshall 	    if (c <= 0) {
100732531Sminshall 		return -1;
100832531Sminshall 	    }
100938208Sminshall 	    if (termdata) {
101038208Sminshall 		Dump('<', ttyiring.supply, c);
101138208Sminshall 	    }
101232667Sminshall 	    ring_supplied(&ttyiring, c);
101332531Sminshall 	}
101432531Sminshall 	returnValue = 1;		/* did something useful */
101532531Sminshall     }
101632531Sminshall 
101732531Sminshall     if (FD_ISSET(net, &obits)) {
101832531Sminshall 	FD_CLR(net, &obits);
101932531Sminshall 	returnValue |= netflush();
102032531Sminshall     }
102132531Sminshall     if (FD_ISSET(tout, &obits)) {
102232531Sminshall 	FD_CLR(tout, &obits);
102338689Sborman 	returnValue |= (ttyflush(SYNCHing|flushout) > 0);
102432531Sminshall     }
102532531Sminshall 
102632531Sminshall     return returnValue;
102732531Sminshall }
1028