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