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
34114630Sobrien#if 0
3529088Smarkm#ifndef lint
3629181Smarkmstatic const char sccsid[] = "@(#)utilities.c	8.3 (Berkeley) 5/30/95";
3763248Speter#endif
38114630Sobrien#endif
39114630Sobrien#include <sys/cdefs.h>
40114630Sobrien__FBSDID("$FreeBSD$");
4129088Smarkm
4229088Smarkm#define	TELOPTS
4329088Smarkm#define	TELCMDS
4429088Smarkm#define	SLC_NAMES
4529088Smarkm#include <arpa/telnet.h>
4629088Smarkm#include <sys/types.h>
4729181Smarkm#include <sys/socket.h>
4829088Smarkm#include <sys/time.h>
4981965Smarkm#include <ctype.h>
5096385Salfred#include <stdlib.h>
5129181Smarkm#include <unistd.h>
5229088Smarkm
5329088Smarkm#include "general.h"
5429088Smarkm
5529088Smarkm#include "fdset.h"
5629088Smarkm
5729088Smarkm#include "ring.h"
5829088Smarkm
5929088Smarkm#include "defines.h"
6029088Smarkm
6129088Smarkm#include "externs.h"
6229088Smarkm
6387139Smarkm#ifdef	AUTHENTICATION
6429181Smarkm#include <libtelnet/auth.h>
6529181Smarkm#endif
6687139Smarkm#ifdef	ENCRYPTION
6729181Smarkm#include <libtelnet/encrypt.h>
6829181Smarkm#endif
6929181Smarkm
7029088SmarkmFILE	*NetTrace = 0;		/* Not in bss, since needs to stay */
7129088Smarkmint	prettydump;
7229088Smarkm
7329088Smarkm/*
7429088Smarkm * upcase()
7529088Smarkm *
7629088Smarkm *	Upcase (in place) the argument.
7729088Smarkm */
7829088Smarkm
7987139Smarkmvoid
8087139Smarkmupcase(char *argument)
8129088Smarkm{
8287139Smarkm    int c;
8329088Smarkm
8429088Smarkm    while ((c = *argument) != 0) {
8529088Smarkm	if (islower(c)) {
8629088Smarkm	    *argument = toupper(c);
8729088Smarkm	}
8829088Smarkm	argument++;
8929088Smarkm    }
9029088Smarkm}
9129088Smarkm
9229088Smarkm/*
9329088Smarkm * SetSockOpt()
9429088Smarkm *
9529088Smarkm * Compensate for differences in 4.2 and 4.3 systems.
9629088Smarkm */
9729088Smarkm
9887139Smarkmint
9987139SmarkmSetSockOpt(int fd, int level, int option, int yesno)
10029088Smarkm{
10129088Smarkm    return setsockopt(fd, level, option,
10229088Smarkm				(char *)&yesno, sizeof yesno);
10329088Smarkm}
10429088Smarkm
10529088Smarkm/*
10629088Smarkm * The following are routines used to print out debugging information.
10729088Smarkm */
10829088Smarkm
10929088Smarkmunsigned char NetTraceFile[256] = "(standard output)";
11029088Smarkm
11187139Smarkmvoid
11287139SmarkmSetNetTrace(char *file)
11329088Smarkm{
11429088Smarkm    if (NetTrace && NetTrace != stdout)
11529088Smarkm	fclose(NetTrace);
11629088Smarkm    if (file  && (strcmp(file, "-") != 0)) {
11729088Smarkm	NetTrace = fopen(file, "w");
11829088Smarkm	if (NetTrace) {
11929088Smarkm	    strcpy((char *)NetTraceFile, file);
12029088Smarkm	    return;
12129088Smarkm	}
12229088Smarkm	fprintf(stderr, "Cannot open %s.\n", file);
12329088Smarkm    }
12429088Smarkm    NetTrace = stdout;
12529088Smarkm    strcpy((char *)NetTraceFile, "(standard output)");
12629088Smarkm}
12729088Smarkm
12887139Smarkmvoid
12987139SmarkmDump(char direction, unsigned char *buffer, int length)
13029088Smarkm{
13129088Smarkm#   define BYTES_PER_LINE	32
13229088Smarkm#   define min(x,y)	((x<y)? x:y)
13329088Smarkm    unsigned char *pThis;
13429088Smarkm    int offset;
13529088Smarkm
13629088Smarkm    offset = 0;
13729088Smarkm
13829088Smarkm    while (length) {
13929088Smarkm	/* print one line */
14029088Smarkm	fprintf(NetTrace, "%c 0x%x\t", direction, offset);
14129088Smarkm	pThis = buffer;
14229088Smarkm	if (prettydump) {
14329088Smarkm	    buffer = buffer + min(length, BYTES_PER_LINE/2);
14429088Smarkm	    while (pThis < buffer) {
14529088Smarkm		fprintf(NetTrace, "%c%.2x",
14629088Smarkm		    (((*pThis)&0xff) == 0xff) ? '*' : ' ',
14729088Smarkm		    (*pThis)&0xff);
14829088Smarkm		pThis++;
14929088Smarkm	    }
15029088Smarkm	    length -= BYTES_PER_LINE/2;
15129088Smarkm	    offset += BYTES_PER_LINE/2;
15229088Smarkm	} else {
15329088Smarkm	    buffer = buffer + min(length, BYTES_PER_LINE);
15429088Smarkm	    while (pThis < buffer) {
15529088Smarkm		fprintf(NetTrace, "%.2x", (*pThis)&0xff);
15629088Smarkm		pThis++;
15729088Smarkm	    }
15829088Smarkm	    length -= BYTES_PER_LINE;
15929088Smarkm	    offset += BYTES_PER_LINE;
16029088Smarkm	}
16129088Smarkm	if (NetTrace == stdout) {
16229088Smarkm	    fprintf(NetTrace, "\r\n");
16329088Smarkm	} else {
16429088Smarkm	    fprintf(NetTrace, "\n");
16529088Smarkm	}
16629088Smarkm	if (length < 0) {
16729088Smarkm	    fflush(NetTrace);
16829088Smarkm	    return;
16929088Smarkm	}
17029088Smarkm	/* find next unique line */
17129088Smarkm    }
17229088Smarkm    fflush(NetTrace);
17329088Smarkm}
17429088Smarkm
17529088Smarkm
17687139Smarkmvoid
17787139Smarkmprintoption(const char *direction, int cmd, int option)
17829088Smarkm{
17929088Smarkm	if (!showoptions)
18029088Smarkm		return;
18129088Smarkm	if (cmd == IAC) {
18229088Smarkm		if (TELCMD_OK(option))
18329088Smarkm		    fprintf(NetTrace, "%s IAC %s", direction, TELCMD(option));
18429088Smarkm		else
18529088Smarkm		    fprintf(NetTrace, "%s IAC %d", direction, option);
18629088Smarkm	} else {
18787139Smarkm		const char *fmt;
18829088Smarkm		fmt = (cmd == WILL) ? "WILL" : (cmd == WONT) ? "WONT" :
18929088Smarkm			(cmd == DO) ? "DO" : (cmd == DONT) ? "DONT" : 0;
19029088Smarkm		if (fmt) {
19129088Smarkm		    fprintf(NetTrace, "%s %s ", direction, fmt);
19229088Smarkm		    if (TELOPT_OK(option))
19329088Smarkm			fprintf(NetTrace, "%s", TELOPT(option));
19429088Smarkm		    else if (option == TELOPT_EXOPL)
19529088Smarkm			fprintf(NetTrace, "EXOPL");
19629088Smarkm		    else
19729088Smarkm			fprintf(NetTrace, "%d", option);
19829088Smarkm		} else
19929088Smarkm		    fprintf(NetTrace, "%s %d %d", direction, cmd, option);
20029088Smarkm	}
20129088Smarkm	if (NetTrace == stdout) {
20229088Smarkm	    fprintf(NetTrace, "\r\n");
20329088Smarkm	    fflush(NetTrace);
20429088Smarkm	} else {
20529088Smarkm	    fprintf(NetTrace, "\n");
20629088Smarkm	}
20729088Smarkm	return;
20829088Smarkm}
20929088Smarkm
21087139Smarkmvoid
21187139Smarkmoptionstatus(void)
21229088Smarkm{
21387139Smarkm    int i;
21429088Smarkm    extern char will_wont_resp[], do_dont_resp[];
21529088Smarkm
21629088Smarkm    for (i = 0; i < 256; i++) {
21729088Smarkm	if (do_dont_resp[i]) {
21829088Smarkm	    if (TELOPT_OK(i))
21929088Smarkm		printf("resp DO_DONT %s: %d\n", TELOPT(i), do_dont_resp[i]);
22029088Smarkm	    else if (TELCMD_OK(i))
22129088Smarkm		printf("resp DO_DONT %s: %d\n", TELCMD(i), do_dont_resp[i]);
22229088Smarkm	    else
22329088Smarkm		printf("resp DO_DONT %d: %d\n", i,
22429088Smarkm				do_dont_resp[i]);
22529088Smarkm	    if (my_want_state_is_do(i)) {
22629088Smarkm		if (TELOPT_OK(i))
22729088Smarkm		    printf("want DO   %s\n", TELOPT(i));
22829088Smarkm		else if (TELCMD_OK(i))
22929088Smarkm		    printf("want DO   %s\n", TELCMD(i));
23029088Smarkm		else
23129088Smarkm		    printf("want DO   %d\n", i);
23229088Smarkm	    } else {
23329088Smarkm		if (TELOPT_OK(i))
23429088Smarkm		    printf("want DONT %s\n", TELOPT(i));
23529088Smarkm		else if (TELCMD_OK(i))
23629088Smarkm		    printf("want DONT %s\n", TELCMD(i));
23729088Smarkm		else
23829088Smarkm		    printf("want DONT %d\n", i);
23929088Smarkm	    }
24029088Smarkm	} else {
24129088Smarkm	    if (my_state_is_do(i)) {
24229088Smarkm		if (TELOPT_OK(i))
24329088Smarkm		    printf("     DO   %s\n", TELOPT(i));
24429088Smarkm		else if (TELCMD_OK(i))
24529088Smarkm		    printf("     DO   %s\n", TELCMD(i));
24629088Smarkm		else
24729088Smarkm		    printf("     DO   %d\n", i);
24829088Smarkm	    }
24929088Smarkm	}
25029088Smarkm	if (will_wont_resp[i]) {
25129088Smarkm	    if (TELOPT_OK(i))
25229088Smarkm		printf("resp WILL_WONT %s: %d\n", TELOPT(i), will_wont_resp[i]);
25329088Smarkm	    else if (TELCMD_OK(i))
25429088Smarkm		printf("resp WILL_WONT %s: %d\n", TELCMD(i), will_wont_resp[i]);
25529088Smarkm	    else
25629088Smarkm		printf("resp WILL_WONT %d: %d\n",
25729088Smarkm				i, will_wont_resp[i]);
25829088Smarkm	    if (my_want_state_is_will(i)) {
25929088Smarkm		if (TELOPT_OK(i))
26029088Smarkm		    printf("want WILL %s\n", TELOPT(i));
26129088Smarkm		else if (TELCMD_OK(i))
26229088Smarkm		    printf("want WILL %s\n", TELCMD(i));
26329088Smarkm		else
26429088Smarkm		    printf("want WILL %d\n", i);
26529088Smarkm	    } else {
26629088Smarkm		if (TELOPT_OK(i))
26729088Smarkm		    printf("want WONT %s\n", TELOPT(i));
26829088Smarkm		else if (TELCMD_OK(i))
26929088Smarkm		    printf("want WONT %s\n", TELCMD(i));
27029088Smarkm		else
27129088Smarkm		    printf("want WONT %d\n", i);
27229088Smarkm	    }
27329088Smarkm	} else {
27429088Smarkm	    if (my_state_is_will(i)) {
27529088Smarkm		if (TELOPT_OK(i))
27629088Smarkm		    printf("     WILL %s\n", TELOPT(i));
27729088Smarkm		else if (TELCMD_OK(i))
27829088Smarkm		    printf("     WILL %s\n", TELCMD(i));
27929088Smarkm		else
28029088Smarkm		    printf("     WILL %d\n", i);
28129088Smarkm	    }
28229088Smarkm	}
28329088Smarkm    }
28429088Smarkm
28529088Smarkm}
28629088Smarkm
28787139Smarkmvoid
28887139Smarkmprintsub(char direction, unsigned char *pointer, int length)
28929088Smarkm{
29087139Smarkm    int i;
29187139Smarkm#ifdef	AUTHENTICATION
29229088Smarkm    char buf[512];
29387139Smarkm#endif
29429088Smarkm    extern int want_status_response;
29529088Smarkm
29629088Smarkm    if (showoptions || direction == 0 ||
29729088Smarkm	(want_status_response && (pointer[0] == TELOPT_STATUS))) {
29829088Smarkm	if (direction) {
29929088Smarkm	    fprintf(NetTrace, "%s IAC SB ",
30029088Smarkm				(direction == '<')? "RCVD":"SENT");
30129088Smarkm	    if (length >= 3) {
30287139Smarkm		int j;
30329088Smarkm
30429088Smarkm		i = pointer[length-2];
30529088Smarkm		j = pointer[length-1];
30629088Smarkm
30729088Smarkm		if (i != IAC || j != SE) {
30829088Smarkm		    fprintf(NetTrace, "(terminated by ");
30929088Smarkm		    if (TELOPT_OK(i))
31029088Smarkm			fprintf(NetTrace, "%s ", TELOPT(i));
31129088Smarkm		    else if (TELCMD_OK(i))
31229088Smarkm			fprintf(NetTrace, "%s ", TELCMD(i));
31329088Smarkm		    else
31429088Smarkm			fprintf(NetTrace, "%d ", i);
31529088Smarkm		    if (TELOPT_OK(j))
31629088Smarkm			fprintf(NetTrace, "%s", TELOPT(j));
31729088Smarkm		    else if (TELCMD_OK(j))
31829088Smarkm			fprintf(NetTrace, "%s", TELCMD(j));
31929088Smarkm		    else
32029088Smarkm			fprintf(NetTrace, "%d", j);
32129088Smarkm		    fprintf(NetTrace, ", not IAC SE!) ");
32229088Smarkm		}
32329088Smarkm	    }
32429088Smarkm	    length -= 2;
32529088Smarkm	}
32629088Smarkm	if (length < 1) {
32729088Smarkm	    fprintf(NetTrace, "(Empty suboption??\?)");
32829088Smarkm	    if (NetTrace == stdout)
32929088Smarkm		fflush(NetTrace);
33029088Smarkm	    return;
33129088Smarkm	}
33229088Smarkm	switch (pointer[0]) {
33329088Smarkm	case TELOPT_TTYPE:
33429088Smarkm	    fprintf(NetTrace, "TERMINAL-TYPE ");
33529088Smarkm	    switch (pointer[1]) {
33629088Smarkm	    case TELQUAL_IS:
33729088Smarkm		fprintf(NetTrace, "IS \"%.*s\"", length-2, (char *)pointer+2);
33829088Smarkm		break;
33929088Smarkm	    case TELQUAL_SEND:
34029088Smarkm		fprintf(NetTrace, "SEND");
34129088Smarkm		break;
34229088Smarkm	    default:
34329088Smarkm		fprintf(NetTrace,
34429088Smarkm				"- unknown qualifier %d (0x%x).",
34529088Smarkm				pointer[1], pointer[1]);
34629088Smarkm	    }
34729088Smarkm	    break;
34829088Smarkm	case TELOPT_TSPEED:
34929088Smarkm	    fprintf(NetTrace, "TERMINAL-SPEED");
35029088Smarkm	    if (length < 2) {
35129088Smarkm		fprintf(NetTrace, " (empty suboption??\?)");
35229088Smarkm		break;
35329088Smarkm	    }
35429088Smarkm	    switch (pointer[1]) {
35529088Smarkm	    case TELQUAL_IS:
35629088Smarkm		fprintf(NetTrace, " IS ");
35729088Smarkm		fprintf(NetTrace, "%.*s", length-2, (char *)pointer+2);
35829088Smarkm		break;
35929088Smarkm	    default:
36029088Smarkm		if (pointer[1] == 1)
36129088Smarkm		    fprintf(NetTrace, " SEND");
36229088Smarkm		else
36329088Smarkm		    fprintf(NetTrace, " %d (unknown)", pointer[1]);
36429088Smarkm		for (i = 2; i < length; i++)
36529088Smarkm		    fprintf(NetTrace, " ?%d?", pointer[i]);
36629088Smarkm		break;
36729088Smarkm	    }
36829088Smarkm	    break;
36929088Smarkm
37029088Smarkm	case TELOPT_LFLOW:
37129088Smarkm	    fprintf(NetTrace, "TOGGLE-FLOW-CONTROL");
37229088Smarkm	    if (length < 2) {
37329088Smarkm		fprintf(NetTrace, " (empty suboption??\?)");
37429088Smarkm		break;
37529088Smarkm	    }
37629088Smarkm	    switch (pointer[1]) {
37729088Smarkm	    case LFLOW_OFF:
37829088Smarkm		fprintf(NetTrace, " OFF"); break;
37929088Smarkm	    case LFLOW_ON:
38029088Smarkm		fprintf(NetTrace, " ON"); break;
38129088Smarkm	    case LFLOW_RESTART_ANY:
38229088Smarkm		fprintf(NetTrace, " RESTART-ANY"); break;
38329088Smarkm	    case LFLOW_RESTART_XON:
38429088Smarkm		fprintf(NetTrace, " RESTART-XON"); break;
38529088Smarkm	    default:
38629088Smarkm		fprintf(NetTrace, " %d (unknown)", pointer[1]);
38729088Smarkm	    }
38829088Smarkm	    for (i = 2; i < length; i++)
38929088Smarkm		fprintf(NetTrace, " ?%d?", pointer[i]);
39029088Smarkm	    break;
39129088Smarkm
39229088Smarkm	case TELOPT_NAWS:
39329088Smarkm	    fprintf(NetTrace, "NAWS");
39429088Smarkm	    if (length < 2) {
39529088Smarkm		fprintf(NetTrace, " (empty suboption??\?)");
39629088Smarkm		break;
39729088Smarkm	    }
39829088Smarkm	    if (length == 2) {
39929088Smarkm		fprintf(NetTrace, " ?%d?", pointer[1]);
40029088Smarkm		break;
40129088Smarkm	    }
40229088Smarkm	    fprintf(NetTrace, " %d %d (%d)",
40329088Smarkm		pointer[1], pointer[2],
40429088Smarkm		(int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2])));
40529088Smarkm	    if (length == 4) {
40629088Smarkm		fprintf(NetTrace, " ?%d?", pointer[3]);
40729088Smarkm		break;
40829088Smarkm	    }
40929088Smarkm	    fprintf(NetTrace, " %d %d (%d)",
41029088Smarkm		pointer[3], pointer[4],
41129088Smarkm		(int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4])));
41229088Smarkm	    for (i = 5; i < length; i++)
41329088Smarkm		fprintf(NetTrace, " ?%d?", pointer[i]);
41429088Smarkm	    break;
41529088Smarkm
41687139Smarkm#ifdef	AUTHENTICATION
41729088Smarkm	case TELOPT_AUTHENTICATION:
41829088Smarkm	    fprintf(NetTrace, "AUTHENTICATION");
41929088Smarkm	    if (length < 2) {
42029088Smarkm		fprintf(NetTrace, " (empty suboption??\?)");
42129088Smarkm		break;
42229088Smarkm	    }
42329088Smarkm	    switch (pointer[1]) {
42429088Smarkm	    case TELQUAL_REPLY:
42529088Smarkm	    case TELQUAL_IS:
42629088Smarkm		fprintf(NetTrace, " %s ", (pointer[1] == TELQUAL_IS) ?
42729088Smarkm							"IS" : "REPLY");
42829088Smarkm		if (AUTHTYPE_NAME_OK(pointer[2]))
42929088Smarkm		    fprintf(NetTrace, "%s ", AUTHTYPE_NAME(pointer[2]));
43029088Smarkm		else
43129088Smarkm		    fprintf(NetTrace, "%d ", pointer[2]);
43229088Smarkm		if (length < 3) {
43329088Smarkm		    fprintf(NetTrace, "(partial suboption??\?)");
43429088Smarkm		    break;
43529088Smarkm		}
43629088Smarkm		fprintf(NetTrace, "%s|%s",
43729088Smarkm			((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
43829088Smarkm			"CLIENT" : "SERVER",
43929088Smarkm			((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
44029088Smarkm			"MUTUAL" : "ONE-WAY");
44129088Smarkm
44229088Smarkm		auth_printsub(&pointer[1], length - 1, buf, sizeof(buf));
44329088Smarkm		fprintf(NetTrace, "%s", buf);
44429088Smarkm		break;
44529088Smarkm
44629088Smarkm	    case TELQUAL_SEND:
44729088Smarkm		i = 2;
44829088Smarkm		fprintf(NetTrace, " SEND ");
44929088Smarkm		while (i < length) {
45029088Smarkm		    if (AUTHTYPE_NAME_OK(pointer[i]))
45129088Smarkm			fprintf(NetTrace, "%s ", AUTHTYPE_NAME(pointer[i]));
45229088Smarkm		    else
45329088Smarkm			fprintf(NetTrace, "%d ", pointer[i]);
45429088Smarkm		    if (++i >= length) {
45529088Smarkm			fprintf(NetTrace, "(partial suboption??\?)");
45629088Smarkm			break;
45729088Smarkm		    }
45829088Smarkm		    fprintf(NetTrace, "%s|%s ",
45929088Smarkm			((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
46029088Smarkm							"CLIENT" : "SERVER",
46129088Smarkm			((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
46229088Smarkm							"MUTUAL" : "ONE-WAY");
46329088Smarkm		    ++i;
46429088Smarkm		}
46529088Smarkm		break;
46629088Smarkm
46729088Smarkm	    case TELQUAL_NAME:
46829088Smarkm		i = 2;
46929088Smarkm		fprintf(NetTrace, " NAME \"");
47029088Smarkm		while (i < length)
47129088Smarkm		    putc(pointer[i++], NetTrace);
47229088Smarkm		putc('"', NetTrace);
47329088Smarkm		break;
47429088Smarkm
47529088Smarkm	    default:
47629088Smarkm		    for (i = 2; i < length; i++)
47729088Smarkm			fprintf(NetTrace, " ?%d?", pointer[i]);
47829088Smarkm		    break;
47929088Smarkm	    }
48029088Smarkm	    break;
48129088Smarkm#endif
48229088Smarkm
48329088Smarkm#ifdef	ENCRYPTION
48429088Smarkm	case TELOPT_ENCRYPT:
48529088Smarkm	    fprintf(NetTrace, "ENCRYPT");
48629088Smarkm	    if (length < 2) {
48729088Smarkm		fprintf(NetTrace, " (empty suboption??\?)");
48829088Smarkm		break;
48929088Smarkm	    }
49029088Smarkm	    switch (pointer[1]) {
49129088Smarkm	    case ENCRYPT_START:
49229088Smarkm		fprintf(NetTrace, " START");
49329088Smarkm		break;
49429088Smarkm
49529088Smarkm	    case ENCRYPT_END:
49629088Smarkm		fprintf(NetTrace, " END");
49729088Smarkm		break;
49829088Smarkm
49929088Smarkm	    case ENCRYPT_REQSTART:
50029088Smarkm		fprintf(NetTrace, " REQUEST-START");
50129088Smarkm		break;
50229088Smarkm
50329088Smarkm	    case ENCRYPT_REQEND:
50429088Smarkm		fprintf(NetTrace, " REQUEST-END");
50529088Smarkm		break;
50629088Smarkm
50729088Smarkm	    case ENCRYPT_IS:
50829088Smarkm	    case ENCRYPT_REPLY:
50929088Smarkm		fprintf(NetTrace, " %s ", (pointer[1] == ENCRYPT_IS) ?
51029088Smarkm							"IS" : "REPLY");
51129088Smarkm		if (length < 3) {
51229088Smarkm		    fprintf(NetTrace, " (partial suboption??\?)");
51329088Smarkm		    break;
51429088Smarkm		}
51529088Smarkm		if (ENCTYPE_NAME_OK(pointer[2]))
51629088Smarkm		    fprintf(NetTrace, "%s ", ENCTYPE_NAME(pointer[2]));
51729088Smarkm		else
51829088Smarkm		    fprintf(NetTrace, " %d (unknown)", pointer[2]);
51929088Smarkm
52029088Smarkm		encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf));
52129088Smarkm		fprintf(NetTrace, "%s", buf);
52229088Smarkm		break;
52329088Smarkm
52429088Smarkm	    case ENCRYPT_SUPPORT:
52529088Smarkm		i = 2;
52629088Smarkm		fprintf(NetTrace, " SUPPORT ");
52729088Smarkm		while (i < length) {
52829088Smarkm		    if (ENCTYPE_NAME_OK(pointer[i]))
52929088Smarkm			fprintf(NetTrace, "%s ", ENCTYPE_NAME(pointer[i]));
53029088Smarkm		    else
53129088Smarkm			fprintf(NetTrace, "%d ", pointer[i]);
53229088Smarkm		    i++;
53329088Smarkm		}
53429088Smarkm		break;
53529088Smarkm
53629088Smarkm	    case ENCRYPT_ENC_KEYID:
53729088Smarkm		fprintf(NetTrace, " ENC_KEYID ");
53829088Smarkm		goto encommon;
53929088Smarkm
54029088Smarkm	    case ENCRYPT_DEC_KEYID:
54129088Smarkm		fprintf(NetTrace, " DEC_KEYID ");
54229088Smarkm		goto encommon;
54329088Smarkm
54429088Smarkm	    default:
54529088Smarkm		fprintf(NetTrace, " %d (unknown)", pointer[1]);
54629088Smarkm	    encommon:
54729088Smarkm		for (i = 2; i < length; i++)
54829088Smarkm		    fprintf(NetTrace, " %d", pointer[i]);
54929088Smarkm		break;
55029088Smarkm	    }
55129088Smarkm	    break;
55229088Smarkm#endif	/* ENCRYPTION */
55329088Smarkm
55429088Smarkm	case TELOPT_LINEMODE:
55529088Smarkm	    fprintf(NetTrace, "LINEMODE ");
55629088Smarkm	    if (length < 2) {
55729088Smarkm		fprintf(NetTrace, " (empty suboption??\?)");
55829088Smarkm		break;
55929088Smarkm	    }
56029088Smarkm	    switch (pointer[1]) {
56129088Smarkm	    case WILL:
56229088Smarkm		fprintf(NetTrace, "WILL ");
56329088Smarkm		goto common;
56429088Smarkm	    case WONT:
56529088Smarkm		fprintf(NetTrace, "WONT ");
56629088Smarkm		goto common;
56729088Smarkm	    case DO:
56829088Smarkm		fprintf(NetTrace, "DO ");
56929088Smarkm		goto common;
57029088Smarkm	    case DONT:
57129088Smarkm		fprintf(NetTrace, "DONT ");
57229088Smarkm	    common:
57329088Smarkm		if (length < 3) {
57429088Smarkm		    fprintf(NetTrace, "(no option??\?)");
57529088Smarkm		    break;
57629088Smarkm		}
57729088Smarkm		switch (pointer[2]) {
57829088Smarkm		case LM_FORWARDMASK:
57929088Smarkm		    fprintf(NetTrace, "Forward Mask");
58029088Smarkm		    for (i = 3; i < length; i++)
58129088Smarkm			fprintf(NetTrace, " %x", pointer[i]);
58229088Smarkm		    break;
58329088Smarkm		default:
58429088Smarkm		    fprintf(NetTrace, "%d (unknown)", pointer[2]);
58529088Smarkm		    for (i = 3; i < length; i++)
58629088Smarkm			fprintf(NetTrace, " %d", pointer[i]);
58729088Smarkm		    break;
58829088Smarkm		}
58929088Smarkm		break;
59029088Smarkm
59129088Smarkm	    case LM_SLC:
59229088Smarkm		fprintf(NetTrace, "SLC");
59329088Smarkm		for (i = 2; i < length - 2; i += 3) {
59429088Smarkm		    if (SLC_NAME_OK(pointer[i+SLC_FUNC]))
59529088Smarkm			fprintf(NetTrace, " %s", SLC_NAME(pointer[i+SLC_FUNC]));
59629088Smarkm		    else
59729088Smarkm			fprintf(NetTrace, " %d", pointer[i+SLC_FUNC]);
59829088Smarkm		    switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) {
59929088Smarkm		    case SLC_NOSUPPORT:
60029088Smarkm			fprintf(NetTrace, " NOSUPPORT"); break;
60129088Smarkm		    case SLC_CANTCHANGE:
60229088Smarkm			fprintf(NetTrace, " CANTCHANGE"); break;
60329088Smarkm		    case SLC_VARIABLE:
60429088Smarkm			fprintf(NetTrace, " VARIABLE"); break;
60529088Smarkm		    case SLC_DEFAULT:
60629088Smarkm			fprintf(NetTrace, " DEFAULT"); break;
60729088Smarkm		    }
60829088Smarkm		    fprintf(NetTrace, "%s%s%s",
60929088Smarkm			pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "",
61029088Smarkm			pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "",
61129088Smarkm			pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : "");
61229088Smarkm		    if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN|
61329088Smarkm						SLC_FLUSHOUT| SLC_LEVELBITS))
61429088Smarkm			fprintf(NetTrace, "(0x%x)", pointer[i+SLC_FLAGS]);
61529088Smarkm		    fprintf(NetTrace, " %d;", pointer[i+SLC_VALUE]);
61629088Smarkm		    if ((pointer[i+SLC_VALUE] == IAC) &&
61729088Smarkm			(pointer[i+SLC_VALUE+1] == IAC))
61829088Smarkm				i++;
61929088Smarkm		}
62029088Smarkm		for (; i < length; i++)
62129088Smarkm		    fprintf(NetTrace, " ?%d?", pointer[i]);
62229088Smarkm		break;
62329088Smarkm
62429088Smarkm	    case LM_MODE:
62529088Smarkm		fprintf(NetTrace, "MODE ");
62629088Smarkm		if (length < 3) {
62729088Smarkm		    fprintf(NetTrace, "(no mode??\?)");
62829088Smarkm		    break;
62929088Smarkm		}
63029088Smarkm		{
63129088Smarkm		    char tbuf[64];
63229088Smarkm		    sprintf(tbuf, "%s%s%s%s%s",
63329088Smarkm			pointer[2]&MODE_EDIT ? "|EDIT" : "",
63429088Smarkm			pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "",
63529088Smarkm			pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "",
63629088Smarkm			pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "",
63729088Smarkm			pointer[2]&MODE_ACK ? "|ACK" : "");
63829088Smarkm		    fprintf(NetTrace, "%s", tbuf[1] ? &tbuf[1] : "0");
63929088Smarkm		}
64029088Smarkm		if (pointer[2]&~(MODE_MASK))
64129088Smarkm		    fprintf(NetTrace, " (0x%x)", pointer[2]);
64229088Smarkm		for (i = 3; i < length; i++)
64329088Smarkm		    fprintf(NetTrace, " ?0x%x?", pointer[i]);
64429088Smarkm		break;
64529088Smarkm	    default:
64629088Smarkm		fprintf(NetTrace, "%d (unknown)", pointer[1]);
64729088Smarkm		for (i = 2; i < length; i++)
64829088Smarkm		    fprintf(NetTrace, " %d", pointer[i]);
64929088Smarkm	    }
65029088Smarkm	    break;
65129088Smarkm
65229088Smarkm	case TELOPT_STATUS: {
65387139Smarkm	    const char *cp;
65487139Smarkm	    int j, k;
65529088Smarkm
65629088Smarkm	    fprintf(NetTrace, "STATUS");
65729088Smarkm
65829088Smarkm	    switch (pointer[1]) {
65929088Smarkm	    default:
66029088Smarkm		if (pointer[1] == TELQUAL_SEND)
66129088Smarkm		    fprintf(NetTrace, " SEND");
66229088Smarkm		else
66329088Smarkm		    fprintf(NetTrace, " %d (unknown)", pointer[1]);
66429088Smarkm		for (i = 2; i < length; i++)
66529088Smarkm		    fprintf(NetTrace, " ?%d?", pointer[i]);
66629088Smarkm		break;
66729088Smarkm	    case TELQUAL_IS:
66829088Smarkm		if (--want_status_response < 0)
66929088Smarkm		    want_status_response = 0;
67029088Smarkm		if (NetTrace == stdout)
67129088Smarkm		    fprintf(NetTrace, " IS\r\n");
67229088Smarkm		else
67329088Smarkm		    fprintf(NetTrace, " IS\n");
67429088Smarkm
67529088Smarkm		for (i = 2; i < length; i++) {
67629088Smarkm		    switch(pointer[i]) {
67729088Smarkm		    case DO:	cp = "DO"; goto common2;
67829088Smarkm		    case DONT:	cp = "DONT"; goto common2;
67929088Smarkm		    case WILL:	cp = "WILL"; goto common2;
68029088Smarkm		    case WONT:	cp = "WONT"; goto common2;
68129088Smarkm		    common2:
68229088Smarkm			i++;
68329088Smarkm			if (TELOPT_OK((int)pointer[i]))
68429088Smarkm			    fprintf(NetTrace, " %s %s", cp, TELOPT(pointer[i]));
68529088Smarkm			else
68629088Smarkm			    fprintf(NetTrace, " %s %d", cp, pointer[i]);
68729088Smarkm
68829088Smarkm			if (NetTrace == stdout)
68929088Smarkm			    fprintf(NetTrace, "\r\n");
69029088Smarkm			else
69129088Smarkm			    fprintf(NetTrace, "\n");
69229088Smarkm			break;
69329088Smarkm
69429088Smarkm		    case SB:
69529088Smarkm			fprintf(NetTrace, " SB ");
69629088Smarkm			i++;
69729088Smarkm			j = k = i;
69829088Smarkm			while (j < length) {
69929088Smarkm			    if (pointer[j] == SE) {
70029088Smarkm				if (j+1 == length)
70129088Smarkm				    break;
70229088Smarkm				if (pointer[j+1] == SE)
70329088Smarkm				    j++;
70429088Smarkm				else
70529088Smarkm				    break;
70629088Smarkm			    }
70729088Smarkm			    pointer[k++] = pointer[j++];
70829088Smarkm			}
70929088Smarkm			printsub(0, &pointer[i], k - i);
71029088Smarkm			if (i < length) {
71129088Smarkm			    fprintf(NetTrace, " SE");
71229088Smarkm			    i = j;
71329088Smarkm			} else
71429088Smarkm			    i = j - 1;
71529088Smarkm
71629088Smarkm			if (NetTrace == stdout)
71729088Smarkm			    fprintf(NetTrace, "\r\n");
71829088Smarkm			else
71929088Smarkm			    fprintf(NetTrace, "\n");
72029088Smarkm
72129088Smarkm			break;
72229088Smarkm
72329088Smarkm		    default:
72429088Smarkm			fprintf(NetTrace, " %d", pointer[i]);
72529088Smarkm			break;
72629088Smarkm		    }
72729088Smarkm		}
72829088Smarkm		break;
72929088Smarkm	    }
73029088Smarkm	    break;
73129088Smarkm	  }
73229088Smarkm
73329088Smarkm	case TELOPT_XDISPLOC:
73429088Smarkm	    fprintf(NetTrace, "X-DISPLAY-LOCATION ");
73529088Smarkm	    switch (pointer[1]) {
73629088Smarkm	    case TELQUAL_IS:
73729088Smarkm		fprintf(NetTrace, "IS \"%.*s\"", length-2, (char *)pointer+2);
73829088Smarkm		break;
73929088Smarkm	    case TELQUAL_SEND:
74029088Smarkm		fprintf(NetTrace, "SEND");
74129088Smarkm		break;
74229088Smarkm	    default:
74329088Smarkm		fprintf(NetTrace, "- unknown qualifier %d (0x%x).",
74429088Smarkm				pointer[1], pointer[1]);
74529088Smarkm	    }
74629088Smarkm	    break;
74729088Smarkm
74829088Smarkm	case TELOPT_NEW_ENVIRON:
74929088Smarkm	    fprintf(NetTrace, "NEW-ENVIRON ");
75029088Smarkm#ifdef	OLD_ENVIRON
75129088Smarkm	    goto env_common1;
75229088Smarkm	case TELOPT_OLD_ENVIRON:
75329088Smarkm	    fprintf(NetTrace, "OLD-ENVIRON");
75429088Smarkm	env_common1:
75529088Smarkm#endif
75629088Smarkm	    switch (pointer[1]) {
75729088Smarkm	    case TELQUAL_IS:
75829088Smarkm		fprintf(NetTrace, "IS ");
75929088Smarkm		goto env_common;
76029088Smarkm	    case TELQUAL_SEND:
76129088Smarkm		fprintf(NetTrace, "SEND ");
76229088Smarkm		goto env_common;
76329088Smarkm	    case TELQUAL_INFO:
76429088Smarkm		fprintf(NetTrace, "INFO ");
76529088Smarkm	    env_common:
76629088Smarkm		{
76787139Smarkm		    int noquote = 2;
76829088Smarkm#if defined(ENV_HACK) && defined(OLD_ENVIRON)
76929088Smarkm		    extern int old_env_var, old_env_value;
77029088Smarkm#endif
77129088Smarkm		    for (i = 2; i < length; i++ ) {
77229088Smarkm			switch (pointer[i]) {
77329088Smarkm			case NEW_ENV_VALUE:
77429088Smarkm#ifdef OLD_ENVIRON
77529088Smarkm		     /*	case NEW_ENV_OVAR: */
77629088Smarkm			    if (pointer[0] == TELOPT_OLD_ENVIRON) {
77729088Smarkm# ifdef	ENV_HACK
77829088Smarkm				if (old_env_var == OLD_ENV_VALUE)
77929088Smarkm				    fprintf(NetTrace, "\" (VALUE) " + noquote);
78029088Smarkm				else
78129088Smarkm# endif
78229088Smarkm				    fprintf(NetTrace, "\" VAR " + noquote);
78329088Smarkm			    } else
78429088Smarkm#endif /* OLD_ENVIRON */
785228651Sdim				fprintf(NetTrace, "%s", "\" VALUE " + noquote);
78629088Smarkm			    noquote = 2;
78729088Smarkm			    break;
78829088Smarkm
78929088Smarkm			case NEW_ENV_VAR:
79029088Smarkm#ifdef OLD_ENVIRON
79129088Smarkm		     /* case OLD_ENV_VALUE: */
79229088Smarkm			    if (pointer[0] == TELOPT_OLD_ENVIRON) {
79329088Smarkm# ifdef	ENV_HACK
79429088Smarkm				if (old_env_value == OLD_ENV_VAR)
79529088Smarkm				    fprintf(NetTrace, "\" (VAR) " + noquote);
79629088Smarkm				else
79729088Smarkm# endif
79829088Smarkm				    fprintf(NetTrace, "\" VALUE " + noquote);
79929088Smarkm			    } else
80029088Smarkm#endif /* OLD_ENVIRON */
801228651Sdim				fprintf(NetTrace, "%s", "\" VAR " + noquote);
80229088Smarkm			    noquote = 2;
80329088Smarkm			    break;
80429088Smarkm
80529088Smarkm			case ENV_ESC:
806228651Sdim			    fprintf(NetTrace, "%s", "\" ESC " + noquote);
80729088Smarkm			    noquote = 2;
80829088Smarkm			    break;
80929088Smarkm
81029088Smarkm			case ENV_USERVAR:
811228651Sdim			    fprintf(NetTrace, "%s", "\" USERVAR " + noquote);
81229088Smarkm			    noquote = 2;
81329088Smarkm			    break;
81429088Smarkm
81529088Smarkm			default:
81629088Smarkm			    if (isprint(pointer[i]) && pointer[i] != '"') {
81729088Smarkm				if (noquote) {
81829088Smarkm				    putc('"', NetTrace);
81929088Smarkm				    noquote = 0;
82029088Smarkm				}
82129088Smarkm				putc(pointer[i], NetTrace);
82229088Smarkm			    } else {
82329088Smarkm				fprintf(NetTrace, "\" %03o " + noquote,
82429088Smarkm							pointer[i]);
82529088Smarkm				noquote = 2;
82629088Smarkm			    }
82729088Smarkm			    break;
82829088Smarkm			}
82929088Smarkm		    }
83029088Smarkm		    if (!noquote)
83129088Smarkm			putc('"', NetTrace);
83229088Smarkm		    break;
83329088Smarkm		}
83429088Smarkm	    }
83529088Smarkm	    break;
83629088Smarkm
83729088Smarkm	default:
83829088Smarkm	    if (TELOPT_OK(pointer[0]))
83929088Smarkm		fprintf(NetTrace, "%s (unknown)", TELOPT(pointer[0]));
84029088Smarkm	    else
84129088Smarkm		fprintf(NetTrace, "%d (unknown)", pointer[0]);
84229088Smarkm	    for (i = 1; i < length; i++)
84329088Smarkm		fprintf(NetTrace, " %d", pointer[i]);
84429088Smarkm	    break;
84529088Smarkm	}
84629088Smarkm	if (direction) {
84729088Smarkm	    if (NetTrace == stdout)
84829088Smarkm		fprintf(NetTrace, "\r\n");
84929088Smarkm	    else
85029088Smarkm		fprintf(NetTrace, "\n");
85129088Smarkm	}
85229088Smarkm	if (NetTrace == stdout)
85329088Smarkm	    fflush(NetTrace);
85429088Smarkm    }
85529088Smarkm}
85629088Smarkm
85729088Smarkm/* EmptyTerminal - called to make sure that the terminal buffer is empty.
85829088Smarkm *			Note that we consider the buffer to run all the
85929088Smarkm *			way to the kernel (thus the select).
86029088Smarkm */
86129088Smarkm
86287139Smarkmstatic void
86387139SmarkmEmptyTerminal(void)
86429088Smarkm{
86529088Smarkm    fd_set	o;
86629088Smarkm
86729088Smarkm    FD_ZERO(&o);
86829088Smarkm
86929088Smarkm    if (TTYBYTES() == 0) {
87029088Smarkm	FD_SET(tout, &o);
87129088Smarkm	(void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
87229088Smarkm			(struct timeval *) 0);	/* wait for TTLOWAT */
87329088Smarkm    } else {
87429088Smarkm	while (TTYBYTES()) {
87529088Smarkm	    (void) ttyflush(0);
87629088Smarkm	    FD_SET(tout, &o);
87729088Smarkm	    (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
87829088Smarkm				(struct timeval *) 0);	/* wait for TTLOWAT */
87929088Smarkm	}
88029088Smarkm    }
88129088Smarkm}
88229088Smarkm
88387139Smarkmstatic void
88487139SmarkmSetForExit(void)
88529088Smarkm{
88629088Smarkm    setconnmode(0);
88729088Smarkm    do {
88829088Smarkm	(void)telrcv();			/* Process any incoming data */
88929088Smarkm	EmptyTerminal();
89029088Smarkm    } while (ring_full_count(&netiring));	/* While there is any */
89129088Smarkm    setcommandmode();
89229088Smarkm    fflush(stdout);
89329088Smarkm    fflush(stderr);
89429088Smarkm    setconnmode(0);
89529088Smarkm    EmptyTerminal();			/* Flush the path to the tty */
89629088Smarkm    setcommandmode();
89729088Smarkm}
89829088Smarkm
89987139Smarkmvoid
90087139SmarkmExit(int returnCode)
90129088Smarkm{
90229088Smarkm    SetForExit();
90329088Smarkm    exit(returnCode);
90429088Smarkm}
90529088Smarkm
90687139Smarkmvoid
90787139SmarkmExitString(const char *string, int returnCode)
90829088Smarkm{
90929088Smarkm    SetForExit();
91029088Smarkm    fwrite(string, 1, strlen(string), stderr);
91129088Smarkm    exit(returnCode);
91229088Smarkm}
913