xref: /csrg-svn/libexec/telnetd/utility.c (revision 69786)
138905Sborman /*
261451Sbostic  * Copyright (c) 1989, 1993
361451Sbostic  *	The Regents of the University of California.  All rights reserved.
438905Sborman  *
542673Sbostic  * %sccs.include.redist.c%
638905Sborman  */
738905Sborman 
838905Sborman #ifndef lint
9*69786Sdab static char sccsid[] = "@(#)utility.c	8.4 (Berkeley) 05/30/95";
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
ttloop()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
stilloob(s)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
ptyflush()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 *
nextitem(current)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
netclear()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 
17060151Sdab #ifdef	ENCRYPTION
17146809Sdab     thisitem = nclearto > netobuf ? nclearto : netobuf;
17260151Sdab #else	/* ENCRYPTION */
17338905Sborman     thisitem = netobuf;
17460151Sdab #endif	/* ENCRYPTION */
17538905Sborman 
17638905Sborman     while ((next = nextitem(thisitem)) <= nbackp) {
17738905Sborman 	thisitem = next;
17838905Sborman     }
17938905Sborman 
18038905Sborman     /* Now, thisitem is first before/at boundary. */
18138905Sborman 
18260151Sdab #ifdef	ENCRYPTION
18346809Sdab     good = nclearto > netobuf ? nclearto : netobuf;
18460151Sdab #else	/* ENCRYPTION */
18538905Sborman     good = netobuf;	/* where the good bytes go */
18660151Sdab #endif	/* ENCRYPTION */
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;
197*69786Sdab 	    memmove(good, thisitem, 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
netflush()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 	    });
22760151Sdab #ifdef	ENCRYPTION
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 	}
23560151Sdab #endif	/* ENCRYPTION */
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;
26660151Sdab #ifdef	ENCRYPTION
26746809Sdab     if (nbackp > nclearto)
26846809Sdab 	nclearto = 0;
26960151Sdab #endif	/* ENCRYPTION */
27038905Sborman     if (nbackp >= neturg) {
27138905Sborman 	neturg = 0;
27238905Sborman     }
27338905Sborman     if (nbackp == nfrontp) {
27438905Sborman 	nbackp = nfrontp = netobuf;
27560151Sdab #ifdef	ENCRYPTION
27646809Sdab 	nclearto = 0;
27760151Sdab #endif	/* ENCRYPTION */
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
writenet(ptr,len)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 
304*69786Sdab 	memmove(nfrontp, ptr, 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
fatal(f,msg)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);
32360151Sdab #ifdef	ENCRYPTION
32446809Sdab 	if (encrypt_output) {
32546809Sdab 		/*
32646809Sdab 		 * Better turn off encryption first....
32746809Sdab 		 * Hope it flushes...
32846809Sdab 		 */
32946809Sdab 		encrypt_send_end();
33046809Sdab 		netflush();
33146809Sdab 	}
33260151Sdab #endif	/* ENCRYPTION */
33338905Sborman 	(void) write(f, buf, (int)strlen(buf));
33438905Sborman 	sleep(1);	/*XXX*/
33538905Sborman 	exit(1);
33638905Sborman }
33738905Sborman 
33846809Sdab 	void
fatalperror(f,msg)33938905Sborman fatalperror(f, msg)
34038905Sborman 	int f;
34138905Sborman 	char *msg;
34238905Sborman {
34342411Sbostic 	char buf[BUFSIZ], *strerror();
34438905Sborman 
34568585Sdab 	(void) sprintf(buf, "%s: %s", msg, strerror(errno));
34638905Sborman 	fatal(f, buf);
34738905Sborman }
34838905Sborman 
34938905Sborman char editedhost[32];
35038905Sborman 
35146809Sdab 	void
edithost(pat,host)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
putstr(s)39538905Sborman putstr(s)
39646809Sdab 	register char *s;
39738905Sborman {
39838905Sborman 
39938905Sborman 	while (*s)
40038905Sborman 		putchr(*s++);
40138905Sborman }
40238905Sborman 
40346809Sdab 	void
putchr(cc)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
putf(cp,where)41838905Sborman putf(cp, where)
41946809Sdab 	register char *cp;
42046809Sdab 	char *where;
42138905Sborman {
42246809Sdab 	char *slash;
42346123Sbostic 	time_t t;
42446809Sdab 	char db[100];
42565158Sdab #ifdef	STREAMSPTY
426*69786Sdab 	extern char *strchr();
42765158Sdab #else
428*69786Sdab 	extern char *strrchr();
42965158Sdab #endif
43038905Sborman 
43138905Sborman 	putlocation = where;
43238905Sborman 
43338905Sborman 	while (*cp) {
43438905Sborman 		if (*cp != '%') {
43538905Sborman 			putchr(*cp++);
43638905Sborman 			continue;
43738905Sborman 		}
43838905Sborman 		switch (*++cp) {
43938905Sborman 
44038905Sborman 		case 't':
44157212Sdab #ifdef	STREAMSPTY
44257212Sdab 			/* names are like /dev/pts/2 -- we want pts/2 */
443*69786Sdab 			slash = strchr(line+1, '/');
44457212Sdab #else
445*69786Sdab 			slash = strrchr(line, '/');
44657212Sdab #endif
44738905Sborman 			if (slash == (char *) 0)
44838905Sborman 				putstr(line);
44938905Sborman 			else
45038905Sborman 				putstr(&slash[1]);
45138905Sborman 			break;
45238905Sborman 
45338905Sborman 		case 'h':
45438905Sborman 			putstr(editedhost);
45538905Sborman 			break;
45638905Sborman 
45746809Sdab 		case 'd':
45846123Sbostic 			(void)time(&t);
45946809Sdab 			(void)strftime(db, sizeof(db), fmtstr, localtime(&t));
46046123Sbostic 			putstr(db);
46138905Sborman 			break;
46238905Sborman 
46338905Sborman 		case '%':
46438905Sborman 			putchr('%');
46538905Sborman 			break;
46638905Sborman 		}
46738905Sborman 		cp++;
46838905Sborman 	}
46938905Sborman }
47038905Sborman 
47144364Sborman #ifdef DIAGNOSTICS
47244364Sborman /*
47344364Sborman  * Print telnet options and commands in plain text, if possible.
47444364Sborman  */
47546809Sdab 	void
printoption(fmt,option)47644364Sborman printoption(fmt, option)
47746809Sdab 	register char *fmt;
47846809Sdab 	register int option;
47944364Sborman {
48044364Sborman 	if (TELOPT_OK(option))
48144364Sborman 		sprintf(nfrontp, "%s %s\r\n", fmt, TELOPT(option));
48244364Sborman 	else if (TELCMD_OK(option))
48344364Sborman 		sprintf(nfrontp, "%s %s\r\n", fmt, TELCMD(option));
48444364Sborman 	else
48544364Sborman 		sprintf(nfrontp, "%s %d\r\n", fmt, option);
48644364Sborman 	nfrontp += strlen(nfrontp);
48744364Sborman 	return;
48844364Sborman }
48944364Sborman 
49046809Sdab     void
printsub(direction,pointer,length)49146809Sdab printsub(direction, pointer, length)
49246809Sdab     char		direction;	/* '<' or '>' */
49346809Sdab     unsigned char	*pointer;	/* where suboption data sits */
49446809Sdab     int			length;		/* length of suboption data */
49544364Sborman {
49644364Sborman     register int i;
49747611Sdab     char buf[512];
49844364Sborman 
499*69786Sdab 	if (!(diagnostic & TD_OPTIONS))
50046809Sdab 		return;
50146809Sdab 
50246809Sdab 	if (direction) {
50346809Sdab 	    sprintf(nfrontp, "td: %s suboption ",
50446809Sdab 					direction == '<' ? "recv" : "send");
50544364Sborman 	    nfrontp += strlen(nfrontp);
50644364Sborman 	    if (length >= 3) {
50744364Sborman 		register int j;
50844364Sborman 
50944364Sborman 		i = pointer[length-2];
51044364Sborman 		j = pointer[length-1];
51144364Sborman 
51244364Sborman 		if (i != IAC || j != SE) {
51344364Sborman 		    sprintf(nfrontp, "(terminated by ");
51444364Sborman 		    nfrontp += strlen(nfrontp);
51544364Sborman 		    if (TELOPT_OK(i))
51644364Sborman 			sprintf(nfrontp, "%s ", TELOPT(i));
51744364Sborman 		    else if (TELCMD_OK(i))
51844364Sborman 			sprintf(nfrontp, "%s ", TELCMD(i));
51944364Sborman 		    else
52044364Sborman 			sprintf(nfrontp, "%d ", i);
52144364Sborman 		    nfrontp += strlen(nfrontp);
52244364Sborman 		    if (TELOPT_OK(j))
52344364Sborman 			sprintf(nfrontp, "%s", TELOPT(j));
52444364Sborman 		    else if (TELCMD_OK(j))
52544364Sborman 			sprintf(nfrontp, "%s", TELCMD(j));
52644364Sborman 		    else
52744364Sborman 			sprintf(nfrontp, "%d", j);
52844364Sborman 		    nfrontp += strlen(nfrontp);
52944364Sborman 		    sprintf(nfrontp, ", not IAC SE!) ");
53044364Sborman 		    nfrontp += strlen(nfrontp);
53144364Sborman 		}
53244364Sborman 	    }
53344364Sborman 	    length -= 2;
53444364Sborman 	}
53544364Sborman 	if (length < 1) {
53665158Sdab 	    sprintf(nfrontp, "(Empty suboption??\?)");
53744364Sborman 	    nfrontp += strlen(nfrontp);
53844364Sborman 	    return;
53944364Sborman 	}
54044364Sborman 	switch (pointer[0]) {
54144364Sborman 	case TELOPT_TTYPE:
54244364Sborman 	    sprintf(nfrontp, "TERMINAL-TYPE ");
54344364Sborman 	    nfrontp += strlen(nfrontp);
54444364Sborman 	    switch (pointer[1]) {
54544364Sborman 	    case TELQUAL_IS:
54644364Sborman 		sprintf(nfrontp, "IS \"%.*s\"", length-2, (char *)pointer+2);
54744364Sborman 		break;
54844364Sborman 	    case TELQUAL_SEND:
54944364Sborman 		sprintf(nfrontp, "SEND");
55044364Sborman 		break;
55144364Sborman 	    default:
55244364Sborman 		sprintf(nfrontp,
55344364Sborman 				"- unknown qualifier %d (0x%x).",
55444364Sborman 				pointer[1], pointer[1]);
55544364Sborman 	    }
55644364Sborman 	    nfrontp += strlen(nfrontp);
55744364Sborman 	    break;
55844364Sborman 	case TELOPT_TSPEED:
55944364Sborman 	    sprintf(nfrontp, "TERMINAL-SPEED");
56044364Sborman 	    nfrontp += strlen(nfrontp);
56144364Sborman 	    if (length < 2) {
56265158Sdab 		sprintf(nfrontp, " (empty suboption??\?)");
56344364Sborman 		nfrontp += strlen(nfrontp);
56444364Sborman 		break;
56544364Sborman 	    }
56644364Sborman 	    switch (pointer[1]) {
56744364Sborman 	    case TELQUAL_IS:
56844364Sborman 		sprintf(nfrontp, " IS %.*s", length-2, (char *)pointer+2);
56944364Sborman 		nfrontp += strlen(nfrontp);
57044364Sborman 		break;
57144364Sborman 	    default:
57244364Sborman 		if (pointer[1] == 1)
57344364Sborman 		    sprintf(nfrontp, " SEND");
57444364Sborman 		else
57544364Sborman 		    sprintf(nfrontp, " %d (unknown)", pointer[1]);
57644364Sborman 		nfrontp += strlen(nfrontp);
57744364Sborman 		for (i = 2; i < length; i++) {
57844364Sborman 		    sprintf(nfrontp, " ?%d?", pointer[i]);
57944364Sborman 		    nfrontp += strlen(nfrontp);
58044364Sborman 		}
58144364Sborman 		break;
58244364Sborman 	    }
58344364Sborman 	    break;
58444364Sborman 
58544364Sborman 	case TELOPT_LFLOW:
58644364Sborman 	    sprintf(nfrontp, "TOGGLE-FLOW-CONTROL");
58744364Sborman 	    nfrontp += strlen(nfrontp);
58844364Sborman 	    if (length < 2) {
58965158Sdab 		sprintf(nfrontp, " (empty suboption??\?)");
59044364Sborman 		nfrontp += strlen(nfrontp);
59144364Sborman 		break;
59244364Sborman 	    }
59344364Sborman 	    switch (pointer[1]) {
59457597Sdab 	    case LFLOW_OFF:
59544364Sborman 		sprintf(nfrontp, " OFF"); break;
59657597Sdab 	    case LFLOW_ON:
59744364Sborman 		sprintf(nfrontp, " ON"); break;
59857597Sdab 	    case LFLOW_RESTART_ANY:
59957597Sdab 		sprintf(nfrontp, " RESTART-ANY"); break;
60057597Sdab 	    case LFLOW_RESTART_XON:
60157597Sdab 		sprintf(nfrontp, " RESTART-XON"); break;
60244364Sborman 	    default:
60344364Sborman 		sprintf(nfrontp, " %d (unknown)", pointer[1]);
60444364Sborman 	    }
60544364Sborman 	    nfrontp += strlen(nfrontp);
60644364Sborman 	    for (i = 2; i < length; i++) {
60744364Sborman 		sprintf(nfrontp, " ?%d?", pointer[i]);
60844364Sborman 		nfrontp += strlen(nfrontp);
60944364Sborman 	    }
61044364Sborman 	    break;
61144364Sborman 
61244364Sborman 	case TELOPT_NAWS:
61344364Sborman 	    sprintf(nfrontp, "NAWS");
61444364Sborman 	    nfrontp += strlen(nfrontp);
61544364Sborman 	    if (length < 2) {
61665158Sdab 		sprintf(nfrontp, " (empty suboption??\?)");
61744364Sborman 		nfrontp += strlen(nfrontp);
61844364Sborman 		break;
61944364Sborman 	    }
62044364Sborman 	    if (length == 2) {
62144364Sborman 		sprintf(nfrontp, " ?%d?", pointer[1]);
62244364Sborman 		nfrontp += strlen(nfrontp);
62344364Sborman 		break;
62444364Sborman 	    }
62544364Sborman 	    sprintf(nfrontp, " %d %d (%d)",
62644364Sborman 		pointer[1], pointer[2],
62744364Sborman 		(int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2])));
62844364Sborman 	    nfrontp += strlen(nfrontp);
62944364Sborman 	    if (length == 4) {
63044364Sborman 		sprintf(nfrontp, " ?%d?", pointer[3]);
63144364Sborman 		nfrontp += strlen(nfrontp);
63244364Sborman 		break;
63344364Sborman 	    }
63444364Sborman 	    sprintf(nfrontp, " %d %d (%d)",
63544364Sborman 		pointer[3], pointer[4],
63644364Sborman 		(int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4])));
63744364Sborman 	    nfrontp += strlen(nfrontp);
63844364Sborman 	    for (i = 5; i < length; i++) {
63944364Sborman 		sprintf(nfrontp, " ?%d?", pointer[i]);
64044364Sborman 		nfrontp += strlen(nfrontp);
64144364Sborman 	    }
64244364Sborman 	    break;
64344364Sborman 
64444364Sborman 	case TELOPT_LINEMODE:
64544364Sborman 	    sprintf(nfrontp, "LINEMODE ");
64644364Sborman 	    nfrontp += strlen(nfrontp);
64744364Sborman 	    if (length < 2) {
64865158Sdab 		sprintf(nfrontp, " (empty suboption??\?)");
64944364Sborman 		nfrontp += strlen(nfrontp);
65044364Sborman 		break;
65144364Sborman 	    }
65244364Sborman 	    switch (pointer[1]) {
65344364Sborman 	    case WILL:
65444364Sborman 		sprintf(nfrontp, "WILL ");
65544364Sborman 		goto common;
65644364Sborman 	    case WONT:
65744364Sborman 		sprintf(nfrontp, "WONT ");
65844364Sborman 		goto common;
65944364Sborman 	    case DO:
66044364Sborman 		sprintf(nfrontp, "DO ");
66144364Sborman 		goto common;
66244364Sborman 	    case DONT:
66344364Sborman 		sprintf(nfrontp, "DONT ");
66444364Sborman 	    common:
66544364Sborman 		nfrontp += strlen(nfrontp);
66644364Sborman 		if (length < 3) {
66765158Sdab 		    sprintf(nfrontp, "(no option??\?)");
66844364Sborman 		    nfrontp += strlen(nfrontp);
66944364Sborman 		    break;
67044364Sborman 		}
67144364Sborman 		switch (pointer[2]) {
67244364Sborman 		case LM_FORWARDMASK:
67344364Sborman 		    sprintf(nfrontp, "Forward Mask");
67444364Sborman 		    nfrontp += strlen(nfrontp);
67544364Sborman 		    for (i = 3; i < length; i++) {
67644364Sborman 			sprintf(nfrontp, " %x", pointer[i]);
67744364Sborman 			nfrontp += strlen(nfrontp);
67844364Sborman 		    }
67944364Sborman 		    break;
68044364Sborman 		default:
68144364Sborman 		    sprintf(nfrontp, "%d (unknown)", pointer[2]);
68244364Sborman 		    nfrontp += strlen(nfrontp);
68344364Sborman 		    for (i = 3; i < length; i++) {
68444364Sborman 			sprintf(nfrontp, " %d", pointer[i]);
68544364Sborman 			nfrontp += strlen(nfrontp);
68644364Sborman 		    }
68744364Sborman 		    break;
68844364Sborman 		}
68944364Sborman 		break;
690*69786Sdab 
69144364Sborman 	    case LM_SLC:
69244364Sborman 		sprintf(nfrontp, "SLC");
69344364Sborman 		nfrontp += strlen(nfrontp);
69444364Sborman 		for (i = 2; i < length - 2; i += 3) {
69546809Sdab 		    if (SLC_NAME_OK(pointer[i+SLC_FUNC]))
69646809Sdab 			sprintf(nfrontp, " %s", SLC_NAME(pointer[i+SLC_FUNC]));
69744364Sborman 		    else
69844364Sborman 			sprintf(nfrontp, " %d", pointer[i+SLC_FUNC]);
69944364Sborman 		    nfrontp += strlen(nfrontp);
70044364Sborman 		    switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) {
70144364Sborman 		    case SLC_NOSUPPORT:
70244364Sborman 			sprintf(nfrontp, " NOSUPPORT"); break;
70344364Sborman 		    case SLC_CANTCHANGE:
70444364Sborman 			sprintf(nfrontp, " CANTCHANGE"); break;
70544364Sborman 		    case SLC_VARIABLE:
70644364Sborman 			sprintf(nfrontp, " VARIABLE"); break;
70744364Sborman 		    case SLC_DEFAULT:
70844364Sborman 			sprintf(nfrontp, " DEFAULT"); break;
70944364Sborman 		    }
71044364Sborman 		    nfrontp += strlen(nfrontp);
71144364Sborman 		    sprintf(nfrontp, "%s%s%s",
71244364Sborman 			pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "",
71344364Sborman 			pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "",
71444364Sborman 			pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : "");
71544364Sborman 		    nfrontp += strlen(nfrontp);
71644364Sborman 		    if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN|
71744364Sborman 						SLC_FLUSHOUT| SLC_LEVELBITS)) {
71844364Sborman 			sprintf(nfrontp, "(0x%x)", pointer[i+SLC_FLAGS]);
71944364Sborman 			nfrontp += strlen(nfrontp);
72044364Sborman 		    }
72144364Sborman 		    sprintf(nfrontp, " %d;", pointer[i+SLC_VALUE]);
72244364Sborman 		    nfrontp += strlen(nfrontp);
72344364Sborman 		    if ((pointer[i+SLC_VALUE] == IAC) &&
72444364Sborman 			(pointer[i+SLC_VALUE+1] == IAC))
72544364Sborman 				i++;
72644364Sborman 		}
72744364Sborman 		for (; i < length; i++) {
72844364Sborman 		    sprintf(nfrontp, " ?%d?", pointer[i]);
72944364Sborman 		    nfrontp += strlen(nfrontp);
73044364Sborman 		}
73144364Sborman 		break;
73244364Sborman 
73344364Sborman 	    case LM_MODE:
73444364Sborman 		sprintf(nfrontp, "MODE ");
73544364Sborman 		nfrontp += strlen(nfrontp);
73644364Sborman 		if (length < 3) {
73765158Sdab 		    sprintf(nfrontp, "(no mode??\?)");
73844364Sborman 		    nfrontp += strlen(nfrontp);
73944364Sborman 		    break;
74044364Sborman 		}
74144364Sborman 		{
74244364Sborman 		    char tbuf[32];
74344364Sborman 		    sprintf(tbuf, "%s%s%s%s%s",
74444364Sborman 			pointer[2]&MODE_EDIT ? "|EDIT" : "",
74544364Sborman 			pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "",
74644364Sborman 			pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "",
74744364Sborman 			pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "",
74844364Sborman 			pointer[2]&MODE_ACK ? "|ACK" : "");
74944364Sborman 		    sprintf(nfrontp, "%s", tbuf[1] ? &tbuf[1] : "0");
75044364Sborman 		    nfrontp += strlen(nfrontp);
75144364Sborman 		}
75244364Sborman 		if (pointer[2]&~(MODE_EDIT|MODE_TRAPSIG|MODE_ACK)) {
75344364Sborman 		    sprintf(nfrontp, " (0x%x)", pointer[2]);
75444364Sborman 		    nfrontp += strlen(nfrontp);
75544364Sborman 		}
75644364Sborman 		for (i = 3; i < length; i++) {
75744364Sborman 		    sprintf(nfrontp, " ?0x%x?", pointer[i]);
75844364Sborman 		    nfrontp += strlen(nfrontp);
75944364Sborman 		}
76044364Sborman 		break;
76144364Sborman 	    default:
76244364Sborman 		sprintf(nfrontp, "%d (unknown)", pointer[1]);
76344364Sborman 		nfrontp += strlen(nfrontp);
76444364Sborman 		for (i = 2; i < length; i++) {
76544364Sborman 		    sprintf(nfrontp, " %d", pointer[i]);
76644364Sborman 		    nfrontp += strlen(nfrontp);
76744364Sborman 		}
76844364Sborman 	    }
76944364Sborman 	    break;
77044364Sborman 
77144364Sborman 	case TELOPT_STATUS: {
77244364Sborman 	    register char *cp;
77344364Sborman 	    register int j, k;
77444364Sborman 
77544364Sborman 	    sprintf(nfrontp, "STATUS");
77644364Sborman 	    nfrontp += strlen(nfrontp);
77744364Sborman 
77844364Sborman 	    switch (pointer[1]) {
77944364Sborman 	    default:
78044364Sborman 		if (pointer[1] == TELQUAL_SEND)
78144364Sborman 		    sprintf(nfrontp, " SEND");
78244364Sborman 		else
78344364Sborman 		    sprintf(nfrontp, " %d (unknown)", pointer[1]);
78444364Sborman 		nfrontp += strlen(nfrontp);
78544364Sborman 		for (i = 2; i < length; i++) {
78644364Sborman 		    sprintf(nfrontp, " ?%d?", pointer[i]);
78744364Sborman 		    nfrontp += strlen(nfrontp);
78844364Sborman 		}
78944364Sborman 		break;
79044364Sborman 	    case TELQUAL_IS:
79144364Sborman 		sprintf(nfrontp, " IS\r\n");
79244364Sborman 		nfrontp += strlen(nfrontp);
79344364Sborman 
79444364Sborman 		for (i = 2; i < length; i++) {
79544364Sborman 		    switch(pointer[i]) {
79644364Sborman 		    case DO:	cp = "DO"; goto common2;
79744364Sborman 		    case DONT:	cp = "DONT"; goto common2;
79844364Sborman 		    case WILL:	cp = "WILL"; goto common2;
79944364Sborman 		    case WONT:	cp = "WONT"; goto common2;
80044364Sborman 		    common2:
80144364Sborman 			i++;
80258971Sdab 			if (TELOPT_OK(pointer[i]))
80344364Sborman 			    sprintf(nfrontp, " %s %s", cp, TELOPT(pointer[i]));
80444364Sborman 			else
80544364Sborman 			    sprintf(nfrontp, " %s %d", cp, pointer[i]);
80644364Sborman 			nfrontp += strlen(nfrontp);
80744364Sborman 
80844364Sborman 			sprintf(nfrontp, "\r\n");
80944364Sborman 			nfrontp += strlen(nfrontp);
81044364Sborman 			break;
81144364Sborman 
81244364Sborman 		    case SB:
81344364Sborman 			sprintf(nfrontp, " SB ");
81444364Sborman 			nfrontp += strlen(nfrontp);
81544364Sborman 			i++;
81644364Sborman 			j = k = i;
81744364Sborman 			while (j < length) {
81844364Sborman 			    if (pointer[j] == SE) {
81944364Sborman 				if (j+1 == length)
82044364Sborman 				    break;
82144364Sborman 				if (pointer[j+1] == SE)
82244364Sborman 				    j++;
82344364Sborman 				else
82444364Sborman 				    break;
82544364Sborman 			    }
82644364Sborman 			    pointer[k++] = pointer[j++];
82744364Sborman 			}
82844364Sborman 			printsub(0, &pointer[i], k - i);
82944364Sborman 			if (i < length) {
83044364Sborman 			    sprintf(nfrontp, " SE");
83144364Sborman 			    nfrontp += strlen(nfrontp);
83244364Sborman 			    i = j;
83344364Sborman 			} else
83444364Sborman 			    i = j - 1;
83544364Sborman 
83644364Sborman 			sprintf(nfrontp, "\r\n");
83744364Sborman 			nfrontp += strlen(nfrontp);
83844364Sborman 
83944364Sborman 			break;
840*69786Sdab 
84144364Sborman 		    default:
84244364Sborman 			sprintf(nfrontp, " %d", pointer[i]);
84344364Sborman 			nfrontp += strlen(nfrontp);
84444364Sborman 			break;
84544364Sborman 		    }
84644364Sborman 		}
84744364Sborman 		break;
84844364Sborman 	    }
84944364Sborman 	    break;
85044364Sborman 	  }
85144364Sborman 
85244364Sborman 	case TELOPT_XDISPLOC:
85344364Sborman 	    sprintf(nfrontp, "X-DISPLAY-LOCATION ");
85444364Sborman 	    nfrontp += strlen(nfrontp);
85544364Sborman 	    switch (pointer[1]) {
85644364Sborman 	    case TELQUAL_IS:
85744364Sborman 		sprintf(nfrontp, "IS \"%.*s\"", length-2, (char *)pointer+2);
85844364Sborman 		break;
85944364Sborman 	    case TELQUAL_SEND:
86044364Sborman 		sprintf(nfrontp, "SEND");
86144364Sborman 		break;
86244364Sborman 	    default:
86344364Sborman 		sprintf(nfrontp, "- unknown qualifier %d (0x%x).",
86444364Sborman 				pointer[1], pointer[1]);
86544364Sborman 	    }
86644364Sborman 	    nfrontp += strlen(nfrontp);
86744364Sborman 	    break;
86844364Sborman 
86965158Sdab 	case TELOPT_NEW_ENVIRON:
87065158Sdab 	    sprintf(nfrontp, "NEW-ENVIRON ");
87165158Sdab 	    goto env_common1;
87265158Sdab 	case TELOPT_OLD_ENVIRON:
87365158Sdab 	    sprintf(nfrontp, "OLD-ENVIRON");
87465158Sdab 	env_common1:
87544364Sborman 	    nfrontp += strlen(nfrontp);
87644364Sborman 	    switch (pointer[1]) {
87744364Sborman 	    case TELQUAL_IS:
87844364Sborman 		sprintf(nfrontp, "IS ");
87944364Sborman 		goto env_common;
88044364Sborman 	    case TELQUAL_SEND:
88144364Sborman 		sprintf(nfrontp, "SEND ");
88244364Sborman 		goto env_common;
88344364Sborman 	    case TELQUAL_INFO:
88444364Sborman 		sprintf(nfrontp, "INFO ");
88544364Sborman 	    env_common:
88665158Sdab 		nfrontp += strlen(nfrontp);
88744364Sborman 		{
88844364Sborman 		    register int noquote = 2;
88944364Sborman 		    for (i = 2; i < length; i++ ) {
89044364Sborman 			switch (pointer[i]) {
89165158Sdab 			case NEW_ENV_VAR:
89244364Sborman 			    sprintf(nfrontp, "\" VAR " + noquote);
89344364Sborman 			    nfrontp += strlen(nfrontp);
89444364Sborman 			    noquote = 2;
89544364Sborman 			    break;
89644364Sborman 
89765158Sdab 			case NEW_ENV_VALUE:
89844364Sborman 			    sprintf(nfrontp, "\" VALUE " + noquote);
89944364Sborman 			    nfrontp += strlen(nfrontp);
90044364Sborman 			    noquote = 2;
90144364Sborman 			    break;
90244364Sborman 
90344364Sborman 			case ENV_ESC:
90444364Sborman 			    sprintf(nfrontp, "\" ESC " + noquote);
90544364Sborman 			    nfrontp += strlen(nfrontp);
90644364Sborman 			    noquote = 2;
90744364Sborman 			    break;
90844364Sborman 
90957212Sdab 			case ENV_USERVAR:
91057212Sdab 			    sprintf(nfrontp, "\" USERVAR " + noquote);
91157212Sdab 			    nfrontp += strlen(nfrontp);
91257212Sdab 			    noquote = 2;
91357212Sdab 			    break;
91457212Sdab 
91544364Sborman 			default:
91644364Sborman 			def_case:
91744364Sborman 			    if (isprint(pointer[i]) && pointer[i] != '"') {
91844364Sborman 				if (noquote) {
91944364Sborman 				    *nfrontp++ = '"';
92044364Sborman 				    noquote = 0;
92144364Sborman 				}
92244364Sborman 				*nfrontp++ = pointer[i];
92344364Sborman 			    } else {
92444364Sborman 				sprintf(nfrontp, "\" %03o " + noquote,
92544364Sborman 							pointer[i]);
92644364Sborman 				nfrontp += strlen(nfrontp);
92744364Sborman 				noquote = 2;
92844364Sborman 			    }
92944364Sborman 			    break;
93044364Sborman 			}
93144364Sborman 		    }
93244364Sborman 		    if (!noquote)
93344364Sborman 			*nfrontp++ = '"';
93444364Sborman 		    break;
93544364Sborman 		}
93644364Sborman 	    }
93744364Sborman 	    break;
93844364Sborman 
93957212Sdab #if	defined(AUTHENTICATION)
94046809Sdab 	case TELOPT_AUTHENTICATION:
94146809Sdab 	    sprintf(nfrontp, "AUTHENTICATION");
94246809Sdab 	    nfrontp += strlen(nfrontp);
943*69786Sdab 
94446809Sdab 	    if (length < 2) {
94565158Sdab 		sprintf(nfrontp, " (empty suboption??\?)");
94646809Sdab 		nfrontp += strlen(nfrontp);
94746809Sdab 		break;
94846809Sdab 	    }
94946809Sdab 	    switch (pointer[1]) {
95046809Sdab 	    case TELQUAL_REPLY:
95146809Sdab 	    case TELQUAL_IS:
95246809Sdab 		sprintf(nfrontp, " %s ", (pointer[1] == TELQUAL_IS) ?
95346809Sdab 							"IS" : "REPLY");
95446809Sdab 		nfrontp += strlen(nfrontp);
95546809Sdab 		if (AUTHTYPE_NAME_OK(pointer[2]))
95646809Sdab 		    sprintf(nfrontp, "%s ", AUTHTYPE_NAME(pointer[2]));
95746809Sdab 		else
95846809Sdab 		    sprintf(nfrontp, "%d ", pointer[2]);
95946809Sdab 		nfrontp += strlen(nfrontp);
96046809Sdab 		if (length < 3) {
96165158Sdab 		    sprintf(nfrontp, "(partial suboption??\?)");
96246809Sdab 		    nfrontp += strlen(nfrontp);
96346809Sdab 		    break;
96446809Sdab 		}
96546809Sdab 		sprintf(nfrontp, "%s|%s",
96647611Sdab 			((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
96746809Sdab 			"CLIENT" : "SERVER",
96847611Sdab 			((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
96946809Sdab 			"MUTUAL" : "ONE-WAY");
97046809Sdab 		nfrontp += strlen(nfrontp);
97146809Sdab 
97246809Sdab 		auth_printsub(&pointer[1], length - 1, buf, sizeof(buf));
97346809Sdab 		sprintf(nfrontp, "%s", buf);
97446809Sdab 		nfrontp += strlen(nfrontp);
97546809Sdab 		break;
97646809Sdab 
97746809Sdab 	    case TELQUAL_SEND:
97846809Sdab 		i = 2;
97946809Sdab 		sprintf(nfrontp, " SEND ");
98046809Sdab 		nfrontp += strlen(nfrontp);
98146809Sdab 		while (i < length) {
98246809Sdab 		    if (AUTHTYPE_NAME_OK(pointer[i]))
98346809Sdab 			sprintf(nfrontp, "%s ", AUTHTYPE_NAME(pointer[i]));
98446809Sdab 		    else
98546809Sdab 			sprintf(nfrontp, "%d ", pointer[i]);
98646809Sdab 		    nfrontp += strlen(nfrontp);
98746809Sdab 		    if (++i >= length) {
98865158Sdab 			sprintf(nfrontp, "(partial suboption??\?)");
98946809Sdab 			nfrontp += strlen(nfrontp);
99046809Sdab 			break;
99146809Sdab 		    }
99246809Sdab 		    sprintf(nfrontp, "%s|%s ",
99347611Sdab 			((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
99446809Sdab 							"CLIENT" : "SERVER",
99547611Sdab 			((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
99646809Sdab 							"MUTUAL" : "ONE-WAY");
99746809Sdab 		    nfrontp += strlen(nfrontp);
99846809Sdab 		    ++i;
99946809Sdab 		}
100046809Sdab 		break;
100146809Sdab 
100247611Sdab 	    case TELQUAL_NAME:
100347611Sdab 		i = 2;
100447611Sdab 		sprintf(nfrontp, " NAME \"");
100547611Sdab 		nfrontp += strlen(nfrontp);
100647611Sdab 		while (i < length)
100747611Sdab 		    *nfrontp += pointer[i++];
100847611Sdab 		*nfrontp += '"';
100947611Sdab 		break;
101047611Sdab 
101146809Sdab 	    default:
101246809Sdab 		    for (i = 2; i < length; i++) {
101346809Sdab 			sprintf(nfrontp, " ?%d?", pointer[i]);
101446809Sdab 			nfrontp += strlen(nfrontp);
101546809Sdab 		    }
101646809Sdab 		    break;
101746809Sdab 	    }
101846809Sdab 	    break;
101946809Sdab #endif
102046809Sdab 
102160151Sdab #ifdef	ENCRYPTION
102246809Sdab 	case TELOPT_ENCRYPT:
102346809Sdab 	    sprintf(nfrontp, "ENCRYPT");
102446809Sdab 	    nfrontp += strlen(nfrontp);
102546809Sdab 	    if (length < 2) {
102665158Sdab 		sprintf(nfrontp, " (empty suboption??\?)");
102746809Sdab 		nfrontp += strlen(nfrontp);
102846809Sdab 		break;
102946809Sdab 	    }
103046809Sdab 	    switch (pointer[1]) {
103146809Sdab 	    case ENCRYPT_START:
103246809Sdab 		sprintf(nfrontp, " START");
103346809Sdab 		nfrontp += strlen(nfrontp);
103446809Sdab 		break;
103546809Sdab 
103646809Sdab 	    case ENCRYPT_END:
103746809Sdab 		sprintf(nfrontp, " END");
103846809Sdab 		nfrontp += strlen(nfrontp);
103946809Sdab 		break;
104046809Sdab 
104146809Sdab 	    case ENCRYPT_REQSTART:
104246809Sdab 		sprintf(nfrontp, " REQUEST-START");
104346809Sdab 		nfrontp += strlen(nfrontp);
104446809Sdab 		break;
104546809Sdab 
104646809Sdab 	    case ENCRYPT_REQEND:
104746809Sdab 		sprintf(nfrontp, " REQUEST-END");
104846809Sdab 		nfrontp += strlen(nfrontp);
104946809Sdab 		break;
105046809Sdab 
105146809Sdab 	    case ENCRYPT_IS:
105246809Sdab 	    case ENCRYPT_REPLY:
105346809Sdab 		sprintf(nfrontp, " %s ", (pointer[1] == ENCRYPT_IS) ?
105446809Sdab 							"IS" : "REPLY");
105546809Sdab 		nfrontp += strlen(nfrontp);
105646809Sdab 		if (length < 3) {
105765158Sdab 		    sprintf(nfrontp, " (partial suboption??\?)");
105846809Sdab 		    nfrontp += strlen(nfrontp);
105946809Sdab 		    break;
106046809Sdab 		}
106146809Sdab 		if (ENCTYPE_NAME_OK(pointer[2]))
106246809Sdab 		    sprintf(nfrontp, "%s ", ENCTYPE_NAME(pointer[2]));
106346809Sdab 		else
106446809Sdab 		    sprintf(nfrontp, " %d (unknown)", pointer[2]);
106546809Sdab 		nfrontp += strlen(nfrontp);
106646809Sdab 
106746809Sdab 		encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf));
106846809Sdab 		sprintf(nfrontp, "%s", buf);
106946809Sdab 		nfrontp += strlen(nfrontp);
107046809Sdab 		break;
107146809Sdab 
107246809Sdab 	    case ENCRYPT_SUPPORT:
107346809Sdab 		i = 2;
107446809Sdab 		sprintf(nfrontp, " SUPPORT ");
107546809Sdab 		nfrontp += strlen(nfrontp);
107646809Sdab 		while (i < length) {
107746809Sdab 		    if (ENCTYPE_NAME_OK(pointer[i]))
107846809Sdab 			sprintf(nfrontp, "%s ", ENCTYPE_NAME(pointer[i]));
107946809Sdab 		    else
108046809Sdab 			sprintf(nfrontp, "%d ", pointer[i]);
108146809Sdab 		    nfrontp += strlen(nfrontp);
108246809Sdab 		    i++;
108346809Sdab 		}
108446809Sdab 		break;
108546809Sdab 
108647611Sdab 	    case ENCRYPT_ENC_KEYID:
108747611Sdab 		sprintf(nfrontp, " ENC_KEYID", pointer[1]);
108847611Sdab 		nfrontp += strlen(nfrontp);
108947611Sdab 		goto encommon;
109047611Sdab 
109147611Sdab 	    case ENCRYPT_DEC_KEYID:
109247611Sdab 		sprintf(nfrontp, " DEC_KEYID", pointer[1]);
109347611Sdab 		nfrontp += strlen(nfrontp);
109447611Sdab 		goto encommon;
109547611Sdab 
109646809Sdab 	    default:
109747611Sdab 		sprintf(nfrontp, " %d (unknown)", pointer[1]);
109846809Sdab 		nfrontp += strlen(nfrontp);
109947611Sdab 	    encommon:
110046809Sdab 		for (i = 2; i < length; i++) {
110146809Sdab 		    sprintf(nfrontp, " %d", pointer[i]);
110246809Sdab 		    nfrontp += strlen(nfrontp);
110346809Sdab 		}
110446809Sdab 		break;
110546809Sdab 	    }
110646809Sdab 	    break;
110760151Sdab #endif	/* ENCRYPTION */
110846809Sdab 
110944364Sborman 	default:
111046809Sdab 	    if (TELOPT_OK(pointer[0]))
1111*69786Sdab 		sprintf(nfrontp, "%s (unknown)", TELOPT(pointer[0]));
111246809Sdab 	    else
1113*69786Sdab 		sprintf(nfrontp, "%d (unknown)", pointer[i]);
111444364Sborman 	    nfrontp += strlen(nfrontp);
111546809Sdab 	    for (i = 1; i < length; i++) {
111644364Sborman 		sprintf(nfrontp, " %d", pointer[i]);
111744364Sborman 		nfrontp += strlen(nfrontp);
111844364Sborman 	    }
111944364Sborman 	    break;
112044364Sborman 	}
112144364Sborman 	sprintf(nfrontp, "\r\n");
112244364Sborman 	nfrontp += strlen(nfrontp);
112344364Sborman }
112444364Sborman 
112544364Sborman /*
112644364Sborman  * Dump a data buffer in hex and ascii to the output data stream.
112744364Sborman  */
112846809Sdab 	void
printdata(tag,ptr,cnt)112944364Sborman printdata(tag, ptr, cnt)
113046809Sdab 	register char *tag;
113146809Sdab 	register char *ptr;
113246809Sdab 	register int cnt;
113344364Sborman {
113446809Sdab 	register int i;
113546809Sdab 	char xbuf[30];
113644364Sborman 
113744364Sborman 	while (cnt) {
113844364Sborman 		/* flush net output buffer if no room for new data) */
113944364Sborman 		if ((&netobuf[BUFSIZ] - nfrontp) < 80) {
114044364Sborman 			netflush();
114144364Sborman 		}
114244364Sborman 
114344364Sborman 		/* add a line of output */
114444364Sborman 		sprintf(nfrontp, "%s: ", tag);
114544364Sborman 		nfrontp += strlen(nfrontp);
114644364Sborman 		for (i = 0; i < 20 && cnt; i++) {
114744364Sborman 			sprintf(nfrontp, "%02x", *ptr);
1148*69786Sdab 			nfrontp += strlen(nfrontp);
114944364Sborman 			if (isprint(*ptr)) {
115044364Sborman 				xbuf[i] = *ptr;
115144364Sborman 			} else {
115244364Sborman 				xbuf[i] = '.';
115344364Sborman 			}
1154*69786Sdab 			if (i % 2) {
115544364Sborman 				*nfrontp = ' ';
115644364Sborman 				nfrontp++;
115744364Sborman 			}
115844364Sborman 			cnt--;
115944364Sborman 			ptr++;
116044364Sborman 		}
116144364Sborman 		xbuf[i] = '\0';
116244364Sborman 		sprintf(nfrontp, " %s\r\n", xbuf );
116344364Sborman 		nfrontp += strlen(nfrontp);
1164*69786Sdab 	}
116544364Sborman }
116644364Sborman #endif /* DIAGNOSTICS */
1167