xref: /csrg-svn/usr.bin/telnet/telnet.c (revision 8378)
1*8378Ssam static char sccsid[] = "@(#)telnet.c	4.11 (Berkeley) 10/07/82";
26000Sroot /*
36000Sroot  * User telnet program.
46000Sroot  */
56000Sroot #include <stdio.h>
66000Sroot #include <ctype.h>
76000Sroot #include <errno.h>
86000Sroot #include <signal.h>
96000Sroot #include <sgtty.h>
106000Sroot #include <setjmp.h>
116000Sroot #include <sys/types.h>
126000Sroot #include <sys/socket.h>
136000Sroot #include <net/in.h>
148345Ssam #include <netdb.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 
226000Sroot char	ttyobuf[BUFSIZ], *tfrontp = ttyobuf, *tbackp = ttyobuf;
23*8378Ssam char	netobuf[BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf;
246000Sroot 
256000Sroot char	hisopts[256];
266000Sroot char	myopts[256];
276000Sroot 
286000Sroot char	doopt[] = { IAC, DO, '%', 'c', 0 };
296000Sroot char	dont[] = { IAC, DONT, '%', 'c', 0 };
306000Sroot char	will[] = { IAC, WILL, '%', 'c', 0 };
316000Sroot char	wont[] = { IAC, WONT, '%', 'c', 0 };
326000Sroot 
336000Sroot int	connected;
346000Sroot int	net;
356024Ssam int	showoptions;
367377Sfeldman int	options;
376000Sroot char	*prompt;
387377Sfeldman char	escape = ctrl(']');
396000Sroot 
406000Sroot char	line[200];
416000Sroot int	margc;
426000Sroot char	*margv[20];
436000Sroot 
446000Sroot jmp_buf	toplevel;
456000Sroot jmp_buf	peerdied;
466000Sroot 
476000Sroot extern	int errno;
486000Sroot 
496000Sroot int	tn(), quit(), suspend(), bye(), help();
506024Ssam int	setescape(), status(), toggle(), setoptions();
516000Sroot 
52*8378Ssam #define HELPINDENT (sizeof ("connect"))
536000Sroot 
546000Sroot struct cmd {
556000Sroot 	char	*name;
566000Sroot 	char	*help;
576000Sroot 	int	(*handler)();
586000Sroot };
596000Sroot 
606000Sroot char	ohelp[] = "connect to a site";
616000Sroot char	chelp[] = "close current connection";
626000Sroot char	qhelp[] = "exit telnet";
636000Sroot char	zhelp[] = "suspend telnet";
646000Sroot char	ehelp[] = "set escape character";
656000Sroot char	shelp[] = "print status information";
666000Sroot char	hhelp[] = "print help information";
676024Ssam char	phelp[] = "toggle viewing of options processing";
686000Sroot 
696000Sroot struct cmd cmdtab[] = {
706000Sroot 	{ "open",	ohelp,		tn },
716000Sroot 	{ "close",	chelp,		bye },
726000Sroot 	{ "quit",	qhelp,		quit },
736000Sroot 	{ "z",		zhelp,		suspend },
746000Sroot 	{ "escape",	ehelp,		setescape },
756000Sroot 	{ "status",	shelp,		status },
766024Ssam 	{ "options",	phelp,		setoptions },
776000Sroot 	{ "?",		hhelp,		help },
786000Sroot 	0
796000Sroot };
806000Sroot 
818345Ssam struct sockaddr_in sin = { AF_INET };
826000Sroot 
836000Sroot int	intr(), deadpeer();
846000Sroot char	*control();
856000Sroot struct	cmd *getcmd();
868345Ssam struct	servent *sp;
876000Sroot 
88*8378Ssam struct	sgttyb ostbuf;
89*8378Ssam struct	tchars otchars;
90*8378Ssam int	odisc;
91*8378Ssam 
926000Sroot main(argc, argv)
936000Sroot 	int argc;
946000Sroot 	char *argv[];
956000Sroot {
968345Ssam 	sp = getservbyname("telnet", "tcp");
978345Ssam 	if (sp == 0) {
988345Ssam 		fprintf(stderr, "telnet: tcp/telnet: unknown service\n");
998345Ssam 		exit(1);
1008345Ssam 	}
101*8378Ssam 	ioctl(0, TIOCGETP, (char *)&ostbuf);
102*8378Ssam 	ioctl(0, TIOCGETC, (char *)&otchars);
103*8378Ssam 	ioctl(0, TIOCGETD, (char *)&odisc);
1046000Sroot 	setbuf(stdin, 0);
1056000Sroot 	setbuf(stdout, 0);
1066000Sroot 	prompt = argv[0];
1077377Sfeldman 	if (argc > 1 && !strcmp(argv[1], "-d"))
1087377Sfeldman 		options = SO_DEBUG, argv++, argc--;
1096000Sroot 	if (argc != 1) {
1106000Sroot 		if (setjmp(toplevel) != 0)
1116000Sroot 			exit(0);
1126000Sroot 		tn(argc, argv);
1136000Sroot 	}
1146000Sroot 	setjmp(toplevel);
1156000Sroot 	for (;;)
1166000Sroot 		command(1);
1176000Sroot }
1186000Sroot 
1198377Ssam char	*hostname;
1208377Ssam char	hnamebuf[32];
1216000Sroot 
1226000Sroot tn(argc, argv)
1236000Sroot 	int argc;
1246000Sroot 	char *argv[];
1256000Sroot {
1266000Sroot 	register int c;
1278377Ssam 	register struct hostent *host;
1286000Sroot 
1296000Sroot 	if (connected) {
1308377Ssam 		printf("?Already connected to %s\n", hostname);
1316000Sroot 		return;
1326000Sroot 	}
1336000Sroot 	if (argc < 2) {
1346000Sroot 		strcpy(line, "Connect ");
1356000Sroot 		printf("(to) ");
1366000Sroot 		gets(&line[strlen(line)]);
1376000Sroot 		makeargv();
1386000Sroot 		argc = margc;
1396000Sroot 		argv = margv;
1406000Sroot 	}
1416000Sroot 	if (argc > 3) {
1426000Sroot 		printf("usage: %s host-name [port]\n", argv[0]);
1436000Sroot 		return;
1446000Sroot 	}
1458345Ssam 	host = gethostbyname(argv[1]);
1468377Ssam 	if (host) {
1478377Ssam 		bcopy(host->h_addr, &sin.sin_addr, host->h_length);
1488377Ssam 		hostname = host->h_name;
1498377Ssam 	} else {
1508377Ssam 		sin.sin_addr.s_addr = inet_addr(argv[1]);
1518377Ssam 		if (sin.sin_addr.s_addr == -1) {
1528377Ssam 			printf("%s: unknown host\n", argv[1]);
1538377Ssam 			return;
1548377Ssam 		}
1558377Ssam 		strcpy(hnamebuf, argv[1]);
1568377Ssam 		hostname = hnamebuf;
1576000Sroot 	}
1588345Ssam 	sin.sin_port = sp->s_port;
1596024Ssam 	if (argc == 3) {
1606024Ssam 		sin.sin_port = atoi(argv[2]);
1616024Ssam 		if (sin.sin_port < 0) {
1626024Ssam 			printf("%s: bad port number\n", argv[2]);
1636024Ssam 			return;
1646024Ssam 		}
1656024Ssam 	}
1668345Ssam 	sin.sin_port = htons(sin.sin_port);
1677377Sfeldman 	if ((net = socket(SOCK_STREAM, 0, 0, options)) < 0) {
1686000Sroot 		perror("socket");
1696000Sroot 		return;
1706000Sroot 	}
1716000Sroot 	sigset(SIGINT, intr);
1726000Sroot 	sigset(SIGPIPE, deadpeer);
1736000Sroot 	printf("Trying...\n");
1746000Sroot 	if (connect(net, &sin)) {
1756000Sroot 		perror("connect");
1766000Sroot 		sigset(SIGINT, SIG_DFL);
1776000Sroot 		return;
1786000Sroot 	}
1796000Sroot 	connected++;
1806000Sroot 	call(status, "status", 0);
1816000Sroot 	if (setjmp(peerdied) == 0)
1826000Sroot 		telnet(net);
1836000Sroot 	fprintf(stderr, "Connection closed by foreign host.\n");
1846000Sroot 	exit(1);
1856000Sroot }
1866000Sroot 
1876000Sroot /*
1886000Sroot  * Print status about the connection.
1896000Sroot  */
1906000Sroot /*VARARGS*/
1916000Sroot status()
1926000Sroot {
1936000Sroot 	if (connected)
1948377Ssam 		printf("Connected to %s.\n", hostname);
1956000Sroot 	else
1966000Sroot 		printf("No connection.\n");
1976000Sroot 	printf("Escape character is '%s'.\n", control(escape));
1986000Sroot }
1996000Sroot 
2006000Sroot makeargv()
2016000Sroot {
2026000Sroot 	register char *cp;
2036000Sroot 	register char **argp = margv;
2046000Sroot 
2056000Sroot 	margc = 0;
2066000Sroot 	for (cp = line; *cp;) {
2076000Sroot 		while (isspace(*cp))
2086000Sroot 			cp++;
2096000Sroot 		if (*cp == '\0')
2106000Sroot 			break;
2116000Sroot 		*argp++ = cp;
2126000Sroot 		margc += 1;
2136000Sroot 		while (*cp != '\0' && !isspace(*cp))
2146000Sroot 			cp++;
2156000Sroot 		if (*cp == '\0')
2166000Sroot 			break;
2176000Sroot 		*cp++ = '\0';
2186000Sroot 	}
2196000Sroot 	*argp++ = 0;
2206000Sroot }
2216000Sroot 
2226000Sroot /*VARARGS*/
2236000Sroot suspend()
2246000Sroot {
2256000Sroot 	register int save;
2266000Sroot 
2276000Sroot 	save = mode(0);
228*8378Ssam 	kill(0, SIGTSTP);
229*8378Ssam 	/* reget parameters in case they were changed */
230*8378Ssam 	ioctl(0, TIOCGETP, (char *)&ostbuf);
231*8378Ssam 	ioctl(0, TIOCGETC, (char *)&otchars);
232*8378Ssam 	ioctl(0, TIOCGETD, (char *)&odisc);
233*8378Ssam 	(void) mode(save);
2346000Sroot }
2356000Sroot 
2366000Sroot /*VARARGS*/
2376000Sroot bye()
2386000Sroot {
2396000Sroot 	int how = 2;
240*8378Ssam 	register char *op;
2416000Sroot 
242*8378Ssam 	(void) mode(0);
2436000Sroot 	if (connected) {
2446000Sroot 		ioctl(net, SIOCDONE, &how);
2456000Sroot 		printf("Connection closed.\n");
2466000Sroot 		close(net);
2476000Sroot 		connected = 0;
248*8378Ssam 		/* reset his options */
249*8378Ssam 		for (op = hisopts; op < &hisopts[256]; op++)
250*8378Ssam 			*op = 0;
2516000Sroot 	}
2526000Sroot }
2536000Sroot 
2546000Sroot /*VARARGS*/
2556000Sroot quit()
2566000Sroot {
2576000Sroot 	call(bye, "bye", 0);
2586000Sroot 	exit(0);
2596000Sroot }
2606000Sroot 
2616000Sroot /*
2626000Sroot  * Help command.
2636000Sroot  * Call each command handler with argc == 0 and argv[0] == name.
2646000Sroot  */
2656000Sroot help(argc, argv)
2666000Sroot 	int argc;
2676000Sroot 	char *argv[];
2686000Sroot {
2696000Sroot 	register struct cmd *c;
2706000Sroot 
2716000Sroot 	if (argc == 1) {
2726000Sroot 		printf("Commands may be abbreviated.  Commands are:\n\n");
2736000Sroot 		for (c = cmdtab; c->name; c++)
2746000Sroot 			printf("%-*s\t%s\n", HELPINDENT, c->name, c->help);
2756000Sroot 		return;
2766000Sroot 	}
2776000Sroot 	while (--argc > 0) {
2786000Sroot 		register char *arg;
2796000Sroot 		arg = *++argv;
2806000Sroot 		c = getcmd(arg);
2816000Sroot 		if (c == (struct cmd *)-1)
2826000Sroot 			printf("?Ambiguous help command %s\n", arg);
2836000Sroot 		else if (c == (struct cmd *)0)
2846000Sroot 			printf("?Invalid help command %s\n", arg);
2856000Sroot 		else
2866000Sroot 			printf("%s\n", c->help);
2876000Sroot 	}
2886000Sroot }
2896000Sroot 
2906000Sroot /*
2916000Sroot  * Call routine with argc, argv set from args (terminated by 0).
2926000Sroot  * VARARGS2
2936000Sroot  */
2946000Sroot call(routine, args)
2956000Sroot 	int (*routine)();
2966000Sroot 	int args;
2976000Sroot {
2986000Sroot 	register int *argp;
2996000Sroot 	register int argc;
3006000Sroot 
3016000Sroot 	for (argc = 0, argp = &args; *argp++ != 0; argc++)
3026000Sroot 		;
3036000Sroot 	(*routine)(argc, &args);
3046000Sroot }
3056000Sroot 
3066000Sroot mode(f)
3076000Sroot 	register int f;
3086000Sroot {
3096000Sroot 	struct sgttyb stbuf;
310*8378Ssam 	static int prevmode = 0;
311*8378Ssam 	struct tchars tchars;
312*8378Ssam 	int onoff, disc, old;
3136000Sroot 
314*8378Ssam 	if (prevmode == f)
315*8378Ssam 		return (f);
316*8378Ssam 	old = prevmode;
317*8378Ssam 	prevmode = f;
318*8378Ssam 	stbuf = ostbuf;
319*8378Ssam 	tchars = otchars;
3206000Sroot 	switch (f) {
321*8378Ssam 
3226000Sroot 	case 0:
323*8378Ssam 		disc = odisc;
3246000Sroot 		onoff = 0;
3256000Sroot 		break;
3266000Sroot 
3276000Sroot 	case 1:
3286000Sroot 	case 2:
329*8378Ssam 		stbuf.sg_flags |= CBREAK;
330*8378Ssam 		if (f == 1)
331*8378Ssam 			stbuf.sg_flags &= ~ECHO;
332*8378Ssam 		else
333*8378Ssam 			stbuf.sg_flags |= ECHO;
334*8378Ssam 		tchars.t_intrc = tchars.t_quitc = -1;
335*8378Ssam 		disc = OTTYDISC;
3366000Sroot 		onoff = 1;
3376000Sroot 	}
338*8378Ssam 	ioctl(fileno(stdin), TIOCSETD, &disc);
339*8378Ssam 	ioctl(fileno(stdin), TIOCSETC, &tchars);
3406000Sroot 	ioctl(fileno(stdin), TIOCSETN, &stbuf);
3416000Sroot 	ioctl(fileno(stdin), FIONBIO, &onoff);
3426000Sroot 	ioctl(fileno(stdout), FIONBIO, &onoff);
3436000Sroot 	return (old);
3446000Sroot }
3456000Sroot 
3466000Sroot char	sibuf[BUFSIZ], *sbp;
3476000Sroot char	tibuf[BUFSIZ], *tbp;
3486000Sroot int	scc, tcc;
3496000Sroot 
3506000Sroot /*
3516000Sroot  * Select from tty and network...
3526000Sroot  */
3536000Sroot telnet(s)
3546000Sroot 	int s;
3556000Sroot {
3566000Sroot 	register int c;
3576000Sroot 	int tin = fileno(stdin), tout = fileno(stdout);
3586000Sroot 	int on = 1;
3596000Sroot 
360*8378Ssam 	(void) mode(2);
3616000Sroot 	ioctl(s, FIONBIO, &on);
3626000Sroot 	for (;;) {
3636000Sroot 		int ibits = 0, obits = 0;
3646000Sroot 
3656000Sroot 		if (nfrontp - nbackp)
3666000Sroot 			obits |= (1 << s);
3676000Sroot 		else
3686000Sroot 			ibits |= (1 << tin);
3696000Sroot 		if (tfrontp - tbackp)
3706000Sroot 			obits |= (1 << tout);
3716000Sroot 		else
3726000Sroot 			ibits |= (1 << s);
3736000Sroot 		if (scc < 0 && tcc < 0)
3746000Sroot 			break;
3756000Sroot 		select(32, &ibits, &obits, INFINITY);
3766000Sroot 		if (ibits == 0 && obits == 0) {
3776000Sroot 			sleep(5);
3786000Sroot 			continue;
3796000Sroot 		}
3806000Sroot 
3816000Sroot 		/*
3826000Sroot 		 * Something to read from the network...
3836000Sroot 		 */
3846000Sroot 		if (ibits & (1 << s)) {
385*8378Ssam 			scc = read(s, sibuf, sizeof (sibuf));
3866000Sroot 			if (scc < 0 && errno == EWOULDBLOCK)
3876000Sroot 				scc = 0;
3886000Sroot 			else {
3896000Sroot 				if (scc <= 0)
3906000Sroot 					break;
3916000Sroot 				sbp = sibuf;
3926000Sroot 			}
3936000Sroot 		}
3946000Sroot 
3956000Sroot 		/*
3966000Sroot 		 * Something to read from the tty...
3976000Sroot 		 */
3986000Sroot 		if (ibits & (1 << tin)) {
399*8378Ssam 			tcc = read(tin, tibuf, sizeof (tibuf));
4006000Sroot 			if (tcc < 0 && errno == EWOULDBLOCK)
4016000Sroot 				tcc = 0;
4026000Sroot 			else {
4036000Sroot 				if (tcc <= 0)
4046000Sroot 					break;
4056000Sroot 				tbp = tibuf;
4066000Sroot 			}
4076000Sroot 		}
4086000Sroot 
4096000Sroot 		while (tcc > 0) {
4106000Sroot 			register int c;
4116000Sroot 
4126000Sroot 			if ((&netobuf[BUFSIZ] - nfrontp) < 2)
4136000Sroot 				break;
4146000Sroot 			c = *tbp++ & 0377, tcc--;
4156000Sroot 			if (strip(c) == escape) {
4166000Sroot 				command(0);
4176000Sroot 				tcc = 0;
4186000Sroot 				break;
4196000Sroot 			}
4206000Sroot 			*nfrontp++ = c;
4216000Sroot 		}
4226000Sroot 		if ((obits & (1 << s)) && (nfrontp - nbackp) > 0)
4236000Sroot 			netflush(s);
4246000Sroot 		if (scc > 0)
4256000Sroot 			telrcv();
4266000Sroot 		if ((obits & (1 << tout)) && (tfrontp - tbackp) > 0)
4276000Sroot 			ttyflush(tout);
4286000Sroot 	}
429*8378Ssam 	(void) mode(0);
4306000Sroot }
4316000Sroot 
4326000Sroot command(top)
4336000Sroot 	int top;
4346000Sroot {
4356000Sroot 	register struct cmd *c;
4366000Sroot 	int oldmode, wasopen;
4376000Sroot 
4386000Sroot 	oldmode = mode(0);
4396000Sroot 	if (!top)
4406000Sroot 		putchar('\n');
4416000Sroot 	else
4426000Sroot 		sigset(SIGINT, SIG_DFL);
4436000Sroot 	for (;;) {
4446000Sroot 		printf("%s> ", prompt);
4456000Sroot 		if (gets(line) == 0)
4466000Sroot 			break;
4476000Sroot 		if (line[0] == 0)
4486000Sroot 			break;
4496000Sroot 		makeargv();
4506000Sroot 		c = getcmd(margv[0]);
4516000Sroot 		if (c == (struct cmd *)-1) {
4526000Sroot 			printf("?Ambiguous command\n");
4536000Sroot 			continue;
4546000Sroot 		}
4556000Sroot 		if (c == 0) {
4566000Sroot 			printf("?Invalid command\n");
4576000Sroot 			continue;
4586000Sroot 		}
4596000Sroot 		(*c->handler)(margc, margv);
4606000Sroot 		if (c->handler != help)
4616000Sroot 			break;
4626000Sroot 	}
4636000Sroot 	if (!top) {
4646000Sroot 		if (!connected)
4656000Sroot 			longjmp(toplevel, 1);
466*8378Ssam 		(void) mode(oldmode);
4676000Sroot 	}
4686000Sroot }
4696000Sroot 
4706000Sroot /*
4716000Sroot  * Telnet receiver states for fsm
4726000Sroot  */
4736000Sroot #define	TS_DATA		0
4746000Sroot #define	TS_IAC		1
4756000Sroot #define	TS_WILL		2
4766000Sroot #define	TS_WONT		3
4776000Sroot #define	TS_DO		4
4786000Sroot #define	TS_DONT		5
4796000Sroot 
4806000Sroot telrcv()
4816000Sroot {
4826000Sroot 	register int c;
4836000Sroot 	static int state = TS_DATA;
4846000Sroot 
4856000Sroot 	while (scc > 0) {
4866000Sroot 		c = *sbp++ & 0377, scc--;
4876000Sroot 		switch (state) {
4886000Sroot 
4896000Sroot 		case TS_DATA:
4906000Sroot 			if (c == IAC)
4916000Sroot 				state = TS_IAC;
4926000Sroot 			else
4936000Sroot 				*tfrontp++ = c;
4946000Sroot 			continue;
4956000Sroot 
4966000Sroot 		case TS_IAC:
4976000Sroot 			switch (c) {
4986000Sroot 
4996000Sroot 			case WILL:
5006000Sroot 				state = TS_WILL;
5016000Sroot 				continue;
5026000Sroot 
5036000Sroot 			case WONT:
5046000Sroot 				state = TS_WONT;
5056000Sroot 				continue;
5066000Sroot 
5076000Sroot 			case DO:
5086000Sroot 				state = TS_DO;
5096000Sroot 				continue;
5106000Sroot 
5116000Sroot 			case DONT:
5126000Sroot 				state = TS_DONT;
5136000Sroot 				continue;
5146000Sroot 
5156000Sroot 			case DM:
5166000Sroot 				ioctl(fileno(stdout), TIOCFLUSH, 0);
5176000Sroot 				break;
5186000Sroot 
5196000Sroot 			case NOP:
5206000Sroot 			case GA:
5216000Sroot 				break;
5226000Sroot 
5236000Sroot 			default:
5246000Sroot 				break;
5256000Sroot 			}
5266000Sroot 			state = TS_DATA;
5276000Sroot 			continue;
5286000Sroot 
5296000Sroot 		case TS_WILL:
5308345Ssam 			printoption("RCVD", will, c, !hisopts[c]);
5316000Sroot 			if (!hisopts[c])
5326000Sroot 				willoption(c);
5336000Sroot 			state = TS_DATA;
5346000Sroot 			continue;
5356000Sroot 
5366000Sroot 		case TS_WONT:
5378345Ssam 			printoption("RCVD", wont, c, hisopts[c]);
5386000Sroot 			if (hisopts[c])
5396000Sroot 				wontoption(c);
5406000Sroot 			state = TS_DATA;
5416000Sroot 			continue;
5426000Sroot 
5436000Sroot 		case TS_DO:
5448345Ssam 			printoption("RCVD", doopt, c, !myopts[c]);
5456000Sroot 			if (!myopts[c])
5466000Sroot 				dooption(c);
5476000Sroot 			state = TS_DATA;
5486000Sroot 			continue;
5496000Sroot 
5506000Sroot 		case TS_DONT:
5518345Ssam 			printoption("RCVD", dont, c, myopts[c]);
5526000Sroot 			if (myopts[c]) {
5536000Sroot 				myopts[c] = 0;
5546000Sroot 				sprintf(nfrontp, wont, c);
555*8378Ssam 				nfrontp += sizeof (wont) - 2;
5568345Ssam 				printoption("SENT", wont, c);
5576000Sroot 			}
5586000Sroot 			state = TS_DATA;
5596000Sroot 			continue;
5606000Sroot 		}
5616000Sroot 	}
5626000Sroot }
5636000Sroot 
5646000Sroot willoption(option)
5656000Sroot 	int option;
5666000Sroot {
5676000Sroot 	char *fmt;
5686000Sroot 
5696000Sroot 	switch (option) {
5706000Sroot 
5716000Sroot 	case TELOPT_ECHO:
572*8378Ssam 		(void) mode(1);
5736000Sroot 
5746000Sroot 	case TELOPT_SGA:
5756000Sroot 		hisopts[option] = 1;
5766000Sroot 		fmt = doopt;
5776000Sroot 		break;
5786000Sroot 
5796000Sroot 	case TELOPT_TM:
5806000Sroot 		fmt = dont;
5816000Sroot 		break;
5826000Sroot 
5836000Sroot 	default:
5846000Sroot 		fmt = dont;
5856000Sroot 		break;
5866000Sroot 	}
5876024Ssam 	sprintf(nfrontp, fmt, option);
588*8378Ssam 	nfrontp += sizeof (dont) - 2;
5898345Ssam 	printoption("SENT", fmt, option);
5906000Sroot }
5916000Sroot 
5926000Sroot wontoption(option)
5936000Sroot 	int option;
5946000Sroot {
5956000Sroot 	char *fmt;
5966000Sroot 
5976000Sroot 	switch (option) {
5986000Sroot 
5996000Sroot 	case TELOPT_ECHO:
600*8378Ssam 		(void) mode(2);
6016000Sroot 
6026000Sroot 	case TELOPT_SGA:
6036000Sroot 		hisopts[option] = 0;
6046000Sroot 		fmt = dont;
6056000Sroot 		break;
6066000Sroot 
6076000Sroot 	default:
6086000Sroot 		fmt = dont;
6096000Sroot 	}
6106000Sroot 	sprintf(nfrontp, fmt, option);
611*8378Ssam 	nfrontp += sizeof (doopt) - 2;
6128345Ssam 	printoption("SENT", fmt, option);
6136000Sroot }
6146000Sroot 
6156000Sroot dooption(option)
6166000Sroot 	int option;
6176000Sroot {
6186000Sroot 	char *fmt;
6196000Sroot 
6206000Sroot 	switch (option) {
6216000Sroot 
6226000Sroot 	case TELOPT_TM:
6236000Sroot 		fmt = wont;
6246000Sroot 		break;
6256000Sroot 
6266000Sroot 	case TELOPT_SGA:
6276000Sroot 		fmt = will;
6286000Sroot 		break;
6296000Sroot 
6306000Sroot 	default:
6316000Sroot 		fmt = wont;
6326000Sroot 		break;
6336000Sroot 	}
6346000Sroot 	sprintf(nfrontp, fmt, option);
635*8378Ssam 	nfrontp += sizeof (doopt) - 2;
6368345Ssam 	printoption("SENT", fmt, option);
6376000Sroot }
6386000Sroot 
6396000Sroot /*
6406000Sroot  * Set the escape character.
6416000Sroot  */
6426000Sroot setescape(argc, argv)
6436000Sroot 	int argc;
6446000Sroot 	char *argv[];
6456000Sroot {
6466000Sroot 	register char *arg;
6476000Sroot 	char buf[50];
6486000Sroot 
6496000Sroot 	if (argc > 2)
6506000Sroot 		arg = argv[1];
6516000Sroot 	else {
6526000Sroot 		printf("new escape character: ");
6536000Sroot 		gets(buf);
6546000Sroot 		arg = buf;
6556000Sroot 	}
6566000Sroot 	if (arg[0] != '\0')
6576000Sroot 		escape = arg[0];
6586000Sroot 	printf("Escape character is '%s'.\n", control(escape));
6596000Sroot }
6606000Sroot 
6616024Ssam /*VARARGS*/
6626024Ssam setoptions()
6636024Ssam {
6646024Ssam 	showoptions = !showoptions;
6656024Ssam 	printf("%s show option processing.\n", showoptions ? "Will" : "Wont");
6666024Ssam }
6676024Ssam 
6686000Sroot /*
6696000Sroot  * Construct a control character sequence
6706000Sroot  * for a special character.
6716000Sroot  */
6726000Sroot char *
6736000Sroot control(c)
6746000Sroot 	register int c;
6756000Sroot {
6766000Sroot 	static char buf[3];
6776000Sroot 
6786000Sroot 	if (c == 0177)
6796000Sroot 		return ("^?");
6806000Sroot 	if (c >= 040) {
6816000Sroot 		buf[0] = c;
6826000Sroot 		buf[1] = 0;
6836000Sroot 	} else {
6846000Sroot 		buf[0] = '^';
6856000Sroot 		buf[1] = '@'+c;
6866000Sroot 		buf[2] = 0;
6876000Sroot 	}
6886000Sroot 	return (buf);
6896000Sroot }
6906000Sroot 
6916000Sroot struct cmd *
6926000Sroot getcmd(name)
6936000Sroot 	register char *name;
6946000Sroot {
6956000Sroot 	register char *p, *q;
6966000Sroot 	register struct cmd *c, *found;
6976000Sroot 	register int nmatches, longest;
6986000Sroot 
6996000Sroot 	longest = 0;
7006000Sroot 	nmatches = 0;
7016000Sroot 	found = 0;
7026000Sroot 	for (c = cmdtab; p = c->name; c++) {
7036000Sroot 		for (q = name; *q == *p++; q++)
7046000Sroot 			if (*q == 0)		/* exact match? */
7056000Sroot 				return (c);
7066000Sroot 		if (!*q) {			/* the name was a prefix */
7076000Sroot 			if (q - name > longest) {
7086000Sroot 				longest = q - name;
7096000Sroot 				nmatches = 1;
7106000Sroot 				found = c;
7116000Sroot 			} else if (q - name == longest)
7126000Sroot 				nmatches++;
7136000Sroot 		}
7146000Sroot 	}
7156000Sroot 	if (nmatches > 1)
7166000Sroot 		return ((struct cmd *)-1);
7176000Sroot 	return (found);
7186000Sroot }
7196000Sroot 
7206000Sroot deadpeer()
7216000Sroot {
7226000Sroot 	sigset(SIGPIPE, deadpeer);
723*8378Ssam 	(void) mode(0);
7246000Sroot 	longjmp(peerdied, -1);
7256000Sroot }
7266000Sroot 
7276000Sroot intr()
7286000Sroot {
7296000Sroot 	sigset(SIGINT, intr);
730*8378Ssam 	(void) mode(0);
7316000Sroot 	longjmp(toplevel, -1);
7326000Sroot }
7336000Sroot 
7346000Sroot ttyflush(fd)
7356000Sroot {
7366000Sroot 	int n;
7376000Sroot 
7386000Sroot 	if ((n = tfrontp - tbackp) > 0)
7396000Sroot 		n = write(fd, tbackp, n);
7408345Ssam 	if (n < 0)
7418345Ssam 		return;
7426000Sroot 	tbackp += n;
7436000Sroot 	if (tbackp == tfrontp)
7446000Sroot 		tbackp = tfrontp = ttyobuf;
7456000Sroot }
7466000Sroot 
7476000Sroot netflush(fd)
7486000Sroot {
7496000Sroot 	int n;
7506000Sroot 
7516000Sroot 	if ((n = nfrontp - nbackp) > 0)
7526000Sroot 		n = write(fd, nbackp, n);
7536501Ssam 	if (n < 0) {
7546501Ssam 		if (errno != ENOBUFS && errno != EWOULDBLOCK) {
755*8378Ssam 			(void) mode(0);
7568377Ssam 			perror(hostname);
7576501Ssam 			close(fd);
7586501Ssam 			longjmp(peerdied, -1);
7596501Ssam 			/*NOTREACHED*/
7606501Ssam 		}
7616000Sroot 		n = 0;
7626501Ssam 	}
7636000Sroot 	nbackp += n;
7646000Sroot 	if (nbackp == nfrontp)
7656000Sroot 		nbackp = nfrontp = netobuf;
7666000Sroot }
7676024Ssam 
7686293Sroot /*VARARGS*/
7696293Sroot printoption(direction, fmt, option, what)
7706024Ssam 	char *direction, *fmt;
7716293Sroot 	int option, what;
7726024Ssam {
7738345Ssam 	if (!showoptions)
7748345Ssam 		return;
7756024Ssam 	printf("%s ", direction);
7766024Ssam 	if (fmt == doopt)
7776024Ssam 		fmt = "do";
7786024Ssam 	else if (fmt == dont)
7796024Ssam 		fmt = "dont";
7806024Ssam 	else if (fmt == will)
7816024Ssam 		fmt = "will";
7826024Ssam 	else if (fmt == wont)
7836024Ssam 		fmt = "wont";
7846024Ssam 	else
7856024Ssam 		fmt = "???";
7866024Ssam 	if (option < TELOPT_SUPDUP)
7876293Sroot 		printf("%s %s", fmt, telopts[option]);
7886024Ssam 	else
7896293Sroot 		printf("%s %d", fmt, option);
7906293Sroot 	if (*direction == '<') {
7916293Sroot 		printf("\r\n");
7926293Sroot 		return;
7936293Sroot 	}
7946293Sroot 	printf(" (%s)\r\n", what ? "reply" : "don't reply");
7956024Ssam }
796