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