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