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