telnet.c revision 29088
1/*
2 * Copyright (c) 1988, 1990, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35static char sccsid[] = "@(#)telnet.c	8.4 (Berkeley) 5/30/95";
36#endif /* not lint */
37
38#include <sys/types.h>
39
40#if	defined(unix)
41#include <signal.h>
42/* By the way, we need to include curses.h before telnet.h since,
43 * among other things, telnet.h #defines 'DO', which is a variable
44 * declared in curses.h.
45 */
46#endif	/* defined(unix) */
47
48#include <arpa/telnet.h>
49
50#include <ctype.h>
51
52#include "ring.h"
53
54#include "defines.h"
55#include "externs.h"
56#include "types.h"
57#include "general.h"
58
59
60#define	strip(x) ((my_want_state_is_wont(TELOPT_BINARY)) ? ((x)&0x7f) : (x))
61
62static unsigned char	subbuffer[SUBBUFSIZE],
63			*subpointer, *subend;	 /* buffer for sub-options */
64#define	SB_CLEAR()	subpointer = subbuffer;
65#define	SB_TERM()	{ subend = subpointer; SB_CLEAR(); }
66#define	SB_ACCUM(c)	if (subpointer < (subbuffer+sizeof subbuffer)) { \
67				*subpointer++ = (c); \
68			}
69
70#define	SB_GET()	((*subpointer++)&0xff)
71#define	SB_PEEK()	((*subpointer)&0xff)
72#define	SB_EOF()	(subpointer >= subend)
73#define	SB_LEN()	(subend - subpointer)
74
75char	options[256];		/* The combined options */
76char	do_dont_resp[256];
77char	will_wont_resp[256];
78
79int
80	eight = 0,
81	autologin = 0,	/* Autologin anyone? */
82	skiprc = 0,
83	connected,
84	showoptions,
85	In3270,		/* Are we in 3270 mode? */
86	ISend,		/* trying to send network data in */
87	debug = 0,
88	crmod,
89	netdata,	/* Print out network data flow */
90	crlf,		/* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
91#if	defined(TN3270)
92	noasynchtty = 0,/* User specified "-noasynch" on command line */
93	noasynchnet = 0,/* User specified "-noasynch" on command line */
94	askedSGA = 0,	/* We have talked about suppress go ahead */
95#endif	/* defined(TN3270) */
96	telnetport,
97	SYNCHing,	/* we are in TELNET SYNCH mode */
98	flushout,	/* flush output */
99	autoflush = 0,	/* flush output when interrupting? */
100	autosynch,	/* send interrupt characters with SYNCH? */
101	localflow,	/* we handle flow control locally */
102	restartany,	/* if flow control enabled, restart on any character */
103	localchars,	/* we recognize interrupt/quit */
104	donelclchars,	/* the user has set "localchars" */
105	donebinarytoggle,	/* the user has put us in binary */
106	dontlecho,	/* do we suppress local echoing right now? */
107	globalmode;
108
109char *prompt = 0;
110
111cc_t escape;
112cc_t rlogin;
113#ifdef	KLUDGELINEMODE
114cc_t echoc;
115#endif
116
117/*
118 * Telnet receiver states for fsm
119 */
120#define	TS_DATA		0
121#define	TS_IAC		1
122#define	TS_WILL		2
123#define	TS_WONT		3
124#define	TS_DO		4
125#define	TS_DONT		5
126#define	TS_CR		6
127#define	TS_SB		7		/* sub-option collection */
128#define	TS_SE		8		/* looking for sub-option end */
129
130static int	telrcv_state;
131#ifdef	OLD_ENVIRON
132unsigned char telopt_environ = TELOPT_NEW_ENVIRON;
133#else
134# define telopt_environ TELOPT_NEW_ENVIRON
135#endif
136
137jmp_buf	toplevel = { 0 };
138jmp_buf	peerdied;
139
140int	flushline;
141int	linemode;
142
143#ifdef	KLUDGELINEMODE
144int	kludgelinemode = 1;
145#endif
146
147/*
148 * The following are some clocks used to decide how to interpret
149 * the relationship between various variables.
150 */
151
152Clocks clocks;
153
154#ifdef	notdef
155Modelist modelist[] = {
156	{ "telnet command mode", COMMAND_LINE },
157	{ "character-at-a-time mode", 0 },
158	{ "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS },
159	{ "line-by-line mode (remote echo)", LINE | LOCAL_CHARS },
160	{ "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS },
161	{ "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS },
162	{ "3270 mode", 0 },
163};
164#endif
165
166
167/*
168 * Initialize telnet environment.
169 */
170
171    void
172init_telnet()
173{
174    env_init();
175
176    SB_CLEAR();
177    ClearArray(options);
178
179    connected = In3270 = ISend = localflow = donebinarytoggle = 0;
180#if	defined(AUTHENTICATION) || defined(ENCRYPTION)
181    auth_encrypt_connect(connected);
182#endif	/* defined(AUTHENTICATION) || defined(ENCRYPTION)  */
183    restartany = -1;
184
185    SYNCHing = 0;
186
187    /* Don't change NetTrace */
188
189    escape = CONTROL(']');
190    rlogin = _POSIX_VDISABLE;
191#ifdef	KLUDGELINEMODE
192    echoc = CONTROL('E');
193#endif
194
195    flushline = 1;
196    telrcv_state = TS_DATA;
197}
198
199
200#ifdef	notdef
201#include <varargs.h>
202
203    /*VARARGS*/
204    static void
205printring(va_alist)
206    va_dcl
207{
208    va_list ap;
209    char buffer[100];		/* where things go */
210    char *ptr;
211    char *format;
212    char *string;
213    Ring *ring;
214    int i;
215
216    va_start(ap);
217
218    ring = va_arg(ap, Ring *);
219    format = va_arg(ap, char *);
220    ptr = buffer;
221
222    while ((i = *format++) != 0) {
223	if (i == '%') {
224	    i = *format++;
225	    switch (i) {
226	    case 'c':
227		*ptr++ = va_arg(ap, int);
228		break;
229	    case 's':
230		string = va_arg(ap, char *);
231		ring_supply_data(ring, buffer, ptr-buffer);
232		ring_supply_data(ring, string, strlen(string));
233		ptr = buffer;
234		break;
235	    case 0:
236		ExitString("printring: trailing %%.\n", 1);
237		/*NOTREACHED*/
238	    default:
239		ExitString("printring: unknown format character.\n", 1);
240		/*NOTREACHED*/
241	    }
242	} else {
243	    *ptr++ = i;
244	}
245    }
246    ring_supply_data(ring, buffer, ptr-buffer);
247}
248#endif
249
250/*
251 * These routines are in charge of sending option negotiations
252 * to the other side.
253 *
254 * The basic idea is that we send the negotiation if either side
255 * is in disagreement as to what the current state should be.
256 */
257
258    void
259send_do(c, init)
260    register int c, init;
261{
262    if (init) {
263	if (((do_dont_resp[c] == 0) && my_state_is_do(c)) ||
264				my_want_state_is_do(c))
265	    return;
266	set_my_want_state_do(c);
267	do_dont_resp[c]++;
268    }
269    NET2ADD(IAC, DO);
270    NETADD(c);
271    printoption("SENT", DO, c);
272}
273
274    void
275send_dont(c, init)
276    register int c, init;
277{
278    if (init) {
279	if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) ||
280				my_want_state_is_dont(c))
281	    return;
282	set_my_want_state_dont(c);
283	do_dont_resp[c]++;
284    }
285    NET2ADD(IAC, DONT);
286    NETADD(c);
287    printoption("SENT", DONT, c);
288}
289
290    void
291send_will(c, init)
292    register int c, init;
293{
294    if (init) {
295	if (((will_wont_resp[c] == 0) && my_state_is_will(c)) ||
296				my_want_state_is_will(c))
297	    return;
298	set_my_want_state_will(c);
299	will_wont_resp[c]++;
300    }
301    NET2ADD(IAC, WILL);
302    NETADD(c);
303    printoption("SENT", WILL, c);
304}
305
306    void
307send_wont(c, init)
308    register int c, init;
309{
310    if (init) {
311	if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) ||
312				my_want_state_is_wont(c))
313	    return;
314	set_my_want_state_wont(c);
315	will_wont_resp[c]++;
316    }
317    NET2ADD(IAC, WONT);
318    NETADD(c);
319    printoption("SENT", WONT, c);
320}
321
322
323	void
324willoption(option)
325	int option;
326{
327	int new_state_ok = 0;
328
329	if (do_dont_resp[option]) {
330	    --do_dont_resp[option];
331	    if (do_dont_resp[option] && my_state_is_do(option))
332		--do_dont_resp[option];
333	}
334
335	if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) {
336
337	    switch (option) {
338
339	    case TELOPT_ECHO:
340#	    if defined(TN3270)
341		/*
342		 * The following is a pain in the rear-end.
343		 * Various IBM servers (some versions of Wiscnet,
344		 * possibly Fibronics/Spartacus, and who knows who
345		 * else) will NOT allow us to send "DO SGA" too early
346		 * in the setup proceedings.  On the other hand,
347		 * 4.2 servers (telnetd) won't set SGA correctly.
348		 * So, we are stuck.  Empirically (but, based on
349		 * a VERY small sample), the IBM servers don't send
350		 * out anything about ECHO, so we postpone our sending
351		 * "DO SGA" until we see "WILL ECHO" (which 4.2 servers
352		 * DO send).
353		  */
354		{
355		    if (askedSGA == 0) {
356			askedSGA = 1;
357			if (my_want_state_is_dont(TELOPT_SGA))
358			    send_do(TELOPT_SGA, 1);
359		    }
360		}
361		    /* Fall through */
362	    case TELOPT_EOR:
363#endif	    /* defined(TN3270) */
364	    case TELOPT_BINARY:
365	    case TELOPT_SGA:
366		settimer(modenegotiated);
367		/* FALL THROUGH */
368	    case TELOPT_STATUS:
369#if	defined(AUTHENTICATION)
370	    case TELOPT_AUTHENTICATION:
371#endif
372#ifdef	ENCRYPTION
373	    case TELOPT_ENCRYPT:
374#endif /* ENCRYPTION */
375		new_state_ok = 1;
376		break;
377
378	    case TELOPT_TM:
379		if (flushout)
380		    flushout = 0;
381		/*
382		 * Special case for TM.  If we get back a WILL,
383		 * pretend we got back a WONT.
384		 */
385		set_my_want_state_dont(option);
386		set_my_state_dont(option);
387		return;			/* Never reply to TM will's/wont's */
388
389	    case TELOPT_LINEMODE:
390	    default:
391		break;
392	    }
393
394	    if (new_state_ok) {
395		set_my_want_state_do(option);
396		send_do(option, 0);
397		setconnmode(0);		/* possibly set new tty mode */
398	    } else {
399		do_dont_resp[option]++;
400		send_dont(option, 0);
401	    }
402	}
403	set_my_state_do(option);
404#ifdef	ENCRYPTION
405	if (option == TELOPT_ENCRYPT)
406		encrypt_send_support();
407#endif	/* ENCRYPTION */
408}
409
410	void
411wontoption(option)
412	int option;
413{
414	if (do_dont_resp[option]) {
415	    --do_dont_resp[option];
416	    if (do_dont_resp[option] && my_state_is_dont(option))
417		--do_dont_resp[option];
418	}
419
420	if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) {
421
422	    switch (option) {
423
424#ifdef	KLUDGELINEMODE
425	    case TELOPT_SGA:
426		if (!kludgelinemode)
427		    break;
428		/* FALL THROUGH */
429#endif
430	    case TELOPT_ECHO:
431		settimer(modenegotiated);
432		break;
433
434	    case TELOPT_TM:
435		if (flushout)
436		    flushout = 0;
437		set_my_want_state_dont(option);
438		set_my_state_dont(option);
439		return;		/* Never reply to TM will's/wont's */
440
441	    default:
442		break;
443	    }
444	    set_my_want_state_dont(option);
445	    if (my_state_is_do(option))
446		send_dont(option, 0);
447	    setconnmode(0);			/* Set new tty mode */
448	} else if (option == TELOPT_TM) {
449	    /*
450	     * Special case for TM.
451	     */
452	    if (flushout)
453		flushout = 0;
454	    set_my_want_state_dont(option);
455	}
456	set_my_state_dont(option);
457}
458
459	static void
460dooption(option)
461	int option;
462{
463	int new_state_ok = 0;
464
465	if (will_wont_resp[option]) {
466	    --will_wont_resp[option];
467	    if (will_wont_resp[option] && my_state_is_will(option))
468		--will_wont_resp[option];
469	}
470
471	if (will_wont_resp[option] == 0) {
472	  if (my_want_state_is_wont(option)) {
473
474	    switch (option) {
475
476	    case TELOPT_TM:
477		/*
478		 * Special case for TM.  We send a WILL, but pretend
479		 * we sent WONT.
480		 */
481		send_will(option, 0);
482		set_my_want_state_wont(TELOPT_TM);
483		set_my_state_wont(TELOPT_TM);
484		return;
485
486#	if defined(TN3270)
487	    case TELOPT_EOR:		/* end of record */
488#	endif	/* defined(TN3270) */
489	    case TELOPT_BINARY:		/* binary mode */
490	    case TELOPT_NAWS:		/* window size */
491	    case TELOPT_TSPEED:		/* terminal speed */
492	    case TELOPT_LFLOW:		/* local flow control */
493	    case TELOPT_TTYPE:		/* terminal type option */
494	    case TELOPT_SGA:		/* no big deal */
495#ifdef	ENCRYPTION
496	    case TELOPT_ENCRYPT:	/* encryption variable option */
497#endif	/* ENCRYPTION */
498		new_state_ok = 1;
499		break;
500
501	    case TELOPT_NEW_ENVIRON:	/* New environment variable option */
502#ifdef	OLD_ENVIRON
503		if (my_state_is_will(TELOPT_OLD_ENVIRON))
504			send_wont(TELOPT_OLD_ENVIRON, 1); /* turn off the old */
505		goto env_common;
506	    case TELOPT_OLD_ENVIRON:	/* Old environment variable option */
507		if (my_state_is_will(TELOPT_NEW_ENVIRON))
508			break;		/* Don't enable if new one is in use! */
509	    env_common:
510		telopt_environ = option;
511#endif
512		new_state_ok = 1;
513		break;
514
515#if	defined(AUTHENTICATION)
516	    case TELOPT_AUTHENTICATION:
517		if (autologin)
518			new_state_ok = 1;
519		break;
520#endif
521
522	    case TELOPT_XDISPLOC:	/* X Display location */
523		if (env_getvalue((unsigned char *)"DISPLAY"))
524		    new_state_ok = 1;
525		break;
526
527	    case TELOPT_LINEMODE:
528#ifdef	KLUDGELINEMODE
529		kludgelinemode = 0;
530		send_do(TELOPT_SGA, 1);
531#endif
532		set_my_want_state_will(TELOPT_LINEMODE);
533		send_will(option, 0);
534		set_my_state_will(TELOPT_LINEMODE);
535		slc_init();
536		return;
537
538	    case TELOPT_ECHO:		/* We're never going to echo... */
539	    default:
540		break;
541	    }
542
543	    if (new_state_ok) {
544		set_my_want_state_will(option);
545		send_will(option, 0);
546		setconnmode(0);			/* Set new tty mode */
547	    } else {
548		will_wont_resp[option]++;
549		send_wont(option, 0);
550	    }
551	  } else {
552	    /*
553	     * Handle options that need more things done after the
554	     * other side has acknowledged the option.
555	     */
556	    switch (option) {
557	    case TELOPT_LINEMODE:
558#ifdef	KLUDGELINEMODE
559		kludgelinemode = 0;
560		send_do(TELOPT_SGA, 1);
561#endif
562		set_my_state_will(option);
563		slc_init();
564		send_do(TELOPT_SGA, 0);
565		return;
566	    }
567	  }
568	}
569	set_my_state_will(option);
570}
571
572	static void
573dontoption(option)
574	int option;
575{
576
577	if (will_wont_resp[option]) {
578	    --will_wont_resp[option];
579	    if (will_wont_resp[option] && my_state_is_wont(option))
580		--will_wont_resp[option];
581	}
582
583	if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) {
584	    switch (option) {
585	    case TELOPT_LINEMODE:
586		linemode = 0;	/* put us back to the default state */
587		break;
588#ifdef	OLD_ENVIRON
589	    case TELOPT_NEW_ENVIRON:
590		/*
591		 * The new environ option wasn't recognized, try
592		 * the old one.
593		 */
594		send_will(TELOPT_OLD_ENVIRON, 1);
595		telopt_environ = TELOPT_OLD_ENVIRON;
596		break;
597#endif
598	    }
599	    /* we always accept a DONT */
600	    set_my_want_state_wont(option);
601	    if (my_state_is_will(option))
602		send_wont(option, 0);
603	    setconnmode(0);			/* Set new tty mode */
604	}
605	set_my_state_wont(option);
606}
607
608/*
609 * Given a buffer returned by tgetent(), this routine will turn
610 * the pipe seperated list of names in the buffer into an array
611 * of pointers to null terminated names.  We toss out any bad,
612 * duplicate, or verbose names (names with spaces).
613 */
614
615static char *name_unknown = "UNKNOWN";
616static char *unknown[] = { 0, 0 };
617
618	char **
619mklist(buf, name)
620	char *buf, *name;
621{
622	register int n;
623	register char c, *cp, **argvp, *cp2, **argv, **avt;
624
625	if (name) {
626		if ((int)strlen(name) > 40) {
627			name = 0;
628			unknown[0] = name_unknown;
629		} else {
630			unknown[0] = name;
631			upcase(name);
632		}
633	} else
634		unknown[0] = name_unknown;
635	/*
636	 * Count up the number of names.
637	 */
638	for (n = 1, cp = buf; *cp && *cp != ':'; cp++) {
639		if (*cp == '|')
640			n++;
641	}
642	/*
643	 * Allocate an array to put the name pointers into
644	 */
645	argv = (char **)malloc((n+3)*sizeof(char *));
646	if (argv == 0)
647		return(unknown);
648
649	/*
650	 * Fill up the array of pointers to names.
651	 */
652	*argv = 0;
653	argvp = argv+1;
654	n = 0;
655	for (cp = cp2 = buf; (c = *cp);  cp++) {
656		if (c == '|' || c == ':') {
657			*cp++ = '\0';
658			/*
659			 * Skip entries that have spaces or are over 40
660			 * characters long.  If this is our environment
661			 * name, then put it up front.  Otherwise, as
662			 * long as this is not a duplicate name (case
663			 * insensitive) add it to the list.
664			 */
665			if (n || (cp - cp2 > 41))
666				;
667			else if (name && (strncasecmp(name, cp2, cp-cp2) == 0))
668				*argv = cp2;
669			else if (is_unique(cp2, argv+1, argvp))
670				*argvp++ = cp2;
671			if (c == ':')
672				break;
673			/*
674			 * Skip multiple delimiters. Reset cp2 to
675			 * the beginning of the next name. Reset n,
676			 * the flag for names with spaces.
677			 */
678			while ((c = *cp) == '|')
679				cp++;
680			cp2 = cp;
681			n = 0;
682		}
683		/*
684		 * Skip entries with spaces or non-ascii values.
685		 * Convert lower case letters to upper case.
686		 */
687		if ((c == ' ') || !isascii(c))
688			n = 1;
689		else if (islower(c))
690			*cp = toupper(c);
691	}
692
693	/*
694	 * Check for an old V6 2 character name.  If the second
695	 * name points to the beginning of the buffer, and is
696	 * only 2 characters long, move it to the end of the array.
697	 */
698	if ((argv[1] == buf) && (strlen(argv[1]) == 2)) {
699		--argvp;
700		for (avt = &argv[1]; avt < argvp; avt++)
701			*avt = *(avt+1);
702		*argvp++ = buf;
703	}
704
705	/*
706	 * Duplicate last name, for TTYPE option, and null
707	 * terminate the array.  If we didn't find a match on
708	 * our terminal name, put that name at the beginning.
709	 */
710	cp = *(argvp-1);
711	*argvp++ = cp;
712	*argvp = 0;
713
714	if (*argv == 0) {
715		if (name)
716			*argv = name;
717		else {
718			--argvp;
719			for (avt = argv; avt < argvp; avt++)
720				*avt = *(avt+1);
721		}
722	}
723	if (*argv)
724		return(argv);
725	else
726		return(unknown);
727}
728
729	int
730is_unique(name, as, ae)
731	register char *name, **as, **ae;
732{
733	register char **ap;
734	register int n;
735
736	n = strlen(name) + 1;
737	for (ap = as; ap < ae; ap++)
738		if (strncasecmp(*ap, name, n) == 0)
739			return(0);
740	return (1);
741}
742
743#ifdef	TERMCAP
744char termbuf[1024];
745
746	/*ARGSUSED*/
747	int
748setupterm(tname, fd, errp)
749	char *tname;
750	int fd, *errp;
751{
752	if (tgetent(termbuf, tname) == 1) {
753		termbuf[1023] = '\0';
754		if (errp)
755			*errp = 1;
756		return(0);
757	}
758	if (errp)
759		*errp = 0;
760	return(-1);
761}
762#else
763#define	termbuf	ttytype
764extern char ttytype[];
765#endif
766
767int resettermname = 1;
768
769	char *
770gettermname()
771{
772	char *tname;
773	static char **tnamep = 0;
774	static char **next;
775	int err;
776
777	if (resettermname) {
778		resettermname = 0;
779		if (tnamep && tnamep != unknown)
780			free(tnamep);
781		if ((tname = (char *)env_getvalue((unsigned char *)"TERM")) &&
782				(setupterm(tname, 1, &err) == 0)) {
783			tnamep = mklist(termbuf, tname);
784		} else {
785			if (tname && ((int)strlen(tname) <= 40)) {
786				unknown[0] = tname;
787				upcase(tname);
788			} else
789				unknown[0] = name_unknown;
790			tnamep = unknown;
791		}
792		next = tnamep;
793	}
794	if (*next == 0)
795		next = tnamep;
796	return(*next++);
797}
798/*
799 * suboption()
800 *
801 *	Look at the sub-option buffer, and try to be helpful to the other
802 * side.
803 *
804 *	Currently we recognize:
805 *
806 *		Terminal type, send request.
807 *		Terminal speed (send request).
808 *		Local flow control (is request).
809 *		Linemode
810 */
811
812    static void
813suboption()
814{
815    unsigned char subchar;
816
817    printsub('<', subbuffer, SB_LEN()+2);
818    switch (subchar = SB_GET()) {
819    case TELOPT_TTYPE:
820	if (my_want_state_is_wont(TELOPT_TTYPE))
821	    return;
822	if (SB_EOF() || SB_GET() != TELQUAL_SEND) {
823	    return;
824	} else {
825	    char *name;
826	    unsigned char temp[50];
827	    int len;
828
829#if	defined(TN3270)
830	    if (tn3270_ttype()) {
831		return;
832	    }
833#endif	/* defined(TN3270) */
834	    name = gettermname();
835	    len = strlen(name) + 4 + 2;
836	    if (len < NETROOM()) {
837		sprintf((char *)temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
838				TELQUAL_IS, name, IAC, SE);
839		ring_supply_data(&netoring, temp, len);
840		printsub('>', &temp[2], len-2);
841	    } else {
842		ExitString("No room in buffer for terminal type.\n", 1);
843		/*NOTREACHED*/
844	    }
845	}
846	break;
847    case TELOPT_TSPEED:
848	if (my_want_state_is_wont(TELOPT_TSPEED))
849	    return;
850	if (SB_EOF())
851	    return;
852	if (SB_GET() == TELQUAL_SEND) {
853	    long ospeed, ispeed;
854	    unsigned char temp[50];
855	    int len;
856
857	    TerminalSpeeds(&ispeed, &ospeed);
858
859	    sprintf((char *)temp, "%c%c%c%c%d,%d%c%c", IAC, SB, TELOPT_TSPEED,
860		    TELQUAL_IS, ospeed, ispeed, IAC, SE);
861	    len = strlen((char *)temp+4) + 4;	/* temp[3] is 0 ... */
862
863	    if (len < NETROOM()) {
864		ring_supply_data(&netoring, temp, len);
865		printsub('>', temp+2, len - 2);
866	    }
867/*@*/	    else printf("lm_will: not enough room in buffer\n");
868	}
869	break;
870    case TELOPT_LFLOW:
871	if (my_want_state_is_wont(TELOPT_LFLOW))
872	    return;
873	if (SB_EOF())
874	    return;
875	switch(SB_GET()) {
876	case LFLOW_RESTART_ANY:
877	    restartany = 1;
878	    break;
879	case LFLOW_RESTART_XON:
880	    restartany = 0;
881	    break;
882	case LFLOW_ON:
883	    localflow = 1;
884	    break;
885	case LFLOW_OFF:
886	    localflow = 0;
887	    break;
888	default:
889	    return;
890	}
891	setcommandmode();
892	setconnmode(0);
893	break;
894
895    case TELOPT_LINEMODE:
896	if (my_want_state_is_wont(TELOPT_LINEMODE))
897	    return;
898	if (SB_EOF())
899	    return;
900	switch (SB_GET()) {
901	case WILL:
902	    lm_will(subpointer, SB_LEN());
903	    break;
904	case WONT:
905	    lm_wont(subpointer, SB_LEN());
906	    break;
907	case DO:
908	    lm_do(subpointer, SB_LEN());
909	    break;
910	case DONT:
911	    lm_dont(subpointer, SB_LEN());
912	    break;
913	case LM_SLC:
914	    slc(subpointer, SB_LEN());
915	    break;
916	case LM_MODE:
917	    lm_mode(subpointer, SB_LEN(), 0);
918	    break;
919	default:
920	    break;
921	}
922	break;
923
924#ifdef	OLD_ENVIRON
925    case TELOPT_OLD_ENVIRON:
926#endif
927    case TELOPT_NEW_ENVIRON:
928	if (SB_EOF())
929	    return;
930	switch(SB_PEEK()) {
931	case TELQUAL_IS:
932	case TELQUAL_INFO:
933	    if (my_want_state_is_dont(subchar))
934		return;
935	    break;
936	case TELQUAL_SEND:
937	    if (my_want_state_is_wont(subchar)) {
938		return;
939	    }
940	    break;
941	default:
942	    return;
943	}
944	env_opt(subpointer, SB_LEN());
945	break;
946
947    case TELOPT_XDISPLOC:
948	if (my_want_state_is_wont(TELOPT_XDISPLOC))
949	    return;
950	if (SB_EOF())
951	    return;
952	if (SB_GET() == TELQUAL_SEND) {
953	    unsigned char temp[50], *dp;
954	    int len;
955
956	    if ((dp = env_getvalue((unsigned char *)"DISPLAY")) == NULL) {
957		/*
958		 * Something happened, we no longer have a DISPLAY
959		 * variable.  So, turn off the option.
960		 */
961		send_wont(TELOPT_XDISPLOC, 1);
962		break;
963	    }
964	    sprintf((char *)temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC,
965		    TELQUAL_IS, dp, IAC, SE);
966	    len = strlen((char *)temp+4) + 4;	/* temp[3] is 0 ... */
967
968	    if (len < NETROOM()) {
969		ring_supply_data(&netoring, temp, len);
970		printsub('>', temp+2, len - 2);
971	    }
972/*@*/	    else printf("lm_will: not enough room in buffer\n");
973	}
974	break;
975
976#if	defined(AUTHENTICATION)
977	case TELOPT_AUTHENTICATION: {
978		if (!autologin)
979			break;
980		if (SB_EOF())
981			return;
982		switch(SB_GET()) {
983		case TELQUAL_IS:
984			if (my_want_state_is_dont(TELOPT_AUTHENTICATION))
985				return;
986			auth_is(subpointer, SB_LEN());
987			break;
988		case TELQUAL_SEND:
989			if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
990				return;
991			auth_send(subpointer, SB_LEN());
992			break;
993		case TELQUAL_REPLY:
994			if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
995				return;
996			auth_reply(subpointer, SB_LEN());
997			break;
998		case TELQUAL_NAME:
999			if (my_want_state_is_dont(TELOPT_AUTHENTICATION))
1000				return;
1001			auth_name(subpointer, SB_LEN());
1002			break;
1003		}
1004	}
1005	break;
1006#endif
1007#ifdef	ENCRYPTION
1008	case TELOPT_ENCRYPT:
1009		if (SB_EOF())
1010			return;
1011		switch(SB_GET()) {
1012		case ENCRYPT_START:
1013			if (my_want_state_is_dont(TELOPT_ENCRYPT))
1014				return;
1015			encrypt_start(subpointer, SB_LEN());
1016			break;
1017		case ENCRYPT_END:
1018			if (my_want_state_is_dont(TELOPT_ENCRYPT))
1019				return;
1020			encrypt_end();
1021			break;
1022		case ENCRYPT_SUPPORT:
1023			if (my_want_state_is_wont(TELOPT_ENCRYPT))
1024				return;
1025			encrypt_support(subpointer, SB_LEN());
1026			break;
1027		case ENCRYPT_REQSTART:
1028			if (my_want_state_is_wont(TELOPT_ENCRYPT))
1029				return;
1030			encrypt_request_start(subpointer, SB_LEN());
1031			break;
1032		case ENCRYPT_REQEND:
1033			if (my_want_state_is_wont(TELOPT_ENCRYPT))
1034				return;
1035			/*
1036			 * We can always send an REQEND so that we cannot
1037			 * get stuck encrypting.  We should only get this
1038			 * if we have been able to get in the correct mode
1039			 * anyhow.
1040			 */
1041			encrypt_request_end();
1042			break;
1043		case ENCRYPT_IS:
1044			if (my_want_state_is_dont(TELOPT_ENCRYPT))
1045				return;
1046			encrypt_is(subpointer, SB_LEN());
1047			break;
1048		case ENCRYPT_REPLY:
1049			if (my_want_state_is_wont(TELOPT_ENCRYPT))
1050				return;
1051			encrypt_reply(subpointer, SB_LEN());
1052			break;
1053		case ENCRYPT_ENC_KEYID:
1054			if (my_want_state_is_dont(TELOPT_ENCRYPT))
1055				return;
1056			encrypt_enc_keyid(subpointer, SB_LEN());
1057			break;
1058		case ENCRYPT_DEC_KEYID:
1059			if (my_want_state_is_wont(TELOPT_ENCRYPT))
1060				return;
1061			encrypt_dec_keyid(subpointer, SB_LEN());
1062			break;
1063		default:
1064			break;
1065		}
1066		break;
1067#endif	/* ENCRYPTION */
1068    default:
1069	break;
1070    }
1071}
1072
1073static unsigned char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE };
1074
1075    void
1076lm_will(cmd, len)
1077    unsigned char *cmd;
1078    int len;
1079{
1080    if (len < 1) {
1081/*@*/	printf("lm_will: no command!!!\n");	/* Should not happen... */
1082	return;
1083    }
1084    switch(cmd[0]) {
1085    case LM_FORWARDMASK:	/* We shouldn't ever get this... */
1086    default:
1087	str_lm[3] = DONT;
1088	str_lm[4] = cmd[0];
1089	if (NETROOM() > sizeof(str_lm)) {
1090	    ring_supply_data(&netoring, str_lm, sizeof(str_lm));
1091	    printsub('>', &str_lm[2], sizeof(str_lm)-2);
1092	}
1093/*@*/	else printf("lm_will: not enough room in buffer\n");
1094	break;
1095    }
1096}
1097
1098    void
1099lm_wont(cmd, len)
1100    unsigned char *cmd;
1101    int len;
1102{
1103    if (len < 1) {
1104/*@*/	printf("lm_wont: no command!!!\n");	/* Should not happen... */
1105	return;
1106    }
1107    switch(cmd[0]) {
1108    case LM_FORWARDMASK:	/* We shouldn't ever get this... */
1109    default:
1110	/* We are always DONT, so don't respond */
1111	return;
1112    }
1113}
1114
1115    void
1116lm_do(cmd, len)
1117    unsigned char *cmd;
1118    int len;
1119{
1120    if (len < 1) {
1121/*@*/	printf("lm_do: no command!!!\n");	/* Should not happen... */
1122	return;
1123    }
1124    switch(cmd[0]) {
1125    case LM_FORWARDMASK:
1126    default:
1127	str_lm[3] = WONT;
1128	str_lm[4] = cmd[0];
1129	if (NETROOM() > sizeof(str_lm)) {
1130	    ring_supply_data(&netoring, str_lm, sizeof(str_lm));
1131	    printsub('>', &str_lm[2], sizeof(str_lm)-2);
1132	}
1133/*@*/	else printf("lm_do: not enough room in buffer\n");
1134	break;
1135    }
1136}
1137
1138    void
1139lm_dont(cmd, len)
1140    unsigned char *cmd;
1141    int len;
1142{
1143    if (len < 1) {
1144/*@*/	printf("lm_dont: no command!!!\n");	/* Should not happen... */
1145	return;
1146    }
1147    switch(cmd[0]) {
1148    case LM_FORWARDMASK:
1149    default:
1150	/* we are always WONT, so don't respond */
1151	break;
1152    }
1153}
1154
1155static unsigned char str_lm_mode[] = {
1156	IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE
1157};
1158
1159	void
1160lm_mode(cmd, len, init)
1161	unsigned char *cmd;
1162	int len, init;
1163{
1164	if (len != 1)
1165		return;
1166	if ((linemode&MODE_MASK&~MODE_ACK) == *cmd)
1167		return;
1168	if (*cmd&MODE_ACK)
1169		return;
1170	linemode = *cmd&(MODE_MASK&~MODE_ACK);
1171	str_lm_mode[4] = linemode;
1172	if (!init)
1173	    str_lm_mode[4] |= MODE_ACK;
1174	if (NETROOM() > sizeof(str_lm_mode)) {
1175	    ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode));
1176	    printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2);
1177	}
1178/*@*/	else printf("lm_mode: not enough room in buffer\n");
1179	setconnmode(0);	/* set changed mode */
1180}
1181
1182
1183
1184/*
1185 * slc()
1186 * Handle special character suboption of LINEMODE.
1187 */
1188
1189struct spc {
1190	cc_t val;
1191	cc_t *valp;
1192	char flags;	/* Current flags & level */
1193	char mylevel;	/* Maximum level & flags */
1194} spc_data[NSLC+1];
1195
1196#define SLC_IMPORT	0
1197#define	SLC_EXPORT	1
1198#define SLC_RVALUE	2
1199static int slc_mode = SLC_EXPORT;
1200
1201	void
1202slc_init()
1203{
1204	register struct spc *spcp;
1205
1206	localchars = 1;
1207	for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) {
1208		spcp->val = 0;
1209		spcp->valp = 0;
1210		spcp->flags = spcp->mylevel = SLC_NOSUPPORT;
1211	}
1212
1213#define	initfunc(func, flags) { \
1214					spcp = &spc_data[func]; \
1215					if (spcp->valp = tcval(func)) { \
1216					    spcp->val = *spcp->valp; \
1217					    spcp->mylevel = SLC_VARIABLE|flags; \
1218					} else { \
1219					    spcp->val = 0; \
1220					    spcp->mylevel = SLC_DEFAULT; \
1221					} \
1222				    }
1223
1224	initfunc(SLC_SYNCH, 0);
1225	/* No BRK */
1226	initfunc(SLC_AO, 0);
1227	initfunc(SLC_AYT, 0);
1228	/* No EOR */
1229	initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT);
1230	initfunc(SLC_EOF, 0);
1231#ifndef	SYSV_TERMIO
1232	initfunc(SLC_SUSP, SLC_FLUSHIN);
1233#endif
1234	initfunc(SLC_EC, 0);
1235	initfunc(SLC_EL, 0);
1236#ifndef	SYSV_TERMIO
1237	initfunc(SLC_EW, 0);
1238	initfunc(SLC_RP, 0);
1239	initfunc(SLC_LNEXT, 0);
1240#endif
1241	initfunc(SLC_XON, 0);
1242	initfunc(SLC_XOFF, 0);
1243#ifdef	SYSV_TERMIO
1244	spc_data[SLC_XON].mylevel = SLC_CANTCHANGE;
1245	spc_data[SLC_XOFF].mylevel = SLC_CANTCHANGE;
1246#endif
1247	initfunc(SLC_FORW1, 0);
1248#ifdef	USE_TERMIO
1249	initfunc(SLC_FORW2, 0);
1250	/* No FORW2 */
1251#endif
1252
1253	initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT);
1254#undef	initfunc
1255
1256	if (slc_mode == SLC_EXPORT)
1257		slc_export();
1258	else
1259		slc_import(1);
1260
1261}
1262
1263    void
1264slcstate()
1265{
1266    printf("Special characters are %s values\n",
1267		slc_mode == SLC_IMPORT ? "remote default" :
1268		slc_mode == SLC_EXPORT ? "local" :
1269					 "remote");
1270}
1271
1272    void
1273slc_mode_export()
1274{
1275    slc_mode = SLC_EXPORT;
1276    if (my_state_is_will(TELOPT_LINEMODE))
1277	slc_export();
1278}
1279
1280    void
1281slc_mode_import(def)
1282    int def;
1283{
1284    slc_mode = def ? SLC_IMPORT : SLC_RVALUE;
1285    if (my_state_is_will(TELOPT_LINEMODE))
1286	slc_import(def);
1287}
1288
1289unsigned char slc_import_val[] = {
1290	IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE
1291};
1292unsigned char slc_import_def[] = {
1293	IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE
1294};
1295
1296    void
1297slc_import(def)
1298    int def;
1299{
1300    if (NETROOM() > sizeof(slc_import_val)) {
1301	if (def) {
1302	    ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def));
1303	    printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2);
1304	} else {
1305	    ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val));
1306	    printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2);
1307	}
1308    }
1309/*@*/ else printf("slc_import: not enough room\n");
1310}
1311
1312    void
1313slc_export()
1314{
1315    register struct spc *spcp;
1316
1317    TerminalDefaultChars();
1318
1319    slc_start_reply();
1320    for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
1321	if (spcp->mylevel != SLC_NOSUPPORT) {
1322	    if (spcp->val == (cc_t)(_POSIX_VDISABLE))
1323		spcp->flags = SLC_NOSUPPORT;
1324	    else
1325		spcp->flags = spcp->mylevel;
1326	    if (spcp->valp)
1327		spcp->val = *spcp->valp;
1328	    slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
1329	}
1330    }
1331    slc_end_reply();
1332    (void)slc_update();
1333    setconnmode(1);	/* Make sure the character values are set */
1334}
1335
1336	void
1337slc(cp, len)
1338	register unsigned char *cp;
1339	int len;
1340{
1341	register struct spc *spcp;
1342	register int func,level;
1343
1344	slc_start_reply();
1345
1346	for (; len >= 3; len -=3, cp +=3) {
1347
1348		func = cp[SLC_FUNC];
1349
1350		if (func == 0) {
1351			/*
1352			 * Client side: always ignore 0 function.
1353			 */
1354			continue;
1355		}
1356		if (func > NSLC) {
1357			if ((cp[SLC_FLAGS] & SLC_LEVELBITS) != SLC_NOSUPPORT)
1358				slc_add_reply(func, SLC_NOSUPPORT, 0);
1359			continue;
1360		}
1361
1362		spcp = &spc_data[func];
1363
1364		level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK);
1365
1366		if ((cp[SLC_VALUE] == (unsigned char)spcp->val) &&
1367		    ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) {
1368			continue;
1369		}
1370
1371		if (level == (SLC_DEFAULT|SLC_ACK)) {
1372			/*
1373			 * This is an error condition, the SLC_ACK
1374			 * bit should never be set for the SLC_DEFAULT
1375			 * level.  Our best guess to recover is to
1376			 * ignore the SLC_ACK bit.
1377			 */
1378			cp[SLC_FLAGS] &= ~SLC_ACK;
1379		}
1380
1381		if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) {
1382			spcp->val = (cc_t)cp[SLC_VALUE];
1383			spcp->flags = cp[SLC_FLAGS];	/* include SLC_ACK */
1384			continue;
1385		}
1386
1387		level &= ~SLC_ACK;
1388
1389		if (level <= (spcp->mylevel&SLC_LEVELBITS)) {
1390			spcp->flags = cp[SLC_FLAGS]|SLC_ACK;
1391			spcp->val = (cc_t)cp[SLC_VALUE];
1392		}
1393		if (level == SLC_DEFAULT) {
1394			if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT)
1395				spcp->flags = spcp->mylevel;
1396			else
1397				spcp->flags = SLC_NOSUPPORT;
1398		}
1399		slc_add_reply(func, spcp->flags, spcp->val);
1400	}
1401	slc_end_reply();
1402	if (slc_update())
1403		setconnmode(1);	/* set the  new character values */
1404}
1405
1406    void
1407slc_check()
1408{
1409    register struct spc *spcp;
1410
1411    slc_start_reply();
1412    for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
1413	if (spcp->valp && spcp->val != *spcp->valp) {
1414	    spcp->val = *spcp->valp;
1415	    if (spcp->val == (cc_t)(_POSIX_VDISABLE))
1416		spcp->flags = SLC_NOSUPPORT;
1417	    else
1418		spcp->flags = spcp->mylevel;
1419	    slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
1420	}
1421    }
1422    slc_end_reply();
1423    setconnmode(1);
1424}
1425
1426
1427unsigned char slc_reply[128];
1428unsigned char *slc_replyp;
1429
1430	void
1431slc_start_reply()
1432{
1433	slc_replyp = slc_reply;
1434	*slc_replyp++ = IAC;
1435	*slc_replyp++ = SB;
1436	*slc_replyp++ = TELOPT_LINEMODE;
1437	*slc_replyp++ = LM_SLC;
1438}
1439
1440	void
1441slc_add_reply(func, flags, value)
1442	unsigned char func;
1443	unsigned char flags;
1444	cc_t value;
1445{
1446	if ((*slc_replyp++ = func) == IAC)
1447		*slc_replyp++ = IAC;
1448	if ((*slc_replyp++ = flags) == IAC)
1449		*slc_replyp++ = IAC;
1450	if ((*slc_replyp++ = (unsigned char)value) == IAC)
1451		*slc_replyp++ = IAC;
1452}
1453
1454    void
1455slc_end_reply()
1456{
1457    register int len;
1458
1459    *slc_replyp++ = IAC;
1460    *slc_replyp++ = SE;
1461    len = slc_replyp - slc_reply;
1462    if (len <= 6)
1463	return;
1464    if (NETROOM() > len) {
1465	ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply);
1466	printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2);
1467    }
1468/*@*/else printf("slc_end_reply: not enough room\n");
1469}
1470
1471	int
1472slc_update()
1473{
1474	register struct spc *spcp;
1475	int need_update = 0;
1476
1477	for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
1478		if (!(spcp->flags&SLC_ACK))
1479			continue;
1480		spcp->flags &= ~SLC_ACK;
1481		if (spcp->valp && (*spcp->valp != spcp->val)) {
1482			*spcp->valp = spcp->val;
1483			need_update = 1;
1484		}
1485	}
1486	return(need_update);
1487}
1488
1489#ifdef	OLD_ENVIRON
1490# ifdef	ENV_HACK
1491/*
1492 * Earlier version of telnet/telnetd from the BSD code had
1493 * the definitions of VALUE and VAR reversed.  To ensure
1494 * maximum interoperability, we assume that the server is
1495 * an older BSD server, until proven otherwise.  The newer
1496 * BSD servers should be able to handle either definition,
1497 * so it is better to use the wrong values if we don't
1498 * know what type of server it is.
1499 */
1500int env_auto = 1;
1501int old_env_var = OLD_ENV_VAR;
1502int old_env_value = OLD_ENV_VALUE;
1503# else
1504#  define old_env_var OLD_ENV_VAR
1505#  define old_env_value OLD_ENV_VALUE
1506# endif
1507#endif
1508
1509	void
1510env_opt(buf, len)
1511	register unsigned char *buf;
1512	register int len;
1513{
1514	register unsigned char *ep = 0, *epc = 0;
1515	register int i;
1516
1517	switch(buf[0]&0xff) {
1518	case TELQUAL_SEND:
1519		env_opt_start();
1520		if (len == 1) {
1521			env_opt_add(NULL);
1522		} else for (i = 1; i < len; i++) {
1523			switch (buf[i]&0xff) {
1524#ifdef	OLD_ENVIRON
1525			case OLD_ENV_VAR:
1526# ifdef	ENV_HACK
1527				if (telopt_environ == TELOPT_OLD_ENVIRON
1528				    && env_auto) {
1529					/* Server has the same definitions */
1530					old_env_var = OLD_ENV_VAR;
1531					old_env_value = OLD_ENV_VALUE;
1532				}
1533				/* FALL THROUGH */
1534# endif
1535			case OLD_ENV_VALUE:
1536				/*
1537				 * Although OLD_ENV_VALUE is not legal, we will
1538				 * still recognize it, just in case it is an
1539				 * old server that has VAR & VALUE mixed up...
1540				 */
1541				/* FALL THROUGH */
1542#else
1543			case NEW_ENV_VAR:
1544#endif
1545			case ENV_USERVAR:
1546				if (ep) {
1547					*epc = 0;
1548					env_opt_add(ep);
1549				}
1550				ep = epc = &buf[i+1];
1551				break;
1552			case ENV_ESC:
1553				i++;
1554				/*FALL THROUGH*/
1555			default:
1556				if (epc)
1557					*epc++ = buf[i];
1558				break;
1559			}
1560		}
1561		if (ep) {
1562			*epc = 0;
1563			env_opt_add(ep);
1564		}
1565		env_opt_end(1);
1566		break;
1567
1568	case TELQUAL_IS:
1569	case TELQUAL_INFO:
1570		/* Ignore for now.  We shouldn't get it anyway. */
1571		break;
1572
1573	default:
1574		break;
1575	}
1576}
1577
1578#define	OPT_REPLY_SIZE	256
1579unsigned char *opt_reply;
1580unsigned char *opt_replyp;
1581unsigned char *opt_replyend;
1582
1583	void
1584env_opt_start()
1585{
1586	if (opt_reply)
1587		opt_reply = (unsigned char *)realloc(opt_reply, OPT_REPLY_SIZE);
1588	else
1589		opt_reply = (unsigned char *)malloc(OPT_REPLY_SIZE);
1590	if (opt_reply == NULL) {
1591/*@*/		printf("env_opt_start: malloc()/realloc() failed!!!\n");
1592		opt_reply = opt_replyp = opt_replyend = NULL;
1593		return;
1594	}
1595	opt_replyp = opt_reply;
1596	opt_replyend = opt_reply + OPT_REPLY_SIZE;
1597	*opt_replyp++ = IAC;
1598	*opt_replyp++ = SB;
1599	*opt_replyp++ = telopt_environ;
1600	*opt_replyp++ = TELQUAL_IS;
1601}
1602
1603	void
1604env_opt_start_info()
1605{
1606	env_opt_start();
1607	if (opt_replyp)
1608	    opt_replyp[-1] = TELQUAL_INFO;
1609}
1610
1611	void
1612env_opt_add(ep)
1613	register unsigned char *ep;
1614{
1615	register unsigned char *vp, c;
1616
1617	if (opt_reply == NULL)		/*XXX*/
1618		return;			/*XXX*/
1619
1620	if (ep == NULL || *ep == '\0') {
1621		/* Send user defined variables first. */
1622		env_default(1, 0);
1623		while (ep = env_default(0, 0))
1624			env_opt_add(ep);
1625
1626		/* Now add the list of well know variables.  */
1627		env_default(1, 1);
1628		while (ep = env_default(0, 1))
1629			env_opt_add(ep);
1630		return;
1631	}
1632	vp = env_getvalue(ep);
1633	if (opt_replyp + (vp ? strlen((char *)vp) : 0) +
1634				strlen((char *)ep) + 6 > opt_replyend)
1635	{
1636		register int len;
1637		opt_replyend += OPT_REPLY_SIZE;
1638		len = opt_replyend - opt_reply;
1639		opt_reply = (unsigned char *)realloc(opt_reply, len);
1640		if (opt_reply == NULL) {
1641/*@*/			printf("env_opt_add: realloc() failed!!!\n");
1642			opt_reply = opt_replyp = opt_replyend = NULL;
1643			return;
1644		}
1645		opt_replyp = opt_reply + len - (opt_replyend - opt_replyp);
1646		opt_replyend = opt_reply + len;
1647	}
1648	if (opt_welldefined(ep))
1649#ifdef	OLD_ENVIRON
1650		if (telopt_environ == TELOPT_OLD_ENVIRON)
1651			*opt_replyp++ = old_env_var;
1652		else
1653#endif
1654			*opt_replyp++ = NEW_ENV_VAR;
1655	else
1656		*opt_replyp++ = ENV_USERVAR;
1657	for (;;) {
1658		while (c = *ep++) {
1659			switch(c&0xff) {
1660			case IAC:
1661				*opt_replyp++ = IAC;
1662				break;
1663			case NEW_ENV_VAR:
1664			case NEW_ENV_VALUE:
1665			case ENV_ESC:
1666			case ENV_USERVAR:
1667				*opt_replyp++ = ENV_ESC;
1668				break;
1669			}
1670			*opt_replyp++ = c;
1671		}
1672		if (ep = vp) {
1673#ifdef	OLD_ENVIRON
1674			if (telopt_environ == TELOPT_OLD_ENVIRON)
1675				*opt_replyp++ = old_env_value;
1676			else
1677#endif
1678				*opt_replyp++ = NEW_ENV_VALUE;
1679			vp = NULL;
1680		} else
1681			break;
1682	}
1683}
1684
1685	int
1686opt_welldefined(ep)
1687	char *ep;
1688{
1689	if ((strcmp(ep, "USER") == 0) ||
1690	    (strcmp(ep, "DISPLAY") == 0) ||
1691	    (strcmp(ep, "PRINTER") == 0) ||
1692	    (strcmp(ep, "SYSTEMTYPE") == 0) ||
1693	    (strcmp(ep, "JOB") == 0) ||
1694	    (strcmp(ep, "ACCT") == 0))
1695		return(1);
1696	return(0);
1697}
1698	void
1699env_opt_end(emptyok)
1700	register int emptyok;
1701{
1702	register int len;
1703
1704	len = opt_replyp - opt_reply + 2;
1705	if (emptyok || len > 6) {
1706		*opt_replyp++ = IAC;
1707		*opt_replyp++ = SE;
1708		if (NETROOM() > len) {
1709			ring_supply_data(&netoring, opt_reply, len);
1710			printsub('>', &opt_reply[2], len - 2);
1711		}
1712/*@*/		else printf("slc_end_reply: not enough room\n");
1713	}
1714	if (opt_reply) {
1715		free(opt_reply);
1716		opt_reply = opt_replyp = opt_replyend = NULL;
1717	}
1718}
1719
1720
1721
1722    int
1723telrcv()
1724{
1725    register int c;
1726    register int scc;
1727    register unsigned char *sbp;
1728    int count;
1729    int returnValue = 0;
1730
1731    scc = 0;
1732    count = 0;
1733    while (TTYROOM() > 2) {
1734	if (scc == 0) {
1735	    if (count) {
1736		ring_consumed(&netiring, count);
1737		returnValue = 1;
1738		count = 0;
1739	    }
1740	    sbp = netiring.consume;
1741	    scc = ring_full_consecutive(&netiring);
1742	    if (scc == 0) {
1743		/* No more data coming in */
1744		break;
1745	    }
1746	}
1747
1748	c = *sbp++ & 0xff, scc--; count++;
1749#ifdef	ENCRYPTION
1750	if (decrypt_input)
1751		c = (*decrypt_input)(c);
1752#endif	/* ENCRYPTION */
1753
1754	switch (telrcv_state) {
1755
1756	case TS_CR:
1757	    telrcv_state = TS_DATA;
1758	    if (c == '\0') {
1759		break;	/* Ignore \0 after CR */
1760	    }
1761	    else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) {
1762		TTYADD(c);
1763		break;
1764	    }
1765	    /* Else, fall through */
1766
1767	case TS_DATA:
1768	    if (c == IAC) {
1769		telrcv_state = TS_IAC;
1770		break;
1771	    }
1772#	    if defined(TN3270)
1773	    if (In3270) {
1774		*Ifrontp++ = c;
1775		while (scc > 0) {
1776		    c = *sbp++ & 0377, scc--; count++;
1777#ifdef	ENCRYPTION
1778		    if (decrypt_input)
1779			c = (*decrypt_input)(c);
1780#endif	/* ENCRYPTION */
1781		    if (c == IAC) {
1782			telrcv_state = TS_IAC;
1783			break;
1784		    }
1785		    *Ifrontp++ = c;
1786		}
1787	    } else
1788#	    endif /* defined(TN3270) */
1789		    /*
1790		     * The 'crmod' hack (see following) is needed
1791		     * since we can't * set CRMOD on output only.
1792		     * Machines like MULTICS like to send \r without
1793		     * \n; since we must turn off CRMOD to get proper
1794		     * input, the mapping is done here (sigh).
1795		     */
1796	    if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) {
1797		if (scc > 0) {
1798		    c = *sbp&0xff;
1799#ifdef	ENCRYPTION
1800		    if (decrypt_input)
1801			c = (*decrypt_input)(c);
1802#endif	/* ENCRYPTION */
1803		    if (c == 0) {
1804			sbp++, scc--; count++;
1805			/* a "true" CR */
1806			TTYADD('\r');
1807		    } else if (my_want_state_is_dont(TELOPT_ECHO) &&
1808					(c == '\n')) {
1809			sbp++, scc--; count++;
1810			TTYADD('\n');
1811		    } else {
1812#ifdef	ENCRYPTION
1813			if (decrypt_input)
1814			    (*decrypt_input)(-1);
1815#endif	/* ENCRYPTION */
1816
1817			TTYADD('\r');
1818			if (crmod) {
1819				TTYADD('\n');
1820			}
1821		    }
1822		} else {
1823		    telrcv_state = TS_CR;
1824		    TTYADD('\r');
1825		    if (crmod) {
1826			    TTYADD('\n');
1827		    }
1828		}
1829	    } else {
1830		TTYADD(c);
1831	    }
1832	    continue;
1833
1834	case TS_IAC:
1835process_iac:
1836	    switch (c) {
1837
1838	    case WILL:
1839		telrcv_state = TS_WILL;
1840		continue;
1841
1842	    case WONT:
1843		telrcv_state = TS_WONT;
1844		continue;
1845
1846	    case DO:
1847		telrcv_state = TS_DO;
1848		continue;
1849
1850	    case DONT:
1851		telrcv_state = TS_DONT;
1852		continue;
1853
1854	    case DM:
1855		    /*
1856		     * We may have missed an urgent notification,
1857		     * so make sure we flush whatever is in the
1858		     * buffer currently.
1859		     */
1860		printoption("RCVD", IAC, DM);
1861		SYNCHing = 1;
1862		(void) ttyflush(1);
1863		SYNCHing = stilloob();
1864		settimer(gotDM);
1865		break;
1866
1867	    case SB:
1868		SB_CLEAR();
1869		telrcv_state = TS_SB;
1870		continue;
1871
1872#	    if defined(TN3270)
1873	    case EOR:
1874		if (In3270) {
1875		    if (Ibackp == Ifrontp) {
1876			Ibackp = Ifrontp = Ibuf;
1877			ISend = 0;	/* should have been! */
1878		    } else {
1879			Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1);
1880			ISend = 1;
1881		    }
1882		}
1883		printoption("RCVD", IAC, EOR);
1884		break;
1885#	    endif /* defined(TN3270) */
1886
1887	    case IAC:
1888#	    if !defined(TN3270)
1889		TTYADD(IAC);
1890#	    else /* !defined(TN3270) */
1891		if (In3270) {
1892		    *Ifrontp++ = IAC;
1893		} else {
1894		    TTYADD(IAC);
1895		}
1896#	    endif /* !defined(TN3270) */
1897		break;
1898
1899	    case NOP:
1900	    case GA:
1901	    default:
1902		printoption("RCVD", IAC, c);
1903		break;
1904	    }
1905	    telrcv_state = TS_DATA;
1906	    continue;
1907
1908	case TS_WILL:
1909	    printoption("RCVD", WILL, c);
1910	    willoption(c);
1911	    SetIn3270();
1912	    telrcv_state = TS_DATA;
1913	    continue;
1914
1915	case TS_WONT:
1916	    printoption("RCVD", WONT, c);
1917	    wontoption(c);
1918	    SetIn3270();
1919	    telrcv_state = TS_DATA;
1920	    continue;
1921
1922	case TS_DO:
1923	    printoption("RCVD", DO, c);
1924	    dooption(c);
1925	    SetIn3270();
1926	    if (c == TELOPT_NAWS) {
1927		sendnaws();
1928	    } else if (c == TELOPT_LFLOW) {
1929		localflow = 1;
1930		setcommandmode();
1931		setconnmode(0);
1932	    }
1933	    telrcv_state = TS_DATA;
1934	    continue;
1935
1936	case TS_DONT:
1937	    printoption("RCVD", DONT, c);
1938	    dontoption(c);
1939	    flushline = 1;
1940	    setconnmode(0);	/* set new tty mode (maybe) */
1941	    SetIn3270();
1942	    telrcv_state = TS_DATA;
1943	    continue;
1944
1945	case TS_SB:
1946	    if (c == IAC) {
1947		telrcv_state = TS_SE;
1948	    } else {
1949		SB_ACCUM(c);
1950	    }
1951	    continue;
1952
1953	case TS_SE:
1954	    if (c != SE) {
1955		if (c != IAC) {
1956		    /*
1957		     * This is an error.  We only expect to get
1958		     * "IAC IAC" or "IAC SE".  Several things may
1959		     * have happend.  An IAC was not doubled, the
1960		     * IAC SE was left off, or another option got
1961		     * inserted into the suboption are all possibilities.
1962		     * If we assume that the IAC was not doubled,
1963		     * and really the IAC SE was left off, we could
1964		     * get into an infinate loop here.  So, instead,
1965		     * we terminate the suboption, and process the
1966		     * partial suboption if we can.
1967		     */
1968		    SB_ACCUM(IAC);
1969		    SB_ACCUM(c);
1970		    subpointer -= 2;
1971		    SB_TERM();
1972
1973		    printoption("In SUBOPTION processing, RCVD", IAC, c);
1974		    suboption();	/* handle sub-option */
1975		    SetIn3270();
1976		    telrcv_state = TS_IAC;
1977		    goto process_iac;
1978		}
1979		SB_ACCUM(c);
1980		telrcv_state = TS_SB;
1981	    } else {
1982		SB_ACCUM(IAC);
1983		SB_ACCUM(SE);
1984		subpointer -= 2;
1985		SB_TERM();
1986		suboption();	/* handle sub-option */
1987		SetIn3270();
1988		telrcv_state = TS_DATA;
1989	    }
1990	}
1991    }
1992    if (count)
1993	ring_consumed(&netiring, count);
1994    return returnValue||count;
1995}
1996
1997static int bol = 1, local = 0;
1998
1999    int
2000rlogin_susp()
2001{
2002    if (local) {
2003	local = 0;
2004	bol = 1;
2005	command(0, "z\n", 2);
2006	return(1);
2007    }
2008    return(0);
2009}
2010
2011    static int
2012telsnd()
2013{
2014    int tcc;
2015    int count;
2016    int returnValue = 0;
2017    unsigned char *tbp;
2018
2019    tcc = 0;
2020    count = 0;
2021    while (NETROOM() > 2) {
2022	register int sc;
2023	register int c;
2024
2025	if (tcc == 0) {
2026	    if (count) {
2027		ring_consumed(&ttyiring, count);
2028		returnValue = 1;
2029		count = 0;
2030	    }
2031	    tbp = ttyiring.consume;
2032	    tcc = ring_full_consecutive(&ttyiring);
2033	    if (tcc == 0) {
2034		break;
2035	    }
2036	}
2037	c = *tbp++ & 0xff, sc = strip(c), tcc--; count++;
2038	if (rlogin != _POSIX_VDISABLE) {
2039		if (bol) {
2040			bol = 0;
2041			if (sc == rlogin) {
2042				local = 1;
2043				continue;
2044			}
2045		} else if (local) {
2046			local = 0;
2047			if (sc == '.' || c == termEofChar) {
2048				bol = 1;
2049				command(0, "close\n", 6);
2050				continue;
2051			}
2052			if (sc == termSuspChar) {
2053				bol = 1;
2054				command(0, "z\n", 2);
2055				continue;
2056			}
2057			if (sc == escape) {
2058				command(0, (char *)tbp, tcc);
2059				bol = 1;
2060				count += tcc;
2061				tcc = 0;
2062				flushline = 1;
2063				break;
2064			}
2065			if (sc != rlogin) {
2066				++tcc;
2067				--tbp;
2068				--count;
2069				c = sc = rlogin;
2070			}
2071		}
2072		if ((sc == '\n') || (sc == '\r'))
2073			bol = 1;
2074	} else if (sc == escape) {
2075	    /*
2076	     * Double escape is a pass through of a single escape character.
2077	     */
2078	    if (tcc && strip(*tbp) == escape) {
2079		tbp++;
2080		tcc--;
2081		count++;
2082		bol = 0;
2083	    } else {
2084		command(0, (char *)tbp, tcc);
2085		bol = 1;
2086		count += tcc;
2087		tcc = 0;
2088		flushline = 1;
2089		break;
2090	    }
2091	} else
2092	    bol = 0;
2093#ifdef	KLUDGELINEMODE
2094	if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) {
2095	    if (tcc > 0 && strip(*tbp) == echoc) {
2096		tcc--; tbp++; count++;
2097	    } else {
2098		dontlecho = !dontlecho;
2099		settimer(echotoggle);
2100		setconnmode(0);
2101		flushline = 1;
2102		break;
2103	    }
2104	}
2105#endif
2106	if (MODE_LOCAL_CHARS(globalmode)) {
2107	    if (TerminalSpecialChars(sc) == 0) {
2108		bol = 1;
2109		break;
2110	    }
2111	}
2112	if (my_want_state_is_wont(TELOPT_BINARY)) {
2113	    switch (c) {
2114	    case '\n':
2115		    /*
2116		     * If we are in CRMOD mode (\r ==> \n)
2117		     * on our local machine, then probably
2118		     * a newline (unix) is CRLF (TELNET).
2119		     */
2120		if (MODE_LOCAL_CHARS(globalmode)) {
2121		    NETADD('\r');
2122		}
2123		NETADD('\n');
2124		bol = flushline = 1;
2125		break;
2126	    case '\r':
2127		if (!crlf) {
2128		    NET2ADD('\r', '\0');
2129		} else {
2130		    NET2ADD('\r', '\n');
2131		}
2132		bol = flushline = 1;
2133		break;
2134	    case IAC:
2135		NET2ADD(IAC, IAC);
2136		break;
2137	    default:
2138		NETADD(c);
2139		break;
2140	    }
2141	} else if (c == IAC) {
2142	    NET2ADD(IAC, IAC);
2143	} else {
2144	    NETADD(c);
2145	}
2146    }
2147    if (count)
2148	ring_consumed(&ttyiring, count);
2149    return returnValue||count;		/* Non-zero if we did anything */
2150}
2151
2152/*
2153 * Scheduler()
2154 *
2155 * Try to do something.
2156 *
2157 * If we do something useful, return 1; else return 0.
2158 *
2159 */
2160
2161
2162    int
2163Scheduler(block)
2164    int	block;			/* should we block in the select ? */
2165{
2166		/* One wants to be a bit careful about setting returnValue
2167		 * to one, since a one implies we did some useful work,
2168		 * and therefore probably won't be called to block next
2169		 * time (TN3270 mode only).
2170		 */
2171    int returnValue;
2172    int netin, netout, netex, ttyin, ttyout;
2173
2174    /* Decide which rings should be processed */
2175
2176    netout = ring_full_count(&netoring) &&
2177	    (flushline ||
2178		(my_want_state_is_wont(TELOPT_LINEMODE)
2179#ifdef	KLUDGELINEMODE
2180			&& (!kludgelinemode || my_want_state_is_do(TELOPT_SGA))
2181#endif
2182		) ||
2183			my_want_state_is_will(TELOPT_BINARY));
2184    ttyout = ring_full_count(&ttyoring);
2185
2186#if	defined(TN3270)
2187    ttyin = ring_empty_count(&ttyiring) && (shell_active == 0);
2188#else	/* defined(TN3270) */
2189    ttyin = ring_empty_count(&ttyiring);
2190#endif	/* defined(TN3270) */
2191
2192#if	defined(TN3270)
2193    netin = ring_empty_count(&netiring);
2194#   else /* !defined(TN3270) */
2195    netin = !ISend && ring_empty_count(&netiring);
2196#   endif /* !defined(TN3270) */
2197
2198    netex = !SYNCHing;
2199
2200    /* If we have seen a signal recently, reset things */
2201#   if defined(TN3270) && defined(unix)
2202    if (HaveInput) {
2203	HaveInput = 0;
2204	(void) signal(SIGIO, inputAvailable);
2205    }
2206#endif	/* defined(TN3270) && defined(unix) */
2207
2208    /* Call to system code to process rings */
2209
2210    returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block);
2211
2212    /* Now, look at the input rings, looking for work to do. */
2213
2214    if (ring_full_count(&ttyiring)) {
2215#   if defined(TN3270)
2216	if (In3270) {
2217	    int c;
2218
2219	    c = DataFromTerminal(ttyiring.consume,
2220					ring_full_consecutive(&ttyiring));
2221	    if (c) {
2222		returnValue = 1;
2223		ring_consumed(&ttyiring, c);
2224	    }
2225	} else {
2226#   endif /* defined(TN3270) */
2227	    returnValue |= telsnd();
2228#   if defined(TN3270)
2229	}
2230#   endif /* defined(TN3270) */
2231    }
2232
2233    if (ring_full_count(&netiring)) {
2234#	if !defined(TN3270)
2235	returnValue |= telrcv();
2236#	else /* !defined(TN3270) */
2237	returnValue = Push3270();
2238#	endif /* !defined(TN3270) */
2239    }
2240    return returnValue;
2241}
2242
2243/*
2244 * Select from tty and network...
2245 */
2246    void
2247telnet(user)
2248    char *user;
2249{
2250    sys_telnet_init();
2251
2252#if	defined(AUTHENTICATION) || defined(ENCRYPTION)
2253    {
2254	static char local_host[256] = { 0 };
2255
2256	if (!local_host[0]) {
2257		gethostname(local_host, sizeof(local_host));
2258		local_host[sizeof(local_host)-1] = 0;
2259	}
2260	auth_encrypt_init(local_host, hostname, "TELNET", 0);
2261	auth_encrypt_user(user);
2262    }
2263#endif	/* defined(AUTHENTICATION) || defined(ENCRYPTION)  */
2264#   if !defined(TN3270)
2265    if (telnetport) {
2266#if	defined(AUTHENTICATION)
2267	if (autologin)
2268		send_will(TELOPT_AUTHENTICATION, 1);
2269#endif
2270#ifdef	ENCRYPTION
2271	send_do(TELOPT_ENCRYPT, 1);
2272	send_will(TELOPT_ENCRYPT, 1);
2273#endif	/* ENCRYPTION */
2274	send_do(TELOPT_SGA, 1);
2275	send_will(TELOPT_TTYPE, 1);
2276	send_will(TELOPT_NAWS, 1);
2277	send_will(TELOPT_TSPEED, 1);
2278	send_will(TELOPT_LFLOW, 1);
2279	send_will(TELOPT_LINEMODE, 1);
2280	send_will(TELOPT_NEW_ENVIRON, 1);
2281	send_do(TELOPT_STATUS, 1);
2282	if (env_getvalue((unsigned char *)"DISPLAY"))
2283	    send_will(TELOPT_XDISPLOC, 1);
2284	if (eight)
2285	    tel_enter_binary(eight);
2286    }
2287#   endif /* !defined(TN3270) */
2288
2289#   if !defined(TN3270)
2290    for (;;) {
2291	int schedValue;
2292
2293	while ((schedValue = Scheduler(0)) != 0) {
2294	    if (schedValue == -1) {
2295		setcommandmode();
2296		return;
2297	    }
2298	}
2299
2300	if (Scheduler(1) == -1) {
2301	    setcommandmode();
2302	    return;
2303	}
2304    }
2305#   else /* !defined(TN3270) */
2306    for (;;) {
2307	int schedValue;
2308
2309	while (!In3270 && !shell_active) {
2310	    if (Scheduler(1) == -1) {
2311		setcommandmode();
2312		return;
2313	    }
2314	}
2315
2316	while ((schedValue = Scheduler(0)) != 0) {
2317	    if (schedValue == -1) {
2318		setcommandmode();
2319		return;
2320	    }
2321	}
2322		/* If there is data waiting to go out to terminal, don't
2323		 * schedule any more data for the terminal.
2324		 */
2325	if (ring_full_count(&ttyoring)) {
2326	    schedValue = 1;
2327	} else {
2328	    if (shell_active) {
2329		if (shell_continue() == 0) {
2330		    ConnectScreen();
2331		}
2332	    } else if (In3270) {
2333		schedValue = DoTerminalOutput();
2334	    }
2335	}
2336	if (schedValue && (shell_active == 0)) {
2337	    if (Scheduler(1) == -1) {
2338		setcommandmode();
2339		return;
2340	    }
2341	}
2342    }
2343#   endif /* !defined(TN3270) */
2344}
2345
2346#if	0	/* XXX - this not being in is a bug */
2347/*
2348 * nextitem()
2349 *
2350 *	Return the address of the next "item" in the TELNET data
2351 * stream.  This will be the address of the next character if
2352 * the current address is a user data character, or it will
2353 * be the address of the character following the TELNET command
2354 * if the current address is a TELNET IAC ("I Am a Command")
2355 * character.
2356 */
2357
2358    static char *
2359nextitem(current)
2360    char *current;
2361{
2362    if ((*current&0xff) != IAC) {
2363	return current+1;
2364    }
2365    switch (*(current+1)&0xff) {
2366    case DO:
2367    case DONT:
2368    case WILL:
2369    case WONT:
2370	return current+3;
2371    case SB:		/* loop forever looking for the SE */
2372	{
2373	    register char *look = current+2;
2374
2375	    for (;;) {
2376		if ((*look++&0xff) == IAC) {
2377		    if ((*look++&0xff) == SE) {
2378			return look;
2379		    }
2380		}
2381	    }
2382	}
2383    default:
2384	return current+2;
2385    }
2386}
2387#endif	/* 0 */
2388
2389/*
2390 * netclear()
2391 *
2392 *	We are about to do a TELNET SYNCH operation.  Clear
2393 * the path to the network.
2394 *
2395 *	Things are a bit tricky since we may have sent the first
2396 * byte or so of a previous TELNET command into the network.
2397 * So, we have to scan the network buffer from the beginning
2398 * until we are up to where we want to be.
2399 *
2400 *	A side effect of what we do, just to keep things
2401 * simple, is to clear the urgent data pointer.  The principal
2402 * caller should be setting the urgent data pointer AFTER calling
2403 * us in any case.
2404 */
2405
2406    static void
2407netclear()
2408{
2409#if	0	/* XXX */
2410    register char *thisitem, *next;
2411    char *good;
2412#define	wewant(p)	((nfrontp > p) && ((*p&0xff) == IAC) && \
2413				((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
2414
2415    thisitem = netobuf;
2416
2417    while ((next = nextitem(thisitem)) <= netobuf.send) {
2418	thisitem = next;
2419    }
2420
2421    /* Now, thisitem is first before/at boundary. */
2422
2423    good = netobuf;	/* where the good bytes go */
2424
2425    while (netoring.add > thisitem) {
2426	if (wewant(thisitem)) {
2427	    int length;
2428
2429	    next = thisitem;
2430	    do {
2431		next = nextitem(next);
2432	    } while (wewant(next) && (nfrontp > next));
2433	    length = next-thisitem;
2434	    memmove(good, thisitem, length);
2435	    good += length;
2436	    thisitem = next;
2437	} else {
2438	    thisitem = nextitem(thisitem);
2439	}
2440    }
2441
2442#endif	/* 0 */
2443}
2444
2445/*
2446 * These routines add various telnet commands to the data stream.
2447 */
2448
2449    static void
2450doflush()
2451{
2452    NET2ADD(IAC, DO);
2453    NETADD(TELOPT_TM);
2454    flushline = 1;
2455    flushout = 1;
2456    (void) ttyflush(1);			/* Flush/drop output */
2457    /* do printoption AFTER flush, otherwise the output gets tossed... */
2458    printoption("SENT", DO, TELOPT_TM);
2459}
2460
2461    void
2462xmitAO()
2463{
2464    NET2ADD(IAC, AO);
2465    printoption("SENT", IAC, AO);
2466    if (autoflush) {
2467	doflush();
2468    }
2469}
2470
2471
2472    void
2473xmitEL()
2474{
2475    NET2ADD(IAC, EL);
2476    printoption("SENT", IAC, EL);
2477}
2478
2479    void
2480xmitEC()
2481{
2482    NET2ADD(IAC, EC);
2483    printoption("SENT", IAC, EC);
2484}
2485
2486
2487    int
2488dosynch()
2489{
2490    netclear();			/* clear the path to the network */
2491    NETADD(IAC);
2492    setneturg();
2493    NETADD(DM);
2494    printoption("SENT", IAC, DM);
2495    return 1;
2496}
2497
2498int want_status_response = 0;
2499
2500    int
2501get_status()
2502{
2503    unsigned char tmp[16];
2504    register unsigned char *cp;
2505
2506    if (my_want_state_is_dont(TELOPT_STATUS)) {
2507	printf("Remote side does not support STATUS option\n");
2508	return 0;
2509    }
2510    cp = tmp;
2511
2512    *cp++ = IAC;
2513    *cp++ = SB;
2514    *cp++ = TELOPT_STATUS;
2515    *cp++ = TELQUAL_SEND;
2516    *cp++ = IAC;
2517    *cp++ = SE;
2518    if (NETROOM() >= cp - tmp) {
2519	ring_supply_data(&netoring, tmp, cp-tmp);
2520	printsub('>', tmp+2, cp - tmp - 2);
2521    }
2522    ++want_status_response;
2523    return 1;
2524}
2525
2526    void
2527intp()
2528{
2529    NET2ADD(IAC, IP);
2530    printoption("SENT", IAC, IP);
2531    flushline = 1;
2532    if (autoflush) {
2533	doflush();
2534    }
2535    if (autosynch) {
2536	dosynch();
2537    }
2538}
2539
2540    void
2541sendbrk()
2542{
2543    NET2ADD(IAC, BREAK);
2544    printoption("SENT", IAC, BREAK);
2545    flushline = 1;
2546    if (autoflush) {
2547	doflush();
2548    }
2549    if (autosynch) {
2550	dosynch();
2551    }
2552}
2553
2554    void
2555sendabort()
2556{
2557    NET2ADD(IAC, ABORT);
2558    printoption("SENT", IAC, ABORT);
2559    flushline = 1;
2560    if (autoflush) {
2561	doflush();
2562    }
2563    if (autosynch) {
2564	dosynch();
2565    }
2566}
2567
2568    void
2569sendsusp()
2570{
2571    NET2ADD(IAC, SUSP);
2572    printoption("SENT", IAC, SUSP);
2573    flushline = 1;
2574    if (autoflush) {
2575	doflush();
2576    }
2577    if (autosynch) {
2578	dosynch();
2579    }
2580}
2581
2582    void
2583sendeof()
2584{
2585    NET2ADD(IAC, xEOF);
2586    printoption("SENT", IAC, xEOF);
2587}
2588
2589    void
2590sendayt()
2591{
2592    NET2ADD(IAC, AYT);
2593    printoption("SENT", IAC, AYT);
2594}
2595
2596/*
2597 * Send a window size update to the remote system.
2598 */
2599
2600    void
2601sendnaws()
2602{
2603    long rows, cols;
2604    unsigned char tmp[16];
2605    register unsigned char *cp;
2606
2607    if (my_state_is_wont(TELOPT_NAWS))
2608	return;
2609
2610#define	PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \
2611			    if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; }
2612
2613    if (TerminalWindowSize(&rows, &cols) == 0) {	/* Failed */
2614	return;
2615    }
2616
2617    cp = tmp;
2618
2619    *cp++ = IAC;
2620    *cp++ = SB;
2621    *cp++ = TELOPT_NAWS;
2622    PUTSHORT(cp, cols);
2623    PUTSHORT(cp, rows);
2624    *cp++ = IAC;
2625    *cp++ = SE;
2626    if (NETROOM() >= cp - tmp) {
2627	ring_supply_data(&netoring, tmp, cp-tmp);
2628	printsub('>', tmp+2, cp - tmp - 2);
2629    }
2630}
2631
2632    void
2633tel_enter_binary(rw)
2634    int rw;
2635{
2636    if (rw&1)
2637	send_do(TELOPT_BINARY, 1);
2638    if (rw&2)
2639	send_will(TELOPT_BINARY, 1);
2640}
2641
2642    void
2643tel_leave_binary(rw)
2644    int rw;
2645{
2646    if (rw&1)
2647	send_dont(TELOPT_BINARY, 1);
2648    if (rw&2)
2649	send_wont(TELOPT_BINARY, 1);
2650}
2651