utilities.c revision 29088
129088Smarkm/*
229088Smarkm * Copyright (c) 1988, 1993
329088Smarkm *	The Regents of the University of California.  All rights reserved.
429088Smarkm *
529088Smarkm * Redistribution and use in source and binary forms, with or without
629088Smarkm * modification, are permitted provided that the following conditions
729088Smarkm * are met:
829088Smarkm * 1. Redistributions of source code must retain the above copyright
929088Smarkm *    notice, this list of conditions and the following disclaimer.
1029088Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1129088Smarkm *    notice, this list of conditions and the following disclaimer in the
1229088Smarkm *    documentation and/or other materials provided with the distribution.
1329088Smarkm * 3. All advertising materials mentioning features or use of this software
1429088Smarkm *    must display the following acknowledgement:
1529088Smarkm *	This product includes software developed by the University of
1629088Smarkm *	California, Berkeley and its contributors.
1729088Smarkm * 4. Neither the name of the University nor the names of its contributors
1829088Smarkm *    may be used to endorse or promote products derived from this software
1929088Smarkm *    without specific prior written permission.
2029088Smarkm *
2129088Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2229088Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2329088Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2429088Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2529088Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2629088Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2729088Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2829088Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2929088Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3029088Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3129088Smarkm * SUCH DAMAGE.
3229088Smarkm */
3329088Smarkm
3429088Smarkm#ifndef lint
3529088Smarkmstatic char sccsid[] = "@(#)utilities.c	8.3 (Berkeley) 5/30/95";
3629088Smarkm#endif /* not lint */
3729088Smarkm
3829088Smarkm#define	TELOPTS
3929088Smarkm#define	TELCMDS
4029088Smarkm#define	SLC_NAMES
4129088Smarkm#include <arpa/telnet.h>
4229088Smarkm#include <sys/types.h>
4329088Smarkm#include <sys/time.h>
4429088Smarkm
4529088Smarkm#include <ctype.h>
4629088Smarkm
4729088Smarkm#include "general.h"
4829088Smarkm
4929088Smarkm#include "fdset.h"
5029088Smarkm
5129088Smarkm#include "ring.h"
5229088Smarkm
5329088Smarkm#include "defines.h"
5429088Smarkm
5529088Smarkm#include "externs.h"
5629088Smarkm
5729088SmarkmFILE	*NetTrace = 0;		/* Not in bss, since needs to stay */
5829088Smarkmint	prettydump;
5929088Smarkm
6029088Smarkm/*
6129088Smarkm * upcase()
6229088Smarkm *
6329088Smarkm *	Upcase (in place) the argument.
6429088Smarkm */
6529088Smarkm
6629088Smarkm    void
6729088Smarkmupcase(argument)
6829088Smarkm    register char *argument;
6929088Smarkm{
7029088Smarkm    register int c;
7129088Smarkm
7229088Smarkm    while ((c = *argument) != 0) {
7329088Smarkm	if (islower(c)) {
7429088Smarkm	    *argument = toupper(c);
7529088Smarkm	}
7629088Smarkm	argument++;
7729088Smarkm    }
7829088Smarkm}
7929088Smarkm
8029088Smarkm/*
8129088Smarkm * SetSockOpt()
8229088Smarkm *
8329088Smarkm * Compensate for differences in 4.2 and 4.3 systems.
8429088Smarkm */
8529088Smarkm
8629088Smarkm    int
8729088SmarkmSetSockOpt(fd, level, option, yesno)
8829088Smarkm    int fd, level, option, yesno;
8929088Smarkm{
9029088Smarkm#ifndef	NOT43
9129088Smarkm    return setsockopt(fd, level, option,
9229088Smarkm				(char *)&yesno, sizeof yesno);
9329088Smarkm#else	/* NOT43 */
9429088Smarkm    if (yesno == 0) {		/* Can't do that in 4.2! */
9529088Smarkm	fprintf(stderr, "Error: attempt to turn off an option 0x%x.\n",
9629088Smarkm				option);
9729088Smarkm	return -1;
9829088Smarkm    }
9929088Smarkm    return setsockopt(fd, level, option, 0, 0);
10029088Smarkm#endif	/* NOT43 */
10129088Smarkm}
10229088Smarkm
10329088Smarkm/*
10429088Smarkm * The following are routines used to print out debugging information.
10529088Smarkm */
10629088Smarkm
10729088Smarkmunsigned char NetTraceFile[256] = "(standard output)";
10829088Smarkm
10929088Smarkm    void
11029088SmarkmSetNetTrace(file)
11129088Smarkm    register char *file;
11229088Smarkm{
11329088Smarkm    if (NetTrace && NetTrace != stdout)
11429088Smarkm	fclose(NetTrace);
11529088Smarkm    if (file  && (strcmp(file, "-") != 0)) {
11629088Smarkm	NetTrace = fopen(file, "w");
11729088Smarkm	if (NetTrace) {
11829088Smarkm	    strcpy((char *)NetTraceFile, file);
11929088Smarkm	    return;
12029088Smarkm	}
12129088Smarkm	fprintf(stderr, "Cannot open %s.\n", file);
12229088Smarkm    }
12329088Smarkm    NetTrace = stdout;
12429088Smarkm    strcpy((char *)NetTraceFile, "(standard output)");
12529088Smarkm}
12629088Smarkm
12729088Smarkm    void
12829088SmarkmDump(direction, buffer, length)
12929088Smarkm    char direction;
13029088Smarkm    unsigned char *buffer;
13129088Smarkm    int length;
13229088Smarkm{
13329088Smarkm#   define BYTES_PER_LINE	32
13429088Smarkm#   define min(x,y)	((x<y)? x:y)
13529088Smarkm    unsigned char *pThis;
13629088Smarkm    int offset;
13729088Smarkm    extern pettydump;
13829088Smarkm
13929088Smarkm    offset = 0;
14029088Smarkm
14129088Smarkm    while (length) {
14229088Smarkm	/* print one line */
14329088Smarkm	fprintf(NetTrace, "%c 0x%x\t", direction, offset);
14429088Smarkm	pThis = buffer;
14529088Smarkm	if (prettydump) {
14629088Smarkm	    buffer = buffer + min(length, BYTES_PER_LINE/2);
14729088Smarkm	    while (pThis < buffer) {
14829088Smarkm		fprintf(NetTrace, "%c%.2x",
14929088Smarkm		    (((*pThis)&0xff) == 0xff) ? '*' : ' ',
15029088Smarkm		    (*pThis)&0xff);
15129088Smarkm		pThis++;
15229088Smarkm	    }
15329088Smarkm	    length -= BYTES_PER_LINE/2;
15429088Smarkm	    offset += BYTES_PER_LINE/2;
15529088Smarkm	} else {
15629088Smarkm	    buffer = buffer + min(length, BYTES_PER_LINE);
15729088Smarkm	    while (pThis < buffer) {
15829088Smarkm		fprintf(NetTrace, "%.2x", (*pThis)&0xff);
15929088Smarkm		pThis++;
16029088Smarkm	    }
16129088Smarkm	    length -= BYTES_PER_LINE;
16229088Smarkm	    offset += BYTES_PER_LINE;
16329088Smarkm	}
16429088Smarkm	if (NetTrace == stdout) {
16529088Smarkm	    fprintf(NetTrace, "\r\n");
16629088Smarkm	} else {
16729088Smarkm	    fprintf(NetTrace, "\n");
16829088Smarkm	}
16929088Smarkm	if (length < 0) {
17029088Smarkm	    fflush(NetTrace);
17129088Smarkm	    return;
17229088Smarkm	}
17329088Smarkm	/* find next unique line */
17429088Smarkm    }
17529088Smarkm    fflush(NetTrace);
17629088Smarkm}
17729088Smarkm
17829088Smarkm
17929088Smarkm	void
18029088Smarkmprintoption(direction, cmd, option)
18129088Smarkm	char *direction;
18229088Smarkm	int cmd, option;
18329088Smarkm{
18429088Smarkm	if (!showoptions)
18529088Smarkm		return;
18629088Smarkm	if (cmd == IAC) {
18729088Smarkm		if (TELCMD_OK(option))
18829088Smarkm		    fprintf(NetTrace, "%s IAC %s", direction, TELCMD(option));
18929088Smarkm		else
19029088Smarkm		    fprintf(NetTrace, "%s IAC %d", direction, option);
19129088Smarkm	} else {
19229088Smarkm		register char *fmt;
19329088Smarkm		fmt = (cmd == WILL) ? "WILL" : (cmd == WONT) ? "WONT" :
19429088Smarkm			(cmd == DO) ? "DO" : (cmd == DONT) ? "DONT" : 0;
19529088Smarkm		if (fmt) {
19629088Smarkm		    fprintf(NetTrace, "%s %s ", direction, fmt);
19729088Smarkm		    if (TELOPT_OK(option))
19829088Smarkm			fprintf(NetTrace, "%s", TELOPT(option));
19929088Smarkm		    else if (option == TELOPT_EXOPL)
20029088Smarkm			fprintf(NetTrace, "EXOPL");
20129088Smarkm		    else
20229088Smarkm			fprintf(NetTrace, "%d", option);
20329088Smarkm		} else
20429088Smarkm		    fprintf(NetTrace, "%s %d %d", direction, cmd, option);
20529088Smarkm	}
20629088Smarkm	if (NetTrace == stdout) {
20729088Smarkm	    fprintf(NetTrace, "\r\n");
20829088Smarkm	    fflush(NetTrace);
20929088Smarkm	} else {
21029088Smarkm	    fprintf(NetTrace, "\n");
21129088Smarkm	}
21229088Smarkm	return;
21329088Smarkm}
21429088Smarkm
21529088Smarkm    void
21629088Smarkmoptionstatus()
21729088Smarkm{
21829088Smarkm    register int i;
21929088Smarkm    extern char will_wont_resp[], do_dont_resp[];
22029088Smarkm
22129088Smarkm    for (i = 0; i < 256; i++) {
22229088Smarkm	if (do_dont_resp[i]) {
22329088Smarkm	    if (TELOPT_OK(i))
22429088Smarkm		printf("resp DO_DONT %s: %d\n", TELOPT(i), do_dont_resp[i]);
22529088Smarkm	    else if (TELCMD_OK(i))
22629088Smarkm		printf("resp DO_DONT %s: %d\n", TELCMD(i), do_dont_resp[i]);
22729088Smarkm	    else
22829088Smarkm		printf("resp DO_DONT %d: %d\n", i,
22929088Smarkm				do_dont_resp[i]);
23029088Smarkm	    if (my_want_state_is_do(i)) {
23129088Smarkm		if (TELOPT_OK(i))
23229088Smarkm		    printf("want DO   %s\n", TELOPT(i));
23329088Smarkm		else if (TELCMD_OK(i))
23429088Smarkm		    printf("want DO   %s\n", TELCMD(i));
23529088Smarkm		else
23629088Smarkm		    printf("want DO   %d\n", i);
23729088Smarkm	    } else {
23829088Smarkm		if (TELOPT_OK(i))
23929088Smarkm		    printf("want DONT %s\n", TELOPT(i));
24029088Smarkm		else if (TELCMD_OK(i))
24129088Smarkm		    printf("want DONT %s\n", TELCMD(i));
24229088Smarkm		else
24329088Smarkm		    printf("want DONT %d\n", i);
24429088Smarkm	    }
24529088Smarkm	} else {
24629088Smarkm	    if (my_state_is_do(i)) {
24729088Smarkm		if (TELOPT_OK(i))
24829088Smarkm		    printf("     DO   %s\n", TELOPT(i));
24929088Smarkm		else if (TELCMD_OK(i))
25029088Smarkm		    printf("     DO   %s\n", TELCMD(i));
25129088Smarkm		else
25229088Smarkm		    printf("     DO   %d\n", i);
25329088Smarkm	    }
25429088Smarkm	}
25529088Smarkm	if (will_wont_resp[i]) {
25629088Smarkm	    if (TELOPT_OK(i))
25729088Smarkm		printf("resp WILL_WONT %s: %d\n", TELOPT(i), will_wont_resp[i]);
25829088Smarkm	    else if (TELCMD_OK(i))
25929088Smarkm		printf("resp WILL_WONT %s: %d\n", TELCMD(i), will_wont_resp[i]);
26029088Smarkm	    else
26129088Smarkm		printf("resp WILL_WONT %d: %d\n",
26229088Smarkm				i, will_wont_resp[i]);
26329088Smarkm	    if (my_want_state_is_will(i)) {
26429088Smarkm		if (TELOPT_OK(i))
26529088Smarkm		    printf("want WILL %s\n", TELOPT(i));
26629088Smarkm		else if (TELCMD_OK(i))
26729088Smarkm		    printf("want WILL %s\n", TELCMD(i));
26829088Smarkm		else
26929088Smarkm		    printf("want WILL %d\n", i);
27029088Smarkm	    } else {
27129088Smarkm		if (TELOPT_OK(i))
27229088Smarkm		    printf("want WONT %s\n", TELOPT(i));
27329088Smarkm		else if (TELCMD_OK(i))
27429088Smarkm		    printf("want WONT %s\n", TELCMD(i));
27529088Smarkm		else
27629088Smarkm		    printf("want WONT %d\n", i);
27729088Smarkm	    }
27829088Smarkm	} else {
27929088Smarkm	    if (my_state_is_will(i)) {
28029088Smarkm		if (TELOPT_OK(i))
28129088Smarkm		    printf("     WILL %s\n", TELOPT(i));
28229088Smarkm		else if (TELCMD_OK(i))
28329088Smarkm		    printf("     WILL %s\n", TELCMD(i));
28429088Smarkm		else
28529088Smarkm		    printf("     WILL %d\n", i);
28629088Smarkm	    }
28729088Smarkm	}
28829088Smarkm    }
28929088Smarkm
29029088Smarkm}
29129088Smarkm
29229088Smarkm    void
29329088Smarkmprintsub(direction, pointer, length)
29429088Smarkm    char direction;	/* '<' or '>' */
29529088Smarkm    unsigned char *pointer;	/* where suboption data sits */
29629088Smarkm    int		  length;	/* length of suboption data */
29729088Smarkm{
29829088Smarkm    register int i;
29929088Smarkm    char buf[512];
30029088Smarkm    extern int want_status_response;
30129088Smarkm
30229088Smarkm    if (showoptions || direction == 0 ||
30329088Smarkm	(want_status_response && (pointer[0] == TELOPT_STATUS))) {
30429088Smarkm	if (direction) {
30529088Smarkm	    fprintf(NetTrace, "%s IAC SB ",
30629088Smarkm				(direction == '<')? "RCVD":"SENT");
30729088Smarkm	    if (length >= 3) {
30829088Smarkm		register int j;
30929088Smarkm
31029088Smarkm		i = pointer[length-2];
31129088Smarkm		j = pointer[length-1];
31229088Smarkm
31329088Smarkm		if (i != IAC || j != SE) {
31429088Smarkm		    fprintf(NetTrace, "(terminated by ");
31529088Smarkm		    if (TELOPT_OK(i))
31629088Smarkm			fprintf(NetTrace, "%s ", TELOPT(i));
31729088Smarkm		    else if (TELCMD_OK(i))
31829088Smarkm			fprintf(NetTrace, "%s ", TELCMD(i));
31929088Smarkm		    else
32029088Smarkm			fprintf(NetTrace, "%d ", i);
32129088Smarkm		    if (TELOPT_OK(j))
32229088Smarkm			fprintf(NetTrace, "%s", TELOPT(j));
32329088Smarkm		    else if (TELCMD_OK(j))
32429088Smarkm			fprintf(NetTrace, "%s", TELCMD(j));
32529088Smarkm		    else
32629088Smarkm			fprintf(NetTrace, "%d", j);
32729088Smarkm		    fprintf(NetTrace, ", not IAC SE!) ");
32829088Smarkm		}
32929088Smarkm	    }
33029088Smarkm	    length -= 2;
33129088Smarkm	}
33229088Smarkm	if (length < 1) {
33329088Smarkm	    fprintf(NetTrace, "(Empty suboption??\?)");
33429088Smarkm	    if (NetTrace == stdout)
33529088Smarkm		fflush(NetTrace);
33629088Smarkm	    return;
33729088Smarkm	}
33829088Smarkm	switch (pointer[0]) {
33929088Smarkm	case TELOPT_TTYPE:
34029088Smarkm	    fprintf(NetTrace, "TERMINAL-TYPE ");
34129088Smarkm	    switch (pointer[1]) {
34229088Smarkm	    case TELQUAL_IS:
34329088Smarkm		fprintf(NetTrace, "IS \"%.*s\"", length-2, (char *)pointer+2);
34429088Smarkm		break;
34529088Smarkm	    case TELQUAL_SEND:
34629088Smarkm		fprintf(NetTrace, "SEND");
34729088Smarkm		break;
34829088Smarkm	    default:
34929088Smarkm		fprintf(NetTrace,
35029088Smarkm				"- unknown qualifier %d (0x%x).",
35129088Smarkm				pointer[1], pointer[1]);
35229088Smarkm	    }
35329088Smarkm	    break;
35429088Smarkm	case TELOPT_TSPEED:
35529088Smarkm	    fprintf(NetTrace, "TERMINAL-SPEED");
35629088Smarkm	    if (length < 2) {
35729088Smarkm		fprintf(NetTrace, " (empty suboption??\?)");
35829088Smarkm		break;
35929088Smarkm	    }
36029088Smarkm	    switch (pointer[1]) {
36129088Smarkm	    case TELQUAL_IS:
36229088Smarkm		fprintf(NetTrace, " IS ");
36329088Smarkm		fprintf(NetTrace, "%.*s", length-2, (char *)pointer+2);
36429088Smarkm		break;
36529088Smarkm	    default:
36629088Smarkm		if (pointer[1] == 1)
36729088Smarkm		    fprintf(NetTrace, " SEND");
36829088Smarkm		else
36929088Smarkm		    fprintf(NetTrace, " %d (unknown)", pointer[1]);
37029088Smarkm		for (i = 2; i < length; i++)
37129088Smarkm		    fprintf(NetTrace, " ?%d?", pointer[i]);
37229088Smarkm		break;
37329088Smarkm	    }
37429088Smarkm	    break;
37529088Smarkm
37629088Smarkm	case TELOPT_LFLOW:
37729088Smarkm	    fprintf(NetTrace, "TOGGLE-FLOW-CONTROL");
37829088Smarkm	    if (length < 2) {
37929088Smarkm		fprintf(NetTrace, " (empty suboption??\?)");
38029088Smarkm		break;
38129088Smarkm	    }
38229088Smarkm	    switch (pointer[1]) {
38329088Smarkm	    case LFLOW_OFF:
38429088Smarkm		fprintf(NetTrace, " OFF"); break;
38529088Smarkm	    case LFLOW_ON:
38629088Smarkm		fprintf(NetTrace, " ON"); break;
38729088Smarkm	    case LFLOW_RESTART_ANY:
38829088Smarkm		fprintf(NetTrace, " RESTART-ANY"); break;
38929088Smarkm	    case LFLOW_RESTART_XON:
39029088Smarkm		fprintf(NetTrace, " RESTART-XON"); break;
39129088Smarkm	    default:
39229088Smarkm		fprintf(NetTrace, " %d (unknown)", pointer[1]);
39329088Smarkm	    }
39429088Smarkm	    for (i = 2; i < length; i++)
39529088Smarkm		fprintf(NetTrace, " ?%d?", pointer[i]);
39629088Smarkm	    break;
39729088Smarkm
39829088Smarkm	case TELOPT_NAWS:
39929088Smarkm	    fprintf(NetTrace, "NAWS");
40029088Smarkm	    if (length < 2) {
40129088Smarkm		fprintf(NetTrace, " (empty suboption??\?)");
40229088Smarkm		break;
40329088Smarkm	    }
40429088Smarkm	    if (length == 2) {
40529088Smarkm		fprintf(NetTrace, " ?%d?", pointer[1]);
40629088Smarkm		break;
40729088Smarkm	    }
40829088Smarkm	    fprintf(NetTrace, " %d %d (%d)",
40929088Smarkm		pointer[1], pointer[2],
41029088Smarkm		(int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2])));
41129088Smarkm	    if (length == 4) {
41229088Smarkm		fprintf(NetTrace, " ?%d?", pointer[3]);
41329088Smarkm		break;
41429088Smarkm	    }
41529088Smarkm	    fprintf(NetTrace, " %d %d (%d)",
41629088Smarkm		pointer[3], pointer[4],
41729088Smarkm		(int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4])));
41829088Smarkm	    for (i = 5; i < length; i++)
41929088Smarkm		fprintf(NetTrace, " ?%d?", pointer[i]);
42029088Smarkm	    break;
42129088Smarkm
42229088Smarkm#if	defined(AUTHENTICATION)
42329088Smarkm	case TELOPT_AUTHENTICATION:
42429088Smarkm	    fprintf(NetTrace, "AUTHENTICATION");
42529088Smarkm	    if (length < 2) {
42629088Smarkm		fprintf(NetTrace, " (empty suboption??\?)");
42729088Smarkm		break;
42829088Smarkm	    }
42929088Smarkm	    switch (pointer[1]) {
43029088Smarkm	    case TELQUAL_REPLY:
43129088Smarkm	    case TELQUAL_IS:
43229088Smarkm		fprintf(NetTrace, " %s ", (pointer[1] == TELQUAL_IS) ?
43329088Smarkm							"IS" : "REPLY");
43429088Smarkm		if (AUTHTYPE_NAME_OK(pointer[2]))
43529088Smarkm		    fprintf(NetTrace, "%s ", AUTHTYPE_NAME(pointer[2]));
43629088Smarkm		else
43729088Smarkm		    fprintf(NetTrace, "%d ", pointer[2]);
43829088Smarkm		if (length < 3) {
43929088Smarkm		    fprintf(NetTrace, "(partial suboption??\?)");
44029088Smarkm		    break;
44129088Smarkm		}
44229088Smarkm		fprintf(NetTrace, "%s|%s",
44329088Smarkm			((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
44429088Smarkm			"CLIENT" : "SERVER",
44529088Smarkm			((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
44629088Smarkm			"MUTUAL" : "ONE-WAY");
44729088Smarkm
44829088Smarkm		auth_printsub(&pointer[1], length - 1, buf, sizeof(buf));
44929088Smarkm		fprintf(NetTrace, "%s", buf);
45029088Smarkm		break;
45129088Smarkm
45229088Smarkm	    case TELQUAL_SEND:
45329088Smarkm		i = 2;
45429088Smarkm		fprintf(NetTrace, " SEND ");
45529088Smarkm		while (i < length) {
45629088Smarkm		    if (AUTHTYPE_NAME_OK(pointer[i]))
45729088Smarkm			fprintf(NetTrace, "%s ", AUTHTYPE_NAME(pointer[i]));
45829088Smarkm		    else
45929088Smarkm			fprintf(NetTrace, "%d ", pointer[i]);
46029088Smarkm		    if (++i >= length) {
46129088Smarkm			fprintf(NetTrace, "(partial suboption??\?)");
46229088Smarkm			break;
46329088Smarkm		    }
46429088Smarkm		    fprintf(NetTrace, "%s|%s ",
46529088Smarkm			((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
46629088Smarkm							"CLIENT" : "SERVER",
46729088Smarkm			((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
46829088Smarkm							"MUTUAL" : "ONE-WAY");
46929088Smarkm		    ++i;
47029088Smarkm		}
47129088Smarkm		break;
47229088Smarkm
47329088Smarkm	    case TELQUAL_NAME:
47429088Smarkm		i = 2;
47529088Smarkm		fprintf(NetTrace, " NAME \"");
47629088Smarkm		while (i < length)
47729088Smarkm		    putc(pointer[i++], NetTrace);
47829088Smarkm		putc('"', NetTrace);
47929088Smarkm		break;
48029088Smarkm
48129088Smarkm	    default:
48229088Smarkm		    for (i = 2; i < length; i++)
48329088Smarkm			fprintf(NetTrace, " ?%d?", pointer[i]);
48429088Smarkm		    break;
48529088Smarkm	    }
48629088Smarkm	    break;
48729088Smarkm#endif
48829088Smarkm
48929088Smarkm#ifdef	ENCRYPTION
49029088Smarkm	case TELOPT_ENCRYPT:
49129088Smarkm	    fprintf(NetTrace, "ENCRYPT");
49229088Smarkm	    if (length < 2) {
49329088Smarkm		fprintf(NetTrace, " (empty suboption??\?)");
49429088Smarkm		break;
49529088Smarkm	    }
49629088Smarkm	    switch (pointer[1]) {
49729088Smarkm	    case ENCRYPT_START:
49829088Smarkm		fprintf(NetTrace, " START");
49929088Smarkm		break;
50029088Smarkm
50129088Smarkm	    case ENCRYPT_END:
50229088Smarkm		fprintf(NetTrace, " END");
50329088Smarkm		break;
50429088Smarkm
50529088Smarkm	    case ENCRYPT_REQSTART:
50629088Smarkm		fprintf(NetTrace, " REQUEST-START");
50729088Smarkm		break;
50829088Smarkm
50929088Smarkm	    case ENCRYPT_REQEND:
51029088Smarkm		fprintf(NetTrace, " REQUEST-END");
51129088Smarkm		break;
51229088Smarkm
51329088Smarkm	    case ENCRYPT_IS:
51429088Smarkm	    case ENCRYPT_REPLY:
51529088Smarkm		fprintf(NetTrace, " %s ", (pointer[1] == ENCRYPT_IS) ?
51629088Smarkm							"IS" : "REPLY");
51729088Smarkm		if (length < 3) {
51829088Smarkm		    fprintf(NetTrace, " (partial suboption??\?)");
51929088Smarkm		    break;
52029088Smarkm		}
52129088Smarkm		if (ENCTYPE_NAME_OK(pointer[2]))
52229088Smarkm		    fprintf(NetTrace, "%s ", ENCTYPE_NAME(pointer[2]));
52329088Smarkm		else
52429088Smarkm		    fprintf(NetTrace, " %d (unknown)", pointer[2]);
52529088Smarkm
52629088Smarkm		encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf));
52729088Smarkm		fprintf(NetTrace, "%s", buf);
52829088Smarkm		break;
52929088Smarkm
53029088Smarkm	    case ENCRYPT_SUPPORT:
53129088Smarkm		i = 2;
53229088Smarkm		fprintf(NetTrace, " SUPPORT ");
53329088Smarkm		while (i < length) {
53429088Smarkm		    if (ENCTYPE_NAME_OK(pointer[i]))
53529088Smarkm			fprintf(NetTrace, "%s ", ENCTYPE_NAME(pointer[i]));
53629088Smarkm		    else
53729088Smarkm			fprintf(NetTrace, "%d ", pointer[i]);
53829088Smarkm		    i++;
53929088Smarkm		}
54029088Smarkm		break;
54129088Smarkm
54229088Smarkm	    case ENCRYPT_ENC_KEYID:
54329088Smarkm		fprintf(NetTrace, " ENC_KEYID ");
54429088Smarkm		goto encommon;
54529088Smarkm
54629088Smarkm	    case ENCRYPT_DEC_KEYID:
54729088Smarkm		fprintf(NetTrace, " DEC_KEYID ");
54829088Smarkm		goto encommon;
54929088Smarkm
55029088Smarkm	    default:
55129088Smarkm		fprintf(NetTrace, " %d (unknown)", pointer[1]);
55229088Smarkm	    encommon:
55329088Smarkm		for (i = 2; i < length; i++)
55429088Smarkm		    fprintf(NetTrace, " %d", pointer[i]);
55529088Smarkm		break;
55629088Smarkm	    }
55729088Smarkm	    break;
55829088Smarkm#endif	/* ENCRYPTION */
55929088Smarkm
56029088Smarkm	case TELOPT_LINEMODE:
56129088Smarkm	    fprintf(NetTrace, "LINEMODE ");
56229088Smarkm	    if (length < 2) {
56329088Smarkm		fprintf(NetTrace, " (empty suboption??\?)");
56429088Smarkm		break;
56529088Smarkm	    }
56629088Smarkm	    switch (pointer[1]) {
56729088Smarkm	    case WILL:
56829088Smarkm		fprintf(NetTrace, "WILL ");
56929088Smarkm		goto common;
57029088Smarkm	    case WONT:
57129088Smarkm		fprintf(NetTrace, "WONT ");
57229088Smarkm		goto common;
57329088Smarkm	    case DO:
57429088Smarkm		fprintf(NetTrace, "DO ");
57529088Smarkm		goto common;
57629088Smarkm	    case DONT:
57729088Smarkm		fprintf(NetTrace, "DONT ");
57829088Smarkm	    common:
57929088Smarkm		if (length < 3) {
58029088Smarkm		    fprintf(NetTrace, "(no option??\?)");
58129088Smarkm		    break;
58229088Smarkm		}
58329088Smarkm		switch (pointer[2]) {
58429088Smarkm		case LM_FORWARDMASK:
58529088Smarkm		    fprintf(NetTrace, "Forward Mask");
58629088Smarkm		    for (i = 3; i < length; i++)
58729088Smarkm			fprintf(NetTrace, " %x", pointer[i]);
58829088Smarkm		    break;
58929088Smarkm		default:
59029088Smarkm		    fprintf(NetTrace, "%d (unknown)", pointer[2]);
59129088Smarkm		    for (i = 3; i < length; i++)
59229088Smarkm			fprintf(NetTrace, " %d", pointer[i]);
59329088Smarkm		    break;
59429088Smarkm		}
59529088Smarkm		break;
59629088Smarkm
59729088Smarkm	    case LM_SLC:
59829088Smarkm		fprintf(NetTrace, "SLC");
59929088Smarkm		for (i = 2; i < length - 2; i += 3) {
60029088Smarkm		    if (SLC_NAME_OK(pointer[i+SLC_FUNC]))
60129088Smarkm			fprintf(NetTrace, " %s", SLC_NAME(pointer[i+SLC_FUNC]));
60229088Smarkm		    else
60329088Smarkm			fprintf(NetTrace, " %d", pointer[i+SLC_FUNC]);
60429088Smarkm		    switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) {
60529088Smarkm		    case SLC_NOSUPPORT:
60629088Smarkm			fprintf(NetTrace, " NOSUPPORT"); break;
60729088Smarkm		    case SLC_CANTCHANGE:
60829088Smarkm			fprintf(NetTrace, " CANTCHANGE"); break;
60929088Smarkm		    case SLC_VARIABLE:
61029088Smarkm			fprintf(NetTrace, " VARIABLE"); break;
61129088Smarkm		    case SLC_DEFAULT:
61229088Smarkm			fprintf(NetTrace, " DEFAULT"); break;
61329088Smarkm		    }
61429088Smarkm		    fprintf(NetTrace, "%s%s%s",
61529088Smarkm			pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "",
61629088Smarkm			pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "",
61729088Smarkm			pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : "");
61829088Smarkm		    if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN|
61929088Smarkm						SLC_FLUSHOUT| SLC_LEVELBITS))
62029088Smarkm			fprintf(NetTrace, "(0x%x)", pointer[i+SLC_FLAGS]);
62129088Smarkm		    fprintf(NetTrace, " %d;", pointer[i+SLC_VALUE]);
62229088Smarkm		    if ((pointer[i+SLC_VALUE] == IAC) &&
62329088Smarkm			(pointer[i+SLC_VALUE+1] == IAC))
62429088Smarkm				i++;
62529088Smarkm		}
62629088Smarkm		for (; i < length; i++)
62729088Smarkm		    fprintf(NetTrace, " ?%d?", pointer[i]);
62829088Smarkm		break;
62929088Smarkm
63029088Smarkm	    case LM_MODE:
63129088Smarkm		fprintf(NetTrace, "MODE ");
63229088Smarkm		if (length < 3) {
63329088Smarkm		    fprintf(NetTrace, "(no mode??\?)");
63429088Smarkm		    break;
63529088Smarkm		}
63629088Smarkm		{
63729088Smarkm		    char tbuf[64];
63829088Smarkm		    sprintf(tbuf, "%s%s%s%s%s",
63929088Smarkm			pointer[2]&MODE_EDIT ? "|EDIT" : "",
64029088Smarkm			pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "",
64129088Smarkm			pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "",
64229088Smarkm			pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "",
64329088Smarkm			pointer[2]&MODE_ACK ? "|ACK" : "");
64429088Smarkm		    fprintf(NetTrace, "%s", tbuf[1] ? &tbuf[1] : "0");
64529088Smarkm		}
64629088Smarkm		if (pointer[2]&~(MODE_MASK))
64729088Smarkm		    fprintf(NetTrace, " (0x%x)", pointer[2]);
64829088Smarkm		for (i = 3; i < length; i++)
64929088Smarkm		    fprintf(NetTrace, " ?0x%x?", pointer[i]);
65029088Smarkm		break;
65129088Smarkm	    default:
65229088Smarkm		fprintf(NetTrace, "%d (unknown)", pointer[1]);
65329088Smarkm		for (i = 2; i < length; i++)
65429088Smarkm		    fprintf(NetTrace, " %d", pointer[i]);
65529088Smarkm	    }
65629088Smarkm	    break;
65729088Smarkm
65829088Smarkm	case TELOPT_STATUS: {
65929088Smarkm	    register char *cp;
66029088Smarkm	    register int j, k;
66129088Smarkm
66229088Smarkm	    fprintf(NetTrace, "STATUS");
66329088Smarkm
66429088Smarkm	    switch (pointer[1]) {
66529088Smarkm	    default:
66629088Smarkm		if (pointer[1] == TELQUAL_SEND)
66729088Smarkm		    fprintf(NetTrace, " SEND");
66829088Smarkm		else
66929088Smarkm		    fprintf(NetTrace, " %d (unknown)", pointer[1]);
67029088Smarkm		for (i = 2; i < length; i++)
67129088Smarkm		    fprintf(NetTrace, " ?%d?", pointer[i]);
67229088Smarkm		break;
67329088Smarkm	    case TELQUAL_IS:
67429088Smarkm		if (--want_status_response < 0)
67529088Smarkm		    want_status_response = 0;
67629088Smarkm		if (NetTrace == stdout)
67729088Smarkm		    fprintf(NetTrace, " IS\r\n");
67829088Smarkm		else
67929088Smarkm		    fprintf(NetTrace, " IS\n");
68029088Smarkm
68129088Smarkm		for (i = 2; i < length; i++) {
68229088Smarkm		    switch(pointer[i]) {
68329088Smarkm		    case DO:	cp = "DO"; goto common2;
68429088Smarkm		    case DONT:	cp = "DONT"; goto common2;
68529088Smarkm		    case WILL:	cp = "WILL"; goto common2;
68629088Smarkm		    case WONT:	cp = "WONT"; goto common2;
68729088Smarkm		    common2:
68829088Smarkm			i++;
68929088Smarkm			if (TELOPT_OK((int)pointer[i]))
69029088Smarkm			    fprintf(NetTrace, " %s %s", cp, TELOPT(pointer[i]));
69129088Smarkm			else
69229088Smarkm			    fprintf(NetTrace, " %s %d", cp, pointer[i]);
69329088Smarkm
69429088Smarkm			if (NetTrace == stdout)
69529088Smarkm			    fprintf(NetTrace, "\r\n");
69629088Smarkm			else
69729088Smarkm			    fprintf(NetTrace, "\n");
69829088Smarkm			break;
69929088Smarkm
70029088Smarkm		    case SB:
70129088Smarkm			fprintf(NetTrace, " SB ");
70229088Smarkm			i++;
70329088Smarkm			j = k = i;
70429088Smarkm			while (j < length) {
70529088Smarkm			    if (pointer[j] == SE) {
70629088Smarkm				if (j+1 == length)
70729088Smarkm				    break;
70829088Smarkm				if (pointer[j+1] == SE)
70929088Smarkm				    j++;
71029088Smarkm				else
71129088Smarkm				    break;
71229088Smarkm			    }
71329088Smarkm			    pointer[k++] = pointer[j++];
71429088Smarkm			}
71529088Smarkm			printsub(0, &pointer[i], k - i);
71629088Smarkm			if (i < length) {
71729088Smarkm			    fprintf(NetTrace, " SE");
71829088Smarkm			    i = j;
71929088Smarkm			} else
72029088Smarkm			    i = j - 1;
72129088Smarkm
72229088Smarkm			if (NetTrace == stdout)
72329088Smarkm			    fprintf(NetTrace, "\r\n");
72429088Smarkm			else
72529088Smarkm			    fprintf(NetTrace, "\n");
72629088Smarkm
72729088Smarkm			break;
72829088Smarkm
72929088Smarkm		    default:
73029088Smarkm			fprintf(NetTrace, " %d", pointer[i]);
73129088Smarkm			break;
73229088Smarkm		    }
73329088Smarkm		}
73429088Smarkm		break;
73529088Smarkm	    }
73629088Smarkm	    break;
73729088Smarkm	  }
73829088Smarkm
73929088Smarkm	case TELOPT_XDISPLOC:
74029088Smarkm	    fprintf(NetTrace, "X-DISPLAY-LOCATION ");
74129088Smarkm	    switch (pointer[1]) {
74229088Smarkm	    case TELQUAL_IS:
74329088Smarkm		fprintf(NetTrace, "IS \"%.*s\"", length-2, (char *)pointer+2);
74429088Smarkm		break;
74529088Smarkm	    case TELQUAL_SEND:
74629088Smarkm		fprintf(NetTrace, "SEND");
74729088Smarkm		break;
74829088Smarkm	    default:
74929088Smarkm		fprintf(NetTrace, "- unknown qualifier %d (0x%x).",
75029088Smarkm				pointer[1], pointer[1]);
75129088Smarkm	    }
75229088Smarkm	    break;
75329088Smarkm
75429088Smarkm	case TELOPT_NEW_ENVIRON:
75529088Smarkm	    fprintf(NetTrace, "NEW-ENVIRON ");
75629088Smarkm#ifdef	OLD_ENVIRON
75729088Smarkm	    goto env_common1;
75829088Smarkm	case TELOPT_OLD_ENVIRON:
75929088Smarkm	    fprintf(NetTrace, "OLD-ENVIRON");
76029088Smarkm	env_common1:
76129088Smarkm#endif
76229088Smarkm	    switch (pointer[1]) {
76329088Smarkm	    case TELQUAL_IS:
76429088Smarkm		fprintf(NetTrace, "IS ");
76529088Smarkm		goto env_common;
76629088Smarkm	    case TELQUAL_SEND:
76729088Smarkm		fprintf(NetTrace, "SEND ");
76829088Smarkm		goto env_common;
76929088Smarkm	    case TELQUAL_INFO:
77029088Smarkm		fprintf(NetTrace, "INFO ");
77129088Smarkm	    env_common:
77229088Smarkm		{
77329088Smarkm		    register int noquote = 2;
77429088Smarkm#if defined(ENV_HACK) && defined(OLD_ENVIRON)
77529088Smarkm		    extern int old_env_var, old_env_value;
77629088Smarkm#endif
77729088Smarkm		    for (i = 2; i < length; i++ ) {
77829088Smarkm			switch (pointer[i]) {
77929088Smarkm			case NEW_ENV_VALUE:
78029088Smarkm#ifdef OLD_ENVIRON
78129088Smarkm		     /*	case NEW_ENV_OVAR: */
78229088Smarkm			    if (pointer[0] == TELOPT_OLD_ENVIRON) {
78329088Smarkm# ifdef	ENV_HACK
78429088Smarkm				if (old_env_var == OLD_ENV_VALUE)
78529088Smarkm				    fprintf(NetTrace, "\" (VALUE) " + noquote);
78629088Smarkm				else
78729088Smarkm# endif
78829088Smarkm				    fprintf(NetTrace, "\" VAR " + noquote);
78929088Smarkm			    } else
79029088Smarkm#endif /* OLD_ENVIRON */
79129088Smarkm				fprintf(NetTrace, "\" VALUE " + noquote);
79229088Smarkm			    noquote = 2;
79329088Smarkm			    break;
79429088Smarkm
79529088Smarkm			case NEW_ENV_VAR:
79629088Smarkm#ifdef OLD_ENVIRON
79729088Smarkm		     /* case OLD_ENV_VALUE: */
79829088Smarkm			    if (pointer[0] == TELOPT_OLD_ENVIRON) {
79929088Smarkm# ifdef	ENV_HACK
80029088Smarkm				if (old_env_value == OLD_ENV_VAR)
80129088Smarkm				    fprintf(NetTrace, "\" (VAR) " + noquote);
80229088Smarkm				else
80329088Smarkm# endif
80429088Smarkm				    fprintf(NetTrace, "\" VALUE " + noquote);
80529088Smarkm			    } else
80629088Smarkm#endif /* OLD_ENVIRON */
80729088Smarkm				fprintf(NetTrace, "\" VAR " + noquote);
80829088Smarkm			    noquote = 2;
80929088Smarkm			    break;
81029088Smarkm
81129088Smarkm			case ENV_ESC:
81229088Smarkm			    fprintf(NetTrace, "\" ESC " + noquote);
81329088Smarkm			    noquote = 2;
81429088Smarkm			    break;
81529088Smarkm
81629088Smarkm			case ENV_USERVAR:
81729088Smarkm			    fprintf(NetTrace, "\" USERVAR " + noquote);
81829088Smarkm			    noquote = 2;
81929088Smarkm			    break;
82029088Smarkm
82129088Smarkm			default:
82229088Smarkm			def_case:
82329088Smarkm			    if (isprint(pointer[i]) && pointer[i] != '"') {
82429088Smarkm				if (noquote) {
82529088Smarkm				    putc('"', NetTrace);
82629088Smarkm				    noquote = 0;
82729088Smarkm				}
82829088Smarkm				putc(pointer[i], NetTrace);
82929088Smarkm			    } else {
83029088Smarkm				fprintf(NetTrace, "\" %03o " + noquote,
83129088Smarkm							pointer[i]);
83229088Smarkm				noquote = 2;
83329088Smarkm			    }
83429088Smarkm			    break;
83529088Smarkm			}
83629088Smarkm		    }
83729088Smarkm		    if (!noquote)
83829088Smarkm			putc('"', NetTrace);
83929088Smarkm		    break;
84029088Smarkm		}
84129088Smarkm	    }
84229088Smarkm	    break;
84329088Smarkm
84429088Smarkm	default:
84529088Smarkm	    if (TELOPT_OK(pointer[0]))
84629088Smarkm		fprintf(NetTrace, "%s (unknown)", TELOPT(pointer[0]));
84729088Smarkm	    else
84829088Smarkm		fprintf(NetTrace, "%d (unknown)", pointer[0]);
84929088Smarkm	    for (i = 1; i < length; i++)
85029088Smarkm		fprintf(NetTrace, " %d", pointer[i]);
85129088Smarkm	    break;
85229088Smarkm	}
85329088Smarkm	if (direction) {
85429088Smarkm	    if (NetTrace == stdout)
85529088Smarkm		fprintf(NetTrace, "\r\n");
85629088Smarkm	    else
85729088Smarkm		fprintf(NetTrace, "\n");
85829088Smarkm	}
85929088Smarkm	if (NetTrace == stdout)
86029088Smarkm	    fflush(NetTrace);
86129088Smarkm    }
86229088Smarkm}
86329088Smarkm
86429088Smarkm/* EmptyTerminal - called to make sure that the terminal buffer is empty.
86529088Smarkm *			Note that we consider the buffer to run all the
86629088Smarkm *			way to the kernel (thus the select).
86729088Smarkm */
86829088Smarkm
86929088Smarkm    void
87029088SmarkmEmptyTerminal()
87129088Smarkm{
87229088Smarkm#if	defined(unix)
87329088Smarkm    fd_set	o;
87429088Smarkm
87529088Smarkm    FD_ZERO(&o);
87629088Smarkm#endif	/* defined(unix) */
87729088Smarkm
87829088Smarkm    if (TTYBYTES() == 0) {
87929088Smarkm#if	defined(unix)
88029088Smarkm	FD_SET(tout, &o);
88129088Smarkm	(void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
88229088Smarkm			(struct timeval *) 0);	/* wait for TTLOWAT */
88329088Smarkm#endif	/* defined(unix) */
88429088Smarkm    } else {
88529088Smarkm	while (TTYBYTES()) {
88629088Smarkm	    (void) ttyflush(0);
88729088Smarkm#if	defined(unix)
88829088Smarkm	    FD_SET(tout, &o);
88929088Smarkm	    (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
89029088Smarkm				(struct timeval *) 0);	/* wait for TTLOWAT */
89129088Smarkm#endif	/* defined(unix) */
89229088Smarkm	}
89329088Smarkm    }
89429088Smarkm}
89529088Smarkm
89629088Smarkm    void
89729088SmarkmSetForExit()
89829088Smarkm{
89929088Smarkm    setconnmode(0);
90029088Smarkm#if	defined(TN3270)
90129088Smarkm    if (In3270) {
90229088Smarkm	Finish3270();
90329088Smarkm    }
90429088Smarkm#else	/* defined(TN3270) */
90529088Smarkm    do {
90629088Smarkm	(void)telrcv();			/* Process any incoming data */
90729088Smarkm	EmptyTerminal();
90829088Smarkm    } while (ring_full_count(&netiring));	/* While there is any */
90929088Smarkm#endif	/* defined(TN3270) */
91029088Smarkm    setcommandmode();
91129088Smarkm    fflush(stdout);
91229088Smarkm    fflush(stderr);
91329088Smarkm#if	defined(TN3270)
91429088Smarkm    if (In3270) {
91529088Smarkm	StopScreen(1);
91629088Smarkm    }
91729088Smarkm#endif	/* defined(TN3270) */
91829088Smarkm    setconnmode(0);
91929088Smarkm    EmptyTerminal();			/* Flush the path to the tty */
92029088Smarkm    setcommandmode();
92129088Smarkm}
92229088Smarkm
92329088Smarkm    void
92429088SmarkmExit(returnCode)
92529088Smarkm    int returnCode;
92629088Smarkm{
92729088Smarkm    SetForExit();
92829088Smarkm    exit(returnCode);
92929088Smarkm}
93029088Smarkm
93129088Smarkm    void
93229088SmarkmExitString(string, returnCode)
93329088Smarkm    char *string;
93429088Smarkm    int returnCode;
93529088Smarkm{
93629088Smarkm    SetForExit();
93729088Smarkm    fwrite(string, 1, strlen(string), stderr);
93829088Smarkm    exit(returnCode);
93929088Smarkm}
940