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