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