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