xref: /csrg-svn/libexec/telnetd/utility.c (revision 47611)
138905Sborman /*
238905Sborman  * Copyright (c) 1989 Regents of the University of California.
338905Sborman  * All rights reserved.
438905Sborman  *
542673Sbostic  * %sccs.include.redist.c%
638905Sborman  */
738905Sborman 
838905Sborman #ifndef lint
9*47611Sdab static char sccsid[] = "@(#)utility.c	5.8 (Berkeley) 03/22/91";
1038905Sborman #endif /* not lint */
1138905Sborman 
1244364Sborman #define PRINTOPTIONS
1338905Sborman #include "telnetd.h"
1438905Sborman 
1538905Sborman /*
1638905Sborman  * utility functions performing io related tasks
1738905Sborman  */
1838905Sborman 
1938905Sborman /*
2038905Sborman  * ttloop
2138905Sborman  *
2238905Sborman  *	A small subroutine to flush the network output buffer, get some data
2338905Sborman  * from the network, and pass it through the telnet state machine.  We
2438905Sborman  * also flush the pty input buffer (by dropping its data) if it becomes
2538905Sborman  * too full.
2638905Sborman  */
2738905Sborman 
2846809Sdab     void
2938905Sborman ttloop()
3038905Sborman {
3138905Sborman     void netflush();
3238905Sborman 
3346809Sdab     DIAG(TD_REPORT, {sprintf(nfrontp, "td: ttloop\r\n");
3446809Sdab 		     nfrontp += strlen(nfrontp);});
3538905Sborman     if (nfrontp-nbackp) {
3638905Sborman 	netflush();
3738905Sborman     }
3838905Sborman     ncc = read(net, netibuf, sizeof netibuf);
3938905Sborman     if (ncc < 0) {
4038905Sborman 	syslog(LOG_INFO, "ttloop:  read: %m\n");
4138905Sborman 	exit(1);
4238905Sborman     } else if (ncc == 0) {
4338905Sborman 	syslog(LOG_INFO, "ttloop:  peer died: %m\n");
4438905Sborman 	exit(1);
4538905Sborman     }
4646809Sdab     DIAG(TD_REPORT, {sprintf(nfrontp, "td: ttloop read %d chars\r\n", ncc);
4746809Sdab 		     nfrontp += strlen(nfrontp);});
4838905Sborman     netip = netibuf;
4938905Sborman     telrcv();			/* state machine */
5038905Sborman     if (ncc > 0) {
5138905Sborman 	pfrontp = pbackp = ptyobuf;
5238905Sborman 	telrcv();
5338905Sborman     }
5438905Sborman }  /* end of ttloop */
5538905Sborman 
5638905Sborman /*
5738905Sborman  * Check a descriptor to see if out of band data exists on it.
5838905Sborman  */
5946809Sdab     int
6038905Sborman stilloob(s)
6146809Sdab     int	s;		/* socket number */
6238905Sborman {
6338905Sborman     static struct timeval timeout = { 0 };
6438905Sborman     fd_set	excepts;
6538905Sborman     int value;
6638905Sborman 
6738905Sborman     do {
6838905Sborman 	FD_ZERO(&excepts);
6938905Sborman 	FD_SET(s, &excepts);
7038905Sborman 	value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout);
7138905Sborman     } while ((value == -1) && (errno == EINTR));
7238905Sborman 
7338905Sborman     if (value < 0) {
7438905Sborman 	fatalperror(pty, "select");
7538905Sborman     }
7638905Sborman     if (FD_ISSET(s, &excepts)) {
7738905Sborman 	return 1;
7838905Sborman     } else {
7938905Sborman 	return 0;
8038905Sborman     }
8138905Sborman }
8238905Sborman 
8346809Sdab 	void
8438905Sborman ptyflush()
8538905Sborman {
8638905Sborman 	int n;
8738905Sborman 
8844364Sborman 	if ((n = pfrontp - pbackp) > 0) {
8946809Sdab 		DIAG((TD_REPORT | TD_PTYDATA),
9046809Sdab 			{ sprintf(nfrontp, "td: ptyflush %d chars\r\n", n);
9146809Sdab 			  nfrontp += strlen(nfrontp); });
9246809Sdab 		DIAG(TD_PTYDATA, printdata("pd", pbackp, n));
9338905Sborman 		n = write(pty, pbackp, n);
9444364Sborman 	}
9546809Sdab 	if (n < 0) {
9646809Sdab 		if (errno == EWOULDBLOCK || errno == EINTR)
9746809Sdab 			return;
9846809Sdab 		cleanup(0);
9946809Sdab 	}
10038905Sborman 	pbackp += n;
10138905Sborman 	if (pbackp == pfrontp)
10238905Sborman 		pbackp = pfrontp = ptyobuf;
10338905Sborman }
10438905Sborman 
10538905Sborman /*
10638905Sborman  * nextitem()
10738905Sborman  *
10838905Sborman  *	Return the address of the next "item" in the TELNET data
10938905Sborman  * stream.  This will be the address of the next character if
11038905Sborman  * the current address is a user data character, or it will
11138905Sborman  * be the address of the character following the TELNET command
11238905Sborman  * if the current address is a TELNET IAC ("I Am a Command")
11338905Sborman  * character.
11438905Sborman  */
11546809Sdab     char *
11638905Sborman nextitem(current)
11746809Sdab     char	*current;
11838905Sborman {
11938905Sborman     if ((*current&0xff) != IAC) {
12038905Sborman 	return current+1;
12138905Sborman     }
12238905Sborman     switch (*(current+1)&0xff) {
12338905Sborman     case DO:
12438905Sborman     case DONT:
12538905Sborman     case WILL:
12638905Sborman     case WONT:
12738905Sborman 	return current+3;
12838905Sborman     case SB:		/* loop forever looking for the SE */
12938905Sborman 	{
13038905Sborman 	    register char *look = current+2;
13138905Sborman 
13238905Sborman 	    for (;;) {
13338905Sborman 		if ((*look++&0xff) == IAC) {
13438905Sborman 		    if ((*look++&0xff) == SE) {
13538905Sborman 			return look;
13638905Sborman 		    }
13738905Sborman 		}
13838905Sborman 	    }
13938905Sborman 	}
14038905Sborman     default:
14138905Sborman 	return current+2;
14238905Sborman     }
14338905Sborman }  /* end of nextitem */
14438905Sborman 
14538905Sborman 
14638905Sborman /*
14738905Sborman  * netclear()
14838905Sborman  *
14938905Sborman  *	We are about to do a TELNET SYNCH operation.  Clear
15038905Sborman  * the path to the network.
15138905Sborman  *
15238905Sborman  *	Things are a bit tricky since we may have sent the first
15338905Sborman  * byte or so of a previous TELNET command into the network.
15438905Sborman  * So, we have to scan the network buffer from the beginning
15538905Sborman  * until we are up to where we want to be.
15638905Sborman  *
15738905Sborman  *	A side effect of what we do, just to keep things
15838905Sborman  * simple, is to clear the urgent data pointer.  The principal
15938905Sborman  * caller should be setting the urgent data pointer AFTER calling
16038905Sborman  * us in any case.
16138905Sborman  */
16246809Sdab     void
16338905Sborman netclear()
16438905Sborman {
16538905Sborman     register char *thisitem, *next;
16638905Sborman     char *good;
16738905Sborman #define	wewant(p)	((nfrontp > p) && ((*p&0xff) == IAC) && \
16838905Sborman 				((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
16938905Sborman 
17046809Sdab #if	defined(ENCRYPT)
17146809Sdab     thisitem = nclearto > netobuf ? nclearto : netobuf;
17246809Sdab #else
17338905Sborman     thisitem = netobuf;
17446809Sdab #endif
17538905Sborman 
17638905Sborman     while ((next = nextitem(thisitem)) <= nbackp) {
17738905Sborman 	thisitem = next;
17838905Sborman     }
17938905Sborman 
18038905Sborman     /* Now, thisitem is first before/at boundary. */
18138905Sborman 
18246809Sdab #if	defined(ENCRYPT)
18346809Sdab     good = nclearto > netobuf ? nclearto : netobuf;
18446809Sdab #else
18538905Sborman     good = netobuf;	/* where the good bytes go */
18646809Sdab #endif
18738905Sborman 
18838905Sborman     while (nfrontp > thisitem) {
18938905Sborman 	if (wewant(thisitem)) {
19038905Sborman 	    int length;
19138905Sborman 
19238905Sborman 	    next = thisitem;
19338905Sborman 	    do {
19438905Sborman 		next = nextitem(next);
19538905Sborman 	    } while (wewant(next) && (nfrontp > next));
19638905Sborman 	    length = next-thisitem;
19738905Sborman 	    bcopy(thisitem, good, length);
19838905Sborman 	    good += length;
19938905Sborman 	    thisitem = next;
20038905Sborman 	} else {
20138905Sborman 	    thisitem = nextitem(thisitem);
20238905Sborman 	}
20338905Sborman     }
20438905Sborman 
20538905Sborman     nbackp = netobuf;
20638905Sborman     nfrontp = good;		/* next byte to be sent */
20738905Sborman     neturg = 0;
20838905Sborman }  /* end of netclear */
20938905Sborman 
21038905Sborman /*
21138905Sborman  *  netflush
21238905Sborman  *		Send as much data as possible to the network,
21338905Sborman  *	handling requests for urgent data.
21438905Sborman  */
21546809Sdab     void
21638905Sborman netflush()
21738905Sborman {
21838905Sborman     int n;
21938905Sborman     extern int not42;
22038905Sborman 
22138905Sborman     if ((n = nfrontp - nbackp) > 0) {
22246809Sdab 	DIAG(TD_REPORT,
22346809Sdab 	    { sprintf(nfrontp, "td: netflush %d chars\r\n", n);
22446809Sdab 	      n += strlen(nfrontp);  /* get count first */
22546809Sdab 	      nfrontp += strlen(nfrontp);  /* then move pointer */
22646809Sdab 	    });
22746809Sdab #if	defined(ENCRYPT)
22846809Sdab 	if (encrypt_output) {
22946809Sdab 		char *s = nclearto ? nclearto : nbackp;
23046809Sdab 		if (nfrontp - s > 0) {
23146809Sdab 			(*encrypt_output)((unsigned char *)s, nfrontp-s);
23246809Sdab 			nclearto = nfrontp;
23346809Sdab 		}
23444364Sborman 	}
23546809Sdab #endif
23638905Sborman 	/*
23738905Sborman 	 * if no urgent data, or if the other side appears to be an
23838905Sborman 	 * old 4.2 client (and thus unable to survive TCP urgent data),
23938905Sborman 	 * write the entire buffer in non-OOB mode.
24038905Sborman 	 */
24138905Sborman 	if ((neturg == 0) || (not42 == 0)) {
24238905Sborman 	    n = write(net, nbackp, n);	/* normal write */
24338905Sborman 	} else {
24438905Sborman 	    n = neturg - nbackp;
24538905Sborman 	    /*
24638905Sborman 	     * In 4.2 (and 4.3) systems, there is some question about
24738905Sborman 	     * what byte in a sendOOB operation is the "OOB" data.
24838905Sborman 	     * To make ourselves compatible, we only send ONE byte
24938905Sborman 	     * out of band, the one WE THINK should be OOB (though
25038905Sborman 	     * we really have more the TCP philosophy of urgent data
25138905Sborman 	     * rather than the Unix philosophy of OOB data).
25238905Sborman 	     */
25338905Sborman 	    if (n > 1) {
25438905Sborman 		n = send(net, nbackp, n-1, 0);	/* send URGENT all by itself */
25538905Sborman 	    } else {
25638905Sborman 		n = send(net, nbackp, n, MSG_OOB);	/* URGENT data */
25738905Sborman 	    }
25838905Sborman 	}
25938905Sborman     }
26038905Sborman     if (n < 0) {
26138905Sborman 	if (errno == EWOULDBLOCK || errno == EINTR)
26238905Sborman 		return;
26346809Sdab 	cleanup(0);
26438905Sborman     }
26538905Sborman     nbackp += n;
26646809Sdab #if	defined(ENCRYPT)
26746809Sdab     if (nbackp > nclearto)
26846809Sdab 	nclearto = 0;
26946809Sdab #endif
27038905Sborman     if (nbackp >= neturg) {
27138905Sborman 	neturg = 0;
27238905Sborman     }
27338905Sborman     if (nbackp == nfrontp) {
27438905Sborman 	nbackp = nfrontp = netobuf;
27546809Sdab #if	defined(ENCRYPT)
27646809Sdab 	nclearto = 0;
27746809Sdab #endif
27838905Sborman     }
27938905Sborman     return;
28038905Sborman }  /* end of netflush */
28138905Sborman 
28238905Sborman 
28338905Sborman /*
28438905Sborman  * writenet
28538905Sborman  *
28638905Sborman  * Just a handy little function to write a bit of raw data to the net.
28738905Sborman  * It will force a transmit of the buffer if necessary
28838905Sborman  *
28938905Sborman  * arguments
29038905Sborman  *    ptr - A pointer to a character string to write
29138905Sborman  *    len - How many bytes to write
29238905Sborman  */
29346809Sdab 	void
29438905Sborman writenet(ptr, len)
29546809Sdab 	register unsigned char *ptr;
29646809Sdab 	register int len;
29738905Sborman {
29838905Sborman 	/* flush buffer if no room for new data) */
29938905Sborman 	if ((&netobuf[BUFSIZ] - nfrontp) < len) {
30038905Sborman 		/* if this fails, don't worry, buffer is a little big */
30138905Sborman 		netflush();
30238905Sborman 	}
30338905Sborman 
30438905Sborman 	bcopy(ptr, nfrontp, len);
30538905Sborman 	nfrontp += len;
30638905Sborman 
30738905Sborman }  /* end of writenet */
30838905Sborman 
30938905Sborman 
31038905Sborman /*
31138905Sborman  * miscellaneous functions doing a variety of little jobs follow ...
31238905Sborman  */
31338905Sborman 
31438905Sborman 
31546809Sdab 	void
31638905Sborman fatal(f, msg)
31738905Sborman 	int f;
31838905Sborman 	char *msg;
31938905Sborman {
32038905Sborman 	char buf[BUFSIZ];
32138905Sborman 
32238905Sborman 	(void) sprintf(buf, "telnetd: %s.\r\n", msg);
32346809Sdab #if	defined(ENCRYPT)
32446809Sdab 	if (encrypt_output) {
32546809Sdab 		/*
32646809Sdab 		 * Better turn off encryption first....
32746809Sdab 		 * Hope it flushes...
32846809Sdab 		 */
32946809Sdab 		encrypt_send_end();
33046809Sdab 		netflush();
33146809Sdab 	}
33246809Sdab #endif
33338905Sborman 	(void) write(f, buf, (int)strlen(buf));
33438905Sborman 	sleep(1);	/*XXX*/
33538905Sborman 	exit(1);
33638905Sborman }
33738905Sborman 
33846809Sdab 	void
33938905Sborman fatalperror(f, msg)
34038905Sborman 	int f;
34138905Sborman 	char *msg;
34238905Sborman {
34342411Sbostic 	char buf[BUFSIZ], *strerror();
34438905Sborman 
34542411Sbostic 	(void) sprintf(buf, "%s: %s\r\n", msg, strerror(errno));
34638905Sborman 	fatal(f, buf);
34738905Sborman }
34838905Sborman 
34938905Sborman char editedhost[32];
35038905Sborman 
35146809Sdab 	void
35238905Sborman edithost(pat, host)
35338905Sborman 	register char *pat;
35438905Sborman 	register char *host;
35538905Sborman {
35638905Sborman 	register char *res = editedhost;
35738905Sborman 	char *strncpy();
35838905Sborman 
35938905Sborman 	if (!pat)
36038905Sborman 		pat = "";
36138905Sborman 	while (*pat) {
36238905Sborman 		switch (*pat) {
36338905Sborman 
36438905Sborman 		case '#':
36538905Sborman 			if (*host)
36638905Sborman 				host++;
36738905Sborman 			break;
36838905Sborman 
36938905Sborman 		case '@':
37038905Sborman 			if (*host)
37138905Sborman 				*res++ = *host++;
37238905Sborman 			break;
37338905Sborman 
37438905Sborman 		default:
37538905Sborman 			*res++ = *pat;
37638905Sborman 			break;
37738905Sborman 		}
37838905Sborman 		if (res == &editedhost[sizeof editedhost - 1]) {
37938905Sborman 			*res = '\0';
38038905Sborman 			return;
38138905Sborman 		}
38238905Sborman 		pat++;
38338905Sborman 	}
38438905Sborman 	if (*host)
38538905Sborman 		(void) strncpy(res, host,
38638905Sborman 				sizeof editedhost - (res - editedhost) -1);
38738905Sborman 	else
38838905Sborman 		*res = '\0';
38938905Sborman 	editedhost[sizeof editedhost - 1] = '\0';
39038905Sborman }
39138905Sborman 
39238905Sborman static char *putlocation;
39338905Sborman 
39446809Sdab 	void
39538905Sborman putstr(s)
39646809Sdab 	register char *s;
39738905Sborman {
39838905Sborman 
39938905Sborman 	while (*s)
40038905Sborman 		putchr(*s++);
40138905Sborman }
40238905Sborman 
40346809Sdab 	void
40438905Sborman putchr(cc)
40546809Sdab 	int cc;
40638905Sborman {
40738905Sborman 	*putlocation++ = cc;
40838905Sborman }
40938905Sborman 
41046809Sdab /*
41146809Sdab  * This is split on two lines so that SCCS will not see the M
41246809Sdab  * between two % signs and expand it...
41346809Sdab  */
41446809Sdab static char fmtstr[] = { "%l:%M\
41546809Sdab %P on %A, %d %B %Y" };
41646809Sdab 
41746809Sdab 	void
41838905Sborman putf(cp, where)
41946809Sdab 	register char *cp;
42046809Sdab 	char *where;
42138905Sborman {
42246809Sdab 	char *slash;
42346123Sbostic 	time_t t;
42446809Sdab 	char db[100];
42538905Sborman 	extern char *rindex();
42638905Sborman 
42738905Sborman 	putlocation = where;
42838905Sborman 
42938905Sborman 	while (*cp) {
43038905Sborman 		if (*cp != '%') {
43138905Sborman 			putchr(*cp++);
43238905Sborman 			continue;
43338905Sborman 		}
43438905Sborman 		switch (*++cp) {
43538905Sborman 
43638905Sborman 		case 't':
43738905Sborman 			slash = rindex(line, '/');
43838905Sborman 			if (slash == (char *) 0)
43938905Sborman 				putstr(line);
44038905Sborman 			else
44138905Sborman 				putstr(&slash[1]);
44238905Sborman 			break;
44338905Sborman 
44438905Sborman 		case 'h':
44538905Sborman 			putstr(editedhost);
44638905Sborman 			break;
44738905Sborman 
44846809Sdab 		case 'd':
44946123Sbostic 			(void)time(&t);
45046809Sdab 			(void)strftime(db, sizeof(db), fmtstr, localtime(&t));
45146123Sbostic 			putstr(db);
45238905Sborman 			break;
45338905Sborman 
45438905Sborman 		case '%':
45538905Sborman 			putchr('%');
45638905Sborman 			break;
45738905Sborman 		}
45838905Sborman 		cp++;
45938905Sborman 	}
46038905Sborman }
46138905Sborman 
46244364Sborman #ifdef DIAGNOSTICS
46344364Sborman /*
46444364Sborman  * Print telnet options and commands in plain text, if possible.
46544364Sborman  */
46646809Sdab 	void
46744364Sborman printoption(fmt, option)
46846809Sdab 	register char *fmt;
46946809Sdab 	register int option;
47044364Sborman {
47144364Sborman 	if (TELOPT_OK(option))
47244364Sborman 		sprintf(nfrontp, "%s %s\r\n", fmt, TELOPT(option));
47344364Sborman 	else if (TELCMD_OK(option))
47444364Sborman 		sprintf(nfrontp, "%s %s\r\n", fmt, TELCMD(option));
47544364Sborman 	else
47644364Sborman 		sprintf(nfrontp, "%s %d\r\n", fmt, option);
47744364Sborman 	nfrontp += strlen(nfrontp);
47844364Sborman 	return;
47944364Sborman }
48044364Sborman 
48146809Sdab     void
48246809Sdab printsub(direction, pointer, length)
48346809Sdab     char		direction;	/* '<' or '>' */
48446809Sdab     unsigned char	*pointer;	/* where suboption data sits */
48546809Sdab     int			length;		/* length of suboption data */
48644364Sborman {
48744364Sborman     register int i;
488*47611Sdab     char buf[512];
48944364Sborman 
49046809Sdab         if (!(diagnostic & TD_OPTIONS))
49146809Sdab 		return;
49246809Sdab 
49346809Sdab 	if (direction) {
49446809Sdab 	    sprintf(nfrontp, "td: %s suboption ",
49546809Sdab 					direction == '<' ? "recv" : "send");
49644364Sborman 	    nfrontp += strlen(nfrontp);
49744364Sborman 	    if (length >= 3) {
49844364Sborman 		register int j;
49944364Sborman 
50044364Sborman 		i = pointer[length-2];
50144364Sborman 		j = pointer[length-1];
50244364Sborman 
50344364Sborman 		if (i != IAC || j != SE) {
50444364Sborman 		    sprintf(nfrontp, "(terminated by ");
50544364Sborman 		    nfrontp += strlen(nfrontp);
50644364Sborman 		    if (TELOPT_OK(i))
50744364Sborman 			sprintf(nfrontp, "%s ", TELOPT(i));
50844364Sborman 		    else if (TELCMD_OK(i))
50944364Sborman 			sprintf(nfrontp, "%s ", TELCMD(i));
51044364Sborman 		    else
51144364Sborman 			sprintf(nfrontp, "%d ", i);
51244364Sborman 		    nfrontp += strlen(nfrontp);
51344364Sborman 		    if (TELOPT_OK(j))
51444364Sborman 			sprintf(nfrontp, "%s", TELOPT(j));
51544364Sborman 		    else if (TELCMD_OK(j))
51644364Sborman 			sprintf(nfrontp, "%s", TELCMD(j));
51744364Sborman 		    else
51844364Sborman 			sprintf(nfrontp, "%d", j);
51944364Sborman 		    nfrontp += strlen(nfrontp);
52044364Sborman 		    sprintf(nfrontp, ", not IAC SE!) ");
52144364Sborman 		    nfrontp += strlen(nfrontp);
52244364Sborman 		}
52344364Sborman 	    }
52444364Sborman 	    length -= 2;
52544364Sborman 	}
52644364Sborman 	if (length < 1) {
52744364Sborman 	    sprintf(nfrontp, "(Empty suboption???)");
52844364Sborman 	    nfrontp += strlen(nfrontp);
52944364Sborman 	    return;
53044364Sborman 	}
53144364Sborman 	switch (pointer[0]) {
53244364Sborman 	case TELOPT_TTYPE:
53344364Sborman 	    sprintf(nfrontp, "TERMINAL-TYPE ");
53444364Sborman 	    nfrontp += strlen(nfrontp);
53544364Sborman 	    switch (pointer[1]) {
53644364Sborman 	    case TELQUAL_IS:
53744364Sborman 		sprintf(nfrontp, "IS \"%.*s\"", length-2, (char *)pointer+2);
53844364Sborman 		break;
53944364Sborman 	    case TELQUAL_SEND:
54044364Sborman 		sprintf(nfrontp, "SEND");
54144364Sborman 		break;
54244364Sborman 	    default:
54344364Sborman 		sprintf(nfrontp,
54444364Sborman 				"- unknown qualifier %d (0x%x).",
54544364Sborman 				pointer[1], pointer[1]);
54644364Sborman 	    }
54744364Sborman 	    nfrontp += strlen(nfrontp);
54844364Sborman 	    break;
54944364Sborman 	case TELOPT_TSPEED:
55044364Sborman 	    sprintf(nfrontp, "TERMINAL-SPEED");
55144364Sborman 	    nfrontp += strlen(nfrontp);
55244364Sborman 	    if (length < 2) {
55344364Sborman 		sprintf(nfrontp, " (empty suboption???)");
55444364Sborman 		nfrontp += strlen(nfrontp);
55544364Sborman 		break;
55644364Sborman 	    }
55744364Sborman 	    switch (pointer[1]) {
55844364Sborman 	    case TELQUAL_IS:
55944364Sborman 		sprintf(nfrontp, " IS %.*s", length-2, (char *)pointer+2);
56044364Sborman 		nfrontp += strlen(nfrontp);
56144364Sborman 		break;
56244364Sborman 	    default:
56344364Sborman 		if (pointer[1] == 1)
56444364Sborman 		    sprintf(nfrontp, " SEND");
56544364Sborman 		else
56644364Sborman 		    sprintf(nfrontp, " %d (unknown)", pointer[1]);
56744364Sborman 		nfrontp += strlen(nfrontp);
56844364Sborman 		for (i = 2; i < length; i++) {
56944364Sborman 		    sprintf(nfrontp, " ?%d?", pointer[i]);
57044364Sborman 		    nfrontp += strlen(nfrontp);
57144364Sborman 		}
57244364Sborman 		break;
57344364Sborman 	    }
57444364Sborman 	    break;
57544364Sborman 
57644364Sborman 	case TELOPT_LFLOW:
57744364Sborman 	    sprintf(nfrontp, "TOGGLE-FLOW-CONTROL");
57844364Sborman 	    nfrontp += strlen(nfrontp);
57944364Sborman 	    if (length < 2) {
58044364Sborman 		sprintf(nfrontp, " (empty suboption???)");
58144364Sborman 		nfrontp += strlen(nfrontp);
58244364Sborman 		break;
58344364Sborman 	    }
58444364Sborman 	    switch (pointer[1]) {
58544364Sborman 	    case 0:
58644364Sborman 		sprintf(nfrontp, " OFF"); break;
58744364Sborman 	    case 1:
58844364Sborman 		sprintf(nfrontp, " ON"); break;
58944364Sborman 	    default:
59044364Sborman 		sprintf(nfrontp, " %d (unknown)", pointer[1]);
59144364Sborman 	    }
59244364Sborman 	    nfrontp += strlen(nfrontp);
59344364Sborman 	    for (i = 2; i < length; i++) {
59444364Sborman 		sprintf(nfrontp, " ?%d?", pointer[i]);
59544364Sborman 		nfrontp += strlen(nfrontp);
59644364Sborman 	    }
59744364Sborman 	    break;
59844364Sborman 
59944364Sborman 	case TELOPT_NAWS:
60044364Sborman 	    sprintf(nfrontp, "NAWS");
60144364Sborman 	    nfrontp += strlen(nfrontp);
60244364Sborman 	    if (length < 2) {
60344364Sborman 		sprintf(nfrontp, " (empty suboption???)");
60444364Sborman 		nfrontp += strlen(nfrontp);
60544364Sborman 		break;
60644364Sborman 	    }
60744364Sborman 	    if (length == 2) {
60844364Sborman 		sprintf(nfrontp, " ?%d?", pointer[1]);
60944364Sborman 		nfrontp += strlen(nfrontp);
61044364Sborman 		break;
61144364Sborman 	    }
61244364Sborman 	    sprintf(nfrontp, " %d %d (%d)",
61344364Sborman 		pointer[1], pointer[2],
61444364Sborman 		(int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2])));
61544364Sborman 	    nfrontp += strlen(nfrontp);
61644364Sborman 	    if (length == 4) {
61744364Sborman 		sprintf(nfrontp, " ?%d?", pointer[3]);
61844364Sborman 		nfrontp += strlen(nfrontp);
61944364Sborman 		break;
62044364Sborman 	    }
62144364Sborman 	    sprintf(nfrontp, " %d %d (%d)",
62244364Sborman 		pointer[3], pointer[4],
62344364Sborman 		(int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4])));
62444364Sborman 	    nfrontp += strlen(nfrontp);
62544364Sborman 	    for (i = 5; i < length; i++) {
62644364Sborman 		sprintf(nfrontp, " ?%d?", pointer[i]);
62744364Sborman 		nfrontp += strlen(nfrontp);
62844364Sborman 	    }
62944364Sborman 	    break;
63044364Sborman 
63144364Sborman 	case TELOPT_LINEMODE:
63244364Sborman 	    sprintf(nfrontp, "LINEMODE ");
63344364Sborman 	    nfrontp += strlen(nfrontp);
63444364Sborman 	    if (length < 2) {
63544364Sborman 		sprintf(nfrontp, " (empty suboption???)");
63644364Sborman 		nfrontp += strlen(nfrontp);
63744364Sborman 		break;
63844364Sborman 	    }
63944364Sborman 	    switch (pointer[1]) {
64044364Sborman 	    case WILL:
64144364Sborman 		sprintf(nfrontp, "WILL ");
64244364Sborman 		goto common;
64344364Sborman 	    case WONT:
64444364Sborman 		sprintf(nfrontp, "WONT ");
64544364Sborman 		goto common;
64644364Sborman 	    case DO:
64744364Sborman 		sprintf(nfrontp, "DO ");
64844364Sborman 		goto common;
64944364Sborman 	    case DONT:
65044364Sborman 		sprintf(nfrontp, "DONT ");
65144364Sborman 	    common:
65244364Sborman 		nfrontp += strlen(nfrontp);
65344364Sborman 		if (length < 3) {
65444364Sborman 		    sprintf(nfrontp, "(no option???)");
65544364Sborman 		    nfrontp += strlen(nfrontp);
65644364Sborman 		    break;
65744364Sborman 		}
65844364Sborman 		switch (pointer[2]) {
65944364Sborman 		case LM_FORWARDMASK:
66044364Sborman 		    sprintf(nfrontp, "Forward Mask");
66144364Sborman 		    nfrontp += strlen(nfrontp);
66244364Sborman 		    for (i = 3; i < length; i++) {
66344364Sborman 			sprintf(nfrontp, " %x", pointer[i]);
66444364Sborman 			nfrontp += strlen(nfrontp);
66544364Sborman 		    }
66644364Sborman 		    break;
66744364Sborman 		default:
66844364Sborman 		    sprintf(nfrontp, "%d (unknown)", pointer[2]);
66944364Sborman 		    nfrontp += strlen(nfrontp);
67044364Sborman 		    for (i = 3; i < length; i++) {
67144364Sborman 			sprintf(nfrontp, " %d", pointer[i]);
67244364Sborman 			nfrontp += strlen(nfrontp);
67344364Sborman 		    }
67444364Sborman 		    break;
67544364Sborman 		}
67644364Sborman 		break;
67744364Sborman 
67844364Sborman 	    case LM_SLC:
67944364Sborman 		sprintf(nfrontp, "SLC");
68044364Sborman 		nfrontp += strlen(nfrontp);
68144364Sborman 		for (i = 2; i < length - 2; i += 3) {
68246809Sdab 		    if (SLC_NAME_OK(pointer[i+SLC_FUNC]))
68346809Sdab 			sprintf(nfrontp, " %s", SLC_NAME(pointer[i+SLC_FUNC]));
68444364Sborman 		    else
68544364Sborman 			sprintf(nfrontp, " %d", pointer[i+SLC_FUNC]);
68644364Sborman 		    nfrontp += strlen(nfrontp);
68744364Sborman 		    switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) {
68844364Sborman 		    case SLC_NOSUPPORT:
68944364Sborman 			sprintf(nfrontp, " NOSUPPORT"); break;
69044364Sborman 		    case SLC_CANTCHANGE:
69144364Sborman 			sprintf(nfrontp, " CANTCHANGE"); break;
69244364Sborman 		    case SLC_VARIABLE:
69344364Sborman 			sprintf(nfrontp, " VARIABLE"); break;
69444364Sborman 		    case SLC_DEFAULT:
69544364Sborman 			sprintf(nfrontp, " DEFAULT"); break;
69644364Sborman 		    }
69744364Sborman 		    nfrontp += strlen(nfrontp);
69844364Sborman 		    sprintf(nfrontp, "%s%s%s",
69944364Sborman 			pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "",
70044364Sborman 			pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "",
70144364Sborman 			pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : "");
70244364Sborman 		    nfrontp += strlen(nfrontp);
70344364Sborman 		    if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN|
70444364Sborman 						SLC_FLUSHOUT| SLC_LEVELBITS)) {
70544364Sborman 			sprintf(nfrontp, "(0x%x)", pointer[i+SLC_FLAGS]);
70644364Sborman 			nfrontp += strlen(nfrontp);
70744364Sborman 		    }
70844364Sborman 		    sprintf(nfrontp, " %d;", pointer[i+SLC_VALUE]);
70944364Sborman 		    nfrontp += strlen(nfrontp);
71044364Sborman 		    if ((pointer[i+SLC_VALUE] == IAC) &&
71144364Sborman 			(pointer[i+SLC_VALUE+1] == IAC))
71244364Sborman 				i++;
71344364Sborman 		}
71444364Sborman 		for (; i < length; i++) {
71544364Sborman 		    sprintf(nfrontp, " ?%d?", pointer[i]);
71644364Sborman 		    nfrontp += strlen(nfrontp);
71744364Sborman 		}
71844364Sborman 		break;
71944364Sborman 
72044364Sborman 	    case LM_MODE:
72144364Sborman 		sprintf(nfrontp, "MODE ");
72244364Sborman 		nfrontp += strlen(nfrontp);
72344364Sborman 		if (length < 3) {
72444364Sborman 		    sprintf(nfrontp, "(no mode???)");
72544364Sborman 		    nfrontp += strlen(nfrontp);
72644364Sborman 		    break;
72744364Sborman 		}
72844364Sborman 		{
72944364Sborman 		    char tbuf[32];
73044364Sborman 		    sprintf(tbuf, "%s%s%s%s%s",
73144364Sborman 			pointer[2]&MODE_EDIT ? "|EDIT" : "",
73244364Sborman 			pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "",
73344364Sborman 			pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "",
73444364Sborman 			pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "",
73544364Sborman 			pointer[2]&MODE_ACK ? "|ACK" : "");
73644364Sborman 		    sprintf(nfrontp, "%s", tbuf[1] ? &tbuf[1] : "0");
73744364Sborman 		    nfrontp += strlen(nfrontp);
73844364Sborman 		}
73944364Sborman 		if (pointer[2]&~(MODE_EDIT|MODE_TRAPSIG|MODE_ACK)) {
74044364Sborman 		    sprintf(nfrontp, " (0x%x)", pointer[2]);
74144364Sborman 		    nfrontp += strlen(nfrontp);
74244364Sborman 		}
74344364Sborman 		for (i = 3; i < length; i++) {
74444364Sborman 		    sprintf(nfrontp, " ?0x%x?", pointer[i]);
74544364Sborman 		    nfrontp += strlen(nfrontp);
74644364Sborman 		}
74744364Sborman 		break;
74844364Sborman 	    default:
74944364Sborman 		sprintf(nfrontp, "%d (unknown)", pointer[1]);
75044364Sborman 		nfrontp += strlen(nfrontp);
75144364Sborman 		for (i = 2; i < length; i++) {
75244364Sborman 		    sprintf(nfrontp, " %d", pointer[i]);
75344364Sborman 		    nfrontp += strlen(nfrontp);
75444364Sborman 		}
75544364Sborman 	    }
75644364Sborman 	    break;
75744364Sborman 
75844364Sborman 	case TELOPT_STATUS: {
75944364Sborman 	    register char *cp;
76044364Sborman 	    register int j, k;
76144364Sborman 
76244364Sborman 	    sprintf(nfrontp, "STATUS");
76344364Sborman 	    nfrontp += strlen(nfrontp);
76444364Sborman 
76544364Sborman 	    switch (pointer[1]) {
76644364Sborman 	    default:
76744364Sborman 		if (pointer[1] == TELQUAL_SEND)
76844364Sborman 		    sprintf(nfrontp, " SEND");
76944364Sborman 		else
77044364Sborman 		    sprintf(nfrontp, " %d (unknown)", pointer[1]);
77144364Sborman 		nfrontp += strlen(nfrontp);
77244364Sborman 		for (i = 2; i < length; i++) {
77344364Sborman 		    sprintf(nfrontp, " ?%d?", pointer[i]);
77444364Sborman 		    nfrontp += strlen(nfrontp);
77544364Sborman 		}
77644364Sborman 		break;
77744364Sborman 	    case TELQUAL_IS:
77844364Sborman 		sprintf(nfrontp, " IS\r\n");
77944364Sborman 		nfrontp += strlen(nfrontp);
78044364Sborman 
78144364Sborman 		for (i = 2; i < length; i++) {
78244364Sborman 		    switch(pointer[i]) {
78344364Sborman 		    case DO:	cp = "DO"; goto common2;
78444364Sborman 		    case DONT:	cp = "DONT"; goto common2;
78544364Sborman 		    case WILL:	cp = "WILL"; goto common2;
78644364Sborman 		    case WONT:	cp = "WONT"; goto common2;
78744364Sborman 		    common2:
78844364Sborman 			i++;
78944364Sborman 			if (TELOPT_OK((int)pointer[i]))
79044364Sborman 			    sprintf(nfrontp, " %s %s", cp, TELOPT(pointer[i]));
79144364Sborman 			else
79244364Sborman 			    sprintf(nfrontp, " %s %d", cp, pointer[i]);
79344364Sborman 			nfrontp += strlen(nfrontp);
79444364Sborman 
79544364Sborman 			sprintf(nfrontp, "\r\n");
79644364Sborman 			nfrontp += strlen(nfrontp);
79744364Sborman 			break;
79844364Sborman 
79944364Sborman 		    case SB:
80044364Sborman 			sprintf(nfrontp, " SB ");
80144364Sborman 			nfrontp += strlen(nfrontp);
80244364Sborman 			i++;
80344364Sborman 			j = k = i;
80444364Sborman 			while (j < length) {
80544364Sborman 			    if (pointer[j] == SE) {
80644364Sborman 				if (j+1 == length)
80744364Sborman 				    break;
80844364Sborman 				if (pointer[j+1] == SE)
80944364Sborman 				    j++;
81044364Sborman 				else
81144364Sborman 				    break;
81244364Sborman 			    }
81344364Sborman 			    pointer[k++] = pointer[j++];
81444364Sborman 			}
81544364Sborman 			printsub(0, &pointer[i], k - i);
81644364Sborman 			if (i < length) {
81744364Sborman 			    sprintf(nfrontp, " SE");
81844364Sborman 			    nfrontp += strlen(nfrontp);
81944364Sborman 			    i = j;
82044364Sborman 			} else
82144364Sborman 			    i = j - 1;
82244364Sborman 
82344364Sborman 			sprintf(nfrontp, "\r\n");
82444364Sborman 			nfrontp += strlen(nfrontp);
82544364Sborman 
82644364Sborman 			break;
82744364Sborman 
82844364Sborman 		    default:
82944364Sborman 			sprintf(nfrontp, " %d", pointer[i]);
83044364Sborman 			nfrontp += strlen(nfrontp);
83144364Sborman 			break;
83244364Sborman 		    }
83344364Sborman 		}
83444364Sborman 		break;
83544364Sborman 	    }
83644364Sborman 	    break;
83744364Sborman 	  }
83844364Sborman 
83944364Sborman 	case TELOPT_XDISPLOC:
84044364Sborman 	    sprintf(nfrontp, "X-DISPLAY-LOCATION ");
84144364Sborman 	    nfrontp += strlen(nfrontp);
84244364Sborman 	    switch (pointer[1]) {
84344364Sborman 	    case TELQUAL_IS:
84444364Sborman 		sprintf(nfrontp, "IS \"%.*s\"", length-2, (char *)pointer+2);
84544364Sborman 		break;
84644364Sborman 	    case TELQUAL_SEND:
84744364Sborman 		sprintf(nfrontp, "SEND");
84844364Sborman 		break;
84944364Sborman 	    default:
85044364Sborman 		sprintf(nfrontp, "- unknown qualifier %d (0x%x).",
85144364Sborman 				pointer[1], pointer[1]);
85244364Sborman 	    }
85344364Sborman 	    nfrontp += strlen(nfrontp);
85444364Sborman 	    break;
85544364Sborman 
85644364Sborman 	case TELOPT_ENVIRON:
85744364Sborman 	    sprintf(nfrontp, "ENVIRON ");
85844364Sborman 	    nfrontp += strlen(nfrontp);
85944364Sborman 	    switch (pointer[1]) {
86044364Sborman 	    case TELQUAL_IS:
86144364Sborman 		sprintf(nfrontp, "IS ");
86244364Sborman 		goto env_common;
86344364Sborman 	    case TELQUAL_SEND:
86444364Sborman 		sprintf(nfrontp, "SEND ");
86544364Sborman 		goto env_common;
86644364Sborman 	    case TELQUAL_INFO:
86744364Sborman 		sprintf(nfrontp, "INFO ");
86844364Sborman 	    env_common:
86944364Sborman 	    nfrontp += strlen(nfrontp);
87044364Sborman 		{
87144364Sborman 		    register int noquote = 2;
87244364Sborman 		    for (i = 2; i < length; i++ ) {
87344364Sborman 			switch (pointer[i]) {
87444364Sborman 			case ENV_VAR:
87544364Sborman 			    if (pointer[1] == TELQUAL_SEND)
87644364Sborman 				goto def_case;
87744364Sborman 			    sprintf(nfrontp, "\" VAR " + noquote);
87844364Sborman 			    nfrontp += strlen(nfrontp);
87944364Sborman 			    noquote = 2;
88044364Sborman 			    break;
88144364Sborman 
88244364Sborman 			case ENV_VALUE:
88344364Sborman 			    sprintf(nfrontp, "\" VALUE " + noquote);
88444364Sborman 			    nfrontp += strlen(nfrontp);
88544364Sborman 			    noquote = 2;
88644364Sborman 			    break;
88744364Sborman 
88844364Sborman 			case ENV_ESC:
88944364Sborman 			    sprintf(nfrontp, "\" ESC " + noquote);
89044364Sborman 			    nfrontp += strlen(nfrontp);
89144364Sborman 			    noquote = 2;
89244364Sborman 			    break;
89344364Sborman 
89444364Sborman 			default:
89544364Sborman 			def_case:
89644364Sborman 			    if (isprint(pointer[i]) && pointer[i] != '"') {
89744364Sborman 				if (noquote) {
89844364Sborman 				    *nfrontp++ = '"';
89944364Sborman 				    noquote = 0;
90044364Sborman 				}
90144364Sborman 				*nfrontp++ = pointer[i];
90244364Sborman 			    } else {
90344364Sborman 				sprintf(nfrontp, "\" %03o " + noquote,
90444364Sborman 							pointer[i]);
90544364Sborman 				nfrontp += strlen(nfrontp);
90644364Sborman 				noquote = 2;
90744364Sborman 			    }
90844364Sborman 			    break;
90944364Sborman 			}
91044364Sborman 		    }
91144364Sborman 		    if (!noquote)
91244364Sborman 			*nfrontp++ = '"';
91344364Sborman 		    break;
91444364Sborman 		}
91544364Sborman 	    }
91644364Sborman 	    break;
91744364Sborman 
91846809Sdab #if	defined(AUTHENTICATE)
91946809Sdab 	case TELOPT_AUTHENTICATION:
92046809Sdab 	    sprintf(nfrontp, "AUTHENTICATION");
92146809Sdab 	    nfrontp += strlen(nfrontp);
92246809Sdab 
92346809Sdab 	    if (length < 2) {
92446809Sdab 		sprintf(nfrontp, " (empty suboption???)");
92546809Sdab 		nfrontp += strlen(nfrontp);
92646809Sdab 		break;
92746809Sdab 	    }
92846809Sdab 	    switch (pointer[1]) {
92946809Sdab 	    case TELQUAL_REPLY:
93046809Sdab 	    case TELQUAL_IS:
93146809Sdab 		sprintf(nfrontp, " %s ", (pointer[1] == TELQUAL_IS) ?
93246809Sdab 							"IS" : "REPLY");
93346809Sdab 		nfrontp += strlen(nfrontp);
93446809Sdab 		if (AUTHTYPE_NAME_OK(pointer[2]))
93546809Sdab 		    sprintf(nfrontp, "%s ", AUTHTYPE_NAME(pointer[2]));
93646809Sdab 		else
93746809Sdab 		    sprintf(nfrontp, "%d ", pointer[2]);
93846809Sdab 		nfrontp += strlen(nfrontp);
93946809Sdab 		if (length < 3) {
94046809Sdab 		    sprintf(nfrontp, "(partial suboption???)");
94146809Sdab 		    nfrontp += strlen(nfrontp);
94246809Sdab 		    break;
94346809Sdab 		}
94446809Sdab 		sprintf(nfrontp, "%s|%s",
945*47611Sdab 			((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
94646809Sdab 			"CLIENT" : "SERVER",
947*47611Sdab 			((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
94846809Sdab 			"MUTUAL" : "ONE-WAY");
94946809Sdab 		nfrontp += strlen(nfrontp);
95046809Sdab 
95146809Sdab 		auth_printsub(&pointer[1], length - 1, buf, sizeof(buf));
95246809Sdab 		sprintf(nfrontp, "%s", buf);
95346809Sdab 		nfrontp += strlen(nfrontp);
95446809Sdab 		break;
95546809Sdab 
95646809Sdab 	    case TELQUAL_SEND:
95746809Sdab 		i = 2;
95846809Sdab 		sprintf(nfrontp, " SEND ");
95946809Sdab 		nfrontp += strlen(nfrontp);
96046809Sdab 		while (i < length) {
96146809Sdab 		    if (AUTHTYPE_NAME_OK(pointer[i]))
96246809Sdab 			sprintf(nfrontp, "%s ", AUTHTYPE_NAME(pointer[i]));
96346809Sdab 		    else
96446809Sdab 			sprintf(nfrontp, "%d ", pointer[i]);
96546809Sdab 		    nfrontp += strlen(nfrontp);
96646809Sdab 		    if (++i >= length) {
96746809Sdab 			sprintf(nfrontp, "(partial suboption???)");
96846809Sdab 			nfrontp += strlen(nfrontp);
96946809Sdab 			break;
97046809Sdab 		    }
97146809Sdab 		    sprintf(nfrontp, "%s|%s ",
972*47611Sdab 			((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
97346809Sdab 							"CLIENT" : "SERVER",
974*47611Sdab 			((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
97546809Sdab 							"MUTUAL" : "ONE-WAY");
97646809Sdab 		    nfrontp += strlen(nfrontp);
97746809Sdab 		    ++i;
97846809Sdab 		}
97946809Sdab 		break;
98046809Sdab 
981*47611Sdab 	    case TELQUAL_NAME:
982*47611Sdab 		i = 2;
983*47611Sdab 		sprintf(nfrontp, " NAME \"");
984*47611Sdab 		nfrontp += strlen(nfrontp);
985*47611Sdab 		while (i < length)
986*47611Sdab 		    *nfrontp += pointer[i++];
987*47611Sdab 		*nfrontp += '"';
988*47611Sdab 		break;
989*47611Sdab 
99046809Sdab 	    default:
99146809Sdab 		    for (i = 2; i < length; i++) {
99246809Sdab 			sprintf(nfrontp, " ?%d?", pointer[i]);
99346809Sdab 			nfrontp += strlen(nfrontp);
99446809Sdab 		    }
99546809Sdab 		    break;
99646809Sdab 	    }
99746809Sdab 	    break;
99846809Sdab #endif
99946809Sdab 
100046809Sdab #if	defined(ENCRYPT)
100146809Sdab 	case TELOPT_ENCRYPT:
100246809Sdab 	    sprintf(nfrontp, "ENCRYPT");
100346809Sdab 	    nfrontp += strlen(nfrontp);
100446809Sdab 	    if (length < 2) {
100546809Sdab 		sprintf(nfrontp, " (empty suboption???)");
100646809Sdab 		nfrontp += strlen(nfrontp);
100746809Sdab 		break;
100846809Sdab 	    }
100946809Sdab 	    switch (pointer[1]) {
101046809Sdab 	    case ENCRYPT_START:
101146809Sdab 		sprintf(nfrontp, " START");
101246809Sdab 		nfrontp += strlen(nfrontp);
101346809Sdab 		break;
101446809Sdab 
101546809Sdab 	    case ENCRYPT_END:
101646809Sdab 		sprintf(nfrontp, " END");
101746809Sdab 		nfrontp += strlen(nfrontp);
101846809Sdab 		break;
101946809Sdab 
102046809Sdab 	    case ENCRYPT_REQSTART:
102146809Sdab 		sprintf(nfrontp, " REQUEST-START");
102246809Sdab 		nfrontp += strlen(nfrontp);
102346809Sdab 		break;
102446809Sdab 
102546809Sdab 	    case ENCRYPT_REQEND:
102646809Sdab 		sprintf(nfrontp, " REQUEST-END");
102746809Sdab 		nfrontp += strlen(nfrontp);
102846809Sdab 		break;
102946809Sdab 
103046809Sdab 	    case ENCRYPT_IS:
103146809Sdab 	    case ENCRYPT_REPLY:
103246809Sdab 		sprintf(nfrontp, " %s ", (pointer[1] == ENCRYPT_IS) ?
103346809Sdab 							"IS" : "REPLY");
103446809Sdab 		nfrontp += strlen(nfrontp);
103546809Sdab 		if (length < 3) {
103646809Sdab 		    sprintf(nfrontp, " (partial suboption???)");
103746809Sdab 		    nfrontp += strlen(nfrontp);
103846809Sdab 		    break;
103946809Sdab 		}
104046809Sdab 		if (ENCTYPE_NAME_OK(pointer[2]))
104146809Sdab 		    sprintf(nfrontp, "%s ", ENCTYPE_NAME(pointer[2]));
104246809Sdab 		else
104346809Sdab 		    sprintf(nfrontp, " %d (unknown)", pointer[2]);
104446809Sdab 		nfrontp += strlen(nfrontp);
104546809Sdab 
104646809Sdab 		encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf));
104746809Sdab 		sprintf(nfrontp, "%s", buf);
104846809Sdab 		nfrontp += strlen(nfrontp);
104946809Sdab 		break;
105046809Sdab 
105146809Sdab 	    case ENCRYPT_SUPPORT:
105246809Sdab 		i = 2;
105346809Sdab 		sprintf(nfrontp, " SUPPORT ");
105446809Sdab 		nfrontp += strlen(nfrontp);
105546809Sdab 		while (i < length) {
105646809Sdab 		    if (ENCTYPE_NAME_OK(pointer[i]))
105746809Sdab 			sprintf(nfrontp, "%s ", ENCTYPE_NAME(pointer[i]));
105846809Sdab 		    else
105946809Sdab 			sprintf(nfrontp, "%d ", pointer[i]);
106046809Sdab 		    nfrontp += strlen(nfrontp);
106146809Sdab 		    i++;
106246809Sdab 		}
106346809Sdab 		break;
106446809Sdab 
1065*47611Sdab 	    case ENCRYPT_ENC_KEYID:
1066*47611Sdab 		sprintf(nfrontp, " ENC_KEYID", pointer[1]);
1067*47611Sdab 		nfrontp += strlen(nfrontp);
1068*47611Sdab 		goto encommon;
1069*47611Sdab 
1070*47611Sdab 	    case ENCRYPT_DEC_KEYID:
1071*47611Sdab 		sprintf(nfrontp, " DEC_KEYID", pointer[1]);
1072*47611Sdab 		nfrontp += strlen(nfrontp);
1073*47611Sdab 		goto encommon;
1074*47611Sdab 
107546809Sdab 	    default:
1076*47611Sdab 		sprintf(nfrontp, " %d (unknown)", pointer[1]);
107746809Sdab 		nfrontp += strlen(nfrontp);
1078*47611Sdab 	    encommon:
107946809Sdab 		for (i = 2; i < length; i++) {
108046809Sdab 		    sprintf(nfrontp, " %d", pointer[i]);
108146809Sdab 		    nfrontp += strlen(nfrontp);
108246809Sdab 		}
108346809Sdab 		break;
108446809Sdab 	    }
108546809Sdab 	    break;
108646809Sdab #endif
108746809Sdab 
108844364Sborman 	default:
108946809Sdab 	    if (TELOPT_OK(pointer[0]))
109046809Sdab 	        sprintf(nfrontp, "%s (unknown)", TELOPT(pointer[0]));
109146809Sdab 	    else
109246809Sdab 	        sprintf(nfrontp, "%d (unknown)", pointer[i]);
109344364Sborman 	    nfrontp += strlen(nfrontp);
109446809Sdab 	    for (i = 1; i < length; i++) {
109544364Sborman 		sprintf(nfrontp, " %d", pointer[i]);
109644364Sborman 		nfrontp += strlen(nfrontp);
109744364Sborman 	    }
109844364Sborman 	    break;
109944364Sborman 	}
110044364Sborman 	sprintf(nfrontp, "\r\n");
110144364Sborman 	nfrontp += strlen(nfrontp);
110244364Sborman }
110344364Sborman 
110444364Sborman /*
110544364Sborman  * Dump a data buffer in hex and ascii to the output data stream.
110644364Sborman  */
110746809Sdab 	void
110844364Sborman printdata(tag, ptr, cnt)
110946809Sdab 	register char *tag;
111046809Sdab 	register char *ptr;
111146809Sdab 	register int cnt;
111244364Sborman {
111346809Sdab 	register int i;
111446809Sdab 	char xbuf[30];
111544364Sborman 
111644364Sborman 	while (cnt) {
111744364Sborman 		/* flush net output buffer if no room for new data) */
111844364Sborman 		if ((&netobuf[BUFSIZ] - nfrontp) < 80) {
111944364Sborman 			netflush();
112044364Sborman 		}
112144364Sborman 
112244364Sborman 		/* add a line of output */
112344364Sborman 		sprintf(nfrontp, "%s: ", tag);
112444364Sborman 		nfrontp += strlen(nfrontp);
112544364Sborman 		for (i = 0; i < 20 && cnt; i++) {
112644364Sborman 			sprintf(nfrontp, "%02x", *ptr);
112744364Sborman 			nfrontp += strlen(nfrontp);
112844364Sborman 			if (isprint(*ptr)) {
112944364Sborman 				xbuf[i] = *ptr;
113044364Sborman 			} else {
113144364Sborman 				xbuf[i] = '.';
113244364Sborman 			}
113344364Sborman 			if (i % 2) {
113444364Sborman 				*nfrontp = ' ';
113544364Sborman 				nfrontp++;
113644364Sborman 			}
113744364Sborman 			cnt--;
113844364Sborman 			ptr++;
113944364Sborman 		}
114044364Sborman 		xbuf[i] = '\0';
114144364Sborman 		sprintf(nfrontp, " %s\r\n", xbuf );
114244364Sborman 		nfrontp += strlen(nfrontp);
114344364Sborman 	}
114444364Sborman }
114544364Sborman #endif /* DIAGNOSTICS */
1146