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