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