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