xref: /csrg-svn/libexec/telnetd/utility.c (revision 44364)
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*44364Sborman static char sccsid[] = "@(#)utility.c	5.4 (Berkeley) 06/28/90";
1038905Sborman #endif /* not lint */
1138905Sborman 
12*44364Sborman #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 
2838905Sborman void
2938905Sborman ttloop()
3038905Sborman {
3138905Sborman     void netflush();
3238905Sborman 
33*44364Sborman #ifdef DIAGNOSTICS
34*44364Sborman     if (diagnostic & TD_REPORT) {
35*44364Sborman 	sprintf(nfrontp, "td: ttloop\r\n");
36*44364Sborman 	nfrontp += strlen(nfrontp);
37*44364Sborman     }
38*44364Sborman #endif /* DIAGNOSTICS */
3938905Sborman     if (nfrontp-nbackp) {
4038905Sborman 	netflush();
4138905Sborman     }
4238905Sborman     ncc = read(net, netibuf, sizeof netibuf);
4338905Sborman     if (ncc < 0) {
4438905Sborman 	syslog(LOG_INFO, "ttloop:  read: %m\n");
4538905Sborman 	exit(1);
4638905Sborman     } else if (ncc == 0) {
4738905Sborman 	syslog(LOG_INFO, "ttloop:  peer died: %m\n");
4838905Sborman 	exit(1);
4938905Sborman     }
50*44364Sborman #ifdef DIAGNOSTICS
51*44364Sborman     if (diagnostic & TD_REPORT) {
52*44364Sborman 	sprintf(nfrontp, "td: ttloop read %d chars\r\n", ncc);
53*44364Sborman 	nfrontp += strlen(nfrontp);
54*44364Sborman     }
55*44364Sborman #endif /* DIAGNOSTICS */
5638905Sborman     netip = netibuf;
5738905Sborman     telrcv();			/* state machine */
5838905Sborman     if (ncc > 0) {
5938905Sborman 	pfrontp = pbackp = ptyobuf;
6038905Sborman 	telrcv();
6138905Sborman     }
6238905Sborman }  /* end of ttloop */
6338905Sborman 
6438905Sborman /*
6538905Sborman  * Check a descriptor to see if out of band data exists on it.
6638905Sborman  */
6738905Sborman stilloob(s)
6838905Sborman int	s;		/* socket number */
6938905Sborman {
7038905Sborman     static struct timeval timeout = { 0 };
7138905Sborman     fd_set	excepts;
7238905Sborman     int value;
7338905Sborman 
7438905Sborman     do {
7538905Sborman 	FD_ZERO(&excepts);
7638905Sborman 	FD_SET(s, &excepts);
7738905Sborman 	value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout);
7838905Sborman     } while ((value == -1) && (errno == EINTR));
7938905Sborman 
8038905Sborman     if (value < 0) {
8138905Sborman 	fatalperror(pty, "select");
8238905Sborman     }
8338905Sborman     if (FD_ISSET(s, &excepts)) {
8438905Sborman 	return 1;
8538905Sborman     } else {
8638905Sborman 	return 0;
8738905Sborman     }
8838905Sborman }
8938905Sborman 
9038905Sborman ptyflush()
9138905Sborman {
9238905Sborman 	int n;
9338905Sborman 
94*44364Sborman 	if ((n = pfrontp - pbackp) > 0) {
95*44364Sborman #ifdef DIAGNOSTICS
96*44364Sborman 		if (diagnostic & (TD_REPORT | TD_PTYDATA)) {
97*44364Sborman 			sprintf(nfrontp, "td: ptyflush %d chars\r\n", n);
98*44364Sborman 			nfrontp += strlen(nfrontp);
99*44364Sborman 		}
100*44364Sborman 		if (diagnostic & TD_PTYDATA) {
101*44364Sborman 			printdata("pd", pbackp, n);
102*44364Sborman 		}
103*44364Sborman #endif /* DIAGNOSTICS */
10438905Sborman 		n = write(pty, pbackp, n);
105*44364Sborman 	}
10638905Sborman 	if (n < 0)
10738905Sborman 		return;
10838905Sborman 	pbackp += n;
10938905Sborman 	if (pbackp == pfrontp)
11038905Sborman 		pbackp = pfrontp = ptyobuf;
11138905Sborman }
11238905Sborman 
11338905Sborman /*
11438905Sborman  * nextitem()
11538905Sborman  *
11638905Sborman  *	Return the address of the next "item" in the TELNET data
11738905Sborman  * stream.  This will be the address of the next character if
11838905Sborman  * the current address is a user data character, or it will
11938905Sborman  * be the address of the character following the TELNET command
12038905Sborman  * if the current address is a TELNET IAC ("I Am a Command")
12138905Sborman  * character.
12238905Sborman  */
12338905Sborman char *
12438905Sborman nextitem(current)
12538905Sborman char	*current;
12638905Sborman {
12738905Sborman     if ((*current&0xff) != IAC) {
12838905Sborman 	return current+1;
12938905Sborman     }
13038905Sborman     switch (*(current+1)&0xff) {
13138905Sborman     case DO:
13238905Sborman     case DONT:
13338905Sborman     case WILL:
13438905Sborman     case WONT:
13538905Sborman 	return current+3;
13638905Sborman     case SB:		/* loop forever looking for the SE */
13738905Sborman 	{
13838905Sborman 	    register char *look = current+2;
13938905Sborman 
14038905Sborman 	    for (;;) {
14138905Sborman 		if ((*look++&0xff) == IAC) {
14238905Sborman 		    if ((*look++&0xff) == SE) {
14338905Sborman 			return look;
14438905Sborman 		    }
14538905Sborman 		}
14638905Sborman 	    }
14738905Sborman 	}
14838905Sborman     default:
14938905Sborman 	return current+2;
15038905Sborman     }
15138905Sborman }  /* end of nextitem */
15238905Sborman 
15338905Sborman 
15438905Sborman /*
15538905Sborman  * netclear()
15638905Sborman  *
15738905Sborman  *	We are about to do a TELNET SYNCH operation.  Clear
15838905Sborman  * the path to the network.
15938905Sborman  *
16038905Sborman  *	Things are a bit tricky since we may have sent the first
16138905Sborman  * byte or so of a previous TELNET command into the network.
16238905Sborman  * So, we have to scan the network buffer from the beginning
16338905Sborman  * until we are up to where we want to be.
16438905Sborman  *
16538905Sborman  *	A side effect of what we do, just to keep things
16638905Sborman  * simple, is to clear the urgent data pointer.  The principal
16738905Sborman  * caller should be setting the urgent data pointer AFTER calling
16838905Sborman  * us in any case.
16938905Sborman  */
17038905Sborman netclear()
17138905Sborman {
17238905Sborman     register char *thisitem, *next;
17338905Sborman     char *good;
17438905Sborman #define	wewant(p)	((nfrontp > p) && ((*p&0xff) == IAC) && \
17538905Sborman 				((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
17638905Sborman 
17738905Sborman     thisitem = netobuf;
17838905Sborman 
17938905Sborman     while ((next = nextitem(thisitem)) <= nbackp) {
18038905Sborman 	thisitem = next;
18138905Sborman     }
18238905Sborman 
18338905Sborman     /* Now, thisitem is first before/at boundary. */
18438905Sborman 
18538905Sborman     good = netobuf;	/* where the good bytes go */
18638905Sborman 
18738905Sborman     while (nfrontp > thisitem) {
18838905Sborman 	if (wewant(thisitem)) {
18938905Sborman 	    int length;
19038905Sborman 
19138905Sborman 	    next = thisitem;
19238905Sborman 	    do {
19338905Sborman 		next = nextitem(next);
19438905Sborman 	    } while (wewant(next) && (nfrontp > next));
19538905Sborman 	    length = next-thisitem;
19638905Sborman 	    bcopy(thisitem, good, length);
19738905Sborman 	    good += length;
19838905Sborman 	    thisitem = next;
19938905Sborman 	} else {
20038905Sborman 	    thisitem = nextitem(thisitem);
20138905Sborman 	}
20238905Sborman     }
20338905Sborman 
20438905Sborman     nbackp = netobuf;
20538905Sborman     nfrontp = good;		/* next byte to be sent */
20638905Sborman     neturg = 0;
20738905Sborman }  /* end of netclear */
20838905Sborman 
20938905Sborman /*
21038905Sborman  *  netflush
21138905Sborman  *		Send as much data as possible to the network,
21238905Sborman  *	handling requests for urgent data.
21338905Sborman  */
21438905Sborman void
21538905Sborman netflush()
21638905Sborman {
21738905Sborman     int n;
21838905Sborman     extern int not42;
21938905Sborman 
22038905Sborman     if ((n = nfrontp - nbackp) > 0) {
221*44364Sborman #ifdef DIAGNOSTICS
222*44364Sborman 	if (diagnostic & TD_REPORT) {
223*44364Sborman 	    sprintf(nfrontp, "td: netflush %d chars\r\n", n);
224*44364Sborman 	    n += strlen(nfrontp);  /* get count first */
225*44364Sborman 	    nfrontp += strlen(nfrontp);  /* then move pointer */
226*44364Sborman 	}
227*44364Sborman #endif /* DIAGNOSTICS */
22838905Sborman 	/*
22938905Sborman 	 * if no urgent data, or if the other side appears to be an
23038905Sborman 	 * old 4.2 client (and thus unable to survive TCP urgent data),
23138905Sborman 	 * write the entire buffer in non-OOB mode.
23238905Sborman 	 */
23338905Sborman 	if ((neturg == 0) || (not42 == 0)) {
23438905Sborman 	    n = write(net, nbackp, n);	/* normal write */
23538905Sborman 	} else {
23638905Sborman 	    n = neturg - nbackp;
23738905Sborman 	    /*
23838905Sborman 	     * In 4.2 (and 4.3) systems, there is some question about
23938905Sborman 	     * what byte in a sendOOB operation is the "OOB" data.
24038905Sborman 	     * To make ourselves compatible, we only send ONE byte
24138905Sborman 	     * out of band, the one WE THINK should be OOB (though
24238905Sborman 	     * we really have more the TCP philosophy of urgent data
24338905Sborman 	     * rather than the Unix philosophy of OOB data).
24438905Sborman 	     */
24538905Sborman 	    if (n > 1) {
24638905Sborman 		n = send(net, nbackp, n-1, 0);	/* send URGENT all by itself */
24738905Sborman 	    } else {
24838905Sborman 		n = send(net, nbackp, n, MSG_OOB);	/* URGENT data */
24938905Sborman 	    }
25038905Sborman 	}
25138905Sborman     }
25238905Sborman     if (n < 0) {
25338905Sborman 	if (errno == EWOULDBLOCK || errno == EINTR)
25438905Sborman 		return;
25538905Sborman 	cleanup();
25638905Sborman     }
25738905Sborman     nbackp += n;
25838905Sborman     if (nbackp >= neturg) {
25938905Sborman 	neturg = 0;
26038905Sborman     }
26138905Sborman     if (nbackp == nfrontp) {
26238905Sborman 	nbackp = nfrontp = netobuf;
26338905Sborman     }
26438905Sborman     return;
26538905Sborman }  /* end of netflush */
26638905Sborman 
26738905Sborman 
26838905Sborman /*
26938905Sborman  * writenet
27038905Sborman  *
27138905Sborman  * Just a handy little function to write a bit of raw data to the net.
27238905Sborman  * It will force a transmit of the buffer if necessary
27338905Sborman  *
27438905Sborman  * arguments
27538905Sborman  *    ptr - A pointer to a character string to write
27638905Sborman  *    len - How many bytes to write
27738905Sborman  */
27838905Sborman writenet(ptr, len)
27938905Sborman register char *ptr;
28038905Sborman register int len;
28138905Sborman {
28238905Sborman 	/* flush buffer if no room for new data) */
28338905Sborman 	if ((&netobuf[BUFSIZ] - nfrontp) < len) {
28438905Sborman 		/* if this fails, don't worry, buffer is a little big */
28538905Sborman 		netflush();
28638905Sborman 	}
28738905Sborman 
28838905Sborman 	bcopy(ptr, nfrontp, len);
28938905Sborman 	nfrontp += len;
29038905Sborman 
29138905Sborman }  /* end of writenet */
29238905Sborman 
29338905Sborman 
29438905Sborman /*
29538905Sborman  * miscellaneous functions doing a variety of little jobs follow ...
29638905Sborman  */
29738905Sborman 
29838905Sborman 
29938905Sborman fatal(f, msg)
30038905Sborman 	int f;
30138905Sborman 	char *msg;
30238905Sborman {
30338905Sborman 	char buf[BUFSIZ];
30438905Sborman 
30538905Sborman 	(void) sprintf(buf, "telnetd: %s.\r\n", msg);
30638905Sborman 	(void) write(f, buf, (int)strlen(buf));
30738905Sborman 	sleep(1);	/*XXX*/
30838905Sborman 	exit(1);
30938905Sborman }
31038905Sborman 
31138905Sborman fatalperror(f, msg)
31238905Sborman 	int f;
31338905Sborman 	char *msg;
31438905Sborman {
31542411Sbostic 	char buf[BUFSIZ], *strerror();
31638905Sborman 
31742411Sbostic 	(void) sprintf(buf, "%s: %s\r\n", msg, strerror(errno));
31838905Sborman 	fatal(f, buf);
31938905Sborman }
32038905Sborman 
32138905Sborman char editedhost[32];
32238905Sborman 
32338905Sborman edithost(pat, host)
32438905Sborman 	register char *pat;
32538905Sborman 	register char *host;
32638905Sborman {
32738905Sborman 	register char *res = editedhost;
32838905Sborman 	char *strncpy();
32938905Sborman 
33038905Sborman 	if (!pat)
33138905Sborman 		pat = "";
33238905Sborman 	while (*pat) {
33338905Sborman 		switch (*pat) {
33438905Sborman 
33538905Sborman 		case '#':
33638905Sborman 			if (*host)
33738905Sborman 				host++;
33838905Sborman 			break;
33938905Sborman 
34038905Sborman 		case '@':
34138905Sborman 			if (*host)
34238905Sborman 				*res++ = *host++;
34338905Sborman 			break;
34438905Sborman 
34538905Sborman 		default:
34638905Sborman 			*res++ = *pat;
34738905Sborman 			break;
34838905Sborman 		}
34938905Sborman 		if (res == &editedhost[sizeof editedhost - 1]) {
35038905Sborman 			*res = '\0';
35138905Sborman 			return;
35238905Sborman 		}
35338905Sborman 		pat++;
35438905Sborman 	}
35538905Sborman 	if (*host)
35638905Sborman 		(void) strncpy(res, host,
35738905Sborman 				sizeof editedhost - (res - editedhost) -1);
35838905Sborman 	else
35938905Sborman 		*res = '\0';
36038905Sborman 	editedhost[sizeof editedhost - 1] = '\0';
36138905Sborman }
36238905Sborman 
36338905Sborman static char *putlocation;
36438905Sborman 
36538905Sborman putstr(s)
36638905Sborman register char *s;
36738905Sborman {
36838905Sborman 
36938905Sborman 	while (*s)
37038905Sborman 		putchr(*s++);
37138905Sborman }
37238905Sborman 
37338905Sborman putchr(cc)
37438905Sborman {
37538905Sborman 	*putlocation++ = cc;
37638905Sborman }
37738905Sborman 
37838905Sborman putf(cp, where)
37938905Sborman register char *cp;
38038905Sborman char *where;
38138905Sborman {
38238905Sborman 	char *slash;
38338905Sborman #ifndef	NO_GETTYTAB
38438905Sborman 	char datebuffer[60];
38538905Sborman #endif	/* NO_GETTYTAB */
38638905Sborman 	extern char *rindex();
38738905Sborman 
38838905Sborman 	putlocation = where;
38938905Sborman 
39038905Sborman 	while (*cp) {
39138905Sborman 		if (*cp != '%') {
39238905Sborman 			putchr(*cp++);
39338905Sborman 			continue;
39438905Sborman 		}
39538905Sborman 		switch (*++cp) {
39638905Sborman 
39738905Sborman 		case 't':
39838905Sborman 			slash = rindex(line, '/');
39938905Sborman 			if (slash == (char *) 0)
40038905Sborman 				putstr(line);
40138905Sborman 			else
40238905Sborman 				putstr(&slash[1]);
40338905Sborman 			break;
40438905Sborman 
40538905Sborman 		case 'h':
40638905Sborman 			putstr(editedhost);
40738905Sborman 			break;
40838905Sborman 
40938905Sborman #ifndef	NO_GETTYTAB
41038905Sborman 		case 'd':
41138905Sborman 			get_date(datebuffer);
41238905Sborman 			putstr(datebuffer);
41338905Sborman 			break;
41438905Sborman #endif	/* NO_GETTYTAB */
41538905Sborman 
41638905Sborman 		case '%':
41738905Sborman 			putchr('%');
41838905Sborman 			break;
41938905Sborman 		}
42038905Sborman 		cp++;
42138905Sborman 	}
42238905Sborman }
42338905Sborman 
42438905Sborman /*ARGSUSED*/
42538905Sborman #ifdef	NO_GETTYTAB
42638905Sborman getent(cp, name)
42738905Sborman char *cp, *name;
42838905Sborman {
42938905Sborman 	return(0);
43038905Sborman }
43138905Sborman 
43238905Sborman /*ARGSUSED*/
43338905Sborman char *
43438905Sborman getstr(cp, cpp)
43538905Sborman char *cp, **cpp;
43638905Sborman {
43738905Sborman 	return(0);
43838905Sborman }
43938905Sborman #endif	/* NO_GETTYTAB */
440*44364Sborman 
441*44364Sborman #ifdef DIAGNOSTICS
442*44364Sborman /*
443*44364Sborman  * Print telnet options and commands in plain text, if possible.
444*44364Sborman  */
445*44364Sborman void
446*44364Sborman printoption(fmt, option)
447*44364Sborman register char *fmt;
448*44364Sborman register int option;
449*44364Sborman {
450*44364Sborman 	if (TELOPT_OK(option))
451*44364Sborman 		sprintf(nfrontp, "%s %s\r\n", fmt, TELOPT(option));
452*44364Sborman 	else if (TELCMD_OK(option))
453*44364Sborman 		sprintf(nfrontp, "%s %s\r\n", fmt, TELCMD(option));
454*44364Sborman 	else
455*44364Sborman 		sprintf(nfrontp, "%s %d\r\n", fmt, option);
456*44364Sborman 	nfrontp += strlen(nfrontp);
457*44364Sborman 	return;
458*44364Sborman }
459*44364Sborman 
460*44364Sborman char *slcnames[] = { SLC_NAMES };
461*44364Sborman 
462*44364Sborman void
463*44364Sborman printsub(dirp, pointer, length)
464*44364Sborman char	*dirp;
465*44364Sborman unsigned char	*pointer;	/* where suboption data sits */
466*44364Sborman int	length;			/* length of suboption data */
467*44364Sborman {
468*44364Sborman     register int i;
469*44364Sborman 
470*44364Sborman 	if (dirp) {
471*44364Sborman 	    sprintf(nfrontp, "%s suboption ", dirp);
472*44364Sborman 	    nfrontp += strlen(nfrontp);
473*44364Sborman 	    if (length >= 3) {
474*44364Sborman 		register int j;
475*44364Sborman 
476*44364Sborman 		i = pointer[length-2];
477*44364Sborman 		j = pointer[length-1];
478*44364Sborman 
479*44364Sborman 		if (i != IAC || j != SE) {
480*44364Sborman 		    sprintf(nfrontp, "(terminated by ");
481*44364Sborman 		    nfrontp += strlen(nfrontp);
482*44364Sborman 		    if (TELOPT_OK(i))
483*44364Sborman 			sprintf(nfrontp, "%s ", TELOPT(i));
484*44364Sborman 		    else if (TELCMD_OK(i))
485*44364Sborman 			sprintf(nfrontp, "%s ", TELCMD(i));
486*44364Sborman 		    else
487*44364Sborman 			sprintf(nfrontp, "%d ", i);
488*44364Sborman 		    nfrontp += strlen(nfrontp);
489*44364Sborman 		    if (TELOPT_OK(j))
490*44364Sborman 			sprintf(nfrontp, "%s", TELOPT(j));
491*44364Sborman 		    else if (TELCMD_OK(j))
492*44364Sborman 			sprintf(nfrontp, "%s", TELCMD(j));
493*44364Sborman 		    else
494*44364Sborman 			sprintf(nfrontp, "%d", j);
495*44364Sborman 		    nfrontp += strlen(nfrontp);
496*44364Sborman 		    sprintf(nfrontp, ", not IAC SE!) ");
497*44364Sborman 		    nfrontp += strlen(nfrontp);
498*44364Sborman 		}
499*44364Sborman 	    }
500*44364Sborman 	    length -= 2;
501*44364Sborman 	}
502*44364Sborman 	if (length < 1) {
503*44364Sborman 	    sprintf(nfrontp, "(Empty suboption???)");
504*44364Sborman 	    nfrontp += strlen(nfrontp);
505*44364Sborman 	    return;
506*44364Sborman 	}
507*44364Sborman 	switch (pointer[0]) {
508*44364Sborman 	case TELOPT_TTYPE:
509*44364Sborman 	    sprintf(nfrontp, "TERMINAL-TYPE ");
510*44364Sborman 	    nfrontp += strlen(nfrontp);
511*44364Sborman 	    switch (pointer[1]) {
512*44364Sborman 	    case TELQUAL_IS:
513*44364Sborman 		sprintf(nfrontp, "IS \"%.*s\"", length-2, (char *)pointer+2);
514*44364Sborman 		break;
515*44364Sborman 	    case TELQUAL_SEND:
516*44364Sborman 		sprintf(nfrontp, "SEND");
517*44364Sborman 		break;
518*44364Sborman 	    default:
519*44364Sborman 		sprintf(nfrontp,
520*44364Sborman 				"- unknown qualifier %d (0x%x).",
521*44364Sborman 				pointer[1], pointer[1]);
522*44364Sborman 	    }
523*44364Sborman 	    nfrontp += strlen(nfrontp);
524*44364Sborman 	    break;
525*44364Sborman 	case TELOPT_TSPEED:
526*44364Sborman 	    sprintf(nfrontp, "TERMINAL-SPEED");
527*44364Sborman 	    nfrontp += strlen(nfrontp);
528*44364Sborman 	    if (length < 2) {
529*44364Sborman 		sprintf(nfrontp, " (empty suboption???)");
530*44364Sborman 		nfrontp += strlen(nfrontp);
531*44364Sborman 		break;
532*44364Sborman 	    }
533*44364Sborman 	    switch (pointer[1]) {
534*44364Sborman 	    case TELQUAL_IS:
535*44364Sborman 		sprintf(nfrontp, " IS %.*s", length-2, (char *)pointer+2);
536*44364Sborman 		nfrontp += strlen(nfrontp);
537*44364Sborman 		break;
538*44364Sborman 	    default:
539*44364Sborman 		if (pointer[1] == 1)
540*44364Sborman 		    sprintf(nfrontp, " SEND");
541*44364Sborman 		else
542*44364Sborman 		    sprintf(nfrontp, " %d (unknown)", pointer[1]);
543*44364Sborman 		nfrontp += strlen(nfrontp);
544*44364Sborman 		for (i = 2; i < length; i++) {
545*44364Sborman 		    sprintf(nfrontp, " ?%d?", pointer[i]);
546*44364Sborman 		    nfrontp += strlen(nfrontp);
547*44364Sborman 		}
548*44364Sborman 		break;
549*44364Sborman 	    }
550*44364Sborman 	    break;
551*44364Sborman 
552*44364Sborman 	case TELOPT_LFLOW:
553*44364Sborman 	    sprintf(nfrontp, "TOGGLE-FLOW-CONTROL");
554*44364Sborman 	    nfrontp += strlen(nfrontp);
555*44364Sborman 	    if (length < 2) {
556*44364Sborman 		sprintf(nfrontp, " (empty suboption???)");
557*44364Sborman 		nfrontp += strlen(nfrontp);
558*44364Sborman 		break;
559*44364Sborman 	    }
560*44364Sborman 	    switch (pointer[1]) {
561*44364Sborman 	    case 0:
562*44364Sborman 		sprintf(nfrontp, " OFF"); break;
563*44364Sborman 	    case 1:
564*44364Sborman 		sprintf(nfrontp, " ON"); break;
565*44364Sborman 	    default:
566*44364Sborman 		sprintf(nfrontp, " %d (unknown)", pointer[1]);
567*44364Sborman 	    }
568*44364Sborman 	    nfrontp += strlen(nfrontp);
569*44364Sborman 	    for (i = 2; i < length; i++) {
570*44364Sborman 		sprintf(nfrontp, " ?%d?", pointer[i]);
571*44364Sborman 		nfrontp += strlen(nfrontp);
572*44364Sborman 	    }
573*44364Sborman 	    break;
574*44364Sborman 
575*44364Sborman 	case TELOPT_NAWS:
576*44364Sborman 	    sprintf(nfrontp, "NAWS");
577*44364Sborman 	    nfrontp += strlen(nfrontp);
578*44364Sborman 	    if (length < 2) {
579*44364Sborman 		sprintf(nfrontp, " (empty suboption???)");
580*44364Sborman 		nfrontp += strlen(nfrontp);
581*44364Sborman 		break;
582*44364Sborman 	    }
583*44364Sborman 	    if (length == 2) {
584*44364Sborman 		sprintf(nfrontp, " ?%d?", pointer[1]);
585*44364Sborman 		nfrontp += strlen(nfrontp);
586*44364Sborman 		break;
587*44364Sborman 	    }
588*44364Sborman 	    sprintf(nfrontp, " %d %d (%d)",
589*44364Sborman 		pointer[1], pointer[2],
590*44364Sborman 		(int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2])));
591*44364Sborman 	    nfrontp += strlen(nfrontp);
592*44364Sborman 	    if (length == 4) {
593*44364Sborman 		sprintf(nfrontp, " ?%d?", pointer[3]);
594*44364Sborman 		nfrontp += strlen(nfrontp);
595*44364Sborman 		break;
596*44364Sborman 	    }
597*44364Sborman 	    sprintf(nfrontp, " %d %d (%d)",
598*44364Sborman 		pointer[3], pointer[4],
599*44364Sborman 		(int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4])));
600*44364Sborman 	    nfrontp += strlen(nfrontp);
601*44364Sborman 	    for (i = 5; i < length; i++) {
602*44364Sborman 		sprintf(nfrontp, " ?%d?", pointer[i]);
603*44364Sborman 		nfrontp += strlen(nfrontp);
604*44364Sborman 	    }
605*44364Sborman 	    break;
606*44364Sborman 
607*44364Sborman 	case TELOPT_LINEMODE:
608*44364Sborman 	    sprintf(nfrontp, "LINEMODE ");
609*44364Sborman 	    nfrontp += strlen(nfrontp);
610*44364Sborman 	    if (length < 2) {
611*44364Sborman 		sprintf(nfrontp, " (empty suboption???)");
612*44364Sborman 		nfrontp += strlen(nfrontp);
613*44364Sborman 		break;
614*44364Sborman 	    }
615*44364Sborman 	    switch (pointer[1]) {
616*44364Sborman 	    case WILL:
617*44364Sborman 		sprintf(nfrontp, "WILL ");
618*44364Sborman 		goto common;
619*44364Sborman 	    case WONT:
620*44364Sborman 		sprintf(nfrontp, "WONT ");
621*44364Sborman 		goto common;
622*44364Sborman 	    case DO:
623*44364Sborman 		sprintf(nfrontp, "DO ");
624*44364Sborman 		goto common;
625*44364Sborman 	    case DONT:
626*44364Sborman 		sprintf(nfrontp, "DONT ");
627*44364Sborman 	    common:
628*44364Sborman 		nfrontp += strlen(nfrontp);
629*44364Sborman 		if (length < 3) {
630*44364Sborman 		    sprintf(nfrontp, "(no option???)");
631*44364Sborman 		    nfrontp += strlen(nfrontp);
632*44364Sborman 		    break;
633*44364Sborman 		}
634*44364Sborman 		switch (pointer[2]) {
635*44364Sborman 		case LM_FORWARDMASK:
636*44364Sborman 		    sprintf(nfrontp, "Forward Mask");
637*44364Sborman 		    nfrontp += strlen(nfrontp);
638*44364Sborman 		    for (i = 3; i < length; i++) {
639*44364Sborman 			sprintf(nfrontp, " %x", pointer[i]);
640*44364Sborman 			nfrontp += strlen(nfrontp);
641*44364Sborman 		    }
642*44364Sborman 		    break;
643*44364Sborman 		default:
644*44364Sborman 		    sprintf(nfrontp, "%d (unknown)", pointer[2]);
645*44364Sborman 		    nfrontp += strlen(nfrontp);
646*44364Sborman 		    for (i = 3; i < length; i++) {
647*44364Sborman 			sprintf(nfrontp, " %d", pointer[i]);
648*44364Sborman 			nfrontp += strlen(nfrontp);
649*44364Sborman 		    }
650*44364Sborman 		    break;
651*44364Sborman 		}
652*44364Sborman 		break;
653*44364Sborman 
654*44364Sborman 	    case LM_SLC:
655*44364Sborman 		sprintf(nfrontp, "SLC");
656*44364Sborman 		nfrontp += strlen(nfrontp);
657*44364Sborman 		for (i = 2; i < length - 2; i += 3) {
658*44364Sborman 		    if (pointer[i+SLC_FUNC] <= NSLC)
659*44364Sborman 			sprintf(nfrontp, " %s", slcnames[pointer[i+SLC_FUNC]]);
660*44364Sborman 		    else
661*44364Sborman 			sprintf(nfrontp, " %d", pointer[i+SLC_FUNC]);
662*44364Sborman 		    nfrontp += strlen(nfrontp);
663*44364Sborman 		    switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) {
664*44364Sborman 		    case SLC_NOSUPPORT:
665*44364Sborman 			sprintf(nfrontp, " NOSUPPORT"); break;
666*44364Sborman 		    case SLC_CANTCHANGE:
667*44364Sborman 			sprintf(nfrontp, " CANTCHANGE"); break;
668*44364Sborman 		    case SLC_VARIABLE:
669*44364Sborman 			sprintf(nfrontp, " VARIABLE"); break;
670*44364Sborman 		    case SLC_DEFAULT:
671*44364Sborman 			sprintf(nfrontp, " DEFAULT"); break;
672*44364Sborman 		    }
673*44364Sborman 		    nfrontp += strlen(nfrontp);
674*44364Sborman 		    sprintf(nfrontp, "%s%s%s",
675*44364Sborman 			pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "",
676*44364Sborman 			pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "",
677*44364Sborman 			pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : "");
678*44364Sborman 		    nfrontp += strlen(nfrontp);
679*44364Sborman 		    if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN|
680*44364Sborman 						SLC_FLUSHOUT| SLC_LEVELBITS)) {
681*44364Sborman 			sprintf(nfrontp, "(0x%x)", pointer[i+SLC_FLAGS]);
682*44364Sborman 			nfrontp += strlen(nfrontp);
683*44364Sborman 		    }
684*44364Sborman 		    sprintf(nfrontp, " %d;", pointer[i+SLC_VALUE]);
685*44364Sborman 		    nfrontp += strlen(nfrontp);
686*44364Sborman 		    if ((pointer[i+SLC_VALUE] == IAC) &&
687*44364Sborman 			(pointer[i+SLC_VALUE+1] == IAC))
688*44364Sborman 				i++;
689*44364Sborman 		}
690*44364Sborman 		for (; i < length; i++) {
691*44364Sborman 		    sprintf(nfrontp, " ?%d?", pointer[i]);
692*44364Sborman 		    nfrontp += strlen(nfrontp);
693*44364Sborman 		}
694*44364Sborman 		break;
695*44364Sborman 
696*44364Sborman 	    case LM_MODE:
697*44364Sborman 		sprintf(nfrontp, "MODE ");
698*44364Sborman 		nfrontp += strlen(nfrontp);
699*44364Sborman 		if (length < 3) {
700*44364Sborman 		    sprintf(nfrontp, "(no mode???)");
701*44364Sborman 		    nfrontp += strlen(nfrontp);
702*44364Sborman 		    break;
703*44364Sborman 		}
704*44364Sborman 		{
705*44364Sborman 		    char tbuf[32];
706*44364Sborman 		    sprintf(tbuf, "%s%s%s%s%s",
707*44364Sborman 			pointer[2]&MODE_EDIT ? "|EDIT" : "",
708*44364Sborman 			pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "",
709*44364Sborman 			pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "",
710*44364Sborman 			pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "",
711*44364Sborman 			pointer[2]&MODE_ACK ? "|ACK" : "");
712*44364Sborman 		    sprintf(nfrontp, "%s", tbuf[1] ? &tbuf[1] : "0");
713*44364Sborman 		    nfrontp += strlen(nfrontp);
714*44364Sborman 		}
715*44364Sborman 		if (pointer[2]&~(MODE_EDIT|MODE_TRAPSIG|MODE_ACK)) {
716*44364Sborman 		    sprintf(nfrontp, " (0x%x)", pointer[2]);
717*44364Sborman 		    nfrontp += strlen(nfrontp);
718*44364Sborman 		}
719*44364Sborman 		for (i = 3; i < length; i++) {
720*44364Sborman 		    sprintf(nfrontp, " ?0x%x?", pointer[i]);
721*44364Sborman 		    nfrontp += strlen(nfrontp);
722*44364Sborman 		}
723*44364Sborman 		break;
724*44364Sborman 	    default:
725*44364Sborman 		sprintf(nfrontp, "%d (unknown)", pointer[1]);
726*44364Sborman 		nfrontp += strlen(nfrontp);
727*44364Sborman 		for (i = 2; i < length; i++) {
728*44364Sborman 		    sprintf(nfrontp, " %d", pointer[i]);
729*44364Sborman 		    nfrontp += strlen(nfrontp);
730*44364Sborman 		}
731*44364Sborman 	    }
732*44364Sborman 	    break;
733*44364Sborman 
734*44364Sborman 	case TELOPT_STATUS: {
735*44364Sborman 	    register char *cp;
736*44364Sborman 	    register int j, k;
737*44364Sborman 
738*44364Sborman 	    sprintf(nfrontp, "STATUS");
739*44364Sborman 	    nfrontp += strlen(nfrontp);
740*44364Sborman 
741*44364Sborman 	    switch (pointer[1]) {
742*44364Sborman 	    default:
743*44364Sborman 		if (pointer[1] == TELQUAL_SEND)
744*44364Sborman 		    sprintf(nfrontp, " SEND");
745*44364Sborman 		else
746*44364Sborman 		    sprintf(nfrontp, " %d (unknown)", pointer[1]);
747*44364Sborman 		nfrontp += strlen(nfrontp);
748*44364Sborman 		for (i = 2; i < length; i++) {
749*44364Sborman 		    sprintf(nfrontp, " ?%d?", pointer[i]);
750*44364Sborman 		    nfrontp += strlen(nfrontp);
751*44364Sborman 		}
752*44364Sborman 		break;
753*44364Sborman 	    case TELQUAL_IS:
754*44364Sborman 		sprintf(nfrontp, " IS\r\n");
755*44364Sborman 		nfrontp += strlen(nfrontp);
756*44364Sborman 
757*44364Sborman 		for (i = 2; i < length; i++) {
758*44364Sborman 		    switch(pointer[i]) {
759*44364Sborman 		    case DO:	cp = "DO"; goto common2;
760*44364Sborman 		    case DONT:	cp = "DONT"; goto common2;
761*44364Sborman 		    case WILL:	cp = "WILL"; goto common2;
762*44364Sborman 		    case WONT:	cp = "WONT"; goto common2;
763*44364Sborman 		    common2:
764*44364Sborman 			i++;
765*44364Sborman 			if (TELOPT_OK((int)pointer[i]))
766*44364Sborman 			    sprintf(nfrontp, " %s %s", cp, TELOPT(pointer[i]));
767*44364Sborman 			else
768*44364Sborman 			    sprintf(nfrontp, " %s %d", cp, pointer[i]);
769*44364Sborman 			nfrontp += strlen(nfrontp);
770*44364Sborman 
771*44364Sborman 			sprintf(nfrontp, "\r\n");
772*44364Sborman 			nfrontp += strlen(nfrontp);
773*44364Sborman 			break;
774*44364Sborman 
775*44364Sborman 		    case SB:
776*44364Sborman 			sprintf(nfrontp, " SB ");
777*44364Sborman 			nfrontp += strlen(nfrontp);
778*44364Sborman 			i++;
779*44364Sborman 			j = k = i;
780*44364Sborman 			while (j < length) {
781*44364Sborman 			    if (pointer[j] == SE) {
782*44364Sborman 				if (j+1 == length)
783*44364Sborman 				    break;
784*44364Sborman 				if (pointer[j+1] == SE)
785*44364Sborman 				    j++;
786*44364Sborman 				else
787*44364Sborman 				    break;
788*44364Sborman 			    }
789*44364Sborman 			    pointer[k++] = pointer[j++];
790*44364Sborman 			}
791*44364Sborman 			printsub(0, &pointer[i], k - i);
792*44364Sborman 			if (i < length) {
793*44364Sborman 			    sprintf(nfrontp, " SE");
794*44364Sborman 			    nfrontp += strlen(nfrontp);
795*44364Sborman 			    i = j;
796*44364Sborman 			} else
797*44364Sborman 			    i = j - 1;
798*44364Sborman 
799*44364Sborman 			sprintf(nfrontp, "\r\n");
800*44364Sborman 			nfrontp += strlen(nfrontp);
801*44364Sborman 
802*44364Sborman 			break;
803*44364Sborman 
804*44364Sborman 		    default:
805*44364Sborman 			sprintf(nfrontp, " %d", pointer[i]);
806*44364Sborman 			nfrontp += strlen(nfrontp);
807*44364Sborman 			break;
808*44364Sborman 		    }
809*44364Sborman 		}
810*44364Sborman 		break;
811*44364Sborman 	    }
812*44364Sborman 	    break;
813*44364Sborman 	  }
814*44364Sborman 
815*44364Sborman 	case TELOPT_XDISPLOC:
816*44364Sborman 	    sprintf(nfrontp, "X-DISPLAY-LOCATION ");
817*44364Sborman 	    nfrontp += strlen(nfrontp);
818*44364Sborman 	    switch (pointer[1]) {
819*44364Sborman 	    case TELQUAL_IS:
820*44364Sborman 		sprintf(nfrontp, "IS \"%.*s\"", length-2, (char *)pointer+2);
821*44364Sborman 		break;
822*44364Sborman 	    case TELQUAL_SEND:
823*44364Sborman 		sprintf(nfrontp, "SEND");
824*44364Sborman 		break;
825*44364Sborman 	    default:
826*44364Sborman 		sprintf(nfrontp, "- unknown qualifier %d (0x%x).",
827*44364Sborman 				pointer[1], pointer[1]);
828*44364Sborman 	    }
829*44364Sborman 	    nfrontp += strlen(nfrontp);
830*44364Sborman 	    break;
831*44364Sborman 
832*44364Sborman 	case TELOPT_ENVIRON:
833*44364Sborman 	    sprintf(nfrontp, "ENVIRON ");
834*44364Sborman 	    nfrontp += strlen(nfrontp);
835*44364Sborman 	    switch (pointer[1]) {
836*44364Sborman 	    case TELQUAL_IS:
837*44364Sborman 		sprintf(nfrontp, "IS ");
838*44364Sborman 		goto env_common;
839*44364Sborman 	    case TELQUAL_SEND:
840*44364Sborman 		sprintf(nfrontp, "SEND ");
841*44364Sborman 		goto env_common;
842*44364Sborman 	    case TELQUAL_INFO:
843*44364Sborman 		sprintf(nfrontp, "INFO ");
844*44364Sborman 	    env_common:
845*44364Sborman 	    nfrontp += strlen(nfrontp);
846*44364Sborman 		{
847*44364Sborman 		    register int noquote = 2;
848*44364Sborman 		    for (i = 2; i < length; i++ ) {
849*44364Sborman 			switch (pointer[i]) {
850*44364Sborman 			case ENV_VAR:
851*44364Sborman 			    if (pointer[1] == TELQUAL_SEND)
852*44364Sborman 				goto def_case;
853*44364Sborman 			    sprintf(nfrontp, "\" VAR " + noquote);
854*44364Sborman 			    nfrontp += strlen(nfrontp);
855*44364Sborman 			    noquote = 2;
856*44364Sborman 			    break;
857*44364Sborman 
858*44364Sborman 			case ENV_VALUE:
859*44364Sborman 			    sprintf(nfrontp, "\" VALUE " + noquote);
860*44364Sborman 			    nfrontp += strlen(nfrontp);
861*44364Sborman 			    noquote = 2;
862*44364Sborman 			    break;
863*44364Sborman 
864*44364Sborman 			case ENV_ESC:
865*44364Sborman 			    sprintf(nfrontp, "\" ESC " + noquote);
866*44364Sborman 			    nfrontp += strlen(nfrontp);
867*44364Sborman 			    noquote = 2;
868*44364Sborman 			    break;
869*44364Sborman 
870*44364Sborman 			default:
871*44364Sborman 			def_case:
872*44364Sborman 			    if (isprint(pointer[i]) && pointer[i] != '"') {
873*44364Sborman 				if (noquote) {
874*44364Sborman 				    *nfrontp++ = '"';
875*44364Sborman 				    noquote = 0;
876*44364Sborman 				}
877*44364Sborman 				*nfrontp++ = pointer[i];
878*44364Sborman 			    } else {
879*44364Sborman 				sprintf(nfrontp, "\" %03o " + noquote,
880*44364Sborman 							pointer[i]);
881*44364Sborman 				nfrontp += strlen(nfrontp);
882*44364Sborman 				noquote = 2;
883*44364Sborman 			    }
884*44364Sborman 			    break;
885*44364Sborman 			}
886*44364Sborman 		    }
887*44364Sborman 		    if (!noquote)
888*44364Sborman 			*nfrontp++ = '"';
889*44364Sborman 		    break;
890*44364Sborman 		}
891*44364Sborman 	    }
892*44364Sborman 	    break;
893*44364Sborman 
894*44364Sborman 	default:
895*44364Sborman 	    sprintf(nfrontp, "Unknown option ");
896*44364Sborman 	    nfrontp += strlen(nfrontp);
897*44364Sborman 	    for (i = 0; i < length; i++) {
898*44364Sborman 		sprintf(nfrontp, " %d", pointer[i]);
899*44364Sborman 		nfrontp += strlen(nfrontp);
900*44364Sborman 	    }
901*44364Sborman 	    break;
902*44364Sborman 	}
903*44364Sborman 	sprintf(nfrontp, "\r\n");
904*44364Sborman 	nfrontp += strlen(nfrontp);
905*44364Sborman }
906*44364Sborman 
907*44364Sborman /*
908*44364Sborman  * Dump a data buffer in hex and ascii to the output data stream.
909*44364Sborman  */
910*44364Sborman void
911*44364Sborman printdata(tag, ptr, cnt)
912*44364Sborman register char *tag;
913*44364Sborman register char *ptr;
914*44364Sborman register int cnt;
915*44364Sborman {
916*44364Sborman register int i;
917*44364Sborman char xbuf[30];
918*44364Sborman 
919*44364Sborman 	while (cnt) {
920*44364Sborman 		/* flush net output buffer if no room for new data) */
921*44364Sborman 		if ((&netobuf[BUFSIZ] - nfrontp) < 80) {
922*44364Sborman 			netflush();
923*44364Sborman 		}
924*44364Sborman 
925*44364Sborman 		/* add a line of output */
926*44364Sborman 		sprintf(nfrontp, "%s: ", tag);
927*44364Sborman 		nfrontp += strlen(nfrontp);
928*44364Sborman 		for (i = 0; i < 20 && cnt; i++) {
929*44364Sborman 			sprintf(nfrontp, "%02x", *ptr);
930*44364Sborman 			nfrontp += strlen(nfrontp);
931*44364Sborman 			if (isprint(*ptr)) {
932*44364Sborman 				xbuf[i] = *ptr;
933*44364Sborman 			} else {
934*44364Sborman 				xbuf[i] = '.';
935*44364Sborman 			}
936*44364Sborman 			if (i % 2) {
937*44364Sborman 				*nfrontp = ' ';
938*44364Sborman 				nfrontp++;
939*44364Sborman 			}
940*44364Sborman 			cnt--;
941*44364Sborman 			ptr++;
942*44364Sborman 		}
943*44364Sborman 		xbuf[i] = '\0';
944*44364Sborman 		sprintf(nfrontp, " %s\r\n", xbuf );
945*44364Sborman 		nfrontp += strlen(nfrontp);
946*44364Sborman 	}
947*44364Sborman }
948*44364Sborman 
949*44364Sborman #endif /* DIAGNOSTICS */
950*44364Sborman 
951*44364Sborman #ifdef	NO_STRERROR
952*44364Sborman char *
953*44364Sborman strerror(errno)
954*44364Sborman {
955*44364Sborman 	extern char *sys_errlist[];
956*44364Sborman 
957*44364Sborman 	return(sys_errlist[errno]);
958*44364Sborman }
959*44364Sborman #endif
960