1/*
2 * Copyright (c) 1988, 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
32static const char sccsid[] = "@(#)utilities.c	8.3 (Berkeley) 5/30/95";
33#endif
34#endif
35#include <sys/cdefs.h>
36__FBSDID("$FreeBSD: stable/11/contrib/telnet/telnet/utilities.c 351432 2019-08-23 17:40:47Z emaste $");
37
38#define	TELOPTS
39#define	TELCMDS
40#define	SLC_NAMES
41#include <arpa/telnet.h>
42#include <sys/types.h>
43#include <sys/socket.h>
44#include <sys/time.h>
45#include <ctype.h>
46#include <stdlib.h>
47#include <unistd.h>
48
49#include "general.h"
50
51#include "fdset.h"
52
53#include "ring.h"
54
55#include "defines.h"
56
57#include "externs.h"
58
59#ifdef	AUTHENTICATION
60#include <libtelnet/auth.h>
61#endif
62#ifdef	ENCRYPTION
63#include <libtelnet/encrypt.h>
64#endif
65
66FILE	*NetTrace = 0;		/* Not in bss, since needs to stay */
67int	prettydump;
68
69/*
70 * upcase()
71 *
72 *	Upcase (in place) the argument.
73 */
74
75void
76upcase(char *argument)
77{
78    int c;
79
80    while ((c = *argument) != 0) {
81	if (islower(c)) {
82	    *argument = toupper(c);
83	}
84	argument++;
85    }
86}
87
88/*
89 * SetSockOpt()
90 *
91 * Compensate for differences in 4.2 and 4.3 systems.
92 */
93
94int
95SetSockOpt(int fd, int level, int option, int yesno)
96{
97    return setsockopt(fd, level, option,
98				(char *)&yesno, sizeof yesno);
99}
100
101/*
102 * The following are routines used to print out debugging information.
103 */
104
105unsigned char NetTraceFile[256] = "(standard output)";
106
107void
108SetNetTrace(char *file)
109{
110    if (NetTrace && NetTrace != stdout)
111	fclose(NetTrace);
112    if (file  && (strcmp(file, "-") != 0)) {
113	NetTrace = fopen(file, "w");
114	if (NetTrace) {
115	    strcpy((char *)NetTraceFile, file);
116	    return;
117	}
118	fprintf(stderr, "Cannot open %s.\n", file);
119    }
120    NetTrace = stdout;
121    strcpy((char *)NetTraceFile, "(standard output)");
122}
123
124void
125Dump(char direction, unsigned char *buffer, int length)
126{
127#   define BYTES_PER_LINE	32
128#   define min(x,y)	((x<y)? x:y)
129    unsigned char *pThis;
130    int offset;
131
132    offset = 0;
133
134    while (length) {
135	/* print one line */
136	fprintf(NetTrace, "%c 0x%x\t", direction, offset);
137	pThis = buffer;
138	if (prettydump) {
139	    buffer = buffer + min(length, BYTES_PER_LINE/2);
140	    while (pThis < buffer) {
141		fprintf(NetTrace, "%c%.2x",
142		    (((*pThis)&0xff) == 0xff) ? '*' : ' ',
143		    (*pThis)&0xff);
144		pThis++;
145	    }
146	    length -= BYTES_PER_LINE/2;
147	    offset += BYTES_PER_LINE/2;
148	} else {
149	    buffer = buffer + min(length, BYTES_PER_LINE);
150	    while (pThis < buffer) {
151		fprintf(NetTrace, "%.2x", (*pThis)&0xff);
152		pThis++;
153	    }
154	    length -= BYTES_PER_LINE;
155	    offset += BYTES_PER_LINE;
156	}
157	if (NetTrace == stdout) {
158	    fprintf(NetTrace, "\r\n");
159	} else {
160	    fprintf(NetTrace, "\n");
161	}
162	if (length < 0) {
163	    fflush(NetTrace);
164	    return;
165	}
166	/* find next unique line */
167    }
168    fflush(NetTrace);
169}
170
171
172void
173printoption(const char *direction, int cmd, int option)
174{
175	if (!showoptions)
176		return;
177	if (cmd == IAC) {
178		if (TELCMD_OK(option))
179		    fprintf(NetTrace, "%s IAC %s", direction, TELCMD(option));
180		else
181		    fprintf(NetTrace, "%s IAC %d", direction, option);
182	} else {
183		const char *fmt;
184		fmt = (cmd == WILL) ? "WILL" : (cmd == WONT) ? "WONT" :
185			(cmd == DO) ? "DO" : (cmd == DONT) ? "DONT" : 0;
186		if (fmt) {
187		    fprintf(NetTrace, "%s %s ", direction, fmt);
188		    if (TELOPT_OK(option))
189			fprintf(NetTrace, "%s", TELOPT(option));
190		    else if (option == TELOPT_EXOPL)
191			fprintf(NetTrace, "EXOPL");
192		    else
193			fprintf(NetTrace, "%d", option);
194		} else
195		    fprintf(NetTrace, "%s %d %d", direction, cmd, option);
196	}
197	if (NetTrace == stdout) {
198	    fprintf(NetTrace, "\r\n");
199	    fflush(NetTrace);
200	} else {
201	    fprintf(NetTrace, "\n");
202	}
203	return;
204}
205
206void
207optionstatus(void)
208{
209    int i;
210    extern char will_wont_resp[], do_dont_resp[];
211
212    for (i = 0; i < 256; i++) {
213	if (do_dont_resp[i]) {
214	    if (TELOPT_OK(i))
215		printf("resp DO_DONT %s: %d\n", TELOPT(i), do_dont_resp[i]);
216	    else if (TELCMD_OK(i))
217		printf("resp DO_DONT %s: %d\n", TELCMD(i), do_dont_resp[i]);
218	    else
219		printf("resp DO_DONT %d: %d\n", i,
220				do_dont_resp[i]);
221	    if (my_want_state_is_do(i)) {
222		if (TELOPT_OK(i))
223		    printf("want DO   %s\n", TELOPT(i));
224		else if (TELCMD_OK(i))
225		    printf("want DO   %s\n", TELCMD(i));
226		else
227		    printf("want DO   %d\n", i);
228	    } else {
229		if (TELOPT_OK(i))
230		    printf("want DONT %s\n", TELOPT(i));
231		else if (TELCMD_OK(i))
232		    printf("want DONT %s\n", TELCMD(i));
233		else
234		    printf("want DONT %d\n", i);
235	    }
236	} else {
237	    if (my_state_is_do(i)) {
238		if (TELOPT_OK(i))
239		    printf("     DO   %s\n", TELOPT(i));
240		else if (TELCMD_OK(i))
241		    printf("     DO   %s\n", TELCMD(i));
242		else
243		    printf("     DO   %d\n", i);
244	    }
245	}
246	if (will_wont_resp[i]) {
247	    if (TELOPT_OK(i))
248		printf("resp WILL_WONT %s: %d\n", TELOPT(i), will_wont_resp[i]);
249	    else if (TELCMD_OK(i))
250		printf("resp WILL_WONT %s: %d\n", TELCMD(i), will_wont_resp[i]);
251	    else
252		printf("resp WILL_WONT %d: %d\n",
253				i, will_wont_resp[i]);
254	    if (my_want_state_is_will(i)) {
255		if (TELOPT_OK(i))
256		    printf("want WILL %s\n", TELOPT(i));
257		else if (TELCMD_OK(i))
258		    printf("want WILL %s\n", TELCMD(i));
259		else
260		    printf("want WILL %d\n", i);
261	    } else {
262		if (TELOPT_OK(i))
263		    printf("want WONT %s\n", TELOPT(i));
264		else if (TELCMD_OK(i))
265		    printf("want WONT %s\n", TELCMD(i));
266		else
267		    printf("want WONT %d\n", i);
268	    }
269	} else {
270	    if (my_state_is_will(i)) {
271		if (TELOPT_OK(i))
272		    printf("     WILL %s\n", TELOPT(i));
273		else if (TELCMD_OK(i))
274		    printf("     WILL %s\n", TELCMD(i));
275		else
276		    printf("     WILL %d\n", i);
277	    }
278	}
279    }
280
281}
282
283void
284printsub(char direction, unsigned char *pointer, int length)
285{
286    int i;
287#ifdef	AUTHENTICATION
288    char buf[512];
289#endif
290    extern int want_status_response;
291
292    if (showoptions || direction == 0 ||
293	(want_status_response && (pointer[0] == TELOPT_STATUS))) {
294	if (direction) {
295	    fprintf(NetTrace, "%s IAC SB ",
296				(direction == '<')? "RCVD":"SENT");
297	    if (length >= 3) {
298		int j;
299
300		i = pointer[length-2];
301		j = pointer[length-1];
302
303		if (i != IAC || j != SE) {
304		    fprintf(NetTrace, "(terminated by ");
305		    if (TELOPT_OK(i))
306			fprintf(NetTrace, "%s ", TELOPT(i));
307		    else if (TELCMD_OK(i))
308			fprintf(NetTrace, "%s ", TELCMD(i));
309		    else
310			fprintf(NetTrace, "%d ", i);
311		    if (TELOPT_OK(j))
312			fprintf(NetTrace, "%s", TELOPT(j));
313		    else if (TELCMD_OK(j))
314			fprintf(NetTrace, "%s", TELCMD(j));
315		    else
316			fprintf(NetTrace, "%d", j);
317		    fprintf(NetTrace, ", not IAC SE!) ");
318		}
319	    }
320	    length -= 2;
321	}
322	if (length < 1) {
323	    fprintf(NetTrace, "(Empty suboption??\?)");
324	    if (NetTrace == stdout)
325		fflush(NetTrace);
326	    return;
327	}
328	switch (pointer[0]) {
329	case TELOPT_TTYPE:
330	    fprintf(NetTrace, "TERMINAL-TYPE ");
331	    switch (pointer[1]) {
332	    case TELQUAL_IS:
333		fprintf(NetTrace, "IS \"%.*s\"", length-2, (char *)pointer+2);
334		break;
335	    case TELQUAL_SEND:
336		fprintf(NetTrace, "SEND");
337		break;
338	    default:
339		fprintf(NetTrace,
340				"- unknown qualifier %d (0x%x).",
341				pointer[1], pointer[1]);
342	    }
343	    break;
344	case TELOPT_TSPEED:
345	    fprintf(NetTrace, "TERMINAL-SPEED");
346	    if (length < 2) {
347		fprintf(NetTrace, " (empty suboption??\?)");
348		break;
349	    }
350	    switch (pointer[1]) {
351	    case TELQUAL_IS:
352		fprintf(NetTrace, " IS ");
353		fprintf(NetTrace, "%.*s", length-2, (char *)pointer+2);
354		break;
355	    default:
356		if (pointer[1] == 1)
357		    fprintf(NetTrace, " SEND");
358		else
359		    fprintf(NetTrace, " %d (unknown)", pointer[1]);
360		for (i = 2; i < length; i++)
361		    fprintf(NetTrace, " ?%d?", pointer[i]);
362		break;
363	    }
364	    break;
365
366	case TELOPT_LFLOW:
367	    fprintf(NetTrace, "TOGGLE-FLOW-CONTROL");
368	    if (length < 2) {
369		fprintf(NetTrace, " (empty suboption??\?)");
370		break;
371	    }
372	    switch (pointer[1]) {
373	    case LFLOW_OFF:
374		fprintf(NetTrace, " OFF"); break;
375	    case LFLOW_ON:
376		fprintf(NetTrace, " ON"); break;
377	    case LFLOW_RESTART_ANY:
378		fprintf(NetTrace, " RESTART-ANY"); break;
379	    case LFLOW_RESTART_XON:
380		fprintf(NetTrace, " RESTART-XON"); break;
381	    default:
382		fprintf(NetTrace, " %d (unknown)", pointer[1]);
383	    }
384	    for (i = 2; i < length; i++)
385		fprintf(NetTrace, " ?%d?", pointer[i]);
386	    break;
387
388	case TELOPT_NAWS:
389	    fprintf(NetTrace, "NAWS");
390	    if (length < 2) {
391		fprintf(NetTrace, " (empty suboption??\?)");
392		break;
393	    }
394	    if (length == 2) {
395		fprintf(NetTrace, " ?%d?", pointer[1]);
396		break;
397	    }
398	    fprintf(NetTrace, " %d %d (%d)",
399		pointer[1], pointer[2],
400		(int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2])));
401	    if (length == 4) {
402		fprintf(NetTrace, " ?%d?", pointer[3]);
403		break;
404	    }
405	    fprintf(NetTrace, " %d %d (%d)",
406		pointer[3], pointer[4],
407		(int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4])));
408	    for (i = 5; i < length; i++)
409		fprintf(NetTrace, " ?%d?", pointer[i]);
410	    break;
411
412#ifdef	AUTHENTICATION
413	case TELOPT_AUTHENTICATION:
414	    fprintf(NetTrace, "AUTHENTICATION");
415	    if (length < 2) {
416		fprintf(NetTrace, " (empty suboption??\?)");
417		break;
418	    }
419	    switch (pointer[1]) {
420	    case TELQUAL_REPLY:
421	    case TELQUAL_IS:
422		fprintf(NetTrace, " %s ", (pointer[1] == TELQUAL_IS) ?
423							"IS" : "REPLY");
424		if (AUTHTYPE_NAME_OK(pointer[2]))
425		    fprintf(NetTrace, "%s ", AUTHTYPE_NAME(pointer[2]));
426		else
427		    fprintf(NetTrace, "%d ", pointer[2]);
428		if (length < 3) {
429		    fprintf(NetTrace, "(partial suboption??\?)");
430		    break;
431		}
432		fprintf(NetTrace, "%s|%s",
433			((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
434			"CLIENT" : "SERVER",
435			((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
436			"MUTUAL" : "ONE-WAY");
437
438		auth_printsub(&pointer[1], length - 1, buf, sizeof(buf));
439		fprintf(NetTrace, "%s", buf);
440		break;
441
442	    case TELQUAL_SEND:
443		i = 2;
444		fprintf(NetTrace, " SEND ");
445		while (i < length) {
446		    if (AUTHTYPE_NAME_OK(pointer[i]))
447			fprintf(NetTrace, "%s ", AUTHTYPE_NAME(pointer[i]));
448		    else
449			fprintf(NetTrace, "%d ", pointer[i]);
450		    if (++i >= length) {
451			fprintf(NetTrace, "(partial suboption??\?)");
452			break;
453		    }
454		    fprintf(NetTrace, "%s|%s ",
455			((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
456							"CLIENT" : "SERVER",
457			((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
458							"MUTUAL" : "ONE-WAY");
459		    ++i;
460		}
461		break;
462
463	    case TELQUAL_NAME:
464		i = 2;
465		fprintf(NetTrace, " NAME \"");
466		while (i < length)
467		    putc(pointer[i++], NetTrace);
468		putc('"', NetTrace);
469		break;
470
471	    default:
472		    for (i = 2; i < length; i++)
473			fprintf(NetTrace, " ?%d?", pointer[i]);
474		    break;
475	    }
476	    break;
477#endif
478
479#ifdef	ENCRYPTION
480	case TELOPT_ENCRYPT:
481	    fprintf(NetTrace, "ENCRYPT");
482	    if (length < 2) {
483		fprintf(NetTrace, " (empty suboption??\?)");
484		break;
485	    }
486	    switch (pointer[1]) {
487	    case ENCRYPT_START:
488		fprintf(NetTrace, " START");
489		break;
490
491	    case ENCRYPT_END:
492		fprintf(NetTrace, " END");
493		break;
494
495	    case ENCRYPT_REQSTART:
496		fprintf(NetTrace, " REQUEST-START");
497		break;
498
499	    case ENCRYPT_REQEND:
500		fprintf(NetTrace, " REQUEST-END");
501		break;
502
503	    case ENCRYPT_IS:
504	    case ENCRYPT_REPLY:
505		fprintf(NetTrace, " %s ", (pointer[1] == ENCRYPT_IS) ?
506							"IS" : "REPLY");
507		if (length < 3) {
508		    fprintf(NetTrace, " (partial suboption??\?)");
509		    break;
510		}
511		if (ENCTYPE_NAME_OK(pointer[2]))
512		    fprintf(NetTrace, "%s ", ENCTYPE_NAME(pointer[2]));
513		else
514		    fprintf(NetTrace, " %d (unknown)", pointer[2]);
515
516		encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf));
517		fprintf(NetTrace, "%s", buf);
518		break;
519
520	    case ENCRYPT_SUPPORT:
521		i = 2;
522		fprintf(NetTrace, " SUPPORT ");
523		while (i < length) {
524		    if (ENCTYPE_NAME_OK(pointer[i]))
525			fprintf(NetTrace, "%s ", ENCTYPE_NAME(pointer[i]));
526		    else
527			fprintf(NetTrace, "%d ", pointer[i]);
528		    i++;
529		}
530		break;
531
532	    case ENCRYPT_ENC_KEYID:
533		fprintf(NetTrace, " ENC_KEYID ");
534		goto encommon;
535
536	    case ENCRYPT_DEC_KEYID:
537		fprintf(NetTrace, " DEC_KEYID ");
538		goto encommon;
539
540	    default:
541		fprintf(NetTrace, " %d (unknown)", pointer[1]);
542	    encommon:
543		for (i = 2; i < length; i++)
544		    fprintf(NetTrace, " %d", pointer[i]);
545		break;
546	    }
547	    break;
548#endif	/* ENCRYPTION */
549
550	case TELOPT_LINEMODE:
551	    fprintf(NetTrace, "LINEMODE ");
552	    if (length < 2) {
553		fprintf(NetTrace, " (empty suboption??\?)");
554		break;
555	    }
556	    switch (pointer[1]) {
557	    case WILL:
558		fprintf(NetTrace, "WILL ");
559		goto common;
560	    case WONT:
561		fprintf(NetTrace, "WONT ");
562		goto common;
563	    case DO:
564		fprintf(NetTrace, "DO ");
565		goto common;
566	    case DONT:
567		fprintf(NetTrace, "DONT ");
568	    common:
569		if (length < 3) {
570		    fprintf(NetTrace, "(no option??\?)");
571		    break;
572		}
573		switch (pointer[2]) {
574		case LM_FORWARDMASK:
575		    fprintf(NetTrace, "Forward Mask");
576		    for (i = 3; i < length; i++)
577			fprintf(NetTrace, " %x", pointer[i]);
578		    break;
579		default:
580		    fprintf(NetTrace, "%d (unknown)", pointer[2]);
581		    for (i = 3; i < length; i++)
582			fprintf(NetTrace, " %d", pointer[i]);
583		    break;
584		}
585		break;
586
587	    case LM_SLC:
588		fprintf(NetTrace, "SLC");
589		for (i = 2; i < length - 2; i += 3) {
590		    if (SLC_NAME_OK(pointer[i+SLC_FUNC]))
591			fprintf(NetTrace, " %s", SLC_NAME(pointer[i+SLC_FUNC]));
592		    else
593			fprintf(NetTrace, " %d", pointer[i+SLC_FUNC]);
594		    switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) {
595		    case SLC_NOSUPPORT:
596			fprintf(NetTrace, " NOSUPPORT"); break;
597		    case SLC_CANTCHANGE:
598			fprintf(NetTrace, " CANTCHANGE"); break;
599		    case SLC_VARIABLE:
600			fprintf(NetTrace, " VARIABLE"); break;
601		    case SLC_DEFAULT:
602			fprintf(NetTrace, " DEFAULT"); break;
603		    }
604		    fprintf(NetTrace, "%s%s%s",
605			pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "",
606			pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "",
607			pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : "");
608		    if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN|
609						SLC_FLUSHOUT| SLC_LEVELBITS))
610			fprintf(NetTrace, "(0x%x)", pointer[i+SLC_FLAGS]);
611		    fprintf(NetTrace, " %d;", pointer[i+SLC_VALUE]);
612		    if ((pointer[i+SLC_VALUE] == IAC) &&
613			(pointer[i+SLC_VALUE+1] == IAC))
614				i++;
615		}
616		for (; i < length; i++)
617		    fprintf(NetTrace, " ?%d?", pointer[i]);
618		break;
619
620	    case LM_MODE:
621		fprintf(NetTrace, "MODE ");
622		if (length < 3) {
623		    fprintf(NetTrace, "(no mode??\?)");
624		    break;
625		}
626		{
627		    char tbuf[64];
628		    snprintf(tbuf, sizeof(tbuf), "%s%s%s%s%s",
629			pointer[2]&MODE_EDIT ? "|EDIT" : "",
630			pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "",
631			pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "",
632			pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "",
633			pointer[2]&MODE_ACK ? "|ACK" : "");
634		    fprintf(NetTrace, "%s", tbuf[1] ? &tbuf[1] : "0");
635		}
636		if (pointer[2]&~(MODE_MASK))
637		    fprintf(NetTrace, " (0x%x)", pointer[2]);
638		for (i = 3; i < length; i++)
639		    fprintf(NetTrace, " ?0x%x?", pointer[i]);
640		break;
641	    default:
642		fprintf(NetTrace, "%d (unknown)", pointer[1]);
643		for (i = 2; i < length; i++)
644		    fprintf(NetTrace, " %d", pointer[i]);
645	    }
646	    break;
647
648	case TELOPT_STATUS: {
649	    const char *cp;
650	    int j, k;
651
652	    fprintf(NetTrace, "STATUS");
653
654	    switch (pointer[1]) {
655	    default:
656		if (pointer[1] == TELQUAL_SEND)
657		    fprintf(NetTrace, " SEND");
658		else
659		    fprintf(NetTrace, " %d (unknown)", pointer[1]);
660		for (i = 2; i < length; i++)
661		    fprintf(NetTrace, " ?%d?", pointer[i]);
662		break;
663	    case TELQUAL_IS:
664		if (--want_status_response < 0)
665		    want_status_response = 0;
666		if (NetTrace == stdout)
667		    fprintf(NetTrace, " IS\r\n");
668		else
669		    fprintf(NetTrace, " IS\n");
670
671		for (i = 2; i < length; i++) {
672		    switch(pointer[i]) {
673		    case DO:	cp = "DO"; goto common2;
674		    case DONT:	cp = "DONT"; goto common2;
675		    case WILL:	cp = "WILL"; goto common2;
676		    case WONT:	cp = "WONT"; goto common2;
677		    common2:
678			i++;
679			if (TELOPT_OK((int)pointer[i]))
680			    fprintf(NetTrace, " %s %s", cp, TELOPT(pointer[i]));
681			else
682			    fprintf(NetTrace, " %s %d", cp, pointer[i]);
683
684			if (NetTrace == stdout)
685			    fprintf(NetTrace, "\r\n");
686			else
687			    fprintf(NetTrace, "\n");
688			break;
689
690		    case SB:
691			fprintf(NetTrace, " SB ");
692			i++;
693			j = k = i;
694			while (j < length) {
695			    if (pointer[j] == SE) {
696				if (j+1 == length)
697				    break;
698				if (pointer[j+1] == SE)
699				    j++;
700				else
701				    break;
702			    }
703			    pointer[k++] = pointer[j++];
704			}
705			printsub(0, &pointer[i], k - i);
706			if (i < length) {
707			    fprintf(NetTrace, " SE");
708			    i = j;
709			} else
710			    i = j - 1;
711
712			if (NetTrace == stdout)
713			    fprintf(NetTrace, "\r\n");
714			else
715			    fprintf(NetTrace, "\n");
716
717			break;
718
719		    default:
720			fprintf(NetTrace, " %d", pointer[i]);
721			break;
722		    }
723		}
724		break;
725	    }
726	    break;
727	  }
728
729	case TELOPT_XDISPLOC:
730	    fprintf(NetTrace, "X-DISPLAY-LOCATION ");
731	    switch (pointer[1]) {
732	    case TELQUAL_IS:
733		fprintf(NetTrace, "IS \"%.*s\"", length-2, (char *)pointer+2);
734		break;
735	    case TELQUAL_SEND:
736		fprintf(NetTrace, "SEND");
737		break;
738	    default:
739		fprintf(NetTrace, "- unknown qualifier %d (0x%x).",
740				pointer[1], pointer[1]);
741	    }
742	    break;
743
744	case TELOPT_NEW_ENVIRON:
745	    fprintf(NetTrace, "NEW-ENVIRON ");
746#ifdef	OLD_ENVIRON
747	    goto env_common1;
748	case TELOPT_OLD_ENVIRON:
749	    fprintf(NetTrace, "OLD-ENVIRON");
750	env_common1:
751#endif
752	    switch (pointer[1]) {
753	    case TELQUAL_IS:
754		fprintf(NetTrace, "IS ");
755		goto env_common;
756	    case TELQUAL_SEND:
757		fprintf(NetTrace, "SEND ");
758		goto env_common;
759	    case TELQUAL_INFO:
760		fprintf(NetTrace, "INFO ");
761	    env_common:
762		{
763		    int noquote = 2;
764#if defined(ENV_HACK) && defined(OLD_ENVIRON)
765		    extern int old_env_var, old_env_value;
766#endif
767		    for (i = 2; i < length; i++ ) {
768			switch (pointer[i]) {
769			case NEW_ENV_VALUE:
770#ifdef OLD_ENVIRON
771		     /*	case NEW_ENV_OVAR: */
772			    if (pointer[0] == TELOPT_OLD_ENVIRON) {
773# ifdef	ENV_HACK
774				if (old_env_var == OLD_ENV_VALUE)
775				    fprintf(NetTrace, "\" (VALUE) " + noquote);
776				else
777# endif
778				    fprintf(NetTrace, "\" VAR " + noquote);
779			    } else
780#endif /* OLD_ENVIRON */
781				fprintf(NetTrace, "%s", "\" VALUE " + noquote);
782			    noquote = 2;
783			    break;
784
785			case NEW_ENV_VAR:
786#ifdef OLD_ENVIRON
787		     /* case OLD_ENV_VALUE: */
788			    if (pointer[0] == TELOPT_OLD_ENVIRON) {
789# ifdef	ENV_HACK
790				if (old_env_value == OLD_ENV_VAR)
791				    fprintf(NetTrace, "\" (VAR) " + noquote);
792				else
793# endif
794				    fprintf(NetTrace, "\" VALUE " + noquote);
795			    } else
796#endif /* OLD_ENVIRON */
797				fprintf(NetTrace, "%s", "\" VAR " + noquote);
798			    noquote = 2;
799			    break;
800
801			case ENV_ESC:
802			    fprintf(NetTrace, "%s", "\" ESC " + noquote);
803			    noquote = 2;
804			    break;
805
806			case ENV_USERVAR:
807			    fprintf(NetTrace, "%s", "\" USERVAR " + noquote);
808			    noquote = 2;
809			    break;
810
811			default:
812			    if (isprint(pointer[i]) && pointer[i] != '"') {
813				if (noquote) {
814				    putc('"', NetTrace);
815				    noquote = 0;
816				}
817				putc(pointer[i], NetTrace);
818			    } else {
819				fprintf(NetTrace, "\" %03o " + noquote,
820							pointer[i]);
821				noquote = 2;
822			    }
823			    break;
824			}
825		    }
826		    if (!noquote)
827			putc('"', NetTrace);
828		    break;
829		}
830	    }
831	    break;
832
833	default:
834	    if (TELOPT_OK(pointer[0]))
835		fprintf(NetTrace, "%s (unknown)", TELOPT(pointer[0]));
836	    else
837		fprintf(NetTrace, "%d (unknown)", pointer[0]);
838	    for (i = 1; i < length; i++)
839		fprintf(NetTrace, " %d", pointer[i]);
840	    break;
841	}
842	if (direction) {
843	    if (NetTrace == stdout)
844		fprintf(NetTrace, "\r\n");
845	    else
846		fprintf(NetTrace, "\n");
847	}
848	if (NetTrace == stdout)
849	    fflush(NetTrace);
850    }
851}
852
853/* EmptyTerminal - called to make sure that the terminal buffer is empty.
854 *			Note that we consider the buffer to run all the
855 *			way to the kernel (thus the select).
856 */
857
858static void
859EmptyTerminal(void)
860{
861    fd_set	o;
862
863    FD_ZERO(&o);
864
865    if (TTYBYTES() == 0) {
866	FD_SET(tout, &o);
867	(void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
868			(struct timeval *) 0);	/* wait for TTLOWAT */
869    } else {
870	while (TTYBYTES()) {
871	    (void) ttyflush(0);
872	    FD_SET(tout, &o);
873	    (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
874				(struct timeval *) 0);	/* wait for TTLOWAT */
875	}
876    }
877}
878
879static void
880SetForExit(void)
881{
882    setconnmode(0);
883    do {
884	(void)telrcv();			/* Process any incoming data */
885	EmptyTerminal();
886    } while (ring_full_count(&netiring));	/* While there is any */
887    setcommandmode();
888    fflush(stdout);
889    fflush(stderr);
890    setconnmode(0);
891    EmptyTerminal();			/* Flush the path to the tty */
892    setcommandmode();
893}
894
895void
896Exit(int returnCode)
897{
898    SetForExit();
899    exit(returnCode);
900}
901
902void
903ExitString(const char *string, int returnCode)
904{
905    SetForExit();
906    fwrite(string, 1, strlen(string), stderr);
907    exit(returnCode);
908}
909