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