xref: /csrg-svn/usr.bin/telnet/utilities.c (revision 62313)
133686Sbostic /*
2*62313Sbostic  * Copyright (c) 1988, 1993
3*62313Sbostic  *	The Regents of the University of California.  All rights reserved.
433686Sbostic  *
544361Sborman  * %sccs.include.redist.c%
633686Sbostic  */
733686Sbostic 
833686Sbostic #ifndef lint
9*62313Sbostic static char sccsid[] = "@(#)utilities.c	8.1 (Berkeley) 06/06/93";
1033686Sbostic #endif /* not lint */
1133686Sbostic 
1232149Sminshall #define	TELOPTS
1338690Sborman #define	TELCMDS
1446808Sdab #define	SLC_NAMES
1532149Sminshall #include <arpa/telnet.h>
1632381Sminshall #include <sys/types.h>
1744361Sborman #include <sys/time.h>
1832149Sminshall 
1932149Sminshall #include <ctype.h>
2032149Sminshall 
2134305Sminshall #include "general.h"
2234305Sminshall 
2336280Sminshall #include "fdset.h"
2436280Sminshall 
2532381Sminshall #include "ring.h"
2632381Sminshall 
2736278Sminshall #include "defines.h"
2836278Sminshall 
2932149Sminshall #include "externs.h"
3032149Sminshall 
3132149Sminshall FILE	*NetTrace = 0;		/* Not in bss, since needs to stay */
3238690Sborman int	prettydump;
3332149Sminshall 
3432149Sminshall /*
3532149Sminshall  * upcase()
3632149Sminshall  *
3732149Sminshall  *	Upcase (in place) the argument.
3832149Sminshall  */
3932149Sminshall 
4046808Sdab     void
4132149Sminshall upcase(argument)
4246808Sdab     register char *argument;
4332149Sminshall {
4432149Sminshall     register int c;
4532149Sminshall 
4632149Sminshall     while ((c = *argument) != 0) {
4732149Sminshall 	if (islower(c)) {
4832149Sminshall 	    *argument = toupper(c);
4932149Sminshall 	}
5032149Sminshall 	argument++;
5132149Sminshall     }
5232149Sminshall }
5332149Sminshall 
5432149Sminshall /*
5532149Sminshall  * SetSockOpt()
5632149Sminshall  *
5732149Sminshall  * Compensate for differences in 4.2 and 4.3 systems.
5832149Sminshall  */
5932149Sminshall 
6046808Sdab     int
6132149Sminshall SetSockOpt(fd, level, option, yesno)
6246808Sdab     int fd, level, option, yesno;
6332149Sminshall {
6432149Sminshall #ifndef	NOT43
6532149Sminshall     return setsockopt(fd, level, option,
6632149Sminshall 				(char *)&yesno, sizeof yesno);
6732149Sminshall #else	/* NOT43 */
6832149Sminshall     if (yesno == 0) {		/* Can't do that in 4.2! */
6932149Sminshall 	fprintf(stderr, "Error: attempt to turn off an option 0x%x.\n",
7032149Sminshall 				option);
7132149Sminshall 	return -1;
7232149Sminshall     }
7332149Sminshall     return setsockopt(fd, level, option, 0, 0);
7432149Sminshall #endif	/* NOT43 */
7532149Sminshall }
7632149Sminshall 
7732149Sminshall /*
7832149Sminshall  * The following are routines used to print out debugging information.
7932149Sminshall  */
8032149Sminshall 
8139529Sborman unsigned char NetTraceFile[256] = "(standard output)";
8232149Sminshall 
8346808Sdab     void
8438690Sborman SetNetTrace(file)
8546808Sdab     register char *file;
8638690Sborman {
8738690Sborman     if (NetTrace && NetTrace != stdout)
8838690Sborman 	fclose(NetTrace);
8938690Sborman     if (file  && (strcmp(file, "-") != 0)) {
9038690Sborman 	NetTrace = fopen(file, "w");
9138690Sborman 	if (NetTrace) {
9246808Sdab 	    strcpy((char *)NetTraceFile, file);
9338690Sborman 	    return;
9438690Sborman 	}
9538690Sborman 	fprintf(stderr, "Cannot open %s.\n", file);
9638690Sborman     }
9738690Sborman     NetTrace = stdout;
9846808Sdab     strcpy((char *)NetTraceFile, "(standard output)");
9938690Sborman }
10038690Sborman 
10146808Sdab     void
10232149Sminshall Dump(direction, buffer, length)
10346808Sdab     char direction;
10446808Sdab     unsigned char *buffer;
10546808Sdab     int length;
10632149Sminshall {
10732149Sminshall #   define BYTES_PER_LINE	32
10832149Sminshall #   define min(x,y)	((x<y)? x:y)
10946808Sdab     unsigned char *pThis;
11032149Sminshall     int offset;
11138690Sborman     extern pettydump;
11232149Sminshall 
11332149Sminshall     offset = 0;
11432149Sminshall 
11532149Sminshall     while (length) {
11632149Sminshall 	/* print one line */
11732149Sminshall 	fprintf(NetTrace, "%c 0x%x\t", direction, offset);
11832149Sminshall 	pThis = buffer;
11938690Sborman 	if (prettydump) {
12038909Sborman 	    buffer = buffer + min(length, BYTES_PER_LINE/2);
12138690Sborman 	    while (pThis < buffer) {
12238690Sborman 		fprintf(NetTrace, "%c%.2x",
12338690Sborman 		    (((*pThis)&0xff) == 0xff) ? '*' : ' ',
12438690Sborman 		    (*pThis)&0xff);
12538690Sborman 		pThis++;
12638690Sborman 	    }
12738909Sborman 	    length -= BYTES_PER_LINE/2;
12838909Sborman 	    offset += BYTES_PER_LINE/2;
12938690Sborman 	} else {
13038909Sborman 	    buffer = buffer + min(length, BYTES_PER_LINE);
13138690Sborman 	    while (pThis < buffer) {
13238690Sborman 		fprintf(NetTrace, "%.2x", (*pThis)&0xff);
13338690Sborman 		pThis++;
13438690Sborman 	    }
13538909Sborman 	    length -= BYTES_PER_LINE;
13638909Sborman 	    offset += BYTES_PER_LINE;
13732149Sminshall 	}
13837226Sminshall 	if (NetTrace == stdout) {
13938207Sminshall 	    fprintf(NetTrace, "\r\n");
14038207Sminshall 	} else {
14137226Sminshall 	    fprintf(NetTrace, "\n");
14237226Sminshall 	}
14332149Sminshall 	if (length < 0) {
14436693Sminshall 	    fflush(NetTrace);
14532149Sminshall 	    return;
14632149Sminshall 	}
14732149Sminshall 	/* find next unique line */
14832149Sminshall     }
14936693Sminshall     fflush(NetTrace);
15032149Sminshall }
15132149Sminshall 
15232149Sminshall 
15346808Sdab 	void
15446808Sdab printoption(direction, cmd, option)
15546808Sdab 	char *direction;
15646808Sdab 	int cmd, option;
15732149Sminshall {
15832149Sminshall 	if (!showoptions)
15932149Sminshall 		return;
16046808Sdab 	if (cmd == IAC) {
16146808Sdab 		if (TELCMD_OK(option))
16246808Sdab 		    fprintf(NetTrace, "%s IAC %s", direction, TELCMD(option));
16346808Sdab 		else
16446808Sdab 		    fprintf(NetTrace, "%s IAC %d", direction, option);
16546808Sdab 	} else {
16646808Sdab 		register char *fmt;
16746808Sdab 		fmt = (cmd == WILL) ? "WILL" : (cmd == WONT) ? "WONT" :
16846808Sdab 			(cmd == DO) ? "DO" : (cmd == DONT) ? "DONT" : 0;
16946808Sdab 		if (fmt) {
17046808Sdab 		    fprintf(NetTrace, "%s %s ", direction, fmt);
17146808Sdab 		    if (TELOPT_OK(option))
17246808Sdab 			fprintf(NetTrace, "%s", TELOPT(option));
17346808Sdab 		    else if (option == TELOPT_EXOPL)
17446808Sdab 			fprintf(NetTrace, "EXOPL");
17546808Sdab 		    else
17646808Sdab 			fprintf(NetTrace, "%d", option);
17746808Sdab 		} else
17846808Sdab 		    fprintf(NetTrace, "%s %d %d", direction, cmd, option);
17946808Sdab 	}
18038690Sborman 	if (NetTrace == stdout)
18137226Sminshall 	    fprintf(NetTrace, "\r\n");
18238690Sborman 	else
18337226Sminshall 	    fprintf(NetTrace, "\n");
18437226Sminshall 	return;
18532149Sminshall }
18632149Sminshall 
18746808Sdab     void
18838690Sborman optionstatus()
18938690Sborman {
19038690Sborman     register int i;
19138690Sborman     extern char will_wont_resp[], do_dont_resp[];
19238690Sborman 
19338690Sborman     for (i = 0; i < 256; i++) {
19438690Sborman 	if (do_dont_resp[i]) {
19538690Sborman 	    if (TELOPT_OK(i))
19638690Sborman 		printf("resp DO_DONT %s: %d\n", TELOPT(i), do_dont_resp[i]);
19738690Sborman 	    else if (TELCMD_OK(i))
19838690Sborman 		printf("resp DO_DONT %s: %d\n", TELCMD(i), do_dont_resp[i]);
19938690Sborman 	    else
20038690Sborman 		printf("resp DO_DONT %d: %d\n", i,
20138690Sborman 				do_dont_resp[i]);
20238690Sborman 	    if (my_want_state_is_do(i)) {
20338690Sborman 		if (TELOPT_OK(i))
20438690Sborman 		    printf("want DO   %s\n", TELOPT(i));
20538690Sborman 		else if (TELCMD_OK(i))
20638690Sborman 		    printf("want DO   %s\n", TELCMD(i));
20738690Sborman 		else
20838690Sborman 		    printf("want DO   %d\n", i);
20938690Sborman 	    } else {
21038690Sborman 		if (TELOPT_OK(i))
21138690Sborman 		    printf("want DONT %s\n", TELOPT(i));
21238690Sborman 		else if (TELCMD_OK(i))
21338690Sborman 		    printf("want DONT %s\n", TELCMD(i));
21438690Sborman 		else
21538690Sborman 		    printf("want DONT %d\n", i);
21638690Sborman 	    }
21738690Sborman 	} else {
21838690Sborman 	    if (my_state_is_do(i)) {
21938690Sborman 		if (TELOPT_OK(i))
22038690Sborman 		    printf("     DO   %s\n", TELOPT(i));
22138690Sborman 		else if (TELCMD_OK(i))
22238690Sborman 		    printf("     DO   %s\n", TELCMD(i));
22338690Sborman 		else
22438690Sborman 		    printf("     DO   %d\n", i);
22538690Sborman 	    }
22638690Sborman 	}
22738690Sborman 	if (will_wont_resp[i]) {
22838690Sborman 	    if (TELOPT_OK(i))
22938690Sborman 		printf("resp WILL_WONT %s: %d\n", TELOPT(i), will_wont_resp[i]);
23038690Sborman 	    else if (TELCMD_OK(i))
23138690Sborman 		printf("resp WILL_WONT %s: %d\n", TELCMD(i), will_wont_resp[i]);
23238690Sborman 	    else
23338690Sborman 		printf("resp WILL_WONT %d: %d\n",
23438690Sborman 				i, will_wont_resp[i]);
23538690Sborman 	    if (my_want_state_is_will(i)) {
23638690Sborman 		if (TELOPT_OK(i))
23738690Sborman 		    printf("want WILL %s\n", TELOPT(i));
23838690Sborman 		else if (TELCMD_OK(i))
23938690Sborman 		    printf("want WILL %s\n", TELCMD(i));
24038690Sborman 		else
24138690Sborman 		    printf("want WILL %d\n", i);
24238690Sborman 	    } else {
24338690Sborman 		if (TELOPT_OK(i))
24438690Sborman 		    printf("want WONT %s\n", TELOPT(i));
24538690Sborman 		else if (TELCMD_OK(i))
24638690Sborman 		    printf("want WONT %s\n", TELCMD(i));
24738690Sborman 		else
24838690Sborman 		    printf("want WONT %d\n", i);
24938690Sborman 	    }
25038690Sborman 	} else {
25138690Sborman 	    if (my_state_is_will(i)) {
25238690Sborman 		if (TELOPT_OK(i))
25338690Sborman 		    printf("     WILL %s\n", TELOPT(i));
25438690Sborman 		else if (TELCMD_OK(i))
25538690Sborman 		    printf("     WILL %s\n", TELCMD(i));
25638690Sborman 		else
25738690Sborman 		    printf("     WILL %d\n", i);
25838690Sborman 	    }
25938690Sborman 	}
26038690Sborman     }
26138690Sborman 
26238690Sborman }
26338690Sborman 
26446808Sdab     void
26532149Sminshall printsub(direction, pointer, length)
26646808Sdab     char direction;	/* '<' or '>' */
26746808Sdab     unsigned char *pointer;	/* where suboption data sits */
26846808Sdab     int		  length;	/* length of suboption data */
26932149Sminshall {
27038690Sborman     register int i;
27147608Sdab     char buf[512];
27246808Sdab     extern int want_status_response;
27338690Sborman 
27446808Sdab     if (showoptions || direction == 0 ||
27546808Sdab 	(want_status_response && (pointer[0] == TELOPT_STATUS))) {
27638909Sborman 	if (direction) {
27746808Sdab 	    fprintf(NetTrace, "%s IAC SB ",
27846808Sdab 				(direction == '<')? "RCVD":"SENT");
27938909Sborman 	    if (length >= 3) {
28038909Sborman 		register int j;
28138690Sborman 
28238909Sborman 		i = pointer[length-2];
28338909Sborman 		j = pointer[length-1];
28438690Sborman 
28538909Sborman 		if (i != IAC || j != SE) {
28638909Sborman 		    fprintf(NetTrace, "(terminated by ");
28738909Sborman 		    if (TELOPT_OK(i))
28838909Sborman 			fprintf(NetTrace, "%s ", TELOPT(i));
28938909Sborman 		    else if (TELCMD_OK(i))
29038909Sborman 			fprintf(NetTrace, "%s ", TELCMD(i));
29138909Sborman 		    else
29238909Sborman 			fprintf(NetTrace, "%d ", i);
29338909Sborman 		    if (TELOPT_OK(j))
29438909Sborman 			fprintf(NetTrace, "%s", TELOPT(j));
29538909Sborman 		    else if (TELCMD_OK(j))
29638909Sborman 			fprintf(NetTrace, "%s", TELCMD(j));
29738909Sborman 		    else
29838909Sborman 			fprintf(NetTrace, "%d", j);
29938909Sborman 		    fprintf(NetTrace, ", not IAC SE!) ");
30038909Sborman 		}
30138690Sborman 	    }
30238909Sborman 	    length -= 2;
30338690Sborman 	}
30438690Sborman 	if (length < 1) {
30538690Sborman 	    fprintf(NetTrace, "(Empty suboption???)");
30638690Sborman 	    return;
30738690Sborman 	}
30832149Sminshall 	switch (pointer[0]) {
30932149Sminshall 	case TELOPT_TTYPE:
31038690Sborman 	    fprintf(NetTrace, "TERMINAL-TYPE ");
31132149Sminshall 	    switch (pointer[1]) {
31232149Sminshall 	    case TELQUAL_IS:
31344361Sborman 		fprintf(NetTrace, "IS \"%.*s\"", length-2, (char *)pointer+2);
31432149Sminshall 		break;
31532149Sminshall 	    case TELQUAL_SEND:
31638690Sborman 		fprintf(NetTrace, "SEND");
31732149Sminshall 		break;
31832149Sminshall 	    default:
31932149Sminshall 		fprintf(NetTrace,
32038690Sborman 				"- unknown qualifier %d (0x%x).",
32134849Sminshall 				pointer[1], pointer[1]);
32232149Sminshall 	    }
32332149Sminshall 	    break;
32438690Sborman 	case TELOPT_TSPEED:
32538690Sborman 	    fprintf(NetTrace, "TERMINAL-SPEED");
32638690Sborman 	    if (length < 2) {
32738690Sborman 		fprintf(NetTrace, " (empty suboption???)");
32838690Sborman 		break;
32938690Sborman 	    }
33038690Sborman 	    switch (pointer[1]) {
33138909Sborman 	    case TELQUAL_IS:
33238690Sborman 		fprintf(NetTrace, " IS ");
33344361Sborman 		fprintf(NetTrace, "%.*s", length-2, (char *)pointer+2);
33438690Sborman 		break;
33538690Sborman 	    default:
33638690Sborman 		if (pointer[1] == 1)
33738690Sborman 		    fprintf(NetTrace, " SEND");
33838690Sborman 		else
33944361Sborman 		    fprintf(NetTrace, " %d (unknown)", pointer[1]);
34038690Sborman 		for (i = 2; i < length; i++)
34138690Sborman 		    fprintf(NetTrace, " ?%d?", pointer[i]);
34238690Sborman 		break;
34338690Sborman 	    }
34438690Sborman 	    break;
34538690Sborman 
34638690Sborman 	case TELOPT_LFLOW:
34738690Sborman 	    fprintf(NetTrace, "TOGGLE-FLOW-CONTROL");
34838690Sborman 	    if (length < 2) {
34938690Sborman 		fprintf(NetTrace, " (empty suboption???)");
35038690Sborman 		break;
35138690Sborman 	    }
35238690Sborman 	    switch (pointer[1]) {
35357598Sdab 	    case LFLOW_OFF:
35438690Sborman 		fprintf(NetTrace, " OFF"); break;
35557598Sdab 	    case LFLOW_ON:
35638690Sborman 		fprintf(NetTrace, " ON"); break;
35757598Sdab 	    case LFLOW_RESTART_ANY:
35857598Sdab 		fprintf(NetTrace, " RESTART-ANY"); break;
35957598Sdab 	    case LFLOW_RESTART_XON:
36057598Sdab 		fprintf(NetTrace, " RESTART-XON"); break;
36138690Sborman 	    default:
36244361Sborman 		fprintf(NetTrace, " %d (unknown)", pointer[1]);
36338690Sborman 	    }
36438690Sborman 	    for (i = 2; i < length; i++)
36538690Sborman 		fprintf(NetTrace, " ?%d?", pointer[i]);
36638690Sborman 	    break;
36738690Sborman 
36838690Sborman 	case TELOPT_NAWS:
36938690Sborman 	    fprintf(NetTrace, "NAWS");
37038690Sborman 	    if (length < 2) {
37138690Sborman 		fprintf(NetTrace, " (empty suboption???)");
37238690Sborman 		break;
37338690Sborman 	    }
37438690Sborman 	    if (length == 2) {
37538690Sborman 		fprintf(NetTrace, " ?%d?", pointer[1]);
37638690Sborman 		break;
37738690Sborman 	    }
37838690Sborman 	    fprintf(NetTrace, " %d %d (%d)",
37938690Sborman 		pointer[1], pointer[2],
38044361Sborman 		(int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2])));
38138690Sborman 	    if (length == 4) {
38238690Sborman 		fprintf(NetTrace, " ?%d?", pointer[3]);
38338690Sborman 		break;
38438690Sborman 	    }
38538690Sborman 	    fprintf(NetTrace, " %d %d (%d)",
38638690Sborman 		pointer[3], pointer[4],
38744361Sborman 		(int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4])));
38838690Sborman 	    for (i = 5; i < length; i++)
38938690Sborman 		fprintf(NetTrace, " ?%d?", pointer[i]);
39038690Sborman 	    break;
39138690Sborman 
39257213Sdab #if	defined(AUTHENTICATION)
39343320Skfall 	case TELOPT_AUTHENTICATION:
39446808Sdab 	    fprintf(NetTrace, "AUTHENTICATION");
39546808Sdab 	    if (length < 2) {
39646808Sdab 		fprintf(NetTrace, " (empty suboption???)");
39746808Sdab 		break;
39846808Sdab 	    }
39943320Skfall 	    switch (pointer[1]) {
40046808Sdab 	    case TELQUAL_REPLY:
40143320Skfall 	    case TELQUAL_IS:
40246808Sdab 		fprintf(NetTrace, " %s ", (pointer[1] == TELQUAL_IS) ?
40346808Sdab 							"IS" : "REPLY");
40446808Sdab 		if (AUTHTYPE_NAME_OK(pointer[2]))
40546808Sdab 		    fprintf(NetTrace, "%s ", AUTHTYPE_NAME(pointer[2]));
40646808Sdab 		else
40746808Sdab 		    fprintf(NetTrace, "%d ", pointer[2]);
40846808Sdab 		if (length < 3) {
40946808Sdab 		    fprintf(NetTrace, "(partial suboption???)");
41046808Sdab 		    break;
41146808Sdab 		}
41246808Sdab 		fprintf(NetTrace, "%s|%s",
41347608Sdab 			((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
41446808Sdab 			"CLIENT" : "SERVER",
41547608Sdab 			((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
41646808Sdab 			"MUTUAL" : "ONE-WAY");
41743320Skfall 
41846808Sdab 		auth_printsub(&pointer[1], length - 1, buf, sizeof(buf));
41946808Sdab 		fprintf(NetTrace, "%s", buf);
42046808Sdab 		break;
42146808Sdab 
42246808Sdab 	    case TELQUAL_SEND:
42346808Sdab 		i = 2;
42446808Sdab 		fprintf(NetTrace, " SEND ");
42546808Sdab 		while (i < length) {
42646808Sdab 		    if (AUTHTYPE_NAME_OK(pointer[i]))
42746808Sdab 			fprintf(NetTrace, "%s ", AUTHTYPE_NAME(pointer[i]));
42846808Sdab 		    else
42946808Sdab 			fprintf(NetTrace, "%d ", pointer[i]);
43046808Sdab 		    if (++i >= length) {
43146808Sdab 			fprintf(NetTrace, "(partial suboption???)");
43243320Skfall 			break;
43346808Sdab 		    }
43446808Sdab 		    fprintf(NetTrace, "%s|%s ",
43547608Sdab 			((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
43646808Sdab 							"CLIENT" : "SERVER",
43747608Sdab 			((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
43846808Sdab 							"MUTUAL" : "ONE-WAY");
43946808Sdab 		    ++i;
44043320Skfall 		}
44146808Sdab 		break;
44243320Skfall 
44347608Sdab 	    case TELQUAL_NAME:
44447608Sdab 		i = 2;
44547608Sdab 		fprintf(NetTrace, " NAME \"");
44647608Sdab 		while (i < length)
44747608Sdab 		    putc(pointer[i++], NetTrace);
44847608Sdab 		putc('"', NetTrace);
44947608Sdab 		break;
45047608Sdab 
45146808Sdab 	    default:
45246808Sdab 		    for (i = 2; i < length; i++)
45346808Sdab 			fprintf(NetTrace, " ?%d?", pointer[i]);
45446808Sdab 		    break;
45543320Skfall 	    }
45646808Sdab 	    break;
45746808Sdab #endif
45846808Sdab 
45960149Sdab #ifdef	ENCRYPTION
46046808Sdab 	case TELOPT_ENCRYPT:
46146808Sdab 	    fprintf(NetTrace, "ENCRYPT");
46246808Sdab 	    if (length < 2) {
46346808Sdab 		fprintf(NetTrace, " (empty suboption???)");
46443320Skfall 		break;
46546808Sdab 	    }
46646808Sdab 	    switch (pointer[1]) {
46746808Sdab 	    case ENCRYPT_START:
46846808Sdab 		fprintf(NetTrace, " START");
46946808Sdab 		break;
47043320Skfall 
47146808Sdab 	    case ENCRYPT_END:
47246808Sdab 		fprintf(NetTrace, " END");
47346808Sdab 		break;
47446808Sdab 
47546808Sdab 	    case ENCRYPT_REQSTART:
47646808Sdab 		fprintf(NetTrace, " REQUEST-START");
47746808Sdab 		break;
47846808Sdab 
47946808Sdab 	    case ENCRYPT_REQEND:
48046808Sdab 		fprintf(NetTrace, " REQUEST-END");
48146808Sdab 		break;
48246808Sdab 
48346808Sdab 	    case ENCRYPT_IS:
48446808Sdab 	    case ENCRYPT_REPLY:
48546808Sdab 		fprintf(NetTrace, " %s ", (pointer[1] == ENCRYPT_IS) ?
48646808Sdab 							"IS" : "REPLY");
48746808Sdab 		if (length < 3) {
48846808Sdab 		    fprintf(NetTrace, " (partial suboption???)");
48946808Sdab 		    break;
49046808Sdab 		}
49146808Sdab 		if (ENCTYPE_NAME_OK(pointer[2]))
49246808Sdab 		    fprintf(NetTrace, "%s ", ENCTYPE_NAME(pointer[2]));
49346808Sdab 		else
49446808Sdab 		    fprintf(NetTrace, " %d (unknown)", pointer[2]);
49546808Sdab 
49646808Sdab 		encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf));
49746808Sdab 		fprintf(NetTrace, "%s", buf);
49846808Sdab 		break;
49946808Sdab 
50046808Sdab 	    case ENCRYPT_SUPPORT:
50146808Sdab 		i = 2;
50246808Sdab 		fprintf(NetTrace, " SUPPORT ");
50346808Sdab 		while (i < length) {
50446808Sdab 		    if (ENCTYPE_NAME_OK(pointer[i]))
50546808Sdab 			fprintf(NetTrace, "%s ", ENCTYPE_NAME(pointer[i]));
50646808Sdab 		    else
50746808Sdab 			fprintf(NetTrace, "%d ", pointer[i]);
50846808Sdab 		    i++;
50946808Sdab 		}
51046808Sdab 		break;
51146808Sdab 
51247608Sdab 	    case ENCRYPT_ENC_KEYID:
51347608Sdab 		fprintf(NetTrace, " ENC_KEYID ");
51447608Sdab 		goto encommon;
51547608Sdab 
51647608Sdab 	    case ENCRYPT_DEC_KEYID:
51747608Sdab 		fprintf(NetTrace, " DEC_KEYID ");
51847608Sdab 		goto encommon;
51947608Sdab 
52043320Skfall 	    default:
52147608Sdab 		fprintf(NetTrace, " %d (unknown)", pointer[1]);
52247608Sdab 	    encommon:
52346808Sdab 		for (i = 2; i < length; i++)
52446808Sdab 		    fprintf(NetTrace, " %d", pointer[i]);
52546808Sdab 		break;
52643320Skfall 	    }
52743320Skfall 	    break;
52860149Sdab #endif	/* ENCRYPTION */
52943320Skfall 
53038690Sborman 	case TELOPT_LINEMODE:
53138690Sborman 	    fprintf(NetTrace, "LINEMODE ");
53238690Sborman 	    if (length < 2) {
53338690Sborman 		fprintf(NetTrace, " (empty suboption???)");
53438690Sborman 		break;
53538690Sborman 	    }
53638690Sborman 	    switch (pointer[1]) {
53738690Sborman 	    case WILL:
53838690Sborman 		fprintf(NetTrace, "WILL ");
53938690Sborman 		goto common;
54038690Sborman 	    case WONT:
54138690Sborman 		fprintf(NetTrace, "WONT ");
54238690Sborman 		goto common;
54338690Sborman 	    case DO:
54438690Sborman 		fprintf(NetTrace, "DO ");
54538690Sborman 		goto common;
54638690Sborman 	    case DONT:
54738690Sborman 		fprintf(NetTrace, "DONT ");
54838690Sborman 	    common:
54938690Sborman 		if (length < 3) {
55038690Sborman 		    fprintf(NetTrace, "(no option???)");
55138690Sborman 		    break;
55238690Sborman 		}
55338690Sborman 		switch (pointer[2]) {
55438690Sborman 		case LM_FORWARDMASK:
55538690Sborman 		    fprintf(NetTrace, "Forward Mask");
55638690Sborman 		    for (i = 3; i < length; i++)
55738690Sborman 			fprintf(NetTrace, " %x", pointer[i]);
55838690Sborman 		    break;
55938690Sborman 		default:
56038690Sborman 		    fprintf(NetTrace, "%d (unknown)", pointer[2]);
56138690Sborman 		    for (i = 3; i < length; i++)
56238690Sborman 			fprintf(NetTrace, " %d", pointer[i]);
56338690Sborman 		    break;
56438690Sborman 		}
56538690Sborman 		break;
56638690Sborman 
56738690Sborman 	    case LM_SLC:
56838690Sborman 		fprintf(NetTrace, "SLC");
56938690Sborman 		for (i = 2; i < length - 2; i += 3) {
57046808Sdab 		    if (SLC_NAME_OK(pointer[i+SLC_FUNC]))
57146808Sdab 			fprintf(NetTrace, " %s", SLC_NAME(pointer[i+SLC_FUNC]));
57238690Sborman 		    else
57338690Sborman 			fprintf(NetTrace, " %d", pointer[i+SLC_FUNC]);
57438690Sborman 		    switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) {
57538690Sborman 		    case SLC_NOSUPPORT:
57638690Sborman 			fprintf(NetTrace, " NOSUPPORT"); break;
57738690Sborman 		    case SLC_CANTCHANGE:
57838690Sborman 			fprintf(NetTrace, " CANTCHANGE"); break;
57938690Sborman 		    case SLC_VARIABLE:
58038690Sborman 			fprintf(NetTrace, " VARIABLE"); break;
58138690Sborman 		    case SLC_DEFAULT:
58238690Sborman 			fprintf(NetTrace, " DEFAULT"); break;
58338690Sborman 		    }
58438690Sborman 		    fprintf(NetTrace, "%s%s%s",
58538690Sborman 			pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "",
58638690Sborman 			pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "",
58738690Sborman 			pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : "");
58838690Sborman 		    if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN|
58938690Sborman 						SLC_FLUSHOUT| SLC_LEVELBITS))
59038690Sborman 			fprintf(NetTrace, "(0x%x)", pointer[i+SLC_FLAGS]);
59138690Sborman 		    fprintf(NetTrace, " %d;", pointer[i+SLC_VALUE]);
59244361Sborman 		    if ((pointer[i+SLC_VALUE] == IAC) &&
59344361Sborman 			(pointer[i+SLC_VALUE+1] == IAC))
59444361Sborman 				i++;
59538690Sborman 		}
59638690Sborman 		for (; i < length; i++)
59738690Sborman 		    fprintf(NetTrace, " ?%d?", pointer[i]);
59838690Sborman 		break;
59938690Sborman 
60038690Sborman 	    case LM_MODE:
60138690Sborman 		fprintf(NetTrace, "MODE ");
60238690Sborman 		if (length < 3) {
60338690Sborman 		    fprintf(NetTrace, "(no mode???)");
60438690Sborman 		    break;
60538690Sborman 		}
60638690Sborman 		{
60744361Sborman 		    char tbuf[64];
60844361Sborman 		    sprintf(tbuf, "%s%s%s%s%s",
60938690Sborman 			pointer[2]&MODE_EDIT ? "|EDIT" : "",
61038690Sborman 			pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "",
61144361Sborman 			pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "",
61244361Sborman 			pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "",
61338690Sborman 			pointer[2]&MODE_ACK ? "|ACK" : "");
61438690Sborman 		    fprintf(NetTrace, "%s", tbuf[1] ? &tbuf[1] : "0");
61538690Sborman 		}
61646808Sdab 		if (pointer[2]&~(MODE_MASK))
61738690Sborman 		    fprintf(NetTrace, " (0x%x)", pointer[2]);
61838690Sborman 		for (i = 3; i < length; i++)
61938690Sborman 		    fprintf(NetTrace, " ?0x%x?", pointer[i]);
62038690Sborman 		break;
62138690Sborman 	    default:
62238690Sborman 		fprintf(NetTrace, "%d (unknown)", pointer[1]);
62338690Sborman 		for (i = 2; i < length; i++)
62438690Sborman 		    fprintf(NetTrace, " %d", pointer[i]);
62538690Sborman 	    }
62638690Sborman 	    break;
62738690Sborman 
62838909Sborman 	case TELOPT_STATUS: {
62938909Sborman 	    register char *cp;
63038909Sborman 	    register int j, k;
63138909Sborman 
63238909Sborman 	    fprintf(NetTrace, "STATUS");
63338909Sborman 
63438909Sborman 	    switch (pointer[1]) {
63538909Sborman 	    default:
63638909Sborman 		if (pointer[1] == TELQUAL_SEND)
63738909Sborman 		    fprintf(NetTrace, " SEND");
63838909Sborman 		else
63944361Sborman 		    fprintf(NetTrace, " %d (unknown)", pointer[1]);
64038909Sborman 		for (i = 2; i < length; i++)
64138909Sborman 		    fprintf(NetTrace, " ?%d?", pointer[i]);
64238909Sborman 		break;
64338909Sborman 	    case TELQUAL_IS:
64446808Sdab 		if (--want_status_response < 0)
64546808Sdab 		    want_status_response = 0;
64638909Sborman 		if (NetTrace == stdout)
64738909Sborman 		    fprintf(NetTrace, " IS\r\n");
64838909Sborman 		else
64938909Sborman 		    fprintf(NetTrace, " IS\n");
65038909Sborman 
65138909Sborman 		for (i = 2; i < length; i++) {
65238909Sborman 		    switch(pointer[i]) {
65338909Sborman 		    case DO:	cp = "DO"; goto common2;
65438909Sborman 		    case DONT:	cp = "DONT"; goto common2;
65538909Sborman 		    case WILL:	cp = "WILL"; goto common2;
65638909Sborman 		    case WONT:	cp = "WONT"; goto common2;
65738909Sborman 		    common2:
65838909Sborman 			i++;
65944361Sborman 			if (TELOPT_OK((int)pointer[i]))
66038909Sborman 			    fprintf(NetTrace, " %s %s", cp, TELOPT(pointer[i]));
66138909Sborman 			else
66238909Sborman 			    fprintf(NetTrace, " %s %d", cp, pointer[i]);
66338909Sborman 
66438909Sborman 			if (NetTrace == stdout)
66538909Sborman 			    fprintf(NetTrace, "\r\n");
66638909Sborman 			else
66738909Sborman 			    fprintf(NetTrace, "\n");
66838909Sborman 			break;
66938909Sborman 
67038909Sborman 		    case SB:
67138909Sborman 			fprintf(NetTrace, " SB ");
67238909Sborman 			i++;
67338909Sborman 			j = k = i;
67438909Sborman 			while (j < length) {
67538909Sborman 			    if (pointer[j] == SE) {
67638909Sborman 				if (j+1 == length)
67738909Sborman 				    break;
67838909Sborman 				if (pointer[j+1] == SE)
67938909Sborman 				    j++;
68038909Sborman 				else
68138909Sborman 				    break;
68238909Sborman 			    }
68338909Sborman 			    pointer[k++] = pointer[j++];
68438909Sborman 			}
68538909Sborman 			printsub(0, &pointer[i], k - i);
68638909Sborman 			if (i < length) {
68738909Sborman 			    fprintf(NetTrace, " SE");
68838909Sborman 			    i = j;
68938909Sborman 			} else
69038909Sborman 			    i = j - 1;
69138909Sborman 
69238909Sborman 			if (NetTrace == stdout)
69338909Sborman 			    fprintf(NetTrace, "\r\n");
69438909Sborman 			else
69538909Sborman 			    fprintf(NetTrace, "\n");
69638909Sborman 
69738909Sborman 			break;
69838909Sborman 
69938909Sborman 		    default:
70038909Sborman 			fprintf(NetTrace, " %d", pointer[i]);
70138909Sborman 			break;
70238909Sborman 		    }
70338909Sborman 		}
70438909Sborman 		break;
70538909Sborman 	    }
70638909Sborman 	    break;
70738909Sborman 	  }
70838909Sborman 
70944361Sborman 	case TELOPT_XDISPLOC:
71044361Sborman 	    fprintf(NetTrace, "X-DISPLAY-LOCATION ");
71144361Sborman 	    switch (pointer[1]) {
71244361Sborman 	    case TELQUAL_IS:
71344361Sborman 		fprintf(NetTrace, "IS \"%.*s\"", length-2, (char *)pointer+2);
71444361Sborman 		break;
71544361Sborman 	    case TELQUAL_SEND:
71644361Sborman 		fprintf(NetTrace, "SEND");
71744361Sborman 		break;
71844361Sborman 	    default:
71944361Sborman 		fprintf(NetTrace, "- unknown qualifier %d (0x%x).",
72044361Sborman 				pointer[1], pointer[1]);
72144361Sborman 	    }
72244361Sborman 	    break;
72344361Sborman 
72444361Sborman 	case TELOPT_ENVIRON:
72544361Sborman 	    fprintf(NetTrace, "ENVIRON ");
72644361Sborman 	    switch (pointer[1]) {
72744361Sborman 	    case TELQUAL_IS:
72844361Sborman 		fprintf(NetTrace, "IS ");
72944361Sborman 		goto env_common;
73044361Sborman 	    case TELQUAL_SEND:
73144361Sborman 		fprintf(NetTrace, "SEND ");
73244361Sborman 		goto env_common;
73344361Sborman 	    case TELQUAL_INFO:
73444361Sborman 		fprintf(NetTrace, "INFO ");
73544361Sborman 	    env_common:
73644361Sborman 		{
73744361Sborman 		    register int noquote = 2;
73858972Sdab #ifdef	ENV_HACK
73958972Sdab 		    extern int env_var, env_value;
74058972Sdab #endif
74144361Sborman 		    for (i = 2; i < length; i++ ) {
74244361Sborman 			switch (pointer[i]) {
74344361Sborman 			case ENV_VAR:
74458972Sdab #ifdef	ENV_HACK
74558972Sdab 			    if (env_var == ENV_VALUE)
74658972Sdab 				fprintf(NetTrace, "\" (VALUE) " + noquote);
74758972Sdab 			    else
74858972Sdab #endif
74944361Sborman 			    fprintf(NetTrace, "\" VAR " + noquote);
75044361Sborman 			    noquote = 2;
75144361Sborman 			    break;
75244361Sborman 
75344361Sborman 			case ENV_VALUE:
75458972Sdab #ifdef	ENV_HACK
75558972Sdab 			    if (env_value == ENV_VAR)
75658972Sdab 				fprintf(NetTrace, "\" (VAR) " + noquote);
75758972Sdab 			    else
75858972Sdab #endif
75944361Sborman 			    fprintf(NetTrace, "\" VALUE " + noquote);
76044361Sborman 			    noquote = 2;
76144361Sborman 			    break;
76244361Sborman 
76344361Sborman 			case ENV_ESC:
76444361Sborman 			    fprintf(NetTrace, "\" ESC " + noquote);
76544361Sborman 			    noquote = 2;
76644361Sborman 			    break;
76744361Sborman 
76857213Sdab 			case ENV_USERVAR:
76957213Sdab 			    fprintf(NetTrace, "\" USERVAR " + noquote);
77057213Sdab 			    noquote = 2;
77157213Sdab 			    break;
77257213Sdab 
77344361Sborman 			default:
77444361Sborman 			def_case:
77544361Sborman 			    if (isprint(pointer[i]) && pointer[i] != '"') {
77644361Sborman 				if (noquote) {
77744361Sborman 				    putc('"', NetTrace);
77844361Sborman 				    noquote = 0;
77944361Sborman 				}
78044361Sborman 				putc(pointer[i], NetTrace);
78144361Sborman 			    } else {
78244361Sborman 				fprintf(NetTrace, "\" %03o " + noquote,
78344361Sborman 							pointer[i]);
78444361Sborman 				noquote = 2;
78544361Sborman 			    }
78644361Sborman 			    break;
78744361Sborman 			}
78844361Sborman 		    }
78944361Sborman 		    if (!noquote)
79044361Sborman 			putc('"', NetTrace);
79144361Sborman 		    break;
79244361Sborman 		}
79344361Sborman 	    }
79444361Sborman 	    break;
79544361Sborman 
79632149Sminshall 	default:
79746808Sdab 	    if (TELOPT_OK(pointer[0]))
79846808Sdab 		fprintf(NetTrace, "%s (unknown)", TELOPT(pointer[0]));
79946808Sdab 	    else
80056860Storek 		fprintf(NetTrace, "%d (unknown)", pointer[0]);
80146808Sdab 	    for (i = 1; i < length; i++)
80238690Sborman 		fprintf(NetTrace, " %d", pointer[i]);
80338690Sborman 	    break;
80432149Sminshall 	}
80538909Sborman 	if (direction) {
80638909Sborman 	    if (NetTrace == stdout)
80738909Sborman 		fprintf(NetTrace, "\r\n");
80838909Sborman 	    else
80938909Sborman 		fprintf(NetTrace, "\n");
81038909Sborman 	}
81132149Sminshall     }
81232149Sminshall }
81336278Sminshall 
81436278Sminshall /* EmptyTerminal - called to make sure that the terminal buffer is empty.
81536278Sminshall  *			Note that we consider the buffer to run all the
81636278Sminshall  *			way to the kernel (thus the select).
81736278Sminshall  */
81836278Sminshall 
81946808Sdab     void
82036278Sminshall EmptyTerminal()
82136278Sminshall {
82236278Sminshall #if	defined(unix)
82336278Sminshall     fd_set	o;
82436278Sminshall 
82536278Sminshall     FD_ZERO(&o);
82636278Sminshall #endif	/* defined(unix) */
82736278Sminshall 
82836278Sminshall     if (TTYBYTES() == 0) {
82936278Sminshall #if	defined(unix)
83036278Sminshall 	FD_SET(tout, &o);
83136278Sminshall 	(void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
83236278Sminshall 			(struct timeval *) 0);	/* wait for TTLOWAT */
83336278Sminshall #endif	/* defined(unix) */
83436278Sminshall     } else {
83536278Sminshall 	while (TTYBYTES()) {
83644361Sborman 	    (void) ttyflush(0);
83736278Sminshall #if	defined(unix)
83836278Sminshall 	    FD_SET(tout, &o);
83936278Sminshall 	    (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
84036278Sminshall 				(struct timeval *) 0);	/* wait for TTLOWAT */
84136278Sminshall #endif	/* defined(unix) */
84236278Sminshall 	}
84336278Sminshall     }
84436278Sminshall }
84536278Sminshall 
84646808Sdab     void
84736278Sminshall SetForExit()
84836278Sminshall {
84938690Sborman     setconnmode(0);
85036278Sminshall #if	defined(TN3270)
85136278Sminshall     if (In3270) {
85236278Sminshall 	Finish3270();
85336278Sminshall     }
85436279Sminshall #else	/* defined(TN3270) */
85536279Sminshall     do {
85644361Sborman 	(void)telrcv();			/* Process any incoming data */
85736279Sminshall 	EmptyTerminal();
85836279Sminshall     } while (ring_full_count(&netiring));	/* While there is any */
85936278Sminshall #endif	/* defined(TN3270) */
86036278Sminshall     setcommandmode();
86136278Sminshall     fflush(stdout);
86236278Sminshall     fflush(stderr);
86336278Sminshall #if	defined(TN3270)
86436278Sminshall     if (In3270) {
86536278Sminshall 	StopScreen(1);
86636278Sminshall     }
86736278Sminshall #endif	/* defined(TN3270) */
86838690Sborman     setconnmode(0);
86936278Sminshall     EmptyTerminal();			/* Flush the path to the tty */
87036278Sminshall     setcommandmode();
87136278Sminshall }
87236278Sminshall 
87346808Sdab     void
87436278Sminshall Exit(returnCode)
87546808Sdab     int returnCode;
87636278Sminshall {
87736278Sminshall     SetForExit();
87836278Sminshall     exit(returnCode);
87936278Sminshall }
88036278Sminshall 
88146808Sdab     void
88236278Sminshall ExitString(string, returnCode)
88346808Sdab     char *string;
88446808Sdab     int returnCode;
88536278Sminshall {
88636278Sminshall     SetForExit();
88736278Sminshall     fwrite(string, 1, strlen(string), stderr);
88836278Sminshall     exit(returnCode);
88936278Sminshall }
890