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