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