xref: /csrg-svn/usr.bin/telnet/sys_bsd.c (revision 38909)
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*38909Sborman static char sccsid[] = "@(#)sys_bsd.c	1.21 (Berkeley) 09/01/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 #if	defined(unix)
2832147Sminshall 
2936274Sminshall #include <fcntl.h>
3032381Sminshall #include <sys/types.h>
3132147Sminshall #include <sys/time.h>
3232531Sminshall #include <sys/socket.h>
3332147Sminshall #include <signal.h>
3432531Sminshall #include <errno.h>
3538689Sborman #include <arpa/telnet.h>
3632147Sminshall 
3732381Sminshall #include "ring.h"
3832381Sminshall 
3932657Sminshall #include "fdset.h"
4032657Sminshall 
4132147Sminshall #include "defines.h"
4232147Sminshall #include "externs.h"
4332147Sminshall #include "types.h"
4432147Sminshall 
4532147Sminshall int
4632531Sminshall 	tout,			/* Output file descriptor */
4732531Sminshall 	tin,			/* Input file descriptor */
4836242Sminshall 	net;
4932147Sminshall 
5038689Sborman #ifndef	USE_TERMIO
5138689Sborman struct	tchars otc = { 0 }, ntc = { 0 };
5238689Sborman struct	ltchars oltc = { 0 }, nltc = { 0 };
5338689Sborman struct	sgttyb ottyb = { 0 }, nttyb = { 0 };
54*38909Sborman int	olmode = 0;
5532147Sminshall 
5638689Sborman #define	ISPEED	ottyb.sg_ispeed
5738689Sborman #define	OSPEED	ottyb.sg_ospeed
5838689Sborman #else	/* USE_TERMIO */
5938689Sborman struct	termio old_tc = { 0 };
6038689Sborman extern struct termio new_tc;
6138689Sborman 
6238689Sborman #define	ISPEED	(old_tc.c_cflag&CBAUD)
6338689Sborman #define	OSPEED	ISPEED
6438689Sborman #endif	/* USE_TERMIO */
6538689Sborman 
6632531Sminshall static fd_set ibits, obits, xbits;
6732147Sminshall 
6832531Sminshall 
6932531Sminshall init_sys()
7032531Sminshall {
7132531Sminshall     tout = fileno(stdout);
7232531Sminshall     tin = fileno(stdin);
7332531Sminshall     FD_ZERO(&ibits);
7432531Sminshall     FD_ZERO(&obits);
7532531Sminshall     FD_ZERO(&xbits);
7632531Sminshall 
7732531Sminshall     errno = 0;
7832531Sminshall }
7932531Sminshall 
8032531Sminshall 
8133286Sminshall TerminalWrite(buf, n)
8232147Sminshall char	*buf;
8332147Sminshall int	n;
8432147Sminshall {
8533286Sminshall     return write(tout, buf, n);
8632147Sminshall }
8732147Sminshall 
8833286Sminshall TerminalRead(buf, n)
8932147Sminshall char	*buf;
9032147Sminshall int	n;
9132147Sminshall {
9233286Sminshall     return read(tin, buf, n);
9332147Sminshall }
9432147Sminshall 
9532147Sminshall /*
9632147Sminshall  *
9732147Sminshall  */
9832147Sminshall 
9932147Sminshall int
10032553Sminshall TerminalAutoFlush()
10132147Sminshall {
10232147Sminshall #if	defined(LNOFLSH)
10332147Sminshall     int flush;
10432147Sminshall 
10532147Sminshall     ioctl(0, TIOCLGET, (char *)&flush);
10632147Sminshall     return !(flush&LNOFLSH);	/* if LNOFLSH, no autoflush */
10732147Sminshall #else	/* LNOFLSH */
10832147Sminshall     return 1;
10932147Sminshall #endif	/* LNOFLSH */
11032147Sminshall }
11132147Sminshall 
11238689Sborman #ifdef	KLUDGELINEMODE
11338689Sborman extern int kludgelinemode;
11438689Sborman #endif
11532147Sminshall /*
11632147Sminshall  * TerminalSpecialChars()
11732147Sminshall  *
11832147Sminshall  * Look at an input character to see if it is a special character
11932147Sminshall  * and decide what to do.
12032147Sminshall  *
12132147Sminshall  * Output:
12232147Sminshall  *
12332147Sminshall  *	0	Don't add this character.
12432147Sminshall  *	1	Do add this character
12532147Sminshall  */
12632147Sminshall 
12732147Sminshall int
12832553Sminshall TerminalSpecialChars(c)
12932147Sminshall int	c;
13032147Sminshall {
13132553Sminshall     void xmitAO(), xmitEL(), xmitEC(), intp(), sendbrk();
13232147Sminshall 
13338689Sborman     if (c == termIntChar) {
13432147Sminshall 	intp();
13532147Sminshall 	return 0;
13638689Sborman     } else if (c == termQuitChar) {
13738689Sborman #ifdef	KLUDGELINEMODE
13838689Sborman 	if (kludgelinemode)
13938689Sborman 	    sendbrk();
14038689Sborman 	else
14138689Sborman #endif
14238689Sborman 	    sendabort();
14332147Sminshall 	return 0;
14438689Sborman     } else if (c == termEofChar) {
14538689Sborman 	if (my_want_state_is_will(TELOPT_LINEMODE)) {
14638689Sborman 	    sendeof();
14738689Sborman 	    return 0;
14838689Sborman 	}
14938689Sborman 	return 1;
15038689Sborman     } else if (c == termSuspChar) {
15138689Sborman 	sendsusp();
15238689Sborman 	return(0);
15338689Sborman     } else if (c == termFlushChar) {
15432147Sminshall 	xmitAO();		/* Transmit Abort Output */
15532147Sminshall 	return 0;
15632147Sminshall     } else if (!MODE_LOCAL_CHARS(globalmode)) {
15738689Sborman 	if (c == termKillChar) {
15832147Sminshall 	    xmitEL();
15932147Sminshall 	    return 0;
16038689Sborman 	} else if (c == termEraseChar) {
16132147Sminshall 	    xmitEC();		/* Transmit Erase Character */
16232147Sminshall 	    return 0;
16332147Sminshall 	}
16432147Sminshall     }
16532147Sminshall     return 1;
16632147Sminshall }
16732147Sminshall 
16832147Sminshall 
16932147Sminshall /*
17032147Sminshall  * Flush output to the terminal
17132147Sminshall  */
17232147Sminshall 
17332147Sminshall void
17432553Sminshall TerminalFlushOutput()
17532147Sminshall {
17638689Sborman #ifndef	USE_TERMIO
17732147Sminshall     (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0);
17838689Sborman #else
17938689Sborman     (void) ioctl(fileno(stdout), TCFLSH, (char *) 0);
18038689Sborman #endif
18132147Sminshall }
18232147Sminshall 
18332147Sminshall void
18432553Sminshall TerminalSaveState()
18532147Sminshall {
18638689Sborman #ifndef	USE_TERMIO
18732147Sminshall     ioctl(0, TIOCGETP, (char *)&ottyb);
18832147Sminshall     ioctl(0, TIOCGETC, (char *)&otc);
18932147Sminshall     ioctl(0, TIOCGLTC, (char *)&oltc);
190*38909Sborman     ioctl(0, TIOCLGET, (char *)&olmode);
19132147Sminshall 
19232147Sminshall     ntc = otc;
19332147Sminshall     nltc = oltc;
19432147Sminshall     nttyb = ottyb;
19532254Sminshall 
19638689Sborman #else	/* USE_TERMIO */
19738689Sborman     ioctl(0, TCGETA, &old_tc);
19838689Sborman 
19938689Sborman     new_tc = old_tc;
20038689Sborman 
20138689Sborman     termFlushChar = 'O'&0x37;
20238689Sborman     termWerasChar = 'W'&0x37;
20338689Sborman     termRprntChar = 'R'&0x37;
20438689Sborman     termLiteralNextChar = 'V'&0x37;
20538689Sborman     termStartChar = 'Q'&0x37;
20638689Sborman     termStopChar = 'S'&0x37;
20738689Sborman #endif	/* USE_TERMIO */
20832147Sminshall }
20932147Sminshall 
21038689Sborman char *
21138689Sborman tcval(func)
21238689Sborman register int func;
21338689Sborman {
21438689Sborman     switch(func) {
21538689Sborman     case SLC_IP:	return(&termIntChar);
21638689Sborman     case SLC_ABORT:	return(&termQuitChar);
21738689Sborman     case SLC_EOF:	return(&termEofChar);
21838689Sborman     case SLC_EC:	return(&termEraseChar);
21938689Sborman     case SLC_EL:	return(&termKillChar);
22038689Sborman     case SLC_XON:	return(&termStartChar);
22138689Sborman     case SLC_XOFF:	return(&termStopChar);
22238689Sborman #ifndef	CRAY
22338689Sborman     case SLC_AO:	return(&termFlushChar);
22438689Sborman     case SLC_SUSP:	return(&termSuspChar);
22538689Sborman     case SLC_EW:	return(&termWerasChar);
22638689Sborman     case SLC_RP:	return(&termRprntChar);
22738689Sborman     case SLC_LNEXT:	return(&termLiteralNextChar);
22838810Sborman #endif	/* CRAY */
22938689Sborman 
23038689Sborman     case SLC_SYNCH:
23138689Sborman     case SLC_BRK:
23238689Sborman     case SLC_AYT:
23338689Sborman     case SLC_EOR:
23438689Sborman     case SLC_FORW1:
23538689Sborman     case SLC_FORW2:
23638689Sborman     default:
23738689Sborman 	return((char *)0);
23838689Sborman     }
23938689Sborman }
24038689Sborman 
24132147Sminshall void
24238689Sborman TerminalDefaultChars()
24338689Sborman {
24438689Sborman #ifndef	USE_TERMIO
24538689Sborman     ntc = otc;
24638689Sborman     nltc = oltc;
24738689Sborman     nttyb.sg_kill = ottyb.sg_kill;
24838689Sborman     nttyb.sg_erase = ottyb.sg_erase;
24938689Sborman #else	/* USE_TERMIO */
25038689Sborman     memcpy(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc));
25138689Sborman     termFlushChar = 'O'&0x37;
25238689Sborman     termWerasChar = 'W'&0x37;
25338689Sborman     termRprntChar = 'R'&0x37;
25438689Sborman     termLiteralNextChar = 'V'&0x37;
25538689Sborman     termStartChar = 'Q'&0x37;
25638689Sborman     termStopChar = 'S'&0x37;
25738689Sborman #endif	/* USE_TERMIO */
25838689Sborman }
25938689Sborman 
26038689Sborman void
26132553Sminshall TerminalRestoreState()
26232147Sminshall {
26332147Sminshall }
26432147Sminshall 
26532147Sminshall /*
26632147Sminshall  * TerminalNewMode - set up terminal to a specific mode.
26738689Sborman  *	MODE_ECHO: do local terminal echo
26838689Sborman  *	MODE_FLOW: do local flow control
26938689Sborman  *	MODE_TRAPSIG: do local mapping to TELNET IAC sequences
27038689Sborman  *	MODE_EDIT: do local line editing
27138689Sborman  *
27238689Sborman  *	Command mode:
27338689Sborman  *		MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG
27438689Sborman  *		local echo
27538689Sborman  *		local editing
27638689Sborman  *		local xon/xoff
27738689Sborman  *		local signal mapping
27838689Sborman  *
27938689Sborman  *	Linemode:
28038689Sborman  *		local/no editing
28138689Sborman  *	Both Linemode and Single Character mode:
28238689Sborman  *		local/remote echo
28338689Sborman  *		local/no xon/xoff
28438689Sborman  *		local/no signal mapping
28532147Sminshall  */
28632147Sminshall 
28732147Sminshall 
28832147Sminshall void
28933286Sminshall TerminalNewMode(f)
29032147Sminshall register int f;
29132147Sminshall {
29232147Sminshall     static int prevmode = 0;
29338689Sborman #ifndef	USE_TERMIO
29438689Sborman     struct tchars tc;
29538689Sborman     struct ltchars ltc;
29632147Sminshall     struct sgttyb sb;
297*38909Sborman     int lmode;
29838689Sborman #else	/* USE_TERMIO */
29938689Sborman     struct termio tmp_tc;
30038689Sborman #endif	/* USE_TERMIO */
30132147Sminshall     int onoff;
30232147Sminshall     int old;
30332147Sminshall 
30438689Sborman     globalmode = f&~MODE_FORCE;
30532147Sminshall     if (prevmode == f)
30632147Sminshall 	return;
30738689Sborman 
30838689Sborman     /*
30938689Sborman      * Write any outstanding data before switching modes
31038689Sborman      * ttyflush() returns 0 only when there is no more data
31138689Sborman      * left to write out, it returns -1 if it couldn't do
31238689Sborman      * anything at all, otherwise it returns 1 + the number
31338689Sborman      * of characters left to write.
31438689Sborman      */
31538689Sborman     old = ttyflush(SYNCHing|flushout);
31638689Sborman     if (old < 0 || old > 1) {
31738689Sborman #ifndef	USE_TERMIO
31838689Sborman 	ioctl(tin, TIOCGETP, (char *)&sb);
31938689Sborman #else	/* USE_TERMIO */
32038689Sborman 	ioctl(tin, TCGETA, (char *)&tmp_tc);
32138689Sborman #endif	/* USE_TERMIO */
32238689Sborman 	do {
32338689Sborman 	    /*
32438689Sborman 	     * Wait for data to drain, then flush again.
32538689Sborman 	     */
32638689Sborman #ifndef	USE_TERMIO
32738689Sborman 	    ioctl(tin, TIOCSETP, (char *)&sb);
32838689Sborman #else	/* USE_TERMIO */
32938689Sborman 	    ioctl(tin, TCSETAW, (char *)&tmp_tc);
33038689Sborman #endif	/* USE_TERMIO */
33138689Sborman 	    old = ttyflush(SYNCHing|flushout);
33238689Sborman 	} while (old < 0 || old > 1);
33338689Sborman     }
33438689Sborman 
33532147Sminshall     old = prevmode;
33638689Sborman     prevmode = f&~MODE_FORCE;
33738689Sborman #ifndef	USE_TERMIO
33832147Sminshall     sb = nttyb;
33938689Sborman     tc = ntc;
34038689Sborman     ltc = nltc;
341*38909Sborman     lmode = olmode;
34238689Sborman #else
34338689Sborman     tmp_tc = new_tc;
34438689Sborman #endif
34532147Sminshall 
34638689Sborman     if (f&MODE_ECHO) {
34738689Sborman #ifndef	USE_TERMIO
34838689Sborman 	sb.sg_flags |= ECHO;
34938689Sborman #else
35038689Sborman 	tmp_tc.c_lflag |= ECHO;
35138689Sborman 	tmp_tc.c_oflag |= ONLCR;
35238689Sborman 	tmp_tc.c_iflag |= ICRNL;
35338689Sborman #endif
35438689Sborman     } else {
35538689Sborman #ifndef	USE_TERMIO
35638689Sborman 	sb.sg_flags &= ~ECHO;
35738689Sborman #else
35838689Sborman 	tmp_tc.c_lflag &= ~ECHO;
35938689Sborman 	tmp_tc.c_oflag &= ~ONLCR;
36038689Sborman 	tmp_tc.c_iflag &= ~ICRNL;
36138689Sborman #endif
36238689Sborman     }
36332147Sminshall 
36438689Sborman     if ((f&MODE_FLOW) == 0) {
36538689Sborman #ifndef	USE_TERMIO
36638689Sborman 	tc.t_startc = -1;
36738689Sborman 	tc.t_stopc = -1;
36838689Sborman #else
36938689Sborman 	tmp_tc.c_iflag &= ~(IXANY|IXOFF|IXON);
37038689Sborman     } else {
37138689Sborman 	tmp_tc.c_iflag |= IXANY|IXOFF|IXON;
37238689Sborman #endif
37338689Sborman     }
37432147Sminshall 
37538689Sborman     if ((f&MODE_TRAPSIG) == 0) {
37638689Sborman #ifndef	USE_TERMIO
37738689Sborman 	tc.t_intrc = -1;
37838689Sborman 	tc.t_quitc = -1;
37938689Sborman 	tc.t_eofc = -1;
38038689Sborman 	ltc.t_suspc = -1;
38138689Sborman 	ltc.t_dsuspc = -1;
38238689Sborman #else
38338689Sborman 	tmp_tc.c_lflag &= ~ISIG;
38438689Sborman #endif
38538689Sborman 	localchars = 0;
38638689Sborman     } else {
38738689Sborman #ifdef	USE_TERMIO
38838689Sborman 	tmp_tc.c_lflag |= ISIG;
38938689Sborman #endif
39038689Sborman 	localchars = 1;
39138689Sborman     }
39238689Sborman 
39338689Sborman     if (f&MODE_EDIT) {
39438689Sborman #ifndef	USE_TERMIO
39538689Sborman 	sb.sg_flags &= ~CBREAK;
39638689Sborman 	sb.sg_flags |= CRMOD;
39738689Sborman #else
39838689Sborman 	tmp_tc.c_lflag |= ICANON;
39938689Sborman #endif
40038689Sborman     } else {
40138689Sborman #ifndef	USE_TERMIO
40238689Sborman 	sb.sg_flags |= CBREAK;
40338689Sborman 	if (f&MODE_ECHO)
40432147Sminshall 	    sb.sg_flags |= CRMOD;
40538689Sborman 	else
40638689Sborman 	    sb.sg_flags &= ~CRMOD;
40738689Sborman #else
40838689Sborman 	tmp_tc.c_lflag &= ~ICANON;
40938689Sborman 	tmp_tc.c_iflag &= ~ICRNL;
41038689Sborman 	tmp_tc.c_cc[VMIN] = 1;
41138689Sborman 	tmp_tc.c_cc[VTIME] = 0;
41238689Sborman #endif
41338689Sborman     }
41432147Sminshall 
41538689Sborman     if (f == -1) {
41638689Sborman 	onoff = 0;
41738689Sborman     } else {
418*38909Sborman #ifndef	USE_TERMIO
419*38909Sborman 	if (his_want_state_is_will(TELOPT_BINARY))
420*38909Sborman 		lmode |= LLITOUT;
421*38909Sborman 	else
422*38909Sborman 		lmode &= ~LLITOUT;
423*38909Sborman 	if (my_want_state_is_will(TELOPT_BINARY))
424*38909Sborman 		lmode |= LPASS8;
425*38909Sborman 	else
426*38909Sborman 		lmode &= ~LPASS8;
427*38909Sborman #else
428*38909Sborman 	if (my_want_state_is_will(TELOPT_BINARY))
429*38909Sborman 		tmp.tc.c_lflag &= ~ISTRIP;
430*38909Sborman 	else
431*38909Sborman 		tmp.tc.c_lflag |= ISTRIP;
432*38909Sborman #endif
43338689Sborman 	onoff = 1;
43432147Sminshall     }
43538689Sborman 
43638689Sborman #ifndef	USE_TERMIO
43738689Sborman     if (f != -1) {
43838689Sborman 	if (f&MODE_EDIT) {
43938689Sborman 	    void doescape();
44038689Sborman 
44138689Sborman 	    ltc.t_suspc = escape;
44238689Sborman 	    (void) signal(SIGTSTP, (int (*)())doescape);
44338689Sborman 	} else if (old&MODE_EDIT) {
44438689Sborman 	    (void) signal(SIGTSTP, SIG_DFL);
44538689Sborman 	    sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
44638689Sborman 	}
447*38909Sborman 	ioctl(tin, TIOCLSET, (char *)&lmode);
44838689Sborman 	ioctl(tin, TIOCSLTC, (char *)&ltc);
44938689Sborman 	ioctl(tin, TIOCSETC, (char *)&tc);
45038689Sborman 	ioctl(tin, TIOCSETP, (char *)&sb);
45138689Sborman     } else {
45238689Sborman 	(void) signal(SIGTSTP, SIG_DFL);
45338689Sborman 	sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
454*38909Sborman 	ioctl(tin, TIOCLSET, (char *)&lmode);
45538689Sborman 	ioctl(tin, TIOCSLTC, (char *)&oltc);
45638689Sborman 	ioctl(tin, TIOCSETC, (char *)&otc);
45738689Sborman 	ioctl(tin, TIOCSETP, (char *)&ottyb);
45838689Sborman     }
45932147Sminshall #if	(!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR))
46033286Sminshall     ioctl(tin, FIONBIO, (char *)&onoff);
46133286Sminshall     ioctl(tout, FIONBIO, (char *)&onoff);
46232147Sminshall #endif	/* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */
46332147Sminshall #if	defined(TN3270)
46436242Sminshall     if (noasynchtty == 0) {
46533286Sminshall 	ioctl(tin, FIOASYNC, (char *)&onoff);
46632147Sminshall     }
46732147Sminshall #endif	/* defined(TN3270) */
46838689Sborman #else	/* USE_TERMIO */
46938689Sborman     if (ioctl(tin, TCSETAW, &tmp_tc) < 0)
47038689Sborman 	ioctl(tin, TCSETA, &tmp_tc);
47138689Sborman #endif	/* USE_TERMIO */
47232147Sminshall }
47332147Sminshall 
47437219Sminshall void
47537219Sminshall TerminalSpeeds(ispeed, ospeed)
47637219Sminshall long *ispeed;
47737219Sminshall long *ospeed;
47837219Sminshall {
47937219Sminshall     /*
48037219Sminshall      * The order here is important.  The index of each speed needs to
48137219Sminshall      * correspond with the sgtty structure value for that speed.
48237219Sminshall      *
48337219Sminshall      * Additionally, the search algorithm assumes the table is in
48437219Sminshall      * ascending sequence.
48537219Sminshall      */
48637219Sminshall     static int ttyspeeds[] = {
48737219Sminshall 	    0, 50, 75, 110, 134, 150, 200, 300,
48837219Sminshall 	    600, 1200, 1800, 2400, 4800, 9600, 19200, 38400 };
48937219Sminshall #define NUMSPEEDS sizeof ttyspeeds/sizeof ttyspeeds[0]
49032147Sminshall 
49138689Sborman     if ((OSPEED < 0) || (OSPEED > NUMSPEEDS) ||
49238689Sborman 	(ISPEED < 0) || (ISPEED > NUMSPEEDS)) {
49337219Sminshall 	ExitString("Invalid terminal speed.");
49437219Sminshall 	/*NOTREACHED*/
49537219Sminshall     } else {
49638689Sborman 	*ispeed = ttyspeeds[ISPEED];
49738689Sborman 	*ospeed = ttyspeeds[OSPEED];
49837219Sminshall     }
49937219Sminshall }
50037219Sminshall 
50132147Sminshall int
50237219Sminshall TerminalWindowSize(rows, cols)
50337219Sminshall long *rows, *cols;
50437219Sminshall {
50538689Sborman #ifdef	TIOCGWINSZ
50637219Sminshall     struct winsize ws;
50737219Sminshall 
50838689Sborman     if (ioctl(fileno(stdin), TIOCGWINSZ, (char *)&ws) >= 0) {
50938689Sborman 	*rows = ws.ws_row;
51038689Sborman 	*cols = ws.ws_col;
51138689Sborman 	return 1;
51237219Sminshall     }
51338810Sborman #endif	/* TIOCGWINSZ */
51438689Sborman     return 0;
51537219Sminshall }
51637219Sminshall 
51737219Sminshall int
51835417Sminshall NetClose(fd)
51935417Sminshall int	fd;
52032147Sminshall {
52135417Sminshall     return close(fd);
52232147Sminshall }
52332147Sminshall 
52432147Sminshall 
52532147Sminshall void
52632553Sminshall NetNonblockingIO(fd, onoff)
52732147Sminshall int
52832147Sminshall 	fd,
52932147Sminshall 	onoff;
53032147Sminshall {
53132147Sminshall     ioctl(fd, FIONBIO, (char *)&onoff);
53232147Sminshall }
53332147Sminshall 
53434849Sminshall #if	defined(TN3270)
53532147Sminshall void
53632553Sminshall NetSigIO(fd, onoff)
53732147Sminshall int
53832147Sminshall 	fd,
53932147Sminshall 	onoff;
54032147Sminshall {
54132147Sminshall     ioctl(fd, FIOASYNC, (char *)&onoff);	/* hear about input */
54232147Sminshall }
54332147Sminshall 
54432147Sminshall void
54532553Sminshall NetSetPgrp(fd)
54632147Sminshall int fd;
54732147Sminshall {
54832147Sminshall     int myPid;
54932147Sminshall 
55032147Sminshall     myPid = getpid();
55136274Sminshall     fcntl(fd, F_SETOWN, myPid);
55232147Sminshall }
55334849Sminshall #endif	/*defined(TN3270)*/
55432553Sminshall 
55532553Sminshall /*
55632553Sminshall  * Various signal handling routines.
55732553Sminshall  */
55832147Sminshall 
55933286Sminshall static void
56032553Sminshall deadpeer()
56132553Sminshall {
56232553Sminshall 	setcommandmode();
56332553Sminshall 	longjmp(peerdied, -1);
56432553Sminshall }
56532147Sminshall 
56633286Sminshall static void
56732553Sminshall intr()
56832553Sminshall {
56932553Sminshall     if (localchars) {
57032553Sminshall 	intp();
57132553Sminshall 	return;
57232553Sminshall     }
57332553Sminshall     setcommandmode();
57432553Sminshall     longjmp(toplevel, -1);
57532553Sminshall }
57632553Sminshall 
57733286Sminshall static void
57832553Sminshall intr2()
57932553Sminshall {
58032553Sminshall     if (localchars) {
58138689Sborman #ifdef	KLUDGELINEMODE
58238689Sborman 	if (kludgelinemode)
58338689Sborman 	    sendbrk();
58438689Sborman 	else
58538689Sborman #endif
58638689Sborman 	    sendabort();
58732553Sminshall 	return;
58832553Sminshall     }
58932553Sminshall }
59032553Sminshall 
59133286Sminshall static void
59237219Sminshall sendwin()
59337219Sminshall {
59437219Sminshall     if (connected) {
59537219Sminshall 	sendnaws();
59637219Sminshall     }
59737219Sminshall }
59837219Sminshall 
59937219Sminshall static void
60032553Sminshall doescape()
60132553Sminshall {
60238689Sborman     command(0, 0, 0);
60332553Sminshall }
60432553Sminshall 
60532553Sminshall void
60632531Sminshall sys_telnet_init()
60732531Sminshall {
60838689Sborman #ifndef	CRAY
60934849Sminshall     (void) signal(SIGINT, (int (*)())intr);
61034849Sminshall     (void) signal(SIGQUIT, (int (*)())intr2);
61134849Sminshall     (void) signal(SIGPIPE, (int (*)())deadpeer);
61238689Sborman #else
61338689Sborman     (void) signal(SIGINT, (void (*)())intr);
61438689Sborman     (void) signal(SIGQUIT, (void (*)())intr2);
61538689Sborman     (void) signal(SIGPIPE, (void (*)())deadpeer);
61638689Sborman #endif
61738689Sborman #ifdef	SIGWINCH
61837219Sminshall     (void) signal(SIGWINCH, (int (*)())sendwin);
61938689Sborman #endif
62032553Sminshall 
62138689Sborman     setconnmode(0);
62232531Sminshall 
62332531Sminshall     NetNonblockingIO(net, 1);
62432531Sminshall 
62532531Sminshall #if	defined(TN3270)
62636242Sminshall     if (noasynchnet == 0) {			/* DBX can't handle! */
62732531Sminshall 	NetSigIO(net, 1);
62832531Sminshall 	NetSetPgrp(net);
62932531Sminshall     }
63032531Sminshall #endif	/* defined(TN3270) */
63132531Sminshall 
63232531Sminshall #if	defined(SO_OOBINLINE)
63334849Sminshall     if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) {
63434849Sminshall 	perror("SetSockOpt");
63534849Sminshall     }
63632531Sminshall #endif	/* defined(SO_OOBINLINE) */
63732531Sminshall }
63832531Sminshall 
63932531Sminshall /*
64032531Sminshall  * Process rings -
64132531Sminshall  *
64232531Sminshall  *	This routine tries to fill up/empty our various rings.
64332531Sminshall  *
64432531Sminshall  *	The parameter specifies whether this is a poll operation,
64532531Sminshall  *	or a block-until-something-happens operation.
64632531Sminshall  *
64732531Sminshall  *	The return value is 1 if something happened, 0 if not.
64832531Sminshall  */
64932531Sminshall 
65032531Sminshall int
65132531Sminshall process_rings(netin, netout, netex, ttyin, ttyout, poll)
65232531Sminshall int poll;		/* If 0, then block until something to do */
65332531Sminshall {
65432531Sminshall     register int c;
65532531Sminshall 		/* One wants to be a bit careful about setting returnValue
65632531Sminshall 		 * to one, since a one implies we did some useful work,
65732531Sminshall 		 * and therefore probably won't be called to block next
65832531Sminshall 		 * time (TN3270 mode only).
65932531Sminshall 		 */
66032531Sminshall     int returnValue = 0;
66132531Sminshall     static struct timeval TimeValue = { 0 };
66232531Sminshall 
66332531Sminshall     if (netout) {
66432531Sminshall 	FD_SET(net, &obits);
66532531Sminshall     }
66632531Sminshall     if (ttyout) {
66732531Sminshall 	FD_SET(tout, &obits);
66832531Sminshall     }
66932531Sminshall #if	defined(TN3270)
67032531Sminshall     if (ttyin) {
67132531Sminshall 	FD_SET(tin, &ibits);
67232531Sminshall     }
67332531Sminshall #else	/* defined(TN3270) */
67432531Sminshall     if (ttyin) {
67532531Sminshall 	FD_SET(tin, &ibits);
67632531Sminshall     }
67732531Sminshall #endif	/* defined(TN3270) */
67832531Sminshall #if	defined(TN3270)
67932531Sminshall     if (netin) {
68032531Sminshall 	FD_SET(net, &ibits);
68132531Sminshall     }
68232531Sminshall #   else /* !defined(TN3270) */
68332531Sminshall     if (netin) {
68432531Sminshall 	FD_SET(net, &ibits);
68532531Sminshall     }
68632531Sminshall #   endif /* !defined(TN3270) */
68732531Sminshall     if (netex) {
68832531Sminshall 	FD_SET(net, &xbits);
68932531Sminshall     }
69032531Sminshall     if ((c = select(16, &ibits, &obits, &xbits,
69132531Sminshall 			(poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) {
69232531Sminshall 	if (c == -1) {
69332531Sminshall 		    /*
69432531Sminshall 		     * we can get EINTR if we are in line mode,
69532531Sminshall 		     * and the user does an escape (TSTP), or
69632531Sminshall 		     * some other signal generator.
69732531Sminshall 		     */
69832531Sminshall 	    if (errno == EINTR) {
69932531Sminshall 		return 0;
70032531Sminshall 	    }
70132531Sminshall #	    if defined(TN3270)
70232531Sminshall 		    /*
70332531Sminshall 		     * we can get EBADF if we were in transparent
70432531Sminshall 		     * mode, and the transcom process died.
70532531Sminshall 		    */
70632531Sminshall 	    if (errno == EBADF) {
70732531Sminshall 			/*
70832531Sminshall 			 * zero the bits (even though kernel does it)
70932531Sminshall 			 * to make sure we are selecting on the right
71032531Sminshall 			 * ones.
71132531Sminshall 			*/
71232531Sminshall 		FD_ZERO(&ibits);
71332531Sminshall 		FD_ZERO(&obits);
71432531Sminshall 		FD_ZERO(&xbits);
71532531Sminshall 		return 0;
71632531Sminshall 	    }
71732531Sminshall #	    endif /* defined(TN3270) */
71832531Sminshall 		    /* I don't like this, does it ever happen? */
71932531Sminshall 	    printf("sleep(5) from telnet, after select\r\n");
72032531Sminshall 	    sleep(5);
72132531Sminshall 	}
72232531Sminshall 	return 0;
72332531Sminshall     }
72432531Sminshall 
72532531Sminshall     /*
72632531Sminshall      * Any urgent data?
72732531Sminshall      */
72832531Sminshall     if (FD_ISSET(net, &xbits)) {
72932531Sminshall 	FD_CLR(net, &xbits);
73032531Sminshall 	SYNCHing = 1;
73132531Sminshall 	ttyflush(1);	/* flush already enqueued data */
73232531Sminshall     }
73332531Sminshall 
73432531Sminshall     /*
73532531Sminshall      * Something to read from the network...
73632531Sminshall      */
73732531Sminshall     if (FD_ISSET(net, &ibits)) {
73832531Sminshall 	int canread;
73932531Sminshall 
74032531Sminshall 	FD_CLR(net, &ibits);
74132531Sminshall 	canread = ring_empty_consecutive(&netiring);
74232531Sminshall #if	!defined(SO_OOBINLINE)
74332531Sminshall 	    /*
74432531Sminshall 	     * In 4.2 (and some early 4.3) systems, the
74532531Sminshall 	     * OOB indication and data handling in the kernel
74632531Sminshall 	     * is such that if two separate TCP Urgent requests
74732531Sminshall 	     * come in, one byte of TCP data will be overlaid.
74832531Sminshall 	     * This is fatal for Telnet, but we try to live
74932531Sminshall 	     * with it.
75032531Sminshall 	     *
75132531Sminshall 	     * In addition, in 4.2 (and...), a special protocol
75232531Sminshall 	     * is needed to pick up the TCP Urgent data in
75332531Sminshall 	     * the correct sequence.
75432531Sminshall 	     *
75532531Sminshall 	     * What we do is:  if we think we are in urgent
75632531Sminshall 	     * mode, we look to see if we are "at the mark".
75732531Sminshall 	     * If we are, we do an OOB receive.  If we run
75832531Sminshall 	     * this twice, we will do the OOB receive twice,
75932531Sminshall 	     * but the second will fail, since the second
76032531Sminshall 	     * time we were "at the mark", but there wasn't
76132531Sminshall 	     * any data there (the kernel doesn't reset
76232531Sminshall 	     * "at the mark" until we do a normal read).
76332531Sminshall 	     * Once we've read the OOB data, we go ahead
76432531Sminshall 	     * and do normal reads.
76532531Sminshall 	     *
76632531Sminshall 	     * There is also another problem, which is that
76732531Sminshall 	     * since the OOB byte we read doesn't put us
76832531Sminshall 	     * out of OOB state, and since that byte is most
76932531Sminshall 	     * likely the TELNET DM (data mark), we would
77032531Sminshall 	     * stay in the TELNET SYNCH (SYNCHing) state.
77132531Sminshall 	     * So, clocks to the rescue.  If we've "just"
77232531Sminshall 	     * received a DM, then we test for the
77332531Sminshall 	     * presence of OOB data when the receive OOB
77432531Sminshall 	     * fails (and AFTER we did the normal mode read
77532531Sminshall 	     * to clear "at the mark").
77632531Sminshall 	     */
77732531Sminshall 	if (SYNCHing) {
77832531Sminshall 	    int atmark;
77932531Sminshall 
78032531Sminshall 	    ioctl(net, SIOCATMARK, (char *)&atmark);
78132531Sminshall 	    if (atmark) {
78232531Sminshall 		c = recv(net, netiring.supply, canread, MSG_OOB);
78332531Sminshall 		if ((c == -1) && (errno == EINVAL)) {
78432531Sminshall 		    c = recv(net, netiring.supply, canread, 0);
78532531Sminshall 		    if (clocks.didnetreceive < clocks.gotDM) {
78632531Sminshall 			SYNCHing = stilloob(net);
78732531Sminshall 		    }
78832531Sminshall 		}
78932531Sminshall 	    } else {
79032531Sminshall 		c = recv(net, netiring.supply, canread, 0);
79132531Sminshall 	    }
79232531Sminshall 	} else {
79332531Sminshall 	    c = recv(net, netiring.supply, canread, 0);
79432531Sminshall 	}
79532531Sminshall 	settimer(didnetreceive);
79632531Sminshall #else	/* !defined(SO_OOBINLINE) */
79732531Sminshall 	c = recv(net, netiring.supply, canread, 0);
79832531Sminshall #endif	/* !defined(SO_OOBINLINE) */
79932531Sminshall 	if (c < 0 && errno == EWOULDBLOCK) {
80032531Sminshall 	    c = 0;
80132531Sminshall 	} else if (c <= 0) {
80232531Sminshall 	    return -1;
80332531Sminshall 	}
80432531Sminshall 	if (netdata) {
80532531Sminshall 	    Dump('<', netiring.supply, c);
80632531Sminshall 	}
80732667Sminshall 	if (c)
80832667Sminshall 	    ring_supplied(&netiring, c);
80932531Sminshall 	returnValue = 1;
81032531Sminshall     }
81132531Sminshall 
81232531Sminshall     /*
81332531Sminshall      * Something to read from the tty...
81432531Sminshall      */
81532531Sminshall     if (FD_ISSET(tin, &ibits)) {
81632531Sminshall 	FD_CLR(tin, &ibits);
81733286Sminshall 	c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring));
81832531Sminshall 	if (c < 0 && errno == EWOULDBLOCK) {
81932531Sminshall 	    c = 0;
82032531Sminshall 	} else {
82132531Sminshall 	    /* EOF detection for line mode!!!! */
82233281Sminshall 	    if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && isatty(tin)) {
82332531Sminshall 			/* must be an EOF... */
82432531Sminshall 		*ttyiring.supply = termEofChar;
82532531Sminshall 		c = 1;
82632531Sminshall 	    }
82732531Sminshall 	    if (c <= 0) {
82832531Sminshall 		return -1;
82932531Sminshall 	    }
83038208Sminshall 	    if (termdata) {
83138208Sminshall 		Dump('<', ttyiring.supply, c);
83238208Sminshall 	    }
83332667Sminshall 	    ring_supplied(&ttyiring, c);
83432531Sminshall 	}
83532531Sminshall 	returnValue = 1;		/* did something useful */
83632531Sminshall     }
83732531Sminshall 
83832531Sminshall     if (FD_ISSET(net, &obits)) {
83932531Sminshall 	FD_CLR(net, &obits);
84032531Sminshall 	returnValue |= netflush();
84132531Sminshall     }
84232531Sminshall     if (FD_ISSET(tout, &obits)) {
84332531Sminshall 	FD_CLR(tout, &obits);
84438689Sborman 	returnValue |= (ttyflush(SYNCHing|flushout) > 0);
84532531Sminshall     }
84632531Sminshall 
84732531Sminshall     return returnValue;
84832531Sminshall }
84932531Sminshall #endif	/* defined(unix) */
850