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