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