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