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