xref: /csrg-svn/usr.bin/telnet/telnet.c (revision 38689)
133685Sbostic /*
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  */
1711758Ssam 
1821580Sdist #ifndef lint
19*38689Sborman static char sccsid[] = "@(#)telnet.c	5.41 (Berkeley) 08/21/89";
2033685Sbostic #endif /* not lint */
2121580Sdist 
229217Ssam #include <sys/types.h>
239217Ssam 
2432377Sminshall #if	defined(unix)
2533804Sminshall #include <signal.h>
2632377Sminshall /* By the way, we need to include curses.h before telnet.h since,
2732377Sminshall  * among other things, telnet.h #defines 'DO', which is a variable
2832377Sminshall  * declared in curses.h.
2932377Sminshall  */
3032377Sminshall #include <curses.h>
3132377Sminshall #endif	/* defined(unix) */
3232377Sminshall 
3312212Ssam #include <arpa/telnet.h>
3432377Sminshall 
3532377Sminshall #if	defined(unix)
3627186Sminshall #include <strings.h>
3732377Sminshall #else	/* defined(unix) */
3832377Sminshall #include <string.h>
3932377Sminshall #endif	/* defined(unix) */
409217Ssam 
4132381Sminshall #include "ring.h"
4232381Sminshall 
4332377Sminshall #include "defines.h"
4432377Sminshall #include "externs.h"
4532377Sminshall #include "types.h"
4632377Sminshall #include "general.h"
4727178Sminshall 
4827178Sminshall 
4927228Sminshall #define	strip(x)	((x)&0x7f)
506000Sroot 
5127088Sminshall 
5232377Sminshall static char	subbuffer[SUBBUFSIZE],
5332377Sminshall 		*subpointer, *subend;	 /* buffer for sub-options */
5427676Sminshall #define	SB_CLEAR()	subpointer = subbuffer;
5527676Sminshall #define	SB_TERM()	subend = subpointer;
5627676Sminshall #define	SB_ACCUM(c)	if (subpointer < (subbuffer+sizeof subbuffer)) { \
5727676Sminshall 				*subpointer++ = (c); \
5827676Sminshall 			}
5927676Sminshall 
6037226Sminshall char	options[256];		/* The combined options */
61*38689Sborman char	do_dont_resp[256];
62*38689Sborman char	will_wont_resp[256];
636000Sroot 
6432377Sminshall int
6532377Sminshall 	connected,
6632377Sminshall 	showoptions,
6732377Sminshall 	In3270,		/* Are we in 3270 mode? */
6832377Sminshall 	ISend,		/* trying to send network data in */
6932377Sminshall 	debug = 0,
7032377Sminshall 	crmod,
7132377Sminshall 	netdata,	/* Print out network data flow */
7232377Sminshall 	crlf,		/* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
7334848Sminshall #if	defined(TN3270)
7436241Sminshall 	noasynchtty = 0,/* User specified "-noasynch" on command line */
7536241Sminshall 	noasynchnet = 0,/* User specified "-noasynch" on command line */
7632377Sminshall 	askedSGA = 0,	/* We have talked about suppress go ahead */
7734848Sminshall #endif	/* defined(TN3270) */
7833286Sminshall 	telnetport,
7932531Sminshall 	SYNCHing,	/* we are in TELNET SYNCH mode */
8032531Sminshall 	flushout,	/* flush output */
8132531Sminshall 	autoflush = 0,	/* flush output when interrupting? */
8232531Sminshall 	autosynch,	/* send interrupt characters with SYNCH? */
8337219Sminshall 	localflow,	/* we handle flow control locally */
8432531Sminshall 	localchars,	/* we recognize interrupt/quit */
8532531Sminshall 	donelclchars,	/* the user has set "localchars" */
8632531Sminshall 	donebinarytoggle,	/* the user has put us in binary */
8732531Sminshall 	dontlecho,	/* do we suppress local echoing right now? */
8832531Sminshall 	globalmode;
8927088Sminshall 
9032377Sminshall #define	CONTROL(x)	((x)&0x1f)		/* CTRL(x) is not portable */
916000Sroot 
9232377Sminshall char
9332377Sminshall 	*prompt = 0,
9432377Sminshall 	escape,
9532377Sminshall 	echoc;
9627186Sminshall 
9727186Sminshall /*
986000Sroot  * Telnet receiver states for fsm
996000Sroot  */
1006000Sroot #define	TS_DATA		0
1016000Sroot #define	TS_IAC		1
1026000Sroot #define	TS_WILL		2
1036000Sroot #define	TS_WONT		3
1046000Sroot #define	TS_DO		4
1056000Sroot #define	TS_DONT		5
10627021Sminshall #define	TS_CR		6
10727676Sminshall #define	TS_SB		7		/* sub-option collection */
10827676Sminshall #define	TS_SE		8		/* looking for sub-option end */
1096000Sroot 
11032377Sminshall static int	telrcv_state;
1116000Sroot 
11232377Sminshall jmp_buf	toplevel = { 0 };
11332377Sminshall jmp_buf	peerdied;
1146000Sroot 
11532377Sminshall int	flushline;
11627021Sminshall 
117*38689Sborman #ifdef	KLUDGELINEMODE
118*38689Sborman int	kludgelinemode = 1;
119*38689Sborman #endif
120*38689Sborman 
12132377Sminshall /*
12232377Sminshall  * The following are some clocks used to decide how to interpret
12332377Sminshall  * the relationship between various variables.
12432377Sminshall  */
1256000Sroot 
12632377Sminshall Clocks clocks;
12732377Sminshall 
128*38689Sborman #ifdef	notdef
12932377Sminshall Modelist modelist[] = {
13032377Sminshall 	{ "telnet command mode", COMMAND_LINE },
13132377Sminshall 	{ "character-at-a-time mode", 0 },
13232377Sminshall 	{ "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS },
13332377Sminshall 	{ "line-by-line mode (remote echo)", LINE | LOCAL_CHARS },
13432377Sminshall 	{ "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS },
13532377Sminshall 	{ "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS },
13632377Sminshall 	{ "3270 mode", 0 },
13732377Sminshall };
138*38689Sborman #endif
1396000Sroot 
14032377Sminshall 
14132377Sminshall /*
14232377Sminshall  * Initialize telnet environment.
14332377Sminshall  */
1446000Sroot 
14532377Sminshall init_telnet()
14632377Sminshall {
14732377Sminshall     SB_CLEAR();
14837226Sminshall     ClearArray(options);
1496000Sroot 
15037219Sminshall     connected = In3270 = ISend = localflow = donebinarytoggle = 0;
1516000Sroot 
15232377Sminshall     SYNCHing = 0;
1536000Sroot 
15432377Sminshall     /* Don't change NetTrace */
1556000Sroot 
15632377Sminshall     escape = CONTROL(']');
15732377Sminshall     echoc = CONTROL('E');
1586000Sroot 
15932377Sminshall     flushline = 1;
16032377Sminshall     telrcv_state = TS_DATA;
16132377Sminshall }
16232554Sminshall 
1636000Sroot 
16432554Sminshall #include <varargs.h>
1656000Sroot 
16634848Sminshall /*VARARGS*/
16732554Sminshall static void
16832554Sminshall printring(va_alist)
16932554Sminshall va_dcl
17032554Sminshall {
17132554Sminshall     va_list ap;
17232554Sminshall     char buffer[100];		/* where things go */
17332554Sminshall     char *ptr;
17432554Sminshall     char *format;
17532554Sminshall     char *string;
17632554Sminshall     Ring *ring;
17732554Sminshall     int i;
17832554Sminshall 
17932554Sminshall     va_start(ap);
18032554Sminshall 
18132554Sminshall     ring = va_arg(ap, Ring *);
18232554Sminshall     format = va_arg(ap, char *);
18332554Sminshall     ptr = buffer;
18432554Sminshall 
18532554Sminshall     while ((i = *format++) != 0) {
18632554Sminshall 	if (i == '%') {
18732554Sminshall 	    i = *format++;
18832554Sminshall 	    switch (i) {
18932554Sminshall 	    case 'c':
19032554Sminshall 		*ptr++ = va_arg(ap, int);
19132554Sminshall 		break;
19232554Sminshall 	    case 's':
19332554Sminshall 		string = va_arg(ap, char *);
19432554Sminshall 		ring_supply_data(ring, buffer, ptr-buffer);
19532554Sminshall 		ring_supply_data(ring, string, strlen(string));
19632554Sminshall 		ptr = buffer;
19732554Sminshall 		break;
19832554Sminshall 	    case 0:
19932554Sminshall 		ExitString("printring: trailing %%.\n", 1);
20032554Sminshall 		/*NOTREACHED*/
20132554Sminshall 	    default:
20232554Sminshall 		ExitString("printring: unknown format character.\n", 1);
20332554Sminshall 		/*NOTREACHED*/
20432554Sminshall 	    }
20532554Sminshall 	} else {
20632554Sminshall 	    *ptr++ = i;
20732554Sminshall 	}
20832554Sminshall     }
20932554Sminshall     ring_supply_data(ring, buffer, ptr-buffer);
21032554Sminshall }
21132554Sminshall 
21237226Sminshall /*
21337226Sminshall  * These routines are in charge of sending option negotiations
21437226Sminshall  * to the other side.
21537226Sminshall  *
21637226Sminshall  * The basic idea is that we send the negotiation if either side
21737226Sminshall  * is in disagreement as to what the current state should be.
21837226Sminshall  */
21932554Sminshall 
220*38689Sborman send_do(c, init)
221*38689Sborman register int c, init;
2226000Sroot {
223*38689Sborman     if (init) {
224*38689Sborman 	if (((do_dont_resp[c] == 0) && my_state_is_do(c)) ||
225*38689Sborman 				my_want_state_is_do(c))
226*38689Sborman 	    return;
227*38689Sborman 	set_my_want_state_do(c);
228*38689Sborman 	do_dont_resp[c]++;
22937226Sminshall     }
230*38689Sborman     NET2ADD(IAC, DO);
231*38689Sborman     NETADD(c);
232*38689Sborman     printoption("SENT", "do", c);
23337226Sminshall }
23437226Sminshall 
23537226Sminshall void
236*38689Sborman send_dont(c, init)
237*38689Sborman register int c, init;
23837226Sminshall {
239*38689Sborman     if (init) {
240*38689Sborman 	if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) ||
241*38689Sborman 				my_want_state_is_dont(c))
242*38689Sborman 	    return;
243*38689Sborman 	set_my_want_state_dont(c);
244*38689Sborman 	do_dont_resp[c]++;
24537226Sminshall     }
246*38689Sborman     NET2ADD(IAC, DONT);
247*38689Sborman     NETADD(c);
248*38689Sborman     printoption("SENT", "dont", c);
24937226Sminshall }
25037226Sminshall 
25137226Sminshall void
252*38689Sborman send_will(c, init)
253*38689Sborman register int c, init;
25437226Sminshall {
255*38689Sborman     if (init) {
256*38689Sborman 	if (((will_wont_resp[c] == 0) && my_state_is_will(c)) ||
257*38689Sborman 				my_want_state_is_will(c))
258*38689Sborman 	    return;
259*38689Sborman 	set_my_want_state_will(c);
260*38689Sborman 	will_wont_resp[c]++;
26137226Sminshall     }
262*38689Sborman     NET2ADD(IAC, WILL);
263*38689Sborman     NETADD(c);
264*38689Sborman     printoption("SENT", "will", c);
26537226Sminshall }
26637226Sminshall 
26737226Sminshall void
268*38689Sborman send_wont(c, init)
269*38689Sborman register int c, init;
27037226Sminshall {
271*38689Sborman     if (init) {
272*38689Sborman 	if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) ||
273*38689Sborman 				my_want_state_is_wont(c))
274*38689Sborman 	    return;
275*38689Sborman 	set_my_want_state_wont(c);
276*38689Sborman 	will_wont_resp[c]++;
27737226Sminshall     }
278*38689Sborman     NET2ADD(IAC, WONT);
279*38689Sborman     NETADD(c);
280*38689Sborman     printoption("SENT", "wont", c);
28137226Sminshall }
28237226Sminshall 
28337226Sminshall 
28437226Sminshall void
28537226Sminshall willoption(option)
28637226Sminshall 	int option;
28737226Sminshall {
2886000Sroot 	char *fmt;
289*38689Sborman 	int new_state_ok = 0;
2906000Sroot 
291*38689Sborman 	if (do_dont_resp[option]) {
292*38689Sborman 	    --do_dont_resp[option];
293*38689Sborman 	    if (do_dont_resp[option] && my_state_is_do(option))
294*38689Sborman 		--do_dont_resp[option];
295*38689Sborman 	}
29637226Sminshall 
297*38689Sborman 	if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) {
2986000Sroot 
299*38689Sborman 	    switch (option) {
300*38689Sborman 
301*38689Sborman 	    case TELOPT_ECHO:
302*38689Sborman #	    if defined(TN3270)
303*38689Sborman 		/*
304*38689Sborman 		 * The following is a pain in the rear-end.
305*38689Sborman 		 * Various IBM servers (some versions of Wiscnet,
306*38689Sborman 		 * possibly Fibronics/Spartacus, and who knows who
307*38689Sborman 		 * else) will NOT allow us to send "DO SGA" too early
308*38689Sborman 		 * in the setup proceedings.  On the other hand,
309*38689Sborman 		 * 4.2 servers (telnetd) won't set SGA correctly.
310*38689Sborman 		 * So, we are stuck.  Empirically (but, based on
311*38689Sborman 		 * a VERY small sample), the IBM servers don't send
312*38689Sborman 		 * out anything about ECHO, so we postpone our sending
313*38689Sborman 		 * "DO SGA" until we see "WILL ECHO" (which 4.2 servers
314*38689Sborman 		 * DO send).
315*38689Sborman 		  */
316*38689Sborman 		{
317*38689Sborman 		    if (askedSGA == 0) {
318*38689Sborman 			askedSGA = 1;
319*38689Sborman 			if (my_want_state_is_dont(TELOPT_SGA))
320*38689Sborman 			    send_do(TELOPT_SGA, 1);
32132377Sminshall 		    }
32232377Sminshall 		}
323*38689Sborman 		    /* Fall through */
324*38689Sborman 	    case TELOPT_EOR:
325*38689Sborman 	    case TELOPT_BINARY:
326*38689Sborman #endif	    /* defined(TN3270) */
327*38689Sborman 	    case TELOPT_SGA:
32827110Sminshall 		settimer(modenegotiated);
329*38689Sborman 		new_state_ok = 1;
3306000Sroot 		break;
3316000Sroot 
332*38689Sborman 	    case TELOPT_TM:
333*38689Sborman 		if (flushout)
334*38689Sborman 		    flushout = 0;
335*38689Sborman 		/*
336*38689Sborman 		 * Special case for TM.  If we get back a WILL,
337*38689Sborman 		 * pretend we got back a WONT.
338*38689Sborman 		 */
339*38689Sborman 		set_my_want_state_dont(option);
340*38689Sborman 		set_my_state_dont(option);
34127110Sminshall 		return;			/* Never reply to TM will's/wont's */
3426000Sroot 
343*38689Sborman 	    case TELOPT_LINEMODE:
344*38689Sborman 	    default:
3456000Sroot 		break;
346*38689Sborman 	    }
347*38689Sborman 
348*38689Sborman 	    if (new_state_ok) {
349*38689Sborman 		set_my_want_state_do(option);
350*38689Sborman 		send_do(option, 0);
351*38689Sborman 		setconnmode(0);		/* possibly set new tty mode */
352*38689Sborman 	    } else {
353*38689Sborman 		do_dont_resp[option]++;
354*38689Sborman 		send_dont(option, 0);
355*38689Sborman 	    }
3566000Sroot 	}
357*38689Sborman 	set_my_state_do(option);
3586000Sroot }
3596000Sroot 
36032377Sminshall void
36137226Sminshall wontoption(option)
36237226Sminshall 	int option;
3636000Sroot {
3646000Sroot 	char *fmt;
3656000Sroot 
366*38689Sborman 	if (do_dont_resp[option]) {
367*38689Sborman 	    --do_dont_resp[option];
368*38689Sborman 	    if (do_dont_resp[option] && my_state_is_dont(option))
369*38689Sborman 		--do_dont_resp[option];
370*38689Sborman 	}
37137226Sminshall 
372*38689Sborman 	if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) {
3736000Sroot 
374*38689Sborman 	    switch (option) {
375*38689Sborman 
376*38689Sborman #ifdef	KLUDGELINEMODE
377*38689Sborman 	    case TELOPT_SGA:
378*38689Sborman 		if (!kludgelinemode)
379*38689Sborman 		    break;
380*38689Sborman 		/* FALL THROUGH */
381*38689Sborman #endif
382*38689Sborman 	    case TELOPT_ECHO:
38327110Sminshall 		settimer(modenegotiated);
3846000Sroot 		break;
3856000Sroot 
386*38689Sborman 	    case TELOPT_TM:
387*38689Sborman 		if (flushout)
388*38689Sborman 		    flushout = 0;
389*38689Sborman 		set_my_want_state_dont(option);
390*38689Sborman 		set_my_state_dont(option);
39127110Sminshall 		return;		/* Never reply to TM will's/wont's */
39227110Sminshall 
393*38689Sborman 	    default:
394*38689Sborman 		break;
395*38689Sborman 	    }
396*38689Sborman 	    set_my_want_state_dont(option);
397*38689Sborman 	    send_dont(option, 0);
398*38689Sborman 	    setconnmode(0);			/* Set new tty mode */
399*38689Sborman 	} else if (option == TELOPT_TM) {
400*38689Sborman 	    /*
401*38689Sborman 	     * Special case for TM.
402*38689Sborman 	     */
403*38689Sborman 	    if (flushout)
404*38689Sborman 		flushout = 0;
405*38689Sborman 	    set_my_want_state_dont(option);
4066000Sroot 	}
407*38689Sborman 	set_my_state_dont(option);
4086000Sroot }
4096000Sroot 
41032377Sminshall static void
4116000Sroot dooption(option)
4126000Sroot 	int option;
4136000Sroot {
4146000Sroot 	char *fmt;
415*38689Sborman 	int new_state_ok = 0;
4166000Sroot 
417*38689Sborman 	if (will_wont_resp[option]) {
418*38689Sborman 	    --will_wont_resp[option];
419*38689Sborman 	    if (will_wont_resp[option] && my_state_is_will(option))
420*38689Sborman 		--will_wont_resp[option];
421*38689Sborman 	}
42237226Sminshall 
423*38689Sborman 	if (will_wont_resp[option] == 0) {
424*38689Sborman 	  if (my_want_state_is_wont(option)) {
4256000Sroot 
426*38689Sborman 	    switch (option) {
427*38689Sborman 
428*38689Sborman 	    case TELOPT_TM:
429*38689Sborman 		/*
430*38689Sborman 		 * Special case for TM.  We send a WILL, but pretend
431*38689Sborman 		 * we sent WONT.
432*38689Sborman 		 */
433*38689Sborman 		send_will(option, 0);
434*38689Sborman 		set_my_want_state_wont(TELOPT_TM);
435*38689Sborman 		set_my_state_wont(TELOPT_TM);
436*38689Sborman 		return;
437*38689Sborman 
43832377Sminshall #	if defined(TN3270)
439*38689Sborman 	    case TELOPT_EOR:		/* end of record */
440*38689Sborman 	    case TELOPT_BINARY:		/* binary mode */
44132377Sminshall #	endif	/* defined(TN3270) */
442*38689Sborman 	    case TELOPT_NAWS:		/* window size */
443*38689Sborman 	    case TELOPT_TSPEED:		/* terminal speed */
444*38689Sborman 	    case TELOPT_LFLOW:		/* local flow control */
445*38689Sborman 	    case TELOPT_TTYPE:		/* terminal type option */
446*38689Sborman 	    case TELOPT_SGA:		/* no big deal */
447*38689Sborman 		new_state_ok = 1;
4486000Sroot 		break;
4496000Sroot 
450*38689Sborman 	    case TELOPT_LINEMODE:
451*38689Sborman #ifdef	KLUDGELINEMODE
452*38689Sborman 		kludgelinemode = 0;
453*38689Sborman #endif
454*38689Sborman 		set_my_want_state_will(TELOPT_LINEMODE);
455*38689Sborman 		send_will(option, 0);
456*38689Sborman 		set_my_state_will(TELOPT_LINEMODE);
457*38689Sborman 		slc_init();
458*38689Sborman 		return;
459*38689Sborman 
460*38689Sborman 	    case TELOPT_ECHO:		/* We're never going to echo... */
461*38689Sborman 	    default:
4626000Sroot 		break;
463*38689Sborman 	    }
464*38689Sborman 
465*38689Sborman 	    if (new_state_ok) {
466*38689Sborman 		set_my_want_state_will(option);
467*38689Sborman 		send_will(option, 0);
468*38689Sborman 	    } else {
469*38689Sborman 		will_wont_resp[option]++;
470*38689Sborman 		send_wont(option, 0);
471*38689Sborman 	    }
472*38689Sborman 	  } else {
473*38689Sborman 	    /*
474*38689Sborman 	     * Handle options that need more things done after the
475*38689Sborman 	     * other side has acknowledged the option.
476*38689Sborman 	     */
477*38689Sborman 	    switch (option) {
478*38689Sborman 	    case TELOPT_LINEMODE:
479*38689Sborman #ifdef	KLUDGELINEMODE
480*38689Sborman 		kludgelinemode = 0;
481*38689Sborman #endif
482*38689Sborman 		set_my_state_will(option);
483*38689Sborman 		slc_init();
484*38689Sborman 		return;
485*38689Sborman 	    }
486*38689Sborman 	  }
4876000Sroot 	}
488*38689Sborman 	set_my_state_will(option);
4896000Sroot }
49027676Sminshall 
491*38689Sborman static void
492*38689Sborman dontoption(option)
493*38689Sborman 	int option;
494*38689Sborman {
495*38689Sborman 
496*38689Sborman 	if (will_wont_resp[option]) {
497*38689Sborman 	    --will_wont_resp[option];
498*38689Sborman 	    if (will_wont_resp[option] && my_state_is_wont(option))
499*38689Sborman 		--will_wont_resp[option];
500*38689Sborman 	}
501*38689Sborman 
502*38689Sborman 	if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) {
503*38689Sborman 	    /* we always accept a DONT */
504*38689Sborman 	    set_my_want_state_wont(option);
505*38689Sborman 	    send_wont(option, 0);
506*38689Sborman 	}
507*38689Sborman 	set_my_state_wont(option);
508*38689Sborman }
509*38689Sborman 
51027676Sminshall /*
51127676Sminshall  * suboption()
51227676Sminshall  *
51327676Sminshall  *	Look at the sub-option buffer, and try to be helpful to the other
51427676Sminshall  * side.
51527676Sminshall  *
51627676Sminshall  *	Currently we recognize:
51727676Sminshall  *
51827676Sminshall  *		Terminal type, send request.
51937219Sminshall  *		Terminal speed (send request).
52037219Sminshall  *		Local flow control (is request).
521*38689Sborman  *		Linemode
52227676Sminshall  */
52327676Sminshall 
524*38689Sborman static char tty1[] = { IAC, SB, TELOPT_TTYPE, TELQUAL_IS, 0 };
525*38689Sborman static char tty2[] = { IAC, SE, 0 };
526*38689Sborman 
52732377Sminshall static void
52827676Sminshall suboption()
52927676Sminshall {
530*38689Sborman     printsub('<', subbuffer, subend-subbuffer+2);
53127676Sminshall     switch (subbuffer[0]&0xff) {
53227676Sminshall     case TELOPT_TTYPE:
533*38689Sborman 	if (my_want_state_is_wont(TELOPT_TTYPE))
534*38689Sborman 	    return;
53527676Sminshall 	if ((subbuffer[1]&0xff) != TELQUAL_SEND) {
53627676Sminshall 	    ;
53727676Sminshall 	} else {
53827676Sminshall 	    char *name;
53932377Sminshall 	    extern char *getenv();
54027676Sminshall 	    int len;
54127676Sminshall 
54232377Sminshall #if	defined(TN3270)
54332531Sminshall 	    if (tn3270_ttype()) {
54432377Sminshall 		return;
54532377Sminshall 	    }
54632377Sminshall #endif	/* defined(TN3270) */
54727676Sminshall 	    name = getenv("TERM");
54827676Sminshall 	    if ((name == 0) || ((len = strlen(name)) > 40)) {
54927676Sminshall 		name = "UNKNOWN";
55033492Sminshall 		len = strlen(name);
55127676Sminshall 	    }
55227676Sminshall 	    if ((len + 4+2) < NETROOM()) {
55337226Sminshall 		char temp[50];
55437226Sminshall 
555*38689Sborman 		strcpy(temp, tty1);
556*38689Sborman 		strcpy(&temp[4], name);
557*38689Sborman 		upcase(&temp[4]);
558*38689Sborman 		strcpy(&temp[4+len], tty2);
559*38689Sborman 		len += 6;
560*38689Sborman 		ring_supply_data(&netoring, temp, len);
561*38689Sborman 		printsub('>', temp+2, len-2);
56232377Sminshall 	    } else {
56337226Sminshall 		ExitString("No room in buffer for terminal type.\n", 1);
56432377Sminshall 		/*NOTREACHED*/
56527676Sminshall 	    }
56627676Sminshall 	}
56737219Sminshall 	break;
56837219Sminshall     case TELOPT_TSPEED:
569*38689Sborman 	if (my_want_state_is_wont(TELOPT_TSPEED))
570*38689Sborman 	    return;
57137219Sminshall 	if ((subbuffer[1]&0xff) == TELQUAL_SEND) {
572*38689Sborman 	    long ospeed,ispeed;
573*38689Sborman 	    char temp[50];
57437219Sminshall 	    int len;
57527676Sminshall 
57637219Sminshall 	    TerminalSpeeds(&ispeed, &ospeed);
57737219Sminshall 
578*38689Sborman 	    sprintf(temp, "%c%c%c%c%d,%d%c%c", IAC, SB, TELOPT_TSPEED,
579*38689Sborman 		    TELQUAL_IS, ospeed, ispeed, IAC, SE);
580*38689Sborman 	    len = strlen(temp+4) + 4;	/* temp[3] is 0 ... */
58137219Sminshall 
582*38689Sborman 	    if (len < NETROOM()) {
583*38689Sborman 		ring_supply_data(&netoring, temp, len);
584*38689Sborman 		printsub('>', temp+2, len - 2);
58537219Sminshall 	    }
58637219Sminshall 	}
58737219Sminshall 	break;
58837219Sminshall     case TELOPT_LFLOW:
589*38689Sborman 	if (my_want_state_is_wont(TELOPT_LFLOW))
590*38689Sborman 	    return;
59137219Sminshall 	if ((subbuffer[1]&0xff) == 1) {
59237219Sminshall 	    localflow = 1;
59337219Sminshall 	} else if ((subbuffer[1]&0xff) == 0) {
59437219Sminshall 	    localflow = 0;
59537219Sminshall 	}
59637219Sminshall 	setcommandmode();
597*38689Sborman 	setconnmode(0);
59837219Sminshall 	break;
599*38689Sborman 
600*38689Sborman     case TELOPT_LINEMODE:
601*38689Sborman 	if (my_want_state_is_wont(TELOPT_LINEMODE))
602*38689Sborman 	    return;
603*38689Sborman 	switch (subbuffer[1]&0xff) {
604*38689Sborman 	case WILL:
605*38689Sborman 	    lm_will(&subbuffer[2], subend - &subbuffer[2]);
606*38689Sborman 	    break;
607*38689Sborman 	case WONT:
608*38689Sborman 	    lm_wont(&subbuffer[2], subend - &subbuffer[2]);
609*38689Sborman 	    break;
610*38689Sborman 	case DO:
611*38689Sborman 	    lm_do(&subbuffer[2], subend - &subbuffer[2]);
612*38689Sborman 	    break;
613*38689Sborman 	case DONT:
614*38689Sborman 	    lm_dont(&subbuffer[2], subend - &subbuffer[2]);
615*38689Sborman 	    break;
616*38689Sborman 	case LM_SLC:
617*38689Sborman 	    slc(&subbuffer[2], subend - &subbuffer[2]);
618*38689Sborman 	    break;
619*38689Sborman 	case LM_MODE:
620*38689Sborman 	    lm_mode(&subbuffer[2], subend - &subbuffer[2], 0);
621*38689Sborman 	    break;
622*38689Sborman 	default:
623*38689Sborman 		break;
624*38689Sborman 	}
625*38689Sborman 	break;
62627676Sminshall     default:
62727676Sminshall 	break;
62827676Sminshall     }
62927676Sminshall }
630*38689Sborman 
631*38689Sborman static char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE };
632*38689Sborman 
633*38689Sborman lm_will(cmd, len)
634*38689Sborman char *cmd;
635*38689Sborman {
636*38689Sborman     switch(cmd[0]) {
637*38689Sborman     case LM_FORWARDMASK:	/* We shouldn't ever get this... */
638*38689Sborman     default:
639*38689Sborman 	str_lm[3] = DONT;
640*38689Sborman 	str_lm[4] = cmd[0];
641*38689Sborman 	if (NETROOM() > sizeof(str_lm)) {
642*38689Sborman 	    ring_supply_data(&netoring, str_lm, sizeof(str_lm));
643*38689Sborman 	    printsub('>', &str_lm[2], sizeof(str_lm)-2);
644*38689Sborman 	}
645*38689Sborman /*@*/	else printf("lm_will: not enough room in buffer\n");
646*38689Sborman 	break;
647*38689Sborman     }
648*38689Sborman }
649*38689Sborman 
650*38689Sborman lm_wont(cmd, len)
651*38689Sborman char *cmd;
652*38689Sborman {
653*38689Sborman     switch(cmd[0]) {
654*38689Sborman     case LM_FORWARDMASK:	/* We shouldn't ever get this... */
655*38689Sborman     default:
656*38689Sborman 	/* We are always DONT, so don't respond */
657*38689Sborman 	return;
658*38689Sborman     }
659*38689Sborman }
660*38689Sborman 
661*38689Sborman int linemode;
662*38689Sborman 
663*38689Sborman lm_do(cmd, len)
664*38689Sborman char *cmd;
665*38689Sborman {
666*38689Sborman     switch(cmd[0]) {
667*38689Sborman     case LM_FORWARDMASK:
668*38689Sborman     default:
669*38689Sborman 	str_lm[3] = WONT;
670*38689Sborman 	str_lm[4] = cmd[0];
671*38689Sborman 	if (NETROOM() > sizeof(str_lm)) {
672*38689Sborman 	    ring_supply_data(&netoring, str_lm, sizeof(str_lm));
673*38689Sborman 	    printsub('>', &str_lm[2], sizeof(str_lm)-2);
674*38689Sborman 	}
675*38689Sborman /*@*/	else printf("lm_do: not enough room in buffer\n");
676*38689Sborman 	break;
677*38689Sborman     }
678*38689Sborman }
679*38689Sborman 
680*38689Sborman lm_dont(cmd, len)
681*38689Sborman char *cmd;
682*38689Sborman {
683*38689Sborman     switch(cmd[0]) {
684*38689Sborman     case LM_FORWARDMASK:
685*38689Sborman     default:
686*38689Sborman 	/* we are always WONT, so don't respond */
687*38689Sborman 	break;
688*38689Sborman     }
689*38689Sborman }
690*38689Sborman 
691*38689Sborman static char str_lm_mode[] = { IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE };
692*38689Sborman 
693*38689Sborman lm_mode(cmd, len, init)
694*38689Sborman char *cmd;
695*38689Sborman int len, init;
696*38689Sborman {
697*38689Sborman 	if (len != 1)
698*38689Sborman 		return;
699*38689Sborman 	if ((linemode&(MODE_EDIT|MODE_TRAPSIG)) == *cmd)
700*38689Sborman 		return;
701*38689Sborman 	if (*cmd&MODE_ACK)
702*38689Sborman 		return;
703*38689Sborman 	linemode = (*cmd&(MODE_EDIT|MODE_TRAPSIG));
704*38689Sborman 	str_lm_mode[4] = linemode;
705*38689Sborman 	if (!init)
706*38689Sborman 	    str_lm_mode[4] |= MODE_ACK;
707*38689Sborman 	if (NETROOM() > sizeof(str_lm_mode)) {
708*38689Sborman 	    ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode));
709*38689Sborman 	    printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2);
710*38689Sborman 	}
711*38689Sborman /*@*/	else printf("lm_mode: not enough room in buffer\n");
712*38689Sborman 	setconnmode(0);	/* set changed mode */
713*38689Sborman }
714*38689Sborman 
71532377Sminshall 
71627088Sminshall 
717*38689Sborman /*
718*38689Sborman  * slc()
719*38689Sborman  * Handle special character suboption of LINEMODE.
720*38689Sborman  */
721*38689Sborman 
722*38689Sborman struct spc {
723*38689Sborman 	char val;
724*38689Sborman 	char *valp;
725*38689Sborman 	char flags;	/* Current flags & level */
726*38689Sborman 	char mylevel;	/* Maximum level & flags */
727*38689Sborman } spc_data[NSLC+1];
728*38689Sborman 
729*38689Sborman #define SLC_IMPORT	0
730*38689Sborman #define	SLC_EXPORT	1
731*38689Sborman #define SLC_RVALUE	2
732*38689Sborman static int slc_mode = SLC_EXPORT;
733*38689Sborman 
734*38689Sborman slc_init()
735*38689Sborman {
736*38689Sborman 	register struct spc *spcp;
737*38689Sborman 	extern char *tcval();
738*38689Sborman 
739*38689Sborman 	localchars = 1;
740*38689Sborman 	for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) {
741*38689Sborman 		spcp->val = 0;
742*38689Sborman 		spcp->valp = 0;
743*38689Sborman 		spcp->flags = spcp->mylevel = SLC_NOSUPPORT;
744*38689Sborman 	}
745*38689Sborman 
746*38689Sborman #define	initfunc(func, flags) { \
747*38689Sborman 					spcp = &spc_data[func]; \
748*38689Sborman 					if (spcp->valp = tcval(func)) { \
749*38689Sborman 					    spcp->val = *spcp->valp; \
750*38689Sborman 					    spcp->mylevel = SLC_VARIABLE|flags; \
751*38689Sborman 					} else { \
752*38689Sborman 					    spcp->val = 0; \
753*38689Sborman 					    spcp->mylevel = SLC_DEFAULT; \
754*38689Sborman 					} \
755*38689Sborman 				    }
756*38689Sborman 
757*38689Sborman 	initfunc(SLC_SYNCH, 0);
758*38689Sborman 	/* No BRK */
759*38689Sborman 	initfunc(SLC_AO, 0);
760*38689Sborman 	initfunc(SLC_AYT, 0);
761*38689Sborman 	/* No EOR */
762*38689Sborman 	initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT);
763*38689Sborman 	initfunc(SLC_EOF, 0);
764*38689Sborman #ifndef	CRAY
765*38689Sborman 	initfunc(SLC_SUSP, SLC_FLUSHIN);
766*38689Sborman #endif
767*38689Sborman 	initfunc(SLC_EC, 0);
768*38689Sborman 	initfunc(SLC_EL, 0);
769*38689Sborman #ifndef	CRAY
770*38689Sborman 	initfunc(SLC_EW, 0);
771*38689Sborman 	initfunc(SLC_RP, 0);
772*38689Sborman 	initfunc(SLC_LNEXT, 0);
773*38689Sborman #endif
774*38689Sborman 	initfunc(SLC_XON, 0);
775*38689Sborman 	initfunc(SLC_XOFF, 0);
776*38689Sborman #ifdef	CRAY
777*38689Sborman 	spc_data[SLC_XON].mylevel = SLC_CANTCHANGE;
778*38689Sborman 	spc_data[SLC_XOFF].mylevel = SLC_CANTCHANGE;
779*38689Sborman #endif
780*38689Sborman 	/* No FORW1 */
781*38689Sborman 	/* No FORW2 */
782*38689Sborman 
783*38689Sborman 	initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT);
784*38689Sborman #undef	initfunc
785*38689Sborman 
786*38689Sborman 	if (slc_mode == SLC_EXPORT)
787*38689Sborman 		slc_export();
788*38689Sborman 	else
789*38689Sborman 		slc_import(1);
790*38689Sborman 
791*38689Sborman }
792*38689Sborman 
793*38689Sborman slcstate()
794*38689Sborman {
795*38689Sborman     printf("Special characters are %s values\n",
796*38689Sborman 		slc_mode == SLC_IMPORT ? "remote default" :
797*38689Sborman 		slc_mode == SLC_EXPORT ? "local" :
798*38689Sborman 					 "remote");
799*38689Sborman }
800*38689Sborman 
801*38689Sborman slc_mode_export()
802*38689Sborman {
803*38689Sborman     slc_mode = SLC_EXPORT;
804*38689Sborman     if (my_state_is_will(TELOPT_LINEMODE))
805*38689Sborman 	slc_export();
806*38689Sborman }
807*38689Sborman 
808*38689Sborman slc_mode_import(def)
809*38689Sborman {
810*38689Sborman     slc_mode = def ? SLC_IMPORT : SLC_RVALUE;
811*38689Sborman     if (my_state_is_will(TELOPT_LINEMODE))
812*38689Sborman 	slc_import(def);
813*38689Sborman }
814*38689Sborman 
815*38689Sborman char slc_import_val[] = {
816*38689Sborman 	IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE
817*38689Sborman };
818*38689Sborman char slc_import_def[] = {
819*38689Sborman 	IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE
820*38689Sborman };
821*38689Sborman 
822*38689Sborman slc_import(def)
823*38689Sborman int def;
824*38689Sborman {
825*38689Sborman     if (NETROOM() > sizeof(slc_import_val)) {
826*38689Sborman 	if (def) {
827*38689Sborman 	    ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def));
828*38689Sborman 	    printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2);
829*38689Sborman 	} else {
830*38689Sborman 	    ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val));
831*38689Sborman 	    printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2);
832*38689Sborman 	}
833*38689Sborman     }
834*38689Sborman /*@*/ else printf("slc_import: not enough room\n");
835*38689Sborman }
836*38689Sborman 
837*38689Sborman slc_export()
838*38689Sborman {
839*38689Sborman     register struct spc *spcp;
840*38689Sborman 
841*38689Sborman     TerminalDefaultChars();
842*38689Sborman 
843*38689Sborman     slc_start_reply();
844*38689Sborman     for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
845*38689Sborman 	if (spcp->mylevel != SLC_NOSUPPORT) {
846*38689Sborman 	    spcp->flags = spcp->mylevel;
847*38689Sborman 	    if (spcp->valp)
848*38689Sborman 		spcp->val = *spcp->valp;
849*38689Sborman 	    slc_add_reply(spcp - spc_data, spcp->mylevel, spcp->val);
850*38689Sborman 	}
851*38689Sborman     }
852*38689Sborman     slc_end_reply();
853*38689Sborman     if (slc_update())
854*38689Sborman 	setconnmode(1);	/* set the  new character values */
855*38689Sborman }
856*38689Sborman 
857*38689Sborman slc(cp, len)
858*38689Sborman register char *cp;
859*38689Sborman int len;
860*38689Sborman {
861*38689Sborman 	register struct spc *spcp;
862*38689Sborman 	register int func,level;
863*38689Sborman 
864*38689Sborman 	slc_start_reply();
865*38689Sborman 
866*38689Sborman 	for (; len >= 3; len -=3, cp +=3) {
867*38689Sborman 
868*38689Sborman 		func = cp[SLC_FUNC];
869*38689Sborman 
870*38689Sborman 		if (func == 0) {
871*38689Sborman 			/*
872*38689Sborman 			 * Client side: always ignore 0 function.
873*38689Sborman 			 */
874*38689Sborman 			continue;
875*38689Sborman 		}
876*38689Sborman 		if (func > NSLC) {
877*38689Sborman 			if (cp[SLC_FLAGS] & SLC_LEVELBITS != SLC_NOSUPPORT)
878*38689Sborman 				slc_add_reply(func, SLC_NOSUPPORT, 0);
879*38689Sborman 			continue;
880*38689Sborman 		}
881*38689Sborman 
882*38689Sborman 		spcp = &spc_data[func];
883*38689Sborman 
884*38689Sborman 		level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK);
885*38689Sborman 
886*38689Sborman 		if ((cp[SLC_VALUE] == spcp->val) &&
887*38689Sborman 		    ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) {
888*38689Sborman 			continue;
889*38689Sborman 		}
890*38689Sborman 
891*38689Sborman 		if (level == (SLC_DEFAULT|SLC_ACK)) {
892*38689Sborman 			/*
893*38689Sborman 			 * This is an error condition, the SLC_ACK
894*38689Sborman 			 * bit should never be set for the SLC_DEFAULT
895*38689Sborman 			 * level.  Our best guess to recover is to
896*38689Sborman 			 * ignore the SLC_ACK bit.
897*38689Sborman 			 */
898*38689Sborman 			cp[SLC_FLAGS] &= ~SLC_ACK;
899*38689Sborman 		}
900*38689Sborman 
901*38689Sborman 		if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) {
902*38689Sborman 			spcp->val = cp[SLC_VALUE];
903*38689Sborman 			spcp->flags = cp[SLC_FLAGS];	/* include SLC_ACK */
904*38689Sborman 			continue;
905*38689Sborman 		}
906*38689Sborman 
907*38689Sborman 		level &= ~SLC_ACK;
908*38689Sborman 
909*38689Sborman 		if (level <= (spcp->mylevel&SLC_LEVELBITS)) {
910*38689Sborman 			spcp->flags = cp[SLC_FLAGS]|SLC_ACK;
911*38689Sborman 			spcp->val = cp[SLC_VALUE];
912*38689Sborman 		}
913*38689Sborman 		if (level == SLC_DEFAULT) {
914*38689Sborman 			if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT)
915*38689Sborman 				spcp->flags = spcp->mylevel;
916*38689Sborman 			else
917*38689Sborman 				spcp->flags = SLC_NOSUPPORT;
918*38689Sborman 		}
919*38689Sborman 		slc_add_reply(func, spcp->flags, spcp->val);
920*38689Sborman 	}
921*38689Sborman 	slc_end_reply();
922*38689Sborman 	if (slc_update())
923*38689Sborman 		setconnmode(1);	/* set the  new character values */
924*38689Sborman }
925*38689Sborman 
926*38689Sborman slc_check()
927*38689Sborman {
928*38689Sborman     register struct spc *spcp;
929*38689Sborman 
930*38689Sborman     slc_start_reply();
931*38689Sborman     for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
932*38689Sborman 	if (spcp->valp && spcp->val != *spcp->valp) {
933*38689Sborman 	    spcp->val = *spcp->valp;
934*38689Sborman 	    slc_add_reply(spcp - spc_data, spcp->mylevel, spcp->val);
935*38689Sborman 	}
936*38689Sborman     }
937*38689Sborman     slc_end_reply();
938*38689Sborman     setconnmode(1);
939*38689Sborman }
940*38689Sborman 
941*38689Sborman 
942*38689Sborman unsigned char slc_reply[128];
943*38689Sborman unsigned char *slc_replyp;
944*38689Sborman slc_start_reply()
945*38689Sborman {
946*38689Sborman 	slc_replyp = slc_reply;
947*38689Sborman 	*slc_replyp++ = IAC;
948*38689Sborman 	*slc_replyp++ = SB;
949*38689Sborman 	*slc_replyp++ = TELOPT_LINEMODE;
950*38689Sborman 	*slc_replyp++ = LM_SLC;
951*38689Sborman }
952*38689Sborman 
953*38689Sborman slc_add_reply(func, flags, value)
954*38689Sborman char func;
955*38689Sborman char flags;
956*38689Sborman char value;
957*38689Sborman {
958*38689Sborman 	if ((*slc_replyp++ = func) == IAC)
959*38689Sborman 		*slc_replyp++ = IAC;
960*38689Sborman 	if ((*slc_replyp++ = flags) == IAC)
961*38689Sborman 		*slc_replyp++ = IAC;
962*38689Sborman 	if ((*slc_replyp++ = value) == IAC)
963*38689Sborman 		*slc_replyp++ = IAC;
964*38689Sborman }
965*38689Sborman 
966*38689Sborman slc_end_reply()
967*38689Sborman {
968*38689Sborman     register char *cp;
969*38689Sborman     register int len;
970*38689Sborman 
971*38689Sborman     *slc_replyp++ = IAC;
972*38689Sborman     *slc_replyp++ = SE;
973*38689Sborman     len = slc_replyp - slc_reply;
974*38689Sborman     if (len <= 6)
975*38689Sborman 	return;
976*38689Sborman     if (NETROOM() > len) {
977*38689Sborman 	ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply);
978*38689Sborman 	printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2);
979*38689Sborman     }
980*38689Sborman /*@*/else printf("slc_end_reply: not enough room\n");
981*38689Sborman }
982*38689Sborman 
983*38689Sborman slc_update()
984*38689Sborman {
985*38689Sborman 	register struct spc *spcp;
986*38689Sborman 	int need_update = 0;
987*38689Sborman 
988*38689Sborman 	for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
989*38689Sborman 		if (!(spcp->flags&SLC_ACK))
990*38689Sborman 			continue;
991*38689Sborman 		spcp->flags &= ~SLC_ACK;
992*38689Sborman 		if (spcp->valp && (*spcp->valp != spcp->val)) {
993*38689Sborman 			*spcp->valp = spcp->val;
994*38689Sborman 			need_update = 1;
995*38689Sborman 		}
996*38689Sborman 	}
997*38689Sborman 	return(need_update);
998*38689Sborman }
999*38689Sborman 
1000*38689Sborman 
1001*38689Sborman 
100233804Sminshall int
100332377Sminshall telrcv()
100427110Sminshall {
100532377Sminshall     register int c;
100632385Sminshall     register int scc;
100732385Sminshall     register char *sbp;
100832385Sminshall     int count;
100932385Sminshall     int returnValue = 0;
101027088Sminshall 
101132385Sminshall     scc = 0;
101232385Sminshall     count = 0;
101332385Sminshall     while (TTYROOM() > 2) {
101432385Sminshall 	if (scc == 0) {
101532385Sminshall 	    if (count) {
101632528Sminshall 		ring_consumed(&netiring, count);
101732385Sminshall 		returnValue = 1;
101832385Sminshall 		count = 0;
101932385Sminshall 	    }
102032528Sminshall 	    sbp = netiring.consume;
102132528Sminshall 	    scc = ring_full_consecutive(&netiring);
102232385Sminshall 	    if (scc == 0) {
102332385Sminshall 		/* No more data coming in */
102432385Sminshall 		break;
102532385Sminshall 	    }
102632385Sminshall 	}
102732385Sminshall 
102832385Sminshall 	c = *sbp++ & 0xff, scc--; count++;
102932385Sminshall 
103032377Sminshall 	switch (telrcv_state) {
103127110Sminshall 
103232377Sminshall 	case TS_CR:
103332377Sminshall 	    telrcv_state = TS_DATA;
103435518Sminshall 	    if (c == '\0') {
103535518Sminshall 		break;	/* Ignore \0 after CR */
1036*38689Sborman 	    } else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) {
103735518Sminshall 		TTYADD(c);
103835518Sminshall 		break;
103932377Sminshall 	    }
104035518Sminshall 	    /* Else, fall through */
104127088Sminshall 
104232377Sminshall 	case TS_DATA:
104332377Sminshall 	    if (c == IAC) {
104432377Sminshall 		telrcv_state = TS_IAC;
104533804Sminshall 		break;
104632377Sminshall 	    }
104732377Sminshall #	    if defined(TN3270)
104832377Sminshall 	    if (In3270) {
104932377Sminshall 		*Ifrontp++ = c;
105032385Sminshall 		while (scc > 0) {
105132385Sminshall 		    c = *sbp++ & 0377, scc--; count++;
105232377Sminshall 		    if (c == IAC) {
105332377Sminshall 			telrcv_state = TS_IAC;
105434304Sminshall 			break;
105532377Sminshall 		    }
105632377Sminshall 		    *Ifrontp++ = c;
105732377Sminshall 		}
105832377Sminshall 	    } else
105932377Sminshall #	    endif /* defined(TN3270) */
106035518Sminshall 		    /*
106135518Sminshall 		     * The 'crmod' hack (see following) is needed
106235518Sminshall 		     * since we can't * set CRMOD on output only.
106335518Sminshall 		     * Machines like MULTICS like to send \r without
106435518Sminshall 		     * \n; since we must turn off CRMOD to get proper
106535518Sminshall 		     * input, the mapping is done here (sigh).
106635518Sminshall 		     */
1067*38689Sborman 	    if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) {
106835518Sminshall 		if (scc > 0) {
106935518Sminshall 		    c = *sbp&0xff;
107035518Sminshall 		    if (c == 0) {
107135518Sminshall 			sbp++, scc--; count++;
107235518Sminshall 			/* a "true" CR */
107332377Sminshall 			TTYADD('\r');
1074*38689Sborman 		    } else if (my_want_state_is_dont(TELOPT_ECHO) &&
107535518Sminshall 					(c == '\n')) {
107635518Sminshall 			sbp++, scc--; count++;
107732377Sminshall 			TTYADD('\n');
107835518Sminshall 		    } else {
107935518Sminshall 			TTYADD('\r');
108035518Sminshall 			if (crmod) {
108135518Sminshall 				TTYADD('\n');
108232377Sminshall 			}
108332377Sminshall 		    }
108435518Sminshall 		} else {
108535518Sminshall 		    telrcv_state = TS_CR;
108635518Sminshall 		    TTYADD('\r');
108735518Sminshall 		    if (crmod) {
108835518Sminshall 			    TTYADD('\n');
108935518Sminshall 		    }
109032377Sminshall 		}
109132377Sminshall 	    } else {
109232377Sminshall 		TTYADD(c);
109332377Sminshall 	    }
109432377Sminshall 	    continue;
109527088Sminshall 
109632377Sminshall 	case TS_IAC:
1097*38689Sborman process_iac:
109832377Sminshall 	    switch (c) {
109932377Sminshall 
110032377Sminshall 	    case WILL:
110132377Sminshall 		telrcv_state = TS_WILL;
110232377Sminshall 		continue;
110327261Sminshall 
110432377Sminshall 	    case WONT:
110532377Sminshall 		telrcv_state = TS_WONT;
110632377Sminshall 		continue;
110727261Sminshall 
110832377Sminshall 	    case DO:
110932377Sminshall 		telrcv_state = TS_DO;
111032377Sminshall 		continue;
111127261Sminshall 
111232377Sminshall 	    case DONT:
111332377Sminshall 		telrcv_state = TS_DONT;
111432377Sminshall 		continue;
111527261Sminshall 
111632377Sminshall 	    case DM:
111732377Sminshall 		    /*
111832377Sminshall 		     * We may have missed an urgent notification,
111932377Sminshall 		     * so make sure we flush whatever is in the
112032377Sminshall 		     * buffer currently.
112132377Sminshall 		     */
112232377Sminshall 		SYNCHing = 1;
112332377Sminshall 		ttyflush(1);
112432554Sminshall 		SYNCHing = stilloob();
112532377Sminshall 		settimer(gotDM);
112632377Sminshall 		break;
112727088Sminshall 
112832377Sminshall 	    case NOP:
112932377Sminshall 	    case GA:
113032377Sminshall 		break;
113127088Sminshall 
113232377Sminshall 	    case SB:
113332377Sminshall 		SB_CLEAR();
113432377Sminshall 		telrcv_state = TS_SB;
1135*38689Sborman 		printoption("RCVD", "IAC", SB);
113632377Sminshall 		continue;
113727261Sminshall 
113832377Sminshall #	    if defined(TN3270)
113932377Sminshall 	    case EOR:
114032377Sminshall 		if (In3270) {
114132377Sminshall 		    Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1);
114232377Sminshall 		    if (Ibackp == Ifrontp) {
114332377Sminshall 			Ibackp = Ifrontp = Ibuf;
114432377Sminshall 			ISend = 0;	/* should have been! */
114532377Sminshall 		    } else {
114632377Sminshall 			ISend = 1;
114727088Sminshall 		    }
114827088Sminshall 		}
114927088Sminshall 		break;
115032377Sminshall #	    endif /* defined(TN3270) */
115132377Sminshall 
115232377Sminshall 	    case IAC:
115332377Sminshall #	    if !defined(TN3270)
115432377Sminshall 		TTYADD(IAC);
115532377Sminshall #	    else /* !defined(TN3270) */
115632377Sminshall 		if (In3270) {
115732377Sminshall 		    *Ifrontp++ = IAC;
115832377Sminshall 		} else {
115932377Sminshall 		    TTYADD(IAC);
116032377Sminshall 		}
116132377Sminshall #	    endif /* !defined(TN3270) */
116227088Sminshall 		break;
116332377Sminshall 
116427088Sminshall 	    default:
116527088Sminshall 		break;
116627088Sminshall 	    }
116732377Sminshall 	    telrcv_state = TS_DATA;
116832377Sminshall 	    continue;
116927088Sminshall 
117032377Sminshall 	case TS_WILL:
117137226Sminshall 	    printoption("RCVD", "will", c);
1172*38689Sborman 	    willoption(c);
117332377Sminshall 	    SetIn3270();
117432377Sminshall 	    telrcv_state = TS_DATA;
117532377Sminshall 	    continue;
117627110Sminshall 
117732377Sminshall 	case TS_WONT:
117837226Sminshall 	    printoption("RCVD", "wont", c);
1179*38689Sborman 	    wontoption(c);
118032377Sminshall 	    SetIn3270();
118132377Sminshall 	    telrcv_state = TS_DATA;
118232377Sminshall 	    continue;
118327088Sminshall 
118432377Sminshall 	case TS_DO:
118537226Sminshall 	    printoption("RCVD", "do", c);
118637226Sminshall 	    dooption(c);
118732377Sminshall 	    SetIn3270();
118837219Sminshall 	    if (c == TELOPT_NAWS) {
118937219Sminshall 		sendnaws();
119037219Sminshall 	    } else if (c == TELOPT_LFLOW) {
119137219Sminshall 		localflow = 1;
119237219Sminshall 		setcommandmode();
1193*38689Sborman 		setconnmode(0);
119437219Sminshall 	    }
119532377Sminshall 	    telrcv_state = TS_DATA;
119632377Sminshall 	    continue;
119727088Sminshall 
119832377Sminshall 	case TS_DONT:
119937226Sminshall 	    printoption("RCVD", "dont", c);
1200*38689Sborman 	    dontoption(c);
120137226Sminshall 	    flushline = 1;
1202*38689Sborman 	    setconnmode(0);	/* set new tty mode (maybe) */
120332377Sminshall 	    SetIn3270();
120432377Sminshall 	    telrcv_state = TS_DATA;
120532377Sminshall 	    continue;
120627088Sminshall 
120732377Sminshall 	case TS_SB:
120832377Sminshall 	    if (c == IAC) {
120932377Sminshall 		telrcv_state = TS_SE;
121032377Sminshall 	    } else {
121132377Sminshall 		SB_ACCUM(c);
121232377Sminshall 	    }
121332377Sminshall 	    continue;
121427088Sminshall 
121532377Sminshall 	case TS_SE:
121632377Sminshall 	    if (c != SE) {
121732377Sminshall 		if (c != IAC) {
1218*38689Sborman 		    /*
1219*38689Sborman 		     * This is an error.  We only expect to get
1220*38689Sborman 		     * "IAC IAC" or "IAC SE".  Several things may
1221*38689Sborman 		     * have happend.  An IAC was not doubled, the
1222*38689Sborman 		     * IAC SE was left off, or another option got
1223*38689Sborman 		     * inserted into the suboption are all possibilities.
1224*38689Sborman 		     * If we assume that the IAC was not doubled,
1225*38689Sborman 		     * and really the IAC SE was left off, we could
1226*38689Sborman 		     * get into an infinate loop here.  So, instead,
1227*38689Sborman 		     * we terminate the suboption, and process the
1228*38689Sborman 		     * partial suboption if we can.
1229*38689Sborman 		     */
1230*38689Sborman 		    SB_TERM();
123132377Sminshall 		    SB_ACCUM(IAC);
1232*38689Sborman 		    SB_ACCUM(c);
1233*38689Sborman 		    printoption("In SUBOPTION processing, RCVD", "IAC", c);
1234*38689Sborman 		    suboption();	/* handle sub-option */
1235*38689Sborman 		    SetIn3270();
1236*38689Sborman 		    telrcv_state = TS_IAC;
1237*38689Sborman 		    goto process_iac;
123832377Sminshall 		}
123932377Sminshall 		SB_ACCUM(c);
124032377Sminshall 		telrcv_state = TS_SB;
124132377Sminshall 	    } else {
124232377Sminshall 		SB_TERM();
1243*38689Sborman 		SB_ACCUM(IAC);
1244*38689Sborman 		SB_ACCUM(SE);
124532377Sminshall 		suboption();	/* handle sub-option */
124632377Sminshall 		SetIn3270();
124732377Sminshall 		telrcv_state = TS_DATA;
124832377Sminshall 	    }
124927088Sminshall 	}
125027088Sminshall     }
125132667Sminshall     if (count)
125232667Sminshall 	ring_consumed(&netiring, count);
125332385Sminshall     return returnValue||count;
125427088Sminshall }
125532385Sminshall 
125632385Sminshall static int
125732554Sminshall telsnd()
125832385Sminshall {
125932385Sminshall     int tcc;
126032385Sminshall     int count;
126132385Sminshall     int returnValue = 0;
126232385Sminshall     char *tbp;
126332385Sminshall 
126432385Sminshall     tcc = 0;
126532385Sminshall     count = 0;
126632385Sminshall     while (NETROOM() > 2) {
126732385Sminshall 	register int sc;
126832385Sminshall 	register int c;
126932385Sminshall 
127032385Sminshall 	if (tcc == 0) {
127132385Sminshall 	    if (count) {
127232528Sminshall 		ring_consumed(&ttyiring, count);
127332385Sminshall 		returnValue = 1;
127432385Sminshall 		count = 0;
127532385Sminshall 	    }
127632528Sminshall 	    tbp = ttyiring.consume;
127732528Sminshall 	    tcc = ring_full_consecutive(&ttyiring);
127832385Sminshall 	    if (tcc == 0) {
127932385Sminshall 		break;
128032385Sminshall 	    }
128132385Sminshall 	}
128232385Sminshall 	c = *tbp++ & 0xff, sc = strip(c), tcc--; count++;
128332385Sminshall 	if (sc == escape) {
1284*38689Sborman 	    /*
1285*38689Sborman 	     * Double escape is a pass through of a single escape character.
1286*38689Sborman 	     */
1287*38689Sborman 	    if (tcc && strip(*tbp) == escape) {
1288*38689Sborman 		tbp++;
1289*38689Sborman 		tcc--;
1290*38689Sborman 		count++;
1291*38689Sborman 	    } else {
1292*38689Sborman 		command(0, tbp, tcc);
1293*38689Sborman 		count += tcc;
1294*38689Sborman 		tcc = 0;
1295*38689Sborman 		flushline = 1;
1296*38689Sborman 		break;
1297*38689Sborman 	    }
1298*38689Sborman 	}
1299*38689Sborman #ifdef	KLUDGELINEMODE
1300*38689Sborman 	if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) {
130132385Sminshall 	    if (tcc > 0 && strip(*tbp) == echoc) {
130232385Sminshall 		tcc--; tbp++; count++;
130332385Sminshall 	    } else {
130432385Sminshall 		dontlecho = !dontlecho;
130532385Sminshall 		settimer(echotoggle);
1306*38689Sborman 		setconnmode(0);
130732385Sminshall 		flushline = 1;
130832385Sminshall 		break;
130932385Sminshall 	    }
131032385Sminshall 	}
1311*38689Sborman #endif
1312*38689Sborman 	if (MODE_LOCAL_CHARS(globalmode)) {
131332385Sminshall 	    if (TerminalSpecialChars(sc) == 0) {
131432385Sminshall 		break;
131532385Sminshall 	    }
131632385Sminshall 	}
1317*38689Sborman 	if (my_want_state_is_wont(TELOPT_BINARY)) {
131832385Sminshall 	    switch (c) {
131932385Sminshall 	    case '\n':
132032385Sminshall 		    /*
132132385Sminshall 		     * If we are in CRMOD mode (\r ==> \n)
132232385Sminshall 		     * on our local machine, then probably
132332385Sminshall 		     * a newline (unix) is CRLF (TELNET).
132432385Sminshall 		     */
132532385Sminshall 		if (MODE_LOCAL_CHARS(globalmode)) {
132632385Sminshall 		    NETADD('\r');
132732385Sminshall 		}
132832385Sminshall 		NETADD('\n');
132932385Sminshall 		flushline = 1;
133032385Sminshall 		break;
133132385Sminshall 	    case '\r':
133232385Sminshall 		if (!crlf) {
133332385Sminshall 		    NET2ADD('\r', '\0');
133432385Sminshall 		} else {
133532385Sminshall 		    NET2ADD('\r', '\n');
133632385Sminshall 		}
133732385Sminshall 		flushline = 1;
133832385Sminshall 		break;
133932385Sminshall 	    case IAC:
134032385Sminshall 		NET2ADD(IAC, IAC);
134132385Sminshall 		break;
134232385Sminshall 	    default:
134332385Sminshall 		NETADD(c);
134432385Sminshall 		break;
134532385Sminshall 	    }
134632385Sminshall 	} else if (c == IAC) {
134732385Sminshall 	    NET2ADD(IAC, IAC);
134832385Sminshall 	} else {
134932385Sminshall 	    NETADD(c);
135032385Sminshall 	}
135132385Sminshall     }
135232667Sminshall     if (count)
135332667Sminshall 	ring_consumed(&ttyiring, count);
135432385Sminshall     return returnValue||count;		/* Non-zero if we did anything */
135532385Sminshall }
135632377Sminshall 
135727088Sminshall /*
135832377Sminshall  * Scheduler()
135932377Sminshall  *
136032377Sminshall  * Try to do something.
136132377Sminshall  *
136232377Sminshall  * If we do something useful, return 1; else return 0.
136332377Sminshall  *
136427110Sminshall  */
136527110Sminshall 
136627110Sminshall 
136732377Sminshall int
136832377Sminshall Scheduler(block)
136932377Sminshall int	block;			/* should we block in the select ? */
137027110Sminshall {
137132377Sminshall 		/* One wants to be a bit careful about setting returnValue
137232377Sminshall 		 * to one, since a one implies we did some useful work,
137332377Sminshall 		 * and therefore probably won't be called to block next
137432377Sminshall 		 * time (TN3270 mode only).
137532377Sminshall 		 */
137632531Sminshall     int returnValue;
137732531Sminshall     int netin, netout, netex, ttyin, ttyout;
137827110Sminshall 
137932531Sminshall     /* Decide which rings should be processed */
138032531Sminshall 
138132531Sminshall     netout = ring_full_count(&netoring) &&
1382*38689Sborman 	    (flushline ||
1383*38689Sborman 		(my_want_state_is_wont(TELOPT_LINEMODE)
1384*38689Sborman #ifdef	KLUDGELINEMODE
1385*38689Sborman 			&& (!kludgelinemode || my_want_state_is_do(TELOPT_SGA))
1386*38689Sborman #endif
1387*38689Sborman 		) ||
1388*38689Sborman 			my_want_state_is_will(TELOPT_BINARY));
138932531Sminshall     ttyout = ring_full_count(&ttyoring);
139032531Sminshall 
139132377Sminshall #if	defined(TN3270)
139232531Sminshall     ttyin = ring_empty_count(&ttyiring) && (shell_active == 0);
139332377Sminshall #else	/* defined(TN3270) */
139432531Sminshall     ttyin = ring_empty_count(&ttyiring);
139532377Sminshall #endif	/* defined(TN3270) */
139632531Sminshall 
139732531Sminshall #if	defined(TN3270)
139832531Sminshall     netin = ring_empty_count(&netiring);
139932377Sminshall #   else /* !defined(TN3270) */
140032531Sminshall     netin = !ISend && ring_empty_count(&netiring);
140132377Sminshall #   endif /* !defined(TN3270) */
140232531Sminshall 
140332531Sminshall     netex = !SYNCHing;
140432531Sminshall 
140532531Sminshall     /* If we have seen a signal recently, reset things */
140632377Sminshall #   if defined(TN3270) && defined(unix)
140732377Sminshall     if (HaveInput) {
140832377Sminshall 	HaveInput = 0;
140932377Sminshall 	signal(SIGIO, inputAvailable);
141032377Sminshall     }
141132377Sminshall #endif	/* defined(TN3270) && defined(unix) */
141232377Sminshall 
141332531Sminshall     /* Call to system code to process rings */
141427178Sminshall 
141532531Sminshall     returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block);
141627178Sminshall 
141732531Sminshall     /* Now, look at the input rings, looking for work to do. */
141832377Sminshall 
141932531Sminshall     if (ring_full_count(&ttyiring)) {
142032377Sminshall #   if defined(TN3270)
142132377Sminshall 	if (In3270) {
142234848Sminshall 	    int c;
142334848Sminshall 
142433804Sminshall 	    c = DataFromTerminal(ttyiring.consume,
142532528Sminshall 					ring_full_consecutive(&ttyiring));
142632377Sminshall 	    if (c) {
142732377Sminshall 		returnValue = 1;
142832667Sminshall 	        ring_consumed(&ttyiring, c);
142932377Sminshall 	    }
143032377Sminshall 	} else {
143132377Sminshall #   endif /* defined(TN3270) */
143232554Sminshall 	    returnValue |= telsnd();
143332377Sminshall #   if defined(TN3270)
143427178Sminshall 	}
143532531Sminshall #   endif /* defined(TN3270) */
143627178Sminshall     }
143732377Sminshall 
143832528Sminshall     if (ring_full_count(&netiring)) {
143932377Sminshall #	if !defined(TN3270)
144032385Sminshall 	returnValue |= telrcv();
144132377Sminshall #	else /* !defined(TN3270) */
144232377Sminshall 	returnValue = Push3270();
144332377Sminshall #	endif /* !defined(TN3270) */
144432377Sminshall     }
144532377Sminshall     return returnValue;
144627178Sminshall }
144727178Sminshall 
144827178Sminshall /*
144932377Sminshall  * Select from tty and network...
145027088Sminshall  */
145132377Sminshall void
145232377Sminshall telnet()
145327088Sminshall {
145432531Sminshall     sys_telnet_init();
145527088Sminshall 
145632377Sminshall #   if !defined(TN3270)
145732377Sminshall     if (telnetport) {
1458*38689Sborman 	send_do(TELOPT_SGA, 1);
1459*38689Sborman 	send_will(TELOPT_TTYPE, 1);
1460*38689Sborman 	send_will(TELOPT_NAWS, 1);
1461*38689Sborman 	send_will(TELOPT_TSPEED, 1);
1462*38689Sborman 	send_will(TELOPT_LFLOW, 1);
1463*38689Sborman 	send_will(TELOPT_LINEMODE, 1);
146427178Sminshall     }
146532377Sminshall #   endif /* !defined(TN3270) */
146627088Sminshall 
146732377Sminshall #   if !defined(TN3270)
146832377Sminshall     for (;;) {
146932385Sminshall 	int schedValue;
147032385Sminshall 
147132385Sminshall 	while ((schedValue = Scheduler(0)) != 0) {
147232385Sminshall 	    if (schedValue == -1) {
147332385Sminshall 		setcommandmode();
147432385Sminshall 		return;
147532385Sminshall 	    }
147632385Sminshall 	}
147732385Sminshall 
147832531Sminshall 	if (Scheduler(1) == -1) {
147932377Sminshall 	    setcommandmode();
148032377Sminshall 	    return;
148132377Sminshall 	}
148232377Sminshall     }
148332377Sminshall #   else /* !defined(TN3270) */
148432377Sminshall     for (;;) {
148532377Sminshall 	int schedValue;
148627088Sminshall 
148732377Sminshall 	while (!In3270 && !shell_active) {
148832531Sminshall 	    if (Scheduler(1) == -1) {
148932377Sminshall 		setcommandmode();
149032377Sminshall 		return;
149132377Sminshall 	    }
149227088Sminshall 	}
149332377Sminshall 
149432377Sminshall 	while ((schedValue = Scheduler(0)) != 0) {
149532377Sminshall 	    if (schedValue == -1) {
149632377Sminshall 		setcommandmode();
149732377Sminshall 		return;
149832377Sminshall 	    }
149927088Sminshall 	}
150032377Sminshall 		/* If there is data waiting to go out to terminal, don't
150132377Sminshall 		 * schedule any more data for the terminal.
150232377Sminshall 		 */
150334304Sminshall 	if (ring_full_count(&ttyoring)) {
150432377Sminshall 	    schedValue = 1;
150527088Sminshall 	} else {
150632377Sminshall 	    if (shell_active) {
150732377Sminshall 		if (shell_continue() == 0) {
150832377Sminshall 		    ConnectScreen();
150927088Sminshall 		}
151032377Sminshall 	    } else if (In3270) {
151132377Sminshall 		schedValue = DoTerminalOutput();
151232377Sminshall 	    }
151327088Sminshall 	}
151432377Sminshall 	if (schedValue && (shell_active == 0)) {
151532531Sminshall 	    if (Scheduler(1) == -1) {
151632377Sminshall 		setcommandmode();
151732377Sminshall 		return;
151832377Sminshall 	    }
151927088Sminshall 	}
152032377Sminshall     }
152132377Sminshall #   endif /* !defined(TN3270) */
152227088Sminshall }
152332377Sminshall 
152434848Sminshall #if	0	/* XXX - this not being in is a bug */
152527088Sminshall /*
152632554Sminshall  * nextitem()
152732554Sminshall  *
152832554Sminshall  *	Return the address of the next "item" in the TELNET data
152932554Sminshall  * stream.  This will be the address of the next character if
153032554Sminshall  * the current address is a user data character, or it will
153132554Sminshall  * be the address of the character following the TELNET command
153232554Sminshall  * if the current address is a TELNET IAC ("I Am a Command")
153332554Sminshall  * character.
153432554Sminshall  */
153532554Sminshall 
153632554Sminshall static char *
153732554Sminshall nextitem(current)
153832554Sminshall char	*current;
153932554Sminshall {
154032554Sminshall     if ((*current&0xff) != IAC) {
154132554Sminshall 	return current+1;
154232554Sminshall     }
154332554Sminshall     switch (*(current+1)&0xff) {
154432554Sminshall     case DO:
154532554Sminshall     case DONT:
154632554Sminshall     case WILL:
154732554Sminshall     case WONT:
154832554Sminshall 	return current+3;
154932554Sminshall     case SB:		/* loop forever looking for the SE */
155032554Sminshall 	{
155132554Sminshall 	    register char *look = current+2;
155232554Sminshall 
155332554Sminshall 	    for (;;) {
155432554Sminshall 		if ((*look++&0xff) == IAC) {
155532554Sminshall 		    if ((*look++&0xff) == SE) {
155632554Sminshall 			return look;
155732554Sminshall 		    }
155832554Sminshall 		}
155932554Sminshall 	    }
156032554Sminshall 	}
156132554Sminshall     default:
156232554Sminshall 	return current+2;
156332554Sminshall     }
156432554Sminshall }
156534848Sminshall #endif	/* 0 */
156632554Sminshall 
156732554Sminshall /*
156832554Sminshall  * netclear()
156932554Sminshall  *
157032554Sminshall  *	We are about to do a TELNET SYNCH operation.  Clear
157132554Sminshall  * the path to the network.
157232554Sminshall  *
157332554Sminshall  *	Things are a bit tricky since we may have sent the first
157432554Sminshall  * byte or so of a previous TELNET command into the network.
157532554Sminshall  * So, we have to scan the network buffer from the beginning
157632554Sminshall  * until we are up to where we want to be.
157732554Sminshall  *
157832554Sminshall  *	A side effect of what we do, just to keep things
157932554Sminshall  * simple, is to clear the urgent data pointer.  The principal
158032554Sminshall  * caller should be setting the urgent data pointer AFTER calling
158132554Sminshall  * us in any case.
158232554Sminshall  */
158332554Sminshall 
158432554Sminshall static void
158532554Sminshall netclear()
158632554Sminshall {
158732554Sminshall #if	0	/* XXX */
158832554Sminshall     register char *thisitem, *next;
158932554Sminshall     char *good;
159032554Sminshall #define	wewant(p)	((nfrontp > p) && ((*p&0xff) == IAC) && \
159132554Sminshall 				((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
159232554Sminshall 
159332554Sminshall     thisitem = netobuf;
159432554Sminshall 
159532554Sminshall     while ((next = nextitem(thisitem)) <= netobuf.send) {
159632554Sminshall 	thisitem = next;
159732554Sminshall     }
159832554Sminshall 
159932554Sminshall     /* Now, thisitem is first before/at boundary. */
160032554Sminshall 
160132554Sminshall     good = netobuf;	/* where the good bytes go */
160232554Sminshall 
160332554Sminshall     while (netoring.add > thisitem) {
160432554Sminshall 	if (wewant(thisitem)) {
160532554Sminshall 	    int length;
160632554Sminshall 
160732554Sminshall 	    next = thisitem;
160832554Sminshall 	    do {
160932554Sminshall 		next = nextitem(next);
161032554Sminshall 	    } while (wewant(next) && (nfrontp > next));
161132554Sminshall 	    length = next-thisitem;
161232554Sminshall 	    memcpy(good, thisitem, length);
161332554Sminshall 	    good += length;
161432554Sminshall 	    thisitem = next;
161532554Sminshall 	} else {
161632554Sminshall 	    thisitem = nextitem(thisitem);
161732554Sminshall 	}
161832554Sminshall     }
161932554Sminshall 
162032554Sminshall #endif	/* 0 */
162132554Sminshall }
162232554Sminshall 
162332554Sminshall /*
162432377Sminshall  * These routines add various telnet commands to the data stream.
162527088Sminshall  */
162632377Sminshall 
162732554Sminshall static void
162832554Sminshall doflush()
162932554Sminshall {
163032554Sminshall     NET2ADD(IAC, DO);
163132554Sminshall     NETADD(TELOPT_TM);
163232554Sminshall     flushline = 1;
163332554Sminshall     flushout = 1;
163432554Sminshall     ttyflush(1);			/* Flush/drop output */
163532554Sminshall     /* do printoption AFTER flush, otherwise the output gets tossed... */
163637226Sminshall     printoption("SENT", "do", TELOPT_TM);
163732554Sminshall }
163832554Sminshall 
163932377Sminshall void
164032377Sminshall xmitAO()
164127088Sminshall {
164232377Sminshall     NET2ADD(IAC, AO);
164332377Sminshall     if (autoflush) {
164432377Sminshall 	doflush();
164532377Sminshall     }
164632377Sminshall }
164727088Sminshall 
164832377Sminshall 
164932377Sminshall void
165032377Sminshall xmitEL()
165127088Sminshall {
165232377Sminshall     NET2ADD(IAC, EL);
165327088Sminshall }
165427088Sminshall 
165532377Sminshall void
165632377Sminshall xmitEC()
165727088Sminshall {
165832377Sminshall     NET2ADD(IAC, EC);
165927088Sminshall }
166027088Sminshall 
166132377Sminshall 
166232377Sminshall #if	defined(NOT43)
166332377Sminshall int
166432377Sminshall #else	/* defined(NOT43) */
166532377Sminshall void
166632377Sminshall #endif	/* defined(NOT43) */
166732377Sminshall dosynch()
166827088Sminshall {
166932377Sminshall     netclear();			/* clear the path to the network */
167033294Sminshall     NETADD(IAC);
167133294Sminshall     setneturg();
167233294Sminshall     NETADD(DM);
167327088Sminshall 
167432377Sminshall #if	defined(NOT43)
167532377Sminshall     return 0;
167632377Sminshall #endif	/* defined(NOT43) */
167727088Sminshall }
167827088Sminshall 
167932377Sminshall void
168032377Sminshall intp()
168127088Sminshall {
168232377Sminshall     NET2ADD(IAC, IP);
168332377Sminshall     flushline = 1;
168432377Sminshall     if (autoflush) {
168532377Sminshall 	doflush();
168632377Sminshall     }
168732377Sminshall     if (autosynch) {
168832377Sminshall 	dosynch();
168932377Sminshall     }
169027088Sminshall }
169127186Sminshall 
169232377Sminshall void
169332377Sminshall sendbrk()
169427186Sminshall {
169532377Sminshall     NET2ADD(IAC, BREAK);
169632377Sminshall     flushline = 1;
169732377Sminshall     if (autoflush) {
169832377Sminshall 	doflush();
169932377Sminshall     }
170032377Sminshall     if (autosynch) {
170132377Sminshall 	dosynch();
170232377Sminshall     }
170327186Sminshall }
1704*38689Sborman 
1705*38689Sborman void
1706*38689Sborman sendabort()
1707*38689Sborman {
1708*38689Sborman     NET2ADD(IAC, ABORT);
1709*38689Sborman     flushline = 1;
1710*38689Sborman     if (autoflush) {
1711*38689Sborman 	doflush();
1712*38689Sborman     }
1713*38689Sborman     if (autosynch) {
1714*38689Sborman 	dosynch();
1715*38689Sborman     }
1716*38689Sborman }
1717*38689Sborman 
1718*38689Sborman void
1719*38689Sborman sendsusp()
1720*38689Sborman {
1721*38689Sborman     NET2ADD(IAC, SUSP);
1722*38689Sborman     flushline = 1;
1723*38689Sborman     if (autoflush) {
1724*38689Sborman 	doflush();
1725*38689Sborman     }
1726*38689Sborman     if (autosynch) {
1727*38689Sborman 	dosynch();
1728*38689Sborman     }
1729*38689Sborman }
1730*38689Sborman 
1731*38689Sborman void
1732*38689Sborman sendeof()
1733*38689Sborman {
1734*38689Sborman    NET2ADD(IAC, xEOF);
1735*38689Sborman }
1736*38689Sborman 
173737219Sminshall /*
173837219Sminshall  * Send a window size update to the remote system.
173937219Sminshall  */
174037219Sminshall 
174137219Sminshall void
174237219Sminshall sendnaws()
174337219Sminshall {
174437219Sminshall     long rows, cols;
1745*38689Sborman     unsigned char tmp[16];
1746*38689Sborman     register unsigned char *cp;
174737219Sminshall 
1748*38689Sborman     if (my_state_is_wont(TELOPT_NAWS))
1749*38689Sborman 	return;
175037219Sminshall 
1751*38689Sborman #define	PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \
1752*38689Sborman 			    if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; }
1753*38689Sborman 
175437219Sminshall     if (TerminalWindowSize(&rows, &cols) == 0) {	/* Failed */
175537219Sminshall 	return;
175637219Sminshall     }
175737219Sminshall 
1758*38689Sborman     cp = tmp;
1759*38689Sborman 
1760*38689Sborman     *cp++ = IAC;
1761*38689Sborman     *cp++ = SB;
1762*38689Sborman     *cp++ = TELOPT_NAWS;
1763*38689Sborman     PUTSHORT(cp, cols);
1764*38689Sborman     PUTSHORT(cp, rows);
1765*38689Sborman     *cp++ = IAC;
1766*38689Sborman     *cp++ = SE;
1767*38689Sborman     if (NETROOM() >= cp - tmp) {
1768*38689Sborman 	ring_supply_data(&netoring, tmp, cp-tmp);
1769*38689Sborman 	printsub('>', tmp+2, cp - tmp - 2);
177037219Sminshall     }
177137219Sminshall }
177237226Sminshall 
177337226Sminshall tel_enter_binary()
177437226Sminshall {
1775*38689Sborman     send_do(TELOPT_BINARY, 1);
1776*38689Sborman     send_will(TELOPT_BINARY, 1);
177737226Sminshall }
177837226Sminshall 
177937226Sminshall tel_leave_binary()
178037226Sminshall {
1781*38689Sborman     send_dont(TELOPT_BINARY, 1);
1782*38689Sborman     send_wont(TELOPT_BINARY, 1);
178337226Sminshall }
1784