xref: /csrg-svn/usr.bin/telnet/utilities.c (revision 44361)
133686Sbostic /*
233686Sbostic  * Copyright (c) 1988 Regents of the University of California.
333686Sbostic  * All rights reserved.
433686Sbostic  *
5*44361Sborman  * %sccs.include.redist.c%
633686Sbostic  */
733686Sbostic 
833686Sbostic #ifndef lint
9*44361Sborman static char sccsid[] = "@(#)utilities.c	1.19 (Berkeley) 06/28/90";
1033686Sbostic #endif /* not lint */
1133686Sbostic 
1232149Sminshall #define	TELOPTS
1338690Sborman #define	TELCMDS
1432149Sminshall #include <arpa/telnet.h>
1532381Sminshall #include <sys/types.h>
16*44361Sborman #include <sys/time.h>
1732149Sminshall 
1832149Sminshall #include <ctype.h>
1932149Sminshall 
2034305Sminshall #include "general.h"
2134305Sminshall 
2236280Sminshall #include "fdset.h"
2336280Sminshall 
2432381Sminshall #include "ring.h"
2532381Sminshall 
2636278Sminshall #include "defines.h"
2736278Sminshall 
2832149Sminshall #include "externs.h"
2932149Sminshall 
3032149Sminshall FILE	*NetTrace = 0;		/* Not in bss, since needs to stay */
3138690Sborman int	prettydump;
3232149Sminshall 
3332149Sminshall /*
3432149Sminshall  * upcase()
3532149Sminshall  *
3632149Sminshall  *	Upcase (in place) the argument.
3732149Sminshall  */
3832149Sminshall 
3932149Sminshall void
4032149Sminshall upcase(argument)
4132149Sminshall register char *argument;
4232149Sminshall {
4332149Sminshall     register int c;
4432149Sminshall 
4532149Sminshall     while ((c = *argument) != 0) {
4632149Sminshall 	if (islower(c)) {
4732149Sminshall 	    *argument = toupper(c);
4832149Sminshall 	}
4932149Sminshall 	argument++;
5032149Sminshall     }
5132149Sminshall }
5232149Sminshall 
5332149Sminshall /*
5432149Sminshall  * SetSockOpt()
5532149Sminshall  *
5632149Sminshall  * Compensate for differences in 4.2 and 4.3 systems.
5732149Sminshall  */
5832149Sminshall 
5932149Sminshall int
6032149Sminshall SetSockOpt(fd, level, option, yesno)
6132149Sminshall int
6232149Sminshall 	fd,
6332149Sminshall 	level,
6432149Sminshall 	option,
6532149Sminshall 	yesno;
6632149Sminshall {
6732149Sminshall #ifndef	NOT43
6832149Sminshall     return setsockopt(fd, level, option,
6932149Sminshall 				(char *)&yesno, sizeof yesno);
7032149Sminshall #else	/* NOT43 */
7132149Sminshall     if (yesno == 0) {		/* Can't do that in 4.2! */
7232149Sminshall 	fprintf(stderr, "Error: attempt to turn off an option 0x%x.\n",
7332149Sminshall 				option);
7432149Sminshall 	return -1;
7532149Sminshall     }
7632149Sminshall     return setsockopt(fd, level, option, 0, 0);
7732149Sminshall #endif	/* NOT43 */
7832149Sminshall }
7932149Sminshall 
8032149Sminshall /*
8132149Sminshall  * The following are routines used to print out debugging information.
8232149Sminshall  */
8332149Sminshall 
8439529Sborman unsigned char NetTraceFile[256] = "(standard output)";
8532149Sminshall 
8632149Sminshall void
8738690Sborman SetNetTrace(file)
8838690Sborman register char *file;
8938690Sborman {
9038690Sborman     if (NetTrace && NetTrace != stdout)
9138690Sborman 	fclose(NetTrace);
9238690Sborman     if (file  && (strcmp(file, "-") != 0)) {
9338690Sborman 	NetTrace = fopen(file, "w");
9438690Sborman 	if (NetTrace) {
9538690Sborman 	    strcpy(NetTraceFile, file);
9638690Sborman 	    return;
9738690Sborman 	}
9838690Sborman 	fprintf(stderr, "Cannot open %s.\n", file);
9938690Sborman     }
10038690Sborman     NetTrace = stdout;
10138690Sborman     strcpy(NetTraceFile, "(standard output)");
10238690Sborman }
10338690Sborman 
10438690Sborman void
10532149Sminshall Dump(direction, buffer, length)
10632149Sminshall char	direction;
10732149Sminshall char	*buffer;
10832149Sminshall int	length;
10932149Sminshall {
11032149Sminshall #   define BYTES_PER_LINE	32
11132149Sminshall #   define min(x,y)	((x<y)? x:y)
11232149Sminshall     char *pThis;
11332149Sminshall     int offset;
11438690Sborman     extern pettydump;
11532149Sminshall 
11632149Sminshall     offset = 0;
11732149Sminshall 
11832149Sminshall     while (length) {
11932149Sminshall 	/* print one line */
12032149Sminshall 	fprintf(NetTrace, "%c 0x%x\t", direction, offset);
12132149Sminshall 	pThis = buffer;
12238690Sborman 	if (prettydump) {
12338909Sborman 	    buffer = buffer + min(length, BYTES_PER_LINE/2);
12438690Sborman 	    while (pThis < buffer) {
12538690Sborman 		fprintf(NetTrace, "%c%.2x",
12638690Sborman 		    (((*pThis)&0xff) == 0xff) ? '*' : ' ',
12738690Sborman 		    (*pThis)&0xff);
12838690Sborman 		pThis++;
12938690Sborman 	    }
13038909Sborman 	    length -= BYTES_PER_LINE/2;
13138909Sborman 	    offset += BYTES_PER_LINE/2;
13238690Sborman 	} else {
13338909Sborman 	    buffer = buffer + min(length, BYTES_PER_LINE);
13438690Sborman 	    while (pThis < buffer) {
13538690Sborman 		fprintf(NetTrace, "%.2x", (*pThis)&0xff);
13638690Sborman 		pThis++;
13738690Sborman 	    }
13838909Sborman 	    length -= BYTES_PER_LINE;
13938909Sborman 	    offset += BYTES_PER_LINE;
14032149Sminshall 	}
14137226Sminshall 	if (NetTrace == stdout) {
14238207Sminshall 	    fprintf(NetTrace, "\r\n");
14338207Sminshall 	} else {
14437226Sminshall 	    fprintf(NetTrace, "\n");
14537226Sminshall 	}
14632149Sminshall 	if (length < 0) {
14736693Sminshall 	    fflush(NetTrace);
14832149Sminshall 	    return;
14932149Sminshall 	}
15032149Sminshall 	/* find next unique line */
15132149Sminshall     }
15236693Sminshall     fflush(NetTrace);
15332149Sminshall }
15432149Sminshall 
15532149Sminshall 
15632149Sminshall void
15737226Sminshall printoption(direction, fmt, option)
15832149Sminshall 	char *direction, *fmt;
15937226Sminshall 	int option;
16032149Sminshall {
16132149Sminshall 	if (!showoptions)
16232149Sminshall 		return;
16337226Sminshall 	fprintf(NetTrace, "%s ", direction);
16438690Sborman 	if (TELOPT_OK(option))
16538690Sborman 		fprintf(NetTrace, "%s %s", fmt, TELOPT(option));
16638690Sborman 	else if (TELCMD_OK(option))
16738690Sborman 		fprintf(NetTrace, "%s %s", fmt, TELCMD(option));
16832149Sminshall 	else
16932149Sminshall 		fprintf(NetTrace, "%s %d", fmt, option);
17038690Sborman 	if (NetTrace == stdout)
17137226Sminshall 	    fprintf(NetTrace, "\r\n");
17238690Sborman 	else
17337226Sminshall 	    fprintf(NetTrace, "\n");
17437226Sminshall 	return;
17532149Sminshall }
17632149Sminshall 
17738690Sborman optionstatus()
17838690Sborman {
17938690Sborman     register int i;
18038690Sborman     extern char will_wont_resp[], do_dont_resp[];
18138690Sborman 
18238690Sborman     for (i = 0; i < 256; i++) {
18338690Sborman 	if (do_dont_resp[i]) {
18438690Sborman 	    if (TELOPT_OK(i))
18538690Sborman 		printf("resp DO_DONT %s: %d\n", TELOPT(i), do_dont_resp[i]);
18638690Sborman 	    else if (TELCMD_OK(i))
18738690Sborman 		printf("resp DO_DONT %s: %d\n", TELCMD(i), do_dont_resp[i]);
18838690Sborman 	    else
18938690Sborman 		printf("resp DO_DONT %d: %d\n", i,
19038690Sborman 				do_dont_resp[i]);
19138690Sborman 	    if (my_want_state_is_do(i)) {
19238690Sborman 		if (TELOPT_OK(i))
19338690Sborman 		    printf("want DO   %s\n", TELOPT(i));
19438690Sborman 		else if (TELCMD_OK(i))
19538690Sborman 		    printf("want DO   %s\n", TELCMD(i));
19638690Sborman 		else
19738690Sborman 		    printf("want DO   %d\n", i);
19838690Sborman 	    } else {
19938690Sborman 		if (TELOPT_OK(i))
20038690Sborman 		    printf("want DONT %s\n", TELOPT(i));
20138690Sborman 		else if (TELCMD_OK(i))
20238690Sborman 		    printf("want DONT %s\n", TELCMD(i));
20338690Sborman 		else
20438690Sborman 		    printf("want DONT %d\n", i);
20538690Sborman 	    }
20638690Sborman 	} else {
20738690Sborman 	    if (my_state_is_do(i)) {
20838690Sborman 		if (TELOPT_OK(i))
20938690Sborman 		    printf("     DO   %s\n", TELOPT(i));
21038690Sborman 		else if (TELCMD_OK(i))
21138690Sborman 		    printf("     DO   %s\n", TELCMD(i));
21238690Sborman 		else
21338690Sborman 		    printf("     DO   %d\n", i);
21438690Sborman 	    }
21538690Sborman 	}
21638690Sborman 	if (will_wont_resp[i]) {
21738690Sborman 	    if (TELOPT_OK(i))
21838690Sborman 		printf("resp WILL_WONT %s: %d\n", TELOPT(i), will_wont_resp[i]);
21938690Sborman 	    else if (TELCMD_OK(i))
22038690Sborman 		printf("resp WILL_WONT %s: %d\n", TELCMD(i), will_wont_resp[i]);
22138690Sborman 	    else
22238690Sborman 		printf("resp WILL_WONT %d: %d\n",
22338690Sborman 				i, will_wont_resp[i]);
22438690Sborman 	    if (my_want_state_is_will(i)) {
22538690Sborman 		if (TELOPT_OK(i))
22638690Sborman 		    printf("want WILL %s\n", TELOPT(i));
22738690Sborman 		else if (TELCMD_OK(i))
22838690Sborman 		    printf("want WILL %s\n", TELCMD(i));
22938690Sborman 		else
23038690Sborman 		    printf("want WILL %d\n", i);
23138690Sborman 	    } else {
23238690Sborman 		if (TELOPT_OK(i))
23338690Sborman 		    printf("want WONT %s\n", TELOPT(i));
23438690Sborman 		else if (TELCMD_OK(i))
23538690Sborman 		    printf("want WONT %s\n", TELCMD(i));
23638690Sborman 		else
23738690Sborman 		    printf("want WONT %d\n", i);
23838690Sborman 	    }
23938690Sborman 	} else {
24038690Sborman 	    if (my_state_is_will(i)) {
24138690Sborman 		if (TELOPT_OK(i))
24238690Sborman 		    printf("     WILL %s\n", TELOPT(i));
24338690Sborman 		else if (TELCMD_OK(i))
24438690Sborman 		    printf("     WILL %s\n", TELCMD(i));
24538690Sborman 		else
24638690Sborman 		    printf("     WILL %d\n", i);
24738690Sborman 	    }
24838690Sborman 	}
24938690Sborman     }
25038690Sborman 
25138690Sborman }
25238690Sborman 
25338690Sborman char *slcnames[] = { SLC_NAMES };
25438690Sborman 
25543320Skfall #ifdef	KERBEROS
25643320Skfall static char *authtypes[3] = { "NONE", "PRIVATE", "KERBEROS" };
25743320Skfall #endif
25843320Skfall 
25932149Sminshall void
26032149Sminshall printsub(direction, pointer, length)
26138690Sborman char	direction;		/* '<' or '>' */
26238690Sborman unsigned char	*pointer;	/* where suboption data sits */
26332149Sminshall int	length;			/* length of suboption data */
26432149Sminshall {
26538690Sborman     register int i;
26638690Sborman 
26732149Sminshall     if (showoptions) {
26838909Sborman 	if (direction) {
26938909Sborman 	    fprintf(NetTrace, "%s suboption ",
27038690Sborman 				(direction == '<')? "Received":"Sent");
27138909Sborman 	    if (length >= 3) {
27238909Sborman 		register int j;
27338690Sborman 
27438909Sborman 		i = pointer[length-2];
27538909Sborman 		j = pointer[length-1];
27638690Sborman 
27738909Sborman 		if (i != IAC || j != SE) {
27838909Sborman 		    fprintf(NetTrace, "(terminated by ");
27938909Sborman 		    if (TELOPT_OK(i))
28038909Sborman 			fprintf(NetTrace, "%s ", TELOPT(i));
28138909Sborman 		    else if (TELCMD_OK(i))
28238909Sborman 			fprintf(NetTrace, "%s ", TELCMD(i));
28338909Sborman 		    else
28438909Sborman 			fprintf(NetTrace, "%d ", i);
28538909Sborman 		    if (TELOPT_OK(j))
28638909Sborman 			fprintf(NetTrace, "%s", TELOPT(j));
28738909Sborman 		    else if (TELCMD_OK(j))
28838909Sborman 			fprintf(NetTrace, "%s", TELCMD(j));
28938909Sborman 		    else
29038909Sborman 			fprintf(NetTrace, "%d", j);
29138909Sborman 		    fprintf(NetTrace, ", not IAC SE!) ");
29238909Sborman 		}
29338690Sborman 	    }
29438909Sborman 	    length -= 2;
29538690Sborman 	}
29638690Sborman 	if (length < 1) {
29738690Sborman 	    fprintf(NetTrace, "(Empty suboption???)");
29838690Sborman 	    return;
29938690Sborman 	}
30032149Sminshall 	switch (pointer[0]) {
30132149Sminshall 	case TELOPT_TTYPE:
30238690Sborman 	    fprintf(NetTrace, "TERMINAL-TYPE ");
30332149Sminshall 	    switch (pointer[1]) {
30432149Sminshall 	    case TELQUAL_IS:
305*44361Sborman 		fprintf(NetTrace, "IS \"%.*s\"", length-2, (char *)pointer+2);
30632149Sminshall 		break;
30732149Sminshall 	    case TELQUAL_SEND:
30838690Sborman 		fprintf(NetTrace, "SEND");
30932149Sminshall 		break;
31032149Sminshall 	    default:
31132149Sminshall 		fprintf(NetTrace,
31238690Sborman 				"- unknown qualifier %d (0x%x).",
31334849Sminshall 				pointer[1], pointer[1]);
31432149Sminshall 	    }
31532149Sminshall 	    break;
31638690Sborman 	case TELOPT_TSPEED:
31738690Sborman 	    fprintf(NetTrace, "TERMINAL-SPEED");
31838690Sborman 	    if (length < 2) {
31938690Sborman 		fprintf(NetTrace, " (empty suboption???)");
32038690Sborman 		break;
32138690Sborman 	    }
32238690Sborman 	    switch (pointer[1]) {
32338909Sborman 	    case TELQUAL_IS:
32438690Sborman 		fprintf(NetTrace, " IS ");
325*44361Sborman 		fprintf(NetTrace, "%.*s", length-2, (char *)pointer+2);
32638690Sborman 		break;
32738690Sborman 	    default:
32838690Sborman 		if (pointer[1] == 1)
32938690Sborman 		    fprintf(NetTrace, " SEND");
33038690Sborman 		else
331*44361Sborman 		    fprintf(NetTrace, " %d (unknown)", pointer[1]);
33238690Sborman 		for (i = 2; i < length; i++)
33338690Sborman 		    fprintf(NetTrace, " ?%d?", pointer[i]);
33438690Sborman 		break;
33538690Sborman 	    }
33638690Sborman 	    break;
33738690Sborman 
33838690Sborman 	case TELOPT_LFLOW:
33938690Sborman 	    fprintf(NetTrace, "TOGGLE-FLOW-CONTROL");
34038690Sborman 	    if (length < 2) {
34138690Sborman 		fprintf(NetTrace, " (empty suboption???)");
34238690Sborman 		break;
34338690Sborman 	    }
34438690Sborman 	    switch (pointer[1]) {
34538690Sborman 	    case 0:
34638690Sborman 		fprintf(NetTrace, " OFF"); break;
34738690Sborman 	    case 1:
34838690Sborman 		fprintf(NetTrace, " ON"); break;
34938690Sborman 	    default:
350*44361Sborman 		fprintf(NetTrace, " %d (unknown)", pointer[1]);
35138690Sborman 	    }
35238690Sborman 	    for (i = 2; i < length; i++)
35338690Sborman 		fprintf(NetTrace, " ?%d?", pointer[i]);
35438690Sborman 	    break;
35538690Sborman 
35638690Sborman 	case TELOPT_NAWS:
35738690Sborman 	    fprintf(NetTrace, "NAWS");
35838690Sborman 	    if (length < 2) {
35938690Sborman 		fprintf(NetTrace, " (empty suboption???)");
36038690Sborman 		break;
36138690Sborman 	    }
36238690Sborman 	    if (length == 2) {
36338690Sborman 		fprintf(NetTrace, " ?%d?", pointer[1]);
36438690Sborman 		break;
36538690Sborman 	    }
36638690Sborman 	    fprintf(NetTrace, " %d %d (%d)",
36738690Sborman 		pointer[1], pointer[2],
368*44361Sborman 		(int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2])));
36938690Sborman 	    if (length == 4) {
37038690Sborman 		fprintf(NetTrace, " ?%d?", pointer[3]);
37138690Sborman 		break;
37238690Sborman 	    }
37338690Sborman 	    fprintf(NetTrace, " %d %d (%d)",
37438690Sborman 		pointer[3], pointer[4],
375*44361Sborman 		(int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4])));
37638690Sborman 	    for (i = 5; i < length; i++)
37738690Sborman 		fprintf(NetTrace, " ?%d?", pointer[i]);
37838690Sborman 	    break;
37938690Sborman 
38043320Skfall #ifdef	KERBEROS
38143320Skfall 	case TELOPT_AUTHENTICATION:
38243320Skfall 	    fprintf(NetTrace, "Authentication information ");
38343320Skfall 	    switch (pointer[1]) {
38443320Skfall 	    case TELQUAL_IS:
38543320Skfall 		switch (pointer[2]) {
38643320Skfall 		case TELQUAL_AUTHTYPE_NONE:
38743320Skfall 		case TELQUAL_AUTHTYPE_PRIVATE:
38843320Skfall 		case TELQUAL_AUTHTYPE_KERBEROS:
38943320Skfall 
39043320Skfall 			fprintf(NetTrace, "is type %s\r\n", authtypes[pointer[2]]);
39143320Skfall 			break;
39243320Skfall 		default:
39343320Skfall 			fprintf(NetTrace, "is type unknown\r\n");
39443320Skfall 			break;
39543320Skfall 		}
39643320Skfall 
39743320Skfall 	    case TELQUAL_SEND:
39843320Skfall 	    {
39943320Skfall 		int	idx = 2;
40043320Skfall 		fprintf(NetTrace, "- request to send, types");
40143320Skfall 		for (idx = 2; idx < length - 1; idx++)
40243320Skfall 			switch (pointer[idx]) {
40343320Skfall 			case TELQUAL_AUTHTYPE_NONE:
40443320Skfall 			case TELQUAL_AUTHTYPE_PRIVATE:
40543320Skfall 			case TELQUAL_AUTHTYPE_KERBEROS:
40643320Skfall 				fprintf(NetTrace, " %s",
40743320Skfall 					authtypes[pointer[idx]]);
40843320Skfall 					break;
40943320Skfall 			default:
41043320Skfall 				fprintf(NetTrace, " <unknown %u>",
41143320Skfall 					pointer[idx]);
41243320Skfall 				break;
41343320Skfall 			}
41443320Skfall 		fprintf(NetTrace, "\r\n");
41543320Skfall 	    }
41643320Skfall 		break;
41743320Skfall 
41843320Skfall 	    default:
41943320Skfall 		fprintf(NetTrace, " - unknown qualifier %d (0x%x).\r\n",
42043320Skfall 			pointer[1], pointer[1]);
42143320Skfall 	    }
42243320Skfall 	    break;
42343320Skfall #endif /* KERBEROS */
42443320Skfall 
42538690Sborman 	case TELOPT_LINEMODE:
42638690Sborman 	    fprintf(NetTrace, "LINEMODE ");
42738690Sborman 	    if (length < 2) {
42838690Sborman 		fprintf(NetTrace, " (empty suboption???)");
42938690Sborman 		break;
43038690Sborman 	    }
43138690Sborman 	    switch (pointer[1]) {
43238690Sborman 	    case WILL:
43338690Sborman 		fprintf(NetTrace, "WILL ");
43438690Sborman 		goto common;
43538690Sborman 	    case WONT:
43638690Sborman 		fprintf(NetTrace, "WONT ");
43738690Sborman 		goto common;
43838690Sborman 	    case DO:
43938690Sborman 		fprintf(NetTrace, "DO ");
44038690Sborman 		goto common;
44138690Sborman 	    case DONT:
44238690Sborman 		fprintf(NetTrace, "DONT ");
44338690Sborman 	    common:
44438690Sborman 		if (length < 3) {
44538690Sborman 		    fprintf(NetTrace, "(no option???)");
44638690Sborman 		    break;
44738690Sborman 		}
44838690Sborman 		switch (pointer[2]) {
44938690Sborman 		case LM_FORWARDMASK:
45038690Sborman 		    fprintf(NetTrace, "Forward Mask");
45138690Sborman 		    for (i = 3; i < length; i++)
45238690Sborman 			fprintf(NetTrace, " %x", pointer[i]);
45338690Sborman 		    break;
45438690Sborman 		default:
45538690Sborman 		    fprintf(NetTrace, "%d (unknown)", pointer[2]);
45638690Sborman 		    for (i = 3; i < length; i++)
45738690Sborman 			fprintf(NetTrace, " %d", pointer[i]);
45838690Sborman 		    break;
45938690Sborman 		}
46038690Sborman 		break;
46138690Sborman 
46238690Sborman 	    case LM_SLC:
46338690Sborman 		fprintf(NetTrace, "SLC");
46438690Sborman 		for (i = 2; i < length - 2; i += 3) {
46538690Sborman 		    if (pointer[i+SLC_FUNC] <= NSLC)
46638690Sborman 			fprintf(NetTrace, " %s", slcnames[pointer[i+SLC_FUNC]]);
46738690Sborman 		    else
46838690Sborman 			fprintf(NetTrace, " %d", pointer[i+SLC_FUNC]);
46938690Sborman 		    switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) {
47038690Sborman 		    case SLC_NOSUPPORT:
47138690Sborman 			fprintf(NetTrace, " NOSUPPORT"); break;
47238690Sborman 		    case SLC_CANTCHANGE:
47338690Sborman 			fprintf(NetTrace, " CANTCHANGE"); break;
47438690Sborman 		    case SLC_VARIABLE:
47538690Sborman 			fprintf(NetTrace, " VARIABLE"); break;
47638690Sborman 		    case SLC_DEFAULT:
47738690Sborman 			fprintf(NetTrace, " DEFAULT"); break;
47838690Sborman 		    }
47938690Sborman 		    fprintf(NetTrace, "%s%s%s",
48038690Sborman 			pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "",
48138690Sborman 			pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "",
48238690Sborman 			pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : "");
48338690Sborman 		    if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN|
48438690Sborman 						SLC_FLUSHOUT| SLC_LEVELBITS))
48538690Sborman 			fprintf(NetTrace, "(0x%x)", pointer[i+SLC_FLAGS]);
48638690Sborman 		    fprintf(NetTrace, " %d;", pointer[i+SLC_VALUE]);
487*44361Sborman 		    if ((pointer[i+SLC_VALUE] == IAC) &&
488*44361Sborman 			(pointer[i+SLC_VALUE+1] == IAC))
489*44361Sborman 				i++;
49038690Sborman 		}
49138690Sborman 		for (; i < length; i++)
49238690Sborman 		    fprintf(NetTrace, " ?%d?", pointer[i]);
49338690Sborman 		break;
49438690Sborman 
49538690Sborman 	    case LM_MODE:
49638690Sborman 		fprintf(NetTrace, "MODE ");
49738690Sborman 		if (length < 3) {
49838690Sborman 		    fprintf(NetTrace, "(no mode???)");
49938690Sborman 		    break;
50038690Sborman 		}
50138690Sborman 		{
502*44361Sborman 		    char tbuf[64];
503*44361Sborman 		    sprintf(tbuf, "%s%s%s%s%s",
50438690Sborman 			pointer[2]&MODE_EDIT ? "|EDIT" : "",
50538690Sborman 			pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "",
506*44361Sborman 			pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "",
507*44361Sborman 			pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "",
50838690Sborman 			pointer[2]&MODE_ACK ? "|ACK" : "");
50938690Sborman 		    fprintf(NetTrace, "%s", tbuf[1] ? &tbuf[1] : "0");
51038690Sborman 		}
51138690Sborman 		if (pointer[2]&~(MODE_EDIT|MODE_TRAPSIG|MODE_ACK))
51238690Sborman 		    fprintf(NetTrace, " (0x%x)", pointer[2]);
51338690Sborman 		for (i = 3; i < length; i++)
51438690Sborman 		    fprintf(NetTrace, " ?0x%x?", pointer[i]);
51538690Sborman 		break;
51638690Sborman 	    default:
51738690Sborman 		fprintf(NetTrace, "%d (unknown)", pointer[1]);
51838690Sborman 		for (i = 2; i < length; i++)
51938690Sborman 		    fprintf(NetTrace, " %d", pointer[i]);
52038690Sborman 	    }
52138690Sborman 	    break;
52238690Sborman 
52338909Sborman 	case TELOPT_STATUS: {
52438909Sborman 	    register char *cp;
52538909Sborman 	    register int j, k;
52638909Sborman 
52738909Sborman 	    fprintf(NetTrace, "STATUS");
52838909Sborman 
52938909Sborman 	    switch (pointer[1]) {
53038909Sborman 	    default:
53138909Sborman 		if (pointer[1] == TELQUAL_SEND)
53238909Sborman 		    fprintf(NetTrace, " SEND");
53338909Sborman 		else
534*44361Sborman 		    fprintf(NetTrace, " %d (unknown)", pointer[1]);
53538909Sborman 		for (i = 2; i < length; i++)
53638909Sborman 		    fprintf(NetTrace, " ?%d?", pointer[i]);
53738909Sborman 		break;
53838909Sborman 	    case TELQUAL_IS:
53938909Sborman 		if (NetTrace == stdout)
54038909Sborman 		    fprintf(NetTrace, " IS\r\n");
54138909Sborman 		else
54238909Sborman 		    fprintf(NetTrace, " IS\n");
54338909Sborman 
54438909Sborman 		for (i = 2; i < length; i++) {
54538909Sborman 		    switch(pointer[i]) {
54638909Sborman 		    case DO:	cp = "DO"; goto common2;
54738909Sborman 		    case DONT:	cp = "DONT"; goto common2;
54838909Sborman 		    case WILL:	cp = "WILL"; goto common2;
54938909Sborman 		    case WONT:	cp = "WONT"; goto common2;
55038909Sborman 		    common2:
55138909Sborman 			i++;
552*44361Sborman 			if (TELOPT_OK((int)pointer[i]))
55338909Sborman 			    fprintf(NetTrace, " %s %s", cp, TELOPT(pointer[i]));
55438909Sborman 			else
55538909Sborman 			    fprintf(NetTrace, " %s %d", cp, pointer[i]);
55638909Sborman 
55738909Sborman 			if (NetTrace == stdout)
55838909Sborman 			    fprintf(NetTrace, "\r\n");
55938909Sborman 			else
56038909Sborman 			    fprintf(NetTrace, "\n");
56138909Sborman 			break;
56238909Sborman 
56338909Sborman 		    case SB:
56438909Sborman 			fprintf(NetTrace, " SB ");
56538909Sborman 			i++;
56638909Sborman 			j = k = i;
56738909Sborman 			while (j < length) {
56838909Sborman 			    if (pointer[j] == SE) {
56938909Sborman 				if (j+1 == length)
57038909Sborman 				    break;
57138909Sborman 				if (pointer[j+1] == SE)
57238909Sborman 				    j++;
57338909Sborman 				else
57438909Sborman 				    break;
57538909Sborman 			    }
57638909Sborman 			    pointer[k++] = pointer[j++];
57738909Sborman 			}
57838909Sborman 			printsub(0, &pointer[i], k - i);
57938909Sborman 			if (i < length) {
58038909Sborman 			    fprintf(NetTrace, " SE");
58138909Sborman 			    i = j;
58238909Sborman 			} else
58338909Sborman 			    i = j - 1;
58438909Sborman 
58538909Sborman 			if (NetTrace == stdout)
58638909Sborman 			    fprintf(NetTrace, "\r\n");
58738909Sborman 			else
58838909Sborman 			    fprintf(NetTrace, "\n");
58938909Sborman 
59038909Sborman 			break;
59138909Sborman 
59238909Sborman 		    default:
59338909Sborman 			fprintf(NetTrace, " %d", pointer[i]);
59438909Sborman 			break;
59538909Sborman 		    }
59638909Sborman 		}
59738909Sborman 		break;
59838909Sborman 	    }
59938909Sborman 	    break;
60038909Sborman 	  }
60138909Sborman 
602*44361Sborman 	case TELOPT_XDISPLOC:
603*44361Sborman 	    fprintf(NetTrace, "X-DISPLAY-LOCATION ");
604*44361Sborman 	    switch (pointer[1]) {
605*44361Sborman 	    case TELQUAL_IS:
606*44361Sborman 		fprintf(NetTrace, "IS \"%.*s\"", length-2, (char *)pointer+2);
607*44361Sborman 		break;
608*44361Sborman 	    case TELQUAL_SEND:
609*44361Sborman 		fprintf(NetTrace, "SEND");
610*44361Sborman 		break;
611*44361Sborman 	    default:
612*44361Sborman 		fprintf(NetTrace, "- unknown qualifier %d (0x%x).",
613*44361Sborman 				pointer[1], pointer[1]);
614*44361Sborman 	    }
615*44361Sborman 	    break;
616*44361Sborman 
617*44361Sborman 	case TELOPT_ENVIRON:
618*44361Sborman 	    fprintf(NetTrace, "ENVIRON ");
619*44361Sborman 	    switch (pointer[1]) {
620*44361Sborman 	    case TELQUAL_IS:
621*44361Sborman 		fprintf(NetTrace, "IS ");
622*44361Sborman 		goto env_common;
623*44361Sborman 	    case TELQUAL_SEND:
624*44361Sborman 		fprintf(NetTrace, "SEND ");
625*44361Sborman 		goto env_common;
626*44361Sborman 	    case TELQUAL_INFO:
627*44361Sborman 		fprintf(NetTrace, "INFO ");
628*44361Sborman 	    env_common:
629*44361Sborman 		{
630*44361Sborman 		    register int noquote = 2;
631*44361Sborman 		    for (i = 2; i < length; i++ ) {
632*44361Sborman 			switch (pointer[i]) {
633*44361Sborman 			case ENV_VAR:
634*44361Sborman 			    if (pointer[1] == TELQUAL_SEND)
635*44361Sborman 				goto def_case;
636*44361Sborman 			    fprintf(NetTrace, "\" VAR " + noquote);
637*44361Sborman 			    noquote = 2;
638*44361Sborman 			    break;
639*44361Sborman 
640*44361Sborman 			case ENV_VALUE:
641*44361Sborman 			    fprintf(NetTrace, "\" VALUE " + noquote);
642*44361Sborman 			    noquote = 2;
643*44361Sborman 			    break;
644*44361Sborman 
645*44361Sborman 			case ENV_ESC:
646*44361Sborman 			    fprintf(NetTrace, "\" ESC " + noquote);
647*44361Sborman 			    noquote = 2;
648*44361Sborman 			    break;
649*44361Sborman 
650*44361Sborman 			default:
651*44361Sborman 			def_case:
652*44361Sborman 			    if (isprint(pointer[i]) && pointer[i] != '"') {
653*44361Sborman 				if (noquote) {
654*44361Sborman 				    putc('"', NetTrace);
655*44361Sborman 				    noquote = 0;
656*44361Sborman 				}
657*44361Sborman 				putc(pointer[i], NetTrace);
658*44361Sborman 			    } else {
659*44361Sborman 				fprintf(NetTrace, "\" %03o " + noquote,
660*44361Sborman 							pointer[i]);
661*44361Sborman 				noquote = 2;
662*44361Sborman 			    }
663*44361Sborman 			    break;
664*44361Sborman 			}
665*44361Sborman 		    }
666*44361Sborman 		    if (!noquote)
667*44361Sborman 			putc('"', NetTrace);
668*44361Sborman 		    break;
669*44361Sborman 		}
670*44361Sborman 	    }
671*44361Sborman 	    break;
672*44361Sborman 
67332149Sminshall 	default:
67438690Sborman 	    fprintf(NetTrace, "Unknown option ");
67538690Sborman 	    for (i = 0; i < length; i++)
67638690Sborman 		fprintf(NetTrace, " %d", pointer[i]);
67738690Sborman 	    break;
67832149Sminshall 	}
67938909Sborman 	if (direction) {
68038909Sborman 	    if (NetTrace == stdout)
68138909Sborman 		fprintf(NetTrace, "\r\n");
68238909Sborman 	    else
68338909Sborman 		fprintf(NetTrace, "\n");
68438909Sborman 	}
68532149Sminshall     }
68632149Sminshall }
68736278Sminshall 
68836278Sminshall /* EmptyTerminal - called to make sure that the terminal buffer is empty.
68936278Sminshall  *			Note that we consider the buffer to run all the
69036278Sminshall  *			way to the kernel (thus the select).
69136278Sminshall  */
69236278Sminshall 
69336278Sminshall void
69436278Sminshall EmptyTerminal()
69536278Sminshall {
69636278Sminshall #if	defined(unix)
69736278Sminshall     fd_set	o;
69836278Sminshall 
69936278Sminshall     FD_ZERO(&o);
70036278Sminshall #endif	/* defined(unix) */
70136278Sminshall 
70236278Sminshall     if (TTYBYTES() == 0) {
70336278Sminshall #if	defined(unix)
70436278Sminshall 	FD_SET(tout, &o);
70536278Sminshall 	(void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
70636278Sminshall 			(struct timeval *) 0);	/* wait for TTLOWAT */
70736278Sminshall #endif	/* defined(unix) */
70836278Sminshall     } else {
70936278Sminshall 	while (TTYBYTES()) {
710*44361Sborman 	    (void) ttyflush(0);
71136278Sminshall #if	defined(unix)
71236278Sminshall 	    FD_SET(tout, &o);
71336278Sminshall 	    (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
71436278Sminshall 				(struct timeval *) 0);	/* wait for TTLOWAT */
71536278Sminshall #endif	/* defined(unix) */
71636278Sminshall 	}
71736278Sminshall     }
71836278Sminshall }
71936278Sminshall 
72036278Sminshall void
72136278Sminshall SetForExit()
72236278Sminshall {
72338690Sborman     setconnmode(0);
72436278Sminshall #if	defined(TN3270)
72536278Sminshall     if (In3270) {
72636278Sminshall 	Finish3270();
72736278Sminshall     }
72836279Sminshall #else	/* defined(TN3270) */
72936279Sminshall     do {
730*44361Sborman 	(void)telrcv();			/* Process any incoming data */
73136279Sminshall 	EmptyTerminal();
73236279Sminshall     } while (ring_full_count(&netiring));	/* While there is any */
73336278Sminshall #endif	/* defined(TN3270) */
73436278Sminshall     setcommandmode();
73536278Sminshall     fflush(stdout);
73636278Sminshall     fflush(stderr);
73736278Sminshall #if	defined(TN3270)
73836278Sminshall     if (In3270) {
73936278Sminshall 	StopScreen(1);
74036278Sminshall     }
74136278Sminshall #endif	/* defined(TN3270) */
74238690Sborman     setconnmode(0);
74336278Sminshall     EmptyTerminal();			/* Flush the path to the tty */
74436278Sminshall     setcommandmode();
74536278Sminshall }
74636278Sminshall 
74736278Sminshall void
74836278Sminshall Exit(returnCode)
74936278Sminshall int returnCode;
75036278Sminshall {
75136278Sminshall     SetForExit();
75236278Sminshall     exit(returnCode);
75336278Sminshall }
75436278Sminshall 
75536278Sminshall void
75636278Sminshall ExitString(string, returnCode)
75736278Sminshall char *string;
75836278Sminshall int returnCode;
75936278Sminshall {
76036278Sminshall     SetForExit();
76136278Sminshall     fwrite(string, 1, strlen(string), stderr);
76236278Sminshall     exit(returnCode);
76336278Sminshall }
764