xref: /netbsd-src/usr.bin/telnet/utilities.c (revision ce0bb6e8d2e560ecacbe865a848624f94498063b)
1 /*
2  * Copyright (c) 1988, 1993
3  *	The Regents of the University of California.  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 /* from: static char sccsid[] = "@(#)utilities.c	8.1 (Berkeley) 6/6/93"; */
36 static char *rcsid = "$Id: utilities.c,v 1.3 1994/02/25 03:00:51 cgd 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 	    fflush(NetTrace);
210 	} else {
211 	    fprintf(NetTrace, "\n");
212 	}
213 	return;
214 }
215 
216     void
217 optionstatus()
218 {
219     register int i;
220     extern char will_wont_resp[], do_dont_resp[];
221 
222     for (i = 0; i < 256; i++) {
223 	if (do_dont_resp[i]) {
224 	    if (TELOPT_OK(i))
225 		printf("resp DO_DONT %s: %d\n", TELOPT(i), do_dont_resp[i]);
226 	    else if (TELCMD_OK(i))
227 		printf("resp DO_DONT %s: %d\n", TELCMD(i), do_dont_resp[i]);
228 	    else
229 		printf("resp DO_DONT %d: %d\n", i,
230 				do_dont_resp[i]);
231 	    if (my_want_state_is_do(i)) {
232 		if (TELOPT_OK(i))
233 		    printf("want DO   %s\n", TELOPT(i));
234 		else if (TELCMD_OK(i))
235 		    printf("want DO   %s\n", TELCMD(i));
236 		else
237 		    printf("want DO   %d\n", i);
238 	    } else {
239 		if (TELOPT_OK(i))
240 		    printf("want DONT %s\n", TELOPT(i));
241 		else if (TELCMD_OK(i))
242 		    printf("want DONT %s\n", TELCMD(i));
243 		else
244 		    printf("want DONT %d\n", i);
245 	    }
246 	} else {
247 	    if (my_state_is_do(i)) {
248 		if (TELOPT_OK(i))
249 		    printf("     DO   %s\n", TELOPT(i));
250 		else if (TELCMD_OK(i))
251 		    printf("     DO   %s\n", TELCMD(i));
252 		else
253 		    printf("     DO   %d\n", i);
254 	    }
255 	}
256 	if (will_wont_resp[i]) {
257 	    if (TELOPT_OK(i))
258 		printf("resp WILL_WONT %s: %d\n", TELOPT(i), will_wont_resp[i]);
259 	    else if (TELCMD_OK(i))
260 		printf("resp WILL_WONT %s: %d\n", TELCMD(i), will_wont_resp[i]);
261 	    else
262 		printf("resp WILL_WONT %d: %d\n",
263 				i, will_wont_resp[i]);
264 	    if (my_want_state_is_will(i)) {
265 		if (TELOPT_OK(i))
266 		    printf("want WILL %s\n", TELOPT(i));
267 		else if (TELCMD_OK(i))
268 		    printf("want WILL %s\n", TELCMD(i));
269 		else
270 		    printf("want WILL %d\n", i);
271 	    } else {
272 		if (TELOPT_OK(i))
273 		    printf("want WONT %s\n", TELOPT(i));
274 		else if (TELCMD_OK(i))
275 		    printf("want WONT %s\n", TELCMD(i));
276 		else
277 		    printf("want WONT %d\n", i);
278 	    }
279 	} else {
280 	    if (my_state_is_will(i)) {
281 		if (TELOPT_OK(i))
282 		    printf("     WILL %s\n", TELOPT(i));
283 		else if (TELCMD_OK(i))
284 		    printf("     WILL %s\n", TELCMD(i));
285 		else
286 		    printf("     WILL %d\n", i);
287 	    }
288 	}
289     }
290 
291 }
292 
293     void
294 printsub(direction, pointer, length)
295     char direction;	/* '<' or '>' */
296     unsigned char *pointer;	/* where suboption data sits */
297     int		  length;	/* length of suboption data */
298 {
299     register int i;
300     char buf[512];
301     extern int want_status_response;
302 
303     if (showoptions || direction == 0 ||
304 	(want_status_response && (pointer[0] == TELOPT_STATUS))) {
305 	if (direction) {
306 	    fprintf(NetTrace, "%s IAC SB ",
307 				(direction == '<')? "RCVD":"SENT");
308 	    if (length >= 3) {
309 		register int j;
310 
311 		i = pointer[length-2];
312 		j = pointer[length-1];
313 
314 		if (i != IAC || j != SE) {
315 		    fprintf(NetTrace, "(terminated by ");
316 		    if (TELOPT_OK(i))
317 			fprintf(NetTrace, "%s ", TELOPT(i));
318 		    else if (TELCMD_OK(i))
319 			fprintf(NetTrace, "%s ", TELCMD(i));
320 		    else
321 			fprintf(NetTrace, "%d ", i);
322 		    if (TELOPT_OK(j))
323 			fprintf(NetTrace, "%s", TELOPT(j));
324 		    else if (TELCMD_OK(j))
325 			fprintf(NetTrace, "%s", TELCMD(j));
326 		    else
327 			fprintf(NetTrace, "%d", j);
328 		    fprintf(NetTrace, ", not IAC SE!) ");
329 		}
330 	    }
331 	    length -= 2;
332 	}
333 	if (length < 1) {
334 	    fprintf(NetTrace, "(Empty suboption??\?)");
335 	    if (NetTrace == stdout)
336 		fflush(NetTrace);
337 	    return;
338 	}
339 	switch (pointer[0]) {
340 	case TELOPT_TTYPE:
341 	    fprintf(NetTrace, "TERMINAL-TYPE ");
342 	    switch (pointer[1]) {
343 	    case TELQUAL_IS:
344 		fprintf(NetTrace, "IS \"%.*s\"", length-2, (char *)pointer+2);
345 		break;
346 	    case TELQUAL_SEND:
347 		fprintf(NetTrace, "SEND");
348 		break;
349 	    default:
350 		fprintf(NetTrace,
351 				"- unknown qualifier %d (0x%x).",
352 				pointer[1], pointer[1]);
353 	    }
354 	    break;
355 	case TELOPT_TSPEED:
356 	    fprintf(NetTrace, "TERMINAL-SPEED");
357 	    if (length < 2) {
358 		fprintf(NetTrace, " (empty suboption??\?)");
359 		break;
360 	    }
361 	    switch (pointer[1]) {
362 	    case TELQUAL_IS:
363 		fprintf(NetTrace, " IS ");
364 		fprintf(NetTrace, "%.*s", length-2, (char *)pointer+2);
365 		break;
366 	    default:
367 		if (pointer[1] == 1)
368 		    fprintf(NetTrace, " SEND");
369 		else
370 		    fprintf(NetTrace, " %d (unknown)", pointer[1]);
371 		for (i = 2; i < length; i++)
372 		    fprintf(NetTrace, " ?%d?", pointer[i]);
373 		break;
374 	    }
375 	    break;
376 
377 	case TELOPT_LFLOW:
378 	    fprintf(NetTrace, "TOGGLE-FLOW-CONTROL");
379 	    if (length < 2) {
380 		fprintf(NetTrace, " (empty suboption??\?)");
381 		break;
382 	    }
383 	    switch (pointer[1]) {
384 	    case LFLOW_OFF:
385 		fprintf(NetTrace, " OFF"); break;
386 	    case LFLOW_ON:
387 		fprintf(NetTrace, " ON"); break;
388 	    case LFLOW_RESTART_ANY:
389 		fprintf(NetTrace, " RESTART-ANY"); break;
390 	    case LFLOW_RESTART_XON:
391 		fprintf(NetTrace, " RESTART-XON"); break;
392 	    default:
393 		fprintf(NetTrace, " %d (unknown)", pointer[1]);
394 	    }
395 	    for (i = 2; i < length; i++)
396 		fprintf(NetTrace, " ?%d?", pointer[i]);
397 	    break;
398 
399 	case TELOPT_NAWS:
400 	    fprintf(NetTrace, "NAWS");
401 	    if (length < 2) {
402 		fprintf(NetTrace, " (empty suboption??\?)");
403 		break;
404 	    }
405 	    if (length == 2) {
406 		fprintf(NetTrace, " ?%d?", pointer[1]);
407 		break;
408 	    }
409 	    fprintf(NetTrace, " %d %d (%d)",
410 		pointer[1], pointer[2],
411 		(int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2])));
412 	    if (length == 4) {
413 		fprintf(NetTrace, " ?%d?", pointer[3]);
414 		break;
415 	    }
416 	    fprintf(NetTrace, " %d %d (%d)",
417 		pointer[3], pointer[4],
418 		(int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4])));
419 	    for (i = 5; i < length; i++)
420 		fprintf(NetTrace, " ?%d?", pointer[i]);
421 	    break;
422 
423 #if	defined(AUTHENTICATION)
424 	case TELOPT_AUTHENTICATION:
425 	    fprintf(NetTrace, "AUTHENTICATION");
426 	    if (length < 2) {
427 		fprintf(NetTrace, " (empty suboption??\?)");
428 		break;
429 	    }
430 	    switch (pointer[1]) {
431 	    case TELQUAL_REPLY:
432 	    case TELQUAL_IS:
433 		fprintf(NetTrace, " %s ", (pointer[1] == TELQUAL_IS) ?
434 							"IS" : "REPLY");
435 		if (AUTHTYPE_NAME_OK(pointer[2]))
436 		    fprintf(NetTrace, "%s ", AUTHTYPE_NAME(pointer[2]));
437 		else
438 		    fprintf(NetTrace, "%d ", pointer[2]);
439 		if (length < 3) {
440 		    fprintf(NetTrace, "(partial suboption??\?)");
441 		    break;
442 		}
443 		fprintf(NetTrace, "%s|%s",
444 			((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
445 			"CLIENT" : "SERVER",
446 			((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
447 			"MUTUAL" : "ONE-WAY");
448 
449 		auth_printsub(&pointer[1], length - 1, buf, sizeof(buf));
450 		fprintf(NetTrace, "%s", buf);
451 		break;
452 
453 	    case TELQUAL_SEND:
454 		i = 2;
455 		fprintf(NetTrace, " SEND ");
456 		while (i < length) {
457 		    if (AUTHTYPE_NAME_OK(pointer[i]))
458 			fprintf(NetTrace, "%s ", AUTHTYPE_NAME(pointer[i]));
459 		    else
460 			fprintf(NetTrace, "%d ", pointer[i]);
461 		    if (++i >= length) {
462 			fprintf(NetTrace, "(partial suboption??\?)");
463 			break;
464 		    }
465 		    fprintf(NetTrace, "%s|%s ",
466 			((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
467 							"CLIENT" : "SERVER",
468 			((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
469 							"MUTUAL" : "ONE-WAY");
470 		    ++i;
471 		}
472 		break;
473 
474 	    case TELQUAL_NAME:
475 		i = 2;
476 		fprintf(NetTrace, " NAME \"");
477 		while (i < length)
478 		    putc(pointer[i++], NetTrace);
479 		putc('"', NetTrace);
480 		break;
481 
482 	    default:
483 		    for (i = 2; i < length; i++)
484 			fprintf(NetTrace, " ?%d?", pointer[i]);
485 		    break;
486 	    }
487 	    break;
488 #endif
489 
490 
491 	case TELOPT_LINEMODE:
492 	    fprintf(NetTrace, "LINEMODE ");
493 	    if (length < 2) {
494 		fprintf(NetTrace, " (empty suboption??\?)");
495 		break;
496 	    }
497 	    switch (pointer[1]) {
498 	    case WILL:
499 		fprintf(NetTrace, "WILL ");
500 		goto common;
501 	    case WONT:
502 		fprintf(NetTrace, "WONT ");
503 		goto common;
504 	    case DO:
505 		fprintf(NetTrace, "DO ");
506 		goto common;
507 	    case DONT:
508 		fprintf(NetTrace, "DONT ");
509 	    common:
510 		if (length < 3) {
511 		    fprintf(NetTrace, "(no option??\?)");
512 		    break;
513 		}
514 		switch (pointer[2]) {
515 		case LM_FORWARDMASK:
516 		    fprintf(NetTrace, "Forward Mask");
517 		    for (i = 3; i < length; i++)
518 			fprintf(NetTrace, " %x", pointer[i]);
519 		    break;
520 		default:
521 		    fprintf(NetTrace, "%d (unknown)", pointer[2]);
522 		    for (i = 3; i < length; i++)
523 			fprintf(NetTrace, " %d", pointer[i]);
524 		    break;
525 		}
526 		break;
527 
528 	    case LM_SLC:
529 		fprintf(NetTrace, "SLC");
530 		for (i = 2; i < length - 2; i += 3) {
531 		    if (SLC_NAME_OK(pointer[i+SLC_FUNC]))
532 			fprintf(NetTrace, " %s", SLC_NAME(pointer[i+SLC_FUNC]));
533 		    else
534 			fprintf(NetTrace, " %d", pointer[i+SLC_FUNC]);
535 		    switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) {
536 		    case SLC_NOSUPPORT:
537 			fprintf(NetTrace, " NOSUPPORT"); break;
538 		    case SLC_CANTCHANGE:
539 			fprintf(NetTrace, " CANTCHANGE"); break;
540 		    case SLC_VARIABLE:
541 			fprintf(NetTrace, " VARIABLE"); break;
542 		    case SLC_DEFAULT:
543 			fprintf(NetTrace, " DEFAULT"); break;
544 		    }
545 		    fprintf(NetTrace, "%s%s%s",
546 			pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "",
547 			pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "",
548 			pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : "");
549 		    if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN|
550 						SLC_FLUSHOUT| SLC_LEVELBITS))
551 			fprintf(NetTrace, "(0x%x)", pointer[i+SLC_FLAGS]);
552 		    fprintf(NetTrace, " %d;", pointer[i+SLC_VALUE]);
553 		    if ((pointer[i+SLC_VALUE] == IAC) &&
554 			(pointer[i+SLC_VALUE+1] == IAC))
555 				i++;
556 		}
557 		for (; i < length; i++)
558 		    fprintf(NetTrace, " ?%d?", pointer[i]);
559 		break;
560 
561 	    case LM_MODE:
562 		fprintf(NetTrace, "MODE ");
563 		if (length < 3) {
564 		    fprintf(NetTrace, "(no mode??\?)");
565 		    break;
566 		}
567 		{
568 		    char tbuf[64];
569 		    sprintf(tbuf, "%s%s%s%s%s",
570 			pointer[2]&MODE_EDIT ? "|EDIT" : "",
571 			pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "",
572 			pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "",
573 			pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "",
574 			pointer[2]&MODE_ACK ? "|ACK" : "");
575 		    fprintf(NetTrace, "%s", tbuf[1] ? &tbuf[1] : "0");
576 		}
577 		if (pointer[2]&~(MODE_MASK))
578 		    fprintf(NetTrace, " (0x%x)", pointer[2]);
579 		for (i = 3; i < length; i++)
580 		    fprintf(NetTrace, " ?0x%x?", pointer[i]);
581 		break;
582 	    default:
583 		fprintf(NetTrace, "%d (unknown)", pointer[1]);
584 		for (i = 2; i < length; i++)
585 		    fprintf(NetTrace, " %d", pointer[i]);
586 	    }
587 	    break;
588 
589 	case TELOPT_STATUS: {
590 	    register char *cp;
591 	    register int j, k;
592 
593 	    fprintf(NetTrace, "STATUS");
594 
595 	    switch (pointer[1]) {
596 	    default:
597 		if (pointer[1] == TELQUAL_SEND)
598 		    fprintf(NetTrace, " SEND");
599 		else
600 		    fprintf(NetTrace, " %d (unknown)", pointer[1]);
601 		for (i = 2; i < length; i++)
602 		    fprintf(NetTrace, " ?%d?", pointer[i]);
603 		break;
604 	    case TELQUAL_IS:
605 		if (--want_status_response < 0)
606 		    want_status_response = 0;
607 		if (NetTrace == stdout)
608 		    fprintf(NetTrace, " IS\r\n");
609 		else
610 		    fprintf(NetTrace, " IS\n");
611 
612 		for (i = 2; i < length; i++) {
613 		    switch(pointer[i]) {
614 		    case DO:	cp = "DO"; goto common2;
615 		    case DONT:	cp = "DONT"; goto common2;
616 		    case WILL:	cp = "WILL"; goto common2;
617 		    case WONT:	cp = "WONT"; goto common2;
618 		    common2:
619 			i++;
620 			if (TELOPT_OK((int)pointer[i]))
621 			    fprintf(NetTrace, " %s %s", cp, TELOPT(pointer[i]));
622 			else
623 			    fprintf(NetTrace, " %s %d", cp, pointer[i]);
624 
625 			if (NetTrace == stdout)
626 			    fprintf(NetTrace, "\r\n");
627 			else
628 			    fprintf(NetTrace, "\n");
629 			break;
630 
631 		    case SB:
632 			fprintf(NetTrace, " SB ");
633 			i++;
634 			j = k = i;
635 			while (j < length) {
636 			    if (pointer[j] == SE) {
637 				if (j+1 == length)
638 				    break;
639 				if (pointer[j+1] == SE)
640 				    j++;
641 				else
642 				    break;
643 			    }
644 			    pointer[k++] = pointer[j++];
645 			}
646 			printsub(0, &pointer[i], k - i);
647 			if (i < length) {
648 			    fprintf(NetTrace, " SE");
649 			    i = j;
650 			} else
651 			    i = j - 1;
652 
653 			if (NetTrace == stdout)
654 			    fprintf(NetTrace, "\r\n");
655 			else
656 			    fprintf(NetTrace, "\n");
657 
658 			break;
659 
660 		    default:
661 			fprintf(NetTrace, " %d", pointer[i]);
662 			break;
663 		    }
664 		}
665 		break;
666 	    }
667 	    break;
668 	  }
669 
670 	case TELOPT_XDISPLOC:
671 	    fprintf(NetTrace, "X-DISPLAY-LOCATION ");
672 	    switch (pointer[1]) {
673 	    case TELQUAL_IS:
674 		fprintf(NetTrace, "IS \"%.*s\"", length-2, (char *)pointer+2);
675 		break;
676 	    case TELQUAL_SEND:
677 		fprintf(NetTrace, "SEND");
678 		break;
679 	    default:
680 		fprintf(NetTrace, "- unknown qualifier %d (0x%x).",
681 				pointer[1], pointer[1]);
682 	    }
683 	    break;
684 
685 	case TELOPT_NEW_ENVIRON:
686 	    fprintf(NetTrace, "NEW-ENVIRON ");
687 #ifdef	OLD_ENVIRON
688 	    goto env_common1;
689 	case TELOPT_OLD_ENVIRON:
690 	    fprintf(NetTrace, "OLD-ENVIRON");
691 	env_common1:
692 #endif
693 	    switch (pointer[1]) {
694 	    case TELQUAL_IS:
695 		fprintf(NetTrace, "IS ");
696 		goto env_common;
697 	    case TELQUAL_SEND:
698 		fprintf(NetTrace, "SEND ");
699 		goto env_common;
700 	    case TELQUAL_INFO:
701 		fprintf(NetTrace, "INFO ");
702 	    env_common:
703 		{
704 		    register int noquote = 2;
705 #if defined(ENV_HACK) && defined(OLD_ENVIRON)
706 		    extern int old_env_var, old_env_value;
707 #endif
708 		    for (i = 2; i < length; i++ ) {
709 			switch (pointer[i]) {
710 			case NEW_ENV_VALUE:
711 #ifdef OLD_ENVIRON
712 		     /*	case NEW_ENV_OVAR: */
713 			    if (pointer[0] == TELOPT_OLD_ENVIRON) {
714 # ifdef	ENV_HACK
715 				if (old_env_var == OLD_ENV_VALUE)
716 				    fprintf(NetTrace, "\" (VALUE) " + noquote);
717 				else
718 # endif
719 				    fprintf(NetTrace, "\" VAR " + noquote);
720 			    } else
721 #endif /* OLD_ENVIRON */
722 				fprintf(NetTrace, "\" VALUE " + noquote);
723 			    noquote = 2;
724 			    break;
725 
726 			case NEW_ENV_VAR:
727 #ifdef OLD_ENVIRON
728 		     /* case OLD_ENV_VALUE: */
729 			    if (pointer[0] == TELOPT_OLD_ENVIRON) {
730 # ifdef	ENV_HACK
731 				if (old_env_value == OLD_ENV_VAR)
732 				    fprintf(NetTrace, "\" (VAR) " + noquote);
733 				else
734 # endif
735 				    fprintf(NetTrace, "\" VALUE " + noquote);
736 			    } else
737 #endif /* OLD_ENVIRON */
738 				fprintf(NetTrace, "\" VAR " + noquote);
739 			    noquote = 2;
740 			    break;
741 
742 			case ENV_ESC:
743 			    fprintf(NetTrace, "\" ESC " + noquote);
744 			    noquote = 2;
745 			    break;
746 
747 			case ENV_USERVAR:
748 			    fprintf(NetTrace, "\" USERVAR " + noquote);
749 			    noquote = 2;
750 			    break;
751 
752 			default:
753 			def_case:
754 			    if (isprint(pointer[i]) && pointer[i] != '"') {
755 				if (noquote) {
756 				    putc('"', NetTrace);
757 				    noquote = 0;
758 				}
759 				putc(pointer[i], NetTrace);
760 			    } else {
761 				fprintf(NetTrace, "\" %03o " + noquote,
762 							pointer[i]);
763 				noquote = 2;
764 			    }
765 			    break;
766 			}
767 		    }
768 		    if (!noquote)
769 			putc('"', NetTrace);
770 		    break;
771 		}
772 	    }
773 	    break;
774 
775 	default:
776 	    if (TELOPT_OK(pointer[0]))
777 		fprintf(NetTrace, "%s (unknown)", TELOPT(pointer[0]));
778 	    else
779 		fprintf(NetTrace, "%d (unknown)", pointer[0]);
780 	    for (i = 1; i < length; i++)
781 		fprintf(NetTrace, " %d", pointer[i]);
782 	    break;
783 	}
784 	if (direction) {
785 	    if (NetTrace == stdout)
786 		fprintf(NetTrace, "\r\n");
787 	    else
788 		fprintf(NetTrace, "\n");
789 	}
790 	if (NetTrace == stdout)
791 	    fflush(NetTrace);
792     }
793 }
794 
795 /* EmptyTerminal - called to make sure that the terminal buffer is empty.
796  *			Note that we consider the buffer to run all the
797  *			way to the kernel (thus the select).
798  */
799 
800     void
801 EmptyTerminal()
802 {
803 #if	defined(unix)
804     fd_set	o;
805 
806     FD_ZERO(&o);
807 #endif	/* defined(unix) */
808 
809     if (TTYBYTES() == 0) {
810 #if	defined(unix)
811 	FD_SET(tout, &o);
812 	(void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
813 			(struct timeval *) 0);	/* wait for TTLOWAT */
814 #endif	/* defined(unix) */
815     } else {
816 	while (TTYBYTES()) {
817 	    (void) ttyflush(0);
818 #if	defined(unix)
819 	    FD_SET(tout, &o);
820 	    (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
821 				(struct timeval *) 0);	/* wait for TTLOWAT */
822 #endif	/* defined(unix) */
823 	}
824     }
825 }
826 
827     void
828 SetForExit()
829 {
830     setconnmode(0);
831 #if	defined(TN3270)
832     if (In3270) {
833 	Finish3270();
834     }
835 #else	/* defined(TN3270) */
836     do {
837 	(void)telrcv();			/* Process any incoming data */
838 	EmptyTerminal();
839     } while (ring_full_count(&netiring));	/* While there is any */
840 #endif	/* defined(TN3270) */
841     setcommandmode();
842     fflush(stdout);
843     fflush(stderr);
844 #if	defined(TN3270)
845     if (In3270) {
846 	StopScreen(1);
847     }
848 #endif	/* defined(TN3270) */
849     setconnmode(0);
850     EmptyTerminal();			/* Flush the path to the tty */
851     setcommandmode();
852 }
853 
854     void
855 Exit(returnCode)
856     int returnCode;
857 {
858     SetForExit();
859     exit(returnCode);
860 }
861 
862     void
863 ExitString(string, returnCode)
864     char *string;
865     int returnCode;
866 {
867     SetForExit();
868     fwrite(string, 1, strlen(string), stderr);
869     exit(returnCode);
870 }
871