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