xref: /csrg-svn/usr.bin/telnet/telnet.c (revision 28066)
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*28066Sminshall static char sccsid[] = "@(#)telnet.c	5.15 (Berkeley) 05/13/86";
1521580Sdist #endif not lint
1621580Sdist 
176000Sroot /*
186000Sroot  * User telnet program.
19*28066Sminshall  *
20*28066Sminshall  * Many of the FUNCTIONAL changes in this newest version of telnet
21*28066Sminshall  * were suggested by Dave Borman of Cray Research, Inc.
226000Sroot  */
23*28066Sminshall 
249217Ssam #include <sys/types.h>
259217Ssam #include <sys/socket.h>
269972Ssam #include <sys/ioctl.h>
2727178Sminshall #include <sys/time.h>
289217Ssam 
299217Ssam #include <netinet/in.h>
309217Ssam 
3112212Ssam #define	TELOPTS
3212212Ssam #include <arpa/telnet.h>
3327186Sminshall #include <arpa/inet.h>
3412212Ssam 
356000Sroot #include <stdio.h>
366000Sroot #include <ctype.h>
376000Sroot #include <errno.h>
386000Sroot #include <signal.h>
396000Sroot #include <setjmp.h>
408345Ssam #include <netdb.h>
4127186Sminshall #include <strings.h>
429217Ssam 
4327178Sminshall 
4427178Sminshall 
4527676Sminshall #ifndef	FD_SETSIZE
4627178Sminshall /*
4727178Sminshall  * The following is defined just in case someone should want to run
4827178Sminshall  * this telnet on a 4.2 system.
4927178Sminshall  *
5027178Sminshall  */
5127178Sminshall 
5227676Sminshall #define	FD_SET(n, p)	((p)->fds_bits[0] |= (1<<(n)))
5327676Sminshall #define	FD_CLR(n, p)	((p)->fds_bits[0] &= ~(1<<(n)))
5427676Sminshall #define	FD_ISSET(n, p)	((p)->fds_bits[0] & (1<<(n)))
5527676Sminshall #define FD_ZERO(p)	((p)->fds_bits[0] = 0)
5627178Sminshall 
5727178Sminshall #endif
5827178Sminshall 
5927228Sminshall #define	strip(x)	((x)&0x7f)
606000Sroot 
6127228Sminshall char	ttyobuf[2*BUFSIZ], *tfrontp = ttyobuf, *tbackp = ttyobuf;
6227228Sminshall #define	TTYADD(c)	{ if (!(SYNCHing||flushout)) { *tfrontp++ = c; } }
6327228Sminshall #define	TTYLOC()	(tfrontp)
6427228Sminshall #define	TTYMAX()	(ttyobuf+sizeof ttyobuf-1)
6527228Sminshall #define	TTYMIN()	(netobuf)
6627228Sminshall #define	TTYBYTES()	(tfrontp-tbackp)
6727228Sminshall #define	TTYROOM()	(TTYMAX()-TTYLOC()+1)
6827088Sminshall 
6927228Sminshall char	netobuf[2*BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf;
7027088Sminshall #define	NETADD(c)	{ *nfrontp++ = c; }
7127088Sminshall #define	NET2ADD(c1,c2)	{ NETADD(c1); NETADD(c2); }
7227088Sminshall #define NETLOC()	(nfrontp)
7327228Sminshall #define	NETMAX()	(netobuf+sizeof netobuf-1)
7427228Sminshall #define	NETBYTES()	(nfrontp-nbackp)
7527228Sminshall #define	NETROOM()	(NETMAX()-NETLOC()+1)
7627088Sminshall char	*neturg = 0;		/* one past last byte of urgent data */
776000Sroot 
7827676Sminshall char	subbuffer[100], *subpointer, *subend;	/* buffer for sub-options */
7927676Sminshall #define	SB_CLEAR()	subpointer = subbuffer;
8027676Sminshall #define	SB_TERM()	subend = subpointer;
8127676Sminshall #define	SB_ACCUM(c)	if (subpointer < (subbuffer+sizeof subbuffer)) { \
8227676Sminshall 				*subpointer++ = (c); \
8327676Sminshall 			}
8427676Sminshall 
856000Sroot char	hisopts[256];
866000Sroot char	myopts[256];
876000Sroot 
886000Sroot char	doopt[] = { IAC, DO, '%', 'c', 0 };
896000Sroot char	dont[] = { IAC, DONT, '%', 'c', 0 };
906000Sroot char	will[] = { IAC, WILL, '%', 'c', 0 };
916000Sroot char	wont[] = { IAC, WONT, '%', 'c', 0 };
926000Sroot 
9327088Sminshall struct cmd {
9427088Sminshall 	char	*name;		/* command name */
9527088Sminshall 	char	*help;		/* help string */
9627088Sminshall 	int	(*handler)();	/* routine which executes command */
9727088Sminshall 	int	dohelp;		/* Should we give general help information? */
9827088Sminshall 	int	needconnect;	/* Do we need to be connected to execute? */
9927088Sminshall };
10027088Sminshall 
1016000Sroot int	connected;
1026000Sroot int	net;
10327088Sminshall int	tout;
1049972Ssam int	showoptions = 0;
10510339Ssam int	debug = 0;
1069972Ssam int	crmod = 0;
10727088Sminshall int	netdata = 0;
10827021Sminshall static FILE	*NetTrace;
10925289Skarels int	telnetport = 1;
11027088Sminshall 
11127088Sminshall 
1126000Sroot char	*prompt;
1139972Ssam char	escape = CTRL(]);
11427110Sminshall char	echoc = CTRL(E);
1156000Sroot 
11627186Sminshall int	SYNCHing = 0;		/* we are in TELNET SYNCH mode */
11727186Sminshall int	flushout = 0;		/* flush output */
11827228Sminshall int	autoflush = 0;		/* flush output when interrupting? */
11927186Sminshall int	autosynch = 0;		/* send interrupt characters with SYNCH? */
12027261Sminshall int	localchars = 0;		/* we recognize interrupt/quit */
12127261Sminshall int	donelclchars = 0;	/* the user has set "localchars" */
12227186Sminshall int	dontlecho = 0;		/* do we suppress local echoing right now? */
12327186Sminshall 
1246000Sroot char	line[200];
1256000Sroot int	margc;
1266000Sroot char	*margv[20];
1276000Sroot 
1286000Sroot jmp_buf	toplevel;
1296000Sroot jmp_buf	peerdied;
1306000Sroot 
1316000Sroot extern	int errno;
1326000Sroot 
1336000Sroot 
1349972Ssam struct sockaddr_in sin;
1356000Sroot 
1366000Sroot struct	cmd *getcmd();
1378345Ssam struct	servent *sp;
1386000Sroot 
13927110Sminshall struct	tchars otc, ntc;
14027228Sminshall struct	ltchars oltc, nltc;
14127110Sminshall struct	sgttyb ottyb, nttyb;
14227110Sminshall int	globalmode = 0;
14327110Sminshall int	flushline = 1;
1448378Ssam 
14527110Sminshall char	*hostname;
14627110Sminshall char	hnamebuf[32];
14727110Sminshall 
14827110Sminshall /*
14927110Sminshall  * The following are some clocks used to decide how to interpret
15027178Sminshall  * the relationship between various variables.
15127110Sminshall  */
15227110Sminshall 
15327110Sminshall struct {
15427110Sminshall     int
15527110Sminshall 	system,			/* what the current time is */
15627110Sminshall 	echotoggle,		/* last time user entered echo character */
15727178Sminshall 	modenegotiated,		/* last time operating mode negotiated */
15827178Sminshall 	didnetreceive,		/* last time we read data from network */
15927178Sminshall 	gotDM;			/* when did we last see a data mark */
16027186Sminshall } clocks;
16127110Sminshall 
16227186Sminshall #define	settimer(x)	clocks.x = clocks.system++
16327110Sminshall 
16427110Sminshall /*
16527110Sminshall  * Various utility routines.
16627110Sminshall  */
1676000Sroot 
16827186Sminshall char *ambiguous;		/* special return value */
16927186Sminshall #define Ambiguous(t)	((t)&ambiguous)
17027186Sminshall 
17127186Sminshall 
17227088Sminshall char **
17327088Sminshall genget(name, table, next)
17427088Sminshall char	*name;		/* name to match */
17527088Sminshall char	**table;		/* name entry in table */
17627088Sminshall char	**(*next)();	/* routine to return next entry in table */
1776000Sroot {
17827088Sminshall 	register char *p, *q;
17927088Sminshall 	register char **c, **found;
18027088Sminshall 	register int nmatches, longest;
1816000Sroot 
18227088Sminshall 	longest = 0;
18327088Sminshall 	nmatches = 0;
18427088Sminshall 	found = 0;
18527088Sminshall 	for (c = table; p = *c; c = (*next)(c)) {
18627088Sminshall 		for (q = name; *q == *p++; q++)
18727088Sminshall 			if (*q == 0)		/* exact match? */
18827088Sminshall 				return (c);
18927088Sminshall 		if (!*q) {			/* the name was a prefix */
19027088Sminshall 			if (q - name > longest) {
19127088Sminshall 				longest = q - name;
19227088Sminshall 				nmatches = 1;
19327088Sminshall 				found = c;
19427088Sminshall 			} else if (q - name == longest)
19527088Sminshall 				nmatches++;
1968377Ssam 		}
1976000Sroot 	}
19827088Sminshall 	if (nmatches > 1)
19927186Sminshall 		return Ambiguous(char **);
20027088Sminshall 	return (found);
2016000Sroot }
2026000Sroot 
20327110Sminshall /*
20427110Sminshall  * Make a character string into a number.
20527110Sminshall  *
20627186Sminshall  * Todo:  1.  Could take random integers (12, 0x12, 012, 0b1).
20727110Sminshall  */
2086000Sroot 
20927110Sminshall special(s)
21027110Sminshall register char *s;
21127110Sminshall {
21227110Sminshall 	register char c;
21327110Sminshall 	char b;
21427110Sminshall 
21527110Sminshall 	switch (*s) {
21627110Sminshall 	case '^':
21727110Sminshall 		b = *++s;
21827110Sminshall 		if (b == '?') {
21927228Sminshall 		    c = b | 0x40;		/* DEL */
22027110Sminshall 		} else {
22127110Sminshall 		    c = b & 0x1f;
22227110Sminshall 		}
22327110Sminshall 		break;
22427110Sminshall 	default:
22527110Sminshall 		c = *s;
22627110Sminshall 		break;
22727110Sminshall 	}
22827110Sminshall 	return c;
22927110Sminshall }
23027186Sminshall 
23127186Sminshall /*
23227186Sminshall  * Construct a control character sequence
23327186Sminshall  * for a special character.
23427186Sminshall  */
23527186Sminshall char *
23627186Sminshall control(c)
23727186Sminshall 	register int c;
23827186Sminshall {
23927186Sminshall 	static char buf[3];
24027186Sminshall 
24127228Sminshall 	if (c == 0x7f)
24227186Sminshall 		return ("^?");
24327186Sminshall 	if (c == '\377') {
24427186Sminshall 		return "off";
24527186Sminshall 	}
24627186Sminshall 	if (c >= 0x20) {
24727186Sminshall 		buf[0] = c;
24827186Sminshall 		buf[1] = 0;
24927186Sminshall 	} else {
25027186Sminshall 		buf[0] = '^';
25127186Sminshall 		buf[1] = '@'+c;
25227186Sminshall 		buf[2] = 0;
25327186Sminshall 	}
25427186Sminshall 	return (buf);
25527186Sminshall }
25627676Sminshall 
25727676Sminshall 
25827676Sminshall /*
25927676Sminshall  * upcase()
26027676Sminshall  *
26127676Sminshall  *	Upcase (in place) the argument.
26227676Sminshall  */
26327676Sminshall 
26427676Sminshall void
26527676Sminshall upcase(argument)
26627676Sminshall register char *argument;
26727676Sminshall {
26827676Sminshall     register int c;
26927676Sminshall 
27027676Sminshall     while (c = *argument) {
27127676Sminshall 	if (islower(c)) {
27227676Sminshall 	    *argument = toupper(c);
27327676Sminshall 	}
27427676Sminshall 	argument++;
27527676Sminshall     }
27627676Sminshall }
27727110Sminshall 
27827110Sminshall /*
27927186Sminshall  * Check to see if any out-of-band data exists on a socket (for
28027186Sminshall  * Telnet "synch" processing).
28127186Sminshall  */
28227186Sminshall 
28327186Sminshall int
28427186Sminshall stilloob(s)
28527186Sminshall int	s;		/* socket number */
28627186Sminshall {
28727186Sminshall     static struct timeval timeout = { 0 };
28827186Sminshall     fd_set	excepts;
28927186Sminshall     int value;
29027186Sminshall 
29127186Sminshall     do {
29227186Sminshall 	FD_ZERO(&excepts);
29327186Sminshall 	FD_SET(s, &excepts);
29427186Sminshall 	value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout);
29527186Sminshall     } while ((value == -1) && (errno = EINTR));
29627186Sminshall 
29727186Sminshall     if (value < 0) {
29827186Sminshall 	perror("select");
29927186Sminshall 	quit();
30027186Sminshall     }
30127186Sminshall     if (FD_ISSET(s, &excepts)) {
30227186Sminshall 	return 1;
30327186Sminshall     } else {
30427186Sminshall 	return 0;
30527186Sminshall     }
30627186Sminshall }
30727186Sminshall 
30827186Sminshall 
30927186Sminshall /*
31027186Sminshall  *  netflush
31127186Sminshall  *		Send as much data as possible to the network,
31227186Sminshall  *	handling requests for urgent data.
31327186Sminshall  */
31427186Sminshall 
31527186Sminshall 
31627186Sminshall netflush(fd)
31727186Sminshall {
31827186Sminshall     int n;
31927186Sminshall 
32027186Sminshall     if ((n = nfrontp - nbackp) > 0) {
32127186Sminshall 	if (!neturg) {
32227186Sminshall 	    n = write(fd, nbackp, n);	/* normal write */
32327186Sminshall 	} else {
32427186Sminshall 	    n = neturg - nbackp;
32527186Sminshall 	    /*
32627186Sminshall 	     * In 4.2 (and 4.3) systems, there is some question about
32727186Sminshall 	     * what byte in a sendOOB operation is the "OOB" data.
32827186Sminshall 	     * To make ourselves compatible, we only send ONE byte
32927186Sminshall 	     * out of band, the one WE THINK should be OOB (though
33027186Sminshall 	     * we really have more the TCP philosophy of urgent data
33127186Sminshall 	     * rather than the Unix philosophy of OOB data).
33227186Sminshall 	     */
33327186Sminshall 	    if (n > 1) {
33427186Sminshall 		n = send(fd, nbackp, n-1, 0);	/* send URGENT all by itself */
33527186Sminshall 	    } else {
33627186Sminshall 		n = send(fd, nbackp, n, MSG_OOB);	/* URGENT data */
33727186Sminshall 	    }
33827186Sminshall 	}
33927186Sminshall     }
34027186Sminshall     if (n < 0) {
34127186Sminshall 	if (errno != ENOBUFS && errno != EWOULDBLOCK) {
34227186Sminshall 	    setcommandmode();
34327186Sminshall 	    perror(hostname);
34427186Sminshall 	    close(fd);
34527186Sminshall 	    neturg = 0;
34627186Sminshall 	    longjmp(peerdied, -1);
34727186Sminshall 	    /*NOTREACHED*/
34827186Sminshall 	}
34927186Sminshall 	n = 0;
35027186Sminshall     }
35127186Sminshall     if (netdata && n) {
35227186Sminshall 	Dump('>', nbackp, n);
35327186Sminshall     }
35427186Sminshall     nbackp += n;
35527186Sminshall     if (nbackp >= neturg) {
35627186Sminshall 	neturg = 0;
35727186Sminshall     }
35827186Sminshall     if (nbackp == nfrontp) {
35927186Sminshall 	nbackp = nfrontp = netobuf;
36027186Sminshall     }
36127186Sminshall }
36227261Sminshall 
36327261Sminshall /*
36427261Sminshall  * nextitem()
36527261Sminshall  *
36627261Sminshall  *	Return the address of the next "item" in the TELNET data
36727261Sminshall  * stream.  This will be the address of the next character if
36827261Sminshall  * the current address is a user data character, or it will
36927261Sminshall  * be the address of the character following the TELNET command
37027261Sminshall  * if the current address is a TELNET IAC ("I Am a Command")
37127261Sminshall  * character.
37227261Sminshall  */
37327186Sminshall 
37427261Sminshall char *
37527261Sminshall nextitem(current)
37627261Sminshall char	*current;
37727261Sminshall {
37827261Sminshall     if ((*current&0xff) != IAC) {
37927261Sminshall 	return current+1;
38027261Sminshall     }
38127261Sminshall     switch (*(current+1)&0xff) {
38227261Sminshall     case DO:
38327261Sminshall     case DONT:
38427261Sminshall     case WILL:
38527261Sminshall     case WONT:
38627261Sminshall 	return current+3;
38727261Sminshall     case SB:		/* loop forever looking for the SE */
38827261Sminshall 	{
38927261Sminshall 	    register char *look = current+2;
39027261Sminshall 
39127261Sminshall 	    for (;;) {
39227261Sminshall 		if ((*look++&0xff) == IAC) {
39327261Sminshall 		    if ((*look++&0xff) == SE) {
39427261Sminshall 			return look;
39527261Sminshall 		    }
39627261Sminshall 		}
39727261Sminshall 	    }
39827261Sminshall 	}
39927261Sminshall     default:
40027261Sminshall 	return current+2;
40127261Sminshall     }
40227261Sminshall }
40327186Sminshall /*
40427261Sminshall  * netclear()
40527261Sminshall  *
40627261Sminshall  *	We are about to do a TELNET SYNCH operation.  Clear
40727261Sminshall  * the path to the network.
40827261Sminshall  *
40927261Sminshall  *	Things are a bit tricky since we may have sent the first
41027261Sminshall  * byte or so of a previous TELNET command into the network.
41127261Sminshall  * So, we have to scan the network buffer from the beginning
41227261Sminshall  * until we are up to where we want to be.
41327261Sminshall  *
41427261Sminshall  *	A side effect of what we do, just to keep things
41527261Sminshall  * simple, is to clear the urgent data pointer.  The principal
41627261Sminshall  * caller should be setting the urgent data pointer AFTER calling
41727261Sminshall  * us in any case.
41827261Sminshall  */
41927261Sminshall 
42027261Sminshall netclear()
42127261Sminshall {
42227261Sminshall     register char *thisitem, *next;
42327261Sminshall     char *good;
42427261Sminshall #define	wewant(p)	((nfrontp > p) && ((*p&0xff) == IAC) && \
42527261Sminshall 				((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
42627261Sminshall 
42727261Sminshall     thisitem = netobuf;
42827261Sminshall 
42927261Sminshall     while ((next = nextitem(thisitem)) <= nbackp) {
43027261Sminshall 	thisitem = next;
43127261Sminshall     }
43227261Sminshall 
43327261Sminshall     /* Now, thisitem is first before/at boundary. */
43427261Sminshall 
43527261Sminshall     good = netobuf;	/* where the good bytes go */
43627261Sminshall 
43727261Sminshall     while (nfrontp > thisitem) {
43827261Sminshall 	if (wewant(thisitem)) {
43927261Sminshall 	    int length;
44027261Sminshall 
44127261Sminshall 	    next = thisitem;
44227261Sminshall 	    do {
44327261Sminshall 		next = nextitem(next);
44427261Sminshall 	    } while (wewant(next) && (nfrontp > next));
44527261Sminshall 	    length = next-thisitem;
44627261Sminshall 	    bcopy(thisitem, good, length);
44727261Sminshall 	    good += length;
44827261Sminshall 	    thisitem = next;
44927261Sminshall 	} else {
45027261Sminshall 	    thisitem = nextitem(thisitem);
45127261Sminshall 	}
45227261Sminshall     }
45327261Sminshall 
45427261Sminshall     nbackp = netobuf;
45527261Sminshall     nfrontp = good;		/* next byte to be sent */
45627261Sminshall     neturg = 0;
45727261Sminshall }
45827261Sminshall 
45927261Sminshall /*
46027186Sminshall  * Send as much data as possible to the terminal.
46127186Sminshall  */
46227186Sminshall 
46327186Sminshall 
46427186Sminshall ttyflush()
46527186Sminshall {
46627186Sminshall     int n;
46727186Sminshall 
46827186Sminshall     if ((n = tfrontp - tbackp) > 0) {
46927228Sminshall 	if (!(SYNCHing||flushout)) {
47027186Sminshall 	    n = write(tout, tbackp, n);
47127186Sminshall 	} else {
47227186Sminshall 	    ioctl(fileno(stdout), TIOCFLUSH, (char *) 0);
47327228Sminshall 	    /* we leave 'n' alone! */
47427186Sminshall 	}
47527186Sminshall     }
47627186Sminshall     if (n < 0) {
47727186Sminshall 	return;
47827186Sminshall     }
47927186Sminshall     tbackp += n;
48027186Sminshall     if (tbackp == tfrontp) {
48127186Sminshall 	tbackp = tfrontp = ttyobuf;
48227186Sminshall     }
48327186Sminshall }
48427186Sminshall 
48527186Sminshall /*
48627110Sminshall  * Various signal handling routines.
48727110Sminshall  */
48827110Sminshall 
48927110Sminshall deadpeer()
49027110Sminshall {
49127110Sminshall 	setcommandmode();
49227110Sminshall 	longjmp(peerdied, -1);
49327110Sminshall }
49427110Sminshall 
49527110Sminshall intr()
49627110Sminshall {
49727261Sminshall     if (localchars) {
49827110Sminshall 	intp();
49927110Sminshall 	return;
50027110Sminshall     }
50127110Sminshall     setcommandmode();
50227110Sminshall     longjmp(toplevel, -1);
50327110Sminshall }
50427110Sminshall 
50527110Sminshall intr2()
50627110Sminshall {
50727261Sminshall     if (localchars) {
50827110Sminshall 	sendbrk();
50927110Sminshall 	return;
51027110Sminshall     }
51127110Sminshall }
51227110Sminshall 
51327110Sminshall doescape()
51427110Sminshall {
51527110Sminshall     command(0);
51627110Sminshall }
51727110Sminshall 
51827110Sminshall /*
51927186Sminshall  * The following are routines used to print out debugging information.
52027186Sminshall  */
52127186Sminshall 
52227186Sminshall 
52327186Sminshall static
52427186Sminshall Dump(direction, buffer, length)
52527186Sminshall char	direction;
52627186Sminshall char	*buffer;
52727186Sminshall int	length;
52827186Sminshall {
52927186Sminshall #   define BYTES_PER_LINE	32
53027186Sminshall #   define min(x,y)	((x<y)? x:y)
53127186Sminshall     char *pThis;
53227186Sminshall     int offset;
53327186Sminshall 
53427186Sminshall     offset = 0;
53527186Sminshall 
53627186Sminshall     while (length) {
53727186Sminshall 	/* print one line */
53827186Sminshall 	fprintf(NetTrace, "%c 0x%x\t", direction, offset);
53927186Sminshall 	pThis = buffer;
54027186Sminshall 	buffer = buffer+min(length, BYTES_PER_LINE);
54127186Sminshall 	while (pThis < buffer) {
54227186Sminshall 	    fprintf(NetTrace, "%.2x", (*pThis)&0xff);
54327186Sminshall 	    pThis++;
54427186Sminshall 	}
54527186Sminshall 	fprintf(NetTrace, "\n");
54627186Sminshall 	length -= BYTES_PER_LINE;
54727186Sminshall 	offset += BYTES_PER_LINE;
54827186Sminshall 	if (length < 0) {
54927186Sminshall 	    return;
55027186Sminshall 	}
55127186Sminshall 	/* find next unique line */
55227186Sminshall     }
55327186Sminshall }
55427186Sminshall 
55527186Sminshall 
55627186Sminshall /*VARARGS*/
55727186Sminshall printoption(direction, fmt, option, what)
55827186Sminshall 	char *direction, *fmt;
55927186Sminshall 	int option, what;
56027186Sminshall {
56127186Sminshall 	if (!showoptions)
56227186Sminshall 		return;
56327676Sminshall 	printf("%s ", direction+1);
56427186Sminshall 	if (fmt == doopt)
56527186Sminshall 		fmt = "do";
56627186Sminshall 	else if (fmt == dont)
56727186Sminshall 		fmt = "dont";
56827186Sminshall 	else if (fmt == will)
56927186Sminshall 		fmt = "will";
57027186Sminshall 	else if (fmt == wont)
57127186Sminshall 		fmt = "wont";
57227186Sminshall 	else
57327186Sminshall 		fmt = "???";
57427676Sminshall 	if (option < (sizeof telopts/sizeof telopts[0]))
57527186Sminshall 		printf("%s %s", fmt, telopts[option]);
57627186Sminshall 	else
57727186Sminshall 		printf("%s %d", fmt, option);
57827186Sminshall 	if (*direction == '<') {
57927186Sminshall 		printf("\r\n");
58027186Sminshall 		return;
58127186Sminshall 	}
58227186Sminshall 	printf(" (%s)\r\n", what ? "reply" : "don't reply");
58327186Sminshall }
58427186Sminshall 
58527186Sminshall /*
58627110Sminshall  * Mode - set up terminal to a specific mode.
58727110Sminshall  */
58827110Sminshall 
5899972Ssam 
5906000Sroot mode(f)
5916000Sroot 	register int f;
5926000Sroot {
5938378Ssam 	static int prevmode = 0;
59413076Ssam 	struct tchars *tc;
59513076Ssam 	struct ltchars *ltc;
59613076Ssam 	struct sgttyb sb;
59713076Ssam 	int onoff, old;
59827228Sminshall 	struct	tchars notc2;
59927228Sminshall 	struct	ltchars noltc2;
60027228Sminshall 	static struct	tchars notc =	{ -1, -1, -1, -1, -1, -1 };
60127228Sminshall 	static struct	ltchars noltc =	{ -1, -1, -1, -1, -1, -1 };
6026000Sroot 
60327110Sminshall 	globalmode = f;
6048378Ssam 	if (prevmode == f)
60527186Sminshall 		return;
6068378Ssam 	old = prevmode;
6078378Ssam 	prevmode = f;
60827110Sminshall 	sb = nttyb;
6096000Sroot 	switch (f) {
6108378Ssam 
6116000Sroot 	case 0:
6126000Sroot 		onoff = 0;
6139972Ssam 		tc = &otc;
61413076Ssam 		ltc = &oltc;
6156000Sroot 		break;
6166000Sroot 
61727110Sminshall 	case 1:		/* remote character processing, remote echo */
61827110Sminshall 	case 2:		/* remote character processing, local echo */
61913076Ssam 		sb.sg_flags |= CBREAK;
6208378Ssam 		if (f == 1)
62113076Ssam 			sb.sg_flags &= ~(ECHO|CRMOD);
6228378Ssam 		else
62313076Ssam 			sb.sg_flags |= ECHO|CRMOD;
62413076Ssam 		sb.sg_erase = sb.sg_kill = -1;
6259972Ssam 		tc = &notc;
62627110Sminshall 		/*
62727110Sminshall 		 * If user hasn't specified one way or the other,
62827110Sminshall 		 * then default to not trapping signals.
62927110Sminshall 		 */
63027261Sminshall 		if (!donelclchars) {
63127261Sminshall 			localchars = 0;
63227228Sminshall 		}
63327261Sminshall 		if (localchars) {
63427110Sminshall 			notc2 = notc;
63527110Sminshall 			notc2.t_intrc = ntc.t_intrc;
63627110Sminshall 			notc2.t_quitc = ntc.t_quitc;
63727110Sminshall 			tc = &notc2;
63827110Sminshall 		} else
63927110Sminshall 			tc = &notc;
64013076Ssam 		ltc = &noltc;
6416000Sroot 		onoff = 1;
6429972Ssam 		break;
64327110Sminshall 	case 3:		/* local character processing, remote echo */
64427110Sminshall 	case 4:		/* local character processing, local echo */
64527110Sminshall 	case 5:		/* local character processing, no echo */
64627110Sminshall 		sb.sg_flags &= ~CBREAK;
64727110Sminshall 		sb.sg_flags |= CRMOD;
64827110Sminshall 		if (f == 4)
64927110Sminshall 			sb.sg_flags |= ECHO;
65027110Sminshall 		else
65127110Sminshall 			sb.sg_flags &= ~ECHO;
65227228Sminshall 		notc2 = ntc;
65327228Sminshall 		tc = &notc2;
65427228Sminshall 		noltc2 = oltc;
65527228Sminshall 		ltc = &noltc2;
65627110Sminshall 		/*
65727110Sminshall 		 * If user hasn't specified one way or the other,
65827110Sminshall 		 * then default to trapping signals.
65927110Sminshall 		 */
66027261Sminshall 		if (!donelclchars) {
66127261Sminshall 			localchars = 1;
66227228Sminshall 		}
66327261Sminshall 		if (localchars) {
66427228Sminshall 			notc2.t_brkc = nltc.t_flushc;
66527228Sminshall 			noltc2.t_flushc = -1;
66627228Sminshall 		} else {
66727110Sminshall 			notc2.t_intrc = notc2.t_quitc = -1;
66827110Sminshall 		}
66927110Sminshall 		noltc2.t_suspc = escape;
67027110Sminshall 		noltc2.t_dsuspc = -1;
67127110Sminshall 		onoff = 1;
67227110Sminshall 		break;
6739972Ssam 
6749972Ssam 	default:
6759972Ssam 		return;
6766000Sroot 	}
67713076Ssam 	ioctl(fileno(stdin), TIOCSLTC, (char *)ltc);
67813076Ssam 	ioctl(fileno(stdin), TIOCSETC, (char *)tc);
67913076Ssam 	ioctl(fileno(stdin), TIOCSETP, (char *)&sb);
68027186Sminshall 	ioctl(fileno(stdin), FIONBIO, (char *)&onoff);
68127186Sminshall 	ioctl(fileno(stdout), FIONBIO, (char *)&onoff);
68227110Sminshall 	if (f >= 3)
68327110Sminshall 		signal(SIGTSTP, doescape);
68427110Sminshall 	else if (old >= 3) {
68527110Sminshall 		signal(SIGTSTP, SIG_DFL);
68627110Sminshall 		sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
68727110Sminshall 	}
6886000Sroot }
68927186Sminshall 
69027110Sminshall /*
69127110Sminshall  * These routines decides on what the mode should be (based on the values
69227110Sminshall  * of various global variables).
69327110Sminshall  */
69427110Sminshall 
69527178Sminshall char *modedescriptions[] = {
69627178Sminshall 	"telnet command mode",					/* 0 */
69727178Sminshall 	"character-at-a-time mode",				/* 1 */
69827178Sminshall 	"character-at-a-time mode (local echo)",		/* 2 */
69927178Sminshall 	"line-by-line mode (remote echo)",			/* 3 */
70027178Sminshall 	"line-by-line mode",					/* 4 */
70127178Sminshall 	"line-by-line mode (local echoing suppressed)",		/* 5 */
70227178Sminshall };
70327178Sminshall 
70427178Sminshall getconnmode()
70527110Sminshall {
70627110Sminshall     static char newmode[8] = { 4, 5, 3, 3, 2, 2, 1, 1 };
70727186Sminshall     int modeindex = 0;
70827110Sminshall 
70927110Sminshall     if (hisopts[TELOPT_ECHO]) {
71027186Sminshall 	modeindex += 2;
71127110Sminshall     }
71227110Sminshall     if (hisopts[TELOPT_SGA]) {
71327186Sminshall 	modeindex += 4;
71427110Sminshall     }
71527186Sminshall     if (dontlecho && (clocks.echotoggle > clocks.modenegotiated)) {
71627186Sminshall 	modeindex += 1;
71727110Sminshall     }
71827186Sminshall     return newmode[modeindex];
71927110Sminshall }
72027110Sminshall 
72127178Sminshall setconnmode()
72227178Sminshall {
72327178Sminshall     mode(getconnmode());
72427178Sminshall }
72527110Sminshall 
72627178Sminshall 
72727110Sminshall setcommandmode()
72827110Sminshall {
72927110Sminshall     mode(0);
73027110Sminshall }
73127110Sminshall 
7326000Sroot char	sibuf[BUFSIZ], *sbp;
7336000Sroot char	tibuf[BUFSIZ], *tbp;
7346000Sroot int	scc, tcc;
7356000Sroot 
73627228Sminshall 
7376000Sroot /*
7386000Sroot  * Select from tty and network...
7396000Sroot  */
74027088Sminshall telnet()
7416000Sroot {
7426000Sroot 	register int c;
74327088Sminshall 	int tin = fileno(stdin);
7446000Sroot 	int on = 1;
74527261Sminshall 	fd_set ibits, obits, xbits;
7466000Sroot 
74727088Sminshall 	tout = fileno(stdout);
74827110Sminshall 	setconnmode();
74927228Sminshall 	scc = 0;
75027228Sminshall 	tcc = 0;
75127261Sminshall 	FD_ZERO(&ibits);
75227261Sminshall 	FD_ZERO(&obits);
75327261Sminshall 	FD_ZERO(&xbits);
75427261Sminshall 
75527186Sminshall 	ioctl(net, FIONBIO, (char *)&on);
75627676Sminshall #if	defined(SO_OOBINLINE)
75727676Sminshall 	setsockopt(net, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
75827676Sminshall #endif	/* defined(SO_OOBINLINE) */
75927676Sminshall 	if (telnetport) {
76027676Sminshall 	    if (!hisopts[TELOPT_SGA]) {
76127676Sminshall 		willoption(TELOPT_SGA, 0);
76227676Sminshall 	    }
76327676Sminshall 	    if (!myopts[TELOPT_TTYPE]) {
76427676Sminshall 		dooption(TELOPT_TTYPE, 0);
76527676Sminshall 	    }
76627088Sminshall 	}
7676000Sroot 	for (;;) {
76827110Sminshall 		if (scc < 0 && tcc < 0) {
7696000Sroot 			break;
77027110Sminshall 		}
77127110Sminshall 
77227228Sminshall 		if (((globalmode < 4) || flushline) && NETBYTES()) {
77327110Sminshall 			FD_SET(net, &obits);
77427088Sminshall 		} else {
77527110Sminshall 			FD_SET(tin, &ibits);
77627088Sminshall 		}
77727228Sminshall 		if (TTYBYTES()) {
77827110Sminshall 			FD_SET(tout, &obits);
77927110Sminshall 		} else {
78027110Sminshall 			FD_SET(net, &ibits);
78127110Sminshall 		}
78227186Sminshall 		if (!SYNCHing) {
78327110Sminshall 			FD_SET(net, &xbits);
78427110Sminshall 		}
78527186Sminshall 		if ((c = select(16, &ibits, &obits, &xbits,
78627186Sminshall 						(struct timeval *)0)) < 1) {
78727110Sminshall 			if (c == -1) {
78827110Sminshall 				/*
78927110Sminshall 				 * we can get EINTR if we are in line mode,
79027110Sminshall 				 * and the user does an escape (TSTP), or
79127110Sminshall 				 * some other signal generator.
79227110Sminshall 				 */
79327110Sminshall 				if (errno == EINTR) {
79427110Sminshall 					continue;
79527110Sminshall 				}
79627110Sminshall 			}
7976000Sroot 			sleep(5);
7986000Sroot 			continue;
7996000Sroot 		}
8006000Sroot 
8016000Sroot 		/*
80227088Sminshall 		 * Any urgent data?
80327088Sminshall 		 */
80427110Sminshall 		if (FD_ISSET(net, &xbits)) {
80527261Sminshall 		    FD_CLR(net, &xbits);
80627186Sminshall 		    SYNCHing = 1;
80727088Sminshall 		    ttyflush();	/* flush already enqueued data */
80827088Sminshall 		}
80927088Sminshall 
81027088Sminshall 		/*
8116000Sroot 		 * Something to read from the network...
8126000Sroot 		 */
81327110Sminshall 		if (FD_ISSET(net, &ibits)) {
81427228Sminshall 			int canread;
81527228Sminshall 
81627261Sminshall 			FD_CLR(net, &ibits);
81727228Sminshall 			if (scc == 0) {
81827228Sminshall 			    sbp = sibuf;
81927228Sminshall 			}
82027228Sminshall 			canread = sibuf + sizeof sibuf - sbp;
82127676Sminshall #if	!defined(SO_OOBINLINE)
82227178Sminshall 			/*
82327178Sminshall 			 * In 4.2 (and some early 4.3) systems, the
82427178Sminshall 			 * OOB indication and data handling in the kernel
82527178Sminshall 			 * is such that if two separate TCP Urgent requests
82627178Sminshall 			 * come in, one byte of TCP data will be overlaid.
82727178Sminshall 			 * This is fatal for Telnet, but we try to live
82827178Sminshall 			 * with it.
82927178Sminshall 			 *
83027178Sminshall 			 * In addition, in 4.2 (and...), a special protocol
83127178Sminshall 			 * is needed to pick up the TCP Urgent data in
83227178Sminshall 			 * the correct sequence.
83327178Sminshall 			 *
83427178Sminshall 			 * What we do is:  if we think we are in urgent
83527178Sminshall 			 * mode, we look to see if we are "at the mark".
83627178Sminshall 			 * If we are, we do an OOB receive.  If we run
83727178Sminshall 			 * this twice, we will do the OOB receive twice,
83827178Sminshall 			 * but the second will fail, since the second
83927178Sminshall 			 * time we were "at the mark", but there wasn't
84027178Sminshall 			 * any data there (the kernel doesn't reset
84127178Sminshall 			 * "at the mark" until we do a normal read).
84227178Sminshall 			 * Once we've read the OOB data, we go ahead
84327178Sminshall 			 * and do normal reads.
84427178Sminshall 			 *
84527178Sminshall 			 * There is also another problem, which is that
84627178Sminshall 			 * since the OOB byte we read doesn't put us
84727178Sminshall 			 * out of OOB state, and since that byte is most
84827178Sminshall 			 * likely the TELNET DM (data mark), we would
84927186Sminshall 			 * stay in the TELNET SYNCH (SYNCHing) state.
85027178Sminshall 			 * So, clocks to the rescue.  If we've "just"
85127178Sminshall 			 * received a DM, then we test for the
85227178Sminshall 			 * presence of OOB data when the receive OOB
85327178Sminshall 			 * fails (and AFTER we did the normal mode read
85427178Sminshall 			 * to clear "at the mark").
85527178Sminshall 			 */
85627186Sminshall 		    if (SYNCHing) {
85727178Sminshall 			int atmark;
85827178Sminshall 
85927186Sminshall 			ioctl(net, SIOCATMARK, (char *)&atmark);
86027178Sminshall 			if (atmark) {
86127228Sminshall 			    c = recv(net, sibuf, canread, MSG_OOB);
86227228Sminshall 			    if ((c == -1) && (errno == EINVAL)) {
86327228Sminshall 				c = read(net, sibuf, canread);
86427186Sminshall 				if (clocks.didnetreceive < clocks.gotDM) {
86527186Sminshall 				    SYNCHing = stilloob(net);
86627021Sminshall 				}
86727178Sminshall 			    }
86827178Sminshall 			} else {
86927228Sminshall 			    c = read(net, sibuf, canread);
8706000Sroot 			}
87127178Sminshall 		    } else {
87227228Sminshall 			c = read(net, sibuf, canread);
87327178Sminshall 		    }
87427178Sminshall 		    settimer(didnetreceive);
87527676Sminshall #else	/* !defined(SO_OOBINLINE) */
87627228Sminshall 		    c = read(net, sbp, canread);
87727676Sminshall #endif	/* !defined(SO_OOBINLINE) */
87827228Sminshall 		    if (c < 0 && errno == EWOULDBLOCK) {
87927228Sminshall 			c = 0;
88027228Sminshall 		    } else if (c <= 0) {
88127228Sminshall 			break;
88227178Sminshall 		    }
88327228Sminshall 		    if (netdata) {
88427228Sminshall 			Dump('<', sbp, c);
88527228Sminshall 		    }
88627228Sminshall 		    scc += c;
8876000Sroot 		}
8886000Sroot 
8896000Sroot 		/*
8906000Sroot 		 * Something to read from the tty...
8916000Sroot 		 */
89227110Sminshall 		if (FD_ISSET(tin, &ibits)) {
89327261Sminshall 			FD_CLR(tin, &ibits);
89427228Sminshall 			if (tcc == 0) {
89527228Sminshall 			    tbp = tibuf;	/* nothing left, reset */
8966000Sroot 			}
89727228Sminshall 			c = read(tin, tbp, tibuf+sizeof tibuf - tbp);
89827228Sminshall 			if (c < 0 && errno == EWOULDBLOCK) {
89927228Sminshall 				c = 0;
90027676Sminshall 			} else {
90127676Sminshall 				/* EOF detection for line mode!!!! */
90227676Sminshall 				if (c == 0 && globalmode >= 3) {
90327676Sminshall 					/* must be an EOF... */
90427676Sminshall 					*tbp = ntc.t_eofc;
90527676Sminshall 					c = 1;
90627676Sminshall 				}
90727676Sminshall 				if (c <= 0) {
90827676Sminshall 					tcc = c;
90927676Sminshall 					break;
91027676Sminshall 				}
91127228Sminshall 			}
91227228Sminshall 			tcc += c;
9136000Sroot 		}
9146000Sroot 
9156000Sroot 		while (tcc > 0) {
91627186Sminshall 			register int sc;
9176000Sroot 
91827228Sminshall 			if (NETROOM() < 2) {
91927110Sminshall 				flushline = 1;
9206000Sroot 				break;
92127110Sminshall 			}
92227186Sminshall 			c = *tbp++ & 0xff, sc = strip(c), tcc--;
92327186Sminshall 			if (sc == escape) {
9246000Sroot 				command(0);
9256000Sroot 				tcc = 0;
92627110Sminshall 				flushline = 1;
9276000Sroot 				break;
92827261Sminshall 			} else if ((globalmode >= 4) && (sc == echoc)) {
92927110Sminshall 				if (tcc > 0 && strip(*tbp) == echoc) {
93027110Sminshall 					tbp++;
93127110Sminshall 					tcc--;
93227110Sminshall 				} else {
93327110Sminshall 					dontlecho = !dontlecho;
93427110Sminshall 					settimer(echotoggle);
93527110Sminshall 					setconnmode();
93627110Sminshall 					tcc = 0;
93727110Sminshall 					flushline = 1;
93827110Sminshall 					break;
93927110Sminshall 				}
9406000Sroot 			}
94127261Sminshall 			if (localchars) {
94227186Sminshall 				if (sc == ntc.t_intrc) {
94327110Sminshall 					intp();
94427110Sminshall 					break;
94527186Sminshall 				} else if (sc == ntc.t_quitc) {
94627110Sminshall 					sendbrk();
94727110Sminshall 					break;
94827228Sminshall 				} else if (sc == nltc.t_flushc) {
94927228Sminshall 					NET2ADD(IAC, AO);
95027228Sminshall 					if (autoflush) {
95127228Sminshall 					    doflush();
95227228Sminshall 					}
95327228Sminshall 					break;
95427110Sminshall 				} else if (globalmode > 2) {
95527110Sminshall 					;
95627186Sminshall 				} else if (sc == nttyb.sg_kill) {
95727110Sminshall 					NET2ADD(IAC, EL);
95827110Sminshall 					break;
95927186Sminshall 				} else if (sc == nttyb.sg_erase) {
96027110Sminshall 					NET2ADD(IAC, EC);
96127110Sminshall 					break;
96227110Sminshall 				}
96327110Sminshall 			}
96417922Sralph 			switch (c) {
96517922Sralph 			case '\n':
96627021Sminshall 				/*
96727021Sminshall 				 * If echoing is happening locally,
96827021Sminshall 				 * then a newline (unix) is CRLF (TELNET).
96927021Sminshall 				 */
97027088Sminshall 				if (!hisopts[TELOPT_ECHO]) {
97127088Sminshall 					NETADD('\r');
97227088Sminshall 				}
97327088Sminshall 				NETADD('\n');
97427110Sminshall 				flushline = 1;
97517922Sralph 				break;
97617922Sralph 			case '\r':
97727088Sminshall 				NET2ADD('\r', '\0');
97827110Sminshall 				flushline = 1;
97917922Sralph 				break;
98017922Sralph 			case IAC:
98127088Sminshall 				NET2ADD(IAC, IAC);
98227021Sminshall 				break;
98317922Sralph 			default:
98427088Sminshall 				NETADD(c);
98517922Sralph 				break;
98617922Sralph 			}
9876000Sroot 		}
98827110Sminshall 		if (((globalmode < 4) || flushline) &&
98927228Sminshall 		    FD_ISSET(net, &obits) && (NETBYTES() > 0)) {
99027261Sminshall 			FD_CLR(net, &obits);
99127088Sminshall 			netflush(net);
99227110Sminshall 		}
9936000Sroot 		if (scc > 0)
9946000Sroot 			telrcv();
99527261Sminshall 		if (FD_ISSET(tout, &obits) && (TTYBYTES() > 0)) {
99627261Sminshall 			FD_CLR(tout, &obits);
99727088Sminshall 			ttyflush();
99827261Sminshall 		}
9996000Sroot 	}
100027110Sminshall 	setcommandmode();
10016000Sroot }
100227110Sminshall 
10036000Sroot /*
10046000Sroot  * Telnet receiver states for fsm
10056000Sroot  */
10066000Sroot #define	TS_DATA		0
10076000Sroot #define	TS_IAC		1
10086000Sroot #define	TS_WILL		2
10096000Sroot #define	TS_WONT		3
10106000Sroot #define	TS_DO		4
10116000Sroot #define	TS_DONT		5
101227021Sminshall #define	TS_CR		6
101327676Sminshall #define	TS_SB		7		/* sub-option collection */
101427676Sminshall #define	TS_SE		8		/* looking for sub-option end */
10156000Sroot 
10166000Sroot telrcv()
10176000Sroot {
10186000Sroot 	register int c;
10196000Sroot 	static int state = TS_DATA;
10206000Sroot 
102127228Sminshall 	while ((scc > 0) && (TTYROOM() > 2)) {
102227186Sminshall 		c = *sbp++ & 0xff, scc--;
10236000Sroot 		switch (state) {
10246000Sroot 
102527021Sminshall 		case TS_CR:
102627021Sminshall 			state = TS_DATA;
102727228Sminshall 			if (c == '\0') {
102827228Sminshall 			    break;	/* Ignore \0 after CR */
102927228Sminshall 			} else if (c == '\n') {
103027228Sminshall 			    if (hisopts[TELOPT_ECHO] && !crmod) {
103127228Sminshall 				TTYADD(c);
103227228Sminshall 			    }
103327228Sminshall 			    break;
103427021Sminshall 			}
103527228Sminshall 			/* Else, fall through */
103627021Sminshall 
10376000Sroot 		case TS_DATA:
10389972Ssam 			if (c == IAC) {
10396000Sroot 				state = TS_IAC;
10409972Ssam 				continue;
10419972Ssam 			}
104227228Sminshall 			    /*
104327228Sminshall 			     * The 'crmod' hack (see following) is needed
104427228Sminshall 			     * since we can't * set CRMOD on output only.
104527228Sminshall 			     * Machines like MULTICS like to send \r without
104627228Sminshall 			     * \n; since we must turn off CRMOD to get proper
104727228Sminshall 			     * input, the mapping is done here (sigh).
104827228Sminshall 			     */
104927021Sminshall 			if (c == '\r') {
105027021Sminshall 				if (scc > 0) {
105127186Sminshall 					c = *sbp&0xff;
105227021Sminshall 					if (c == 0) {
105327021Sminshall 						sbp++, scc--;
105427228Sminshall 						/* a "true" CR */
105527088Sminshall 						TTYADD('\r');
105627021Sminshall 					} else if (!hisopts[TELOPT_ECHO] &&
105727021Sminshall 								(c == '\n')) {
105827021Sminshall 						sbp++, scc--;
105927088Sminshall 						TTYADD('\n');
106027021Sminshall 					} else {
106127088Sminshall 						TTYADD('\r');
106227228Sminshall 						if (crmod) {
106327228Sminshall 							TTYADD('\n');
106427228Sminshall 						}
106527021Sminshall 					}
106627021Sminshall 				} else {
106727021Sminshall 					state = TS_CR;
106827088Sminshall 					TTYADD('\r');
106927228Sminshall 					if (crmod) {
107027228Sminshall 						TTYADD('\n');
107127228Sminshall 					}
107227021Sminshall 				}
107327021Sminshall 			} else {
107427088Sminshall 				TTYADD(c);
107527021Sminshall 			}
10766000Sroot 			continue;
10776000Sroot 
10786000Sroot 		case TS_IAC:
10796000Sroot 			switch (c) {
10806000Sroot 
10816000Sroot 			case WILL:
10826000Sroot 				state = TS_WILL;
10836000Sroot 				continue;
10846000Sroot 
10856000Sroot 			case WONT:
10866000Sroot 				state = TS_WONT;
10876000Sroot 				continue;
10886000Sroot 
10896000Sroot 			case DO:
10906000Sroot 				state = TS_DO;
10916000Sroot 				continue;
10926000Sroot 
10936000Sroot 			case DONT:
10946000Sroot 				state = TS_DONT;
10956000Sroot 				continue;
10966000Sroot 
10976000Sroot 			case DM:
109827088Sminshall 				/*
109927088Sminshall 				 * We may have missed an urgent notification,
110027088Sminshall 				 * so make sure we flush whatever is in the
110127088Sminshall 				 * buffer currently.
110227088Sminshall 				 */
110327186Sminshall 				SYNCHing = 1;
110427088Sminshall 				ttyflush();
110527186Sminshall 				SYNCHing = stilloob(net);
110627178Sminshall 				settimer(gotDM);
11076000Sroot 				break;
11086000Sroot 
11096000Sroot 			case NOP:
11106000Sroot 			case GA:
11116000Sroot 				break;
11126000Sroot 
111327676Sminshall 			case SB:
111427676Sminshall 				SB_CLEAR();
111527676Sminshall 				state = TS_SB;
111627676Sminshall 				continue;
111727676Sminshall 
11186000Sroot 			default:
11196000Sroot 				break;
11206000Sroot 			}
11216000Sroot 			state = TS_DATA;
11226000Sroot 			continue;
11236000Sroot 
11246000Sroot 		case TS_WILL:
112527676Sminshall 			printoption(">RCVD", will, c, !hisopts[c]);
112627110Sminshall 			if (c == TELOPT_TM) {
112727110Sminshall 				if (flushout) {
112827186Sminshall 					flushout = 0;
112927110Sminshall 				}
113027110Sminshall 			} else if (!hisopts[c]) {
113127676Sminshall 				willoption(c, 1);
113227110Sminshall 			}
11336000Sroot 			state = TS_DATA;
11346000Sroot 			continue;
11356000Sroot 
11366000Sroot 		case TS_WONT:
113727676Sminshall 			printoption(">RCVD", wont, c, hisopts[c]);
113827110Sminshall 			if (c == TELOPT_TM) {
113927110Sminshall 				if (flushout) {
114027186Sminshall 					flushout = 0;
114127110Sminshall 				}
114227110Sminshall 			} else if (hisopts[c]) {
114327676Sminshall 				wontoption(c, 1);
114427110Sminshall 			}
11456000Sroot 			state = TS_DATA;
11466000Sroot 			continue;
11476000Sroot 
11486000Sroot 		case TS_DO:
114927676Sminshall 			printoption(">RCVD", doopt, c, !myopts[c]);
11506000Sroot 			if (!myopts[c])
11516000Sroot 				dooption(c);
11526000Sroot 			state = TS_DATA;
11536000Sroot 			continue;
11546000Sroot 
11556000Sroot 		case TS_DONT:
115627676Sminshall 			printoption(">RCVD", dont, c, myopts[c]);
11576000Sroot 			if (myopts[c]) {
11586000Sroot 				myopts[c] = 0;
11596000Sroot 				sprintf(nfrontp, wont, c);
11608378Ssam 				nfrontp += sizeof (wont) - 2;
116127110Sminshall 				flushline = 1;
116227110Sminshall 				setconnmode();	/* set new tty mode (maybe) */
116327676Sminshall 				printoption(">SENT", wont, c);
11646000Sroot 			}
11656000Sroot 			state = TS_DATA;
11666000Sroot 			continue;
116727676Sminshall 		case TS_SB:
116827676Sminshall 			if (c == IAC) {
116927676Sminshall 				state = TS_SE;
117027676Sminshall 			} else {
117127676Sminshall 				SB_ACCUM(c);
117227676Sminshall 			}
117327676Sminshall 			continue;
117427676Sminshall 
117527676Sminshall 		case TS_SE:
117627676Sminshall 			if (c != SE) {
117727676Sminshall 				if (c != IAC) {
117827676Sminshall 					SB_ACCUM(IAC);
117927676Sminshall 				}
118027676Sminshall 				SB_ACCUM(c);
118127676Sminshall 				state = TS_SB;
118227676Sminshall 			} else {
118327676Sminshall 				SB_TERM();
118427676Sminshall 				suboption();	/* handle sub-option */
118527676Sminshall 				state = TS_DATA;
118627676Sminshall 			}
11876000Sroot 		}
11886000Sroot 	}
11896000Sroot }
119027110Sminshall 
119127676Sminshall willoption(option, reply)
119227676Sminshall 	int option, reply;
11936000Sroot {
11946000Sroot 	char *fmt;
11956000Sroot 
11966000Sroot 	switch (option) {
11976000Sroot 
11986000Sroot 	case TELOPT_ECHO:
11996000Sroot 	case TELOPT_SGA:
120027110Sminshall 		settimer(modenegotiated);
12016000Sroot 		hisopts[option] = 1;
12026000Sroot 		fmt = doopt;
120327110Sminshall 		setconnmode();		/* possibly set new tty mode */
12046000Sroot 		break;
12056000Sroot 
12066000Sroot 	case TELOPT_TM:
120727110Sminshall 		return;			/* Never reply to TM will's/wont's */
12086000Sroot 
12096000Sroot 	default:
12106000Sroot 		fmt = dont;
12116000Sroot 		break;
12126000Sroot 	}
12136024Ssam 	sprintf(nfrontp, fmt, option);
12148378Ssam 	nfrontp += sizeof (dont) - 2;
121527676Sminshall 	if (reply)
121627676Sminshall 		printoption(">SENT", fmt, option);
121727676Sminshall 	else
121827676Sminshall 		printoption("<SENT", fmt, option);
12196000Sroot }
12206000Sroot 
122127676Sminshall wontoption(option, reply)
122227676Sminshall 	int option, reply;
12236000Sroot {
12246000Sroot 	char *fmt;
12256000Sroot 
12266000Sroot 	switch (option) {
12276000Sroot 
12286000Sroot 	case TELOPT_ECHO:
12296000Sroot 	case TELOPT_SGA:
123027110Sminshall 		settimer(modenegotiated);
12316000Sroot 		hisopts[option] = 0;
12326000Sroot 		fmt = dont;
123327110Sminshall 		setconnmode();			/* Set new tty mode */
12346000Sroot 		break;
12356000Sroot 
123627110Sminshall 	case TELOPT_TM:
123727110Sminshall 		return;		/* Never reply to TM will's/wont's */
123827110Sminshall 
12396000Sroot 	default:
12406000Sroot 		fmt = dont;
12416000Sroot 	}
12426000Sroot 	sprintf(nfrontp, fmt, option);
12438378Ssam 	nfrontp += sizeof (doopt) - 2;
124427676Sminshall 	if (reply)
124527676Sminshall 		printoption(">SENT", fmt, option);
124627676Sminshall 	else
124727676Sminshall 		printoption("<SENT", fmt, option);
12486000Sroot }
12496000Sroot 
12506000Sroot dooption(option)
12516000Sroot 	int option;
12526000Sroot {
12536000Sroot 	char *fmt;
12546000Sroot 
12556000Sroot 	switch (option) {
12566000Sroot 
12576000Sroot 	case TELOPT_TM:
125813231Ssam 		fmt = will;
125913231Ssam 		break;
126013231Ssam 
126127676Sminshall 	case TELOPT_TTYPE:		/* terminal type option */
126227110Sminshall 	case TELOPT_SGA:		/* no big deal */
12636000Sroot 		fmt = will;
126427110Sminshall 		myopts[option] = 1;
12656000Sroot 		break;
12666000Sroot 
126727110Sminshall 	case TELOPT_ECHO:		/* We're never going to echo... */
12686000Sroot 	default:
12696000Sroot 		fmt = wont;
12706000Sroot 		break;
12716000Sroot 	}
12726000Sroot 	sprintf(nfrontp, fmt, option);
12738378Ssam 	nfrontp += sizeof (doopt) - 2;
127427676Sminshall 	printoption(">SENT", fmt, option);
12756000Sroot }
127627676Sminshall 
127727676Sminshall /*
127827676Sminshall  * suboption()
127927676Sminshall  *
128027676Sminshall  *	Look at the sub-option buffer, and try to be helpful to the other
128127676Sminshall  * side.
128227676Sminshall  *
128327676Sminshall  *	Currently we recognize:
128427676Sminshall  *
128527676Sminshall  *		Terminal type, send request.
128627676Sminshall  */
128727676Sminshall 
128827676Sminshall suboption()
128927676Sminshall {
129027676Sminshall     switch (subbuffer[0]&0xff) {
129127676Sminshall     case TELOPT_TTYPE:
129227676Sminshall 	if ((subbuffer[1]&0xff) != TELQUAL_SEND) {
129327676Sminshall 	    ;
129427676Sminshall 	} else {
129527676Sminshall 	    char *name;
129627676Sminshall 	    char namebuf[41];
129727676Sminshall 	    char *getenv();
129827676Sminshall 	    int len;
129927676Sminshall 
130027676Sminshall 	    name = getenv("TERM");
130127676Sminshall 	    if ((name == 0) || ((len = strlen(name)) > 40)) {
130227676Sminshall 		name = "UNKNOWN";
130327676Sminshall 	    }
130427676Sminshall 	    if ((len + 4+2) < NETROOM()) {
130527676Sminshall 		strcpy(namebuf, name);
130627676Sminshall 		upcase(namebuf);
130727676Sminshall 		sprintf(nfrontp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
130827676Sminshall 				    TELQUAL_IS, namebuf, IAC, SE);
130927676Sminshall 		nfrontp += 4+strlen(namebuf)+2;
131027676Sminshall 	    }
131127676Sminshall 	}
131227676Sminshall 
131327676Sminshall     default:
131427676Sminshall 	break;
131527676Sminshall     }
131627676Sminshall }
131727110Sminshall 
13186000Sroot /*
131927088Sminshall  *	The following are data structures and routines for
132027088Sminshall  *	the "send" command.
132127088Sminshall  *
132227088Sminshall  */
132327088Sminshall 
132427088Sminshall struct sendlist {
132527088Sminshall     char	*name;		/* How user refers to it (case independent) */
132627088Sminshall     int		what;		/* Character to be sent (<0 ==> special) */
132727088Sminshall     char	*help;		/* Help information (0 ==> no help) */
132827088Sminshall     int		(*routine)();	/* Routine to perform (for special ops) */
132927088Sminshall };
133027088Sminshall 
133127186Sminshall /*ARGSUSED*/
133227088Sminshall dosynch(s)
133327088Sminshall struct sendlist *s;
133427088Sminshall {
133527261Sminshall     netclear();			/* clear the path to the network */
133627088Sminshall     NET2ADD(IAC, DM);
133727186Sminshall     neturg = NETLOC()-1;	/* Some systems are off by one XXX */
133827088Sminshall }
133927088Sminshall 
134027228Sminshall doflush()
134127228Sminshall {
134227228Sminshall     NET2ADD(IAC, DO);
134327228Sminshall     NETADD(TELOPT_TM);
134427228Sminshall     flushline = 1;
134527228Sminshall     flushout = 1;
134627228Sminshall     ttyflush();
134727676Sminshall     /* do printoption AFTER flush, otherwise the output gets tossed... */
134827676Sminshall     printoption("<SENT", doopt, TELOPT_TM);
134927228Sminshall }
135027228Sminshall 
135127088Sminshall intp()
135227088Sminshall {
135327110Sminshall     NET2ADD(IAC, IP);
135427228Sminshall     if (autoflush) {
135527228Sminshall 	doflush();
135627228Sminshall     }
135727228Sminshall     if (autosynch) {
135827228Sminshall 	dosynch();
135927228Sminshall     }
136027088Sminshall }
136127088Sminshall 
136227110Sminshall sendbrk()
136327110Sminshall {
136427186Sminshall     NET2ADD(IAC, BREAK);
136527228Sminshall     if (autoflush) {
136627228Sminshall 	doflush();
136727228Sminshall     }
136827228Sminshall     if (autosynch) {
136927228Sminshall 	dosynch();
137027228Sminshall     }
137127110Sminshall }
137227088Sminshall 
137327110Sminshall 
137427088Sminshall #define	SENDQUESTION	-1
137527088Sminshall #define	SENDESCAPE	-3
137627088Sminshall 
137727088Sminshall struct sendlist Sendlist[] = {
137827088Sminshall     { "ao", AO, "Send Telnet Abort output" },
137927088Sminshall     { "ayt", AYT, "Send Telnet 'Are You There'" },
138027261Sminshall     { "brk", BREAK, "Send Telnet Break" },
138127088Sminshall     { "ec", EC, "Send Telnet Erase Character" },
138227088Sminshall     { "el", EL, "Send Telnet Erase Line" },
138327261Sminshall     { "escape", SENDESCAPE, "Send current escape character" },
138427088Sminshall     { "ga", GA, "Send Telnet 'Go Ahead' sequence" },
138527261Sminshall     { "ip", IP, "Send Telnet Interrupt Process" },
138627088Sminshall     { "nop", NOP, "Send Telnet 'No operation'" },
138727261Sminshall     { "synch", SYNCH, "Perform Telnet 'Synch operation'", dosynch },
138827088Sminshall     { "?", SENDQUESTION, "Display send options" },
138927088Sminshall     { 0 }
139027088Sminshall };
139127088Sminshall 
139227261Sminshall struct sendlist Sendlist2[] = {		/* some synonyms */
139327261Sminshall 	{ "break", BREAK, 0 },
139427261Sminshall 
139527261Sminshall 	{ "intp", IP, 0 },
139627261Sminshall 	{ "interrupt", IP, 0 },
139727261Sminshall 	{ "intr", IP, 0 },
139827261Sminshall 
139927261Sminshall 	{ "help", SENDQUESTION, 0 },
140027261Sminshall 
140127261Sminshall 	{ 0 }
140227261Sminshall };
140327261Sminshall 
140427088Sminshall char **
140527088Sminshall getnextsend(name)
140627088Sminshall char *name;
140727088Sminshall {
140827088Sminshall     struct sendlist *c = (struct sendlist *) name;
140927088Sminshall 
141027088Sminshall     return (char **) (c+1);
141127088Sminshall }
141227088Sminshall 
141327088Sminshall struct sendlist *
141427088Sminshall getsend(name)
141527088Sminshall char *name;
141627088Sminshall {
141727261Sminshall     struct sendlist *sl;
141827261Sminshall 
141927261Sminshall     if (sl = (struct sendlist *)
142027261Sminshall 				genget(name, (char **) Sendlist, getnextsend)) {
142127261Sminshall 	return sl;
142227261Sminshall     } else {
142327261Sminshall 	return (struct sendlist *)
142427261Sminshall 				genget(name, (char **) Sendlist2, getnextsend);
142527261Sminshall     }
142627088Sminshall }
142727088Sminshall 
142827088Sminshall sendcmd(argc, argv)
142927088Sminshall int	argc;
143027088Sminshall char	**argv;
143127088Sminshall {
143227088Sminshall     int what;		/* what we are sending this time */
143327088Sminshall     int count;		/* how many bytes we are going to need to send */
143427088Sminshall     int hadsynch;	/* are we going to process a "synch"? */
143527088Sminshall     int i;
143627261Sminshall     int question = 0;	/* was at least one argument a question */
143727088Sminshall     struct sendlist *s;	/* pointer to current command */
143827088Sminshall 
143927088Sminshall     if (argc < 2) {
144027088Sminshall 	printf("need at least one argument for 'send' command\n");
144127088Sminshall 	printf("'send ?' for help\n");
144227261Sminshall 	return 0;
144327088Sminshall     }
144427088Sminshall     /*
144527088Sminshall      * First, validate all the send arguments.
144627088Sminshall      * In addition, we see how much space we are going to need, and
144727088Sminshall      * whether or not we will be doing a "SYNCH" operation (which
144827088Sminshall      * flushes the network queue).
144927088Sminshall      */
145027088Sminshall     count = 0;
145127088Sminshall     hadsynch = 0;
145227088Sminshall     for (i = 1; i < argc; i++) {
145327088Sminshall 	s = getsend(argv[i]);
145427088Sminshall 	if (s == 0) {
145527088Sminshall 	    printf("Unknown send argument '%s'\n'send ?' for help.\n",
145627088Sminshall 			argv[i]);
145727261Sminshall 	    return 0;
145827186Sminshall 	} else if (s == Ambiguous(struct sendlist *)) {
145927088Sminshall 	    printf("Ambiguous send argument '%s'\n'send ?' for help.\n",
146027088Sminshall 			argv[i]);
146127261Sminshall 	    return 0;
146227088Sminshall 	}
146327088Sminshall 	switch (s->what) {
146427088Sminshall 	case SENDQUESTION:
146527088Sminshall 	    break;
146627088Sminshall 	case SENDESCAPE:
146727088Sminshall 	    count += 1;
146827088Sminshall 	    break;
146927088Sminshall 	case SYNCH:
147027088Sminshall 	    hadsynch = 1;
147127088Sminshall 	    count += 2;
147227088Sminshall 	    break;
147327088Sminshall 	default:
147427088Sminshall 	    count += 2;
147527088Sminshall 	    break;
147627088Sminshall 	}
147727088Sminshall     }
147827088Sminshall     /* Now, do we have enough room? */
147927228Sminshall     if (NETROOM() < count) {
148027088Sminshall 	printf("There is not enough room in the buffer TO the network\n");
148127088Sminshall 	printf("to process your request.  Nothing will be done.\n");
148227088Sminshall 	printf("('send synch' will throw away most data in the network\n");
148327088Sminshall 	printf("buffer, if this might help.)\n");
148427261Sminshall 	return 0;
148527088Sminshall     }
148627088Sminshall     /* OK, they are all OK, now go through again and actually send */
148727088Sminshall     for (i = 1; i < argc; i++) {
148827088Sminshall 	if (!(s = getsend(argv[i]))) {
148927088Sminshall 	    fprintf(stderr, "Telnet 'send' error - argument disappeared!\n");
149027088Sminshall 	    quit();
149127088Sminshall 	    /*NOTREACHED*/
149227088Sminshall 	}
149327088Sminshall 	if (s->routine) {
149427088Sminshall 	    (*s->routine)(s);
149527088Sminshall 	} else {
149627088Sminshall 	    switch (what = s->what) {
149727261Sminshall 	    case SYNCH:
149827261Sminshall 		dosynch();
149927261Sminshall 		break;
150027088Sminshall 	    case SENDQUESTION:
150127088Sminshall 		for (s = Sendlist; s->name; s++) {
150227261Sminshall 		    if (s->help) {
150327088Sminshall 			printf(s->name);
150427088Sminshall 			if (s->help) {
150527088Sminshall 			    printf("\t%s", s->help);
150627088Sminshall 			}
150727088Sminshall 			printf("\n");
150827088Sminshall 		    }
150927088Sminshall 		}
151027261Sminshall 		question = 1;
151127088Sminshall 		break;
151227088Sminshall 	    case SENDESCAPE:
151327088Sminshall 		NETADD(escape);
151427088Sminshall 		break;
151527088Sminshall 	    default:
151627088Sminshall 		NET2ADD(IAC, what);
151727088Sminshall 		break;
151827088Sminshall 	    }
151927088Sminshall 	}
152027088Sminshall     }
152127261Sminshall     return !question;
152227088Sminshall }
152327088Sminshall 
152427088Sminshall /*
152527088Sminshall  * The following are the routines and data structures referred
152627088Sminshall  * to by the arguments to the "toggle" command.
152727088Sminshall  */
152827088Sminshall 
152927261Sminshall lclchars()
153027110Sminshall {
153127261Sminshall     donelclchars = 1;
153227261Sminshall     return 1;
153327110Sminshall }
153427110Sminshall 
153527178Sminshall togdebug()
153627088Sminshall {
153727676Sminshall #ifndef	NOT43
153827110Sminshall     if (net > 0 &&
153927186Sminshall 	setsockopt(net, SOL_SOCKET, SO_DEBUG, (char *)&debug, sizeof(debug))
154027186Sminshall 									< 0) {
154127110Sminshall 	    perror("setsockopt (SO_DEBUG)");
154227186Sminshall     }
154327676Sminshall #else	NOT43
154427676Sminshall     if (debug) {
154527676Sminshall 	if (net > 0 && setsockopt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
154627676Sminshall 	    perror("setsockopt (SO_DEBUG)");
154727676Sminshall     } else
154827676Sminshall 	printf("Cannot turn off socket debugging\n");
154927676Sminshall #endif	NOT43
155027261Sminshall     return 1;
155127088Sminshall }
155227088Sminshall 
155327088Sminshall 
155427088Sminshall 
155527088Sminshall int togglehelp();
155627088Sminshall 
155727178Sminshall struct togglelist {
155827178Sminshall     char	*name;		/* name of toggle */
155927178Sminshall     char	*help;		/* help message */
156027186Sminshall     int		(*handler)();	/* routine to do actual setting */
156127178Sminshall     int		dohelp;		/* should we display help information */
156227178Sminshall     int		*variable;
156327178Sminshall     char	*actionexplanation;
156427178Sminshall };
156527178Sminshall 
156627178Sminshall struct togglelist Togglelist[] = {
156727261Sminshall     { "autoflush",
156827261Sminshall 	"toggle flushing of output when sending interrupt characters",
156927186Sminshall 	    0,
157027178Sminshall 		1,
157127261Sminshall 		    &autoflush,
157227261Sminshall 			"flush output when sending interrupt characters" },
157327186Sminshall     { "autosynch",
157427186Sminshall 	"toggle automatic sending of interrupt characters in urgent mode",
157527186Sminshall 	    0,
157627186Sminshall 		1,
157727186Sminshall 		    &autosynch,
157827186Sminshall 			"send interrupt characters in urgent mode" },
157927178Sminshall     { "crmod",
158027261Sminshall 	"toggle mapping of received carriage returns",
158127186Sminshall 	    0,
158227178Sminshall 		1,
158327178Sminshall 		    &crmod,
158427178Sminshall 			"map carriage return on output" },
158527261Sminshall     { "localchars",
158627261Sminshall 	"toggle local recognition of certain control characters",
158727261Sminshall 	    lclchars,
158827261Sminshall 		1,
158927261Sminshall 		    &localchars,
159027261Sminshall 			"recognize certain control characters" },
159127110Sminshall     { " ", "", 0, 1 },		/* empty line */
159227178Sminshall     { "debug",
159327178Sminshall 	"(debugging) toggle debugging",
159427178Sminshall 	    togdebug,
159527178Sminshall 		1,
159627178Sminshall 		    &debug,
159727178Sminshall 			"turn on socket level debugging" },
159827261Sminshall     { "netdata",
159927261Sminshall 	"(debugging) toggle printing of hexadecimal network data",
160027261Sminshall 	    0,
160127261Sminshall 		1,
160227261Sminshall 		    &netdata,
160327261Sminshall 			"print hexadecimal representation of network traffic" },
160427178Sminshall     { "options",
160527178Sminshall 	"(debugging) toggle viewing of options processing",
160627186Sminshall 	    0,
160727178Sminshall 		1,
160827178Sminshall 		    &showoptions,
160927178Sminshall 			"show option processing" },
161027261Sminshall     { " ", "", 0, 1 },		/* empty line */
161127178Sminshall     { "?",
161227178Sminshall 	"display help information",
161327178Sminshall 	    togglehelp,
161427178Sminshall 		1 },
161527178Sminshall     { "help",
161627178Sminshall 	"display help information",
161727178Sminshall 	    togglehelp,
161827178Sminshall 		0 },
161927088Sminshall     { 0 }
162027088Sminshall };
162127088Sminshall 
162227088Sminshall togglehelp()
162327088Sminshall {
162427178Sminshall     struct togglelist *c;
162527088Sminshall 
162627178Sminshall     for (c = Togglelist; c->name; c++) {
162727088Sminshall 	if (c->dohelp) {
162827088Sminshall 	    printf("%s\t%s\n", c->name, c->help);
162927088Sminshall 	}
163027088Sminshall     }
163127261Sminshall     return 0;
163227088Sminshall }
163327088Sminshall 
163427088Sminshall char **
163527088Sminshall getnexttoggle(name)
163627088Sminshall char *name;
163727088Sminshall {
163827178Sminshall     struct togglelist *c = (struct togglelist *) name;
163927088Sminshall 
164027088Sminshall     return (char **) (c+1);
164127088Sminshall }
164227088Sminshall 
164327178Sminshall struct togglelist *
164427088Sminshall gettoggle(name)
164527088Sminshall char *name;
164627088Sminshall {
164727178Sminshall     return (struct togglelist *)
164827178Sminshall 			genget(name, (char **) Togglelist, getnexttoggle);
164927088Sminshall }
165027088Sminshall 
165127088Sminshall toggle(argc, argv)
165227088Sminshall int	argc;
165327088Sminshall char	*argv[];
165427088Sminshall {
165527261Sminshall     int retval = 1;
165627088Sminshall     char *name;
165727178Sminshall     struct togglelist *c;
165827088Sminshall 
165927088Sminshall     if (argc < 2) {
166027088Sminshall 	fprintf(stderr,
166127088Sminshall 	    "Need an argument to 'toggle' command.  'toggle ?' for help.\n");
166227261Sminshall 	return 0;
166327088Sminshall     }
166427088Sminshall     argc--;
166527088Sminshall     argv++;
166627088Sminshall     while (argc--) {
166727088Sminshall 	name = *argv++;
166827088Sminshall 	c = gettoggle(name);
166927186Sminshall 	if (c == Ambiguous(struct togglelist *)) {
167027088Sminshall 	    fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n",
167127088Sminshall 					name);
167227261Sminshall 	    return 0;
167327088Sminshall 	} else if (c == 0) {
167427088Sminshall 	    fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n",
167527088Sminshall 					name);
167627261Sminshall 	    return 0;
167727088Sminshall 	} else {
167827186Sminshall 	    if (c->variable) {
167927186Sminshall 		*c->variable = !*c->variable;		/* invert it */
168027186Sminshall 		printf("%s %s.\n", *c->variable? "Will" : "Won't",
168127186Sminshall 							c->actionexplanation);
168227186Sminshall 	    }
168327186Sminshall 	    if (c->handler) {
168427261Sminshall 		retval &= (*c->handler)(c);
168527186Sminshall 	    }
168627088Sminshall 	}
168727088Sminshall     }
168827261Sminshall     return retval;
168927088Sminshall }
169027088Sminshall 
169127088Sminshall /*
169227110Sminshall  * The following perform the "set" command.
169327110Sminshall  */
169427110Sminshall 
169527178Sminshall struct setlist {
169627178Sminshall     char *name;				/* name */
169727110Sminshall     char *help;				/* help information */
169827110Sminshall     char *charp;			/* where it is located at */
169927110Sminshall };
170027110Sminshall 
170127178Sminshall struct setlist Setlist[] = {
170227110Sminshall     { "echo", 	"character to toggle local echoing on/off", &echoc },
170327110Sminshall     { "escape",	"character to escape back to telnet command mode", &escape },
170427261Sminshall     { " ", "" },
170527261Sminshall     { " ", "The following need 'localchars' to be toggled true", 0 },
170627261Sminshall     { "erase",	"character to cause an Erase Character", &nttyb.sg_erase },
170727261Sminshall     { "flushoutput", "character to cause an Abort Oubput", &nltc.t_flushc },
170827110Sminshall     { "interrupt", "character to cause an Interrupt Process", &ntc.t_intrc },
170927261Sminshall     { "kill",	"character to cause an Erase Line", &nttyb.sg_kill },
171027110Sminshall     { "quit",	"character to cause a Break", &ntc.t_quitc },
171127676Sminshall     { "eof",	"character to cause an EOF ", &ntc.t_eofc },
171227110Sminshall     { 0 }
171327110Sminshall };
171427110Sminshall 
171527110Sminshall char **
171627178Sminshall getnextset(name)
171727110Sminshall char *name;
171827110Sminshall {
171927178Sminshall     struct setlist *c = (struct setlist *)name;
172027110Sminshall 
172127110Sminshall     return (char **) (c+1);
172227110Sminshall }
172327110Sminshall 
172427178Sminshall struct setlist *
172527178Sminshall getset(name)
172627110Sminshall char *name;
172727110Sminshall {
172827178Sminshall     return (struct setlist *) genget(name, (char **) Setlist, getnextset);
172927110Sminshall }
173027110Sminshall 
173127110Sminshall setcmd(argc, argv)
173227110Sminshall int	argc;
173327110Sminshall char	*argv[];
173427110Sminshall {
173527110Sminshall     int value;
173627178Sminshall     struct setlist *ct;
173727110Sminshall 
173827110Sminshall     /* XXX back we go... sigh */
173927110Sminshall     if (argc != 3) {
174027261Sminshall 	if ((argc == 2) &&
174127261Sminshall 		    ((!strcmp(argv[1], "?")) || (!strcmp(argv[1], "help")))) {
174227261Sminshall 	    for (ct = Setlist; ct->name; ct++) {
174327261Sminshall 		printf("%s\t%s\n", ct->name, ct->help);
174427261Sminshall 	    }
174527261Sminshall 	    printf("?\tdisplay help information\n");
174627261Sminshall 	} else {
174727261Sminshall 	    printf("Format is 'set Name Value'\n'set ?' for help.\n");
174827110Sminshall 	}
174927261Sminshall 	return 0;
175027110Sminshall     }
175127110Sminshall 
175227178Sminshall     ct = getset(argv[1]);
175327110Sminshall     if (ct == 0) {
175427110Sminshall 	fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n",
175527110Sminshall 			argv[1]);
175627261Sminshall 	return 0;
175727186Sminshall     } else if (ct == Ambiguous(struct setlist *)) {
175827110Sminshall 	fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
175927110Sminshall 			argv[1]);
176027261Sminshall 	return 0;
176127110Sminshall     } else {
176227110Sminshall 	if (strcmp("off", argv[2])) {
176327110Sminshall 	    value = special(argv[2]);
176427110Sminshall 	} else {
176527110Sminshall 	    value = -1;
176627110Sminshall 	}
176727110Sminshall 	*(ct->charp) = value;
176827178Sminshall 	printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
176927110Sminshall     }
177027261Sminshall     return 1;
177127110Sminshall }
177227110Sminshall 
177327110Sminshall /*
177427110Sminshall  * The following are the data structures and routines for the
177527110Sminshall  * 'mode' command.
177627110Sminshall  */
177727110Sminshall 
177827110Sminshall dolinemode()
177927110Sminshall {
178027110Sminshall     if (hisopts[TELOPT_SGA]) {
178127676Sminshall 	wontoption(TELOPT_SGA, 0);
178227110Sminshall     }
178327110Sminshall     if (hisopts[TELOPT_ECHO]) {
178427676Sminshall 	wontoption(TELOPT_ECHO, 0);
178527110Sminshall     }
178627110Sminshall }
178727110Sminshall 
178827110Sminshall docharmode()
178927110Sminshall {
179027110Sminshall     if (!hisopts[TELOPT_SGA]) {
179127676Sminshall 	willoption(TELOPT_SGA, 0);
179227110Sminshall     }
179327110Sminshall     if (!hisopts[TELOPT_ECHO]) {
179427676Sminshall 	willoption(TELOPT_ECHO, 0);
179527110Sminshall     }
179627110Sminshall }
179727110Sminshall 
179827110Sminshall struct cmd Modelist[] = {
179927261Sminshall     { "character",	"character-at-a-time mode",	docharmode, 1, 1 },
180027110Sminshall     { "line",		"line-by-line mode",		dolinemode, 1, 1 },
180127110Sminshall     { 0 },
180227110Sminshall };
180327110Sminshall 
180427110Sminshall char **
180527110Sminshall getnextmode(name)
180627110Sminshall char *name;
180727110Sminshall {
180827110Sminshall     struct cmd *c = (struct cmd *) name;
180927110Sminshall 
181027110Sminshall     return (char **) (c+1);
181127110Sminshall }
181227110Sminshall 
181327110Sminshall struct cmd *
181427110Sminshall getmodecmd(name)
181527110Sminshall char *name;
181627110Sminshall {
181727110Sminshall     return (struct cmd *) genget(name, (char **) Modelist, getnextmode);
181827110Sminshall }
181927110Sminshall 
182027110Sminshall modecmd(argc, argv)
182127110Sminshall int	argc;
182227110Sminshall char	*argv[];
182327110Sminshall {
182427110Sminshall     struct cmd *mt;
182527110Sminshall 
182627110Sminshall     if ((argc != 2) || !strcmp(argv[1], "?") || !strcmp(argv[1], "help")) {
182727110Sminshall 	printf("format is:  'mode Mode', where 'Mode' is one of:\n\n");
182827110Sminshall 	for (mt = Modelist; mt->name; mt++) {
182927110Sminshall 	    printf("%s\t%s\n", mt->name, mt->help);
183027110Sminshall 	}
183127261Sminshall 	return 0;
183227110Sminshall     }
183327110Sminshall     mt = getmodecmd(argv[1]);
183427110Sminshall     if (mt == 0) {
183527110Sminshall 	fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]);
183627261Sminshall 	return 0;
183727186Sminshall     } else if (mt == Ambiguous(struct cmd *)) {
183827110Sminshall 	fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]);
183927261Sminshall 	return 0;
184027110Sminshall     } else {
184127110Sminshall 	(*mt->handler)();
184227110Sminshall     }
184327261Sminshall     return 1;
184427110Sminshall }
184527110Sminshall 
184627110Sminshall /*
184727178Sminshall  * The following data structures and routines implement the
184827178Sminshall  * "display" command.
184927178Sminshall  */
185027178Sminshall 
185127178Sminshall display(argc, argv)
185227178Sminshall int	argc;
185327178Sminshall char	*argv[];
185427178Sminshall {
185527178Sminshall #define	dotog(tl)	if (tl->variable && tl->actionexplanation) { \
185627178Sminshall 			    if (*tl->variable) { \
185727178Sminshall 				printf("will"); \
185827178Sminshall 			    } else { \
185927178Sminshall 				printf("won't"); \
186027178Sminshall 			    } \
186127178Sminshall 			    printf(" %s.\n", tl->actionexplanation); \
186227178Sminshall 			}
186327178Sminshall 
186427261Sminshall #define	doset(sl)   if (sl->name && *sl->name != ' ') { \
186527261Sminshall 			printf("[%s]\t%s.\n", control(*sl->charp), sl->name); \
186627261Sminshall 		    }
186727178Sminshall 
186827178Sminshall     struct togglelist *tl;
186927178Sminshall     struct setlist *sl;
187027178Sminshall 
187127178Sminshall     if (argc == 1) {
187227178Sminshall 	for (tl = Togglelist; tl->name; tl++) {
187327178Sminshall 	    dotog(tl);
187427178Sminshall 	}
187527261Sminshall 	printf("\n");
187627178Sminshall 	for (sl = Setlist; sl->name; sl++) {
187727178Sminshall 	    doset(sl);
187827178Sminshall 	}
187927178Sminshall     } else {
188027178Sminshall 	int i;
188127178Sminshall 
188227178Sminshall 	for (i = 1; i < argc; i++) {
188327178Sminshall 	    sl = getset(argv[i]);
188427178Sminshall 	    tl = gettoggle(argv[i]);
188527186Sminshall 	    if ((sl == Ambiguous(struct setlist *)) ||
188627186Sminshall 				(tl == Ambiguous(struct togglelist *))) {
188727178Sminshall 		printf("?Ambiguous argument '%s'.\n", argv[i]);
188827261Sminshall 		return 0;
188927178Sminshall 	    } else if (!sl && !tl) {
189027178Sminshall 		printf("?Unknown argument '%s'.\n", argv[i]);
189127261Sminshall 		return 0;
189227178Sminshall 	    } else {
189327186Sminshall 		if (tl) {
189427186Sminshall 		    dotog(tl);
189527186Sminshall 		}
189627186Sminshall 		if (sl) {
189727186Sminshall 		    doset(sl);
189827186Sminshall 		}
189927178Sminshall 	    }
190027178Sminshall 	}
190127178Sminshall     }
190227261Sminshall     return 1;
190327178Sminshall #undef	doset(sl)
190427178Sminshall #undef	dotog(tl)
190527178Sminshall }
190627178Sminshall 
190727178Sminshall /*
190827088Sminshall  * The following are the data structures, and many of the routines,
190927088Sminshall  * relating to command processing.
191027088Sminshall  */
191127088Sminshall 
191227088Sminshall /*
191327088Sminshall  * Set the escape character.
191427088Sminshall  */
191527088Sminshall setescape(argc, argv)
191627088Sminshall 	int argc;
191727088Sminshall 	char *argv[];
191827088Sminshall {
191927088Sminshall 	register char *arg;
192027088Sminshall 	char buf[50];
192127088Sminshall 
192227186Sminshall 	printf(
192327186Sminshall 	    "Deprecated usage - please use 'set escape%s%s' in the future.\n",
192427186Sminshall 				(argc > 2)? " ":"", (argc > 2)? argv[1]: "");
192527088Sminshall 	if (argc > 2)
192627088Sminshall 		arg = argv[1];
192727088Sminshall 	else {
192827088Sminshall 		printf("new escape character: ");
192927088Sminshall 		gets(buf);
193027088Sminshall 		arg = buf;
193127088Sminshall 	}
193227088Sminshall 	if (arg[0] != '\0')
193327088Sminshall 		escape = arg[0];
193427088Sminshall 	printf("Escape character is '%s'.\n", control(escape));
193527088Sminshall 	fflush(stdout);
193627261Sminshall 	return 1;
193727088Sminshall }
193827088Sminshall 
193927088Sminshall /*VARARGS*/
194027261Sminshall togcrmod()
194127261Sminshall {
194227261Sminshall     crmod = !crmod;
194327261Sminshall     printf("Deprecated usage - please use 'toggle crmod' in the future.\n");
194427261Sminshall     printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't");
194527261Sminshall     fflush(stdout);
194627261Sminshall     return 1;
194727261Sminshall }
194827261Sminshall 
194927261Sminshall /*VARARGS*/
195027088Sminshall suspend()
195127088Sminshall {
195227110Sminshall 	setcommandmode();
195327088Sminshall 	kill(0, SIGTSTP);
195427088Sminshall 	/* reget parameters in case they were changed */
195527088Sminshall 	ioctl(0, TIOCGETP, (char *)&ottyb);
195627088Sminshall 	ioctl(0, TIOCGETC, (char *)&otc);
195727088Sminshall 	ioctl(0, TIOCGLTC, (char *)&oltc);
195827261Sminshall 	return 1;
195927088Sminshall }
196027088Sminshall 
196127088Sminshall /*VARARGS*/
196227088Sminshall bye()
196327088Sminshall {
196427088Sminshall 	register char *op;
196527088Sminshall 
196627088Sminshall 	if (connected) {
196727088Sminshall 		shutdown(net, 2);
196827088Sminshall 		printf("Connection closed.\n");
196927088Sminshall 		close(net);
197027088Sminshall 		connected = 0;
197127088Sminshall 		/* reset his options */
197227088Sminshall 		for (op = hisopts; op < &hisopts[256]; op++)
197327088Sminshall 			*op = 0;
197427088Sminshall 	}
197527261Sminshall 	return 1;
197627088Sminshall }
197727088Sminshall 
197827088Sminshall /*VARARGS*/
197927088Sminshall quit()
198027088Sminshall {
198127261Sminshall 	(void) call(bye, "bye", 0);
198227088Sminshall 	exit(0);
198327261Sminshall 	/*NOTREACHED*/
198427088Sminshall }
198527088Sminshall 
198627088Sminshall /*
198727088Sminshall  * Print status about the connection.
198827088Sminshall  */
198927186Sminshall /*ARGSUSED*/
199027178Sminshall status(argc, argv)
199127178Sminshall int	argc;
199227178Sminshall char	*argv[];
199327088Sminshall {
199427178Sminshall     if (connected) {
199527178Sminshall 	printf("Connected to %s.\n", hostname);
199627178Sminshall 	if (argc < 2) {
199727178Sminshall 	    printf("Operating in %s.\n", modedescriptions[getconnmode()]);
199827261Sminshall 	    if (localchars) {
199927178Sminshall 		printf("Catching signals locally.\n");
200027178Sminshall 	    }
200127110Sminshall 	}
200227178Sminshall     } else {
200327178Sminshall 	printf("No connection.\n");
200427178Sminshall     }
200527178Sminshall     printf("Escape character is '%s'.\n", control(escape));
200627178Sminshall     fflush(stdout);
200727261Sminshall     return 1;
200827088Sminshall }
200927088Sminshall 
201027088Sminshall tn(argc, argv)
201127088Sminshall 	int argc;
201227088Sminshall 	char *argv[];
201327088Sminshall {
201427088Sminshall 	register struct hostent *host = 0;
201527088Sminshall 
201627088Sminshall 	if (connected) {
201727088Sminshall 		printf("?Already connected to %s\n", hostname);
201827261Sminshall 		return 0;
201927088Sminshall 	}
202027088Sminshall 	if (argc < 2) {
202127186Sminshall 		(void) strcpy(line, "Connect ");
202227088Sminshall 		printf("(to) ");
202327088Sminshall 		gets(&line[strlen(line)]);
202427088Sminshall 		makeargv();
202527088Sminshall 		argc = margc;
202627088Sminshall 		argv = margv;
202727088Sminshall 	}
202827088Sminshall 	if (argc > 3) {
202927088Sminshall 		printf("usage: %s host-name [port]\n", argv[0]);
203027261Sminshall 		return 0;
203127088Sminshall 	}
203227088Sminshall 	sin.sin_addr.s_addr = inet_addr(argv[1]);
203327088Sminshall 	if (sin.sin_addr.s_addr != -1) {
203427088Sminshall 		sin.sin_family = AF_INET;
203527186Sminshall 		(void) strcpy(hnamebuf, argv[1]);
203627088Sminshall 		hostname = hnamebuf;
203727088Sminshall 	} else {
203827088Sminshall 		host = gethostbyname(argv[1]);
203927088Sminshall 		if (host) {
204027088Sminshall 			sin.sin_family = host->h_addrtype;
204127676Sminshall #ifndef	NOT43
204227088Sminshall 			bcopy(host->h_addr_list[0], (caddr_t)&sin.sin_addr,
204327088Sminshall 				host->h_length);
204427676Sminshall #else	NOT43
204527676Sminshall 			bcopy(host->h_addr, (caddr_t)&sin.sin_addr,
204627676Sminshall 				host->h_length);
204727676Sminshall #endif	NOT43
204827088Sminshall 			hostname = host->h_name;
204927088Sminshall 		} else {
205027088Sminshall 			printf("%s: unknown host\n", argv[1]);
205127261Sminshall 			return 0;
205227088Sminshall 		}
205327088Sminshall 	}
205427088Sminshall 	sin.sin_port = sp->s_port;
205527088Sminshall 	if (argc == 3) {
205627088Sminshall 		sin.sin_port = atoi(argv[2]);
205727186Sminshall 		if (sin.sin_port == 0) {
205827088Sminshall 			sp = getservbyname(argv[2], "tcp");
205927088Sminshall 			if (sp)
206027088Sminshall 				sin.sin_port = sp->s_port;
206127088Sminshall 			else {
206227088Sminshall 				printf("%s: bad port number\n", argv[2]);
206327261Sminshall 				return 0;
206427088Sminshall 			}
206527088Sminshall 		} else {
206627088Sminshall 			sin.sin_port = atoi(argv[2]);
206727088Sminshall 			sin.sin_port = htons(sin.sin_port);
206827088Sminshall 		}
206927088Sminshall 		telnetport = 0;
207027110Sminshall 	} else {
207127110Sminshall 		telnetport = 1;
207227088Sminshall 	}
207327088Sminshall 	signal(SIGINT, intr);
207427110Sminshall 	signal(SIGQUIT, intr2);
207527088Sminshall 	signal(SIGPIPE, deadpeer);
207627088Sminshall 	printf("Trying...\n");
207727088Sminshall 	do {
207827088Sminshall 		net = socket(AF_INET, SOCK_STREAM, 0);
207927088Sminshall 		if (net < 0) {
208027088Sminshall 			perror("telnet: socket");
208127261Sminshall 			return 0;
208227088Sminshall 		}
208327676Sminshall #ifndef	NOT43
208427186Sminshall 		if (debug &&
208527186Sminshall 				setsockopt(net, SOL_SOCKET, SO_DEBUG,
208627676Sminshall 					(char *)&debug, sizeof(debug)) < 0)
208727676Sminshall #else	NOT43
208827676Sminshall 		if (debug && setsockopt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
208927676Sminshall #endif	NOT43
209027088Sminshall 			perror("setsockopt (SO_DEBUG)");
209127676Sminshall 
209227186Sminshall 		if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
209327676Sminshall #ifndef	NOT43
209427088Sminshall 			if (host && host->h_addr_list[1]) {
209527088Sminshall 				int oerrno = errno;
209627088Sminshall 
209727088Sminshall 				fprintf(stderr,
209827088Sminshall 				    "telnet: connect to address %s: ",
209927088Sminshall 				    inet_ntoa(sin.sin_addr));
210027088Sminshall 				errno = oerrno;
210127186Sminshall 				perror((char *)0);
210227088Sminshall 				host->h_addr_list++;
210327088Sminshall 				bcopy(host->h_addr_list[0],
210427088Sminshall 				    (caddr_t)&sin.sin_addr, host->h_length);
210527088Sminshall 				fprintf(stderr, "Trying %s...\n",
210627088Sminshall 					inet_ntoa(sin.sin_addr));
210727088Sminshall 				(void) close(net);
210827088Sminshall 				continue;
210927088Sminshall 			}
211027676Sminshall #endif	NOT43
211127088Sminshall 			perror("telnet: connect");
211227088Sminshall 			signal(SIGINT, SIG_DFL);
211327261Sminshall 			signal(SIGQUIT, SIG_DFL);
211427261Sminshall 			return 0;
211527088Sminshall 		}
211627088Sminshall 		connected++;
211727088Sminshall 	} while (connected == 0);
211827178Sminshall 	call(status, "status", "notmuch", 0);
211927088Sminshall 	if (setjmp(peerdied) == 0)
212027088Sminshall 		telnet();
212127088Sminshall 	fprintf(stderr, "Connection closed by foreign host.\n");
212227088Sminshall 	exit(1);
212327261Sminshall 	/*NOTREACHED*/
212427088Sminshall }
212527088Sminshall 
212627088Sminshall 
212727088Sminshall #define HELPINDENT (sizeof ("connect"))
212827088Sminshall 
212927088Sminshall char	openhelp[] =	"connect to a site";
213027088Sminshall char	closehelp[] =	"close current connection";
213127088Sminshall char	quithelp[] =	"exit telnet";
213227088Sminshall char	zhelp[] =	"suspend telnet";
213327088Sminshall char	statushelp[] =	"print status information";
213427088Sminshall char	helphelp[] =	"print help information";
213527110Sminshall char	sendhelp[] =	"transmit special characters ('send ?' for more)";
213627178Sminshall char	sethelp[] = 	"set operating parameters ('set ?' for more)";
213727178Sminshall char	togglestring[] ="toggle operating parameters ('toggle ?' for more)";
213827178Sminshall char	displayhelp[] =	"display operating parameters";
213927178Sminshall char	modehelp[] =
214027178Sminshall 		"try to enter line-by-line or character-at-a-time mode";
214127088Sminshall 
214227088Sminshall int	help();
214327088Sminshall 
214427088Sminshall struct cmd cmdtab[] = {
214527261Sminshall 	{ "close",	closehelp,	bye,		1, 1 },
214627261Sminshall 	{ "display",	displayhelp,	display,	1, 0 },
214727261Sminshall 	{ "mode",	modehelp,	modecmd,	1, 1 },
214827110Sminshall 	{ "open",	openhelp,	tn,		1, 0 },
214927110Sminshall 	{ "quit",	quithelp,	quit,		1, 0 },
215027110Sminshall 	{ "send",	sendhelp,	sendcmd,	1, 1 },
215127178Sminshall 	{ "set",	sethelp,	setcmd,		1, 0 },
215227261Sminshall 	{ "status",	statushelp,	status,		1, 0 },
215327110Sminshall 	{ "toggle",	togglestring,	toggle,		1, 0 },
215427261Sminshall 	{ "z",		zhelp,		suspend,	1, 0 },
215527110Sminshall 	{ "?",		helphelp,	help,		1, 0 },
215627261Sminshall 	0
215727261Sminshall };
215827261Sminshall 
215927261Sminshall char	crmodhelp[] =	"deprecated command -- use 'toggle crmod' instead";
216027261Sminshall char	escapehelp[] =	"deprecated command -- use 'set escape' instead";
216127261Sminshall 
216227261Sminshall struct cmd cmdtab2[] = {
216327110Sminshall 	{ "help",	helphelp,	help,		0, 0 },
216427261Sminshall 	{ "escape",	escapehelp,	setescape,	1, 0 },
216527261Sminshall 	{ "crmod",	crmodhelp,	togcrmod,	1, 0 },
216627088Sminshall 	0
216727088Sminshall };
216827088Sminshall 
216927088Sminshall /*
217027088Sminshall  * Help command.
217127088Sminshall  */
217227088Sminshall help(argc, argv)
217327088Sminshall 	int argc;
217427088Sminshall 	char *argv[];
217527088Sminshall {
217627088Sminshall 	register struct cmd *c;
217727088Sminshall 
217827088Sminshall 	if (argc == 1) {
217927088Sminshall 		printf("Commands may be abbreviated.  Commands are:\n\n");
218027088Sminshall 		for (c = cmdtab; c->name; c++)
218127088Sminshall 			if (c->dohelp) {
218227088Sminshall 				printf("%-*s\t%s\n", HELPINDENT, c->name,
218327088Sminshall 								    c->help);
218427088Sminshall 			}
218527261Sminshall 		return 0;
218627088Sminshall 	}
218727088Sminshall 	while (--argc > 0) {
218827088Sminshall 		register char *arg;
218927088Sminshall 		arg = *++argv;
219027088Sminshall 		c = getcmd(arg);
219127186Sminshall 		if (c == Ambiguous(struct cmd *))
219227088Sminshall 			printf("?Ambiguous help command %s\n", arg);
219327088Sminshall 		else if (c == (struct cmd *)0)
219427088Sminshall 			printf("?Invalid help command %s\n", arg);
219527088Sminshall 		else
219627088Sminshall 			printf("%s\n", c->help);
219727088Sminshall 	}
219827261Sminshall 	return 0;
219927088Sminshall }
220027088Sminshall /*
220127088Sminshall  * Call routine with argc, argv set from args (terminated by 0).
220227088Sminshall  * VARARGS2
220327088Sminshall  */
220427088Sminshall call(routine, args)
220527088Sminshall 	int (*routine)();
220627186Sminshall 	char *args;
220727088Sminshall {
220827186Sminshall 	register char **argp;
220927088Sminshall 	register int argc;
221027088Sminshall 
221127088Sminshall 	for (argc = 0, argp = &args; *argp++ != 0; argc++)
221227088Sminshall 		;
221327261Sminshall 	return (*routine)(argc, &args);
221427088Sminshall }
221527088Sminshall 
221627088Sminshall makeargv()
221727088Sminshall {
221827088Sminshall 	register char *cp;
221927088Sminshall 	register char **argp = margv;
222027088Sminshall 
222127088Sminshall 	margc = 0;
222227088Sminshall 	for (cp = line; *cp;) {
222327088Sminshall 		while (isspace(*cp))
222427088Sminshall 			cp++;
222527088Sminshall 		if (*cp == '\0')
222627088Sminshall 			break;
222727088Sminshall 		*argp++ = cp;
222827088Sminshall 		margc += 1;
222927088Sminshall 		while (*cp != '\0' && !isspace(*cp))
223027088Sminshall 			cp++;
223127088Sminshall 		if (*cp == '\0')
223227088Sminshall 			break;
223327088Sminshall 		*cp++ = '\0';
223427088Sminshall 	}
223527088Sminshall 	*argp++ = 0;
223627088Sminshall }
223727088Sminshall 
223827088Sminshall char **
223927088Sminshall getnextcmd(name)
224027088Sminshall char *name;
224127088Sminshall {
224227088Sminshall     struct cmd *c = (struct cmd *) name;
224327088Sminshall 
224427088Sminshall     return (char **) (c+1);
224527088Sminshall }
224627088Sminshall 
224727088Sminshall struct cmd *
224827088Sminshall getcmd(name)
224927088Sminshall char *name;
225027088Sminshall {
225127261Sminshall     struct cmd *cm;
225227261Sminshall 
225327261Sminshall     if (cm = (struct cmd *) genget(name, (char **) cmdtab, getnextcmd)) {
225427261Sminshall 	return cm;
225527261Sminshall     } else {
225627261Sminshall 	return (struct cmd *) genget(name, (char **) cmdtab2, getnextcmd);
225727261Sminshall     }
225827088Sminshall }
225927088Sminshall 
226027088Sminshall command(top)
226127088Sminshall 	int top;
226227088Sminshall {
226327088Sminshall 	register struct cmd *c;
226427088Sminshall 
226527110Sminshall 	setcommandmode();
226627261Sminshall 	if (!top) {
226727088Sminshall 		putchar('\n');
226827261Sminshall 	} else {
226927088Sminshall 		signal(SIGINT, SIG_DFL);
227027261Sminshall 		signal(SIGQUIT, SIG_DFL);
227127261Sminshall 	}
227227088Sminshall 	for (;;) {
227327088Sminshall 		printf("%s> ", prompt);
227427088Sminshall 		if (gets(line) == 0) {
227527088Sminshall 			if (feof(stdin))
227627088Sminshall 				quit();
227727088Sminshall 			break;
227827088Sminshall 		}
227927088Sminshall 		if (line[0] == 0)
228027088Sminshall 			break;
228127088Sminshall 		makeargv();
228227088Sminshall 		c = getcmd(margv[0]);
228327186Sminshall 		if (c == Ambiguous(struct cmd *)) {
228427088Sminshall 			printf("?Ambiguous command\n");
228527088Sminshall 			continue;
228627088Sminshall 		}
228727088Sminshall 		if (c == 0) {
228827088Sminshall 			printf("?Invalid command\n");
228927088Sminshall 			continue;
229027088Sminshall 		}
229127088Sminshall 		if (c->needconnect && !connected) {
229227088Sminshall 			printf("?Need to be connected first.\n");
229327088Sminshall 			continue;
229427088Sminshall 		}
229527261Sminshall 		if ((*c->handler)(margc, margv)) {
229627088Sminshall 			break;
229727261Sminshall 		}
229827088Sminshall 	}
229927088Sminshall 	if (!top) {
230027110Sminshall 		if (!connected) {
230127088Sminshall 			longjmp(toplevel, 1);
230227110Sminshall 			/*NOTREACHED*/
230327110Sminshall 		}
230427110Sminshall 		setconnmode();
230527088Sminshall 	}
230627088Sminshall }
230727186Sminshall 
230827186Sminshall /*
230927186Sminshall  * main.  Parse arguments, invoke the protocol or command parser.
231027186Sminshall  */
231127186Sminshall 
231227186Sminshall 
231327186Sminshall main(argc, argv)
231427186Sminshall 	int argc;
231527186Sminshall 	char *argv[];
231627186Sminshall {
231727186Sminshall 	sp = getservbyname("telnet", "tcp");
231827186Sminshall 	if (sp == 0) {
231927186Sminshall 		fprintf(stderr, "telnet: tcp/telnet: unknown service\n");
232027186Sminshall 		exit(1);
232127186Sminshall 	}
232227186Sminshall 	NetTrace = stdout;
232327186Sminshall 	ioctl(0, TIOCGETP, (char *)&ottyb);
232427186Sminshall 	ioctl(0, TIOCGETC, (char *)&otc);
232527186Sminshall 	ioctl(0, TIOCGLTC, (char *)&oltc);
232627228Sminshall #if	defined(LNOFLSH)
232727228Sminshall 	ioctl(0, TIOCLGET, (char *)&autoflush);
232827261Sminshall 	autoflush = !(autoflush&LNOFLSH);	/* if LNOFLSH, no autoflush */
232927261Sminshall #else	/* LNOFLSH */
233027261Sminshall 	autoflush = 1;
233127228Sminshall #endif	/* LNOFLSH */
233227186Sminshall 	ntc = otc;
233327228Sminshall 	nltc = oltc;
233427186Sminshall 	nttyb = ottyb;
233527186Sminshall 	setbuf(stdin, (char *)0);
233627186Sminshall 	setbuf(stdout, (char *)0);
233727186Sminshall 	prompt = argv[0];
233827186Sminshall 	if (argc > 1 && !strcmp(argv[1], "-d")) {
233927186Sminshall 		debug = 1;
234027186Sminshall 		argv++;
234127186Sminshall 		argc--;
234227186Sminshall 	}
234327186Sminshall 	if (argc > 1 && !strcmp(argv[1], "-n")) {
234427186Sminshall 	    argv++;
234527186Sminshall 	    argc--;
234627186Sminshall 	    if (argc > 1) {		/* get file name */
234727186Sminshall 		NetTrace = fopen(argv[1], "w");
234827186Sminshall 		argv++;
234927186Sminshall 		argc--;
235027186Sminshall 		if (NetTrace == NULL) {
235127186Sminshall 		    NetTrace = stdout;
235227186Sminshall 		}
235327186Sminshall 	    }
235427186Sminshall 	}
235527186Sminshall 	if (argc != 1) {
235627186Sminshall 		if (setjmp(toplevel) != 0)
235727186Sminshall 			exit(0);
235827186Sminshall 		tn(argc, argv);
235927186Sminshall 	}
236027186Sminshall 	setjmp(toplevel);
236127186Sminshall 	for (;;)
236227186Sminshall 		command(1);
236327186Sminshall }
2364