xref: /csrg-svn/usr.bin/telnet/telnet.c (revision 6025)
1*6025Ssam /*	telnet.c	4.3	82/03/01	*/
26000Sroot 
36000Sroot /*
46000Sroot  * User telnet program.
56000Sroot  */
66000Sroot #include <stdio.h>
76000Sroot #include <ctype.h>
86000Sroot #include <errno.h>
96000Sroot #include <signal.h>
106000Sroot #include <sgtty.h>
116000Sroot #include <setjmp.h>
126000Sroot #include <sys/types.h>
136000Sroot #include <sys/socket.h>
146000Sroot #include <net/in.h>
156024Ssam #define	TELOPTS
166000Sroot #include "telnet.h"
176000Sroot 
186000Sroot #define	ctrl(x)		((x) & 037)
196000Sroot #define	strip(x)	((x)&0177)
206000Sroot #define	INFINITY	10000000
216000Sroot #define	swab(x)		((((x) >> 8) | ((x) << 8)) & 0xffff)
226000Sroot 
236000Sroot char	ttyobuf[BUFSIZ], *tfrontp = ttyobuf, *tbackp = ttyobuf;
246000Sroot char	netobuf[BUFSIZ] =
256000Sroot 	{ IAC, DO, TELOPT_ECHO, IAC, DO, TELOPT_SGA,
266000Sroot 	  IAC, WONT, TELOPT_SGA },
276000Sroot 	*nfrontp = netobuf + 9, *nbackp = netobuf;
286000Sroot 
296000Sroot char	hisopts[256];
306000Sroot char	myopts[256];
316000Sroot 
326000Sroot char	doopt[] = { IAC, DO, '%', 'c', 0 };
336000Sroot char	dont[] = { IAC, DONT, '%', 'c', 0 };
346000Sroot char	will[] = { IAC, WILL, '%', 'c', 0 };
356000Sroot char	wont[] = { IAC, WONT, '%', 'c', 0 };
366000Sroot 
376000Sroot int	connected;
386000Sroot int	net;
396024Ssam int	showoptions;
406000Sroot char	*prompt;
416000Sroot 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();
546000Sroot 
556000Sroot #define HELPINDENT (sizeof("connect"))
566000Sroot 
576000Sroot struct cmd {
586000Sroot 	char	*name;
596000Sroot 	char	*help;
606000Sroot 	int	(*handler)();
616000Sroot };
626000Sroot 
636000Sroot char	ohelp[] = "connect to a site";
646000Sroot char	chelp[] = "close current connection";
656000Sroot char	qhelp[] = "exit telnet";
666000Sroot char	zhelp[] = "suspend telnet";
676000Sroot char	ehelp[] = "set escape character";
686000Sroot char	shelp[] = "print status information";
696000Sroot char	hhelp[] = "print help information";
706024Ssam char	phelp[] = "toggle viewing of options processing";
716000Sroot 
726000Sroot struct cmd cmdtab[] = {
736000Sroot 	{ "open",	ohelp,		tn },
746000Sroot 	{ "close",	chelp,		bye },
756000Sroot 	{ "quit",	qhelp,		quit },
766000Sroot 	{ "z",		zhelp,		suspend },
776000Sroot 	{ "escape",	ehelp,		setescape },
786000Sroot 	{ "status",	shelp,		status },
796024Ssam 	{ "options",	phelp,		setoptions },
806000Sroot 	{ "?",		hhelp,		help },
816000Sroot 	0
826000Sroot };
836000Sroot 
846000Sroot struct	sockaddr_in sin = { AF_INET, swab(IPPORT_TELNET) };
856000Sroot 
866000Sroot int	intr(), deadpeer();
876000Sroot char	*control();
886000Sroot struct	cmd *getcmd();
896000Sroot 
906000Sroot main(argc, argv)
916000Sroot 	int argc;
926000Sroot 	char *argv[];
936000Sroot {
946000Sroot 	setbuf(stdin, 0);
956000Sroot 	setbuf(stdout, 0);
966000Sroot 	prompt = argv[0];
976000Sroot 	if (argc != 1) {
986000Sroot 		if (setjmp(toplevel) != 0)
996000Sroot 			exit(0);
1006000Sroot 		tn(argc, argv);
1016000Sroot 	}
1026000Sroot 	setjmp(toplevel);
1036000Sroot 	for (;;)
1046000Sroot 		command(1);
1056000Sroot }
1066000Sroot 
1076000Sroot char host_name[100];
1086000Sroot 
1096000Sroot tn(argc, argv)
1106000Sroot 	int argc;
1116000Sroot 	char *argv[];
1126000Sroot {
1136000Sroot 	register int c;
1146000Sroot 
1156000Sroot 	if (connected) {
1166000Sroot 		printf("?Already connected to %s\n", host_name);
1176000Sroot 		return;
1186000Sroot 	}
1196000Sroot 	if (argc < 2) {
1206000Sroot 		strcpy(line, "Connect ");
1216000Sroot 		printf("(to) ");
1226000Sroot 		gets(&line[strlen(line)]);
1236000Sroot 		makeargv();
1246000Sroot 		argc = margc;
1256000Sroot 		argv = margv;
1266000Sroot 	}
1276000Sroot 	if (argc > 3) {
1286000Sroot 		printf("usage: %s host-name [port]\n", argv[0]);
1296000Sroot 		return;
1306000Sroot 	}
1316000Sroot 	sin.sin_addr.s_addr = rhost(&argv[1]);
132*6025Ssam 	if (sin.sin_addr.s_addr == (u_long)-1) {
1336000Sroot 		printf("%s: unknown host\n", argv[1]);
1346000Sroot 		return;
1356000Sroot 	}
1366024Ssam 	if (argc == 3) {
1376024Ssam 		sin.sin_port = atoi(argv[2]);
1386024Ssam 		if (sin.sin_port < 0) {
1396024Ssam 			printf("%s: bad port number\n", argv[2]);
1406024Ssam 			return;
1416024Ssam 		}
1426024Ssam 	}
1436000Sroot 	if ((net = socket(SOCK_STREAM, 0, 0, 0)) < 0) {
1446000Sroot 		perror("socket");
1456000Sroot 		return;
1466000Sroot 	}
1476000Sroot 	sigset(SIGINT, intr);
1486000Sroot 	sigset(SIGPIPE, deadpeer);
1496000Sroot 	printf("Trying...\n");
1506000Sroot 	if (connect(net, &sin)) {
1516000Sroot 		perror("connect");
1526000Sroot 		sigset(SIGINT, SIG_DFL);
1536000Sroot 		return;
1546000Sroot 	}
1556000Sroot 	strcpy(host_name, argv[1]);
1566000Sroot 	connected++;
1576000Sroot 	call(status, "status", 0);
1586000Sroot 	if (setjmp(peerdied) == 0)
1596000Sroot 		telnet(net);
1606000Sroot 	fprintf(stderr, "Connection closed by foreign host.\n");
1616000Sroot 	exit(1);
1626000Sroot }
1636000Sroot 
1646000Sroot /*
1656000Sroot  * Print status about the connection.
1666000Sroot  */
1676000Sroot /*VARARGS*/
1686000Sroot status()
1696000Sroot {
1706000Sroot 	if (connected)
1716000Sroot 		printf("Connected to %s.\n", host_name);
1726000Sroot 	else
1736000Sroot 		printf("No connection.\n");
1746000Sroot 	printf("Escape character is '%s'.\n", control(escape));
1756000Sroot }
1766000Sroot 
1776000Sroot makeargv()
1786000Sroot {
1796000Sroot 	register char *cp;
1806000Sroot 	register char **argp = margv;
1816000Sroot 
1826000Sroot 	margc = 0;
1836000Sroot 	for (cp = line; *cp;) {
1846000Sroot 		while (isspace(*cp))
1856000Sroot 			cp++;
1866000Sroot 		if (*cp == '\0')
1876000Sroot 			break;
1886000Sroot 		*argp++ = cp;
1896000Sroot 		margc += 1;
1906000Sroot 		while (*cp != '\0' && !isspace(*cp))
1916000Sroot 			cp++;
1926000Sroot 		if (*cp == '\0')
1936000Sroot 			break;
1946000Sroot 		*cp++ = '\0';
1956000Sroot 	}
1966000Sroot 	*argp++ = 0;
1976000Sroot }
1986000Sroot 
1996000Sroot /*VARARGS*/
2006000Sroot suspend()
2016000Sroot {
2026000Sroot 	register int save;
2036000Sroot 
2046000Sroot 	save = mode(0);
2056000Sroot 	kill(0, SIGTSTP);	/* get whole process group */
2066000Sroot 	mode(save);
2076000Sroot }
2086000Sroot 
2096000Sroot /*VARARGS*/
2106000Sroot bye()
2116000Sroot {
2126000Sroot 	int how = 2;
2136000Sroot 
2146000Sroot 	mode(0);
2156000Sroot 	if (connected) {
2166000Sroot 		ioctl(net, SIOCDONE, &how);
2176000Sroot 		printf("Connection closed.\n");
2186000Sroot 		close(net);
2196000Sroot 		connected = 0;
2206000Sroot 	}
2216000Sroot }
2226000Sroot 
2236000Sroot /*VARARGS*/
2246000Sroot quit()
2256000Sroot {
2266000Sroot 	call(bye, "bye", 0);
2276000Sroot 	exit(0);
2286000Sroot }
2296000Sroot 
2306000Sroot /*
2316000Sroot  * Help command.
2326000Sroot  * Call each command handler with argc == 0 and argv[0] == name.
2336000Sroot  */
2346000Sroot help(argc, argv)
2356000Sroot 	int argc;
2366000Sroot 	char *argv[];
2376000Sroot {
2386000Sroot 	register struct cmd *c;
2396000Sroot 
2406000Sroot 	if (argc == 1) {
2416000Sroot 		printf("Commands may be abbreviated.  Commands are:\n\n");
2426000Sroot 		for (c = cmdtab; c->name; c++)
2436000Sroot 			printf("%-*s\t%s\n", HELPINDENT, c->name, c->help);
2446000Sroot 		return;
2456000Sroot 	}
2466000Sroot 	while (--argc > 0) {
2476000Sroot 		register char *arg;
2486000Sroot 		arg = *++argv;
2496000Sroot 		c = getcmd(arg);
2506000Sroot 		if (c == (struct cmd *)-1)
2516000Sroot 			printf("?Ambiguous help command %s\n", arg);
2526000Sroot 		else if (c == (struct cmd *)0)
2536000Sroot 			printf("?Invalid help command %s\n", arg);
2546000Sroot 		else
2556000Sroot 			printf("%s\n", c->help);
2566000Sroot 	}
2576000Sroot }
2586000Sroot 
2596000Sroot /*
2606000Sroot  * Call routine with argc, argv set from args (terminated by 0).
2616000Sroot  * VARARGS2
2626000Sroot  */
2636000Sroot call(routine, args)
2646000Sroot 	int (*routine)();
2656000Sroot 	int args;
2666000Sroot {
2676000Sroot 	register int *argp;
2686000Sroot 	register int argc;
2696000Sroot 
2706000Sroot 	for (argc = 0, argp = &args; *argp++ != 0; argc++)
2716000Sroot 		;
2726000Sroot 	(*routine)(argc, &args);
2736000Sroot }
2746000Sroot 
2756000Sroot mode(f)
2766000Sroot 	register int f;
2776000Sroot {
2786000Sroot 	register int old;
2796000Sroot 	struct sgttyb stbuf;
2806000Sroot 	static int ttymode = 0;
2816000Sroot 	int onoff;
2826000Sroot 
2836000Sroot 	ioctl(fileno(stdin), TIOCGETP, &stbuf);
2846000Sroot 	old = ttymode;
2856000Sroot 	ttymode = f;
2866000Sroot 	switch (f) {
2876000Sroot 	case 0:
2886000Sroot 		stbuf.sg_flags &= ~RAW;
2896000Sroot 		stbuf.sg_flags |= ECHO|CRMOD;
2906000Sroot 		onoff = 0;
2916000Sroot 		break;
2926000Sroot 
2936000Sroot 	case 1:
2946000Sroot 		stbuf.sg_flags |= RAW;
2956000Sroot 		stbuf.sg_flags &= ~(ECHO|CRMOD);
2966000Sroot 		onoff = 1;
2976000Sroot 		break;
2986000Sroot 
2996000Sroot 	case 2:
3006000Sroot 		stbuf.sg_flags |= RAW;
3016000Sroot 		stbuf.sg_flags |= ECHO|CRMOD;
3026000Sroot 		onoff = 1;
3036000Sroot 	}
3046000Sroot 	ioctl(fileno(stdin), TIOCSETN, &stbuf);
3056000Sroot 	ioctl(fileno(stdin), FIONBIO, &onoff);
3066000Sroot 	ioctl(fileno(stdout), FIONBIO, &onoff);
3076000Sroot 	return (old);
3086000Sroot }
3096000Sroot 
3106000Sroot char	sibuf[BUFSIZ], *sbp;
3116000Sroot char	tibuf[BUFSIZ], *tbp;
3126000Sroot int	scc, tcc;
3136000Sroot 
3146000Sroot /*
3156000Sroot  * Select from tty and network...
3166000Sroot  */
3176000Sroot telnet(s)
3186000Sroot 	int s;
3196000Sroot {
3206000Sroot 	register int c;
3216000Sroot 	int tin = fileno(stdin), tout = fileno(stdout);
3226000Sroot 	int on = 1;
3236000Sroot 
3246000Sroot 	mode(1);
3256024Ssam 	if (showoptions)
3266024Ssam 		printoption("<--", doopt, TELOPT_ECHO);
3276000Sroot 	sprintf(nfrontp, doopt, TELOPT_ECHO);
3286000Sroot 	nfrontp += sizeof(doopt) - 2;
3296024Ssam 	if (showoptions)
3306024Ssam 		printoption("<--", doopt, TELOPT_SGA);
3316000Sroot 	sprintf(nfrontp, doopt, TELOPT_SGA);
3326000Sroot 	nfrontp += sizeof(doopt) - 2;
3336024Ssam 	if (showoptions)
3346024Ssam 		printoption("<--", will, TELOPT_SGA);
3356000Sroot 	sprintf(nfrontp, will, TELOPT_SGA);
3366000Sroot 	nfrontp += sizeof(doopt) - 2;
3376000Sroot 	ioctl(s, FIONBIO, &on);
3386000Sroot 	for (;;) {
3396000Sroot 		int ibits = 0, obits = 0;
3406000Sroot 
3416000Sroot 		if (nfrontp - nbackp)
3426000Sroot 			obits |= (1 << s);
3436000Sroot 		else
3446000Sroot 			ibits |= (1 << tin);
3456000Sroot 		if (tfrontp - tbackp)
3466000Sroot 			obits |= (1 << tout);
3476000Sroot 		else
3486000Sroot 			ibits |= (1 << s);
3496000Sroot 		if (scc < 0 && tcc < 0)
3506000Sroot 			break;
3516000Sroot 		select(32, &ibits, &obits, INFINITY);
3526000Sroot 		if (ibits == 0 && obits == 0) {
3536000Sroot 			sleep(5);
3546000Sroot 			continue;
3556000Sroot 		}
3566000Sroot 
3576000Sroot 		/*
3586000Sroot 		 * Something to read from the network...
3596000Sroot 		 */
3606000Sroot 		if (ibits & (1 << s)) {
3616000Sroot 			scc = read(s, sibuf, sizeof(sibuf));
3626000Sroot 			if (scc < 0 && errno == EWOULDBLOCK)
3636000Sroot 				scc = 0;
3646000Sroot 			else {
3656000Sroot 				if (scc <= 0)
3666000Sroot 					break;
3676000Sroot 				sbp = sibuf;
3686000Sroot 			}
3696000Sroot 		}
3706000Sroot 
3716000Sroot 		/*
3726000Sroot 		 * Something to read from the tty...
3736000Sroot 		 */
3746000Sroot 		if (ibits & (1 << tin)) {
3756000Sroot 			tcc = read(tin, tibuf, sizeof(tibuf));
3766000Sroot 			if (tcc < 0 && errno == EWOULDBLOCK)
3776000Sroot 				tcc = 0;
3786000Sroot 			else {
3796000Sroot 				if (tcc <= 0)
3806000Sroot 					break;
3816000Sroot 				tbp = tibuf;
3826000Sroot 			}
3836000Sroot 		}
3846000Sroot 
3856000Sroot 		while (tcc > 0) {
3866000Sroot 			register int c;
3876000Sroot 
3886000Sroot 			if ((&netobuf[BUFSIZ] - nfrontp) < 2)
3896000Sroot 				break;
3906000Sroot 			c = *tbp++ & 0377, tcc--;
3916000Sroot 			if (strip(c) == escape) {
3926000Sroot 				command(0);
3936000Sroot 				tcc = 0;
3946000Sroot 				break;
3956000Sroot 			}
3966000Sroot 			*nfrontp++ = c;
3976000Sroot 		}
3986000Sroot 		if ((obits & (1 << s)) && (nfrontp - nbackp) > 0)
3996000Sroot 			netflush(s);
4006000Sroot 		if (scc > 0)
4016000Sroot 			telrcv();
4026000Sroot 		if ((obits & (1 << tout)) && (tfrontp - tbackp) > 0)
4036000Sroot 			ttyflush(tout);
4046000Sroot 	}
4056000Sroot 	mode(0);
4066000Sroot }
4076000Sroot 
4086000Sroot command(top)
4096000Sroot 	int top;
4106000Sroot {
4116000Sroot 	register struct cmd *c;
4126000Sroot 	int oldmode, wasopen;
4136000Sroot 
4146000Sroot 	oldmode = mode(0);
4156000Sroot 	if (!top)
4166000Sroot 		putchar('\n');
4176000Sroot 	else
4186000Sroot 		sigset(SIGINT, SIG_DFL);
4196000Sroot 	for (;;) {
4206000Sroot 		printf("%s> ", prompt);
4216000Sroot 		if (gets(line) == 0)
4226000Sroot 			break;
4236000Sroot 		if (line[0] == 0)
4246000Sroot 			break;
4256000Sroot 		makeargv();
4266000Sroot 		c = getcmd(margv[0]);
4276000Sroot 		if (c == (struct cmd *)-1) {
4286000Sroot 			printf("?Ambiguous command\n");
4296000Sroot 			continue;
4306000Sroot 		}
4316000Sroot 		if (c == 0) {
4326000Sroot 			printf("?Invalid command\n");
4336000Sroot 			continue;
4346000Sroot 		}
4356000Sroot 		(*c->handler)(margc, margv);
4366000Sroot 		if (c->handler != help)
4376000Sroot 			break;
4386000Sroot 	}
4396000Sroot 	if (!top) {
4406000Sroot 		if (!connected)
4416000Sroot 			longjmp(toplevel, 1);
4426000Sroot 		mode(oldmode);
4436000Sroot 	}
4446000Sroot }
4456000Sroot 
4466000Sroot /*
4476000Sroot  * Telnet receiver states for fsm
4486000Sroot  */
4496000Sroot #define	TS_DATA		0
4506000Sroot #define	TS_IAC		1
4516000Sroot #define	TS_WILL		2
4526000Sroot #define	TS_WONT		3
4536000Sroot #define	TS_DO		4
4546000Sroot #define	TS_DONT		5
4556000Sroot 
4566000Sroot telrcv()
4576000Sroot {
4586000Sroot 	register int c;
4596000Sroot 	static int state = TS_DATA;
4606000Sroot 
4616000Sroot 	while (scc > 0) {
4626000Sroot 		c = *sbp++ & 0377, scc--;
4636000Sroot 		switch (state) {
4646000Sroot 
4656000Sroot 		case TS_DATA:
4666000Sroot 			if (c == IAC)
4676000Sroot 				state = TS_IAC;
4686000Sroot 			else
4696000Sroot 				*tfrontp++ = c;
4706000Sroot 			continue;
4716000Sroot 
4726000Sroot 		case TS_IAC:
4736000Sroot 			switch (c) {
4746000Sroot 
4756000Sroot 			case WILL:
4766000Sroot 				state = TS_WILL;
4776000Sroot 				continue;
4786000Sroot 
4796000Sroot 			case WONT:
4806000Sroot 				state = TS_WONT;
4816000Sroot 				continue;
4826000Sroot 
4836000Sroot 			case DO:
4846000Sroot 				state = TS_DO;
4856000Sroot 				continue;
4866000Sroot 
4876000Sroot 			case DONT:
4886000Sroot 				state = TS_DONT;
4896000Sroot 				continue;
4906000Sroot 
4916000Sroot 			case DM:
4926000Sroot 				ioctl(fileno(stdout), TIOCFLUSH, 0);
4936000Sroot 				break;
4946000Sroot 
4956000Sroot 			case NOP:
4966000Sroot 			case GA:
4976000Sroot 				break;
4986000Sroot 
4996000Sroot 			default:
5006000Sroot 				break;
5016000Sroot 			}
5026000Sroot 			state = TS_DATA;
5036000Sroot 			continue;
5046000Sroot 
5056000Sroot 		case TS_WILL:
5066024Ssam 			if (showoptions)
5076024Ssam 				printoption("-->", will, c);
5086000Sroot 			if (!hisopts[c])
5096000Sroot 				willoption(c);
5106000Sroot 			state = TS_DATA;
5116000Sroot 			continue;
5126000Sroot 
5136000Sroot 		case TS_WONT:
5146024Ssam 			if (showoptions)
5156024Ssam 				printoption("-->", wont, c);
5166000Sroot 			if (hisopts[c])
5176000Sroot 				wontoption(c);
5186000Sroot 			state = TS_DATA;
5196000Sroot 			continue;
5206000Sroot 
5216000Sroot 		case TS_DO:
5226024Ssam 			if (showoptions)
5236024Ssam 				printoption("-->", doopt, c);
5246000Sroot 			if (!myopts[c])
5256000Sroot 				dooption(c);
5266000Sroot 			state = TS_DATA;
5276000Sroot 			continue;
5286000Sroot 
5296000Sroot 		case TS_DONT:
5306024Ssam 			if (showoptions)
5316024Ssam 				printoption("-->", dont, c);
5326000Sroot 			if (myopts[c]) {
5336000Sroot 				myopts[c] = 0;
5346000Sroot 				sprintf(nfrontp, wont, c);
5356000Sroot 				nfrontp += sizeof(wont) - 2;
5366024Ssam 				if (showoptions)
5376024Ssam 					printoption("<--", wont, c);
5386000Sroot 			}
5396000Sroot 			state = TS_DATA;
5406000Sroot 			continue;
5416000Sroot 		}
5426000Sroot 	}
5436000Sroot }
5446000Sroot 
5456000Sroot willoption(option)
5466000Sroot 	int option;
5476000Sroot {
5486000Sroot 	char *fmt;
5496000Sroot 
5506000Sroot 	switch (option) {
5516000Sroot 
5526000Sroot 	case TELOPT_ECHO:
5536000Sroot 		mode(1);
5546000Sroot 
5556000Sroot 	case TELOPT_SGA:
5566000Sroot 		hisopts[option] = 1;
5576000Sroot 		fmt = doopt;
5586000Sroot 		break;
5596000Sroot 
5606000Sroot 	case TELOPT_TM:
5616000Sroot 		fmt = dont;
5626000Sroot 		break;
5636000Sroot 
5646000Sroot 	default:
5656000Sroot 		fmt = dont;
5666000Sroot 		break;
5676000Sroot 	}
5686024Ssam 	sprintf(nfrontp, fmt, option);
5696000Sroot 	nfrontp += sizeof(dont) - 2;
5706024Ssam 	if (showoptions)
5716024Ssam 		printoption("<--", fmt, option);
5726000Sroot }
5736000Sroot 
5746000Sroot wontoption(option)
5756000Sroot 	int option;
5766000Sroot {
5776000Sroot 	char *fmt;
5786000Sroot 
5796000Sroot 	switch (option) {
5806000Sroot 
5816000Sroot 	case TELOPT_ECHO:
5826000Sroot 		mode(2);
5836000Sroot 
5846000Sroot 	case TELOPT_SGA:
5856000Sroot 		hisopts[option] = 0;
5866000Sroot 		fmt = dont;
5876000Sroot 		break;
5886000Sroot 
5896000Sroot 	default:
5906000Sroot 		fmt = dont;
5916000Sroot 	}
5926000Sroot 	sprintf(nfrontp, fmt, option);
5936000Sroot 	nfrontp += sizeof(doopt) - 2;
5946024Ssam 	if (showoptions)
5956024Ssam 		printoption("<--", fmt, option);
5966000Sroot }
5976000Sroot 
5986000Sroot dooption(option)
5996000Sroot 	int option;
6006000Sroot {
6016000Sroot 	char *fmt;
6026000Sroot 
6036000Sroot 	switch (option) {
6046000Sroot 
6056000Sroot 	case TELOPT_TM:
6066000Sroot 		fmt = wont;
6076000Sroot 		break;
6086000Sroot 
6096000Sroot 	case TELOPT_SGA:
6106000Sroot 		fmt = will;
6116000Sroot 		break;
6126000Sroot 
6136000Sroot 	default:
6146000Sroot 		fmt = wont;
6156000Sroot 		break;
6166000Sroot 	}
6176000Sroot 	sprintf(nfrontp, fmt, option);
6186000Sroot 	nfrontp += sizeof(doopt) - 2;
6196024Ssam 	if (showoptions)
6206024Ssam 		printoption("<--", fmt, option);
6216000Sroot }
6226000Sroot 
6236000Sroot /*
6246000Sroot  * Set the escape character.
6256000Sroot  */
6266000Sroot setescape(argc, argv)
6276000Sroot 	int argc;
6286000Sroot 	char *argv[];
6296000Sroot {
6306000Sroot 	register char *arg;
6316000Sroot 	char buf[50];
6326000Sroot 
6336000Sroot 	if (argc > 2)
6346000Sroot 		arg = argv[1];
6356000Sroot 	else {
6366000Sroot 		printf("new escape character: ");
6376000Sroot 		gets(buf);
6386000Sroot 		arg = buf;
6396000Sroot 	}
6406000Sroot 	if (arg[0] != '\0')
6416000Sroot 		escape = arg[0];
6426000Sroot 	printf("Escape character is '%s'.\n", control(escape));
6436000Sroot }
6446000Sroot 
6456024Ssam /*VARARGS*/
6466024Ssam setoptions()
6476024Ssam {
6486024Ssam 	showoptions = !showoptions;
6496024Ssam 	printf("%s show option processing.\n", showoptions ? "Will" : "Wont");
6506024Ssam }
6516024Ssam 
6526000Sroot /*
6536000Sroot  * Construct a control character sequence
6546000Sroot  * for a special character.
6556000Sroot  */
6566000Sroot char *
6576000Sroot control(c)
6586000Sroot 	register int c;
6596000Sroot {
6606000Sroot 	static char buf[3];
6616000Sroot 
6626000Sroot 	if (c == 0177)
6636000Sroot 		return ("^?");
6646000Sroot 	if (c >= 040) {
6656000Sroot 		buf[0] = c;
6666000Sroot 		buf[1] = 0;
6676000Sroot 	} else {
6686000Sroot 		buf[0] = '^';
6696000Sroot 		buf[1] = '@'+c;
6706000Sroot 		buf[2] = 0;
6716000Sroot 	}
6726000Sroot 	return (buf);
6736000Sroot }
6746000Sroot 
6756000Sroot struct cmd *
6766000Sroot getcmd(name)
6776000Sroot 	register char *name;
6786000Sroot {
6796000Sroot 	register char *p, *q;
6806000Sroot 	register struct cmd *c, *found;
6816000Sroot 	register int nmatches, longest;
6826000Sroot 
6836000Sroot 	longest = 0;
6846000Sroot 	nmatches = 0;
6856000Sroot 	found = 0;
6866000Sroot 	for (c = cmdtab; p = c->name; c++) {
6876000Sroot 		for (q = name; *q == *p++; q++)
6886000Sroot 			if (*q == 0)		/* exact match? */
6896000Sroot 				return (c);
6906000Sroot 		if (!*q) {			/* the name was a prefix */
6916000Sroot 			if (q - name > longest) {
6926000Sroot 				longest = q - name;
6936000Sroot 				nmatches = 1;
6946000Sroot 				found = c;
6956000Sroot 			} else if (q - name == longest)
6966000Sroot 				nmatches++;
6976000Sroot 		}
6986000Sroot 	}
6996000Sroot 	if (nmatches > 1)
7006000Sroot 		return ((struct cmd *)-1);
7016000Sroot 	return (found);
7026000Sroot }
7036000Sroot 
7046000Sroot deadpeer()
7056000Sroot {
7066000Sroot 	sigset(SIGPIPE, deadpeer);
7076000Sroot 	mode(0);
7086000Sroot 	longjmp(peerdied, -1);
7096000Sroot }
7106000Sroot 
7116000Sroot intr()
7126000Sroot {
7136000Sroot 	sigset(SIGINT, intr);
7146000Sroot 	mode(0);
7156000Sroot 	longjmp(toplevel, -1);
7166000Sroot }
7176000Sroot 
7186000Sroot ttyflush(fd)
7196000Sroot {
7206000Sroot 	int n;
7216000Sroot 
7226000Sroot 	if ((n = tfrontp - tbackp) > 0)
7236000Sroot 		n = write(fd, tbackp, n);
7246000Sroot 	if (n < 0 && errno == EWOULDBLOCK)
7256000Sroot 		n = 0;
7266000Sroot 	tbackp += n;
7276000Sroot 	if (tbackp == tfrontp)
7286000Sroot 		tbackp = tfrontp = ttyobuf;
7296000Sroot }
7306000Sroot 
7316000Sroot netflush(fd)
7326000Sroot {
7336000Sroot 	int n;
7346000Sroot 
7356000Sroot 	if ((n = nfrontp - nbackp) > 0)
7366000Sroot 		n = write(fd, nbackp, n);
7376000Sroot 	if (n < 0 && errno == EWOULDBLOCK)
7386000Sroot 		n = 0;
7396000Sroot 	nbackp += n;
7406000Sroot 	if (nbackp == nfrontp)
7416000Sroot 		nbackp = nfrontp = netobuf;
7426000Sroot }
7436024Ssam 
7446024Ssam printoption(direction, fmt, option)
7456024Ssam 	char *direction, *fmt;
7466024Ssam 	int option;
7476024Ssam {
7486024Ssam 	printf("%s ", direction);
7496024Ssam 	if (fmt == doopt)
7506024Ssam 		fmt = "do";
7516024Ssam 	else if (fmt == dont)
7526024Ssam 		fmt = "dont";
7536024Ssam 	else if (fmt == will)
7546024Ssam 		fmt = "will";
7556024Ssam 	else if (fmt == wont)
7566024Ssam 		fmt = "wont";
7576024Ssam 	else
7586024Ssam 		fmt = "???";
7596024Ssam 	if (option < TELOPT_SUPDUP)
7606024Ssam 		printf("%s %s\r\n", fmt, telopts[option]);
7616024Ssam 	else
7626024Ssam 		printf("%s %d\r\n", fmt, option);
7636024Ssam }
764