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