xref: /csrg-svn/usr.bin/telnet/telnet.c (revision 10603)
1*10603Ssam static char sccsid[] = "@(#)telnet.c	4.17 (Berkeley) 01/23/83";
26000Sroot /*
36000Sroot  * User telnet program.
46000Sroot  */
59217Ssam #include <sys/types.h>
69217Ssam #include <sys/socket.h>
79972Ssam #include <sys/ioctl.h>
89217Ssam 
99217Ssam #include <netinet/in.h>
109217Ssam 
116000Sroot #include <stdio.h>
126000Sroot #include <ctype.h>
136000Sroot #include <errno.h>
146000Sroot #include <signal.h>
156000Sroot #include <setjmp.h>
168345Ssam #include <netdb.h>
179217Ssam 
186024Ssam #define	TELOPTS
196000Sroot #include "telnet.h"
206000Sroot 
216000Sroot #define	strip(x)	((x)&0177)
226000Sroot 
236000Sroot char	ttyobuf[BUFSIZ], *tfrontp = ttyobuf, *tbackp = ttyobuf;
248378Ssam char	netobuf[BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf;
256000Sroot 
266000Sroot char	hisopts[256];
276000Sroot char	myopts[256];
286000Sroot 
296000Sroot char	doopt[] = { IAC, DO, '%', 'c', 0 };
306000Sroot char	dont[] = { IAC, DONT, '%', 'c', 0 };
316000Sroot char	will[] = { IAC, WILL, '%', 'c', 0 };
326000Sroot char	wont[] = { IAC, WONT, '%', 'c', 0 };
336000Sroot 
346000Sroot int	connected;
356000Sroot int	net;
369972Ssam int	showoptions = 0;
377377Sfeldman int	options;
3810339Ssam int	debug = 0;
399972Ssam int	crmod = 0;
406000Sroot char	*prompt;
419972Ssam char	escape = CTRL(]);
426000Sroot 
436000Sroot char	line[200];
446000Sroot int	margc;
456000Sroot char	*margv[20];
466000Sroot 
476000Sroot jmp_buf	toplevel;
486000Sroot jmp_buf	peerdied;
496000Sroot 
506000Sroot extern	int errno;
516000Sroot 
526000Sroot int	tn(), quit(), suspend(), bye(), help();
536024Ssam int	setescape(), status(), toggle(), setoptions();
54*10603Ssam int	setcrmod(), setdebug();
556000Sroot 
568378Ssam #define HELPINDENT (sizeof ("connect"))
576000Sroot 
586000Sroot struct cmd {
596000Sroot 	char	*name;
606000Sroot 	char	*help;
616000Sroot 	int	(*handler)();
626000Sroot };
636000Sroot 
646000Sroot char	ohelp[] = "connect to a site";
656000Sroot char	chelp[] = "close current connection";
666000Sroot char	qhelp[] = "exit telnet";
676000Sroot char	zhelp[] = "suspend telnet";
6810339Ssam char	dhelp[] = "toggle debugging";
696000Sroot char	ehelp[] = "set escape character";
706000Sroot char	shelp[] = "print status information";
716000Sroot char	hhelp[] = "print help information";
726024Ssam char	phelp[] = "toggle viewing of options processing";
739972Ssam char	rhelp[] = "toggle mapping of received carriage returns";
746000Sroot 
756000Sroot struct cmd cmdtab[] = {
766000Sroot 	{ "open",	ohelp,		tn },
776000Sroot 	{ "close",	chelp,		bye },
786000Sroot 	{ "quit",	qhelp,		quit },
796000Sroot 	{ "z",		zhelp,		suspend },
806000Sroot 	{ "escape",	ehelp,		setescape },
816000Sroot 	{ "status",	shelp,		status },
826024Ssam 	{ "options",	phelp,		setoptions },
839972Ssam 	{ "crmod",	rhelp,		setcrmod },
8410339Ssam 	{ "debug",	dhelp,		setdebug },
856000Sroot 	{ "?",		hhelp,		help },
866000Sroot 	0
876000Sroot };
886000Sroot 
899972Ssam struct sockaddr_in sin;
906000Sroot 
916000Sroot int	intr(), deadpeer();
926000Sroot char	*control();
936000Sroot struct	cmd *getcmd();
948345Ssam struct	servent *sp;
956000Sroot 
969972Ssam struct	ttychars otc;
979972Ssam int	oflags;
988378Ssam 
996000Sroot main(argc, argv)
1006000Sroot 	int argc;
1016000Sroot 	char *argv[];
1026000Sroot {
1038345Ssam 	sp = getservbyname("telnet", "tcp");
1048345Ssam 	if (sp == 0) {
1058345Ssam 		fprintf(stderr, "telnet: tcp/telnet: unknown service\n");
1068345Ssam 		exit(1);
1078345Ssam 	}
1089972Ssam 	ioctl(0, TIOCGET, (char *)&oflags);
1099972Ssam 	ioctl(0, TIOCCGET, (char *)&otc);
1106000Sroot 	setbuf(stdin, 0);
1116000Sroot 	setbuf(stdout, 0);
1126000Sroot 	prompt = argv[0];
1137377Sfeldman 	if (argc > 1 && !strcmp(argv[1], "-d"))
1147377Sfeldman 		options = SO_DEBUG, argv++, argc--;
1156000Sroot 	if (argc != 1) {
1166000Sroot 		if (setjmp(toplevel) != 0)
1176000Sroot 			exit(0);
1186000Sroot 		tn(argc, argv);
1196000Sroot 	}
1206000Sroot 	setjmp(toplevel);
1216000Sroot 	for (;;)
1226000Sroot 		command(1);
1236000Sroot }
1246000Sroot 
1258377Ssam char	*hostname;
1268377Ssam char	hnamebuf[32];
1276000Sroot 
1286000Sroot tn(argc, argv)
1296000Sroot 	int argc;
1306000Sroot 	char *argv[];
1316000Sroot {
1326000Sroot 	register int c;
1338377Ssam 	register struct hostent *host;
1346000Sroot 
1356000Sroot 	if (connected) {
1368377Ssam 		printf("?Already connected to %s\n", hostname);
1376000Sroot 		return;
1386000Sroot 	}
1396000Sroot 	if (argc < 2) {
1406000Sroot 		strcpy(line, "Connect ");
1416000Sroot 		printf("(to) ");
1426000Sroot 		gets(&line[strlen(line)]);
1436000Sroot 		makeargv();
1446000Sroot 		argc = margc;
1456000Sroot 		argv = margv;
1466000Sroot 	}
1476000Sroot 	if (argc > 3) {
1486000Sroot 		printf("usage: %s host-name [port]\n", argv[0]);
1496000Sroot 		return;
1506000Sroot 	}
1518345Ssam 	host = gethostbyname(argv[1]);
1528377Ssam 	if (host) {
1539217Ssam 		sin.sin_family = host->h_addrtype;
1549217Ssam 		bcopy(host->h_addr, (caddr_t)&sin.sin_addr, host->h_length);
1558377Ssam 		hostname = host->h_name;
1568377Ssam 	} else {
1579217Ssam 		sin.sin_family = AF_INET;
1588377Ssam 		sin.sin_addr.s_addr = inet_addr(argv[1]);
1598377Ssam 		if (sin.sin_addr.s_addr == -1) {
1608377Ssam 			printf("%s: unknown host\n", argv[1]);
1618377Ssam 			return;
1628377Ssam 		}
1638377Ssam 		strcpy(hnamebuf, argv[1]);
1648377Ssam 		hostname = hnamebuf;
1656000Sroot 	}
1668345Ssam 	sin.sin_port = sp->s_port;
1676024Ssam 	if (argc == 3) {
1686024Ssam 		sin.sin_port = atoi(argv[2]);
1696024Ssam 		if (sin.sin_port < 0) {
1706024Ssam 			printf("%s: bad port number\n", argv[2]);
1716024Ssam 			return;
1726024Ssam 		}
1739968Ssam 		sin.sin_port = htons(sin.sin_port);
1746024Ssam 	}
1759287Ssam 	net = socket(AF_INET, SOCK_STREAM, 0, 0);
1769217Ssam 	if (net < 0) {
1779217Ssam 		perror("telnet: socket");
1786000Sroot 		return;
1796000Sroot 	}
18010339Ssam 	if (debug)
18110339Ssam 		if (setsockopt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
18210339Ssam 			perror("telnet: setsockopt");
1836000Sroot 	sigset(SIGINT, intr);
1846000Sroot 	sigset(SIGPIPE, deadpeer);
1856000Sroot 	printf("Trying...\n");
1869217Ssam 	if (connect(net, (caddr_t)&sin, sizeof (sin), 0) < 0) {
1879217Ssam 		perror("telnet: connect");
1886000Sroot 		sigset(SIGINT, SIG_DFL);
1896000Sroot 		return;
1906000Sroot 	}
1916000Sroot 	connected++;
1926000Sroot 	call(status, "status", 0);
1936000Sroot 	if (setjmp(peerdied) == 0)
1946000Sroot 		telnet(net);
1956000Sroot 	fprintf(stderr, "Connection closed by foreign host.\n");
1966000Sroot 	exit(1);
1976000Sroot }
1986000Sroot 
1996000Sroot /*
2006000Sroot  * Print status about the connection.
2016000Sroot  */
2026000Sroot /*VARARGS*/
2036000Sroot status()
2046000Sroot {
2056000Sroot 	if (connected)
2068377Ssam 		printf("Connected to %s.\n", hostname);
2076000Sroot 	else
2086000Sroot 		printf("No connection.\n");
2096000Sroot 	printf("Escape character is '%s'.\n", control(escape));
2109972Ssam 	fflush(stdout);
2116000Sroot }
2126000Sroot 
2136000Sroot makeargv()
2146000Sroot {
2156000Sroot 	register char *cp;
2166000Sroot 	register char **argp = margv;
2176000Sroot 
2186000Sroot 	margc = 0;
2196000Sroot 	for (cp = line; *cp;) {
2206000Sroot 		while (isspace(*cp))
2216000Sroot 			cp++;
2226000Sroot 		if (*cp == '\0')
2236000Sroot 			break;
2246000Sroot 		*argp++ = cp;
2256000Sroot 		margc += 1;
2266000Sroot 		while (*cp != '\0' && !isspace(*cp))
2276000Sroot 			cp++;
2286000Sroot 		if (*cp == '\0')
2296000Sroot 			break;
2306000Sroot 		*cp++ = '\0';
2316000Sroot 	}
2326000Sroot 	*argp++ = 0;
2336000Sroot }
2346000Sroot 
2356000Sroot /*VARARGS*/
2366000Sroot suspend()
2376000Sroot {
2386000Sroot 	register int save;
2396000Sroot 
2406000Sroot 	save = mode(0);
2418378Ssam 	kill(0, SIGTSTP);
2428378Ssam 	/* reget parameters in case they were changed */
2439972Ssam 	ioctl(0, TIOCGET, (char *)&oflags);
2449972Ssam 	ioctl(0, TIOCCGET, (char *)&otc);
2458378Ssam 	(void) mode(save);
2466000Sroot }
2476000Sroot 
2486000Sroot /*VARARGS*/
2496000Sroot bye()
2506000Sroot {
2516000Sroot 	int how = 2;
2528378Ssam 	register char *op;
2536000Sroot 
2548378Ssam 	(void) mode(0);
2556000Sroot 	if (connected) {
2566000Sroot 		ioctl(net, SIOCDONE, &how);
2576000Sroot 		printf("Connection closed.\n");
2586000Sroot 		close(net);
2596000Sroot 		connected = 0;
2608378Ssam 		/* reset his options */
2618378Ssam 		for (op = hisopts; op < &hisopts[256]; op++)
2628378Ssam 			*op = 0;
2636000Sroot 	}
2646000Sroot }
2656000Sroot 
2666000Sroot /*VARARGS*/
2676000Sroot quit()
2686000Sroot {
2696000Sroot 	call(bye, "bye", 0);
2706000Sroot 	exit(0);
2716000Sroot }
2726000Sroot 
2736000Sroot /*
2746000Sroot  * Help command.
2756000Sroot  * Call each command handler with argc == 0 and argv[0] == name.
2766000Sroot  */
2776000Sroot help(argc, argv)
2786000Sroot 	int argc;
2796000Sroot 	char *argv[];
2806000Sroot {
2816000Sroot 	register struct cmd *c;
2826000Sroot 
2836000Sroot 	if (argc == 1) {
2846000Sroot 		printf("Commands may be abbreviated.  Commands are:\n\n");
2856000Sroot 		for (c = cmdtab; c->name; c++)
2866000Sroot 			printf("%-*s\t%s\n", HELPINDENT, c->name, c->help);
2876000Sroot 		return;
2886000Sroot 	}
2896000Sroot 	while (--argc > 0) {
2906000Sroot 		register char *arg;
2916000Sroot 		arg = *++argv;
2926000Sroot 		c = getcmd(arg);
2936000Sroot 		if (c == (struct cmd *)-1)
2946000Sroot 			printf("?Ambiguous help command %s\n", arg);
2956000Sroot 		else if (c == (struct cmd *)0)
2966000Sroot 			printf("?Invalid help command %s\n", arg);
2976000Sroot 		else
2986000Sroot 			printf("%s\n", c->help);
2996000Sroot 	}
3006000Sroot }
3016000Sroot 
3026000Sroot /*
3036000Sroot  * Call routine with argc, argv set from args (terminated by 0).
3046000Sroot  * VARARGS2
3056000Sroot  */
3066000Sroot call(routine, args)
3076000Sroot 	int (*routine)();
3086000Sroot 	int args;
3096000Sroot {
3106000Sroot 	register int *argp;
3116000Sroot 	register int argc;
3126000Sroot 
3136000Sroot 	for (argc = 0, argp = &args; *argp++ != 0; argc++)
3146000Sroot 		;
3156000Sroot 	(*routine)(argc, &args);
3166000Sroot }
3176000Sroot 
3189972Ssam struct	ttychars notc = {
3199972Ssam 	-1,	-1,	-1,	-1,	-1,
3209972Ssam 	-1,	-1,	-1,	-1,	-1,
3219972Ssam 	-1,	-1,	-1,	-1
3229972Ssam };
3239972Ssam 
3246000Sroot mode(f)
3256000Sroot 	register int f;
3266000Sroot {
3278378Ssam 	static int prevmode = 0;
3289972Ssam 	struct ttychars *tc;
3299972Ssam 	int onoff, old, flags;
3306000Sroot 
3318378Ssam 	if (prevmode == f)
3328378Ssam 		return (f);
3338378Ssam 	old = prevmode;
3348378Ssam 	prevmode = f;
3359972Ssam 	flags = oflags;
3366000Sroot 	switch (f) {
3378378Ssam 
3386000Sroot 	case 0:
3396000Sroot 		onoff = 0;
3409972Ssam 		tc = &otc;
3416000Sroot 		break;
3426000Sroot 
3436000Sroot 	case 1:
3446000Sroot 	case 2:
3459972Ssam 		flags |= CBREAK;
3468378Ssam 		if (f == 1)
3479972Ssam 			flags &= ~(ECHO|CRMOD);
3488378Ssam 		else
3499972Ssam 			flags |= ECHO|CRMOD;
3509972Ssam 		tc = &notc;
3516000Sroot 		onoff = 1;
3529972Ssam 		break;
3539972Ssam 
3549972Ssam 	default:
3559972Ssam 		return;
3566000Sroot 	}
3579972Ssam 	ioctl(fileno(stdin), TIOCCSET, (char *)tc);
3589972Ssam 	ioctl(fileno(stdin), TIOCSET, (char *)&flags);
3596000Sroot 	ioctl(fileno(stdin), FIONBIO, &onoff);
3606000Sroot 	ioctl(fileno(stdout), FIONBIO, &onoff);
3616000Sroot 	return (old);
3626000Sroot }
3636000Sroot 
3646000Sroot char	sibuf[BUFSIZ], *sbp;
3656000Sroot char	tibuf[BUFSIZ], *tbp;
3666000Sroot int	scc, tcc;
3676000Sroot 
3686000Sroot /*
3696000Sroot  * Select from tty and network...
3706000Sroot  */
3716000Sroot telnet(s)
3726000Sroot 	int s;
3736000Sroot {
3746000Sroot 	register int c;
3756000Sroot 	int tin = fileno(stdin), tout = fileno(stdout);
3766000Sroot 	int on = 1;
3776000Sroot 
3788378Ssam 	(void) mode(2);
3796000Sroot 	ioctl(s, FIONBIO, &on);
3806000Sroot 	for (;;) {
3816000Sroot 		int ibits = 0, obits = 0;
3826000Sroot 
3836000Sroot 		if (nfrontp - nbackp)
3846000Sroot 			obits |= (1 << s);
3856000Sroot 		else
3866000Sroot 			ibits |= (1 << tin);
3876000Sroot 		if (tfrontp - tbackp)
3886000Sroot 			obits |= (1 << tout);
3896000Sroot 		else
3906000Sroot 			ibits |= (1 << s);
3916000Sroot 		if (scc < 0 && tcc < 0)
3926000Sroot 			break;
3939217Ssam 		select(16, &ibits, &obits, 0, 0);
3946000Sroot 		if (ibits == 0 && obits == 0) {
3956000Sroot 			sleep(5);
3966000Sroot 			continue;
3976000Sroot 		}
3986000Sroot 
3996000Sroot 		/*
4006000Sroot 		 * Something to read from the network...
4016000Sroot 		 */
4026000Sroot 		if (ibits & (1 << s)) {
4038378Ssam 			scc = read(s, sibuf, sizeof (sibuf));
4046000Sroot 			if (scc < 0 && errno == EWOULDBLOCK)
4056000Sroot 				scc = 0;
4066000Sroot 			else {
4076000Sroot 				if (scc <= 0)
4086000Sroot 					break;
4096000Sroot 				sbp = sibuf;
4106000Sroot 			}
4116000Sroot 		}
4126000Sroot 
4136000Sroot 		/*
4146000Sroot 		 * Something to read from the tty...
4156000Sroot 		 */
4166000Sroot 		if (ibits & (1 << tin)) {
4178378Ssam 			tcc = read(tin, tibuf, sizeof (tibuf));
4186000Sroot 			if (tcc < 0 && errno == EWOULDBLOCK)
4196000Sroot 				tcc = 0;
4206000Sroot 			else {
4216000Sroot 				if (tcc <= 0)
4226000Sroot 					break;
4236000Sroot 				tbp = tibuf;
4246000Sroot 			}
4256000Sroot 		}
4266000Sroot 
4276000Sroot 		while (tcc > 0) {
4286000Sroot 			register int c;
4296000Sroot 
4306000Sroot 			if ((&netobuf[BUFSIZ] - nfrontp) < 2)
4316000Sroot 				break;
4326000Sroot 			c = *tbp++ & 0377, tcc--;
4336000Sroot 			if (strip(c) == escape) {
4346000Sroot 				command(0);
4356000Sroot 				tcc = 0;
4366000Sroot 				break;
4376000Sroot 			}
4386000Sroot 			*nfrontp++ = c;
4396000Sroot 		}
4406000Sroot 		if ((obits & (1 << s)) && (nfrontp - nbackp) > 0)
4416000Sroot 			netflush(s);
4426000Sroot 		if (scc > 0)
4436000Sroot 			telrcv();
4446000Sroot 		if ((obits & (1 << tout)) && (tfrontp - tbackp) > 0)
4456000Sroot 			ttyflush(tout);
4466000Sroot 	}
4478378Ssam 	(void) mode(0);
4486000Sroot }
4496000Sroot 
4506000Sroot command(top)
4516000Sroot 	int top;
4526000Sroot {
4536000Sroot 	register struct cmd *c;
4546000Sroot 	int oldmode, wasopen;
4556000Sroot 
4566000Sroot 	oldmode = mode(0);
4576000Sroot 	if (!top)
4586000Sroot 		putchar('\n');
4596000Sroot 	else
4606000Sroot 		sigset(SIGINT, SIG_DFL);
4616000Sroot 	for (;;) {
4626000Sroot 		printf("%s> ", prompt);
4636000Sroot 		if (gets(line) == 0)
4646000Sroot 			break;
4656000Sroot 		if (line[0] == 0)
4666000Sroot 			break;
4676000Sroot 		makeargv();
4686000Sroot 		c = getcmd(margv[0]);
4696000Sroot 		if (c == (struct cmd *)-1) {
4706000Sroot 			printf("?Ambiguous command\n");
4716000Sroot 			continue;
4726000Sroot 		}
4736000Sroot 		if (c == 0) {
4746000Sroot 			printf("?Invalid command\n");
4756000Sroot 			continue;
4766000Sroot 		}
4776000Sroot 		(*c->handler)(margc, margv);
4786000Sroot 		if (c->handler != help)
4796000Sroot 			break;
4806000Sroot 	}
4816000Sroot 	if (!top) {
4826000Sroot 		if (!connected)
4836000Sroot 			longjmp(toplevel, 1);
4848378Ssam 		(void) mode(oldmode);
4856000Sroot 	}
4866000Sroot }
4876000Sroot 
4886000Sroot /*
4896000Sroot  * Telnet receiver states for fsm
4906000Sroot  */
4916000Sroot #define	TS_DATA		0
4926000Sroot #define	TS_IAC		1
4936000Sroot #define	TS_WILL		2
4946000Sroot #define	TS_WONT		3
4956000Sroot #define	TS_DO		4
4966000Sroot #define	TS_DONT		5
4976000Sroot 
4986000Sroot telrcv()
4996000Sroot {
5006000Sroot 	register int c;
5016000Sroot 	static int state = TS_DATA;
5026000Sroot 
5036000Sroot 	while (scc > 0) {
5046000Sroot 		c = *sbp++ & 0377, scc--;
5056000Sroot 		switch (state) {
5066000Sroot 
5076000Sroot 		case TS_DATA:
5089972Ssam 			if (c == IAC) {
5096000Sroot 				state = TS_IAC;
5109972Ssam 				continue;
5119972Ssam 			}
5129972Ssam 			*tfrontp++ = c;
5139972Ssam 			/*
5149972Ssam 			 * This hack is needed since we can't set
5159972Ssam 			 * CRMOD on output only.  Machines like MULTICS
5169972Ssam 			 * like to send \r without \n; since we must
5179972Ssam 			 * turn off CRMOD to get proper input, the mapping
5189972Ssam 			 * is done here (sigh).
5199972Ssam 			 */
5209972Ssam 			if (c == '\r' && crmod)
5219972Ssam 				*tfrontp++ = '\n';
5226000Sroot 			continue;
5236000Sroot 
5246000Sroot 		case TS_IAC:
5256000Sroot 			switch (c) {
5266000Sroot 
5276000Sroot 			case WILL:
5286000Sroot 				state = TS_WILL;
5296000Sroot 				continue;
5306000Sroot 
5316000Sroot 			case WONT:
5326000Sroot 				state = TS_WONT;
5336000Sroot 				continue;
5346000Sroot 
5356000Sroot 			case DO:
5366000Sroot 				state = TS_DO;
5376000Sroot 				continue;
5386000Sroot 
5396000Sroot 			case DONT:
5406000Sroot 				state = TS_DONT;
5416000Sroot 				continue;
5426000Sroot 
5436000Sroot 			case DM:
5446000Sroot 				ioctl(fileno(stdout), TIOCFLUSH, 0);
5456000Sroot 				break;
5466000Sroot 
5476000Sroot 			case NOP:
5486000Sroot 			case GA:
5496000Sroot 				break;
5506000Sroot 
5516000Sroot 			default:
5526000Sroot 				break;
5536000Sroot 			}
5546000Sroot 			state = TS_DATA;
5556000Sroot 			continue;
5566000Sroot 
5576000Sroot 		case TS_WILL:
5588345Ssam 			printoption("RCVD", will, c, !hisopts[c]);
5596000Sroot 			if (!hisopts[c])
5606000Sroot 				willoption(c);
5616000Sroot 			state = TS_DATA;
5626000Sroot 			continue;
5636000Sroot 
5646000Sroot 		case TS_WONT:
5658345Ssam 			printoption("RCVD", wont, c, hisopts[c]);
5666000Sroot 			if (hisopts[c])
5676000Sroot 				wontoption(c);
5686000Sroot 			state = TS_DATA;
5696000Sroot 			continue;
5706000Sroot 
5716000Sroot 		case TS_DO:
5728345Ssam 			printoption("RCVD", doopt, c, !myopts[c]);
5736000Sroot 			if (!myopts[c])
5746000Sroot 				dooption(c);
5756000Sroot 			state = TS_DATA;
5766000Sroot 			continue;
5776000Sroot 
5786000Sroot 		case TS_DONT:
5798345Ssam 			printoption("RCVD", dont, c, myopts[c]);
5806000Sroot 			if (myopts[c]) {
5816000Sroot 				myopts[c] = 0;
5826000Sroot 				sprintf(nfrontp, wont, c);
5838378Ssam 				nfrontp += sizeof (wont) - 2;
5848345Ssam 				printoption("SENT", wont, c);
5856000Sroot 			}
5866000Sroot 			state = TS_DATA;
5876000Sroot 			continue;
5886000Sroot 		}
5896000Sroot 	}
5906000Sroot }
5916000Sroot 
5926000Sroot willoption(option)
5936000Sroot 	int option;
5946000Sroot {
5956000Sroot 	char *fmt;
5966000Sroot 
5976000Sroot 	switch (option) {
5986000Sroot 
5996000Sroot 	case TELOPT_ECHO:
6008378Ssam 		(void) mode(1);
6016000Sroot 
6026000Sroot 	case TELOPT_SGA:
6036000Sroot 		hisopts[option] = 1;
6046000Sroot 		fmt = doopt;
6056000Sroot 		break;
6066000Sroot 
6076000Sroot 	case TELOPT_TM:
6086000Sroot 		fmt = dont;
6096000Sroot 		break;
6106000Sroot 
6116000Sroot 	default:
6126000Sroot 		fmt = dont;
6136000Sroot 		break;
6146000Sroot 	}
6156024Ssam 	sprintf(nfrontp, fmt, option);
6168378Ssam 	nfrontp += sizeof (dont) - 2;
6178345Ssam 	printoption("SENT", fmt, option);
6186000Sroot }
6196000Sroot 
6206000Sroot wontoption(option)
6216000Sroot 	int option;
6226000Sroot {
6236000Sroot 	char *fmt;
6246000Sroot 
6256000Sroot 	switch (option) {
6266000Sroot 
6276000Sroot 	case TELOPT_ECHO:
6288378Ssam 		(void) mode(2);
6296000Sroot 
6306000Sroot 	case TELOPT_SGA:
6316000Sroot 		hisopts[option] = 0;
6326000Sroot 		fmt = dont;
6336000Sroot 		break;
6346000Sroot 
6356000Sroot 	default:
6366000Sroot 		fmt = dont;
6376000Sroot 	}
6386000Sroot 	sprintf(nfrontp, fmt, option);
6398378Ssam 	nfrontp += sizeof (doopt) - 2;
6408345Ssam 	printoption("SENT", fmt, option);
6416000Sroot }
6426000Sroot 
6436000Sroot dooption(option)
6446000Sroot 	int option;
6456000Sroot {
6466000Sroot 	char *fmt;
6476000Sroot 
6486000Sroot 	switch (option) {
6496000Sroot 
6506000Sroot 	case TELOPT_TM:
6516000Sroot 		fmt = wont;
6526000Sroot 		break;
6536000Sroot 
6546000Sroot 	case TELOPT_SGA:
6556000Sroot 		fmt = will;
6566000Sroot 		break;
6576000Sroot 
6586000Sroot 	default:
6596000Sroot 		fmt = wont;
6606000Sroot 		break;
6616000Sroot 	}
6626000Sroot 	sprintf(nfrontp, fmt, option);
6638378Ssam 	nfrontp += sizeof (doopt) - 2;
6648345Ssam 	printoption("SENT", fmt, option);
6656000Sroot }
6666000Sroot 
6676000Sroot /*
6686000Sroot  * Set the escape character.
6696000Sroot  */
6706000Sroot setescape(argc, argv)
6716000Sroot 	int argc;
6726000Sroot 	char *argv[];
6736000Sroot {
6746000Sroot 	register char *arg;
6756000Sroot 	char buf[50];
6766000Sroot 
6776000Sroot 	if (argc > 2)
6786000Sroot 		arg = argv[1];
6796000Sroot 	else {
6806000Sroot 		printf("new escape character: ");
6816000Sroot 		gets(buf);
6826000Sroot 		arg = buf;
6836000Sroot 	}
6846000Sroot 	if (arg[0] != '\0')
6856000Sroot 		escape = arg[0];
6866000Sroot 	printf("Escape character is '%s'.\n", control(escape));
6879972Ssam 	fflush(stdout);
6886000Sroot }
6896000Sroot 
6906024Ssam /*VARARGS*/
6916024Ssam setoptions()
6926024Ssam {
6939972Ssam 
6946024Ssam 	showoptions = !showoptions;
6956024Ssam 	printf("%s show option processing.\n", showoptions ? "Will" : "Wont");
6969972Ssam 	fflush(stdout);
6976024Ssam }
6986024Ssam 
6999972Ssam /*VARARGS*/
7009972Ssam setcrmod()
7019972Ssam {
7029972Ssam 
7039972Ssam 	crmod = !crmod;
7049972Ssam 	printf("%s map carriage return on output.\n", crmod ? "Will" : "Wont");
7059972Ssam 	fflush(stdout);
7069972Ssam }
7079972Ssam 
70810339Ssam /*VARARGS*/
70910339Ssam setdebug()
71010339Ssam {
71110339Ssam 
71210339Ssam 	debug = !debug;
71310339Ssam 	printf("%s turn on socket level debugging.\n",
71410339Ssam 		debug ? "Will" : "Wont");
71510339Ssam 	fflush(stdout);
71610339Ssam }
71710339Ssam 
7186000Sroot /*
7196000Sroot  * Construct a control character sequence
7206000Sroot  * for a special character.
7216000Sroot  */
7226000Sroot char *
7236000Sroot control(c)
7246000Sroot 	register int c;
7256000Sroot {
7266000Sroot 	static char buf[3];
7276000Sroot 
7286000Sroot 	if (c == 0177)
7296000Sroot 		return ("^?");
7306000Sroot 	if (c >= 040) {
7316000Sroot 		buf[0] = c;
7326000Sroot 		buf[1] = 0;
7336000Sroot 	} else {
7346000Sroot 		buf[0] = '^';
7356000Sroot 		buf[1] = '@'+c;
7366000Sroot 		buf[2] = 0;
7376000Sroot 	}
7386000Sroot 	return (buf);
7396000Sroot }
7406000Sroot 
7416000Sroot struct cmd *
7426000Sroot getcmd(name)
7436000Sroot 	register char *name;
7446000Sroot {
7456000Sroot 	register char *p, *q;
7466000Sroot 	register struct cmd *c, *found;
7476000Sroot 	register int nmatches, longest;
7486000Sroot 
7496000Sroot 	longest = 0;
7506000Sroot 	nmatches = 0;
7516000Sroot 	found = 0;
7526000Sroot 	for (c = cmdtab; p = c->name; c++) {
7536000Sroot 		for (q = name; *q == *p++; q++)
7546000Sroot 			if (*q == 0)		/* exact match? */
7556000Sroot 				return (c);
7566000Sroot 		if (!*q) {			/* the name was a prefix */
7576000Sroot 			if (q - name > longest) {
7586000Sroot 				longest = q - name;
7596000Sroot 				nmatches = 1;
7606000Sroot 				found = c;
7616000Sroot 			} else if (q - name == longest)
7626000Sroot 				nmatches++;
7636000Sroot 		}
7646000Sroot 	}
7656000Sroot 	if (nmatches > 1)
7666000Sroot 		return ((struct cmd *)-1);
7676000Sroot 	return (found);
7686000Sroot }
7696000Sroot 
7706000Sroot deadpeer()
7716000Sroot {
7726000Sroot 	sigset(SIGPIPE, deadpeer);
7738378Ssam 	(void) mode(0);
7746000Sroot 	longjmp(peerdied, -1);
7756000Sroot }
7766000Sroot 
7776000Sroot intr()
7786000Sroot {
7796000Sroot 	sigset(SIGINT, intr);
7808378Ssam 	(void) mode(0);
7816000Sroot 	longjmp(toplevel, -1);
7826000Sroot }
7836000Sroot 
7846000Sroot ttyflush(fd)
7856000Sroot {
7866000Sroot 	int n;
7876000Sroot 
7886000Sroot 	if ((n = tfrontp - tbackp) > 0)
7896000Sroot 		n = write(fd, tbackp, n);
7908345Ssam 	if (n < 0)
7918345Ssam 		return;
7926000Sroot 	tbackp += n;
7936000Sroot 	if (tbackp == tfrontp)
7946000Sroot 		tbackp = tfrontp = ttyobuf;
7956000Sroot }
7966000Sroot 
7976000Sroot netflush(fd)
7986000Sroot {
7996000Sroot 	int n;
8006000Sroot 
8016000Sroot 	if ((n = nfrontp - nbackp) > 0)
8026000Sroot 		n = write(fd, nbackp, n);
8036501Ssam 	if (n < 0) {
8046501Ssam 		if (errno != ENOBUFS && errno != EWOULDBLOCK) {
8058378Ssam 			(void) mode(0);
8068377Ssam 			perror(hostname);
8076501Ssam 			close(fd);
8086501Ssam 			longjmp(peerdied, -1);
8096501Ssam 			/*NOTREACHED*/
8106501Ssam 		}
8116000Sroot 		n = 0;
8126501Ssam 	}
8136000Sroot 	nbackp += n;
8146000Sroot 	if (nbackp == nfrontp)
8156000Sroot 		nbackp = nfrontp = netobuf;
8166000Sroot }
8176024Ssam 
8186293Sroot /*VARARGS*/
8196293Sroot printoption(direction, fmt, option, what)
8206024Ssam 	char *direction, *fmt;
8216293Sroot 	int option, what;
8226024Ssam {
8238345Ssam 	if (!showoptions)
8248345Ssam 		return;
8256024Ssam 	printf("%s ", direction);
8266024Ssam 	if (fmt == doopt)
8276024Ssam 		fmt = "do";
8286024Ssam 	else if (fmt == dont)
8296024Ssam 		fmt = "dont";
8306024Ssam 	else if (fmt == will)
8316024Ssam 		fmt = "will";
8326024Ssam 	else if (fmt == wont)
8336024Ssam 		fmt = "wont";
8346024Ssam 	else
8356024Ssam 		fmt = "???";
8366024Ssam 	if (option < TELOPT_SUPDUP)
8376293Sroot 		printf("%s %s", fmt, telopts[option]);
8386024Ssam 	else
8396293Sroot 		printf("%s %d", fmt, option);
8406293Sroot 	if (*direction == '<') {
8416293Sroot 		printf("\r\n");
8426293Sroot 		return;
8436293Sroot 	}
8446293Sroot 	printf(" (%s)\r\n", what ? "reply" : "don't reply");
8456024Ssam }
846