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