xref: /csrg-svn/usr.bin/telnet/telnet.c (revision 27676)
121580Sdist /*
221580Sdist  * Copyright (c) 1983 Regents of the University of California.
321580Sdist  * All rights reserved.  The Berkeley software License Agreement
421580Sdist  * specifies the terms and conditions for redistribution.
521580Sdist  */
621580Sdist 
711758Ssam #ifndef lint
821580Sdist char copyright[] =
921580Sdist "@(#) Copyright (c) 1983 Regents of the University of California.\n\
1021580Sdist  All rights reserved.\n";
1121580Sdist #endif not lint
1211758Ssam 
1321580Sdist #ifndef lint
14*27676Sminshall static char sccsid[] = "@(#)telnet.c	5.12 (Berkeley) 4/22/86";
1521580Sdist #endif not lint
1621580Sdist 
176000Sroot /*
186000Sroot  * User telnet program.
196000Sroot  */
209217Ssam #include <sys/types.h>
219217Ssam #include <sys/socket.h>
229972Ssam #include <sys/ioctl.h>
2327178Sminshall #include <sys/time.h>
249217Ssam 
259217Ssam #include <netinet/in.h>
269217Ssam 
2712212Ssam #define	TELOPTS
2812212Ssam #include <arpa/telnet.h>
2927186Sminshall #include <arpa/inet.h>
3012212Ssam 
316000Sroot #include <stdio.h>
326000Sroot #include <ctype.h>
336000Sroot #include <errno.h>
346000Sroot #include <signal.h>
356000Sroot #include <setjmp.h>
368345Ssam #include <netdb.h>
3727186Sminshall #include <strings.h>
389217Ssam 
3927178Sminshall 
4027178Sminshall 
41*27676Sminshall #ifndef	FD_SETSIZE
4227178Sminshall /*
4327178Sminshall  * The following is defined just in case someone should want to run
4427178Sminshall  * this telnet on a 4.2 system.
4527178Sminshall  *
4627178Sminshall  */
4727178Sminshall 
48*27676Sminshall #define	FD_SET(n, p)	((p)->fds_bits[0] |= (1<<(n)))
49*27676Sminshall #define	FD_CLR(n, p)	((p)->fds_bits[0] &= ~(1<<(n)))
50*27676Sminshall #define	FD_ISSET(n, p)	((p)->fds_bits[0] & (1<<(n)))
51*27676Sminshall #define FD_ZERO(p)	((p)->fds_bits[0] = 0)
5227178Sminshall 
5327178Sminshall #endif
5427178Sminshall 
5527228Sminshall #define	strip(x)	((x)&0x7f)
566000Sroot 
5727228Sminshall char	ttyobuf[2*BUFSIZ], *tfrontp = ttyobuf, *tbackp = ttyobuf;
5827228Sminshall #define	TTYADD(c)	{ if (!(SYNCHing||flushout)) { *tfrontp++ = c; } }
5927228Sminshall #define	TTYLOC()	(tfrontp)
6027228Sminshall #define	TTYMAX()	(ttyobuf+sizeof ttyobuf-1)
6127228Sminshall #define	TTYMIN()	(netobuf)
6227228Sminshall #define	TTYBYTES()	(tfrontp-tbackp)
6327228Sminshall #define	TTYROOM()	(TTYMAX()-TTYLOC()+1)
6427088Sminshall 
6527228Sminshall char	netobuf[2*BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf;
6627088Sminshall #define	NETADD(c)	{ *nfrontp++ = c; }
6727088Sminshall #define	NET2ADD(c1,c2)	{ NETADD(c1); NETADD(c2); }
6827088Sminshall #define NETLOC()	(nfrontp)
6927228Sminshall #define	NETMAX()	(netobuf+sizeof netobuf-1)
7027228Sminshall #define	NETBYTES()	(nfrontp-nbackp)
7127228Sminshall #define	NETROOM()	(NETMAX()-NETLOC()+1)
7227088Sminshall char	*neturg = 0;		/* one past last byte of urgent data */
736000Sroot 
74*27676Sminshall char	subbuffer[100], *subpointer, *subend;	/* buffer for sub-options */
75*27676Sminshall #define	SB_CLEAR()	subpointer = subbuffer;
76*27676Sminshall #define	SB_TERM()	subend = subpointer;
77*27676Sminshall #define	SB_ACCUM(c)	if (subpointer < (subbuffer+sizeof subbuffer)) { \
78*27676Sminshall 				*subpointer++ = (c); \
79*27676Sminshall 			}
80*27676Sminshall 
816000Sroot char	hisopts[256];
826000Sroot char	myopts[256];
836000Sroot 
846000Sroot char	doopt[] = { IAC, DO, '%', 'c', 0 };
856000Sroot char	dont[] = { IAC, DONT, '%', 'c', 0 };
866000Sroot char	will[] = { IAC, WILL, '%', 'c', 0 };
876000Sroot char	wont[] = { IAC, WONT, '%', 'c', 0 };
886000Sroot 
8927088Sminshall struct cmd {
9027088Sminshall 	char	*name;		/* command name */
9127088Sminshall 	char	*help;		/* help string */
9227088Sminshall 	int	(*handler)();	/* routine which executes command */
9327088Sminshall 	int	dohelp;		/* Should we give general help information? */
9427088Sminshall 	int	needconnect;	/* Do we need to be connected to execute? */
9527088Sminshall };
9627088Sminshall 
976000Sroot int	connected;
986000Sroot int	net;
9927088Sminshall int	tout;
1009972Ssam int	showoptions = 0;
10110339Ssam int	debug = 0;
1029972Ssam int	crmod = 0;
10327088Sminshall int	netdata = 0;
10427021Sminshall static FILE	*NetTrace;
10525289Skarels int	telnetport = 1;
10627088Sminshall 
10727088Sminshall 
1086000Sroot char	*prompt;
1099972Ssam char	escape = CTRL(]);
11027110Sminshall char	echoc = CTRL(E);
1116000Sroot 
11227186Sminshall int	SYNCHing = 0;		/* we are in TELNET SYNCH mode */
11327186Sminshall int	flushout = 0;		/* flush output */
11427228Sminshall int	autoflush = 0;		/* flush output when interrupting? */
11527186Sminshall int	autosynch = 0;		/* send interrupt characters with SYNCH? */
11627261Sminshall int	localchars = 0;		/* we recognize interrupt/quit */
11727261Sminshall int	donelclchars = 0;	/* the user has set "localchars" */
11827186Sminshall int	dontlecho = 0;		/* do we suppress local echoing right now? */
11927186Sminshall 
1206000Sroot char	line[200];
1216000Sroot int	margc;
1226000Sroot char	*margv[20];
1236000Sroot 
1246000Sroot jmp_buf	toplevel;
1256000Sroot jmp_buf	peerdied;
1266000Sroot 
1276000Sroot extern	int errno;
1286000Sroot 
1296000Sroot 
1309972Ssam struct sockaddr_in sin;
1316000Sroot 
1326000Sroot struct	cmd *getcmd();
1338345Ssam struct	servent *sp;
1346000Sroot 
13527110Sminshall struct	tchars otc, ntc;
13627228Sminshall struct	ltchars oltc, nltc;
13727110Sminshall struct	sgttyb ottyb, nttyb;
13827110Sminshall int	globalmode = 0;
13927110Sminshall int	flushline = 1;
1408378Ssam 
14127110Sminshall char	*hostname;
14227110Sminshall char	hnamebuf[32];
14327110Sminshall 
14427110Sminshall /*
14527110Sminshall  * The following are some clocks used to decide how to interpret
14627178Sminshall  * the relationship between various variables.
14727110Sminshall  */
14827110Sminshall 
14927110Sminshall struct {
15027110Sminshall     int
15127110Sminshall 	system,			/* what the current time is */
15227110Sminshall 	echotoggle,		/* last time user entered echo character */
15327178Sminshall 	modenegotiated,		/* last time operating mode negotiated */
15427178Sminshall 	didnetreceive,		/* last time we read data from network */
15527178Sminshall 	gotDM;			/* when did we last see a data mark */
15627186Sminshall } clocks;
15727110Sminshall 
15827186Sminshall #define	settimer(x)	clocks.x = clocks.system++
15927110Sminshall 
16027110Sminshall /*
16127110Sminshall  * Various utility routines.
16227110Sminshall  */
1636000Sroot 
16427186Sminshall char *ambiguous;		/* special return value */
16527186Sminshall #define Ambiguous(t)	((t)&ambiguous)
16627186Sminshall 
16727186Sminshall 
16827088Sminshall char **
16927088Sminshall genget(name, table, next)
17027088Sminshall char	*name;		/* name to match */
17127088Sminshall char	**table;		/* name entry in table */
17227088Sminshall char	**(*next)();	/* routine to return next entry in table */
1736000Sroot {
17427088Sminshall 	register char *p, *q;
17527088Sminshall 	register char **c, **found;
17627088Sminshall 	register int nmatches, longest;
1776000Sroot 
17827088Sminshall 	longest = 0;
17927088Sminshall 	nmatches = 0;
18027088Sminshall 	found = 0;
18127088Sminshall 	for (c = table; p = *c; c = (*next)(c)) {
18227088Sminshall 		for (q = name; *q == *p++; q++)
18327088Sminshall 			if (*q == 0)		/* exact match? */
18427088Sminshall 				return (c);
18527088Sminshall 		if (!*q) {			/* the name was a prefix */
18627088Sminshall 			if (q - name > longest) {
18727088Sminshall 				longest = q - name;
18827088Sminshall 				nmatches = 1;
18927088Sminshall 				found = c;
19027088Sminshall 			} else if (q - name == longest)
19127088Sminshall 				nmatches++;
1928377Ssam 		}
1936000Sroot 	}
19427088Sminshall 	if (nmatches > 1)
19527186Sminshall 		return Ambiguous(char **);
19627088Sminshall 	return (found);
1976000Sroot }
1986000Sroot 
19927110Sminshall /*
20027110Sminshall  * Make a character string into a number.
20127110Sminshall  *
20227186Sminshall  * Todo:  1.  Could take random integers (12, 0x12, 012, 0b1).
20327110Sminshall  */
2046000Sroot 
20527110Sminshall special(s)
20627110Sminshall register char *s;
20727110Sminshall {
20827110Sminshall 	register char c;
20927110Sminshall 	char b;
21027110Sminshall 
21127110Sminshall 	switch (*s) {
21227110Sminshall 	case '^':
21327110Sminshall 		b = *++s;
21427110Sminshall 		if (b == '?') {
21527228Sminshall 		    c = b | 0x40;		/* DEL */
21627110Sminshall 		} else {
21727110Sminshall 		    c = b & 0x1f;
21827110Sminshall 		}
21927110Sminshall 		break;
22027110Sminshall 	default:
22127110Sminshall 		c = *s;
22227110Sminshall 		break;
22327110Sminshall 	}
22427110Sminshall 	return c;
22527110Sminshall }
22627186Sminshall 
22727186Sminshall /*
22827186Sminshall  * Construct a control character sequence
22927186Sminshall  * for a special character.
23027186Sminshall  */
23127186Sminshall char *
23227186Sminshall control(c)
23327186Sminshall 	register int c;
23427186Sminshall {
23527186Sminshall 	static char buf[3];
23627186Sminshall 
23727228Sminshall 	if (c == 0x7f)
23827186Sminshall 		return ("^?");
23927186Sminshall 	if (c == '\377') {
24027186Sminshall 		return "off";
24127186Sminshall 	}
24227186Sminshall 	if (c >= 0x20) {
24327186Sminshall 		buf[0] = c;
24427186Sminshall 		buf[1] = 0;
24527186Sminshall 	} else {
24627186Sminshall 		buf[0] = '^';
24727186Sminshall 		buf[1] = '@'+c;
24827186Sminshall 		buf[2] = 0;
24927186Sminshall 	}
25027186Sminshall 	return (buf);
25127186Sminshall }
252*27676Sminshall 
253*27676Sminshall 
254*27676Sminshall /*
255*27676Sminshall  * upcase()
256*27676Sminshall  *
257*27676Sminshall  *	Upcase (in place) the argument.
258*27676Sminshall  */
259*27676Sminshall 
260*27676Sminshall void
261*27676Sminshall upcase(argument)
262*27676Sminshall register char *argument;
263*27676Sminshall {
264*27676Sminshall     register int c;
265*27676Sminshall 
266*27676Sminshall     while (c = *argument) {
267*27676Sminshall 	if (islower(c)) {
268*27676Sminshall 	    *argument = toupper(c);
269*27676Sminshall 	}
270*27676Sminshall 	argument++;
271*27676Sminshall     }
272*27676Sminshall }
27327110Sminshall 
27427110Sminshall /*
27527186Sminshall  * Check to see if any out-of-band data exists on a socket (for
27627186Sminshall  * Telnet "synch" processing).
27727186Sminshall  */
27827186Sminshall 
27927186Sminshall int
28027186Sminshall stilloob(s)
28127186Sminshall int	s;		/* socket number */
28227186Sminshall {
28327186Sminshall     static struct timeval timeout = { 0 };
28427186Sminshall     fd_set	excepts;
28527186Sminshall     int value;
28627186Sminshall 
28727186Sminshall     do {
28827186Sminshall 	FD_ZERO(&excepts);
28927186Sminshall 	FD_SET(s, &excepts);
29027186Sminshall 	value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout);
29127186Sminshall     } while ((value == -1) && (errno = EINTR));
29227186Sminshall 
29327186Sminshall     if (value < 0) {
29427186Sminshall 	perror("select");
29527186Sminshall 	quit();
29627186Sminshall     }
29727186Sminshall     if (FD_ISSET(s, &excepts)) {
29827186Sminshall 	return 1;
29927186Sminshall     } else {
30027186Sminshall 	return 0;
30127186Sminshall     }
30227186Sminshall }
30327186Sminshall 
30427186Sminshall 
30527186Sminshall /*
30627186Sminshall  *  netflush
30727186Sminshall  *		Send as much data as possible to the network,
30827186Sminshall  *	handling requests for urgent data.
30927186Sminshall  */
31027186Sminshall 
31127186Sminshall 
31227186Sminshall netflush(fd)
31327186Sminshall {
31427186Sminshall     int n;
31527186Sminshall 
31627186Sminshall     if ((n = nfrontp - nbackp) > 0) {
31727186Sminshall 	if (!neturg) {
31827186Sminshall 	    n = write(fd, nbackp, n);	/* normal write */
31927186Sminshall 	} else {
32027186Sminshall 	    n = neturg - nbackp;
32127186Sminshall 	    /*
32227186Sminshall 	     * In 4.2 (and 4.3) systems, there is some question about
32327186Sminshall 	     * what byte in a sendOOB operation is the "OOB" data.
32427186Sminshall 	     * To make ourselves compatible, we only send ONE byte
32527186Sminshall 	     * out of band, the one WE THINK should be OOB (though
32627186Sminshall 	     * we really have more the TCP philosophy of urgent data
32727186Sminshall 	     * rather than the Unix philosophy of OOB data).
32827186Sminshall 	     */
32927186Sminshall 	    if (n > 1) {
33027186Sminshall 		n = send(fd, nbackp, n-1, 0);	/* send URGENT all by itself */
33127186Sminshall 	    } else {
33227186Sminshall 		n = send(fd, nbackp, n, MSG_OOB);	/* URGENT data */
33327186Sminshall 	    }
33427186Sminshall 	}
33527186Sminshall     }
33627186Sminshall     if (n < 0) {
33727186Sminshall 	if (errno != ENOBUFS && errno != EWOULDBLOCK) {
33827186Sminshall 	    setcommandmode();
33927186Sminshall 	    perror(hostname);
34027186Sminshall 	    close(fd);
34127186Sminshall 	    neturg = 0;
34227186Sminshall 	    longjmp(peerdied, -1);
34327186Sminshall 	    /*NOTREACHED*/
34427186Sminshall 	}
34527186Sminshall 	n = 0;
34627186Sminshall     }
34727186Sminshall     if (netdata && n) {
34827186Sminshall 	Dump('>', nbackp, n);
34927186Sminshall     }
35027186Sminshall     nbackp += n;
35127186Sminshall     if (nbackp >= neturg) {
35227186Sminshall 	neturg = 0;
35327186Sminshall     }
35427186Sminshall     if (nbackp == nfrontp) {
35527186Sminshall 	nbackp = nfrontp = netobuf;
35627186Sminshall     }
35727186Sminshall }
35827261Sminshall 
35927261Sminshall /*
36027261Sminshall  * nextitem()
36127261Sminshall  *
36227261Sminshall  *	Return the address of the next "item" in the TELNET data
36327261Sminshall  * stream.  This will be the address of the next character if
36427261Sminshall  * the current address is a user data character, or it will
36527261Sminshall  * be the address of the character following the TELNET command
36627261Sminshall  * if the current address is a TELNET IAC ("I Am a Command")
36727261Sminshall  * character.
36827261Sminshall  */
36927186Sminshall 
37027261Sminshall char *
37127261Sminshall nextitem(current)
37227261Sminshall char	*current;
37327261Sminshall {
37427261Sminshall     if ((*current&0xff) != IAC) {
37527261Sminshall 	return current+1;
37627261Sminshall     }
37727261Sminshall     switch (*(current+1)&0xff) {
37827261Sminshall     case DO:
37927261Sminshall     case DONT:
38027261Sminshall     case WILL:
38127261Sminshall     case WONT:
38227261Sminshall 	return current+3;
38327261Sminshall     case SB:		/* loop forever looking for the SE */
38427261Sminshall 	{
38527261Sminshall 	    register char *look = current+2;
38627261Sminshall 
38727261Sminshall 	    for (;;) {
38827261Sminshall 		if ((*look++&0xff) == IAC) {
38927261Sminshall 		    if ((*look++&0xff) == SE) {
39027261Sminshall 			return look;
39127261Sminshall 		    }
39227261Sminshall 		}
39327261Sminshall 	    }
39427261Sminshall 	}
39527261Sminshall     default:
39627261Sminshall 	return current+2;
39727261Sminshall     }
39827261Sminshall }
39927186Sminshall /*
40027261Sminshall  * netclear()
40127261Sminshall  *
40227261Sminshall  *	We are about to do a TELNET SYNCH operation.  Clear
40327261Sminshall  * the path to the network.
40427261Sminshall  *
40527261Sminshall  *	Things are a bit tricky since we may have sent the first
40627261Sminshall  * byte or so of a previous TELNET command into the network.
40727261Sminshall  * So, we have to scan the network buffer from the beginning
40827261Sminshall  * until we are up to where we want to be.
40927261Sminshall  *
41027261Sminshall  *	A side effect of what we do, just to keep things
41127261Sminshall  * simple, is to clear the urgent data pointer.  The principal
41227261Sminshall  * caller should be setting the urgent data pointer AFTER calling
41327261Sminshall  * us in any case.
41427261Sminshall  */
41527261Sminshall 
41627261Sminshall netclear()
41727261Sminshall {
41827261Sminshall     register char *thisitem, *next;
41927261Sminshall     char *good;
42027261Sminshall #define	wewant(p)	((nfrontp > p) && ((*p&0xff) == IAC) && \
42127261Sminshall 				((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
42227261Sminshall 
42327261Sminshall     thisitem = netobuf;
42427261Sminshall 
42527261Sminshall     while ((next = nextitem(thisitem)) <= nbackp) {
42627261Sminshall 	thisitem = next;
42727261Sminshall     }
42827261Sminshall 
42927261Sminshall     /* Now, thisitem is first before/at boundary. */
43027261Sminshall 
43127261Sminshall     good = netobuf;	/* where the good bytes go */
43227261Sminshall 
43327261Sminshall     while (nfrontp > thisitem) {
43427261Sminshall 	if (wewant(thisitem)) {
43527261Sminshall 	    int length;
43627261Sminshall 
43727261Sminshall 	    next = thisitem;
43827261Sminshall 	    do {
43927261Sminshall 		next = nextitem(next);
44027261Sminshall 	    } while (wewant(next) && (nfrontp > next));
44127261Sminshall 	    length = next-thisitem;
44227261Sminshall 	    bcopy(thisitem, good, length);
44327261Sminshall 	    good += length;
44427261Sminshall 	    thisitem = next;
44527261Sminshall 	} else {
44627261Sminshall 	    thisitem = nextitem(thisitem);
44727261Sminshall 	}
44827261Sminshall     }
44927261Sminshall 
45027261Sminshall     nbackp = netobuf;
45127261Sminshall     nfrontp = good;		/* next byte to be sent */
45227261Sminshall     neturg = 0;
45327261Sminshall }
45427261Sminshall 
45527261Sminshall /*
45627186Sminshall  * Send as much data as possible to the terminal.
45727186Sminshall  */
45827186Sminshall 
45927186Sminshall 
46027186Sminshall ttyflush()
46127186Sminshall {
46227186Sminshall     int n;
46327186Sminshall 
46427186Sminshall     if ((n = tfrontp - tbackp) > 0) {
46527228Sminshall 	if (!(SYNCHing||flushout)) {
46627186Sminshall 	    n = write(tout, tbackp, n);
46727186Sminshall 	} else {
46827186Sminshall 	    ioctl(fileno(stdout), TIOCFLUSH, (char *) 0);
46927228Sminshall 	    /* we leave 'n' alone! */
47027186Sminshall 	}
47127186Sminshall     }
47227186Sminshall     if (n < 0) {
47327186Sminshall 	return;
47427186Sminshall     }
47527186Sminshall     tbackp += n;
47627186Sminshall     if (tbackp == tfrontp) {
47727186Sminshall 	tbackp = tfrontp = ttyobuf;
47827186Sminshall     }
47927186Sminshall }
48027186Sminshall 
48127186Sminshall /*
48227110Sminshall  * Various signal handling routines.
48327110Sminshall  */
48427110Sminshall 
48527110Sminshall deadpeer()
48627110Sminshall {
48727110Sminshall 	setcommandmode();
48827110Sminshall 	longjmp(peerdied, -1);
48927110Sminshall }
49027110Sminshall 
49127110Sminshall intr()
49227110Sminshall {
49327261Sminshall     if (localchars) {
49427110Sminshall 	intp();
49527110Sminshall 	return;
49627110Sminshall     }
49727110Sminshall     setcommandmode();
49827110Sminshall     longjmp(toplevel, -1);
49927110Sminshall }
50027110Sminshall 
50127110Sminshall intr2()
50227110Sminshall {
50327261Sminshall     if (localchars) {
50427110Sminshall 	sendbrk();
50527110Sminshall 	return;
50627110Sminshall     }
50727110Sminshall }
50827110Sminshall 
50927110Sminshall doescape()
51027110Sminshall {
51127110Sminshall     command(0);
51227110Sminshall }
51327110Sminshall 
51427110Sminshall /*
51527186Sminshall  * The following are routines used to print out debugging information.
51627186Sminshall  */
51727186Sminshall 
51827186Sminshall 
51927186Sminshall static
52027186Sminshall Dump(direction, buffer, length)
52127186Sminshall char	direction;
52227186Sminshall char	*buffer;
52327186Sminshall int	length;
52427186Sminshall {
52527186Sminshall #   define BYTES_PER_LINE	32
52627186Sminshall #   define min(x,y)	((x<y)? x:y)
52727186Sminshall     char *pThis;
52827186Sminshall     int offset;
52927186Sminshall 
53027186Sminshall     offset = 0;
53127186Sminshall 
53227186Sminshall     while (length) {
53327186Sminshall 	/* print one line */
53427186Sminshall 	fprintf(NetTrace, "%c 0x%x\t", direction, offset);
53527186Sminshall 	pThis = buffer;
53627186Sminshall 	buffer = buffer+min(length, BYTES_PER_LINE);
53727186Sminshall 	while (pThis < buffer) {
53827186Sminshall 	    fprintf(NetTrace, "%.2x", (*pThis)&0xff);
53927186Sminshall 	    pThis++;
54027186Sminshall 	}
54127186Sminshall 	fprintf(NetTrace, "\n");
54227186Sminshall 	length -= BYTES_PER_LINE;
54327186Sminshall 	offset += BYTES_PER_LINE;
54427186Sminshall 	if (length < 0) {
54527186Sminshall 	    return;
54627186Sminshall 	}
54727186Sminshall 	/* find next unique line */
54827186Sminshall     }
54927186Sminshall }
55027186Sminshall 
55127186Sminshall 
55227186Sminshall /*VARARGS*/
55327186Sminshall printoption(direction, fmt, option, what)
55427186Sminshall 	char *direction, *fmt;
55527186Sminshall 	int option, what;
55627186Sminshall {
55727186Sminshall 	if (!showoptions)
55827186Sminshall 		return;
559*27676Sminshall 	printf("%s ", direction+1);
56027186Sminshall 	if (fmt == doopt)
56127186Sminshall 		fmt = "do";
56227186Sminshall 	else if (fmt == dont)
56327186Sminshall 		fmt = "dont";
56427186Sminshall 	else if (fmt == will)
56527186Sminshall 		fmt = "will";
56627186Sminshall 	else if (fmt == wont)
56727186Sminshall 		fmt = "wont";
56827186Sminshall 	else
56927186Sminshall 		fmt = "???";
570*27676Sminshall 	if (option < (sizeof telopts/sizeof telopts[0]))
57127186Sminshall 		printf("%s %s", fmt, telopts[option]);
57227186Sminshall 	else
57327186Sminshall 		printf("%s %d", fmt, option);
57427186Sminshall 	if (*direction == '<') {
57527186Sminshall 		printf("\r\n");
57627186Sminshall 		return;
57727186Sminshall 	}
57827186Sminshall 	printf(" (%s)\r\n", what ? "reply" : "don't reply");
57927186Sminshall }
58027186Sminshall 
58127186Sminshall /*
58227110Sminshall  * Mode - set up terminal to a specific mode.
58327110Sminshall  */
58427110Sminshall 
5859972Ssam 
5866000Sroot mode(f)
5876000Sroot 	register int f;
5886000Sroot {
5898378Ssam 	static int prevmode = 0;
59013076Ssam 	struct tchars *tc;
59113076Ssam 	struct ltchars *ltc;
59213076Ssam 	struct sgttyb sb;
59313076Ssam 	int onoff, old;
59427228Sminshall 	struct	tchars notc2;
59527228Sminshall 	struct	ltchars noltc2;
59627228Sminshall 	static struct	tchars notc =	{ -1, -1, -1, -1, -1, -1 };
59727228Sminshall 	static struct	ltchars noltc =	{ -1, -1, -1, -1, -1, -1 };
5986000Sroot 
59927110Sminshall 	globalmode = f;
6008378Ssam 	if (prevmode == f)
60127186Sminshall 		return;
6028378Ssam 	old = prevmode;
6038378Ssam 	prevmode = f;
60427110Sminshall 	sb = nttyb;
6056000Sroot 	switch (f) {
6068378Ssam 
6076000Sroot 	case 0:
6086000Sroot 		onoff = 0;
6099972Ssam 		tc = &otc;
61013076Ssam 		ltc = &oltc;
6116000Sroot 		break;
6126000Sroot 
61327110Sminshall 	case 1:		/* remote character processing, remote echo */
61427110Sminshall 	case 2:		/* remote character processing, local echo */
61513076Ssam 		sb.sg_flags |= CBREAK;
6168378Ssam 		if (f == 1)
61713076Ssam 			sb.sg_flags &= ~(ECHO|CRMOD);
6188378Ssam 		else
61913076Ssam 			sb.sg_flags |= ECHO|CRMOD;
62013076Ssam 		sb.sg_erase = sb.sg_kill = -1;
6219972Ssam 		tc = &notc;
62227110Sminshall 		/*
62327110Sminshall 		 * If user hasn't specified one way or the other,
62427110Sminshall 		 * then default to not trapping signals.
62527110Sminshall 		 */
62627261Sminshall 		if (!donelclchars) {
62727261Sminshall 			localchars = 0;
62827228Sminshall 		}
62927261Sminshall 		if (localchars) {
63027110Sminshall 			notc2 = notc;
63127110Sminshall 			notc2.t_intrc = ntc.t_intrc;
63227110Sminshall 			notc2.t_quitc = ntc.t_quitc;
63327110Sminshall 			tc = &notc2;
63427110Sminshall 		} else
63527110Sminshall 			tc = &notc;
63613076Ssam 		ltc = &noltc;
6376000Sroot 		onoff = 1;
6389972Ssam 		break;
63927110Sminshall 	case 3:		/* local character processing, remote echo */
64027110Sminshall 	case 4:		/* local character processing, local echo */
64127110Sminshall 	case 5:		/* local character processing, no echo */
64227110Sminshall 		sb.sg_flags &= ~CBREAK;
64327110Sminshall 		sb.sg_flags |= CRMOD;
64427110Sminshall 		if (f == 4)
64527110Sminshall 			sb.sg_flags |= ECHO;
64627110Sminshall 		else
64727110Sminshall 			sb.sg_flags &= ~ECHO;
64827228Sminshall 		notc2 = ntc;
64927228Sminshall 		tc = &notc2;
65027228Sminshall 		noltc2 = oltc;
65127228Sminshall 		ltc = &noltc2;
65227110Sminshall 		/*
65327110Sminshall 		 * If user hasn't specified one way or the other,
65427110Sminshall 		 * then default to trapping signals.
65527110Sminshall 		 */
65627261Sminshall 		if (!donelclchars) {
65727261Sminshall 			localchars = 1;
65827228Sminshall 		}
65927261Sminshall 		if (localchars) {
66027228Sminshall 			notc2.t_brkc = nltc.t_flushc;
66127228Sminshall 			noltc2.t_flushc = -1;
66227228Sminshall 		} else {
66327110Sminshall 			notc2.t_intrc = notc2.t_quitc = -1;
66427110Sminshall 		}
66527110Sminshall 		noltc2.t_suspc = escape;
66627110Sminshall 		noltc2.t_dsuspc = -1;
66727110Sminshall 		onoff = 1;
66827110Sminshall 		break;
6699972Ssam 
6709972Ssam 	default:
6719972Ssam 		return;
6726000Sroot 	}
67313076Ssam 	ioctl(fileno(stdin), TIOCSLTC, (char *)ltc);
67413076Ssam 	ioctl(fileno(stdin), TIOCSETC, (char *)tc);
67513076Ssam 	ioctl(fileno(stdin), TIOCSETP, (char *)&sb);
67627186Sminshall 	ioctl(fileno(stdin), FIONBIO, (char *)&onoff);
67727186Sminshall 	ioctl(fileno(stdout), FIONBIO, (char *)&onoff);
67827110Sminshall 	if (f >= 3)
67927110Sminshall 		signal(SIGTSTP, doescape);
68027110Sminshall 	else if (old >= 3) {
68127110Sminshall 		signal(SIGTSTP, SIG_DFL);
68227110Sminshall 		sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
68327110Sminshall 	}
6846000Sroot }
68527186Sminshall 
68627110Sminshall /*
68727110Sminshall  * These routines decides on what the mode should be (based on the values
68827110Sminshall  * of various global variables).
68927110Sminshall  */
69027110Sminshall 
69127178Sminshall char *modedescriptions[] = {
69227178Sminshall 	"telnet command mode",					/* 0 */
69327178Sminshall 	"character-at-a-time mode",				/* 1 */
69427178Sminshall 	"character-at-a-time mode (local echo)",		/* 2 */
69527178Sminshall 	"line-by-line mode (remote echo)",			/* 3 */
69627178Sminshall 	"line-by-line mode",					/* 4 */
69727178Sminshall 	"line-by-line mode (local echoing suppressed)",		/* 5 */
69827178Sminshall };
69927178Sminshall 
70027178Sminshall getconnmode()
70127110Sminshall {
70227110Sminshall     static char newmode[8] = { 4, 5, 3, 3, 2, 2, 1, 1 };
70327186Sminshall     int modeindex = 0;
70427110Sminshall 
70527110Sminshall     if (hisopts[TELOPT_ECHO]) {
70627186Sminshall 	modeindex += 2;
70727110Sminshall     }
70827110Sminshall     if (hisopts[TELOPT_SGA]) {
70927186Sminshall 	modeindex += 4;
71027110Sminshall     }
71127186Sminshall     if (dontlecho && (clocks.echotoggle > clocks.modenegotiated)) {
71227186Sminshall 	modeindex += 1;
71327110Sminshall     }
71427186Sminshall     return newmode[modeindex];
71527110Sminshall }
71627110Sminshall 
71727178Sminshall setconnmode()
71827178Sminshall {
71927178Sminshall     mode(getconnmode());
72027178Sminshall }
72127110Sminshall 
72227178Sminshall 
72327110Sminshall setcommandmode()
72427110Sminshall {
72527110Sminshall     mode(0);
72627110Sminshall }
72727110Sminshall 
7286000Sroot char	sibuf[BUFSIZ], *sbp;
7296000Sroot char	tibuf[BUFSIZ], *tbp;
7306000Sroot int	scc, tcc;
7316000Sroot 
73227228Sminshall 
7336000Sroot /*
7346000Sroot  * Select from tty and network...
7356000Sroot  */
73627088Sminshall telnet()
7376000Sroot {
7386000Sroot 	register int c;
73927088Sminshall 	int tin = fileno(stdin);
7406000Sroot 	int on = 1;
74127261Sminshall 	fd_set ibits, obits, xbits;
7426000Sroot 
74327088Sminshall 	tout = fileno(stdout);
74427110Sminshall 	setconnmode();
74527228Sminshall 	scc = 0;
74627228Sminshall 	tcc = 0;
74727261Sminshall 	FD_ZERO(&ibits);
74827261Sminshall 	FD_ZERO(&obits);
74927261Sminshall 	FD_ZERO(&xbits);
75027261Sminshall 
75127186Sminshall 	ioctl(net, FIONBIO, (char *)&on);
752*27676Sminshall #if	defined(SO_OOBINLINE)
753*27676Sminshall 	setsockopt(net, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
754*27676Sminshall #endif	/* defined(SO_OOBINLINE) */
755*27676Sminshall 	if (telnetport) {
756*27676Sminshall 	    if (!hisopts[TELOPT_SGA]) {
757*27676Sminshall 		willoption(TELOPT_SGA, 0);
758*27676Sminshall 	    }
759*27676Sminshall 	    if (!myopts[TELOPT_TTYPE]) {
760*27676Sminshall 		dooption(TELOPT_TTYPE, 0);
761*27676Sminshall 	    }
76227088Sminshall 	}
7636000Sroot 	for (;;) {
76427110Sminshall 		if (scc < 0 && tcc < 0) {
7656000Sroot 			break;
76627110Sminshall 		}
76727110Sminshall 
76827228Sminshall 		if (((globalmode < 4) || flushline) && NETBYTES()) {
76927110Sminshall 			FD_SET(net, &obits);
77027088Sminshall 		} else {
77127110Sminshall 			FD_SET(tin, &ibits);
77227088Sminshall 		}
77327228Sminshall 		if (TTYBYTES()) {
77427110Sminshall 			FD_SET(tout, &obits);
77527110Sminshall 		} else {
77627110Sminshall 			FD_SET(net, &ibits);
77727110Sminshall 		}
77827186Sminshall 		if (!SYNCHing) {
77927110Sminshall 			FD_SET(net, &xbits);
78027110Sminshall 		}
78127186Sminshall 		if ((c = select(16, &ibits, &obits, &xbits,
78227186Sminshall 						(struct timeval *)0)) < 1) {
78327110Sminshall 			if (c == -1) {
78427110Sminshall 				/*
78527110Sminshall 				 * we can get EINTR if we are in line mode,
78627110Sminshall 				 * and the user does an escape (TSTP), or
78727110Sminshall 				 * some other signal generator.
78827110Sminshall 				 */
78927110Sminshall 				if (errno == EINTR) {
79027110Sminshall 					continue;
79127110Sminshall 				}
79227110Sminshall 			}
7936000Sroot 			sleep(5);
7946000Sroot 			continue;
7956000Sroot 		}
7966000Sroot 
7976000Sroot 		/*
79827088Sminshall 		 * Any urgent data?
79927088Sminshall 		 */
80027110Sminshall 		if (FD_ISSET(net, &xbits)) {
80127261Sminshall 		    FD_CLR(net, &xbits);
80227186Sminshall 		    SYNCHing = 1;
80327088Sminshall 		    ttyflush();	/* flush already enqueued data */
80427088Sminshall 		}
80527088Sminshall 
80627088Sminshall 		/*
8076000Sroot 		 * Something to read from the network...
8086000Sroot 		 */
80927110Sminshall 		if (FD_ISSET(net, &ibits)) {
81027228Sminshall 			int canread;
81127228Sminshall 
81227261Sminshall 			FD_CLR(net, &ibits);
81327228Sminshall 			if (scc == 0) {
81427228Sminshall 			    sbp = sibuf;
81527228Sminshall 			}
81627228Sminshall 			canread = sibuf + sizeof sibuf - sbp;
817*27676Sminshall #if	!defined(SO_OOBINLINE)
81827178Sminshall 			/*
81927178Sminshall 			 * In 4.2 (and some early 4.3) systems, the
82027178Sminshall 			 * OOB indication and data handling in the kernel
82127178Sminshall 			 * is such that if two separate TCP Urgent requests
82227178Sminshall 			 * come in, one byte of TCP data will be overlaid.
82327178Sminshall 			 * This is fatal for Telnet, but we try to live
82427178Sminshall 			 * with it.
82527178Sminshall 			 *
82627178Sminshall 			 * In addition, in 4.2 (and...), a special protocol
82727178Sminshall 			 * is needed to pick up the TCP Urgent data in
82827178Sminshall 			 * the correct sequence.
82927178Sminshall 			 *
83027178Sminshall 			 * What we do is:  if we think we are in urgent
83127178Sminshall 			 * mode, we look to see if we are "at the mark".
83227178Sminshall 			 * If we are, we do an OOB receive.  If we run
83327178Sminshall 			 * this twice, we will do the OOB receive twice,
83427178Sminshall 			 * but the second will fail, since the second
83527178Sminshall 			 * time we were "at the mark", but there wasn't
83627178Sminshall 			 * any data there (the kernel doesn't reset
83727178Sminshall 			 * "at the mark" until we do a normal read).
83827178Sminshall 			 * Once we've read the OOB data, we go ahead
83927178Sminshall 			 * and do normal reads.
84027178Sminshall 			 *
84127178Sminshall 			 * There is also another problem, which is that
84227178Sminshall 			 * since the OOB byte we read doesn't put us
84327178Sminshall 			 * out of OOB state, and since that byte is most
84427178Sminshall 			 * likely the TELNET DM (data mark), we would
84527186Sminshall 			 * stay in the TELNET SYNCH (SYNCHing) state.
84627178Sminshall 			 * So, clocks to the rescue.  If we've "just"
84727178Sminshall 			 * received a DM, then we test for the
84827178Sminshall 			 * presence of OOB data when the receive OOB
84927178Sminshall 			 * fails (and AFTER we did the normal mode read
85027178Sminshall 			 * to clear "at the mark").
85127178Sminshall 			 */
85227186Sminshall 		    if (SYNCHing) {
85327178Sminshall 			int atmark;
85427178Sminshall 
85527186Sminshall 			ioctl(net, SIOCATMARK, (char *)&atmark);
85627178Sminshall 			if (atmark) {
85727228Sminshall 			    c = recv(net, sibuf, canread, MSG_OOB);
85827228Sminshall 			    if ((c == -1) && (errno == EINVAL)) {
85927228Sminshall 				c = read(net, sibuf, canread);
86027186Sminshall 				if (clocks.didnetreceive < clocks.gotDM) {
86127186Sminshall 				    SYNCHing = stilloob(net);
86227021Sminshall 				}
86327178Sminshall 			    }
86427178Sminshall 			} else {
86527228Sminshall 			    c = read(net, sibuf, canread);
8666000Sroot 			}
86727178Sminshall 		    } else {
86827228Sminshall 			c = read(net, sibuf, canread);
86927178Sminshall 		    }
87027178Sminshall 		    settimer(didnetreceive);
871*27676Sminshall #else	/* !defined(SO_OOBINLINE) */
87227228Sminshall 		    c = read(net, sbp, canread);
873*27676Sminshall #endif	/* !defined(SO_OOBINLINE) */
87427228Sminshall 		    if (c < 0 && errno == EWOULDBLOCK) {
87527228Sminshall 			c = 0;
87627228Sminshall 		    } else if (c <= 0) {
87727228Sminshall 			break;
87827178Sminshall 		    }
87927228Sminshall 		    if (netdata) {
88027228Sminshall 			Dump('<', sbp, c);
88127228Sminshall 		    }
88227228Sminshall 		    scc += c;
8836000Sroot 		}
8846000Sroot 
8856000Sroot 		/*
8866000Sroot 		 * Something to read from the tty...
8876000Sroot 		 */
88827110Sminshall 		if (FD_ISSET(tin, &ibits)) {
88927261Sminshall 			FD_CLR(tin, &ibits);
89027228Sminshall 			if (tcc == 0) {
89127228Sminshall 			    tbp = tibuf;	/* nothing left, reset */
8926000Sroot 			}
89327228Sminshall 			c = read(tin, tbp, tibuf+sizeof tibuf - tbp);
89427228Sminshall 			if (c < 0 && errno == EWOULDBLOCK) {
89527228Sminshall 				c = 0;
896*27676Sminshall 			} else {
897*27676Sminshall 				/* EOF detection for line mode!!!! */
898*27676Sminshall 				if (c == 0 && globalmode >= 3) {
899*27676Sminshall 					/* must be an EOF... */
900*27676Sminshall 					*tbp = ntc.t_eofc;
901*27676Sminshall 					c = 1;
902*27676Sminshall 				}
903*27676Sminshall 				if (c <= 0) {
904*27676Sminshall 					tcc = c;
905*27676Sminshall 					break;
906*27676Sminshall 				}
90727228Sminshall 			}
90827228Sminshall 			tcc += c;
9096000Sroot 		}
9106000Sroot 
9116000Sroot 		while (tcc > 0) {
91227186Sminshall 			register int sc;
9136000Sroot 
91427228Sminshall 			if (NETROOM() < 2) {
91527110Sminshall 				flushline = 1;
9166000Sroot 				break;
91727110Sminshall 			}
91827186Sminshall 			c = *tbp++ & 0xff, sc = strip(c), tcc--;
91927186Sminshall 			if (sc == escape) {
9206000Sroot 				command(0);
9216000Sroot 				tcc = 0;
92227110Sminshall 				flushline = 1;
9236000Sroot 				break;
92427261Sminshall 			} else if ((globalmode >= 4) && (sc == echoc)) {
92527110Sminshall 				if (tcc > 0 && strip(*tbp) == echoc) {
92627110Sminshall 					tbp++;
92727110Sminshall 					tcc--;
92827110Sminshall 				} else {
92927110Sminshall 					dontlecho = !dontlecho;
93027110Sminshall 					settimer(echotoggle);
93127110Sminshall 					setconnmode();
93227110Sminshall 					tcc = 0;
93327110Sminshall 					flushline = 1;
93427110Sminshall 					break;
93527110Sminshall 				}
9366000Sroot 			}
93727261Sminshall 			if (localchars) {
93827186Sminshall 				if (sc == ntc.t_intrc) {
93927110Sminshall 					intp();
94027110Sminshall 					break;
94127186Sminshall 				} else if (sc == ntc.t_quitc) {
94227110Sminshall 					sendbrk();
94327110Sminshall 					break;
94427228Sminshall 				} else if (sc == nltc.t_flushc) {
94527228Sminshall 					NET2ADD(IAC, AO);
94627228Sminshall 					if (autoflush) {
94727228Sminshall 					    doflush();
94827228Sminshall 					}
94927228Sminshall 					break;
95027110Sminshall 				} else if (globalmode > 2) {
95127110Sminshall 					;
95227186Sminshall 				} else if (sc == nttyb.sg_kill) {
95327110Sminshall 					NET2ADD(IAC, EL);
95427110Sminshall 					break;
95527186Sminshall 				} else if (sc == nttyb.sg_erase) {
95627110Sminshall 					NET2ADD(IAC, EC);
95727110Sminshall 					break;
95827110Sminshall 				}
95927110Sminshall 			}
96017922Sralph 			switch (c) {
96117922Sralph 			case '\n':
96227021Sminshall 				/*
96327021Sminshall 				 * If echoing is happening locally,
96427021Sminshall 				 * then a newline (unix) is CRLF (TELNET).
96527021Sminshall 				 */
96627088Sminshall 				if (!hisopts[TELOPT_ECHO]) {
96727088Sminshall 					NETADD('\r');
96827088Sminshall 				}
96927088Sminshall 				NETADD('\n');
97027110Sminshall 				flushline = 1;
97117922Sralph 				break;
97217922Sralph 			case '\r':
97327088Sminshall 				NET2ADD('\r', '\0');
97427110Sminshall 				flushline = 1;
97517922Sralph 				break;
97617922Sralph 			case IAC:
97727088Sminshall 				NET2ADD(IAC, IAC);
97827021Sminshall 				break;
97917922Sralph 			default:
98027088Sminshall 				NETADD(c);
98117922Sralph 				break;
98217922Sralph 			}
9836000Sroot 		}
98427110Sminshall 		if (((globalmode < 4) || flushline) &&
98527228Sminshall 		    FD_ISSET(net, &obits) && (NETBYTES() > 0)) {
98627261Sminshall 			FD_CLR(net, &obits);
98727088Sminshall 			netflush(net);
98827110Sminshall 		}
9896000Sroot 		if (scc > 0)
9906000Sroot 			telrcv();
99127261Sminshall 		if (FD_ISSET(tout, &obits) && (TTYBYTES() > 0)) {
99227261Sminshall 			FD_CLR(tout, &obits);
99327088Sminshall 			ttyflush();
99427261Sminshall 		}
9956000Sroot 	}
99627110Sminshall 	setcommandmode();
9976000Sroot }
99827110Sminshall 
9996000Sroot /*
10006000Sroot  * Telnet receiver states for fsm
10016000Sroot  */
10026000Sroot #define	TS_DATA		0
10036000Sroot #define	TS_IAC		1
10046000Sroot #define	TS_WILL		2
10056000Sroot #define	TS_WONT		3
10066000Sroot #define	TS_DO		4
10076000Sroot #define	TS_DONT		5
100827021Sminshall #define	TS_CR		6
1009*27676Sminshall #define	TS_SB		7		/* sub-option collection */
1010*27676Sminshall #define	TS_SE		8		/* looking for sub-option end */
10116000Sroot 
10126000Sroot telrcv()
10136000Sroot {
10146000Sroot 	register int c;
10156000Sroot 	static int state = TS_DATA;
10166000Sroot 
101727228Sminshall 	while ((scc > 0) && (TTYROOM() > 2)) {
101827186Sminshall 		c = *sbp++ & 0xff, scc--;
10196000Sroot 		switch (state) {
10206000Sroot 
102127021Sminshall 		case TS_CR:
102227021Sminshall 			state = TS_DATA;
102327228Sminshall 			if (c == '\0') {
102427228Sminshall 			    break;	/* Ignore \0 after CR */
102527228Sminshall 			} else if (c == '\n') {
102627228Sminshall 			    if (hisopts[TELOPT_ECHO] && !crmod) {
102727228Sminshall 				TTYADD(c);
102827228Sminshall 			    }
102927228Sminshall 			    break;
103027021Sminshall 			}
103127228Sminshall 			/* Else, fall through */
103227021Sminshall 
10336000Sroot 		case TS_DATA:
10349972Ssam 			if (c == IAC) {
10356000Sroot 				state = TS_IAC;
10369972Ssam 				continue;
10379972Ssam 			}
103827228Sminshall 			    /*
103927228Sminshall 			     * The 'crmod' hack (see following) is needed
104027228Sminshall 			     * since we can't * set CRMOD on output only.
104127228Sminshall 			     * Machines like MULTICS like to send \r without
104227228Sminshall 			     * \n; since we must turn off CRMOD to get proper
104327228Sminshall 			     * input, the mapping is done here (sigh).
104427228Sminshall 			     */
104527021Sminshall 			if (c == '\r') {
104627021Sminshall 				if (scc > 0) {
104727186Sminshall 					c = *sbp&0xff;
104827021Sminshall 					if (c == 0) {
104927021Sminshall 						sbp++, scc--;
105027228Sminshall 						/* a "true" CR */
105127088Sminshall 						TTYADD('\r');
105227021Sminshall 					} else if (!hisopts[TELOPT_ECHO] &&
105327021Sminshall 								(c == '\n')) {
105427021Sminshall 						sbp++, scc--;
105527088Sminshall 						TTYADD('\n');
105627021Sminshall 					} else {
105727088Sminshall 						TTYADD('\r');
105827228Sminshall 						if (crmod) {
105927228Sminshall 							TTYADD('\n');
106027228Sminshall 						}
106127021Sminshall 					}
106227021Sminshall 				} else {
106327021Sminshall 					state = TS_CR;
106427088Sminshall 					TTYADD('\r');
106527228Sminshall 					if (crmod) {
106627228Sminshall 						TTYADD('\n');
106727228Sminshall 					}
106827021Sminshall 				}
106927021Sminshall 			} else {
107027088Sminshall 				TTYADD(c);
107127021Sminshall 			}
10726000Sroot 			continue;
10736000Sroot 
10746000Sroot 		case TS_IAC:
10756000Sroot 			switch (c) {
10766000Sroot 
10776000Sroot 			case WILL:
10786000Sroot 				state = TS_WILL;
10796000Sroot 				continue;
10806000Sroot 
10816000Sroot 			case WONT:
10826000Sroot 				state = TS_WONT;
10836000Sroot 				continue;
10846000Sroot 
10856000Sroot 			case DO:
10866000Sroot 				state = TS_DO;
10876000Sroot 				continue;
10886000Sroot 
10896000Sroot 			case DONT:
10906000Sroot 				state = TS_DONT;
10916000Sroot 				continue;
10926000Sroot 
10936000Sroot 			case DM:
109427088Sminshall 				/*
109527088Sminshall 				 * We may have missed an urgent notification,
109627088Sminshall 				 * so make sure we flush whatever is in the
109727088Sminshall 				 * buffer currently.
109827088Sminshall 				 */
109927186Sminshall 				SYNCHing = 1;
110027088Sminshall 				ttyflush();
110127186Sminshall 				SYNCHing = stilloob(net);
110227178Sminshall 				settimer(gotDM);
11036000Sroot 				break;
11046000Sroot 
11056000Sroot 			case NOP:
11066000Sroot 			case GA:
11076000Sroot 				break;
11086000Sroot 
1109*27676Sminshall 			case SB:
1110*27676Sminshall 				SB_CLEAR();
1111*27676Sminshall 				state = TS_SB;
1112*27676Sminshall 				continue;
1113*27676Sminshall 
11146000Sroot 			default:
11156000Sroot 				break;
11166000Sroot 			}
11176000Sroot 			state = TS_DATA;
11186000Sroot 			continue;
11196000Sroot 
11206000Sroot 		case TS_WILL:
1121*27676Sminshall 			printoption(">RCVD", will, c, !hisopts[c]);
112227110Sminshall 			if (c == TELOPT_TM) {
112327110Sminshall 				if (flushout) {
112427186Sminshall 					flushout = 0;
112527110Sminshall 				}
112627110Sminshall 			} else if (!hisopts[c]) {
1127*27676Sminshall 				willoption(c, 1);
112827110Sminshall 			}
11296000Sroot 			state = TS_DATA;
11306000Sroot 			continue;
11316000Sroot 
11326000Sroot 		case TS_WONT:
1133*27676Sminshall 			printoption(">RCVD", wont, c, hisopts[c]);
113427110Sminshall 			if (c == TELOPT_TM) {
113527110Sminshall 				if (flushout) {
113627186Sminshall 					flushout = 0;
113727110Sminshall 				}
113827110Sminshall 			} else if (hisopts[c]) {
1139*27676Sminshall 				wontoption(c, 1);
114027110Sminshall 			}
11416000Sroot 			state = TS_DATA;
11426000Sroot 			continue;
11436000Sroot 
11446000Sroot 		case TS_DO:
1145*27676Sminshall 			printoption(">RCVD", doopt, c, !myopts[c]);
11466000Sroot 			if (!myopts[c])
11476000Sroot 				dooption(c);
11486000Sroot 			state = TS_DATA;
11496000Sroot 			continue;
11506000Sroot 
11516000Sroot 		case TS_DONT:
1152*27676Sminshall 			printoption(">RCVD", dont, c, myopts[c]);
11536000Sroot 			if (myopts[c]) {
11546000Sroot 				myopts[c] = 0;
11556000Sroot 				sprintf(nfrontp, wont, c);
11568378Ssam 				nfrontp += sizeof (wont) - 2;
115727110Sminshall 				flushline = 1;
115827110Sminshall 				setconnmode();	/* set new tty mode (maybe) */
1159*27676Sminshall 				printoption(">SENT", wont, c);
11606000Sroot 			}
11616000Sroot 			state = TS_DATA;
11626000Sroot 			continue;
1163*27676Sminshall 		case TS_SB:
1164*27676Sminshall 			if (c == IAC) {
1165*27676Sminshall 				state = TS_SE;
1166*27676Sminshall 			} else {
1167*27676Sminshall 				SB_ACCUM(c);
1168*27676Sminshall 			}
1169*27676Sminshall 			continue;
1170*27676Sminshall 
1171*27676Sminshall 		case TS_SE:
1172*27676Sminshall 			if (c != SE) {
1173*27676Sminshall 				if (c != IAC) {
1174*27676Sminshall 					SB_ACCUM(IAC);
1175*27676Sminshall 				}
1176*27676Sminshall 				SB_ACCUM(c);
1177*27676Sminshall 				state = TS_SB;
1178*27676Sminshall 			} else {
1179*27676Sminshall 				SB_TERM();
1180*27676Sminshall 				suboption();	/* handle sub-option */
1181*27676Sminshall 				state = TS_DATA;
1182*27676Sminshall 			}
11836000Sroot 		}
11846000Sroot 	}
11856000Sroot }
118627110Sminshall 
1187*27676Sminshall willoption(option, reply)
1188*27676Sminshall 	int option, reply;
11896000Sroot {
11906000Sroot 	char *fmt;
11916000Sroot 
11926000Sroot 	switch (option) {
11936000Sroot 
11946000Sroot 	case TELOPT_ECHO:
11956000Sroot 	case TELOPT_SGA:
119627110Sminshall 		settimer(modenegotiated);
11976000Sroot 		hisopts[option] = 1;
11986000Sroot 		fmt = doopt;
119927110Sminshall 		setconnmode();		/* possibly set new tty mode */
12006000Sroot 		break;
12016000Sroot 
12026000Sroot 	case TELOPT_TM:
120327110Sminshall 		return;			/* Never reply to TM will's/wont's */
12046000Sroot 
12056000Sroot 	default:
12066000Sroot 		fmt = dont;
12076000Sroot 		break;
12086000Sroot 	}
12096024Ssam 	sprintf(nfrontp, fmt, option);
12108378Ssam 	nfrontp += sizeof (dont) - 2;
1211*27676Sminshall 	if (reply)
1212*27676Sminshall 		printoption(">SENT", fmt, option);
1213*27676Sminshall 	else
1214*27676Sminshall 		printoption("<SENT", fmt, option);
12156000Sroot }
12166000Sroot 
1217*27676Sminshall wontoption(option, reply)
1218*27676Sminshall 	int option, reply;
12196000Sroot {
12206000Sroot 	char *fmt;
12216000Sroot 
12226000Sroot 	switch (option) {
12236000Sroot 
12246000Sroot 	case TELOPT_ECHO:
12256000Sroot 	case TELOPT_SGA:
122627110Sminshall 		settimer(modenegotiated);
12276000Sroot 		hisopts[option] = 0;
12286000Sroot 		fmt = dont;
122927110Sminshall 		setconnmode();			/* Set new tty mode */
12306000Sroot 		break;
12316000Sroot 
123227110Sminshall 	case TELOPT_TM:
123327110Sminshall 		return;		/* Never reply to TM will's/wont's */
123427110Sminshall 
12356000Sroot 	default:
12366000Sroot 		fmt = dont;
12376000Sroot 	}
12386000Sroot 	sprintf(nfrontp, fmt, option);
12398378Ssam 	nfrontp += sizeof (doopt) - 2;
1240*27676Sminshall 	if (reply)
1241*27676Sminshall 		printoption(">SENT", fmt, option);
1242*27676Sminshall 	else
1243*27676Sminshall 		printoption("<SENT", fmt, option);
12446000Sroot }
12456000Sroot 
12466000Sroot dooption(option)
12476000Sroot 	int option;
12486000Sroot {
12496000Sroot 	char *fmt;
12506000Sroot 
12516000Sroot 	switch (option) {
12526000Sroot 
12536000Sroot 	case TELOPT_TM:
125413231Ssam 		fmt = will;
125513231Ssam 		break;
125613231Ssam 
1257*27676Sminshall 	case TELOPT_TTYPE:		/* terminal type option */
125827110Sminshall 	case TELOPT_SGA:		/* no big deal */
12596000Sroot 		fmt = will;
126027110Sminshall 		myopts[option] = 1;
12616000Sroot 		break;
12626000Sroot 
126327110Sminshall 	case TELOPT_ECHO:		/* We're never going to echo... */
12646000Sroot 	default:
12656000Sroot 		fmt = wont;
12666000Sroot 		break;
12676000Sroot 	}
12686000Sroot 	sprintf(nfrontp, fmt, option);
12698378Ssam 	nfrontp += sizeof (doopt) - 2;
1270*27676Sminshall 	printoption(">SENT", fmt, option);
12716000Sroot }
1272*27676Sminshall 
1273*27676Sminshall /*
1274*27676Sminshall  * suboption()
1275*27676Sminshall  *
1276*27676Sminshall  *	Look at the sub-option buffer, and try to be helpful to the other
1277*27676Sminshall  * side.
1278*27676Sminshall  *
1279*27676Sminshall  *	Currently we recognize:
1280*27676Sminshall  *
1281*27676Sminshall  *		Terminal type, send request.
1282*27676Sminshall  */
1283*27676Sminshall 
1284*27676Sminshall suboption()
1285*27676Sminshall {
1286*27676Sminshall     switch (subbuffer[0]&0xff) {
1287*27676Sminshall     case TELOPT_TTYPE:
1288*27676Sminshall 	if ((subbuffer[1]&0xff) != TELQUAL_SEND) {
1289*27676Sminshall 	    ;
1290*27676Sminshall 	} else {
1291*27676Sminshall 	    char *name;
1292*27676Sminshall 	    char namebuf[41];
1293*27676Sminshall 	    char *getenv();
1294*27676Sminshall 	    int len;
1295*27676Sminshall 
1296*27676Sminshall 	    name = getenv("TERM");
1297*27676Sminshall 	    if ((name == 0) || ((len = strlen(name)) > 40)) {
1298*27676Sminshall 		name = "UNKNOWN";
1299*27676Sminshall 	    }
1300*27676Sminshall 	    if ((len + 4+2) < NETROOM()) {
1301*27676Sminshall 		strcpy(namebuf, name);
1302*27676Sminshall 		upcase(namebuf);
1303*27676Sminshall 		sprintf(nfrontp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
1304*27676Sminshall 				    TELQUAL_IS, namebuf, IAC, SE);
1305*27676Sminshall 		nfrontp += 4+strlen(namebuf)+2;
1306*27676Sminshall 	    }
1307*27676Sminshall 	}
1308*27676Sminshall 
1309*27676Sminshall     default:
1310*27676Sminshall 	break;
1311*27676Sminshall     }
1312*27676Sminshall }
131327110Sminshall 
13146000Sroot /*
131527088Sminshall  *	The following are data structures and routines for
131627088Sminshall  *	the "send" command.
131727088Sminshall  *
131827088Sminshall  */
131927088Sminshall 
132027088Sminshall struct sendlist {
132127088Sminshall     char	*name;		/* How user refers to it (case independent) */
132227088Sminshall     int		what;		/* Character to be sent (<0 ==> special) */
132327088Sminshall     char	*help;		/* Help information (0 ==> no help) */
132427088Sminshall     int		(*routine)();	/* Routine to perform (for special ops) */
132527088Sminshall };
132627088Sminshall 
132727186Sminshall /*ARGSUSED*/
132827088Sminshall dosynch(s)
132927088Sminshall struct sendlist *s;
133027088Sminshall {
133127261Sminshall     netclear();			/* clear the path to the network */
133227088Sminshall     NET2ADD(IAC, DM);
133327186Sminshall     neturg = NETLOC()-1;	/* Some systems are off by one XXX */
133427088Sminshall }
133527088Sminshall 
133627228Sminshall doflush()
133727228Sminshall {
133827228Sminshall     NET2ADD(IAC, DO);
133927228Sminshall     NETADD(TELOPT_TM);
134027228Sminshall     flushline = 1;
134127228Sminshall     flushout = 1;
134227228Sminshall     ttyflush();
1343*27676Sminshall     /* do printoption AFTER flush, otherwise the output gets tossed... */
1344*27676Sminshall     printoption("<SENT", doopt, TELOPT_TM);
134527228Sminshall }
134627228Sminshall 
134727088Sminshall intp()
134827088Sminshall {
134927110Sminshall     NET2ADD(IAC, IP);
135027228Sminshall     if (autoflush) {
135127228Sminshall 	doflush();
135227228Sminshall     }
135327228Sminshall     if (autosynch) {
135427228Sminshall 	dosynch();
135527228Sminshall     }
135627088Sminshall }
135727088Sminshall 
135827110Sminshall sendbrk()
135927110Sminshall {
136027186Sminshall     NET2ADD(IAC, BREAK);
136127228Sminshall     if (autoflush) {
136227228Sminshall 	doflush();
136327228Sminshall     }
136427228Sminshall     if (autosynch) {
136527228Sminshall 	dosynch();
136627228Sminshall     }
136727110Sminshall }
136827088Sminshall 
136927110Sminshall 
137027088Sminshall #define	SENDQUESTION	-1
137127088Sminshall #define	SENDESCAPE	-3
137227088Sminshall 
137327088Sminshall struct sendlist Sendlist[] = {
137427088Sminshall     { "ao", AO, "Send Telnet Abort output" },
137527088Sminshall     { "ayt", AYT, "Send Telnet 'Are You There'" },
137627261Sminshall     { "brk", BREAK, "Send Telnet Break" },
137727088Sminshall     { "ec", EC, "Send Telnet Erase Character" },
137827088Sminshall     { "el", EL, "Send Telnet Erase Line" },
137927261Sminshall     { "escape", SENDESCAPE, "Send current escape character" },
138027088Sminshall     { "ga", GA, "Send Telnet 'Go Ahead' sequence" },
138127261Sminshall     { "ip", IP, "Send Telnet Interrupt Process" },
138227088Sminshall     { "nop", NOP, "Send Telnet 'No operation'" },
138327261Sminshall     { "synch", SYNCH, "Perform Telnet 'Synch operation'", dosynch },
138427088Sminshall     { "?", SENDQUESTION, "Display send options" },
138527088Sminshall     { 0 }
138627088Sminshall };
138727088Sminshall 
138827261Sminshall struct sendlist Sendlist2[] = {		/* some synonyms */
138927261Sminshall 	{ "break", BREAK, 0 },
139027261Sminshall 
139127261Sminshall 	{ "intp", IP, 0 },
139227261Sminshall 	{ "interrupt", IP, 0 },
139327261Sminshall 	{ "intr", IP, 0 },
139427261Sminshall 
139527261Sminshall 	{ "help", SENDQUESTION, 0 },
139627261Sminshall 
139727261Sminshall 	{ 0 }
139827261Sminshall };
139927261Sminshall 
140027088Sminshall char **
140127088Sminshall getnextsend(name)
140227088Sminshall char *name;
140327088Sminshall {
140427088Sminshall     struct sendlist *c = (struct sendlist *) name;
140527088Sminshall 
140627088Sminshall     return (char **) (c+1);
140727088Sminshall }
140827088Sminshall 
140927088Sminshall struct sendlist *
141027088Sminshall getsend(name)
141127088Sminshall char *name;
141227088Sminshall {
141327261Sminshall     struct sendlist *sl;
141427261Sminshall 
141527261Sminshall     if (sl = (struct sendlist *)
141627261Sminshall 				genget(name, (char **) Sendlist, getnextsend)) {
141727261Sminshall 	return sl;
141827261Sminshall     } else {
141927261Sminshall 	return (struct sendlist *)
142027261Sminshall 				genget(name, (char **) Sendlist2, getnextsend);
142127261Sminshall     }
142227088Sminshall }
142327088Sminshall 
142427088Sminshall sendcmd(argc, argv)
142527088Sminshall int	argc;
142627088Sminshall char	**argv;
142727088Sminshall {
142827088Sminshall     int what;		/* what we are sending this time */
142927088Sminshall     int count;		/* how many bytes we are going to need to send */
143027088Sminshall     int hadsynch;	/* are we going to process a "synch"? */
143127088Sminshall     int i;
143227261Sminshall     int question = 0;	/* was at least one argument a question */
143327088Sminshall     struct sendlist *s;	/* pointer to current command */
143427088Sminshall 
143527088Sminshall     if (argc < 2) {
143627088Sminshall 	printf("need at least one argument for 'send' command\n");
143727088Sminshall 	printf("'send ?' for help\n");
143827261Sminshall 	return 0;
143927088Sminshall     }
144027088Sminshall     /*
144127088Sminshall      * First, validate all the send arguments.
144227088Sminshall      * In addition, we see how much space we are going to need, and
144327088Sminshall      * whether or not we will be doing a "SYNCH" operation (which
144427088Sminshall      * flushes the network queue).
144527088Sminshall      */
144627088Sminshall     count = 0;
144727088Sminshall     hadsynch = 0;
144827088Sminshall     for (i = 1; i < argc; i++) {
144927088Sminshall 	s = getsend(argv[i]);
145027088Sminshall 	if (s == 0) {
145127088Sminshall 	    printf("Unknown send argument '%s'\n'send ?' for help.\n",
145227088Sminshall 			argv[i]);
145327261Sminshall 	    return 0;
145427186Sminshall 	} else if (s == Ambiguous(struct sendlist *)) {
145527088Sminshall 	    printf("Ambiguous send argument '%s'\n'send ?' for help.\n",
145627088Sminshall 			argv[i]);
145727261Sminshall 	    return 0;
145827088Sminshall 	}
145927088Sminshall 	switch (s->what) {
146027088Sminshall 	case SENDQUESTION:
146127088Sminshall 	    break;
146227088Sminshall 	case SENDESCAPE:
146327088Sminshall 	    count += 1;
146427088Sminshall 	    break;
146527088Sminshall 	case SYNCH:
146627088Sminshall 	    hadsynch = 1;
146727088Sminshall 	    count += 2;
146827088Sminshall 	    break;
146927088Sminshall 	default:
147027088Sminshall 	    count += 2;
147127088Sminshall 	    break;
147227088Sminshall 	}
147327088Sminshall     }
147427088Sminshall     /* Now, do we have enough room? */
147527228Sminshall     if (NETROOM() < count) {
147627088Sminshall 	printf("There is not enough room in the buffer TO the network\n");
147727088Sminshall 	printf("to process your request.  Nothing will be done.\n");
147827088Sminshall 	printf("('send synch' will throw away most data in the network\n");
147927088Sminshall 	printf("buffer, if this might help.)\n");
148027261Sminshall 	return 0;
148127088Sminshall     }
148227088Sminshall     /* OK, they are all OK, now go through again and actually send */
148327088Sminshall     for (i = 1; i < argc; i++) {
148427088Sminshall 	if (!(s = getsend(argv[i]))) {
148527088Sminshall 	    fprintf(stderr, "Telnet 'send' error - argument disappeared!\n");
148627088Sminshall 	    quit();
148727088Sminshall 	    /*NOTREACHED*/
148827088Sminshall 	}
148927088Sminshall 	if (s->routine) {
149027088Sminshall 	    (*s->routine)(s);
149127088Sminshall 	} else {
149227088Sminshall 	    switch (what = s->what) {
149327261Sminshall 	    case SYNCH:
149427261Sminshall 		dosynch();
149527261Sminshall 		break;
149627088Sminshall 	    case SENDQUESTION:
149727088Sminshall 		for (s = Sendlist; s->name; s++) {
149827261Sminshall 		    if (s->help) {
149927088Sminshall 			printf(s->name);
150027088Sminshall 			if (s->help) {
150127088Sminshall 			    printf("\t%s", s->help);
150227088Sminshall 			}
150327088Sminshall 			printf("\n");
150427088Sminshall 		    }
150527088Sminshall 		}
150627261Sminshall 		question = 1;
150727088Sminshall 		break;
150827088Sminshall 	    case SENDESCAPE:
150927088Sminshall 		NETADD(escape);
151027088Sminshall 		break;
151127088Sminshall 	    default:
151227088Sminshall 		NET2ADD(IAC, what);
151327088Sminshall 		break;
151427088Sminshall 	    }
151527088Sminshall 	}
151627088Sminshall     }
151727261Sminshall     return !question;
151827088Sminshall }
151927088Sminshall 
152027088Sminshall /*
152127088Sminshall  * The following are the routines and data structures referred
152227088Sminshall  * to by the arguments to the "toggle" command.
152327088Sminshall  */
152427088Sminshall 
152527261Sminshall lclchars()
152627110Sminshall {
152727261Sminshall     donelclchars = 1;
152827261Sminshall     return 1;
152927110Sminshall }
153027110Sminshall 
153127178Sminshall togdebug()
153227088Sminshall {
1533*27676Sminshall #ifndef	NOT43
153427110Sminshall     if (net > 0 &&
153527186Sminshall 	setsockopt(net, SOL_SOCKET, SO_DEBUG, (char *)&debug, sizeof(debug))
153627186Sminshall 									< 0) {
153727110Sminshall 	    perror("setsockopt (SO_DEBUG)");
153827186Sminshall     }
1539*27676Sminshall #else	NOT43
1540*27676Sminshall     if (debug) {
1541*27676Sminshall 	if (net > 0 && setsockopt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
1542*27676Sminshall 	    perror("setsockopt (SO_DEBUG)");
1543*27676Sminshall     } else
1544*27676Sminshall 	printf("Cannot turn off socket debugging\n");
1545*27676Sminshall #endif	NOT43
154627261Sminshall     return 1;
154727088Sminshall }
154827088Sminshall 
154927088Sminshall 
155027088Sminshall 
155127088Sminshall int togglehelp();
155227088Sminshall 
155327178Sminshall struct togglelist {
155427178Sminshall     char	*name;		/* name of toggle */
155527178Sminshall     char	*help;		/* help message */
155627186Sminshall     int		(*handler)();	/* routine to do actual setting */
155727178Sminshall     int		dohelp;		/* should we display help information */
155827178Sminshall     int		*variable;
155927178Sminshall     char	*actionexplanation;
156027178Sminshall };
156127178Sminshall 
156227178Sminshall struct togglelist Togglelist[] = {
156327261Sminshall     { "autoflush",
156427261Sminshall 	"toggle flushing of output when sending interrupt characters",
156527186Sminshall 	    0,
156627178Sminshall 		1,
156727261Sminshall 		    &autoflush,
156827261Sminshall 			"flush output when sending interrupt characters" },
156927186Sminshall     { "autosynch",
157027186Sminshall 	"toggle automatic sending of interrupt characters in urgent mode",
157127186Sminshall 	    0,
157227186Sminshall 		1,
157327186Sminshall 		    &autosynch,
157427186Sminshall 			"send interrupt characters in urgent mode" },
157527178Sminshall     { "crmod",
157627261Sminshall 	"toggle mapping of received carriage returns",
157727186Sminshall 	    0,
157827178Sminshall 		1,
157927178Sminshall 		    &crmod,
158027178Sminshall 			"map carriage return on output" },
158127261Sminshall     { "localchars",
158227261Sminshall 	"toggle local recognition of certain control characters",
158327261Sminshall 	    lclchars,
158427261Sminshall 		1,
158527261Sminshall 		    &localchars,
158627261Sminshall 			"recognize certain control characters" },
158727110Sminshall     { " ", "", 0, 1 },		/* empty line */
158827178Sminshall     { "debug",
158927178Sminshall 	"(debugging) toggle debugging",
159027178Sminshall 	    togdebug,
159127178Sminshall 		1,
159227178Sminshall 		    &debug,
159327178Sminshall 			"turn on socket level debugging" },
159427261Sminshall     { "netdata",
159527261Sminshall 	"(debugging) toggle printing of hexadecimal network data",
159627261Sminshall 	    0,
159727261Sminshall 		1,
159827261Sminshall 		    &netdata,
159927261Sminshall 			"print hexadecimal representation of network traffic" },
160027178Sminshall     { "options",
160127178Sminshall 	"(debugging) toggle viewing of options processing",
160227186Sminshall 	    0,
160327178Sminshall 		1,
160427178Sminshall 		    &showoptions,
160527178Sminshall 			"show option processing" },
160627261Sminshall     { " ", "", 0, 1 },		/* empty line */
160727178Sminshall     { "?",
160827178Sminshall 	"display help information",
160927178Sminshall 	    togglehelp,
161027178Sminshall 		1 },
161127178Sminshall     { "help",
161227178Sminshall 	"display help information",
161327178Sminshall 	    togglehelp,
161427178Sminshall 		0 },
161527088Sminshall     { 0 }
161627088Sminshall };
161727088Sminshall 
161827088Sminshall togglehelp()
161927088Sminshall {
162027178Sminshall     struct togglelist *c;
162127088Sminshall 
162227178Sminshall     for (c = Togglelist; c->name; c++) {
162327088Sminshall 	if (c->dohelp) {
162427088Sminshall 	    printf("%s\t%s\n", c->name, c->help);
162527088Sminshall 	}
162627088Sminshall     }
162727261Sminshall     return 0;
162827088Sminshall }
162927088Sminshall 
163027088Sminshall char **
163127088Sminshall getnexttoggle(name)
163227088Sminshall char *name;
163327088Sminshall {
163427178Sminshall     struct togglelist *c = (struct togglelist *) name;
163527088Sminshall 
163627088Sminshall     return (char **) (c+1);
163727088Sminshall }
163827088Sminshall 
163927178Sminshall struct togglelist *
164027088Sminshall gettoggle(name)
164127088Sminshall char *name;
164227088Sminshall {
164327178Sminshall     return (struct togglelist *)
164427178Sminshall 			genget(name, (char **) Togglelist, getnexttoggle);
164527088Sminshall }
164627088Sminshall 
164727088Sminshall toggle(argc, argv)
164827088Sminshall int	argc;
164927088Sminshall char	*argv[];
165027088Sminshall {
165127261Sminshall     int retval = 1;
165227088Sminshall     char *name;
165327178Sminshall     struct togglelist *c;
165427088Sminshall 
165527088Sminshall     if (argc < 2) {
165627088Sminshall 	fprintf(stderr,
165727088Sminshall 	    "Need an argument to 'toggle' command.  'toggle ?' for help.\n");
165827261Sminshall 	return 0;
165927088Sminshall     }
166027088Sminshall     argc--;
166127088Sminshall     argv++;
166227088Sminshall     while (argc--) {
166327088Sminshall 	name = *argv++;
166427088Sminshall 	c = gettoggle(name);
166527186Sminshall 	if (c == Ambiguous(struct togglelist *)) {
166627088Sminshall 	    fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n",
166727088Sminshall 					name);
166827261Sminshall 	    return 0;
166927088Sminshall 	} else if (c == 0) {
167027088Sminshall 	    fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n",
167127088Sminshall 					name);
167227261Sminshall 	    return 0;
167327088Sminshall 	} else {
167427186Sminshall 	    if (c->variable) {
167527186Sminshall 		*c->variable = !*c->variable;		/* invert it */
167627186Sminshall 		printf("%s %s.\n", *c->variable? "Will" : "Won't",
167727186Sminshall 							c->actionexplanation);
167827186Sminshall 	    }
167927186Sminshall 	    if (c->handler) {
168027261Sminshall 		retval &= (*c->handler)(c);
168127186Sminshall 	    }
168227088Sminshall 	}
168327088Sminshall     }
168427261Sminshall     return retval;
168527088Sminshall }
168627088Sminshall 
168727088Sminshall /*
168827110Sminshall  * The following perform the "set" command.
168927110Sminshall  */
169027110Sminshall 
169127178Sminshall struct setlist {
169227178Sminshall     char *name;				/* name */
169327110Sminshall     char *help;				/* help information */
169427110Sminshall     char *charp;			/* where it is located at */
169527110Sminshall };
169627110Sminshall 
169727178Sminshall struct setlist Setlist[] = {
169827110Sminshall     { "echo", 	"character to toggle local echoing on/off", &echoc },
169927110Sminshall     { "escape",	"character to escape back to telnet command mode", &escape },
170027261Sminshall     { " ", "" },
170127261Sminshall     { " ", "The following need 'localchars' to be toggled true", 0 },
170227261Sminshall     { "erase",	"character to cause an Erase Character", &nttyb.sg_erase },
170327261Sminshall     { "flushoutput", "character to cause an Abort Oubput", &nltc.t_flushc },
170427110Sminshall     { "interrupt", "character to cause an Interrupt Process", &ntc.t_intrc },
170527261Sminshall     { "kill",	"character to cause an Erase Line", &nttyb.sg_kill },
170627110Sminshall     { "quit",	"character to cause a Break", &ntc.t_quitc },
1707*27676Sminshall     { "eof",	"character to cause an EOF ", &ntc.t_eofc },
170827110Sminshall     { 0 }
170927110Sminshall };
171027110Sminshall 
171127110Sminshall char **
171227178Sminshall getnextset(name)
171327110Sminshall char *name;
171427110Sminshall {
171527178Sminshall     struct setlist *c = (struct setlist *)name;
171627110Sminshall 
171727110Sminshall     return (char **) (c+1);
171827110Sminshall }
171927110Sminshall 
172027178Sminshall struct setlist *
172127178Sminshall getset(name)
172227110Sminshall char *name;
172327110Sminshall {
172427178Sminshall     return (struct setlist *) genget(name, (char **) Setlist, getnextset);
172527110Sminshall }
172627110Sminshall 
172727110Sminshall setcmd(argc, argv)
172827110Sminshall int	argc;
172927110Sminshall char	*argv[];
173027110Sminshall {
173127110Sminshall     int value;
173227178Sminshall     struct setlist *ct;
173327110Sminshall 
173427110Sminshall     /* XXX back we go... sigh */
173527110Sminshall     if (argc != 3) {
173627261Sminshall 	if ((argc == 2) &&
173727261Sminshall 		    ((!strcmp(argv[1], "?")) || (!strcmp(argv[1], "help")))) {
173827261Sminshall 	    for (ct = Setlist; ct->name; ct++) {
173927261Sminshall 		printf("%s\t%s\n", ct->name, ct->help);
174027261Sminshall 	    }
174127261Sminshall 	    printf("?\tdisplay help information\n");
174227261Sminshall 	} else {
174327261Sminshall 	    printf("Format is 'set Name Value'\n'set ?' for help.\n");
174427110Sminshall 	}
174527261Sminshall 	return 0;
174627110Sminshall     }
174727110Sminshall 
174827178Sminshall     ct = getset(argv[1]);
174927110Sminshall     if (ct == 0) {
175027110Sminshall 	fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n",
175127110Sminshall 			argv[1]);
175227261Sminshall 	return 0;
175327186Sminshall     } else if (ct == Ambiguous(struct setlist *)) {
175427110Sminshall 	fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
175527110Sminshall 			argv[1]);
175627261Sminshall 	return 0;
175727110Sminshall     } else {
175827110Sminshall 	if (strcmp("off", argv[2])) {
175927110Sminshall 	    value = special(argv[2]);
176027110Sminshall 	} else {
176127110Sminshall 	    value = -1;
176227110Sminshall 	}
176327110Sminshall 	*(ct->charp) = value;
176427178Sminshall 	printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
176527110Sminshall     }
176627261Sminshall     return 1;
176727110Sminshall }
176827110Sminshall 
176927110Sminshall /*
177027110Sminshall  * The following are the data structures and routines for the
177127110Sminshall  * 'mode' command.
177227110Sminshall  */
177327110Sminshall 
177427110Sminshall dolinemode()
177527110Sminshall {
177627110Sminshall     if (hisopts[TELOPT_SGA]) {
1777*27676Sminshall 	wontoption(TELOPT_SGA, 0);
177827110Sminshall     }
177927110Sminshall     if (hisopts[TELOPT_ECHO]) {
1780*27676Sminshall 	wontoption(TELOPT_ECHO, 0);
178127110Sminshall     }
178227110Sminshall }
178327110Sminshall 
178427110Sminshall docharmode()
178527110Sminshall {
178627110Sminshall     if (!hisopts[TELOPT_SGA]) {
1787*27676Sminshall 	willoption(TELOPT_SGA, 0);
178827110Sminshall     }
178927110Sminshall     if (!hisopts[TELOPT_ECHO]) {
1790*27676Sminshall 	willoption(TELOPT_ECHO, 0);
179127110Sminshall     }
179227110Sminshall }
179327110Sminshall 
179427110Sminshall struct cmd Modelist[] = {
179527261Sminshall     { "character",	"character-at-a-time mode",	docharmode, 1, 1 },
179627110Sminshall     { "line",		"line-by-line mode",		dolinemode, 1, 1 },
179727110Sminshall     { 0 },
179827110Sminshall };
179927110Sminshall 
180027110Sminshall char **
180127110Sminshall getnextmode(name)
180227110Sminshall char *name;
180327110Sminshall {
180427110Sminshall     struct cmd *c = (struct cmd *) name;
180527110Sminshall 
180627110Sminshall     return (char **) (c+1);
180727110Sminshall }
180827110Sminshall 
180927110Sminshall struct cmd *
181027110Sminshall getmodecmd(name)
181127110Sminshall char *name;
181227110Sminshall {
181327110Sminshall     return (struct cmd *) genget(name, (char **) Modelist, getnextmode);
181427110Sminshall }
181527110Sminshall 
181627110Sminshall modecmd(argc, argv)
181727110Sminshall int	argc;
181827110Sminshall char	*argv[];
181927110Sminshall {
182027110Sminshall     struct cmd *mt;
182127110Sminshall 
182227110Sminshall     if ((argc != 2) || !strcmp(argv[1], "?") || !strcmp(argv[1], "help")) {
182327110Sminshall 	printf("format is:  'mode Mode', where 'Mode' is one of:\n\n");
182427110Sminshall 	for (mt = Modelist; mt->name; mt++) {
182527110Sminshall 	    printf("%s\t%s\n", mt->name, mt->help);
182627110Sminshall 	}
182727261Sminshall 	return 0;
182827110Sminshall     }
182927110Sminshall     mt = getmodecmd(argv[1]);
183027110Sminshall     if (mt == 0) {
183127110Sminshall 	fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]);
183227261Sminshall 	return 0;
183327186Sminshall     } else if (mt == Ambiguous(struct cmd *)) {
183427110Sminshall 	fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]);
183527261Sminshall 	return 0;
183627110Sminshall     } else {
183727110Sminshall 	(*mt->handler)();
183827110Sminshall     }
183927261Sminshall     return 1;
184027110Sminshall }
184127110Sminshall 
184227110Sminshall /*
184327178Sminshall  * The following data structures and routines implement the
184427178Sminshall  * "display" command.
184527178Sminshall  */
184627178Sminshall 
184727178Sminshall display(argc, argv)
184827178Sminshall int	argc;
184927178Sminshall char	*argv[];
185027178Sminshall {
185127178Sminshall #define	dotog(tl)	if (tl->variable && tl->actionexplanation) { \
185227178Sminshall 			    if (*tl->variable) { \
185327178Sminshall 				printf("will"); \
185427178Sminshall 			    } else { \
185527178Sminshall 				printf("won't"); \
185627178Sminshall 			    } \
185727178Sminshall 			    printf(" %s.\n", tl->actionexplanation); \
185827178Sminshall 			}
185927178Sminshall 
186027261Sminshall #define	doset(sl)   if (sl->name && *sl->name != ' ') { \
186127261Sminshall 			printf("[%s]\t%s.\n", control(*sl->charp), sl->name); \
186227261Sminshall 		    }
186327178Sminshall 
186427178Sminshall     struct togglelist *tl;
186527178Sminshall     struct setlist *sl;
186627178Sminshall 
186727178Sminshall     if (argc == 1) {
186827178Sminshall 	for (tl = Togglelist; tl->name; tl++) {
186927178Sminshall 	    dotog(tl);
187027178Sminshall 	}
187127261Sminshall 	printf("\n");
187227178Sminshall 	for (sl = Setlist; sl->name; sl++) {
187327178Sminshall 	    doset(sl);
187427178Sminshall 	}
187527178Sminshall     } else {
187627178Sminshall 	int i;
187727178Sminshall 
187827178Sminshall 	for (i = 1; i < argc; i++) {
187927178Sminshall 	    sl = getset(argv[i]);
188027178Sminshall 	    tl = gettoggle(argv[i]);
188127186Sminshall 	    if ((sl == Ambiguous(struct setlist *)) ||
188227186Sminshall 				(tl == Ambiguous(struct togglelist *))) {
188327178Sminshall 		printf("?Ambiguous argument '%s'.\n", argv[i]);
188427261Sminshall 		return 0;
188527178Sminshall 	    } else if (!sl && !tl) {
188627178Sminshall 		printf("?Unknown argument '%s'.\n", argv[i]);
188727261Sminshall 		return 0;
188827178Sminshall 	    } else {
188927186Sminshall 		if (tl) {
189027186Sminshall 		    dotog(tl);
189127186Sminshall 		}
189227186Sminshall 		if (sl) {
189327186Sminshall 		    doset(sl);
189427186Sminshall 		}
189527178Sminshall 	    }
189627178Sminshall 	}
189727178Sminshall     }
189827261Sminshall     return 1;
189927178Sminshall #undef	doset(sl)
190027178Sminshall #undef	dotog(tl)
190127178Sminshall }
190227178Sminshall 
190327178Sminshall /*
190427088Sminshall  * The following are the data structures, and many of the routines,
190527088Sminshall  * relating to command processing.
190627088Sminshall  */
190727088Sminshall 
190827088Sminshall /*
190927088Sminshall  * Set the escape character.
191027088Sminshall  */
191127088Sminshall setescape(argc, argv)
191227088Sminshall 	int argc;
191327088Sminshall 	char *argv[];
191427088Sminshall {
191527088Sminshall 	register char *arg;
191627088Sminshall 	char buf[50];
191727088Sminshall 
191827186Sminshall 	printf(
191927186Sminshall 	    "Deprecated usage - please use 'set escape%s%s' in the future.\n",
192027186Sminshall 				(argc > 2)? " ":"", (argc > 2)? argv[1]: "");
192127088Sminshall 	if (argc > 2)
192227088Sminshall 		arg = argv[1];
192327088Sminshall 	else {
192427088Sminshall 		printf("new escape character: ");
192527088Sminshall 		gets(buf);
192627088Sminshall 		arg = buf;
192727088Sminshall 	}
192827088Sminshall 	if (arg[0] != '\0')
192927088Sminshall 		escape = arg[0];
193027088Sminshall 	printf("Escape character is '%s'.\n", control(escape));
193127088Sminshall 	fflush(stdout);
193227261Sminshall 	return 1;
193327088Sminshall }
193427088Sminshall 
193527088Sminshall /*VARARGS*/
193627261Sminshall togcrmod()
193727261Sminshall {
193827261Sminshall     crmod = !crmod;
193927261Sminshall     printf("Deprecated usage - please use 'toggle crmod' in the future.\n");
194027261Sminshall     printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't");
194127261Sminshall     fflush(stdout);
194227261Sminshall     return 1;
194327261Sminshall }
194427261Sminshall 
194527261Sminshall /*VARARGS*/
194627088Sminshall suspend()
194727088Sminshall {
194827110Sminshall 	setcommandmode();
194927088Sminshall 	kill(0, SIGTSTP);
195027088Sminshall 	/* reget parameters in case they were changed */
195127088Sminshall 	ioctl(0, TIOCGETP, (char *)&ottyb);
195227088Sminshall 	ioctl(0, TIOCGETC, (char *)&otc);
195327088Sminshall 	ioctl(0, TIOCGLTC, (char *)&oltc);
195427261Sminshall 	return 1;
195527088Sminshall }
195627088Sminshall 
195727088Sminshall /*VARARGS*/
195827088Sminshall bye()
195927088Sminshall {
196027088Sminshall 	register char *op;
196127088Sminshall 
196227088Sminshall 	if (connected) {
196327088Sminshall 		shutdown(net, 2);
196427088Sminshall 		printf("Connection closed.\n");
196527088Sminshall 		close(net);
196627088Sminshall 		connected = 0;
196727088Sminshall 		/* reset his options */
196827088Sminshall 		for (op = hisopts; op < &hisopts[256]; op++)
196927088Sminshall 			*op = 0;
197027088Sminshall 	}
197127261Sminshall 	return 1;
197227088Sminshall }
197327088Sminshall 
197427088Sminshall /*VARARGS*/
197527088Sminshall quit()
197627088Sminshall {
197727261Sminshall 	(void) call(bye, "bye", 0);
197827088Sminshall 	exit(0);
197927261Sminshall 	/*NOTREACHED*/
198027088Sminshall }
198127088Sminshall 
198227088Sminshall /*
198327088Sminshall  * Print status about the connection.
198427088Sminshall  */
198527186Sminshall /*ARGSUSED*/
198627178Sminshall status(argc, argv)
198727178Sminshall int	argc;
198827178Sminshall char	*argv[];
198927088Sminshall {
199027178Sminshall     if (connected) {
199127178Sminshall 	printf("Connected to %s.\n", hostname);
199227178Sminshall 	if (argc < 2) {
199327178Sminshall 	    printf("Operating in %s.\n", modedescriptions[getconnmode()]);
199427261Sminshall 	    if (localchars) {
199527178Sminshall 		printf("Catching signals locally.\n");
199627178Sminshall 	    }
199727110Sminshall 	}
199827178Sminshall     } else {
199927178Sminshall 	printf("No connection.\n");
200027178Sminshall     }
200127178Sminshall     printf("Escape character is '%s'.\n", control(escape));
200227178Sminshall     fflush(stdout);
200327261Sminshall     return 1;
200427088Sminshall }
200527088Sminshall 
200627088Sminshall tn(argc, argv)
200727088Sminshall 	int argc;
200827088Sminshall 	char *argv[];
200927088Sminshall {
201027088Sminshall 	register struct hostent *host = 0;
201127088Sminshall 
201227088Sminshall 	if (connected) {
201327088Sminshall 		printf("?Already connected to %s\n", hostname);
201427261Sminshall 		return 0;
201527088Sminshall 	}
201627088Sminshall 	if (argc < 2) {
201727186Sminshall 		(void) strcpy(line, "Connect ");
201827088Sminshall 		printf("(to) ");
201927088Sminshall 		gets(&line[strlen(line)]);
202027088Sminshall 		makeargv();
202127088Sminshall 		argc = margc;
202227088Sminshall 		argv = margv;
202327088Sminshall 	}
202427088Sminshall 	if (argc > 3) {
202527088Sminshall 		printf("usage: %s host-name [port]\n", argv[0]);
202627261Sminshall 		return 0;
202727088Sminshall 	}
202827088Sminshall 	sin.sin_addr.s_addr = inet_addr(argv[1]);
202927088Sminshall 	if (sin.sin_addr.s_addr != -1) {
203027088Sminshall 		sin.sin_family = AF_INET;
203127186Sminshall 		(void) strcpy(hnamebuf, argv[1]);
203227088Sminshall 		hostname = hnamebuf;
203327088Sminshall 	} else {
203427088Sminshall 		host = gethostbyname(argv[1]);
203527088Sminshall 		if (host) {
203627088Sminshall 			sin.sin_family = host->h_addrtype;
2037*27676Sminshall #ifndef	NOT43
203827088Sminshall 			bcopy(host->h_addr_list[0], (caddr_t)&sin.sin_addr,
203927088Sminshall 				host->h_length);
2040*27676Sminshall #else	NOT43
2041*27676Sminshall 			bcopy(host->h_addr, (caddr_t)&sin.sin_addr,
2042*27676Sminshall 				host->h_length);
2043*27676Sminshall #endif	NOT43
204427088Sminshall 			hostname = host->h_name;
204527088Sminshall 		} else {
204627088Sminshall 			printf("%s: unknown host\n", argv[1]);
204727261Sminshall 			return 0;
204827088Sminshall 		}
204927088Sminshall 	}
205027088Sminshall 	sin.sin_port = sp->s_port;
205127088Sminshall 	if (argc == 3) {
205227088Sminshall 		sin.sin_port = atoi(argv[2]);
205327186Sminshall 		if (sin.sin_port == 0) {
205427088Sminshall 			sp = getservbyname(argv[2], "tcp");
205527088Sminshall 			if (sp)
205627088Sminshall 				sin.sin_port = sp->s_port;
205727088Sminshall 			else {
205827088Sminshall 				printf("%s: bad port number\n", argv[2]);
205927261Sminshall 				return 0;
206027088Sminshall 			}
206127088Sminshall 		} else {
206227088Sminshall 			sin.sin_port = atoi(argv[2]);
206327088Sminshall 			sin.sin_port = htons(sin.sin_port);
206427088Sminshall 		}
206527088Sminshall 		telnetport = 0;
206627110Sminshall 	} else {
206727110Sminshall 		telnetport = 1;
206827088Sminshall 	}
206927088Sminshall 	signal(SIGINT, intr);
207027110Sminshall 	signal(SIGQUIT, intr2);
207127088Sminshall 	signal(SIGPIPE, deadpeer);
207227088Sminshall 	printf("Trying...\n");
207327088Sminshall 	do {
207427088Sminshall 		net = socket(AF_INET, SOCK_STREAM, 0);
207527088Sminshall 		if (net < 0) {
207627088Sminshall 			perror("telnet: socket");
207727261Sminshall 			return 0;
207827088Sminshall 		}
2079*27676Sminshall #ifndef	NOT43
208027186Sminshall 		if (debug &&
208127186Sminshall 				setsockopt(net, SOL_SOCKET, SO_DEBUG,
2082*27676Sminshall 					(char *)&debug, sizeof(debug)) < 0)
2083*27676Sminshall #else	NOT43
2084*27676Sminshall 		if (debug && setsockopt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
2085*27676Sminshall #endif	NOT43
208627088Sminshall 			perror("setsockopt (SO_DEBUG)");
2087*27676Sminshall 
208827186Sminshall 		if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
2089*27676Sminshall #ifndef	NOT43
209027088Sminshall 			if (host && host->h_addr_list[1]) {
209127088Sminshall 				int oerrno = errno;
209227088Sminshall 
209327088Sminshall 				fprintf(stderr,
209427088Sminshall 				    "telnet: connect to address %s: ",
209527088Sminshall 				    inet_ntoa(sin.sin_addr));
209627088Sminshall 				errno = oerrno;
209727186Sminshall 				perror((char *)0);
209827088Sminshall 				host->h_addr_list++;
209927088Sminshall 				bcopy(host->h_addr_list[0],
210027088Sminshall 				    (caddr_t)&sin.sin_addr, host->h_length);
210127088Sminshall 				fprintf(stderr, "Trying %s...\n",
210227088Sminshall 					inet_ntoa(sin.sin_addr));
210327088Sminshall 				(void) close(net);
210427088Sminshall 				continue;
210527088Sminshall 			}
2106*27676Sminshall #endif	NOT43
210727088Sminshall 			perror("telnet: connect");
210827088Sminshall 			signal(SIGINT, SIG_DFL);
210927261Sminshall 			signal(SIGQUIT, SIG_DFL);
211027261Sminshall 			return 0;
211127088Sminshall 		}
211227088Sminshall 		connected++;
211327088Sminshall 	} while (connected == 0);
211427178Sminshall 	call(status, "status", "notmuch", 0);
211527088Sminshall 	if (setjmp(peerdied) == 0)
211627088Sminshall 		telnet();
211727088Sminshall 	fprintf(stderr, "Connection closed by foreign host.\n");
211827088Sminshall 	exit(1);
211927261Sminshall 	/*NOTREACHED*/
212027088Sminshall }
212127088Sminshall 
212227088Sminshall 
212327088Sminshall #define HELPINDENT (sizeof ("connect"))
212427088Sminshall 
212527088Sminshall char	openhelp[] =	"connect to a site";
212627088Sminshall char	closehelp[] =	"close current connection";
212727088Sminshall char	quithelp[] =	"exit telnet";
212827088Sminshall char	zhelp[] =	"suspend telnet";
212927088Sminshall char	statushelp[] =	"print status information";
213027088Sminshall char	helphelp[] =	"print help information";
213127110Sminshall char	sendhelp[] =	"transmit special characters ('send ?' for more)";
213227178Sminshall char	sethelp[] = 	"set operating parameters ('set ?' for more)";
213327178Sminshall char	togglestring[] ="toggle operating parameters ('toggle ?' for more)";
213427178Sminshall char	displayhelp[] =	"display operating parameters";
213527178Sminshall char	modehelp[] =
213627178Sminshall 		"try to enter line-by-line or character-at-a-time mode";
213727088Sminshall 
213827088Sminshall int	help();
213927088Sminshall 
214027088Sminshall struct cmd cmdtab[] = {
214127261Sminshall 	{ "close",	closehelp,	bye,		1, 1 },
214227261Sminshall 	{ "display",	displayhelp,	display,	1, 0 },
214327261Sminshall 	{ "mode",	modehelp,	modecmd,	1, 1 },
214427110Sminshall 	{ "open",	openhelp,	tn,		1, 0 },
214527110Sminshall 	{ "quit",	quithelp,	quit,		1, 0 },
214627110Sminshall 	{ "send",	sendhelp,	sendcmd,	1, 1 },
214727178Sminshall 	{ "set",	sethelp,	setcmd,		1, 0 },
214827261Sminshall 	{ "status",	statushelp,	status,		1, 0 },
214927110Sminshall 	{ "toggle",	togglestring,	toggle,		1, 0 },
215027261Sminshall 	{ "z",		zhelp,		suspend,	1, 0 },
215127110Sminshall 	{ "?",		helphelp,	help,		1, 0 },
215227261Sminshall 	0
215327261Sminshall };
215427261Sminshall 
215527261Sminshall char	crmodhelp[] =	"deprecated command -- use 'toggle crmod' instead";
215627261Sminshall char	escapehelp[] =	"deprecated command -- use 'set escape' instead";
215727261Sminshall 
215827261Sminshall struct cmd cmdtab2[] = {
215927110Sminshall 	{ "help",	helphelp,	help,		0, 0 },
216027261Sminshall 	{ "escape",	escapehelp,	setescape,	1, 0 },
216127261Sminshall 	{ "crmod",	crmodhelp,	togcrmod,	1, 0 },
216227088Sminshall 	0
216327088Sminshall };
216427088Sminshall 
216527088Sminshall /*
216627088Sminshall  * Help command.
216727088Sminshall  */
216827088Sminshall help(argc, argv)
216927088Sminshall 	int argc;
217027088Sminshall 	char *argv[];
217127088Sminshall {
217227088Sminshall 	register struct cmd *c;
217327088Sminshall 
217427088Sminshall 	if (argc == 1) {
217527088Sminshall 		printf("Commands may be abbreviated.  Commands are:\n\n");
217627088Sminshall 		for (c = cmdtab; c->name; c++)
217727088Sminshall 			if (c->dohelp) {
217827088Sminshall 				printf("%-*s\t%s\n", HELPINDENT, c->name,
217927088Sminshall 								    c->help);
218027088Sminshall 			}
218127261Sminshall 		return 0;
218227088Sminshall 	}
218327088Sminshall 	while (--argc > 0) {
218427088Sminshall 		register char *arg;
218527088Sminshall 		arg = *++argv;
218627088Sminshall 		c = getcmd(arg);
218727186Sminshall 		if (c == Ambiguous(struct cmd *))
218827088Sminshall 			printf("?Ambiguous help command %s\n", arg);
218927088Sminshall 		else if (c == (struct cmd *)0)
219027088Sminshall 			printf("?Invalid help command %s\n", arg);
219127088Sminshall 		else
219227088Sminshall 			printf("%s\n", c->help);
219327088Sminshall 	}
219427261Sminshall 	return 0;
219527088Sminshall }
219627088Sminshall /*
219727088Sminshall  * Call routine with argc, argv set from args (terminated by 0).
219827088Sminshall  * VARARGS2
219927088Sminshall  */
220027088Sminshall call(routine, args)
220127088Sminshall 	int (*routine)();
220227186Sminshall 	char *args;
220327088Sminshall {
220427186Sminshall 	register char **argp;
220527088Sminshall 	register int argc;
220627088Sminshall 
220727088Sminshall 	for (argc = 0, argp = &args; *argp++ != 0; argc++)
220827088Sminshall 		;
220927261Sminshall 	return (*routine)(argc, &args);
221027088Sminshall }
221127088Sminshall 
221227088Sminshall makeargv()
221327088Sminshall {
221427088Sminshall 	register char *cp;
221527088Sminshall 	register char **argp = margv;
221627088Sminshall 
221727088Sminshall 	margc = 0;
221827088Sminshall 	for (cp = line; *cp;) {
221927088Sminshall 		while (isspace(*cp))
222027088Sminshall 			cp++;
222127088Sminshall 		if (*cp == '\0')
222227088Sminshall 			break;
222327088Sminshall 		*argp++ = cp;
222427088Sminshall 		margc += 1;
222527088Sminshall 		while (*cp != '\0' && !isspace(*cp))
222627088Sminshall 			cp++;
222727088Sminshall 		if (*cp == '\0')
222827088Sminshall 			break;
222927088Sminshall 		*cp++ = '\0';
223027088Sminshall 	}
223127088Sminshall 	*argp++ = 0;
223227088Sminshall }
223327088Sminshall 
223427088Sminshall char **
223527088Sminshall getnextcmd(name)
223627088Sminshall char *name;
223727088Sminshall {
223827088Sminshall     struct cmd *c = (struct cmd *) name;
223927088Sminshall 
224027088Sminshall     return (char **) (c+1);
224127088Sminshall }
224227088Sminshall 
224327088Sminshall struct cmd *
224427088Sminshall getcmd(name)
224527088Sminshall char *name;
224627088Sminshall {
224727261Sminshall     struct cmd *cm;
224827261Sminshall 
224927261Sminshall     if (cm = (struct cmd *) genget(name, (char **) cmdtab, getnextcmd)) {
225027261Sminshall 	return cm;
225127261Sminshall     } else {
225227261Sminshall 	return (struct cmd *) genget(name, (char **) cmdtab2, getnextcmd);
225327261Sminshall     }
225427088Sminshall }
225527088Sminshall 
225627088Sminshall command(top)
225727088Sminshall 	int top;
225827088Sminshall {
225927088Sminshall 	register struct cmd *c;
226027088Sminshall 
226127110Sminshall 	setcommandmode();
226227261Sminshall 	if (!top) {
226327088Sminshall 		putchar('\n');
226427261Sminshall 	} else {
226527088Sminshall 		signal(SIGINT, SIG_DFL);
226627261Sminshall 		signal(SIGQUIT, SIG_DFL);
226727261Sminshall 	}
226827088Sminshall 	for (;;) {
226927088Sminshall 		printf("%s> ", prompt);
227027088Sminshall 		if (gets(line) == 0) {
227127088Sminshall 			if (feof(stdin))
227227088Sminshall 				quit();
227327088Sminshall 			break;
227427088Sminshall 		}
227527088Sminshall 		if (line[0] == 0)
227627088Sminshall 			break;
227727088Sminshall 		makeargv();
227827088Sminshall 		c = getcmd(margv[0]);
227927186Sminshall 		if (c == Ambiguous(struct cmd *)) {
228027088Sminshall 			printf("?Ambiguous command\n");
228127088Sminshall 			continue;
228227088Sminshall 		}
228327088Sminshall 		if (c == 0) {
228427088Sminshall 			printf("?Invalid command\n");
228527088Sminshall 			continue;
228627088Sminshall 		}
228727088Sminshall 		if (c->needconnect && !connected) {
228827088Sminshall 			printf("?Need to be connected first.\n");
228927088Sminshall 			continue;
229027088Sminshall 		}
229127261Sminshall 		if ((*c->handler)(margc, margv)) {
229227088Sminshall 			break;
229327261Sminshall 		}
229427088Sminshall 	}
229527088Sminshall 	if (!top) {
229627110Sminshall 		if (!connected) {
229727088Sminshall 			longjmp(toplevel, 1);
229827110Sminshall 			/*NOTREACHED*/
229927110Sminshall 		}
230027110Sminshall 		setconnmode();
230127088Sminshall 	}
230227088Sminshall }
230327186Sminshall 
230427186Sminshall /*
230527186Sminshall  * main.  Parse arguments, invoke the protocol or command parser.
230627186Sminshall  */
230727186Sminshall 
230827186Sminshall 
230927186Sminshall main(argc, argv)
231027186Sminshall 	int argc;
231127186Sminshall 	char *argv[];
231227186Sminshall {
231327186Sminshall 	sp = getservbyname("telnet", "tcp");
231427186Sminshall 	if (sp == 0) {
231527186Sminshall 		fprintf(stderr, "telnet: tcp/telnet: unknown service\n");
231627186Sminshall 		exit(1);
231727186Sminshall 	}
231827186Sminshall 	NetTrace = stdout;
231927186Sminshall 	ioctl(0, TIOCGETP, (char *)&ottyb);
232027186Sminshall 	ioctl(0, TIOCGETC, (char *)&otc);
232127186Sminshall 	ioctl(0, TIOCGLTC, (char *)&oltc);
232227228Sminshall #if	defined(LNOFLSH)
232327228Sminshall 	ioctl(0, TIOCLGET, (char *)&autoflush);
232427261Sminshall 	autoflush = !(autoflush&LNOFLSH);	/* if LNOFLSH, no autoflush */
232527261Sminshall #else	/* LNOFLSH */
232627261Sminshall 	autoflush = 1;
232727228Sminshall #endif	/* LNOFLSH */
232827186Sminshall 	ntc = otc;
232927228Sminshall 	nltc = oltc;
233027186Sminshall 	nttyb = ottyb;
233127186Sminshall 	setbuf(stdin, (char *)0);
233227186Sminshall 	setbuf(stdout, (char *)0);
233327186Sminshall 	prompt = argv[0];
233427186Sminshall 	if (argc > 1 && !strcmp(argv[1], "-d")) {
233527186Sminshall 		debug = 1;
233627186Sminshall 		argv++;
233727186Sminshall 		argc--;
233827186Sminshall 	}
233927186Sminshall 	if (argc > 1 && !strcmp(argv[1], "-n")) {
234027186Sminshall 	    argv++;
234127186Sminshall 	    argc--;
234227186Sminshall 	    if (argc > 1) {		/* get file name */
234327186Sminshall 		NetTrace = fopen(argv[1], "w");
234427186Sminshall 		argv++;
234527186Sminshall 		argc--;
234627186Sminshall 		if (NetTrace == NULL) {
234727186Sminshall 		    NetTrace = stdout;
234827186Sminshall 		}
234927186Sminshall 	    }
235027186Sminshall 	}
235127186Sminshall 	if (argc != 1) {
235227186Sminshall 		if (setjmp(toplevel) != 0)
235327186Sminshall 			exit(0);
235427186Sminshall 		tn(argc, argv);
235527186Sminshall 	}
235627186Sminshall 	setjmp(toplevel);
235727186Sminshall 	for (;;)
235827186Sminshall 		command(1);
235927186Sminshall }
2360