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