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