xref: /dragonfly/usr.bin/telnet/utilities.c (revision 768af85b)
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. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * @(#)utilities.c	8.3 (Berkeley) 5/30/95
34  * $FreeBSD: src/crypto/telnet/telnet/utilities.c,v 1.2.8.2 2002/04/13 10:59:08 markm Exp $
35  * $DragonFly: src/crypto/telnet/telnet/utilities.c,v 1.2 2003/06/17 04:24:37 dillon Exp $
36  */
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 
66 FILE	*NetTrace = 0;		/* Not in bss, since needs to stay */
67 int	prettydump;
68 
69 /*
70  * upcase()
71  *
72  *	Upcase (in place) the argument.
73  */
74 
75 void
76 upcase(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 
94 int
95 SetSockOpt(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 
105 unsigned char NetTraceFile[256] = "(standard output)";
106 
107 void
108 SetNetTrace(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 
124 void
125 Dump(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 
172 void
173 printoption(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 
206 void
207 optionstatus(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 
283 void
284 printsub(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 		    sprintf(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, "\" 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, "\" VAR " + noquote);
798 			    noquote = 2;
799 			    break;
800 
801 			case ENV_ESC:
802 			    fprintf(NetTrace, "\" ESC " + noquote);
803 			    noquote = 2;
804 			    break;
805 
806 			case ENV_USERVAR:
807 			    fprintf(NetTrace, "\" 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 
858 static void
859 EmptyTerminal(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, NULL, &o, NULL, NULL);	/* wait for TTLOWAT */
868     } else {
869 	while (TTYBYTES()) {
870 	    (void) ttyflush(0);
871 	    FD_SET(tout, &o);
872 	    (void) select(tout+1, NULL, &o, NULL, NULL); /* wait for TTLOWAT */
873 	}
874     }
875 }
876 
877 static void
878 SetForExit(void)
879 {
880     setconnmode(0);
881     do {
882 	(void)telrcv();			/* Process any incoming data */
883 	EmptyTerminal();
884     } while (ring_full_count(&netiring));	/* While there is any */
885     setcommandmode();
886     fflush(stdout);
887     fflush(stderr);
888     setconnmode(0);
889     EmptyTerminal();			/* Flush the path to the tty */
890     setcommandmode();
891 }
892 
893 void
894 Exit(int returnCode)
895 {
896     SetForExit();
897     exit(returnCode);
898 }
899 
900 void
901 ExitString(const char *string, int returnCode)
902 {
903     SetForExit();
904     fwrite(string, 1, strlen(string), stderr);
905     exit(returnCode);
906 }
907