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