157416Smarkm/*
257416Smarkm * Copyright (c) 1988, 1993
357416Smarkm *	The Regents of the University of California.  All rights reserved.
457416Smarkm *
557416Smarkm * Redistribution and use in source and binary forms, with or without
657416Smarkm * modification, are permitted provided that the following conditions
757416Smarkm * are met:
857416Smarkm * 1. Redistributions of source code must retain the above copyright
957416Smarkm *    notice, this list of conditions and the following disclaimer.
1057416Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1157416Smarkm *    notice, this list of conditions and the following disclaimer in the
1257416Smarkm *    documentation and/or other materials provided with the distribution.
1357416Smarkm * 3. All advertising materials mentioning features or use of this software
1457416Smarkm *    must display the following acknowledgement:
1557416Smarkm *	This product includes software developed by the University of
1657416Smarkm *	California, Berkeley and its contributors.
1757416Smarkm * 4. Neither the name of the University nor the names of its contributors
1857416Smarkm *    may be used to endorse or promote products derived from this software
1957416Smarkm *    without specific prior written permission.
2057416Smarkm *
2157416Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2257416Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2357416Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2457416Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2557416Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2657416Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2757416Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2857416Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2957416Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3057416Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3157416Smarkm * SUCH DAMAGE.
3257416Smarkm */
3357416Smarkm
3457416Smarkm#define TELOPTS
3557416Smarkm#define TELCMDS
3657416Smarkm#define SLC_NAMES
3757416Smarkm
3857416Smarkm#include "telnet_locl.h"
3957416Smarkm
40233294SstasRCSID("$Id$");
4157416Smarkm
4257416SmarkmFILE	*NetTrace = 0;		/* Not in bss, since needs to stay */
4357416Smarkmint	prettydump;
4457416Smarkm
4557416Smarkm/*
4657416Smarkm * SetSockOpt()
4757416Smarkm *
4857416Smarkm * Compensate for differences in 4.2 and 4.3 systems.
4957416Smarkm */
5057416Smarkm
5157416Smarkmint
5257416SmarkmSetSockOpt(int fd, int level, int option, int yesno)
5357416Smarkm{
5457416Smarkm#ifdef HAVE_SETSOCKOPT
5557416Smarkm#ifndef	NOT43
5657416Smarkm    return setsockopt(fd, level, option,
5757416Smarkm				(void *)&yesno, sizeof yesno);
5857416Smarkm#else	/* NOT43 */
5957416Smarkm    if (yesno == 0) {		/* Can't do that in 4.2! */
6057416Smarkm	fprintf(stderr, "Error: attempt to turn off an option 0x%x.\n",
6157416Smarkm				option);
6257416Smarkm	return -1;
6357416Smarkm    }
6457416Smarkm    return setsockopt(fd, level, option, 0, 0);
6557416Smarkm#endif	/* NOT43 */
6657416Smarkm#else
6757416Smarkm    return -1;
6857416Smarkm#endif
6957416Smarkm}
7057416Smarkm
7157416Smarkm/*
7257416Smarkm * The following are routines used to print out debugging information.
7357416Smarkm */
7457416Smarkm
7557416Smarkmchar NetTraceFile[256] = "(standard output)";
7657416Smarkm
7757416Smarkmvoid
7857416SmarkmSetNetTrace(char *file)
7957416Smarkm{
8057416Smarkm    if (NetTrace && NetTrace != stdout)
8157416Smarkm	fclose(NetTrace);
8257416Smarkm    if (file  && (strcmp(file, "-") != 0)) {
8357416Smarkm	NetTrace = fopen(file, "w");
8457416Smarkm	if (NetTrace) {
8557416Smarkm	    strlcpy(NetTraceFile, file, sizeof(NetTraceFile));
8657416Smarkm	    return;
8757416Smarkm	}
8857416Smarkm	fprintf(stderr, "Cannot open %s.\n", file);
8957416Smarkm    }
9057416Smarkm    NetTrace = stdout;
9157416Smarkm    strlcpy(NetTraceFile, "(standard output)", sizeof(NetTraceFile));
9257416Smarkm}
9357416Smarkm
9457416Smarkmvoid
9557416SmarkmDump(char direction, unsigned char *buffer, int length)
9657416Smarkm{
9757416Smarkm#   define BYTES_PER_LINE	32
9857416Smarkm    unsigned char *pThis;
9957416Smarkm    int offset;
10057416Smarkm
10157416Smarkm    offset = 0;
10257416Smarkm
10357416Smarkm    while (length) {
10457416Smarkm	/* print one line */
10557416Smarkm	fprintf(NetTrace, "%c 0x%x\t", direction, offset);
10657416Smarkm	pThis = buffer;
10757416Smarkm	if (prettydump) {
10857416Smarkm	    buffer = buffer + min(length, BYTES_PER_LINE/2);
10957416Smarkm	    while (pThis < buffer) {
11057416Smarkm		fprintf(NetTrace, "%c%.2x",
11157416Smarkm		    (((*pThis)&0xff) == 0xff) ? '*' : ' ',
11257416Smarkm		    (*pThis)&0xff);
11357416Smarkm		pThis++;
11457416Smarkm	    }
11557416Smarkm	    length -= BYTES_PER_LINE/2;
11657416Smarkm	    offset += BYTES_PER_LINE/2;
11757416Smarkm	} else {
11857416Smarkm	    buffer = buffer + min(length, BYTES_PER_LINE);
11957416Smarkm	    while (pThis < buffer) {
12057416Smarkm		fprintf(NetTrace, "%.2x", (*pThis)&0xff);
12157416Smarkm		pThis++;
12257416Smarkm	    }
12357416Smarkm	    length -= BYTES_PER_LINE;
12457416Smarkm	    offset += BYTES_PER_LINE;
12557416Smarkm	}
12657416Smarkm	if (NetTrace == stdout) {
12757416Smarkm	    fprintf(NetTrace, "\r\n");
12857416Smarkm	} else {
12957416Smarkm	    fprintf(NetTrace, "\n");
13057416Smarkm	}
13157416Smarkm	if (length < 0) {
13257416Smarkm	    fflush(NetTrace);
13357416Smarkm	    return;
13457416Smarkm	}
13557416Smarkm	/* find next unique line */
13657416Smarkm    }
13757416Smarkm    fflush(NetTrace);
13857416Smarkm}
13957416Smarkm
14057416Smarkm
14157416Smarkmvoid
14257416Smarkmprintoption(char *direction, int cmd, int option)
14357416Smarkm{
14457416Smarkm	if (!showoptions)
14557416Smarkm		return;
14657416Smarkm	if (cmd == IAC) {
14757416Smarkm		if (TELCMD_OK(option))
14857416Smarkm		    fprintf(NetTrace, "%s IAC %s", direction, TELCMD(option));
14957416Smarkm		else
15057416Smarkm		    fprintf(NetTrace, "%s IAC %d", direction, option);
15157416Smarkm	} else {
15257416Smarkm		char *fmt;
15357416Smarkm		fmt = (cmd == WILL) ? "WILL" : (cmd == WONT) ? "WONT" :
15457416Smarkm			(cmd == DO) ? "DO" : (cmd == DONT) ? "DONT" : 0;
15557416Smarkm		if (fmt) {
15657416Smarkm		    fprintf(NetTrace, "%s %s ", direction, fmt);
15757416Smarkm		    if (TELOPT_OK(option))
15857416Smarkm			fprintf(NetTrace, "%s", TELOPT(option));
15957416Smarkm		    else if (option == TELOPT_EXOPL)
16057416Smarkm			fprintf(NetTrace, "EXOPL");
16157416Smarkm		    else
16257416Smarkm			fprintf(NetTrace, "%d", option);
16357416Smarkm		} else
16457416Smarkm		    fprintf(NetTrace, "%s %d %d", direction, cmd, option);
16557416Smarkm	}
16657416Smarkm	if (NetTrace == stdout) {
16757416Smarkm	    fprintf(NetTrace, "\r\n");
16857416Smarkm	    fflush(NetTrace);
16957416Smarkm	} else {
17057416Smarkm	    fprintf(NetTrace, "\n");
17157416Smarkm	}
17257416Smarkm	return;
17357416Smarkm}
17457416Smarkm
17557416Smarkmvoid
17657416Smarkmoptionstatus(void)
17757416Smarkm{
17857416Smarkm    int i;
17957416Smarkm
18057416Smarkm    for (i = 0; i < 256; i++) {
18157416Smarkm	if (do_dont_resp[i]) {
18257416Smarkm	    if (TELOPT_OK(i))
18357416Smarkm		printf("resp DO_DONT %s: %d\n", TELOPT(i), do_dont_resp[i]);
18457416Smarkm	    else if (TELCMD_OK(i))
18557416Smarkm		printf("resp DO_DONT %s: %d\n", TELCMD(i), do_dont_resp[i]);
18657416Smarkm	    else
18757416Smarkm		printf("resp DO_DONT %d: %d\n", i,
18857416Smarkm				do_dont_resp[i]);
18957416Smarkm	    if (my_want_state_is_do(i)) {
19057416Smarkm		if (TELOPT_OK(i))
19157416Smarkm		    printf("want DO   %s\n", TELOPT(i));
19257416Smarkm		else if (TELCMD_OK(i))
19357416Smarkm		    printf("want DO   %s\n", TELCMD(i));
19457416Smarkm		else
19557416Smarkm		    printf("want DO   %d\n", i);
19657416Smarkm	    } else {
19757416Smarkm		if (TELOPT_OK(i))
19857416Smarkm		    printf("want DONT %s\n", TELOPT(i));
19957416Smarkm		else if (TELCMD_OK(i))
20057416Smarkm		    printf("want DONT %s\n", TELCMD(i));
20157416Smarkm		else
20257416Smarkm		    printf("want DONT %d\n", i);
20357416Smarkm	    }
20457416Smarkm	} else {
20557416Smarkm	    if (my_state_is_do(i)) {
20657416Smarkm		if (TELOPT_OK(i))
20757416Smarkm		    printf("     DO   %s\n", TELOPT(i));
20857416Smarkm		else if (TELCMD_OK(i))
20957416Smarkm		    printf("     DO   %s\n", TELCMD(i));
21057416Smarkm		else
21157416Smarkm		    printf("     DO   %d\n", i);
21257416Smarkm	    }
21357416Smarkm	}
21457416Smarkm	if (will_wont_resp[i]) {
21557416Smarkm	    if (TELOPT_OK(i))
21657416Smarkm		printf("resp WILL_WONT %s: %d\n", TELOPT(i), will_wont_resp[i]);
21757416Smarkm	    else if (TELCMD_OK(i))
21857416Smarkm		printf("resp WILL_WONT %s: %d\n", TELCMD(i), will_wont_resp[i]);
21957416Smarkm	    else
22057416Smarkm		printf("resp WILL_WONT %d: %d\n",
22157416Smarkm				i, will_wont_resp[i]);
22257416Smarkm	    if (my_want_state_is_will(i)) {
22357416Smarkm		if (TELOPT_OK(i))
22457416Smarkm		    printf("want WILL %s\n", TELOPT(i));
22557416Smarkm		else if (TELCMD_OK(i))
22657416Smarkm		    printf("want WILL %s\n", TELCMD(i));
22757416Smarkm		else
22857416Smarkm		    printf("want WILL %d\n", i);
22957416Smarkm	    } else {
23057416Smarkm		if (TELOPT_OK(i))
23157416Smarkm		    printf("want WONT %s\n", TELOPT(i));
23257416Smarkm		else if (TELCMD_OK(i))
23357416Smarkm		    printf("want WONT %s\n", TELCMD(i));
23457416Smarkm		else
23557416Smarkm		    printf("want WONT %d\n", i);
23657416Smarkm	    }
23757416Smarkm	} else {
23857416Smarkm	    if (my_state_is_will(i)) {
23957416Smarkm		if (TELOPT_OK(i))
24057416Smarkm		    printf("     WILL %s\n", TELOPT(i));
24157416Smarkm		else if (TELCMD_OK(i))
24257416Smarkm		    printf("     WILL %s\n", TELCMD(i));
24357416Smarkm		else
24457416Smarkm		    printf("     WILL %d\n", i);
24557416Smarkm	    }
24657416Smarkm	}
24757416Smarkm    }
24857416Smarkm
24957416Smarkm}
25057416Smarkm
251233294Sstasstatic void __attribute__((format (printf, 3, 4)))
252233294Sstasqprintf(int quote, FILE *f, const char *fmt, ...)
253233294Sstas
254233294Sstas{
255233294Sstas    va_list va;
256233294Sstas    if (quote)
257233294Sstas	fprintf(f, "\" ");
258233294Sstas    va_start(va, fmt);
259233294Sstas    vfprintf(f, fmt, va);
260233294Sstas    va_end(va);
261233294Sstas}
262233294Sstas
26357416Smarkmvoid
264233294Sstasprintsub(int direction, unsigned char *pointer, size_t length)
26557416Smarkm{
26657416Smarkm    int i;
26757416Smarkm    unsigned char buf[512];
26857416Smarkm
26957416Smarkm    if (showoptions || direction == 0 ||
27057416Smarkm	(want_status_response && (pointer[0] == TELOPT_STATUS))) {
27157416Smarkm	if (direction) {
27257416Smarkm	    fprintf(NetTrace, "%s IAC SB ",
27357416Smarkm				(direction == '<')? "RCVD":"SENT");
27457416Smarkm	    if (length >= 3) {
27557416Smarkm		int j;
27657416Smarkm
27757416Smarkm		i = pointer[length-2];
27857416Smarkm		j = pointer[length-1];
27957416Smarkm
28057416Smarkm		if (i != IAC || j != SE) {
28157416Smarkm		    fprintf(NetTrace, "(terminated by ");
28257416Smarkm		    if (TELOPT_OK(i))
28357416Smarkm			fprintf(NetTrace, "%s ", TELOPT(i));
28457416Smarkm		    else if (TELCMD_OK(i))
28557416Smarkm			fprintf(NetTrace, "%s ", TELCMD(i));
28657416Smarkm		    else
28757416Smarkm			fprintf(NetTrace, "%d ", i);
28857416Smarkm		    if (TELOPT_OK(j))
28957416Smarkm			fprintf(NetTrace, "%s", TELOPT(j));
29057416Smarkm		    else if (TELCMD_OK(j))
29157416Smarkm			fprintf(NetTrace, "%s", TELCMD(j));
29257416Smarkm		    else
29357416Smarkm			fprintf(NetTrace, "%d", j);
29457416Smarkm		    fprintf(NetTrace, ", not IAC SE!) ");
29557416Smarkm		}
29657416Smarkm	    }
29757416Smarkm	    length -= 2;
29857416Smarkm	}
29957416Smarkm	if (length < 1) {
30057416Smarkm	    fprintf(NetTrace, "(Empty suboption??\?)");
30157416Smarkm	    if (NetTrace == stdout)
30257416Smarkm		fflush(NetTrace);
30357416Smarkm	    return;
30457416Smarkm	}
30557416Smarkm	switch (pointer[0]) {
30657416Smarkm	case TELOPT_TTYPE:
30757416Smarkm	    fprintf(NetTrace, "TERMINAL-TYPE ");
30857416Smarkm	    switch (pointer[1]) {
30957416Smarkm	    case TELQUAL_IS:
310233294Sstas		fprintf(NetTrace, "IS \"%.*s\"",
311233294Sstas			(int)(length-2),
312233294Sstas			(char *)pointer+2);
31357416Smarkm		break;
31457416Smarkm	    case TELQUAL_SEND:
31557416Smarkm		fprintf(NetTrace, "SEND");
31657416Smarkm		break;
31757416Smarkm	    default:
31857416Smarkm		fprintf(NetTrace,
31957416Smarkm				"- unknown qualifier %d (0x%x).",
32057416Smarkm				pointer[1], pointer[1]);
32157416Smarkm	    }
32257416Smarkm	    break;
32357416Smarkm	case TELOPT_TSPEED:
32457416Smarkm	    fprintf(NetTrace, "TERMINAL-SPEED");
32557416Smarkm	    if (length < 2) {
32657416Smarkm		fprintf(NetTrace, " (empty suboption??\?)");
32757416Smarkm		break;
32857416Smarkm	    }
32957416Smarkm	    switch (pointer[1]) {
33057416Smarkm	    case TELQUAL_IS:
33157416Smarkm		fprintf(NetTrace, " IS ");
332233294Sstas		fprintf(NetTrace, "%.*s", (int)(length-2), (char *)pointer+2);
33357416Smarkm		break;
33457416Smarkm	    default:
33557416Smarkm		if (pointer[1] == 1)
33657416Smarkm		    fprintf(NetTrace, " SEND");
33757416Smarkm		else
33857416Smarkm		    fprintf(NetTrace, " %d (unknown)", pointer[1]);
33957416Smarkm		for (i = 2; i < length; i++)
34057416Smarkm		    fprintf(NetTrace, " ?%d?", pointer[i]);
34157416Smarkm		break;
34257416Smarkm	    }
34357416Smarkm	    break;
34457416Smarkm
34557416Smarkm	case TELOPT_LFLOW:
34657416Smarkm	    fprintf(NetTrace, "TOGGLE-FLOW-CONTROL");
34757416Smarkm	    if (length < 2) {
34857416Smarkm		fprintf(NetTrace, " (empty suboption??\?)");
34957416Smarkm		break;
35057416Smarkm	    }
35157416Smarkm	    switch (pointer[1]) {
35257416Smarkm	    case LFLOW_OFF:
35357416Smarkm		fprintf(NetTrace, " OFF"); break;
35457416Smarkm	    case LFLOW_ON:
35557416Smarkm		fprintf(NetTrace, " ON"); break;
35657416Smarkm	    case LFLOW_RESTART_ANY:
35757416Smarkm		fprintf(NetTrace, " RESTART-ANY"); break;
35857416Smarkm	    case LFLOW_RESTART_XON:
35957416Smarkm		fprintf(NetTrace, " RESTART-XON"); break;
36057416Smarkm	    default:
36157416Smarkm		fprintf(NetTrace, " %d (unknown)", pointer[1]);
36257416Smarkm	    }
36357416Smarkm	    for (i = 2; i < length; i++)
36457416Smarkm		fprintf(NetTrace, " ?%d?", pointer[i]);
36557416Smarkm	    break;
36657416Smarkm
36757416Smarkm	case TELOPT_NAWS:
36857416Smarkm	    fprintf(NetTrace, "NAWS");
36957416Smarkm	    if (length < 2) {
37057416Smarkm		fprintf(NetTrace, " (empty suboption??\?)");
37157416Smarkm		break;
37257416Smarkm	    }
37357416Smarkm	    if (length == 2) {
37457416Smarkm		fprintf(NetTrace, " ?%d?", pointer[1]);
37557416Smarkm		break;
37657416Smarkm	    }
37757416Smarkm	    fprintf(NetTrace, " %d %d (%d)",
37857416Smarkm		pointer[1], pointer[2],
37957416Smarkm		(int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2])));
38057416Smarkm	    if (length == 4) {
38157416Smarkm		fprintf(NetTrace, " ?%d?", pointer[3]);
38257416Smarkm		break;
38357416Smarkm	    }
38457416Smarkm	    fprintf(NetTrace, " %d %d (%d)",
38557416Smarkm		pointer[3], pointer[4],
38657416Smarkm		(int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4])));
38757416Smarkm	    for (i = 5; i < length; i++)
38857416Smarkm		fprintf(NetTrace, " ?%d?", pointer[i]);
38957416Smarkm	    break;
39057416Smarkm
39157416Smarkm#if	defined(AUTHENTICATION)
39257416Smarkm	case TELOPT_AUTHENTICATION:
39357416Smarkm	    fprintf(NetTrace, "AUTHENTICATION");
39457416Smarkm	    if (length < 2) {
39557416Smarkm		fprintf(NetTrace, " (empty suboption??\?)");
39657416Smarkm		break;
39757416Smarkm	    }
39857416Smarkm	    switch (pointer[1]) {
39957416Smarkm	    case TELQUAL_REPLY:
40057416Smarkm	    case TELQUAL_IS:
40157416Smarkm		fprintf(NetTrace, " %s ", (pointer[1] == TELQUAL_IS) ?
40257416Smarkm							"IS" : "REPLY");
40357416Smarkm		if (AUTHTYPE_NAME_OK(pointer[2]))
40457416Smarkm		    fprintf(NetTrace, "%s ", AUTHTYPE_NAME(pointer[2]));
40557416Smarkm		else
40657416Smarkm		    fprintf(NetTrace, "%d ", pointer[2]);
40757416Smarkm		if (length < 3) {
40857416Smarkm		    fprintf(NetTrace, "(partial suboption??\?)");
40957416Smarkm		    break;
41057416Smarkm		}
41157416Smarkm		fprintf(NetTrace, "%s|%s",
41257416Smarkm			((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
41357416Smarkm			"CLIENT" : "SERVER",
41457416Smarkm			((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
41557416Smarkm			"MUTUAL" : "ONE-WAY");
41657416Smarkm
41757416Smarkm		auth_printsub(&pointer[1], length - 1, buf, sizeof(buf));
41857416Smarkm		fprintf(NetTrace, "%s", buf);
41957416Smarkm		break;
42057416Smarkm
42157416Smarkm	    case TELQUAL_SEND:
42257416Smarkm		i = 2;
42357416Smarkm		fprintf(NetTrace, " SEND ");
42457416Smarkm		while (i < length) {
42557416Smarkm		    if (AUTHTYPE_NAME_OK(pointer[i]))
42657416Smarkm			fprintf(NetTrace, "%s ", AUTHTYPE_NAME(pointer[i]));
42757416Smarkm		    else
42857416Smarkm			fprintf(NetTrace, "%d ", pointer[i]);
42957416Smarkm		    if (++i >= length) {
43057416Smarkm			fprintf(NetTrace, "(partial suboption??\?)");
43157416Smarkm			break;
43257416Smarkm		    }
43357416Smarkm		    fprintf(NetTrace, "%s|%s ",
43457416Smarkm			((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
43557416Smarkm							"CLIENT" : "SERVER",
43657416Smarkm			((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
43757416Smarkm							"MUTUAL" : "ONE-WAY");
43857416Smarkm		    ++i;
43957416Smarkm		}
44057416Smarkm		break;
44157416Smarkm
44257416Smarkm	    case TELQUAL_NAME:
44357416Smarkm		i = 2;
44457416Smarkm		fprintf(NetTrace, " NAME \"");
44557416Smarkm		while (i < length)
44657416Smarkm		    putc(pointer[i++], NetTrace);
44757416Smarkm		putc('"', NetTrace);
44857416Smarkm		break;
44957416Smarkm
45057416Smarkm	    default:
45157416Smarkm		    for (i = 2; i < length; i++)
45257416Smarkm			fprintf(NetTrace, " ?%d?", pointer[i]);
45357416Smarkm		    break;
45457416Smarkm	    }
45557416Smarkm	    break;
45657416Smarkm#endif
45757416Smarkm
45857416Smarkm#if	defined(ENCRYPTION)
45957416Smarkm	case TELOPT_ENCRYPT:
46057416Smarkm	    fprintf(NetTrace, "ENCRYPT");
46157416Smarkm	    if (length < 2) {
46257416Smarkm		fprintf(NetTrace, " (empty suboption?)");
46357416Smarkm		break;
46457416Smarkm	    }
46557416Smarkm	    switch (pointer[1]) {
46657416Smarkm	    case ENCRYPT_START:
46757416Smarkm		fprintf(NetTrace, " START");
46857416Smarkm		break;
46957416Smarkm
47057416Smarkm	    case ENCRYPT_END:
47157416Smarkm		fprintf(NetTrace, " END");
47257416Smarkm		break;
47357416Smarkm
47457416Smarkm	    case ENCRYPT_REQSTART:
47557416Smarkm		fprintf(NetTrace, " REQUEST-START");
47657416Smarkm		break;
47757416Smarkm
47857416Smarkm	    case ENCRYPT_REQEND:
47957416Smarkm		fprintf(NetTrace, " REQUEST-END");
48057416Smarkm		break;
48157416Smarkm
48257416Smarkm	    case ENCRYPT_IS:
48357416Smarkm	    case ENCRYPT_REPLY:
48457416Smarkm		fprintf(NetTrace, " %s ", (pointer[1] == ENCRYPT_IS) ?
48557416Smarkm							"IS" : "REPLY");
48657416Smarkm		if (length < 3) {
48757416Smarkm		    fprintf(NetTrace, " (partial suboption?)");
48857416Smarkm		    break;
48957416Smarkm		}
49057416Smarkm		if (ENCTYPE_NAME_OK(pointer[2]))
49157416Smarkm		    fprintf(NetTrace, "%s ", ENCTYPE_NAME(pointer[2]));
49257416Smarkm		else
49357416Smarkm		    fprintf(NetTrace, " %d (unknown)", pointer[2]);
49457416Smarkm
49557416Smarkm		encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf));
49657416Smarkm		fprintf(NetTrace, "%s", buf);
49757416Smarkm		break;
49857416Smarkm
49957416Smarkm	    case ENCRYPT_SUPPORT:
50057416Smarkm		i = 2;
50157416Smarkm		fprintf(NetTrace, " SUPPORT ");
50257416Smarkm		while (i < length) {
50357416Smarkm		    if (ENCTYPE_NAME_OK(pointer[i]))
50457416Smarkm			fprintf(NetTrace, "%s ", ENCTYPE_NAME(pointer[i]));
50557416Smarkm		    else
50657416Smarkm			fprintf(NetTrace, "%d ", pointer[i]);
50757416Smarkm		    i++;
50857416Smarkm		}
50957416Smarkm		break;
51057416Smarkm
51157416Smarkm	    case ENCRYPT_ENC_KEYID:
51257416Smarkm		fprintf(NetTrace, " ENC_KEYID ");
51357416Smarkm		goto encommon;
51457416Smarkm
51557416Smarkm	    case ENCRYPT_DEC_KEYID:
51657416Smarkm		fprintf(NetTrace, " DEC_KEYID ");
51757416Smarkm		goto encommon;
51857416Smarkm
51957416Smarkm	    default:
52057416Smarkm		fprintf(NetTrace, " %d (unknown)", pointer[1]);
52157416Smarkm	    encommon:
52257416Smarkm		for (i = 2; i < length; i++)
52357416Smarkm		    fprintf(NetTrace, " %d", pointer[i]);
52457416Smarkm		break;
52557416Smarkm	    }
52657416Smarkm	    break;
52757416Smarkm#endif
52857416Smarkm
52957416Smarkm	case TELOPT_LINEMODE:
53057416Smarkm	    fprintf(NetTrace, "LINEMODE ");
53157416Smarkm	    if (length < 2) {
53257416Smarkm		fprintf(NetTrace, " (empty suboption??\?)");
53357416Smarkm		break;
53457416Smarkm	    }
53557416Smarkm	    switch (pointer[1]) {
53657416Smarkm	    case WILL:
53757416Smarkm		fprintf(NetTrace, "WILL ");
53857416Smarkm		goto common;
53957416Smarkm	    case WONT:
54057416Smarkm		fprintf(NetTrace, "WONT ");
54157416Smarkm		goto common;
54257416Smarkm	    case DO:
54357416Smarkm		fprintf(NetTrace, "DO ");
54457416Smarkm		goto common;
54557416Smarkm	    case DONT:
54657416Smarkm		fprintf(NetTrace, "DONT ");
54757416Smarkm	    common:
54857416Smarkm		if (length < 3) {
54957416Smarkm		    fprintf(NetTrace, "(no option??\?)");
55057416Smarkm		    break;
55157416Smarkm		}
55257416Smarkm		switch (pointer[2]) {
55357416Smarkm		case LM_FORWARDMASK:
55457416Smarkm		    fprintf(NetTrace, "Forward Mask");
55557416Smarkm		    for (i = 3; i < length; i++)
55657416Smarkm			fprintf(NetTrace, " %x", pointer[i]);
55757416Smarkm		    break;
55857416Smarkm		default:
55957416Smarkm		    fprintf(NetTrace, "%d (unknown)", pointer[2]);
56057416Smarkm		    for (i = 3; i < length; i++)
56157416Smarkm			fprintf(NetTrace, " %d", pointer[i]);
56257416Smarkm		    break;
56357416Smarkm		}
56457416Smarkm		break;
56557416Smarkm
56657416Smarkm	    case LM_SLC:
56757416Smarkm		fprintf(NetTrace, "SLC");
56857416Smarkm		for (i = 2; i < length - 2; i += 3) {
56957416Smarkm		    if (SLC_NAME_OK(pointer[i+SLC_FUNC]))
57057416Smarkm			fprintf(NetTrace, " %s", SLC_NAME(pointer[i+SLC_FUNC]));
57157416Smarkm		    else
57257416Smarkm			fprintf(NetTrace, " %d", pointer[i+SLC_FUNC]);
57357416Smarkm		    switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) {
57457416Smarkm		    case SLC_NOSUPPORT:
57557416Smarkm			fprintf(NetTrace, " NOSUPPORT"); break;
57657416Smarkm		    case SLC_CANTCHANGE:
57757416Smarkm			fprintf(NetTrace, " CANTCHANGE"); break;
57857416Smarkm		    case SLC_VARIABLE:
57957416Smarkm			fprintf(NetTrace, " VARIABLE"); break;
58057416Smarkm		    case SLC_DEFAULT:
58157416Smarkm			fprintf(NetTrace, " DEFAULT"); break;
58257416Smarkm		    }
58357416Smarkm		    fprintf(NetTrace, "%s%s%s",
58457416Smarkm			pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "",
58557416Smarkm			pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "",
58657416Smarkm			pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : "");
58757416Smarkm		    if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN|
58857416Smarkm						SLC_FLUSHOUT| SLC_LEVELBITS))
58957416Smarkm			fprintf(NetTrace, "(0x%x)", pointer[i+SLC_FLAGS]);
59057416Smarkm		    fprintf(NetTrace, " %d;", pointer[i+SLC_VALUE]);
59157416Smarkm		    if ((pointer[i+SLC_VALUE] == IAC) &&
59257416Smarkm			(pointer[i+SLC_VALUE+1] == IAC))
59357416Smarkm				i++;
59457416Smarkm		}
59557416Smarkm		for (; i < length; i++)
59657416Smarkm		    fprintf(NetTrace, " ?%d?", pointer[i]);
59757416Smarkm		break;
59857416Smarkm
59957416Smarkm	    case LM_MODE:
60057416Smarkm		fprintf(NetTrace, "MODE ");
60157416Smarkm		if (length < 3) {
60257416Smarkm		    fprintf(NetTrace, "(no mode??\?)");
60357416Smarkm		    break;
60457416Smarkm		}
60557416Smarkm		{
60657416Smarkm		    char tbuf[64];
60757416Smarkm		    snprintf(tbuf, sizeof(tbuf),
60857416Smarkm			     "%s%s%s%s%s",
60957416Smarkm			     pointer[2]&MODE_EDIT ? "|EDIT" : "",
61057416Smarkm			     pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "",
61157416Smarkm			     pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "",
61257416Smarkm			     pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "",
61357416Smarkm			     pointer[2]&MODE_ACK ? "|ACK" : "");
61457416Smarkm		    fprintf(NetTrace, "%s", tbuf[1] ? &tbuf[1] : "0");
61557416Smarkm		}
61657416Smarkm		if (pointer[2]&~(MODE_MASK))
61757416Smarkm		    fprintf(NetTrace, " (0x%x)", pointer[2]);
61857416Smarkm		for (i = 3; i < length; i++)
61957416Smarkm		    fprintf(NetTrace, " ?0x%x?", pointer[i]);
62057416Smarkm		break;
62157416Smarkm	    default:
62257416Smarkm		fprintf(NetTrace, "%d (unknown)", pointer[1]);
62357416Smarkm		for (i = 2; i < length; i++)
62457416Smarkm		    fprintf(NetTrace, " %d", pointer[i]);
62557416Smarkm	    }
62657416Smarkm	    break;
62757416Smarkm
62857416Smarkm	case TELOPT_STATUS: {
62957416Smarkm	    char *cp;
63057416Smarkm	    int j, k;
63157416Smarkm
63257416Smarkm	    fprintf(NetTrace, "STATUS");
63357416Smarkm
63457416Smarkm	    switch (pointer[1]) {
63557416Smarkm	    default:
63657416Smarkm		if (pointer[1] == TELQUAL_SEND)
63757416Smarkm		    fprintf(NetTrace, " SEND");
63857416Smarkm		else
63957416Smarkm		    fprintf(NetTrace, " %d (unknown)", pointer[1]);
64057416Smarkm		for (i = 2; i < length; i++)
64157416Smarkm		    fprintf(NetTrace, " ?%d?", pointer[i]);
64257416Smarkm		break;
64357416Smarkm	    case TELQUAL_IS:
64457416Smarkm		if (--want_status_response < 0)
64557416Smarkm		    want_status_response = 0;
64657416Smarkm		if (NetTrace == stdout)
64757416Smarkm		    fprintf(NetTrace, " IS\r\n");
64857416Smarkm		else
64957416Smarkm		    fprintf(NetTrace, " IS\n");
65057416Smarkm
65157416Smarkm		for (i = 2; i < length; i++) {
65257416Smarkm		    switch(pointer[i]) {
65357416Smarkm		    case DO:	cp = "DO"; goto common2;
65457416Smarkm		    case DONT:	cp = "DONT"; goto common2;
65557416Smarkm		    case WILL:	cp = "WILL"; goto common2;
65657416Smarkm		    case WONT:	cp = "WONT"; goto common2;
65757416Smarkm		    common2:
65857416Smarkm			i++;
65957416Smarkm			if (TELOPT_OK((int)pointer[i]))
66057416Smarkm			    fprintf(NetTrace, " %s %s", cp, TELOPT(pointer[i]));
66157416Smarkm			else
66257416Smarkm			    fprintf(NetTrace, " %s %d", cp, pointer[i]);
66357416Smarkm
66457416Smarkm			if (NetTrace == stdout)
66557416Smarkm			    fprintf(NetTrace, "\r\n");
66657416Smarkm			else
66757416Smarkm			    fprintf(NetTrace, "\n");
66857416Smarkm			break;
66957416Smarkm
67057416Smarkm		    case SB:
67157416Smarkm			fprintf(NetTrace, " SB ");
67257416Smarkm			i++;
67357416Smarkm			j = k = i;
67457416Smarkm			while (j < length) {
67557416Smarkm			    if (pointer[j] == SE) {
67657416Smarkm				if (j+1 == length)
67757416Smarkm				    break;
67857416Smarkm				if (pointer[j+1] == SE)
67957416Smarkm				    j++;
68057416Smarkm				else
68157416Smarkm				    break;
68257416Smarkm			    }
68357416Smarkm			    pointer[k++] = pointer[j++];
68457416Smarkm			}
68557416Smarkm			printsub(0, &pointer[i], k - i);
68657416Smarkm			if (i < length) {
68757416Smarkm			    fprintf(NetTrace, " SE");
68857416Smarkm			    i = j;
68957416Smarkm			} else
69057416Smarkm			    i = j - 1;
69157416Smarkm
69257416Smarkm			if (NetTrace == stdout)
69357416Smarkm			    fprintf(NetTrace, "\r\n");
69457416Smarkm			else
69557416Smarkm			    fprintf(NetTrace, "\n");
69657416Smarkm
69757416Smarkm			break;
69857416Smarkm
69957416Smarkm		    default:
70057416Smarkm			fprintf(NetTrace, " %d", pointer[i]);
70157416Smarkm			break;
70257416Smarkm		    }
70357416Smarkm		}
70457416Smarkm		break;
70557416Smarkm	    }
70657416Smarkm	    break;
70757416Smarkm	  }
70857416Smarkm
70957416Smarkm	case TELOPT_XDISPLOC:
71057416Smarkm	    fprintf(NetTrace, "X-DISPLAY-LOCATION ");
71157416Smarkm	    switch (pointer[1]) {
71257416Smarkm	    case TELQUAL_IS:
713233294Sstas		fprintf(NetTrace, "IS \"%.*s\"", (int)(length-2), (char *)pointer+2);
71457416Smarkm		break;
71557416Smarkm	    case TELQUAL_SEND:
71657416Smarkm		fprintf(NetTrace, "SEND");
71757416Smarkm		break;
71857416Smarkm	    default:
71957416Smarkm		fprintf(NetTrace, "- unknown qualifier %d (0x%x).",
72057416Smarkm				pointer[1], pointer[1]);
72157416Smarkm	    }
72257416Smarkm	    break;
72357416Smarkm
72457416Smarkm	case TELOPT_NEW_ENVIRON:
72557416Smarkm	    fprintf(NetTrace, "NEW-ENVIRON ");
72657416Smarkm#ifdef	OLD_ENVIRON
72757416Smarkm	    goto env_common1;
72857416Smarkm	case TELOPT_OLD_ENVIRON:
72957416Smarkm	    fprintf(NetTrace, "OLD-ENVIRON");
73057416Smarkm	env_common1:
73157416Smarkm#endif
73257416Smarkm	    switch (pointer[1]) {
73357416Smarkm	    case TELQUAL_IS:
73457416Smarkm		fprintf(NetTrace, "IS ");
73557416Smarkm		goto env_common;
73657416Smarkm	    case TELQUAL_SEND:
73757416Smarkm		fprintf(NetTrace, "SEND ");
73857416Smarkm		goto env_common;
73957416Smarkm	    case TELQUAL_INFO:
74057416Smarkm		fprintf(NetTrace, "INFO ");
74157416Smarkm	    env_common:
74257416Smarkm		{
743233294Sstas		    int quote = 0;
74457416Smarkm		    for (i = 2; i < length; i++ ) {
74557416Smarkm			switch (pointer[i]) {
746233294Sstas			case NEW_ENV_VAR:
747233294Sstas			    qprintf(quote, NetTrace, "VAR ");
748233294Sstas			    quote = 0;
74957416Smarkm			    break;
75057416Smarkm
751233294Sstas			case NEW_ENV_VALUE:
752233294Sstas			    qprintf(quote, NetTrace, "VALUE");
753233294Sstas			    quote = 0;
75457416Smarkm			    break;
75557416Smarkm
75657416Smarkm			case ENV_ESC:
757233294Sstas			    qprintf(quote, NetTrace, "ESC ");
758233294Sstas			    quote = 0;
75957416Smarkm			    break;
76057416Smarkm
76157416Smarkm			case ENV_USERVAR:
762233294Sstas			    qprintf(quote, NetTrace, "USERVAR ");
763233294Sstas			    quote = 0;
76457416Smarkm			    break;
76557416Smarkm
76657416Smarkm			default:
76757416Smarkm			    if (isprint(pointer[i]) && pointer[i] != '"') {
768233294Sstas				if (!quote) {
76957416Smarkm				    putc('"', NetTrace);
770233294Sstas				    quote = 1;
77157416Smarkm				}
77257416Smarkm				putc(pointer[i], NetTrace);
77357416Smarkm			    } else {
774233294Sstas				qprintf(quote, NetTrace, "%03o ", pointer[i]);
775233294Sstas				quote = 0;
77657416Smarkm			    }
77757416Smarkm			    break;
77857416Smarkm			}
77957416Smarkm		    }
780233294Sstas		    if (quote)
78157416Smarkm			putc('"', NetTrace);
78257416Smarkm		    break;
78357416Smarkm		}
78457416Smarkm	    }
78557416Smarkm	    break;
78657416Smarkm
78757416Smarkm	default:
78857416Smarkm	    if (TELOPT_OK(pointer[0]))
78957416Smarkm		fprintf(NetTrace, "%s (unknown)", TELOPT(pointer[0]));
79057416Smarkm	    else
79157416Smarkm		fprintf(NetTrace, "%d (unknown)", pointer[0]);
79257416Smarkm	    for (i = 1; i < length; i++)
79357416Smarkm		fprintf(NetTrace, " %d", pointer[i]);
79457416Smarkm	    break;
79557416Smarkm	}
79657416Smarkm	if (direction) {
79757416Smarkm	    if (NetTrace == stdout)
79857416Smarkm		fprintf(NetTrace, "\r\n");
79957416Smarkm	    else
80057416Smarkm		fprintf(NetTrace, "\n");
80157416Smarkm	}
80257416Smarkm	if (NetTrace == stdout)
80357416Smarkm	    fflush(NetTrace);
80457416Smarkm    }
80557416Smarkm}
80657416Smarkm
80757416Smarkm/* EmptyTerminal - called to make sure that the terminal buffer is empty.
80857416Smarkm *			Note that we consider the buffer to run all the
80957416Smarkm *			way to the kernel (thus the select).
81057416Smarkm */
81157416Smarkm
81257416Smarkmvoid
81357416SmarkmEmptyTerminal(void)
81457416Smarkm{
81557416Smarkm    fd_set	outs;
81657416Smarkm
81757416Smarkm    FD_ZERO(&outs);
81857416Smarkm
81972445Sassar    if (tout >= FD_SETSIZE)
82072445Sassar	ExitString("fd too large", 1);
82172445Sassar
82257416Smarkm    if (TTYBYTES() == 0) {
82357416Smarkm	FD_SET(tout, &outs);
82457416Smarkm	select(tout+1, 0, &outs, 0,
82557416Smarkm		      (struct timeval *) 0); /* wait for TTLOWAT */
82657416Smarkm    } else {
82757416Smarkm	while (TTYBYTES()) {
82857416Smarkm	    ttyflush(0);
82957416Smarkm	    FD_SET(tout, &outs);
83057416Smarkm	    select(tout+1, 0, &outs, 0,
83157416Smarkm			  (struct timeval *) 0); /* wait for TTLOWAT */
83257416Smarkm	}
83357416Smarkm    }
83457416Smarkm}
83557416Smarkm
83657416Smarkmvoid
83757416SmarkmSetForExit(void)
83857416Smarkm{
83957416Smarkm    setconnmode(0);
84057416Smarkm    do {
84157416Smarkm	telrcv();			/* Process any incoming data */
84257416Smarkm	EmptyTerminal();
84357416Smarkm    } while (ring_full_count(&netiring));	/* While there is any */
84457416Smarkm    setcommandmode();
84557416Smarkm    fflush(stdout);
84657416Smarkm    fflush(stderr);
84757416Smarkm    setconnmode(0);
84857416Smarkm    EmptyTerminal();			/* Flush the path to the tty */
84957416Smarkm    setcommandmode();
85057416Smarkm}
85157416Smarkm
85257416Smarkmvoid
85357416SmarkmExit(int returnCode)
85457416Smarkm{
85557416Smarkm    SetForExit();
85657416Smarkm    exit(returnCode);
85757416Smarkm}
85857416Smarkm
85957416Smarkmvoid
86057416SmarkmExitString(char *string, int returnCode)
86157416Smarkm{
86257416Smarkm    SetForExit();
86357416Smarkm    fwrite(string, 1, strlen(string), stderr);
86457416Smarkm    exit(returnCode);
86557416Smarkm}
866