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$");
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
251static void __attribute__((format (printf, 3, 4)))
252qprintf(int quote, FILE *f, const char *fmt, ...)
253
254{
255    va_list va;
256    if (quote)
257	fprintf(f, "\" ");
258    va_start(va, fmt);
259    vfprintf(f, fmt, va);
260    va_end(va);
261}
262
263void
264printsub(int direction, unsigned char *pointer, size_t length)
265{
266    int i;
267    unsigned char buf[512];
268
269    if (showoptions || direction == 0 ||
270	(want_status_response && (pointer[0] == TELOPT_STATUS))) {
271	if (direction) {
272	    fprintf(NetTrace, "%s IAC SB ",
273				(direction == '<')? "RCVD":"SENT");
274	    if (length >= 3) {
275		int j;
276
277		i = pointer[length-2];
278		j = pointer[length-1];
279
280		if (i != IAC || j != SE) {
281		    fprintf(NetTrace, "(terminated by ");
282		    if (TELOPT_OK(i))
283			fprintf(NetTrace, "%s ", TELOPT(i));
284		    else if (TELCMD_OK(i))
285			fprintf(NetTrace, "%s ", TELCMD(i));
286		    else
287			fprintf(NetTrace, "%d ", i);
288		    if (TELOPT_OK(j))
289			fprintf(NetTrace, "%s", TELOPT(j));
290		    else if (TELCMD_OK(j))
291			fprintf(NetTrace, "%s", TELCMD(j));
292		    else
293			fprintf(NetTrace, "%d", j);
294		    fprintf(NetTrace, ", not IAC SE!) ");
295		}
296	    }
297	    length -= 2;
298	}
299	if (length < 1) {
300	    fprintf(NetTrace, "(Empty suboption??\?)");
301	    if (NetTrace == stdout)
302		fflush(NetTrace);
303	    return;
304	}
305	switch (pointer[0]) {
306	case TELOPT_TTYPE:
307	    fprintf(NetTrace, "TERMINAL-TYPE ");
308	    switch (pointer[1]) {
309	    case TELQUAL_IS:
310		fprintf(NetTrace, "IS \"%.*s\"",
311			(int)(length-2),
312			(char *)pointer+2);
313		break;
314	    case TELQUAL_SEND:
315		fprintf(NetTrace, "SEND");
316		break;
317	    default:
318		fprintf(NetTrace,
319				"- unknown qualifier %d (0x%x).",
320				pointer[1], pointer[1]);
321	    }
322	    break;
323	case TELOPT_TSPEED:
324	    fprintf(NetTrace, "TERMINAL-SPEED");
325	    if (length < 2) {
326		fprintf(NetTrace, " (empty suboption??\?)");
327		break;
328	    }
329	    switch (pointer[1]) {
330	    case TELQUAL_IS:
331		fprintf(NetTrace, " IS ");
332		fprintf(NetTrace, "%.*s", (int)(length-2), (char *)pointer+2);
333		break;
334	    default:
335		if (pointer[1] == 1)
336		    fprintf(NetTrace, " SEND");
337		else
338		    fprintf(NetTrace, " %d (unknown)", pointer[1]);
339		for (i = 2; i < length; i++)
340		    fprintf(NetTrace, " ?%d?", pointer[i]);
341		break;
342	    }
343	    break;
344
345	case TELOPT_LFLOW:
346	    fprintf(NetTrace, "TOGGLE-FLOW-CONTROL");
347	    if (length < 2) {
348		fprintf(NetTrace, " (empty suboption??\?)");
349		break;
350	    }
351	    switch (pointer[1]) {
352	    case LFLOW_OFF:
353		fprintf(NetTrace, " OFF"); break;
354	    case LFLOW_ON:
355		fprintf(NetTrace, " ON"); break;
356	    case LFLOW_RESTART_ANY:
357		fprintf(NetTrace, " RESTART-ANY"); break;
358	    case LFLOW_RESTART_XON:
359		fprintf(NetTrace, " RESTART-XON"); break;
360	    default:
361		fprintf(NetTrace, " %d (unknown)", pointer[1]);
362	    }
363	    for (i = 2; i < length; i++)
364		fprintf(NetTrace, " ?%d?", pointer[i]);
365	    break;
366
367	case TELOPT_NAWS:
368	    fprintf(NetTrace, "NAWS");
369	    if (length < 2) {
370		fprintf(NetTrace, " (empty suboption??\?)");
371		break;
372	    }
373	    if (length == 2) {
374		fprintf(NetTrace, " ?%d?", pointer[1]);
375		break;
376	    }
377	    fprintf(NetTrace, " %d %d (%d)",
378		pointer[1], pointer[2],
379		(int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2])));
380	    if (length == 4) {
381		fprintf(NetTrace, " ?%d?", pointer[3]);
382		break;
383	    }
384	    fprintf(NetTrace, " %d %d (%d)",
385		pointer[3], pointer[4],
386		(int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4])));
387	    for (i = 5; i < length; i++)
388		fprintf(NetTrace, " ?%d?", pointer[i]);
389	    break;
390
391#if	defined(AUTHENTICATION)
392	case TELOPT_AUTHENTICATION:
393	    fprintf(NetTrace, "AUTHENTICATION");
394	    if (length < 2) {
395		fprintf(NetTrace, " (empty suboption??\?)");
396		break;
397	    }
398	    switch (pointer[1]) {
399	    case TELQUAL_REPLY:
400	    case TELQUAL_IS:
401		fprintf(NetTrace, " %s ", (pointer[1] == TELQUAL_IS) ?
402							"IS" : "REPLY");
403		if (AUTHTYPE_NAME_OK(pointer[2]))
404		    fprintf(NetTrace, "%s ", AUTHTYPE_NAME(pointer[2]));
405		else
406		    fprintf(NetTrace, "%d ", pointer[2]);
407		if (length < 3) {
408		    fprintf(NetTrace, "(partial suboption??\?)");
409		    break;
410		}
411		fprintf(NetTrace, "%s|%s",
412			((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
413			"CLIENT" : "SERVER",
414			((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
415			"MUTUAL" : "ONE-WAY");
416
417		auth_printsub(&pointer[1], length - 1, buf, sizeof(buf));
418		fprintf(NetTrace, "%s", buf);
419		break;
420
421	    case TELQUAL_SEND:
422		i = 2;
423		fprintf(NetTrace, " SEND ");
424		while (i < length) {
425		    if (AUTHTYPE_NAME_OK(pointer[i]))
426			fprintf(NetTrace, "%s ", AUTHTYPE_NAME(pointer[i]));
427		    else
428			fprintf(NetTrace, "%d ", pointer[i]);
429		    if (++i >= length) {
430			fprintf(NetTrace, "(partial suboption??\?)");
431			break;
432		    }
433		    fprintf(NetTrace, "%s|%s ",
434			((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
435							"CLIENT" : "SERVER",
436			((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
437							"MUTUAL" : "ONE-WAY");
438		    ++i;
439		}
440		break;
441
442	    case TELQUAL_NAME:
443		i = 2;
444		fprintf(NetTrace, " NAME \"");
445		while (i < length)
446		    putc(pointer[i++], NetTrace);
447		putc('"', NetTrace);
448		break;
449
450	    default:
451		    for (i = 2; i < length; i++)
452			fprintf(NetTrace, " ?%d?", pointer[i]);
453		    break;
454	    }
455	    break;
456#endif
457
458#if	defined(ENCRYPTION)
459	case TELOPT_ENCRYPT:
460	    fprintf(NetTrace, "ENCRYPT");
461	    if (length < 2) {
462		fprintf(NetTrace, " (empty suboption?)");
463		break;
464	    }
465	    switch (pointer[1]) {
466	    case ENCRYPT_START:
467		fprintf(NetTrace, " START");
468		break;
469
470	    case ENCRYPT_END:
471		fprintf(NetTrace, " END");
472		break;
473
474	    case ENCRYPT_REQSTART:
475		fprintf(NetTrace, " REQUEST-START");
476		break;
477
478	    case ENCRYPT_REQEND:
479		fprintf(NetTrace, " REQUEST-END");
480		break;
481
482	    case ENCRYPT_IS:
483	    case ENCRYPT_REPLY:
484		fprintf(NetTrace, " %s ", (pointer[1] == ENCRYPT_IS) ?
485							"IS" : "REPLY");
486		if (length < 3) {
487		    fprintf(NetTrace, " (partial suboption?)");
488		    break;
489		}
490		if (ENCTYPE_NAME_OK(pointer[2]))
491		    fprintf(NetTrace, "%s ", ENCTYPE_NAME(pointer[2]));
492		else
493		    fprintf(NetTrace, " %d (unknown)", pointer[2]);
494
495		encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf));
496		fprintf(NetTrace, "%s", buf);
497		break;
498
499	    case ENCRYPT_SUPPORT:
500		i = 2;
501		fprintf(NetTrace, " SUPPORT ");
502		while (i < length) {
503		    if (ENCTYPE_NAME_OK(pointer[i]))
504			fprintf(NetTrace, "%s ", ENCTYPE_NAME(pointer[i]));
505		    else
506			fprintf(NetTrace, "%d ", pointer[i]);
507		    i++;
508		}
509		break;
510
511	    case ENCRYPT_ENC_KEYID:
512		fprintf(NetTrace, " ENC_KEYID ");
513		goto encommon;
514
515	    case ENCRYPT_DEC_KEYID:
516		fprintf(NetTrace, " DEC_KEYID ");
517		goto encommon;
518
519	    default:
520		fprintf(NetTrace, " %d (unknown)", pointer[1]);
521	    encommon:
522		for (i = 2; i < length; i++)
523		    fprintf(NetTrace, " %d", pointer[i]);
524		break;
525	    }
526	    break;
527#endif
528
529	case TELOPT_LINEMODE:
530	    fprintf(NetTrace, "LINEMODE ");
531	    if (length < 2) {
532		fprintf(NetTrace, " (empty suboption??\?)");
533		break;
534	    }
535	    switch (pointer[1]) {
536	    case WILL:
537		fprintf(NetTrace, "WILL ");
538		goto common;
539	    case WONT:
540		fprintf(NetTrace, "WONT ");
541		goto common;
542	    case DO:
543		fprintf(NetTrace, "DO ");
544		goto common;
545	    case DONT:
546		fprintf(NetTrace, "DONT ");
547	    common:
548		if (length < 3) {
549		    fprintf(NetTrace, "(no option??\?)");
550		    break;
551		}
552		switch (pointer[2]) {
553		case LM_FORWARDMASK:
554		    fprintf(NetTrace, "Forward Mask");
555		    for (i = 3; i < length; i++)
556			fprintf(NetTrace, " %x", pointer[i]);
557		    break;
558		default:
559		    fprintf(NetTrace, "%d (unknown)", pointer[2]);
560		    for (i = 3; i < length; i++)
561			fprintf(NetTrace, " %d", pointer[i]);
562		    break;
563		}
564		break;
565
566	    case LM_SLC:
567		fprintf(NetTrace, "SLC");
568		for (i = 2; i < length - 2; i += 3) {
569		    if (SLC_NAME_OK(pointer[i+SLC_FUNC]))
570			fprintf(NetTrace, " %s", SLC_NAME(pointer[i+SLC_FUNC]));
571		    else
572			fprintf(NetTrace, " %d", pointer[i+SLC_FUNC]);
573		    switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) {
574		    case SLC_NOSUPPORT:
575			fprintf(NetTrace, " NOSUPPORT"); break;
576		    case SLC_CANTCHANGE:
577			fprintf(NetTrace, " CANTCHANGE"); break;
578		    case SLC_VARIABLE:
579			fprintf(NetTrace, " VARIABLE"); break;
580		    case SLC_DEFAULT:
581			fprintf(NetTrace, " DEFAULT"); break;
582		    }
583		    fprintf(NetTrace, "%s%s%s",
584			pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "",
585			pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "",
586			pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : "");
587		    if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN|
588						SLC_FLUSHOUT| SLC_LEVELBITS))
589			fprintf(NetTrace, "(0x%x)", pointer[i+SLC_FLAGS]);
590		    fprintf(NetTrace, " %d;", pointer[i+SLC_VALUE]);
591		    if ((pointer[i+SLC_VALUE] == IAC) &&
592			(pointer[i+SLC_VALUE+1] == IAC))
593				i++;
594		}
595		for (; i < length; i++)
596		    fprintf(NetTrace, " ?%d?", pointer[i]);
597		break;
598
599	    case LM_MODE:
600		fprintf(NetTrace, "MODE ");
601		if (length < 3) {
602		    fprintf(NetTrace, "(no mode??\?)");
603		    break;
604		}
605		{
606		    char tbuf[64];
607		    snprintf(tbuf, sizeof(tbuf),
608			     "%s%s%s%s%s",
609			     pointer[2]&MODE_EDIT ? "|EDIT" : "",
610			     pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "",
611			     pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "",
612			     pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "",
613			     pointer[2]&MODE_ACK ? "|ACK" : "");
614		    fprintf(NetTrace, "%s", tbuf[1] ? &tbuf[1] : "0");
615		}
616		if (pointer[2]&~(MODE_MASK))
617		    fprintf(NetTrace, " (0x%x)", pointer[2]);
618		for (i = 3; i < length; i++)
619		    fprintf(NetTrace, " ?0x%x?", pointer[i]);
620		break;
621	    default:
622		fprintf(NetTrace, "%d (unknown)", pointer[1]);
623		for (i = 2; i < length; i++)
624		    fprintf(NetTrace, " %d", pointer[i]);
625	    }
626	    break;
627
628	case TELOPT_STATUS: {
629	    char *cp;
630	    int j, k;
631
632	    fprintf(NetTrace, "STATUS");
633
634	    switch (pointer[1]) {
635	    default:
636		if (pointer[1] == TELQUAL_SEND)
637		    fprintf(NetTrace, " SEND");
638		else
639		    fprintf(NetTrace, " %d (unknown)", pointer[1]);
640		for (i = 2; i < length; i++)
641		    fprintf(NetTrace, " ?%d?", pointer[i]);
642		break;
643	    case TELQUAL_IS:
644		if (--want_status_response < 0)
645		    want_status_response = 0;
646		if (NetTrace == stdout)
647		    fprintf(NetTrace, " IS\r\n");
648		else
649		    fprintf(NetTrace, " IS\n");
650
651		for (i = 2; i < length; i++) {
652		    switch(pointer[i]) {
653		    case DO:	cp = "DO"; goto common2;
654		    case DONT:	cp = "DONT"; goto common2;
655		    case WILL:	cp = "WILL"; goto common2;
656		    case WONT:	cp = "WONT"; goto common2;
657		    common2:
658			i++;
659			if (TELOPT_OK((int)pointer[i]))
660			    fprintf(NetTrace, " %s %s", cp, TELOPT(pointer[i]));
661			else
662			    fprintf(NetTrace, " %s %d", cp, pointer[i]);
663
664			if (NetTrace == stdout)
665			    fprintf(NetTrace, "\r\n");
666			else
667			    fprintf(NetTrace, "\n");
668			break;
669
670		    case SB:
671			fprintf(NetTrace, " SB ");
672			i++;
673			j = k = i;
674			while (j < length) {
675			    if (pointer[j] == SE) {
676				if (j+1 == length)
677				    break;
678				if (pointer[j+1] == SE)
679				    j++;
680				else
681				    break;
682			    }
683			    pointer[k++] = pointer[j++];
684			}
685			printsub(0, &pointer[i], k - i);
686			if (i < length) {
687			    fprintf(NetTrace, " SE");
688			    i = j;
689			} else
690			    i = j - 1;
691
692			if (NetTrace == stdout)
693			    fprintf(NetTrace, "\r\n");
694			else
695			    fprintf(NetTrace, "\n");
696
697			break;
698
699		    default:
700			fprintf(NetTrace, " %d", pointer[i]);
701			break;
702		    }
703		}
704		break;
705	    }
706	    break;
707	  }
708
709	case TELOPT_XDISPLOC:
710	    fprintf(NetTrace, "X-DISPLAY-LOCATION ");
711	    switch (pointer[1]) {
712	    case TELQUAL_IS:
713		fprintf(NetTrace, "IS \"%.*s\"", (int)(length-2), (char *)pointer+2);
714		break;
715	    case TELQUAL_SEND:
716		fprintf(NetTrace, "SEND");
717		break;
718	    default:
719		fprintf(NetTrace, "- unknown qualifier %d (0x%x).",
720				pointer[1], pointer[1]);
721	    }
722	    break;
723
724	case TELOPT_NEW_ENVIRON:
725	    fprintf(NetTrace, "NEW-ENVIRON ");
726#ifdef	OLD_ENVIRON
727	    goto env_common1;
728	case TELOPT_OLD_ENVIRON:
729	    fprintf(NetTrace, "OLD-ENVIRON");
730	env_common1:
731#endif
732	    switch (pointer[1]) {
733	    case TELQUAL_IS:
734		fprintf(NetTrace, "IS ");
735		goto env_common;
736	    case TELQUAL_SEND:
737		fprintf(NetTrace, "SEND ");
738		goto env_common;
739	    case TELQUAL_INFO:
740		fprintf(NetTrace, "INFO ");
741	    env_common:
742		{
743		    int quote = 0;
744		    for (i = 2; i < length; i++ ) {
745			switch (pointer[i]) {
746			case NEW_ENV_VAR:
747			    qprintf(quote, NetTrace, "VAR ");
748			    quote = 0;
749			    break;
750
751			case NEW_ENV_VALUE:
752			    qprintf(quote, NetTrace, "VALUE");
753			    quote = 0;
754			    break;
755
756			case ENV_ESC:
757			    qprintf(quote, NetTrace, "ESC ");
758			    quote = 0;
759			    break;
760
761			case ENV_USERVAR:
762			    qprintf(quote, NetTrace, "USERVAR ");
763			    quote = 0;
764			    break;
765
766			default:
767			    if (isprint(pointer[i]) && pointer[i] != '"') {
768				if (!quote) {
769				    putc('"', NetTrace);
770				    quote = 1;
771				}
772				putc(pointer[i], NetTrace);
773			    } else {
774				qprintf(quote, NetTrace, "%03o ", pointer[i]);
775				quote = 0;
776			    }
777			    break;
778			}
779		    }
780		    if (quote)
781			putc('"', NetTrace);
782		    break;
783		}
784	    }
785	    break;
786
787	default:
788	    if (TELOPT_OK(pointer[0]))
789		fprintf(NetTrace, "%s (unknown)", TELOPT(pointer[0]));
790	    else
791		fprintf(NetTrace, "%d (unknown)", pointer[0]);
792	    for (i = 1; i < length; i++)
793		fprintf(NetTrace, " %d", pointer[i]);
794	    break;
795	}
796	if (direction) {
797	    if (NetTrace == stdout)
798		fprintf(NetTrace, "\r\n");
799	    else
800		fprintf(NetTrace, "\n");
801	}
802	if (NetTrace == stdout)
803	    fflush(NetTrace);
804    }
805}
806
807/* EmptyTerminal - called to make sure that the terminal buffer is empty.
808 *			Note that we consider the buffer to run all the
809 *			way to the kernel (thus the select).
810 */
811
812void
813EmptyTerminal(void)
814{
815    fd_set	outs;
816
817    FD_ZERO(&outs);
818
819    if (tout >= FD_SETSIZE)
820	ExitString("fd too large", 1);
821
822    if (TTYBYTES() == 0) {
823	FD_SET(tout, &outs);
824	select(tout+1, 0, &outs, 0,
825		      (struct timeval *) 0); /* wait for TTLOWAT */
826    } else {
827	while (TTYBYTES()) {
828	    ttyflush(0);
829	    FD_SET(tout, &outs);
830	    select(tout+1, 0, &outs, 0,
831			  (struct timeval *) 0); /* wait for TTLOWAT */
832	}
833    }
834}
835
836void
837SetForExit(void)
838{
839    setconnmode(0);
840    do {
841	telrcv();			/* Process any incoming data */
842	EmptyTerminal();
843    } while (ring_full_count(&netiring));	/* While there is any */
844    setcommandmode();
845    fflush(stdout);
846    fflush(stderr);
847    setconnmode(0);
848    EmptyTerminal();			/* Flush the path to the tty */
849    setcommandmode();
850}
851
852void
853Exit(int returnCode)
854{
855    SetForExit();
856    exit(returnCode);
857}
858
859void
860ExitString(char *string, int returnCode)
861{
862    SetForExit();
863    fwrite(string, 1, strlen(string), stderr);
864    exit(returnCode);
865}
866