xref: /original-bsd/usr.bin/telnet/telnet.c (revision 780b584d)
1 /*
2  * Copyright (c) 1988 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #ifndef lint
19 static char sccsid[] = "@(#)telnet.c	5.44 (Berkeley) 11/14/89";
20 #endif /* not lint */
21 
22 #include <sys/types.h>
23 
24 #if	defined(unix)
25 #include <signal.h>
26 /* By the way, we need to include curses.h before telnet.h since,
27  * among other things, telnet.h #defines 'DO', which is a variable
28  * declared in curses.h.
29  */
30 #endif	/* defined(unix) */
31 
32 #include <arpa/telnet.h>
33 
34 #if	defined(unix)
35 #include <strings.h>
36 #else	/* defined(unix) */
37 #include <string.h>
38 #endif	/* defined(unix) */
39 
40 #include <ctype.h>
41 
42 #include "ring.h"
43 
44 #include "defines.h"
45 #include "externs.h"
46 #include "types.h"
47 #include "general.h"
48 
49 
50 #define	strip(x)	((x)&0x7f)
51 
52 
53 static char	subbuffer[SUBBUFSIZE],
54 		*subpointer, *subend;	 /* buffer for sub-options */
55 #define	SB_CLEAR()	subpointer = subbuffer;
56 #define	SB_TERM()	subend = subpointer;
57 #define	SB_ACCUM(c)	if (subpointer < (subbuffer+sizeof subbuffer)) { \
58 				*subpointer++ = (c); \
59 			}
60 
61 char	options[256];		/* The combined options */
62 char	do_dont_resp[256];
63 char	will_wont_resp[256];
64 
65 int
66 	connected,
67 	showoptions,
68 	In3270,		/* Are we in 3270 mode? */
69 	ISend,		/* trying to send network data in */
70 	debug = 0,
71 	crmod,
72 	netdata,	/* Print out network data flow */
73 	crlf,		/* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
74 #if	defined(TN3270)
75 	noasynchtty = 0,/* User specified "-noasynch" on command line */
76 	noasynchnet = 0,/* User specified "-noasynch" on command line */
77 	askedSGA = 0,	/* We have talked about suppress go ahead */
78 #endif	/* defined(TN3270) */
79 	telnetport,
80 	SYNCHing,	/* we are in TELNET SYNCH mode */
81 	flushout,	/* flush output */
82 	autoflush = 0,	/* flush output when interrupting? */
83 	autosynch,	/* send interrupt characters with SYNCH? */
84 	localflow,	/* we handle flow control locally */
85 	localchars,	/* we recognize interrupt/quit */
86 	donelclchars,	/* the user has set "localchars" */
87 	donebinarytoggle,	/* the user has put us in binary */
88 	dontlecho,	/* do we suppress local echoing right now? */
89 	globalmode;
90 
91 #define	CONTROL(x)	((x)&0x1f)		/* CTRL(x) is not portable */
92 
93 unsigned char
94 	*prompt = 0,
95 	escape,
96 	echoc;
97 
98 /*
99  * Telnet receiver states for fsm
100  */
101 #define	TS_DATA		0
102 #define	TS_IAC		1
103 #define	TS_WILL		2
104 #define	TS_WONT		3
105 #define	TS_DO		4
106 #define	TS_DONT		5
107 #define	TS_CR		6
108 #define	TS_SB		7		/* sub-option collection */
109 #define	TS_SE		8		/* looking for sub-option end */
110 
111 static int	telrcv_state;
112 
113 jmp_buf	toplevel = { 0 };
114 jmp_buf	peerdied;
115 
116 int	flushline;
117 int	linemode;
118 
119 #ifdef	KLUDGELINEMODE
120 int	kludgelinemode = 1;
121 #endif
122 
123 /*
124  * The following are some clocks used to decide how to interpret
125  * the relationship between various variables.
126  */
127 
128 Clocks clocks;
129 
130 #ifdef	notdef
131 Modelist modelist[] = {
132 	{ "telnet command mode", COMMAND_LINE },
133 	{ "character-at-a-time mode", 0 },
134 	{ "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS },
135 	{ "line-by-line mode (remote echo)", LINE | LOCAL_CHARS },
136 	{ "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS },
137 	{ "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS },
138 	{ "3270 mode", 0 },
139 };
140 #endif
141 
142 
143 /*
144  * Initialize telnet environment.
145  */
146 
147 init_telnet()
148 {
149     SB_CLEAR();
150     ClearArray(options);
151 
152     connected = In3270 = ISend = localflow = donebinarytoggle = 0;
153 
154     SYNCHing = 0;
155 
156     /* Don't change NetTrace */
157 
158     escape = CONTROL(']');
159     echoc = CONTROL('E');
160 
161     flushline = 1;
162     telrcv_state = TS_DATA;
163 }
164 
165 
166 #include <varargs.h>
167 
168 /*VARARGS*/
169 static void
170 printring(va_alist)
171 va_dcl
172 {
173     va_list ap;
174     char buffer[100];		/* where things go */
175     char *ptr;
176     char *format;
177     char *string;
178     Ring *ring;
179     int i;
180 
181     va_start(ap);
182 
183     ring = va_arg(ap, Ring *);
184     format = va_arg(ap, char *);
185     ptr = buffer;
186 
187     while ((i = *format++) != 0) {
188 	if (i == '%') {
189 	    i = *format++;
190 	    switch (i) {
191 	    case 'c':
192 		*ptr++ = va_arg(ap, int);
193 		break;
194 	    case 's':
195 		string = va_arg(ap, char *);
196 		ring_supply_data(ring, buffer, ptr-buffer);
197 		ring_supply_data(ring, string, strlen(string));
198 		ptr = buffer;
199 		break;
200 	    case 0:
201 		ExitString("printring: trailing %%.\n", 1);
202 		/*NOTREACHED*/
203 	    default:
204 		ExitString("printring: unknown format character.\n", 1);
205 		/*NOTREACHED*/
206 	    }
207 	} else {
208 	    *ptr++ = i;
209 	}
210     }
211     ring_supply_data(ring, buffer, ptr-buffer);
212 }
213 
214 /*
215  * These routines are in charge of sending option negotiations
216  * to the other side.
217  *
218  * The basic idea is that we send the negotiation if either side
219  * is in disagreement as to what the current state should be.
220  */
221 
222 send_do(c, init)
223 register int c, init;
224 {
225     if (init) {
226 	if (((do_dont_resp[c] == 0) && my_state_is_do(c)) ||
227 				my_want_state_is_do(c))
228 	    return;
229 	set_my_want_state_do(c);
230 	do_dont_resp[c]++;
231     }
232     NET2ADD(IAC, DO);
233     NETADD(c);
234     printoption("SENT", "do", c);
235 }
236 
237 void
238 send_dont(c, init)
239 register int c, init;
240 {
241     if (init) {
242 	if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) ||
243 				my_want_state_is_dont(c))
244 	    return;
245 	set_my_want_state_dont(c);
246 	do_dont_resp[c]++;
247     }
248     NET2ADD(IAC, DONT);
249     NETADD(c);
250     printoption("SENT", "dont", c);
251 }
252 
253 void
254 send_will(c, init)
255 register int c, init;
256 {
257     if (init) {
258 	if (((will_wont_resp[c] == 0) && my_state_is_will(c)) ||
259 				my_want_state_is_will(c))
260 	    return;
261 	set_my_want_state_will(c);
262 	will_wont_resp[c]++;
263     }
264     NET2ADD(IAC, WILL);
265     NETADD(c);
266     printoption("SENT", "will", c);
267 }
268 
269 void
270 send_wont(c, init)
271 register int c, init;
272 {
273     if (init) {
274 	if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) ||
275 				my_want_state_is_wont(c))
276 	    return;
277 	set_my_want_state_wont(c);
278 	will_wont_resp[c]++;
279     }
280     NET2ADD(IAC, WONT);
281     NETADD(c);
282     printoption("SENT", "wont", c);
283 }
284 
285 
286 void
287 willoption(option)
288 	int option;
289 {
290 	char *fmt;
291 	int new_state_ok = 0;
292 
293 	if (do_dont_resp[option]) {
294 	    --do_dont_resp[option];
295 	    if (do_dont_resp[option] && my_state_is_do(option))
296 		--do_dont_resp[option];
297 	}
298 
299 	if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) {
300 
301 	    switch (option) {
302 
303 	    case TELOPT_ECHO:
304 #	    if defined(TN3270)
305 		/*
306 		 * The following is a pain in the rear-end.
307 		 * Various IBM servers (some versions of Wiscnet,
308 		 * possibly Fibronics/Spartacus, and who knows who
309 		 * else) will NOT allow us to send "DO SGA" too early
310 		 * in the setup proceedings.  On the other hand,
311 		 * 4.2 servers (telnetd) won't set SGA correctly.
312 		 * So, we are stuck.  Empirically (but, based on
313 		 * a VERY small sample), the IBM servers don't send
314 		 * out anything about ECHO, so we postpone our sending
315 		 * "DO SGA" until we see "WILL ECHO" (which 4.2 servers
316 		 * DO send).
317 		  */
318 		{
319 		    if (askedSGA == 0) {
320 			askedSGA = 1;
321 			if (my_want_state_is_dont(TELOPT_SGA))
322 			    send_do(TELOPT_SGA, 1);
323 		    }
324 		}
325 		    /* Fall through */
326 	    case TELOPT_EOR:
327 #endif	    /* defined(TN3270) */
328 	    case TELOPT_BINARY:
329 	    case TELOPT_SGA:
330 		settimer(modenegotiated);
331 		/* FALL THROUGH */
332 	    case TELOPT_STATUS:
333 		new_state_ok = 1;
334 		break;
335 
336 	    case TELOPT_TM:
337 		if (flushout)
338 		    flushout = 0;
339 		/*
340 		 * Special case for TM.  If we get back a WILL,
341 		 * pretend we got back a WONT.
342 		 */
343 		set_my_want_state_dont(option);
344 		set_my_state_dont(option);
345 		return;			/* Never reply to TM will's/wont's */
346 
347 	    case TELOPT_LINEMODE:
348 	    default:
349 		break;
350 	    }
351 
352 	    if (new_state_ok) {
353 		set_my_want_state_do(option);
354 		send_do(option, 0);
355 		setconnmode(0);		/* possibly set new tty mode */
356 	    } else {
357 		do_dont_resp[option]++;
358 		send_dont(option, 0);
359 	    }
360 	}
361 	set_my_state_do(option);
362 }
363 
364 void
365 wontoption(option)
366 	int option;
367 {
368 	char *fmt;
369 
370 	if (do_dont_resp[option]) {
371 	    --do_dont_resp[option];
372 	    if (do_dont_resp[option] && my_state_is_dont(option))
373 		--do_dont_resp[option];
374 	}
375 
376 	if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) {
377 
378 	    switch (option) {
379 
380 #ifdef	KLUDGELINEMODE
381 	    case TELOPT_SGA:
382 		if (!kludgelinemode)
383 		    break;
384 		/* FALL THROUGH */
385 #endif
386 	    case TELOPT_ECHO:
387 		settimer(modenegotiated);
388 		break;
389 
390 	    case TELOPT_TM:
391 		if (flushout)
392 		    flushout = 0;
393 		set_my_want_state_dont(option);
394 		set_my_state_dont(option);
395 		return;		/* Never reply to TM will's/wont's */
396 
397 	    default:
398 		break;
399 	    }
400 	    set_my_want_state_dont(option);
401 	    send_dont(option, 0);
402 	    setconnmode(0);			/* Set new tty mode */
403 	} else if (option == TELOPT_TM) {
404 	    /*
405 	     * Special case for TM.
406 	     */
407 	    if (flushout)
408 		flushout = 0;
409 	    set_my_want_state_dont(option);
410 	}
411 	set_my_state_dont(option);
412 }
413 
414 static void
415 dooption(option)
416 	int option;
417 {
418 	char *fmt;
419 	int new_state_ok = 0;
420 
421 	if (will_wont_resp[option]) {
422 	    --will_wont_resp[option];
423 	    if (will_wont_resp[option] && my_state_is_will(option))
424 		--will_wont_resp[option];
425 	}
426 
427 	if (will_wont_resp[option] == 0) {
428 	  if (my_want_state_is_wont(option)) {
429 
430 	    switch (option) {
431 
432 	    case TELOPT_TM:
433 		/*
434 		 * Special case for TM.  We send a WILL, but pretend
435 		 * we sent WONT.
436 		 */
437 		send_will(option, 0);
438 		set_my_want_state_wont(TELOPT_TM);
439 		set_my_state_wont(TELOPT_TM);
440 		return;
441 
442 #	if defined(TN3270)
443 	    case TELOPT_EOR:		/* end of record */
444 #	endif	/* defined(TN3270) */
445 	    case TELOPT_BINARY:		/* binary mode */
446 	    case TELOPT_NAWS:		/* window size */
447 	    case TELOPT_TSPEED:		/* terminal speed */
448 	    case TELOPT_LFLOW:		/* local flow control */
449 	    case TELOPT_TTYPE:		/* terminal type option */
450 	    case TELOPT_SGA:		/* no big deal */
451 		new_state_ok = 1;
452 		break;
453 
454 	    case TELOPT_LINEMODE:
455 #ifdef	KLUDGELINEMODE
456 		kludgelinemode = 0;
457 #endif
458 		set_my_want_state_will(TELOPT_LINEMODE);
459 		send_will(option, 0);
460 		set_my_state_will(TELOPT_LINEMODE);
461 		slc_init();
462 		return;
463 
464 	    case TELOPT_ECHO:		/* We're never going to echo... */
465 	    default:
466 		break;
467 	    }
468 
469 	    if (new_state_ok) {
470 		set_my_want_state_will(option);
471 		send_will(option, 0);
472 	    } else {
473 		will_wont_resp[option]++;
474 		send_wont(option, 0);
475 	    }
476 	  } else {
477 	    /*
478 	     * Handle options that need more things done after the
479 	     * other side has acknowledged the option.
480 	     */
481 	    switch (option) {
482 	    case TELOPT_LINEMODE:
483 #ifdef	KLUDGELINEMODE
484 		kludgelinemode = 0;
485 #endif
486 		set_my_state_will(option);
487 		slc_init();
488 		return;
489 	    }
490 	  }
491 	}
492 	set_my_state_will(option);
493 }
494 
495 static void
496 dontoption(option)
497 	int option;
498 {
499 
500 	if (will_wont_resp[option]) {
501 	    --will_wont_resp[option];
502 	    if (will_wont_resp[option] && my_state_is_wont(option))
503 		--will_wont_resp[option];
504 	}
505 
506 	if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) {
507 	    switch (option) {
508 	    case TELOPT_LINEMODE:
509 		linemode = 0;	/* put us back to the default state */
510 		break;
511 	    }
512 	    /* we always accept a DONT */
513 	    set_my_want_state_wont(option);
514 	    send_wont(option, 0);
515 	    setconnmode(0);			/* Set new tty mode */
516 	}
517 	set_my_state_wont(option);
518 }
519 
520 /*
521  * Given a buffer returned by tgetent(), this routine will turn
522  * the pipe seperated list of names in the buffer into an array
523  * of pointers to null terminated names.  We toss out any bad,
524  * duplicate, or verbose names (names with spaces).
525  */
526 
527 static char *unknown[] = { "UNKNOWN", 0 };
528 
529 char **
530 mklist(buf, name)
531 char *buf, *name;
532 {
533 	register int n;
534 	register char c, *cp, **argvp, *cp2, **argv;
535 	char *malloc();
536 
537 	if (name) {
538 		if (strlen(name) > 40)
539 			name = 0;
540 		else {
541 			unknown[0] = name;
542 			upcase(name);
543 		}
544 	}
545 	/*
546 	 * Count up the number of names.
547 	 */
548 	for (n = 1, cp = buf; *cp && *cp != ':'; cp++) {
549 		if (*cp == '|')
550 			n++;
551 	}
552 	/*
553 	 * Allocate an array to put the name pointers into
554 	 */
555 	argv = (char **)malloc((n+3)*sizeof(char *));
556 	if (argv == 0)
557 		return(unknown);
558 
559 	/*
560 	 * Fill up the array of pointers to names.
561 	 */
562 	*argv = 0;
563 	argvp = argv+1;
564 	n = 0;
565 	for (cp = cp2 = buf; (c = *cp);  cp++) {
566 		if (c == '|' || c == ':') {
567 			*cp++ = '\0';
568 			/*
569 			 * Skip entries that have spaces or are over 40
570 			 * characters long.  If this is our environment
571 			 * name, then put it up front.  Otherwise, as
572 			 * long as this is not a duplicate name (case
573 			 * insensitive) add it to the list.
574 			 */
575 			if (n || (cp - cp2 > 41))
576 				;
577 			else if (name && (strncasecmp(name, cp2, cp-cp2) == 0))
578 				*argv = cp2;
579 			else if (is_unique(cp2, argv+1, argvp))
580 				*argvp++ = cp2;
581 			if (c == ':')
582 				break;
583 			/*
584 			 * Skip multiple delimiters. Reset cp2 to
585 			 * the beginning of the next name. Reset n,
586 			 * the flag for names with spaces.
587 			 */
588 			while ((c = *cp) == '|')
589 				cp++;
590 			cp2 = cp;
591 			n = 0;
592 		}
593 		/*
594 		 * Skip entries with spaces or non-ascii values.
595 		 * Convert lower case letters to upper case.
596 		 */
597 		if ((c == ' ') || !isascii(c))
598 			n = 1;
599 		else if (islower(c))
600 			*cp = toupper(c);
601 	}
602 
603 	/*
604 	 * Check for an old V6 2 character name.  If the second
605 	 * name points to the beginning of the buffer, and is
606 	 * only 2 characters long, move it to the end of the array.
607 	 */
608 	if ((argv[1] == buf) && (strlen(argv[1]) == 2)) {
609 		*argvp++ = buf;
610 		cp = *argv++;
611 		*argv = cp;
612 	}
613 
614 	/*
615 	 * Duplicate last name, for TTYPE option, and null
616 	 * terminate the array.  If we didn't find a match on
617 	 * our terminal name, put that name at the beginning.
618 	 */
619 	cp = *(argvp-1);
620 	*argvp++ = cp;
621 	*argvp = 0;
622 
623 	if (*argv == 0) {
624 		if (name)
625 			*argv = name;
626 		else
627 			argv++;
628 	}
629 	if (*argv)
630 		return(argv);
631 	else
632 		return(unknown);
633 }
634 
635 is_unique(name, as, ae)
636 register char *name, **as, **ae;
637 {
638 	register char **ap;
639 	register int n;
640 
641 	n = strlen(name) + 1;
642 	for (ap = as; ap < ae; ap++)
643 		if (strncasecmp(*ap, name, n) == 0)
644 			return(0);
645 	return (1);
646 }
647 
648 #ifdef	TERMCAP
649 char termbuf[1024];
650 setupterm(tname, fd, errp)
651 char *tname;
652 int fd, *errp;
653 {
654 	if (tgetent(termbuf, tname) == 1) {
655 		termbuf[1023] = '\0';
656 		if (errp)
657 			*errp = 1;
658 		return(0);
659 	}
660 	if (errp)
661 		*errp = 0;
662 	return(-1);
663 }
664 #else
665 #define	termbuf	ttytype
666 extern char ttytype[];
667 #endif
668 
669 char *
670 gettermname()
671 {
672 	char *tname;
673 	static int first = 1;
674 	static char **tnamep;
675 	static char **next;
676 	char *getenv();
677 	int err;
678 
679 	if (first) {
680 		first = 0;
681 		if ((tname = getenv("TERM")) &&
682 				(setupterm(tname, 1, &err) == 0)) {
683 			tnamep = mklist(termbuf, tname);
684 		} else {
685 			if (tname && (strlen(tname) <= 40)) {
686 				unknown[0] = tname;
687 				upcase(tname);
688 			}
689 			tnamep = unknown;
690 		}
691 		next = tnamep;
692 	}
693 	if (*next == 0)
694 		next = tnamep;
695 	return(*next++);
696 }
697 /*
698  * suboption()
699  *
700  *	Look at the sub-option buffer, and try to be helpful to the other
701  * side.
702  *
703  *	Currently we recognize:
704  *
705  *		Terminal type, send request.
706  *		Terminal speed (send request).
707  *		Local flow control (is request).
708  *		Linemode
709  */
710 
711 static void
712 suboption()
713 {
714     printsub('<', subbuffer, subend-subbuffer+2);
715     switch (subbuffer[0]&0xff) {
716     case TELOPT_TTYPE:
717 	if (my_want_state_is_wont(TELOPT_TTYPE))
718 	    return;
719 	if ((subbuffer[1]&0xff) != TELQUAL_SEND) {
720 	    ;
721 	} else {
722 	    char *name;
723 	    extern char *getenv();
724 	    char temp[50];
725 	    int len;
726 
727 #if	defined(TN3270)
728 	    if (tn3270_ttype()) {
729 		return;
730 	    }
731 #endif	/* defined(TN3270) */
732 	    name = gettermname();
733 	    len = strlen(name) + 4 + 2;
734 	    if (len < NETROOM()) {
735 		sprintf(temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
736 				TELQUAL_IS, name, IAC, SE);
737 		ring_supply_data(&netoring, temp, len);
738 		printsub('>', &temp[2], len-2);
739 	    } else {
740 		ExitString("No room in buffer for terminal type.\n", 1);
741 		/*NOTREACHED*/
742 	    }
743 	}
744 	break;
745     case TELOPT_TSPEED:
746 	if (my_want_state_is_wont(TELOPT_TSPEED))
747 	    return;
748 	if ((subbuffer[1]&0xff) == TELQUAL_SEND) {
749 	    long ospeed,ispeed;
750 	    char temp[50];
751 	    int len;
752 
753 	    TerminalSpeeds(&ispeed, &ospeed);
754 
755 	    sprintf(temp, "%c%c%c%c%d,%d%c%c", IAC, SB, TELOPT_TSPEED,
756 		    TELQUAL_IS, ospeed, ispeed, IAC, SE);
757 	    len = strlen(temp+4) + 4;	/* temp[3] is 0 ... */
758 
759 	    if (len < NETROOM()) {
760 		ring_supply_data(&netoring, temp, len);
761 		printsub('>', temp+2, len - 2);
762 	    }
763 	}
764 	break;
765     case TELOPT_LFLOW:
766 	if (my_want_state_is_wont(TELOPT_LFLOW))
767 	    return;
768 	if ((subbuffer[1]&0xff) == 1) {
769 	    localflow = 1;
770 	} else if ((subbuffer[1]&0xff) == 0) {
771 	    localflow = 0;
772 	}
773 	setcommandmode();
774 	setconnmode(0);
775 	break;
776 
777     case TELOPT_LINEMODE:
778 	if (my_want_state_is_wont(TELOPT_LINEMODE))
779 	    return;
780 	switch (subbuffer[1]&0xff) {
781 	case WILL:
782 	    lm_will(&subbuffer[2], subend - &subbuffer[2]);
783 	    break;
784 	case WONT:
785 	    lm_wont(&subbuffer[2], subend - &subbuffer[2]);
786 	    break;
787 	case DO:
788 	    lm_do(&subbuffer[2], subend - &subbuffer[2]);
789 	    break;
790 	case DONT:
791 	    lm_dont(&subbuffer[2], subend - &subbuffer[2]);
792 	    break;
793 	case LM_SLC:
794 	    slc(&subbuffer[2], subend - &subbuffer[2]);
795 	    break;
796 	case LM_MODE:
797 	    lm_mode(&subbuffer[2], subend - &subbuffer[2], 0);
798 	    break;
799 	default:
800 		break;
801 	}
802 	break;
803     default:
804 	break;
805     }
806 }
807 
808 static char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE };
809 
810 lm_will(cmd, len)
811 char *cmd;
812 {
813     switch(cmd[0]) {
814     case LM_FORWARDMASK:	/* We shouldn't ever get this... */
815     default:
816 	str_lm[3] = DONT;
817 	str_lm[4] = cmd[0];
818 	if (NETROOM() > sizeof(str_lm)) {
819 	    ring_supply_data(&netoring, str_lm, sizeof(str_lm));
820 	    printsub('>', &str_lm[2], sizeof(str_lm)-2);
821 	}
822 /*@*/	else printf("lm_will: not enough room in buffer\n");
823 	break;
824     }
825 }
826 
827 lm_wont(cmd, len)
828 char *cmd;
829 {
830     switch(cmd[0]) {
831     case LM_FORWARDMASK:	/* We shouldn't ever get this... */
832     default:
833 	/* We are always DONT, so don't respond */
834 	return;
835     }
836 }
837 
838 lm_do(cmd, len)
839 char *cmd;
840 {
841     switch(cmd[0]) {
842     case LM_FORWARDMASK:
843     default:
844 	str_lm[3] = WONT;
845 	str_lm[4] = cmd[0];
846 	if (NETROOM() > sizeof(str_lm)) {
847 	    ring_supply_data(&netoring, str_lm, sizeof(str_lm));
848 	    printsub('>', &str_lm[2], sizeof(str_lm)-2);
849 	}
850 /*@*/	else printf("lm_do: not enough room in buffer\n");
851 	break;
852     }
853 }
854 
855 lm_dont(cmd, len)
856 char *cmd;
857 {
858     switch(cmd[0]) {
859     case LM_FORWARDMASK:
860     default:
861 	/* we are always WONT, so don't respond */
862 	break;
863     }
864 }
865 
866 static char str_lm_mode[] = { IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE };
867 
868 lm_mode(cmd, len, init)
869 char *cmd;
870 int len, init;
871 {
872 	if (len != 1)
873 		return;
874 	if ((linemode&(MODE_EDIT|MODE_TRAPSIG)) == *cmd)
875 		return;
876 	if (*cmd&MODE_ACK)
877 		return;
878 	linemode = (*cmd&(MODE_EDIT|MODE_TRAPSIG));
879 	str_lm_mode[4] = linemode;
880 	if (!init)
881 	    str_lm_mode[4] |= MODE_ACK;
882 	if (NETROOM() > sizeof(str_lm_mode)) {
883 	    ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode));
884 	    printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2);
885 	}
886 /*@*/	else printf("lm_mode: not enough room in buffer\n");
887 	setconnmode(0);	/* set changed mode */
888 }
889 
890 
891 
892 /*
893  * slc()
894  * Handle special character suboption of LINEMODE.
895  */
896 
897 struct spc {
898 	char val;
899 	char *valp;
900 	char flags;	/* Current flags & level */
901 	char mylevel;	/* Maximum level & flags */
902 } spc_data[NSLC+1];
903 
904 #define SLC_IMPORT	0
905 #define	SLC_EXPORT	1
906 #define SLC_RVALUE	2
907 static int slc_mode = SLC_EXPORT;
908 
909 slc_init()
910 {
911 	register struct spc *spcp;
912 	extern char *tcval();
913 
914 	localchars = 1;
915 	for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) {
916 		spcp->val = 0;
917 		spcp->valp = 0;
918 		spcp->flags = spcp->mylevel = SLC_NOSUPPORT;
919 	}
920 
921 #define	initfunc(func, flags) { \
922 					spcp = &spc_data[func]; \
923 					if (spcp->valp = tcval(func)) { \
924 					    spcp->val = *spcp->valp; \
925 					    spcp->mylevel = SLC_VARIABLE|flags; \
926 					} else { \
927 					    spcp->val = 0; \
928 					    spcp->mylevel = SLC_DEFAULT; \
929 					} \
930 				    }
931 
932 	initfunc(SLC_SYNCH, 0);
933 	/* No BRK */
934 	initfunc(SLC_AO, 0);
935 	initfunc(SLC_AYT, 0);
936 	/* No EOR */
937 	initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT);
938 	initfunc(SLC_EOF, 0);
939 #ifndef	SYSV_TERMIO
940 	initfunc(SLC_SUSP, SLC_FLUSHIN);
941 #endif
942 	initfunc(SLC_EC, 0);
943 	initfunc(SLC_EL, 0);
944 #ifndef	SYSV_TERMIO
945 	initfunc(SLC_EW, 0);
946 	initfunc(SLC_RP, 0);
947 	initfunc(SLC_LNEXT, 0);
948 #endif
949 	initfunc(SLC_XON, 0);
950 	initfunc(SLC_XOFF, 0);
951 #ifdef	SYSV_TERMIO
952 	spc_data[SLC_XON].mylevel = SLC_CANTCHANGE;
953 	spc_data[SLC_XOFF].mylevel = SLC_CANTCHANGE;
954 #endif
955 	/* No FORW1 */
956 	/* No FORW2 */
957 
958 	initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT);
959 #undef	initfunc
960 
961 	if (slc_mode == SLC_EXPORT)
962 		slc_export();
963 	else
964 		slc_import(1);
965 
966 }
967 
968 slcstate()
969 {
970     printf("Special characters are %s values\n",
971 		slc_mode == SLC_IMPORT ? "remote default" :
972 		slc_mode == SLC_EXPORT ? "local" :
973 					 "remote");
974 }
975 
976 slc_mode_export()
977 {
978     slc_mode = SLC_EXPORT;
979     if (my_state_is_will(TELOPT_LINEMODE))
980 	slc_export();
981 }
982 
983 slc_mode_import(def)
984 {
985     slc_mode = def ? SLC_IMPORT : SLC_RVALUE;
986     if (my_state_is_will(TELOPT_LINEMODE))
987 	slc_import(def);
988 }
989 
990 char slc_import_val[] = {
991 	IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE
992 };
993 char slc_import_def[] = {
994 	IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE
995 };
996 
997 slc_import(def)
998 int def;
999 {
1000     if (NETROOM() > sizeof(slc_import_val)) {
1001 	if (def) {
1002 	    ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def));
1003 	    printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2);
1004 	} else {
1005 	    ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val));
1006 	    printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2);
1007 	}
1008     }
1009 /*@*/ else printf("slc_import: not enough room\n");
1010 }
1011 
1012 slc_export()
1013 {
1014     register struct spc *spcp;
1015 
1016     TerminalDefaultChars();
1017 
1018     slc_start_reply();
1019     for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
1020 	if (spcp->mylevel != SLC_NOSUPPORT) {
1021 	    spcp->flags = spcp->mylevel;
1022 	    if (spcp->valp)
1023 		spcp->val = *spcp->valp;
1024 	    slc_add_reply(spcp - spc_data, spcp->mylevel, spcp->val);
1025 	}
1026     }
1027     slc_end_reply();
1028     if (slc_update())
1029 	setconnmode(1);	/* set the  new character values */
1030 }
1031 
1032 slc(cp, len)
1033 register char *cp;
1034 int len;
1035 {
1036 	register struct spc *spcp;
1037 	register int func,level;
1038 
1039 	slc_start_reply();
1040 
1041 	for (; len >= 3; len -=3, cp +=3) {
1042 
1043 		func = cp[SLC_FUNC];
1044 
1045 		if (func == 0) {
1046 			/*
1047 			 * Client side: always ignore 0 function.
1048 			 */
1049 			continue;
1050 		}
1051 		if (func > NSLC) {
1052 			if (cp[SLC_FLAGS] & SLC_LEVELBITS != SLC_NOSUPPORT)
1053 				slc_add_reply(func, SLC_NOSUPPORT, 0);
1054 			continue;
1055 		}
1056 
1057 		spcp = &spc_data[func];
1058 
1059 		level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK);
1060 
1061 		if ((cp[SLC_VALUE] == spcp->val) &&
1062 		    ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) {
1063 			continue;
1064 		}
1065 
1066 		if (level == (SLC_DEFAULT|SLC_ACK)) {
1067 			/*
1068 			 * This is an error condition, the SLC_ACK
1069 			 * bit should never be set for the SLC_DEFAULT
1070 			 * level.  Our best guess to recover is to
1071 			 * ignore the SLC_ACK bit.
1072 			 */
1073 			cp[SLC_FLAGS] &= ~SLC_ACK;
1074 		}
1075 
1076 		if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) {
1077 			spcp->val = cp[SLC_VALUE];
1078 			spcp->flags = cp[SLC_FLAGS];	/* include SLC_ACK */
1079 			continue;
1080 		}
1081 
1082 		level &= ~SLC_ACK;
1083 
1084 		if (level <= (spcp->mylevel&SLC_LEVELBITS)) {
1085 			spcp->flags = cp[SLC_FLAGS]|SLC_ACK;
1086 			spcp->val = cp[SLC_VALUE];
1087 		}
1088 		if (level == SLC_DEFAULT) {
1089 			if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT)
1090 				spcp->flags = spcp->mylevel;
1091 			else
1092 				spcp->flags = SLC_NOSUPPORT;
1093 		}
1094 		slc_add_reply(func, spcp->flags, spcp->val);
1095 	}
1096 	slc_end_reply();
1097 	if (slc_update())
1098 		setconnmode(1);	/* set the  new character values */
1099 }
1100 
1101 slc_check()
1102 {
1103     register struct spc *spcp;
1104 
1105     slc_start_reply();
1106     for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
1107 	if (spcp->valp && spcp->val != *spcp->valp) {
1108 	    spcp->val = *spcp->valp;
1109 	    slc_add_reply(spcp - spc_data, spcp->mylevel, spcp->val);
1110 	}
1111     }
1112     slc_end_reply();
1113     setconnmode(1);
1114 }
1115 
1116 
1117 unsigned char slc_reply[128];
1118 unsigned char *slc_replyp;
1119 slc_start_reply()
1120 {
1121 	slc_replyp = slc_reply;
1122 	*slc_replyp++ = IAC;
1123 	*slc_replyp++ = SB;
1124 	*slc_replyp++ = TELOPT_LINEMODE;
1125 	*slc_replyp++ = LM_SLC;
1126 }
1127 
1128 slc_add_reply(func, flags, value)
1129 char func;
1130 char flags;
1131 char value;
1132 {
1133 	if ((*slc_replyp++ = func) == IAC)
1134 		*slc_replyp++ = IAC;
1135 	if ((*slc_replyp++ = flags) == IAC)
1136 		*slc_replyp++ = IAC;
1137 	if ((*slc_replyp++ = value) == IAC)
1138 		*slc_replyp++ = IAC;
1139 }
1140 
1141 slc_end_reply()
1142 {
1143     register char *cp;
1144     register int len;
1145 
1146     *slc_replyp++ = IAC;
1147     *slc_replyp++ = SE;
1148     len = slc_replyp - slc_reply;
1149     if (len <= 6)
1150 	return;
1151     if (NETROOM() > len) {
1152 	ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply);
1153 	printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2);
1154     }
1155 /*@*/else printf("slc_end_reply: not enough room\n");
1156 }
1157 
1158 slc_update()
1159 {
1160 	register struct spc *spcp;
1161 	int need_update = 0;
1162 
1163 	for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
1164 		if (!(spcp->flags&SLC_ACK))
1165 			continue;
1166 		spcp->flags &= ~SLC_ACK;
1167 		if (spcp->valp && (*spcp->valp != spcp->val)) {
1168 			*spcp->valp = spcp->val;
1169 			need_update = 1;
1170 		}
1171 	}
1172 	return(need_update);
1173 }
1174 
1175 
1176 
1177 int
1178 telrcv()
1179 {
1180     register int c;
1181     register int scc;
1182     register char *sbp;
1183     int count;
1184     int returnValue = 0;
1185 
1186     scc = 0;
1187     count = 0;
1188     while (TTYROOM() > 2) {
1189 	if (scc == 0) {
1190 	    if (count) {
1191 		ring_consumed(&netiring, count);
1192 		returnValue = 1;
1193 		count = 0;
1194 	    }
1195 	    sbp = netiring.consume;
1196 	    scc = ring_full_consecutive(&netiring);
1197 	    if (scc == 0) {
1198 		/* No more data coming in */
1199 		break;
1200 	    }
1201 	}
1202 
1203 	c = *sbp++ & 0xff, scc--; count++;
1204 
1205 	switch (telrcv_state) {
1206 
1207 	case TS_CR:
1208 	    telrcv_state = TS_DATA;
1209 	    if (c == '\0') {
1210 		break;	/* Ignore \0 after CR */
1211 	    }
1212 	    else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) {
1213 		TTYADD(c);
1214 		break;
1215 	    }
1216 	    /* Else, fall through */
1217 
1218 	case TS_DATA:
1219 	    if (c == IAC) {
1220 		telrcv_state = TS_IAC;
1221 		break;
1222 	    }
1223 #	    if defined(TN3270)
1224 	    if (In3270) {
1225 		*Ifrontp++ = c;
1226 		while (scc > 0) {
1227 		    c = *sbp++ & 0377, scc--; count++;
1228 		    if (c == IAC) {
1229 			telrcv_state = TS_IAC;
1230 			break;
1231 		    }
1232 		    *Ifrontp++ = c;
1233 		}
1234 	    } else
1235 #	    endif /* defined(TN3270) */
1236 		    /*
1237 		     * The 'crmod' hack (see following) is needed
1238 		     * since we can't * set CRMOD on output only.
1239 		     * Machines like MULTICS like to send \r without
1240 		     * \n; since we must turn off CRMOD to get proper
1241 		     * input, the mapping is done here (sigh).
1242 		     */
1243 	    if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) {
1244 		if (scc > 0) {
1245 		    c = *sbp&0xff;
1246 		    if (c == 0) {
1247 			sbp++, scc--; count++;
1248 			/* a "true" CR */
1249 			TTYADD('\r');
1250 		    } else if (my_want_state_is_dont(TELOPT_ECHO) &&
1251 					(c == '\n')) {
1252 			sbp++, scc--; count++;
1253 			TTYADD('\n');
1254 		    } else {
1255 			TTYADD('\r');
1256 			if (crmod) {
1257 				TTYADD('\n');
1258 			}
1259 		    }
1260 		} else {
1261 		    telrcv_state = TS_CR;
1262 		    TTYADD('\r');
1263 		    if (crmod) {
1264 			    TTYADD('\n');
1265 		    }
1266 		}
1267 	    } else {
1268 		TTYADD(c);
1269 	    }
1270 	    continue;
1271 
1272 	case TS_IAC:
1273 process_iac:
1274 	    switch (c) {
1275 
1276 	    case WILL:
1277 		telrcv_state = TS_WILL;
1278 		continue;
1279 
1280 	    case WONT:
1281 		telrcv_state = TS_WONT;
1282 		continue;
1283 
1284 	    case DO:
1285 		telrcv_state = TS_DO;
1286 		continue;
1287 
1288 	    case DONT:
1289 		telrcv_state = TS_DONT;
1290 		continue;
1291 
1292 	    case DM:
1293 		    /*
1294 		     * We may have missed an urgent notification,
1295 		     * so make sure we flush whatever is in the
1296 		     * buffer currently.
1297 		     */
1298 		SYNCHing = 1;
1299 		ttyflush(1);
1300 		SYNCHing = stilloob();
1301 		settimer(gotDM);
1302 		break;
1303 
1304 	    case NOP:
1305 	    case GA:
1306 		break;
1307 
1308 	    case SB:
1309 		SB_CLEAR();
1310 		telrcv_state = TS_SB;
1311 		printoption("RCVD", "IAC", SB);
1312 		continue;
1313 
1314 #	    if defined(TN3270)
1315 	    case EOR:
1316 		if (In3270) {
1317 		    Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1);
1318 		    if (Ibackp == Ifrontp) {
1319 			Ibackp = Ifrontp = Ibuf;
1320 			ISend = 0;	/* should have been! */
1321 		    } else {
1322 			ISend = 1;
1323 		    }
1324 		}
1325 		break;
1326 #	    endif /* defined(TN3270) */
1327 
1328 	    case IAC:
1329 #	    if !defined(TN3270)
1330 		TTYADD(IAC);
1331 #	    else /* !defined(TN3270) */
1332 		if (In3270) {
1333 		    *Ifrontp++ = IAC;
1334 		} else {
1335 		    TTYADD(IAC);
1336 		}
1337 #	    endif /* !defined(TN3270) */
1338 		break;
1339 
1340 	    default:
1341 		break;
1342 	    }
1343 	    telrcv_state = TS_DATA;
1344 	    continue;
1345 
1346 	case TS_WILL:
1347 	    printoption("RCVD", "will", c);
1348 	    willoption(c);
1349 	    SetIn3270();
1350 	    telrcv_state = TS_DATA;
1351 	    continue;
1352 
1353 	case TS_WONT:
1354 	    printoption("RCVD", "wont", c);
1355 	    wontoption(c);
1356 	    SetIn3270();
1357 	    telrcv_state = TS_DATA;
1358 	    continue;
1359 
1360 	case TS_DO:
1361 	    printoption("RCVD", "do", c);
1362 	    dooption(c);
1363 	    SetIn3270();
1364 	    if (c == TELOPT_NAWS) {
1365 		sendnaws();
1366 	    } else if (c == TELOPT_LFLOW) {
1367 		localflow = 1;
1368 		setcommandmode();
1369 		setconnmode(0);
1370 	    }
1371 	    telrcv_state = TS_DATA;
1372 	    continue;
1373 
1374 	case TS_DONT:
1375 	    printoption("RCVD", "dont", c);
1376 	    dontoption(c);
1377 	    flushline = 1;
1378 	    setconnmode(0);	/* set new tty mode (maybe) */
1379 	    SetIn3270();
1380 	    telrcv_state = TS_DATA;
1381 	    continue;
1382 
1383 	case TS_SB:
1384 	    if (c == IAC) {
1385 		telrcv_state = TS_SE;
1386 	    } else {
1387 		SB_ACCUM(c);
1388 	    }
1389 	    continue;
1390 
1391 	case TS_SE:
1392 	    if (c != SE) {
1393 		if (c != IAC) {
1394 		    /*
1395 		     * This is an error.  We only expect to get
1396 		     * "IAC IAC" or "IAC SE".  Several things may
1397 		     * have happend.  An IAC was not doubled, the
1398 		     * IAC SE was left off, or another option got
1399 		     * inserted into the suboption are all possibilities.
1400 		     * If we assume that the IAC was not doubled,
1401 		     * and really the IAC SE was left off, we could
1402 		     * get into an infinate loop here.  So, instead,
1403 		     * we terminate the suboption, and process the
1404 		     * partial suboption if we can.
1405 		     */
1406 		    SB_TERM();
1407 		    SB_ACCUM(IAC);
1408 		    SB_ACCUM(c);
1409 		    printoption("In SUBOPTION processing, RCVD", "IAC", c);
1410 		    suboption();	/* handle sub-option */
1411 		    SetIn3270();
1412 		    telrcv_state = TS_IAC;
1413 		    goto process_iac;
1414 		}
1415 		SB_ACCUM(c);
1416 		telrcv_state = TS_SB;
1417 	    } else {
1418 		SB_TERM();
1419 		SB_ACCUM(IAC);
1420 		SB_ACCUM(SE);
1421 		suboption();	/* handle sub-option */
1422 		SetIn3270();
1423 		telrcv_state = TS_DATA;
1424 	    }
1425 	}
1426     }
1427     if (count)
1428 	ring_consumed(&netiring, count);
1429     return returnValue||count;
1430 }
1431 
1432 static int
1433 telsnd()
1434 {
1435     int tcc;
1436     int count;
1437     int returnValue = 0;
1438     char *tbp;
1439 
1440     tcc = 0;
1441     count = 0;
1442     while (NETROOM() > 2) {
1443 	register int sc;
1444 	register int c;
1445 
1446 	if (tcc == 0) {
1447 	    if (count) {
1448 		ring_consumed(&ttyiring, count);
1449 		returnValue = 1;
1450 		count = 0;
1451 	    }
1452 	    tbp = ttyiring.consume;
1453 	    tcc = ring_full_consecutive(&ttyiring);
1454 	    if (tcc == 0) {
1455 		break;
1456 	    }
1457 	}
1458 	c = *tbp++ & 0xff, sc = strip(c), tcc--; count++;
1459 	if (sc == escape) {
1460 	    /*
1461 	     * Double escape is a pass through of a single escape character.
1462 	     */
1463 	    if (tcc && strip(*tbp) == escape) {
1464 		tbp++;
1465 		tcc--;
1466 		count++;
1467 	    } else {
1468 		command(0, tbp, tcc);
1469 		count += tcc;
1470 		tcc = 0;
1471 		flushline = 1;
1472 		break;
1473 	    }
1474 	}
1475 #ifdef	KLUDGELINEMODE
1476 	if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) {
1477 	    if (tcc > 0 && strip(*tbp) == echoc) {
1478 		tcc--; tbp++; count++;
1479 	    } else {
1480 		dontlecho = !dontlecho;
1481 		settimer(echotoggle);
1482 		setconnmode(0);
1483 		flushline = 1;
1484 		break;
1485 	    }
1486 	}
1487 #endif
1488 	if (MODE_LOCAL_CHARS(globalmode)) {
1489 	    if (TerminalSpecialChars(sc) == 0) {
1490 		break;
1491 	    }
1492 	}
1493 	if (my_want_state_is_wont(TELOPT_BINARY)) {
1494 	    switch (c) {
1495 	    case '\n':
1496 		    /*
1497 		     * If we are in CRMOD mode (\r ==> \n)
1498 		     * on our local machine, then probably
1499 		     * a newline (unix) is CRLF (TELNET).
1500 		     */
1501 		if (MODE_LOCAL_CHARS(globalmode)) {
1502 		    NETADD('\r');
1503 		}
1504 		NETADD('\n');
1505 		flushline = 1;
1506 		break;
1507 	    case '\r':
1508 		if (!crlf) {
1509 		    NET2ADD('\r', '\0');
1510 		} else {
1511 		    NET2ADD('\r', '\n');
1512 		}
1513 		flushline = 1;
1514 		break;
1515 	    case IAC:
1516 		NET2ADD(IAC, IAC);
1517 		break;
1518 	    default:
1519 		NETADD(c);
1520 		break;
1521 	    }
1522 	} else if (c == IAC) {
1523 	    NET2ADD(IAC, IAC);
1524 	} else {
1525 	    NETADD(c);
1526 	}
1527     }
1528     if (count)
1529 	ring_consumed(&ttyiring, count);
1530     return returnValue||count;		/* Non-zero if we did anything */
1531 }
1532 
1533 /*
1534  * Scheduler()
1535  *
1536  * Try to do something.
1537  *
1538  * If we do something useful, return 1; else return 0.
1539  *
1540  */
1541 
1542 
1543 int
1544 Scheduler(block)
1545 int	block;			/* should we block in the select ? */
1546 {
1547 		/* One wants to be a bit careful about setting returnValue
1548 		 * to one, since a one implies we did some useful work,
1549 		 * and therefore probably won't be called to block next
1550 		 * time (TN3270 mode only).
1551 		 */
1552     int returnValue;
1553     int netin, netout, netex, ttyin, ttyout;
1554 
1555     /* Decide which rings should be processed */
1556 
1557     netout = ring_full_count(&netoring) &&
1558 	    (flushline ||
1559 		(my_want_state_is_wont(TELOPT_LINEMODE)
1560 #ifdef	KLUDGELINEMODE
1561 			&& (!kludgelinemode || my_want_state_is_do(TELOPT_SGA))
1562 #endif
1563 		) ||
1564 			my_want_state_is_will(TELOPT_BINARY));
1565     ttyout = ring_full_count(&ttyoring);
1566 
1567 #if	defined(TN3270)
1568     ttyin = ring_empty_count(&ttyiring) && (shell_active == 0);
1569 #else	/* defined(TN3270) */
1570     ttyin = ring_empty_count(&ttyiring);
1571 #endif	/* defined(TN3270) */
1572 
1573 #if	defined(TN3270)
1574     netin = ring_empty_count(&netiring);
1575 #   else /* !defined(TN3270) */
1576     netin = !ISend && ring_empty_count(&netiring);
1577 #   endif /* !defined(TN3270) */
1578 
1579     netex = !SYNCHing;
1580 
1581     /* If we have seen a signal recently, reset things */
1582 #   if defined(TN3270) && defined(unix)
1583     if (HaveInput) {
1584 	HaveInput = 0;
1585 	signal(SIGIO, inputAvailable);
1586     }
1587 #endif	/* defined(TN3270) && defined(unix) */
1588 
1589     /* Call to system code to process rings */
1590 
1591     returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block);
1592 
1593     /* Now, look at the input rings, looking for work to do. */
1594 
1595     if (ring_full_count(&ttyiring)) {
1596 #   if defined(TN3270)
1597 	if (In3270) {
1598 	    int c;
1599 
1600 	    c = DataFromTerminal(ttyiring.consume,
1601 					ring_full_consecutive(&ttyiring));
1602 	    if (c) {
1603 		returnValue = 1;
1604 	        ring_consumed(&ttyiring, c);
1605 	    }
1606 	} else {
1607 #   endif /* defined(TN3270) */
1608 	    returnValue |= telsnd();
1609 #   if defined(TN3270)
1610 	}
1611 #   endif /* defined(TN3270) */
1612     }
1613 
1614     if (ring_full_count(&netiring)) {
1615 #	if !defined(TN3270)
1616 	returnValue |= telrcv();
1617 #	else /* !defined(TN3270) */
1618 	returnValue = Push3270();
1619 #	endif /* !defined(TN3270) */
1620     }
1621     return returnValue;
1622 }
1623 
1624 /*
1625  * Select from tty and network...
1626  */
1627 void
1628 telnet()
1629 {
1630     sys_telnet_init();
1631 
1632 #   if !defined(TN3270)
1633     if (telnetport) {
1634 	send_do(TELOPT_SGA, 1);
1635 	send_will(TELOPT_TTYPE, 1);
1636 	send_will(TELOPT_NAWS, 1);
1637 	send_will(TELOPT_TSPEED, 1);
1638 	send_will(TELOPT_LFLOW, 1);
1639 	send_will(TELOPT_LINEMODE, 1);
1640 	send_do(TELOPT_STATUS, 1);
1641     }
1642 #   endif /* !defined(TN3270) */
1643 
1644 #   if !defined(TN3270)
1645     for (;;) {
1646 	int schedValue;
1647 
1648 	while ((schedValue = Scheduler(0)) != 0) {
1649 	    if (schedValue == -1) {
1650 		setcommandmode();
1651 		return;
1652 	    }
1653 	}
1654 
1655 	if (Scheduler(1) == -1) {
1656 	    setcommandmode();
1657 	    return;
1658 	}
1659     }
1660 #   else /* !defined(TN3270) */
1661     for (;;) {
1662 	int schedValue;
1663 
1664 	while (!In3270 && !shell_active) {
1665 	    if (Scheduler(1) == -1) {
1666 		setcommandmode();
1667 		return;
1668 	    }
1669 	}
1670 
1671 	while ((schedValue = Scheduler(0)) != 0) {
1672 	    if (schedValue == -1) {
1673 		setcommandmode();
1674 		return;
1675 	    }
1676 	}
1677 		/* If there is data waiting to go out to terminal, don't
1678 		 * schedule any more data for the terminal.
1679 		 */
1680 	if (ring_full_count(&ttyoring)) {
1681 	    schedValue = 1;
1682 	} else {
1683 	    if (shell_active) {
1684 		if (shell_continue() == 0) {
1685 		    ConnectScreen();
1686 		}
1687 	    } else if (In3270) {
1688 		schedValue = DoTerminalOutput();
1689 	    }
1690 	}
1691 	if (schedValue && (shell_active == 0)) {
1692 	    if (Scheduler(1) == -1) {
1693 		setcommandmode();
1694 		return;
1695 	    }
1696 	}
1697     }
1698 #   endif /* !defined(TN3270) */
1699 }
1700 
1701 #if	0	/* XXX - this not being in is a bug */
1702 /*
1703  * nextitem()
1704  *
1705  *	Return the address of the next "item" in the TELNET data
1706  * stream.  This will be the address of the next character if
1707  * the current address is a user data character, or it will
1708  * be the address of the character following the TELNET command
1709  * if the current address is a TELNET IAC ("I Am a Command")
1710  * character.
1711  */
1712 
1713 static char *
1714 nextitem(current)
1715 char	*current;
1716 {
1717     if ((*current&0xff) != IAC) {
1718 	return current+1;
1719     }
1720     switch (*(current+1)&0xff) {
1721     case DO:
1722     case DONT:
1723     case WILL:
1724     case WONT:
1725 	return current+3;
1726     case SB:		/* loop forever looking for the SE */
1727 	{
1728 	    register char *look = current+2;
1729 
1730 	    for (;;) {
1731 		if ((*look++&0xff) == IAC) {
1732 		    if ((*look++&0xff) == SE) {
1733 			return look;
1734 		    }
1735 		}
1736 	    }
1737 	}
1738     default:
1739 	return current+2;
1740     }
1741 }
1742 #endif	/* 0 */
1743 
1744 /*
1745  * netclear()
1746  *
1747  *	We are about to do a TELNET SYNCH operation.  Clear
1748  * the path to the network.
1749  *
1750  *	Things are a bit tricky since we may have sent the first
1751  * byte or so of a previous TELNET command into the network.
1752  * So, we have to scan the network buffer from the beginning
1753  * until we are up to where we want to be.
1754  *
1755  *	A side effect of what we do, just to keep things
1756  * simple, is to clear the urgent data pointer.  The principal
1757  * caller should be setting the urgent data pointer AFTER calling
1758  * us in any case.
1759  */
1760 
1761 static void
1762 netclear()
1763 {
1764 #if	0	/* XXX */
1765     register char *thisitem, *next;
1766     char *good;
1767 #define	wewant(p)	((nfrontp > p) && ((*p&0xff) == IAC) && \
1768 				((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
1769 
1770     thisitem = netobuf;
1771 
1772     while ((next = nextitem(thisitem)) <= netobuf.send) {
1773 	thisitem = next;
1774     }
1775 
1776     /* Now, thisitem is first before/at boundary. */
1777 
1778     good = netobuf;	/* where the good bytes go */
1779 
1780     while (netoring.add > thisitem) {
1781 	if (wewant(thisitem)) {
1782 	    int length;
1783 
1784 	    next = thisitem;
1785 	    do {
1786 		next = nextitem(next);
1787 	    } while (wewant(next) && (nfrontp > next));
1788 	    length = next-thisitem;
1789 	    memcpy(good, thisitem, length);
1790 	    good += length;
1791 	    thisitem = next;
1792 	} else {
1793 	    thisitem = nextitem(thisitem);
1794 	}
1795     }
1796 
1797 #endif	/* 0 */
1798 }
1799 
1800 /*
1801  * These routines add various telnet commands to the data stream.
1802  */
1803 
1804 static void
1805 doflush()
1806 {
1807     NET2ADD(IAC, DO);
1808     NETADD(TELOPT_TM);
1809     flushline = 1;
1810     flushout = 1;
1811     ttyflush(1);			/* Flush/drop output */
1812     /* do printoption AFTER flush, otherwise the output gets tossed... */
1813     printoption("SENT", "do", TELOPT_TM);
1814 }
1815 
1816 void
1817 xmitAO()
1818 {
1819     NET2ADD(IAC, AO);
1820     printoption("SENT", "IAC", AO);
1821     if (autoflush) {
1822 	doflush();
1823     }
1824 }
1825 
1826 
1827 void
1828 xmitEL()
1829 {
1830     NET2ADD(IAC, EL);
1831     printoption("SENT", "IAC", EL);
1832 }
1833 
1834 void
1835 xmitEC()
1836 {
1837     NET2ADD(IAC, EC);
1838     printoption("SENT", "IAC", EC);
1839 }
1840 
1841 
1842 #if	defined(NOT43)
1843 int
1844 #else	/* defined(NOT43) */
1845 void
1846 #endif	/* defined(NOT43) */
1847 dosynch()
1848 {
1849     netclear();			/* clear the path to the network */
1850     NETADD(IAC);
1851     setneturg();
1852     NETADD(DM);
1853     printoption("SENT", "IAC", DM);
1854 
1855 #if	defined(NOT43)
1856     return 0;
1857 #endif	/* defined(NOT43) */
1858 }
1859 
1860 void
1861 get_status()
1862 {
1863     char tmp[16];
1864     register char *cp;
1865 
1866     if (my_want_state_is_dont(TELOPT_STATUS)) {
1867 	printf("Remote side does not support STATUS option\n");
1868 	return;
1869     }
1870     if (!showoptions)
1871 	printf("You will not see the response unless you set \"options\"\n");
1872 
1873     cp = tmp;
1874 
1875     *cp++ = IAC;
1876     *cp++ = SB;
1877     *cp++ = TELOPT_STATUS;
1878     *cp++ = TELQUAL_SEND;
1879     *cp++ = IAC;
1880     *cp++ = SE;
1881     if (NETROOM() >= cp - tmp) {
1882 	ring_supply_data(&netoring, tmp, cp-tmp);
1883 	printsub('>', tmp+2, cp - tmp - 2);
1884     }
1885 }
1886 
1887 void
1888 intp()
1889 {
1890     NET2ADD(IAC, IP);
1891     printoption("SENT", "IAC", IP);
1892     flushline = 1;
1893     if (autoflush) {
1894 	doflush();
1895     }
1896     if (autosynch) {
1897 	dosynch();
1898     }
1899 }
1900 
1901 void
1902 sendbrk()
1903 {
1904     NET2ADD(IAC, BREAK);
1905     printoption("SENT", "IAC", BREAK);
1906     flushline = 1;
1907     if (autoflush) {
1908 	doflush();
1909     }
1910     if (autosynch) {
1911 	dosynch();
1912     }
1913 }
1914 
1915 void
1916 sendabort()
1917 {
1918     NET2ADD(IAC, ABORT);
1919     printoption("SENT", "IAC", ABORT);
1920     flushline = 1;
1921     if (autoflush) {
1922 	doflush();
1923     }
1924     if (autosynch) {
1925 	dosynch();
1926     }
1927 }
1928 
1929 void
1930 sendsusp()
1931 {
1932     NET2ADD(IAC, SUSP);
1933     printoption("SENT", "IAC", SUSP);
1934     flushline = 1;
1935     if (autoflush) {
1936 	doflush();
1937     }
1938     if (autosynch) {
1939 	dosynch();
1940     }
1941 }
1942 
1943 void
1944 sendeof()
1945 {
1946     NET2ADD(IAC, xEOF);
1947     printoption("SENT", "IAC", xEOF);
1948 }
1949 
1950 /*
1951  * Send a window size update to the remote system.
1952  */
1953 
1954 void
1955 sendnaws()
1956 {
1957     long rows, cols;
1958     unsigned char tmp[16];
1959     register unsigned char *cp;
1960 
1961     if (my_state_is_wont(TELOPT_NAWS))
1962 	return;
1963 
1964 #define	PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \
1965 			    if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; }
1966 
1967     if (TerminalWindowSize(&rows, &cols) == 0) {	/* Failed */
1968 	return;
1969     }
1970 
1971     cp = tmp;
1972 
1973     *cp++ = IAC;
1974     *cp++ = SB;
1975     *cp++ = TELOPT_NAWS;
1976     PUTSHORT(cp, cols);
1977     PUTSHORT(cp, rows);
1978     *cp++ = IAC;
1979     *cp++ = SE;
1980     if (NETROOM() >= cp - tmp) {
1981 	ring_supply_data(&netoring, tmp, cp-tmp);
1982 	printsub('>', tmp+2, cp - tmp - 2);
1983     }
1984 }
1985 
1986 tel_enter_binary(rw)
1987 int rw;
1988 {
1989     if (rw&1)
1990 	send_do(TELOPT_BINARY, 1);
1991     if (rw&2)
1992 	send_will(TELOPT_BINARY, 1);
1993 }
1994 
1995 tel_leave_binary(rw)
1996 int rw;
1997 {
1998     if (rw&1)
1999 	send_dont(TELOPT_BINARY, 1);
2000     if (rw&2)
2001 	send_wont(TELOPT_BINARY, 1);
2002 }
2003