xref: /csrg-svn/usr.bin/telnet/telnet.c (revision 27088)
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*27088Sminshall static char sccsid[] = "@(#)telnet.c	5.7 (Berkeley) 04/15/86";
1521580Sdist #endif not lint
1621580Sdist 
176000Sroot /*
186000Sroot  * User telnet program.
196000Sroot  */
209217Ssam #include <sys/types.h>
219217Ssam #include <sys/socket.h>
229972Ssam #include <sys/ioctl.h>
239217Ssam 
249217Ssam #include <netinet/in.h>
259217Ssam 
2612212Ssam #define	TELOPTS
2712212Ssam #include <arpa/telnet.h>
2812212Ssam 
296000Sroot #include <stdio.h>
306000Sroot #include <ctype.h>
316000Sroot #include <errno.h>
326000Sroot #include <signal.h>
336000Sroot #include <setjmp.h>
348345Ssam #include <netdb.h>
359217Ssam 
366000Sroot #define	strip(x)	((x)&0177)
376000Sroot 
386000Sroot char	ttyobuf[BUFSIZ], *tfrontp = ttyobuf, *tbackp = ttyobuf;
39*27088Sminshall #define	TTYADD(c)	{ if (!flushing) { *tfrontp++ = c; } }
40*27088Sminshall 
418378Ssam char	netobuf[BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf;
42*27088Sminshall #define	NETADD(c)	{ *nfrontp++ = c; }
43*27088Sminshall #define	NET2ADD(c1,c2)	{ NETADD(c1); NETADD(c2); }
44*27088Sminshall #define NETLOC()	(nfrontp)
45*27088Sminshall char	*neturg = 0;		/* one past last byte of urgent data */
466000Sroot 
476000Sroot char	hisopts[256];
486000Sroot char	myopts[256];
496000Sroot 
506000Sroot char	doopt[] = { IAC, DO, '%', 'c', 0 };
516000Sroot char	dont[] = { IAC, DONT, '%', 'c', 0 };
526000Sroot char	will[] = { IAC, WILL, '%', 'c', 0 };
536000Sroot char	wont[] = { IAC, WONT, '%', 'c', 0 };
546000Sroot 
55*27088Sminshall struct cmd {
56*27088Sminshall 	char	*name;		/* command name */
57*27088Sminshall 	char	*help;		/* help string */
58*27088Sminshall 	int	(*handler)();	/* routine which executes command */
59*27088Sminshall 	int	dohelp;		/* Should we give general help information? */
60*27088Sminshall 	int	needconnect;	/* Do we need to be connected to execute? */
61*27088Sminshall };
62*27088Sminshall 
636000Sroot int	connected;
646000Sroot int	net;
65*27088Sminshall int	tout;
669972Ssam int	showoptions = 0;
677377Sfeldman int	options;
6810339Ssam int	debug = 0;
699972Ssam int	crmod = 0;
70*27088Sminshall int	netdata = 0;
7127021Sminshall static FILE	*NetTrace;
7225289Skarels int	telnetport = 1;
73*27088Sminshall 
74*27088Sminshall int	flushing = 0;		/* are we in TELNET SYNCH mode? */
75*27088Sminshall 
766000Sroot char	*prompt;
779972Ssam char	escape = CTRL(]);
786000Sroot 
796000Sroot char	line[200];
806000Sroot int	margc;
816000Sroot char	*margv[20];
826000Sroot 
836000Sroot jmp_buf	toplevel;
846000Sroot jmp_buf	peerdied;
856000Sroot 
866000Sroot extern	int errno;
876000Sroot 
886000Sroot 
899972Ssam struct sockaddr_in sin;
906000Sroot 
916000Sroot int	intr(), deadpeer();
926000Sroot char	*control();
936000Sroot struct	cmd *getcmd();
948345Ssam struct	servent *sp;
956000Sroot 
9613076Ssam struct	tchars otc;
9713076Ssam struct	ltchars oltc;
9813076Ssam struct	sgttyb ottyb;
998378Ssam 
1006000Sroot main(argc, argv)
1016000Sroot 	int argc;
1026000Sroot 	char *argv[];
1036000Sroot {
1048345Ssam 	sp = getservbyname("telnet", "tcp");
1058345Ssam 	if (sp == 0) {
1068345Ssam 		fprintf(stderr, "telnet: tcp/telnet: unknown service\n");
1078345Ssam 		exit(1);
1088345Ssam 	}
10927021Sminshall 	NetTrace = stdout;
11013076Ssam 	ioctl(0, TIOCGETP, (char *)&ottyb);
11113076Ssam 	ioctl(0, TIOCGETC, (char *)&otc);
11213076Ssam 	ioctl(0, TIOCGLTC, (char *)&oltc);
1136000Sroot 	setbuf(stdin, 0);
1146000Sroot 	setbuf(stdout, 0);
1156000Sroot 	prompt = argv[0];
11617484Sleres 	if (argc > 1 && !strcmp(argv[1], "-d")) {
11717484Sleres 		debug = 1;
11817484Sleres 		argv++;
11917484Sleres 		argc--;
12017484Sleres 	}
12127021Sminshall 	if (argc > 1 && !strcmp(argv[1], "-n")) {
12227021Sminshall 	    argv++;
12327021Sminshall 	    argc--;
12427021Sminshall 	    if (argc > 1) {		/* get file name */
12527021Sminshall 		NetTrace = fopen(argv[1], "w");
12627021Sminshall 		argv++;
12727021Sminshall 		argc--;
12827021Sminshall 		if (NetTrace == NULL) {
12927021Sminshall 		    NetTrace = stdout;
13027021Sminshall 		}
13127021Sminshall 	    }
13227021Sminshall 	}
1336000Sroot 	if (argc != 1) {
1346000Sroot 		if (setjmp(toplevel) != 0)
1356000Sroot 			exit(0);
1366000Sroot 		tn(argc, argv);
1376000Sroot 	}
1386000Sroot 	setjmp(toplevel);
1396000Sroot 	for (;;)
1406000Sroot 		command(1);
1416000Sroot }
1426000Sroot 
1438377Ssam char	*hostname;
1448377Ssam char	hnamebuf[32];
1456000Sroot 
146*27088Sminshall 
147*27088Sminshall char **
148*27088Sminshall genget(name, table, next)
149*27088Sminshall char	*name;		/* name to match */
150*27088Sminshall char	**table;		/* name entry in table */
151*27088Sminshall char	**(*next)();	/* routine to return next entry in table */
1526000Sroot {
153*27088Sminshall 	register char *p, *q;
154*27088Sminshall 	register char **c, **found;
155*27088Sminshall 	register int nmatches, longest;
1566000Sroot 
157*27088Sminshall 	longest = 0;
158*27088Sminshall 	nmatches = 0;
159*27088Sminshall 	found = 0;
160*27088Sminshall 	for (c = table; p = *c; c = (*next)(c)) {
161*27088Sminshall 		for (q = name; *q == *p++; q++)
162*27088Sminshall 			if (*q == 0)		/* exact match? */
163*27088Sminshall 				return (c);
164*27088Sminshall 		if (!*q) {			/* the name was a prefix */
165*27088Sminshall 			if (q - name > longest) {
166*27088Sminshall 				longest = q - name;
167*27088Sminshall 				nmatches = 1;
168*27088Sminshall 				found = c;
169*27088Sminshall 			} else if (q - name == longest)
170*27088Sminshall 				nmatches++;
1718377Ssam 		}
1726000Sroot 	}
173*27088Sminshall 	if (nmatches > 1)
174*27088Sminshall 		return ((char **)-1);
175*27088Sminshall 	return (found);
1766000Sroot }
1776000Sroot 
1786000Sroot 
17913076Ssam struct	tchars notc =	{ -1, -1, -1, -1, -1, -1 };
18013076Ssam struct	ltchars noltc =	{ -1, -1, -1, -1, -1, -1 };
1819972Ssam 
1826000Sroot mode(f)
1836000Sroot 	register int f;
1846000Sroot {
1858378Ssam 	static int prevmode = 0;
18613076Ssam 	struct tchars *tc;
18713076Ssam 	struct ltchars *ltc;
18813076Ssam 	struct sgttyb sb;
18913076Ssam 	int onoff, old;
1906000Sroot 
1918378Ssam 	if (prevmode == f)
1928378Ssam 		return (f);
1938378Ssam 	old = prevmode;
1948378Ssam 	prevmode = f;
19513076Ssam 	sb = ottyb;
1966000Sroot 	switch (f) {
1978378Ssam 
1986000Sroot 	case 0:
1996000Sroot 		onoff = 0;
2009972Ssam 		tc = &otc;
20113076Ssam 		ltc = &oltc;
2026000Sroot 		break;
2036000Sroot 
2046000Sroot 	case 1:
2056000Sroot 	case 2:
20613076Ssam 		sb.sg_flags |= CBREAK;
2078378Ssam 		if (f == 1)
20813076Ssam 			sb.sg_flags &= ~(ECHO|CRMOD);
2098378Ssam 		else
21013076Ssam 			sb.sg_flags |= ECHO|CRMOD;
21113076Ssam 		sb.sg_erase = sb.sg_kill = -1;
2129972Ssam 		tc = &notc;
21313076Ssam 		ltc = &noltc;
2146000Sroot 		onoff = 1;
2159972Ssam 		break;
2169972Ssam 
2179972Ssam 	default:
2189972Ssam 		return;
2196000Sroot 	}
22013076Ssam 	ioctl(fileno(stdin), TIOCSLTC, (char *)ltc);
22113076Ssam 	ioctl(fileno(stdin), TIOCSETC, (char *)tc);
22213076Ssam 	ioctl(fileno(stdin), TIOCSETP, (char *)&sb);
2236000Sroot 	ioctl(fileno(stdin), FIONBIO, &onoff);
2246000Sroot 	ioctl(fileno(stdout), FIONBIO, &onoff);
2256000Sroot 	return (old);
2266000Sroot }
2276000Sroot 
2286000Sroot char	sibuf[BUFSIZ], *sbp;
2296000Sroot char	tibuf[BUFSIZ], *tbp;
2306000Sroot int	scc, tcc;
2316000Sroot 
2326000Sroot /*
2336000Sroot  * Select from tty and network...
2346000Sroot  */
235*27088Sminshall telnet()
2366000Sroot {
2376000Sroot 	register int c;
238*27088Sminshall 	int tin = fileno(stdin);
2396000Sroot 	int on = 1;
2406000Sroot 
241*27088Sminshall 	tout = fileno(stdout);
2428378Ssam 	(void) mode(2);
243*27088Sminshall 	ioctl(net, FIONBIO, &on);
244*27088Sminshall 	if (telnetport && !hisopts[TELOPT_SGA]) {
24517922Sralph 		willoption(TELOPT_SGA);
246*27088Sminshall 	}
2476000Sroot 	for (;;) {
248*27088Sminshall 		long ibits = 0, obits = 0, xbits = 0;
2496000Sroot 
2506000Sroot 		if (nfrontp - nbackp)
251*27088Sminshall 			obits |= (1 << net);
2526000Sroot 		else
2536000Sroot 			ibits |= (1 << tin);
2546000Sroot 		if (tfrontp - tbackp)
2556000Sroot 			obits |= (1 << tout);
2566000Sroot 		else
257*27088Sminshall 			ibits |= (1 << net);
2586000Sroot 		if (scc < 0 && tcc < 0)
2596000Sroot 			break;
260*27088Sminshall 		if (flushing) {
261*27088Sminshall 			xbits = 0;
262*27088Sminshall 		} else {
263*27088Sminshall 			xbits = (1 << net);
264*27088Sminshall 		}
265*27088Sminshall 		select(16, &ibits, &obits, &xbits, 0);
266*27088Sminshall 		if (ibits == 0 && obits == 0 && xbits == 0) {
2676000Sroot 			sleep(5);
2686000Sroot 			continue;
2696000Sroot 		}
2706000Sroot 
2716000Sroot 		/*
272*27088Sminshall 		 * Any urgent data?
273*27088Sminshall 		 */
274*27088Sminshall 		if (xbits) {
275*27088Sminshall 		    flushing = 1;
276*27088Sminshall 		    ttyflush();	/* flush already enqueued data */
277*27088Sminshall 		}
278*27088Sminshall 
279*27088Sminshall 		/*
2806000Sroot 		 * Something to read from the network...
2816000Sroot 		 */
282*27088Sminshall 		if (ibits & (1 << net)) {
283*27088Sminshall 			scc = read(net, sibuf, sizeof (sibuf));
2846000Sroot 			if (scc < 0 && errno == EWOULDBLOCK)
2856000Sroot 				scc = 0;
2866000Sroot 			else {
2876000Sroot 				if (scc <= 0)
2886000Sroot 					break;
2896000Sroot 				sbp = sibuf;
290*27088Sminshall 				if (netdata) {
29127021Sminshall 					Dump('<', sbp, scc);
29227021Sminshall 				}
2936000Sroot 			}
2946000Sroot 		}
2956000Sroot 
2966000Sroot 		/*
2976000Sroot 		 * Something to read from the tty...
2986000Sroot 		 */
2996000Sroot 		if (ibits & (1 << tin)) {
3008378Ssam 			tcc = read(tin, tibuf, sizeof (tibuf));
3016000Sroot 			if (tcc < 0 && errno == EWOULDBLOCK)
3026000Sroot 				tcc = 0;
3036000Sroot 			else {
3046000Sroot 				if (tcc <= 0)
3056000Sroot 					break;
3066000Sroot 				tbp = tibuf;
3076000Sroot 			}
3086000Sroot 		}
3096000Sroot 
3106000Sroot 		while (tcc > 0) {
3116000Sroot 			register int c;
3126000Sroot 
3136000Sroot 			if ((&netobuf[BUFSIZ] - nfrontp) < 2)
3146000Sroot 				break;
3156000Sroot 			c = *tbp++ & 0377, tcc--;
3166000Sroot 			if (strip(c) == escape) {
3176000Sroot 				command(0);
3186000Sroot 				tcc = 0;
3196000Sroot 				break;
3206000Sroot 			}
32117922Sralph 			switch (c) {
32227021Sminshall 			case '\n'|0x80:
32317922Sralph 			case '\n':
32427021Sminshall 				/*
32527021Sminshall 				 * If echoing is happening locally,
32627021Sminshall 				 * then a newline (unix) is CRLF (TELNET).
32727021Sminshall 				 */
328*27088Sminshall 				if (!hisopts[TELOPT_ECHO]) {
329*27088Sminshall 					NETADD('\r');
330*27088Sminshall 				}
331*27088Sminshall 				NETADD('\n');
33217922Sralph 				break;
33327021Sminshall 			case '\r'|0x80:
33417922Sralph 			case '\r':
335*27088Sminshall 				NET2ADD('\r', '\0');
33617922Sralph 				break;
33717922Sralph 			case IAC:
338*27088Sminshall 				NET2ADD(IAC, IAC);
33927021Sminshall 				break;
34017922Sralph 			default:
341*27088Sminshall 				NETADD(c);
34217922Sralph 				break;
34317922Sralph 			}
3446000Sroot 		}
345*27088Sminshall 		if ((obits & (1 << net)) && (nfrontp - nbackp) > 0)
346*27088Sminshall 			netflush(net);
3476000Sroot 		if (scc > 0)
3486000Sroot 			telrcv();
3496000Sroot 		if ((obits & (1 << tout)) && (tfrontp - tbackp) > 0)
350*27088Sminshall 			ttyflush();
3516000Sroot 	}
3528378Ssam 	(void) mode(0);
3536000Sroot }
3546000Sroot 
3556000Sroot /*
3566000Sroot  * Telnet receiver states for fsm
3576000Sroot  */
3586000Sroot #define	TS_DATA		0
3596000Sroot #define	TS_IAC		1
3606000Sroot #define	TS_WILL		2
3616000Sroot #define	TS_WONT		3
3626000Sroot #define	TS_DO		4
3636000Sroot #define	TS_DONT		5
36427021Sminshall #define	TS_CR		6
3656000Sroot 
3666000Sroot telrcv()
3676000Sroot {
3686000Sroot 	register int c;
3696000Sroot 	static int state = TS_DATA;
3706000Sroot 
3716000Sroot 	while (scc > 0) {
3726000Sroot 		c = *sbp++ & 0377, scc--;
3736000Sroot 		switch (state) {
3746000Sroot 
37527021Sminshall 		case TS_CR:
37627021Sminshall 			state = TS_DATA;
37727021Sminshall 			if ((c == '\0') || (c == '\n')) {
37827021Sminshall 			    break;	/* by now, we ignore \n */
37927021Sminshall 			}
38027021Sminshall 
3816000Sroot 		case TS_DATA:
3829972Ssam 			if (c == IAC) {
3836000Sroot 				state = TS_IAC;
3849972Ssam 				continue;
3859972Ssam 			}
38627021Sminshall 			if (c == '\r') {
38727021Sminshall 				if (scc > 0) {
38827021Sminshall 					c = *sbp&0377;
38927021Sminshall 					if (c == 0) {
39027021Sminshall 						sbp++, scc--;
391*27088Sminshall 						TTYADD('\r');
39227021Sminshall 				/*
39327021Sminshall 				 * The following hack is needed since we can't
39427021Sminshall 				 * set CRMOD on output only.  Machines like
39527021Sminshall 				 * MULTICS like to send \r without \n; since
39627021Sminshall 				 * we must turn off CRMOD to get proper input,
39727021Sminshall 				 * the mapping is done here (sigh).
39827021Sminshall 				 */
39927021Sminshall 						if (crmod) {
400*27088Sminshall 							TTYADD('\n');
40127021Sminshall 						}
40227021Sminshall 					} else if (!hisopts[TELOPT_ECHO] &&
40327021Sminshall 								(c == '\n')) {
40427021Sminshall 						sbp++, scc--;
405*27088Sminshall 						TTYADD('\n');
40627021Sminshall 					} else {
407*27088Sminshall 						TTYADD('\r');
40827021Sminshall 					}
40927021Sminshall 				} else {
41027021Sminshall 					state = TS_CR;
411*27088Sminshall 					TTYADD('\r');
41227021Sminshall 				}
41327021Sminshall 			} else {
414*27088Sminshall 				TTYADD(c);
41527021Sminshall 			}
4166000Sroot 			continue;
4176000Sroot 
4186000Sroot 		case TS_IAC:
4196000Sroot 			switch (c) {
4206000Sroot 
4216000Sroot 			case WILL:
4226000Sroot 				state = TS_WILL;
4236000Sroot 				continue;
4246000Sroot 
4256000Sroot 			case WONT:
4266000Sroot 				state = TS_WONT;
4276000Sroot 				continue;
4286000Sroot 
4296000Sroot 			case DO:
4306000Sroot 				state = TS_DO;
4316000Sroot 				continue;
4326000Sroot 
4336000Sroot 			case DONT:
4346000Sroot 				state = TS_DONT;
4356000Sroot 				continue;
4366000Sroot 
4376000Sroot 			case DM:
438*27088Sminshall 				/*
439*27088Sminshall 				 * We may have missed an urgent notification,
440*27088Sminshall 				 * so make sure we flush whatever is in the
441*27088Sminshall 				 * buffer currently.
442*27088Sminshall 				 */
443*27088Sminshall 				flushing = 1;
444*27088Sminshall 				ttyflush();
445*27088Sminshall 				flushing = stilloob(net);
4466000Sroot 				break;
4476000Sroot 
4486000Sroot 			case NOP:
4496000Sroot 			case GA:
4506000Sroot 				break;
4516000Sroot 
4526000Sroot 			default:
4536000Sroot 				break;
4546000Sroot 			}
4556000Sroot 			state = TS_DATA;
4566000Sroot 			continue;
4576000Sroot 
4586000Sroot 		case TS_WILL:
4598345Ssam 			printoption("RCVD", will, c, !hisopts[c]);
4606000Sroot 			if (!hisopts[c])
4616000Sroot 				willoption(c);
4626000Sroot 			state = TS_DATA;
4636000Sroot 			continue;
4646000Sroot 
4656000Sroot 		case TS_WONT:
4668345Ssam 			printoption("RCVD", wont, c, hisopts[c]);
4676000Sroot 			if (hisopts[c])
4686000Sroot 				wontoption(c);
4696000Sroot 			state = TS_DATA;
4706000Sroot 			continue;
4716000Sroot 
4726000Sroot 		case TS_DO:
4738345Ssam 			printoption("RCVD", doopt, c, !myopts[c]);
4746000Sroot 			if (!myopts[c])
4756000Sroot 				dooption(c);
4766000Sroot 			state = TS_DATA;
4776000Sroot 			continue;
4786000Sroot 
4796000Sroot 		case TS_DONT:
4808345Ssam 			printoption("RCVD", dont, c, myopts[c]);
4816000Sroot 			if (myopts[c]) {
4826000Sroot 				myopts[c] = 0;
4836000Sroot 				sprintf(nfrontp, wont, c);
4848378Ssam 				nfrontp += sizeof (wont) - 2;
4858345Ssam 				printoption("SENT", wont, c);
4866000Sroot 			}
4876000Sroot 			state = TS_DATA;
4886000Sroot 			continue;
4896000Sroot 		}
4906000Sroot 	}
4916000Sroot }
4926000Sroot 
4936000Sroot willoption(option)
4946000Sroot 	int option;
4956000Sroot {
4966000Sroot 	char *fmt;
4976000Sroot 
4986000Sroot 	switch (option) {
4996000Sroot 
5006000Sroot 	case TELOPT_ECHO:
5018378Ssam 		(void) mode(1);
5026000Sroot 
5036000Sroot 	case TELOPT_SGA:
5046000Sroot 		hisopts[option] = 1;
5056000Sroot 		fmt = doopt;
5066000Sroot 		break;
5076000Sroot 
5086000Sroot 	case TELOPT_TM:
5096000Sroot 		fmt = dont;
5106000Sroot 		break;
5116000Sroot 
5126000Sroot 	default:
5136000Sroot 		fmt = dont;
5146000Sroot 		break;
5156000Sroot 	}
5166024Ssam 	sprintf(nfrontp, fmt, option);
5178378Ssam 	nfrontp += sizeof (dont) - 2;
5188345Ssam 	printoption("SENT", fmt, option);
5196000Sroot }
5206000Sroot 
5216000Sroot wontoption(option)
5226000Sroot 	int option;
5236000Sroot {
5246000Sroot 	char *fmt;
5256000Sroot 
5266000Sroot 	switch (option) {
5276000Sroot 
5286000Sroot 	case TELOPT_ECHO:
5298378Ssam 		(void) mode(2);
5306000Sroot 
5316000Sroot 	case TELOPT_SGA:
5326000Sroot 		hisopts[option] = 0;
5336000Sroot 		fmt = dont;
5346000Sroot 		break;
5356000Sroot 
5366000Sroot 	default:
5376000Sroot 		fmt = dont;
5386000Sroot 	}
5396000Sroot 	sprintf(nfrontp, fmt, option);
5408378Ssam 	nfrontp += sizeof (doopt) - 2;
5418345Ssam 	printoption("SENT", fmt, option);
5426000Sroot }
5436000Sroot 
5446000Sroot dooption(option)
5456000Sroot 	int option;
5466000Sroot {
5476000Sroot 	char *fmt;
5486000Sroot 
5496000Sroot 	switch (option) {
5506000Sroot 
5516000Sroot 	case TELOPT_TM:
5526000Sroot 		fmt = wont;
5536000Sroot 		break;
5546000Sroot 
55513231Ssam 	case TELOPT_ECHO:
55613231Ssam 		(void) mode(2);
55713231Ssam 		fmt = will;
55813231Ssam 		hisopts[option] = 0;
55913231Ssam 		break;
56013231Ssam 
5616000Sroot 	case TELOPT_SGA:
5626000Sroot 		fmt = will;
5636000Sroot 		break;
5646000Sroot 
5656000Sroot 	default:
5666000Sroot 		fmt = wont;
5676000Sroot 		break;
5686000Sroot 	}
5696000Sroot 	sprintf(nfrontp, fmt, option);
5708378Ssam 	nfrontp += sizeof (doopt) - 2;
5718345Ssam 	printoption("SENT", fmt, option);
5726000Sroot }
5736000Sroot 
5746000Sroot /*
575*27088Sminshall  * Check to see if any out-of-band data exists on a socket (for
576*27088Sminshall  * Telnet "synch" processing).
5776000Sroot  */
5786000Sroot 
579*27088Sminshall int
580*27088Sminshall stilloob(s)
581*27088Sminshall int	s;		/* socket number */
5826024Ssam {
583*27088Sminshall     struct timeval *timeout = { 0 };
584*27088Sminshall     long	excepts = (1<<s);
5859972Ssam 
586*27088Sminshall     if (select(s+1, 0, 0, &excepts, timeout) < 0) {
587*27088Sminshall 	perror("select");
588*27088Sminshall 	quit();
589*27088Sminshall     }
590*27088Sminshall     if (excepts) {
591*27088Sminshall 	return 1;
592*27088Sminshall     } else {
593*27088Sminshall 	return 0;
594*27088Sminshall     }
5956024Ssam }
5966024Ssam 
5976000Sroot /*
5986000Sroot  * Construct a control character sequence
5996000Sroot  * for a special character.
6006000Sroot  */
6016000Sroot char *
6026000Sroot control(c)
6036000Sroot 	register int c;
6046000Sroot {
6056000Sroot 	static char buf[3];
6066000Sroot 
6076000Sroot 	if (c == 0177)
6086000Sroot 		return ("^?");
6096000Sroot 	if (c >= 040) {
6106000Sroot 		buf[0] = c;
6116000Sroot 		buf[1] = 0;
6126000Sroot 	} else {
6136000Sroot 		buf[0] = '^';
6146000Sroot 		buf[1] = '@'+c;
6156000Sroot 		buf[2] = 0;
6166000Sroot 	}
6176000Sroot 	return (buf);
6186000Sroot }
6196000Sroot 
6206000Sroot deadpeer()
6216000Sroot {
6228378Ssam 	(void) mode(0);
6236000Sroot 	longjmp(peerdied, -1);
6246000Sroot }
6256000Sroot 
6266000Sroot intr()
6276000Sroot {
6288378Ssam 	(void) mode(0);
6296000Sroot 	longjmp(toplevel, -1);
6306000Sroot }
6316000Sroot 
632*27088Sminshall ttyflush()
6336000Sroot {
634*27088Sminshall     int n;
6356000Sroot 
636*27088Sminshall     if ((n = tfrontp - tbackp) > 0) {
637*27088Sminshall 	if (!flushing) {
638*27088Sminshall 	    n = write(tout, tbackp, n);
639*27088Sminshall 	} else {
640*27088Sminshall 	    ioctl(fileno(stdout), TIOCFLUSH, 0);
641*27088Sminshall 	}
642*27088Sminshall     }
643*27088Sminshall     if (n < 0) {
644*27088Sminshall 	return;
645*27088Sminshall     }
646*27088Sminshall     tbackp += n;
647*27088Sminshall     if (tbackp == tfrontp) {
648*27088Sminshall 	tbackp = tfrontp = ttyobuf;
649*27088Sminshall     }
6506000Sroot }
6516000Sroot 
6526000Sroot netflush(fd)
6536000Sroot {
654*27088Sminshall     int n;
6556000Sroot 
656*27088Sminshall     if ((n = nfrontp - nbackp) > 0) {
657*27088Sminshall 	if (!neturg) {
658*27088Sminshall 	    n = write(fd, nbackp, n);	/* normal write */
659*27088Sminshall 	} else {
660*27088Sminshall 	    n = neturg - nbackp;
661*27088Sminshall 	    n = send(fd, nbackp, n, MSG_OOB);	/* URGENT data (SYNCH) */
6626501Ssam 	}
663*27088Sminshall     }
664*27088Sminshall     if (n < 0) {
665*27088Sminshall 	if (errno != ENOBUFS && errno != EWOULDBLOCK) {
666*27088Sminshall 	    (void) mode(0);
667*27088Sminshall 	    perror(hostname);
668*27088Sminshall 	    close(fd);
669*27088Sminshall 	    neturg = 0;
670*27088Sminshall 	    longjmp(peerdied, -1);
671*27088Sminshall 	    /*NOTREACHED*/
67227021Sminshall 	}
673*27088Sminshall 	n = 0;
674*27088Sminshall     }
675*27088Sminshall     if (netdata && n) {
676*27088Sminshall 	Dump('>', nbackp, n);
677*27088Sminshall     }
678*27088Sminshall     nbackp += n;
679*27088Sminshall     if (nbackp >= neturg) {
680*27088Sminshall 	neturg = 0;
681*27088Sminshall     }
682*27088Sminshall     if (nbackp == nfrontp) {
683*27088Sminshall 	nbackp = nfrontp = netobuf;
684*27088Sminshall     }
6856000Sroot }
6866024Ssam 
68727021Sminshall static
68827021Sminshall Dump(direction, buffer, length)
68927021Sminshall char	direction;
69027021Sminshall char	*buffer;
69127021Sminshall int	length;
69227021Sminshall {
69327021Sminshall #   define BYTES_PER_LINE	32
69427021Sminshall #   define min(x,y)	((x<y)? x:y)
69527021Sminshall     char *pThis;
69627021Sminshall     int offset;
69727021Sminshall 
69827021Sminshall     offset = 0;
69927021Sminshall 
70027021Sminshall     while (length) {
70127021Sminshall 	/* print one line */
70227021Sminshall 	fprintf(NetTrace, "%c 0x%x\t", direction, offset);
70327021Sminshall 	pThis = buffer;
70427021Sminshall 	buffer = buffer+min(length, BYTES_PER_LINE);
70527021Sminshall 	while (pThis < buffer) {
70627021Sminshall 	    fprintf(NetTrace, "%.2x", (*pThis)&0xff);
70727021Sminshall 	    pThis++;
70827021Sminshall 	}
70927021Sminshall 	fprintf(NetTrace, "\n");
71027021Sminshall 	length -= BYTES_PER_LINE;
71127021Sminshall 	offset += BYTES_PER_LINE;
71227021Sminshall 	if (length < 0) {
71327021Sminshall 	    return;
71427021Sminshall 	}
71527021Sminshall 	/* find next unique line */
71627021Sminshall     }
71727021Sminshall }
71827021Sminshall 
71927021Sminshall 
7206293Sroot /*VARARGS*/
7216293Sroot printoption(direction, fmt, option, what)
7226024Ssam 	char *direction, *fmt;
7236293Sroot 	int option, what;
7246024Ssam {
7258345Ssam 	if (!showoptions)
7268345Ssam 		return;
7276024Ssam 	printf("%s ", direction);
7286024Ssam 	if (fmt == doopt)
7296024Ssam 		fmt = "do";
7306024Ssam 	else if (fmt == dont)
7316024Ssam 		fmt = "dont";
7326024Ssam 	else if (fmt == will)
7336024Ssam 		fmt = "will";
7346024Ssam 	else if (fmt == wont)
7356024Ssam 		fmt = "wont";
7366024Ssam 	else
7376024Ssam 		fmt = "???";
7386024Ssam 	if (option < TELOPT_SUPDUP)
7396293Sroot 		printf("%s %s", fmt, telopts[option]);
7406024Ssam 	else
7416293Sroot 		printf("%s %d", fmt, option);
7426293Sroot 	if (*direction == '<') {
7436293Sroot 		printf("\r\n");
7446293Sroot 		return;
7456293Sroot 	}
7466293Sroot 	printf(" (%s)\r\n", what ? "reply" : "don't reply");
7476024Ssam }
748*27088Sminshall 
749*27088Sminshall /*
750*27088Sminshall  *	The following are data structures and routines for
751*27088Sminshall  *	the "send" command.
752*27088Sminshall  *
753*27088Sminshall  */
754*27088Sminshall 
755*27088Sminshall struct sendlist {
756*27088Sminshall     char	*name;		/* How user refers to it (case independent) */
757*27088Sminshall     int		what;		/* Character to be sent (<0 ==> special) */
758*27088Sminshall     char	*help;		/* Help information (0 ==> no help) */
759*27088Sminshall     int		(*routine)();	/* Routine to perform (for special ops) */
760*27088Sminshall };
761*27088Sminshall 
762*27088Sminshall dosynch(s)
763*27088Sminshall struct sendlist *s;
764*27088Sminshall {
765*27088Sminshall     /* XXX We really should purge the buffer to the network */
766*27088Sminshall     NET2ADD(IAC, DM);
767*27088Sminshall     neturg = NETLOC();
768*27088Sminshall }
769*27088Sminshall 
770*27088Sminshall sendesc()
771*27088Sminshall {
772*27088Sminshall 	NETADD(escape);
773*27088Sminshall }
774*27088Sminshall 
775*27088Sminshall ayt()
776*27088Sminshall {
777*27088Sminshall 	NET2ADD(IAC, AYT);
778*27088Sminshall }
779*27088Sminshall 
780*27088Sminshall intp()
781*27088Sminshall {
782*27088Sminshall 	NET2ADD(IAC, IP);
783*27088Sminshall }
784*27088Sminshall 
785*27088Sminshall 
786*27088Sminshall #define	SENDQUESTION	-1
787*27088Sminshall #define	SEND2QUESTION	-2
788*27088Sminshall #define	SENDESCAPE	-3
789*27088Sminshall 
790*27088Sminshall struct sendlist Sendlist[] = {
791*27088Sminshall     { "synch", SYNCH, "Perform Telnet 'Synch operation'", dosynch },
792*27088Sminshall     { "brk", BREAK, "Send Telnet Break" },
793*27088Sminshall 	{ "break", BREAK, 0 },
794*27088Sminshall     { "ip", IP, "Send Telnet Interrupt Process" },
795*27088Sminshall 	{ "intp", IP, 0 },
796*27088Sminshall 	{ "interrupt", IP, 0 },
797*27088Sminshall 	{ "intr", IP, 0 },
798*27088Sminshall     { "ao", AO, "Send Telnet Abort output" },
799*27088Sminshall 	{ "abort", AO, 0 },
800*27088Sminshall     { "ayt", AYT, "Send Telnet 'Are You There'" },
801*27088Sminshall 	{ "are", AYT, 0 },
802*27088Sminshall 	{ "hello", AYT, 0 },
803*27088Sminshall     { "ec", EC, "Send Telnet Erase Character" },
804*27088Sminshall     { "el", EL, "Send Telnet Erase Line" },
805*27088Sminshall     { "ga", GA, "Send Telnet 'Go Ahead' sequence" },
806*27088Sminshall 	{ "go", GA, 0 },
807*27088Sminshall     { "nop", NOP, "Send Telnet 'No operation'" },
808*27088Sminshall     { "escape", SENDESCAPE, "Send current escape character" },
809*27088Sminshall     { "?", SENDQUESTION, "Display send options" },
810*27088Sminshall 	{ "help", SENDQUESTION, 0 },
811*27088Sminshall     { "??", SEND2QUESTION, "Display all send options (including aliases)" },
812*27088Sminshall     { 0 }
813*27088Sminshall };
814*27088Sminshall 
815*27088Sminshall char **
816*27088Sminshall getnextsend(name)
817*27088Sminshall char *name;
818*27088Sminshall {
819*27088Sminshall     struct sendlist *c = (struct sendlist *) name;
820*27088Sminshall 
821*27088Sminshall     return (char **) (c+1);
822*27088Sminshall }
823*27088Sminshall 
824*27088Sminshall struct sendlist *
825*27088Sminshall getsend(name)
826*27088Sminshall char *name;
827*27088Sminshall {
828*27088Sminshall     return (struct sendlist *) genget(name, (char **) Sendlist, getnextsend);
829*27088Sminshall }
830*27088Sminshall 
831*27088Sminshall sendcmd(argc, argv)
832*27088Sminshall int	argc;
833*27088Sminshall char	**argv;
834*27088Sminshall {
835*27088Sminshall     int what;		/* what we are sending this time */
836*27088Sminshall     int count;		/* how many bytes we are going to need to send */
837*27088Sminshall     int hadsynch;	/* are we going to process a "synch"? */
838*27088Sminshall     int i;
839*27088Sminshall     struct sendlist *s;	/* pointer to current command */
840*27088Sminshall 
841*27088Sminshall     if (argc < 2) {
842*27088Sminshall 	printf("need at least one argument for 'send' command\n");
843*27088Sminshall 	printf("'send ?' for help\n");
844*27088Sminshall 	return;
845*27088Sminshall     }
846*27088Sminshall     /*
847*27088Sminshall      * First, validate all the send arguments.
848*27088Sminshall      * In addition, we see how much space we are going to need, and
849*27088Sminshall      * whether or not we will be doing a "SYNCH" operation (which
850*27088Sminshall      * flushes the network queue).
851*27088Sminshall      */
852*27088Sminshall     count = 0;
853*27088Sminshall     hadsynch = 0;
854*27088Sminshall     for (i = 1; i < argc; i++) {
855*27088Sminshall 	s = getsend(argv[i]);
856*27088Sminshall 	if (s == 0) {
857*27088Sminshall 	    printf("Unknown send argument '%s'\n'send ?' for help.\n",
858*27088Sminshall 			argv[i]);
859*27088Sminshall 	    return;
860*27088Sminshall 	} else if (s == (struct sendlist *) -1) {
861*27088Sminshall 	    printf("Ambiguous send argument '%s'\n'send ?' for help.\n",
862*27088Sminshall 			argv[i]);
863*27088Sminshall 	    return;
864*27088Sminshall 	}
865*27088Sminshall 	switch (s->what) {
866*27088Sminshall 	case SENDQUESTION:
867*27088Sminshall 	case SEND2QUESTION:
868*27088Sminshall 	    break;
869*27088Sminshall 	case SENDESCAPE:
870*27088Sminshall 	    count += 1;
871*27088Sminshall 	    break;
872*27088Sminshall 	case SYNCH:
873*27088Sminshall 	    hadsynch = 1;
874*27088Sminshall 	    count += 2;
875*27088Sminshall 	    break;
876*27088Sminshall 	default:
877*27088Sminshall 	    count += 2;
878*27088Sminshall 	    break;
879*27088Sminshall 	}
880*27088Sminshall     }
881*27088Sminshall     /* Now, do we have enough room? */
882*27088Sminshall     if (netobuf+sizeof netobuf-nfrontp-1 < count) {
883*27088Sminshall 	printf("There is not enough room in the buffer TO the network\n");
884*27088Sminshall 	printf("to process your request.  Nothing will be done.\n");
885*27088Sminshall 	printf("('send synch' will throw away most data in the network\n");
886*27088Sminshall 	printf("buffer, if this might help.)\n");
887*27088Sminshall 	return;
888*27088Sminshall     }
889*27088Sminshall     /* OK, they are all OK, now go through again and actually send */
890*27088Sminshall     for (i = 1; i < argc; i++) {
891*27088Sminshall 	if (!(s = getsend(argv[i]))) {
892*27088Sminshall 	    fprintf(stderr, "Telnet 'send' error - argument disappeared!\n");
893*27088Sminshall 	    quit();
894*27088Sminshall 	    /*NOTREACHED*/
895*27088Sminshall 	}
896*27088Sminshall 	if (s->routine) {
897*27088Sminshall 	    (*s->routine)(s);
898*27088Sminshall 	} else {
899*27088Sminshall 	    switch (what = s->what) {
900*27088Sminshall 	    case SENDQUESTION:
901*27088Sminshall 	    case SEND2QUESTION:
902*27088Sminshall 		for (s = Sendlist; s->name; s++) {
903*27088Sminshall 		    if (s->help || (what == SEND2QUESTION)) {
904*27088Sminshall 			printf(s->name);
905*27088Sminshall 			if (s->help) {
906*27088Sminshall 			    printf("\t%s", s->help);
907*27088Sminshall 			}
908*27088Sminshall 			printf("\n");
909*27088Sminshall 		    }
910*27088Sminshall 		}
911*27088Sminshall 		break;
912*27088Sminshall 	    case SENDESCAPE:
913*27088Sminshall 		NETADD(escape);
914*27088Sminshall 		break;
915*27088Sminshall 	    default:
916*27088Sminshall 		NET2ADD(IAC, what);
917*27088Sminshall 		break;
918*27088Sminshall 	    }
919*27088Sminshall 	}
920*27088Sminshall     }
921*27088Sminshall }
922*27088Sminshall 
923*27088Sminshall /*
924*27088Sminshall  * The following are the routines and data structures referred
925*27088Sminshall  * to by the arguments to the "toggle" command.
926*27088Sminshall  */
927*27088Sminshall 
928*27088Sminshall setdebug()
929*27088Sminshall {
930*27088Sminshall 
931*27088Sminshall 	debug = debug ? 0 : 1;
932*27088Sminshall 	printf("%s turn on socket level debugging.\n",
933*27088Sminshall 		debug ? "Will" : "Won't");
934*27088Sminshall 	fflush(stdout);
935*27088Sminshall 	if (net > 0 &&
936*27088Sminshall 	    setsockopt(net, SOL_SOCKET, SO_DEBUG, &debug, sizeof(debug)) < 0)
937*27088Sminshall 		perror("setsockopt (SO_DEBUG)");
938*27088Sminshall }
939*27088Sminshall 
940*27088Sminshall static
941*27088Sminshall setnetdata()
942*27088Sminshall {
943*27088Sminshall 
944*27088Sminshall 	netdata = !netdata;
945*27088Sminshall 	printf("%s turn on printing of raw network traffic.\n",
946*27088Sminshall 		netdata ? "Will" : "Wont");
947*27088Sminshall }
948*27088Sminshall 
949*27088Sminshall setoptions()
950*27088Sminshall {
951*27088Sminshall 
952*27088Sminshall 	showoptions = !showoptions;
953*27088Sminshall 	printf("%s show option processing.\n", showoptions ? "Will" : "Won't");
954*27088Sminshall 	fflush(stdout);
955*27088Sminshall }
956*27088Sminshall 
957*27088Sminshall int togglehelp();
958*27088Sminshall 
959*27088Sminshall struct cmd togglelist[] = {
960*27088Sminshall     { "debug", "toggle debugging", setdebug, 1 },
961*27088Sminshall     { "options", "toggle viewing of options processing", setoptions, 1 },
962*27088Sminshall     { "netdata", "toggle printing of hexadecimal network data",
963*27088Sminshall 							setnetdata, 1 },
964*27088Sminshall     { "?", "display help information", togglehelp, 1 },
965*27088Sminshall     { "help", "display help information", togglehelp, 0 },
966*27088Sminshall     { 0 }
967*27088Sminshall };
968*27088Sminshall 
969*27088Sminshall togglehelp()
970*27088Sminshall {
971*27088Sminshall     struct cmd *c;
972*27088Sminshall 
973*27088Sminshall     for (c = togglelist; c->name; c++) {
974*27088Sminshall 	if (c->dohelp) {
975*27088Sminshall 	    printf("%s\t%s\n", c->name, c->help);
976*27088Sminshall 	}
977*27088Sminshall     }
978*27088Sminshall }
979*27088Sminshall 
980*27088Sminshall char **
981*27088Sminshall getnexttoggle(name)
982*27088Sminshall char *name;
983*27088Sminshall {
984*27088Sminshall     struct cmd *c = (struct cmd *) name;
985*27088Sminshall 
986*27088Sminshall     return (char **) (c+1);
987*27088Sminshall }
988*27088Sminshall 
989*27088Sminshall struct cmd *
990*27088Sminshall gettoggle(name)
991*27088Sminshall char *name;
992*27088Sminshall {
993*27088Sminshall     return (struct cmd *) genget(name, (char **) togglelist, getnexttoggle);
994*27088Sminshall }
995*27088Sminshall 
996*27088Sminshall toggle(argc, argv)
997*27088Sminshall int	argc;
998*27088Sminshall char	*argv[];
999*27088Sminshall {
1000*27088Sminshall     char *name;
1001*27088Sminshall     struct cmd *c;
1002*27088Sminshall 
1003*27088Sminshall     if (argc < 2) {
1004*27088Sminshall 	fprintf(stderr,
1005*27088Sminshall 	    "Need an argument to 'toggle' command.  'toggle ?' for help.\n");
1006*27088Sminshall 	return;
1007*27088Sminshall     }
1008*27088Sminshall     argc--;
1009*27088Sminshall     argv++;
1010*27088Sminshall     while (argc--) {
1011*27088Sminshall 	name = *argv++;
1012*27088Sminshall 	c = gettoggle(name);
1013*27088Sminshall 	if (c == (struct cmd *) -1) {
1014*27088Sminshall 	    fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n",
1015*27088Sminshall 					name);
1016*27088Sminshall 	} else if (c == 0) {
1017*27088Sminshall 	    fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n",
1018*27088Sminshall 					name);
1019*27088Sminshall 	} else {
1020*27088Sminshall 	    (*c->handler)(c);
1021*27088Sminshall 	}
1022*27088Sminshall     }
1023*27088Sminshall }
1024*27088Sminshall 
1025*27088Sminshall /*
1026*27088Sminshall  * The following are the data structures, and many of the routines,
1027*27088Sminshall  * relating to command processing.
1028*27088Sminshall  */
1029*27088Sminshall 
1030*27088Sminshall /*
1031*27088Sminshall  * Set the escape character.
1032*27088Sminshall  */
1033*27088Sminshall setescape(argc, argv)
1034*27088Sminshall 	int argc;
1035*27088Sminshall 	char *argv[];
1036*27088Sminshall {
1037*27088Sminshall 	register char *arg;
1038*27088Sminshall 	char buf[50];
1039*27088Sminshall 
1040*27088Sminshall 	if (argc > 2)
1041*27088Sminshall 		arg = argv[1];
1042*27088Sminshall 	else {
1043*27088Sminshall 		printf("new escape character: ");
1044*27088Sminshall 		gets(buf);
1045*27088Sminshall 		arg = buf;
1046*27088Sminshall 	}
1047*27088Sminshall 	if (arg[0] != '\0')
1048*27088Sminshall 		escape = arg[0];
1049*27088Sminshall 	printf("Escape character is '%s'.\n", control(escape));
1050*27088Sminshall 	fflush(stdout);
1051*27088Sminshall }
1052*27088Sminshall 
1053*27088Sminshall /*VARARGS*/
1054*27088Sminshall setcrmod()
1055*27088Sminshall {
1056*27088Sminshall 
1057*27088Sminshall 	crmod = !crmod;
1058*27088Sminshall 	printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't");
1059*27088Sminshall 	fflush(stdout);
1060*27088Sminshall }
1061*27088Sminshall 
1062*27088Sminshall /*VARARGS*/
1063*27088Sminshall suspend()
1064*27088Sminshall {
1065*27088Sminshall 	register int save;
1066*27088Sminshall 
1067*27088Sminshall 	save = mode(0);
1068*27088Sminshall 	kill(0, SIGTSTP);
1069*27088Sminshall 	/* reget parameters in case they were changed */
1070*27088Sminshall 	ioctl(0, TIOCGETP, (char *)&ottyb);
1071*27088Sminshall 	ioctl(0, TIOCGETC, (char *)&otc);
1072*27088Sminshall 	ioctl(0, TIOCGLTC, (char *)&oltc);
1073*27088Sminshall 	(void) mode(save);
1074*27088Sminshall }
1075*27088Sminshall 
1076*27088Sminshall /*VARARGS*/
1077*27088Sminshall bye()
1078*27088Sminshall {
1079*27088Sminshall 	register char *op;
1080*27088Sminshall 
1081*27088Sminshall 	(void) mode(0);
1082*27088Sminshall 	if (connected) {
1083*27088Sminshall 		shutdown(net, 2);
1084*27088Sminshall 		printf("Connection closed.\n");
1085*27088Sminshall 		close(net);
1086*27088Sminshall 		connected = 0;
1087*27088Sminshall 		/* reset his options */
1088*27088Sminshall 		for (op = hisopts; op < &hisopts[256]; op++)
1089*27088Sminshall 			*op = 0;
1090*27088Sminshall 	}
1091*27088Sminshall }
1092*27088Sminshall 
1093*27088Sminshall /*VARARGS*/
1094*27088Sminshall quit()
1095*27088Sminshall {
1096*27088Sminshall 	call(bye, "bye", 0);
1097*27088Sminshall 	exit(0);
1098*27088Sminshall }
1099*27088Sminshall 
1100*27088Sminshall /*
1101*27088Sminshall  * Print status about the connection.
1102*27088Sminshall  */
1103*27088Sminshall /*VARARGS*/
1104*27088Sminshall status()
1105*27088Sminshall {
1106*27088Sminshall 	if (connected)
1107*27088Sminshall 		printf("Connected to %s.\n", hostname);
1108*27088Sminshall 	else
1109*27088Sminshall 		printf("No connection.\n");
1110*27088Sminshall 	printf("Escape character is '%s'.\n", control(escape));
1111*27088Sminshall 	fflush(stdout);
1112*27088Sminshall }
1113*27088Sminshall 
1114*27088Sminshall tn(argc, argv)
1115*27088Sminshall 	int argc;
1116*27088Sminshall 	char *argv[];
1117*27088Sminshall {
1118*27088Sminshall 	register int c;
1119*27088Sminshall 	register struct hostent *host = 0;
1120*27088Sminshall 
1121*27088Sminshall 	if (connected) {
1122*27088Sminshall 		printf("?Already connected to %s\n", hostname);
1123*27088Sminshall 		return;
1124*27088Sminshall 	}
1125*27088Sminshall 	if (argc < 2) {
1126*27088Sminshall 		strcpy(line, "Connect ");
1127*27088Sminshall 		printf("(to) ");
1128*27088Sminshall 		gets(&line[strlen(line)]);
1129*27088Sminshall 		makeargv();
1130*27088Sminshall 		argc = margc;
1131*27088Sminshall 		argv = margv;
1132*27088Sminshall 	}
1133*27088Sminshall 	if (argc > 3) {
1134*27088Sminshall 		printf("usage: %s host-name [port]\n", argv[0]);
1135*27088Sminshall 		return;
1136*27088Sminshall 	}
1137*27088Sminshall 	sin.sin_addr.s_addr = inet_addr(argv[1]);
1138*27088Sminshall 	if (sin.sin_addr.s_addr != -1) {
1139*27088Sminshall 		sin.sin_family = AF_INET;
1140*27088Sminshall 		strcpy(hnamebuf, argv[1]);
1141*27088Sminshall 		hostname = hnamebuf;
1142*27088Sminshall 	} else {
1143*27088Sminshall 		host = gethostbyname(argv[1]);
1144*27088Sminshall 		if (host) {
1145*27088Sminshall 			sin.sin_family = host->h_addrtype;
1146*27088Sminshall 			bcopy(host->h_addr_list[0], (caddr_t)&sin.sin_addr,
1147*27088Sminshall 				host->h_length);
1148*27088Sminshall 			hostname = host->h_name;
1149*27088Sminshall 		} else {
1150*27088Sminshall 			printf("%s: unknown host\n", argv[1]);
1151*27088Sminshall 			return;
1152*27088Sminshall 		}
1153*27088Sminshall 	}
1154*27088Sminshall 	sin.sin_port = sp->s_port;
1155*27088Sminshall 	if (argc == 3) {
1156*27088Sminshall 		sin.sin_port = atoi(argv[2]);
1157*27088Sminshall 		if (sin.sin_port <= 0) {
1158*27088Sminshall 			sp = getservbyname(argv[2], "tcp");
1159*27088Sminshall 			if (sp)
1160*27088Sminshall 				sin.sin_port = sp->s_port;
1161*27088Sminshall 			else {
1162*27088Sminshall 				printf("%s: bad port number\n", argv[2]);
1163*27088Sminshall 				return;
1164*27088Sminshall 			}
1165*27088Sminshall 		} else {
1166*27088Sminshall 			sin.sin_port = atoi(argv[2]);
1167*27088Sminshall 			sin.sin_port = htons(sin.sin_port);
1168*27088Sminshall 		}
1169*27088Sminshall 		telnetport = 0;
1170*27088Sminshall 	}
1171*27088Sminshall 	signal(SIGINT, intr);
1172*27088Sminshall 	signal(SIGPIPE, deadpeer);
1173*27088Sminshall 	printf("Trying...\n");
1174*27088Sminshall 	do {
1175*27088Sminshall 		net = socket(AF_INET, SOCK_STREAM, 0);
1176*27088Sminshall 		if (net < 0) {
1177*27088Sminshall 			perror("telnet: socket");
1178*27088Sminshall 			return;
1179*27088Sminshall 		}
1180*27088Sminshall 		if (debug && setsockopt(net, SOL_SOCKET, SO_DEBUG, &debug,
1181*27088Sminshall 		    sizeof(debug)) < 0)
1182*27088Sminshall 			perror("setsockopt (SO_DEBUG)");
1183*27088Sminshall 		if (connect(net, (caddr_t)&sin, sizeof (sin)) < 0) {
1184*27088Sminshall 			if (host && host->h_addr_list[1]) {
1185*27088Sminshall 				int oerrno = errno;
1186*27088Sminshall 
1187*27088Sminshall 				fprintf(stderr,
1188*27088Sminshall 				    "telnet: connect to address %s: ",
1189*27088Sminshall 				    inet_ntoa(sin.sin_addr));
1190*27088Sminshall 				errno = oerrno;
1191*27088Sminshall 				perror(0);
1192*27088Sminshall 				host->h_addr_list++;
1193*27088Sminshall 				bcopy(host->h_addr_list[0],
1194*27088Sminshall 				    (caddr_t)&sin.sin_addr, host->h_length);
1195*27088Sminshall 				fprintf(stderr, "Trying %s...\n",
1196*27088Sminshall 					inet_ntoa(sin.sin_addr));
1197*27088Sminshall 				(void) close(net);
1198*27088Sminshall 				continue;
1199*27088Sminshall 			}
1200*27088Sminshall 			perror("telnet: connect");
1201*27088Sminshall 			signal(SIGINT, SIG_DFL);
1202*27088Sminshall 			return;
1203*27088Sminshall 		}
1204*27088Sminshall 		connected++;
1205*27088Sminshall 	} while (connected == 0);
1206*27088Sminshall 	call(status, "status", 0);
1207*27088Sminshall 	if (setjmp(peerdied) == 0)
1208*27088Sminshall 		telnet();
1209*27088Sminshall 	fprintf(stderr, "Connection closed by foreign host.\n");
1210*27088Sminshall 	exit(1);
1211*27088Sminshall }
1212*27088Sminshall 
1213*27088Sminshall 
1214*27088Sminshall #define HELPINDENT (sizeof ("connect"))
1215*27088Sminshall 
1216*27088Sminshall char	openhelp[] =	"connect to a site";
1217*27088Sminshall char	closehelp[] =	"close current connection";
1218*27088Sminshall char	quithelp[] =	"exit telnet";
1219*27088Sminshall char	zhelp[] =	"suspend telnet";
1220*27088Sminshall char	escapehelp[] =	"set escape character";
1221*27088Sminshall char	statushelp[] =	"print status information";
1222*27088Sminshall char	helphelp[] =	"print help information";
1223*27088Sminshall char	crmodhelp[] =	"toggle mapping of received carriage returns";
1224*27088Sminshall char	togglestring[] = "toggle various (debugging) options";
1225*27088Sminshall char	sendhelp[] =	"transmit special characters";
1226*27088Sminshall 
1227*27088Sminshall int	help();
1228*27088Sminshall 
1229*27088Sminshall struct cmd cmdtab[] = {
1230*27088Sminshall 	{ "open",	openhelp,	tn, 1, 0 },
1231*27088Sminshall 	{ "close",	closehelp,	bye, 1, 1 },
1232*27088Sminshall 	{ "quit",	quithelp,	quit, 1, 0 },
1233*27088Sminshall 	{ "z",		zhelp,		suspend, 1, 0 },
1234*27088Sminshall 	{ "escape",	escapehelp,	setescape, 1, 0 },
1235*27088Sminshall 	{ "status",	statushelp,	status, 1, 0 },
1236*27088Sminshall 	{ "crmod",	crmodhelp,	setcrmod, 1, 0 },
1237*27088Sminshall 	{ "send",	sendhelp,	sendcmd, 1, 1 },
1238*27088Sminshall 	    { "transmit",	sendhelp,	sendcmd, 0, 1 },
1239*27088Sminshall 	    { "xmit",		sendhelp,	sendcmd, 0, 1 },
1240*27088Sminshall 	{ "toggle",	togglestring,	toggle, 1, 0 },
1241*27088Sminshall 	{ "?",		helphelp,	help, 1, 0 },
1242*27088Sminshall 	{ "help",	helphelp,	help, 0, 0 },
1243*27088Sminshall 	0
1244*27088Sminshall };
1245*27088Sminshall 
1246*27088Sminshall 
1247*27088Sminshall /*
1248*27088Sminshall  * Help command.
1249*27088Sminshall  */
1250*27088Sminshall help(argc, argv)
1251*27088Sminshall 	int argc;
1252*27088Sminshall 	char *argv[];
1253*27088Sminshall {
1254*27088Sminshall 	register struct cmd *c;
1255*27088Sminshall 
1256*27088Sminshall 	if (argc == 1) {
1257*27088Sminshall 		printf("Commands may be abbreviated.  Commands are:\n\n");
1258*27088Sminshall 		for (c = cmdtab; c->name; c++)
1259*27088Sminshall 			if (c->dohelp) {
1260*27088Sminshall 				printf("%-*s\t%s\n", HELPINDENT, c->name,
1261*27088Sminshall 								    c->help);
1262*27088Sminshall 			}
1263*27088Sminshall 		return;
1264*27088Sminshall 	}
1265*27088Sminshall 	while (--argc > 0) {
1266*27088Sminshall 		register char *arg;
1267*27088Sminshall 		arg = *++argv;
1268*27088Sminshall 		c = getcmd(arg);
1269*27088Sminshall 		if (c == (struct cmd *)-1)
1270*27088Sminshall 			printf("?Ambiguous help command %s\n", arg);
1271*27088Sminshall 		else if (c == (struct cmd *)0)
1272*27088Sminshall 			printf("?Invalid help command %s\n", arg);
1273*27088Sminshall 		else
1274*27088Sminshall 			printf("%s\n", c->help);
1275*27088Sminshall 	}
1276*27088Sminshall }
1277*27088Sminshall /*
1278*27088Sminshall  * Call routine with argc, argv set from args (terminated by 0).
1279*27088Sminshall  * VARARGS2
1280*27088Sminshall  */
1281*27088Sminshall call(routine, args)
1282*27088Sminshall 	int (*routine)();
1283*27088Sminshall 	int args;
1284*27088Sminshall {
1285*27088Sminshall 	register int *argp;
1286*27088Sminshall 	register int argc;
1287*27088Sminshall 
1288*27088Sminshall 	for (argc = 0, argp = &args; *argp++ != 0; argc++)
1289*27088Sminshall 		;
1290*27088Sminshall 	(*routine)(argc, &args);
1291*27088Sminshall }
1292*27088Sminshall 
1293*27088Sminshall makeargv()
1294*27088Sminshall {
1295*27088Sminshall 	register char *cp;
1296*27088Sminshall 	register char **argp = margv;
1297*27088Sminshall 
1298*27088Sminshall 	margc = 0;
1299*27088Sminshall 	for (cp = line; *cp;) {
1300*27088Sminshall 		while (isspace(*cp))
1301*27088Sminshall 			cp++;
1302*27088Sminshall 		if (*cp == '\0')
1303*27088Sminshall 			break;
1304*27088Sminshall 		*argp++ = cp;
1305*27088Sminshall 		margc += 1;
1306*27088Sminshall 		while (*cp != '\0' && !isspace(*cp))
1307*27088Sminshall 			cp++;
1308*27088Sminshall 		if (*cp == '\0')
1309*27088Sminshall 			break;
1310*27088Sminshall 		*cp++ = '\0';
1311*27088Sminshall 	}
1312*27088Sminshall 	*argp++ = 0;
1313*27088Sminshall }
1314*27088Sminshall 
1315*27088Sminshall char **
1316*27088Sminshall getnextcmd(name)
1317*27088Sminshall char *name;
1318*27088Sminshall {
1319*27088Sminshall     struct cmd *c = (struct cmd *) name;
1320*27088Sminshall 
1321*27088Sminshall     return (char **) (c+1);
1322*27088Sminshall }
1323*27088Sminshall 
1324*27088Sminshall struct cmd *
1325*27088Sminshall getcmd(name)
1326*27088Sminshall char *name;
1327*27088Sminshall {
1328*27088Sminshall     return (struct cmd *) genget(name, (char **) cmdtab, getnextcmd);
1329*27088Sminshall }
1330*27088Sminshall 
1331*27088Sminshall command(top)
1332*27088Sminshall 	int top;
1333*27088Sminshall {
1334*27088Sminshall 	register struct cmd *c;
1335*27088Sminshall 	int oldmode, wasopen;
1336*27088Sminshall 
1337*27088Sminshall 	oldmode = mode(0);
1338*27088Sminshall 	if (!top)
1339*27088Sminshall 		putchar('\n');
1340*27088Sminshall 	else
1341*27088Sminshall 		signal(SIGINT, SIG_DFL);
1342*27088Sminshall 	for (;;) {
1343*27088Sminshall 		printf("%s> ", prompt);
1344*27088Sminshall 		if (gets(line) == 0) {
1345*27088Sminshall 			if (feof(stdin))
1346*27088Sminshall 				quit();
1347*27088Sminshall 			break;
1348*27088Sminshall 		}
1349*27088Sminshall 		if (line[0] == 0)
1350*27088Sminshall 			break;
1351*27088Sminshall 		makeargv();
1352*27088Sminshall 		c = getcmd(margv[0]);
1353*27088Sminshall 		if (c == (struct cmd *)-1) {
1354*27088Sminshall 			printf("?Ambiguous command\n");
1355*27088Sminshall 			continue;
1356*27088Sminshall 		}
1357*27088Sminshall 		if (c == 0) {
1358*27088Sminshall 			printf("?Invalid command\n");
1359*27088Sminshall 			continue;
1360*27088Sminshall 		}
1361*27088Sminshall 		if (c->needconnect && !connected) {
1362*27088Sminshall 			printf("?Need to be connected first.\n");
1363*27088Sminshall 			continue;
1364*27088Sminshall 		}
1365*27088Sminshall 		(*c->handler)(margc, margv);
1366*27088Sminshall 		if (c->handler != help)
1367*27088Sminshall 			break;
1368*27088Sminshall 	}
1369*27088Sminshall 	if (!top) {
1370*27088Sminshall 		if (!connected)
1371*27088Sminshall 			longjmp(toplevel, 1);
1372*27088Sminshall 		(void) mode(oldmode);
1373*27088Sminshall 	}
1374*27088Sminshall }
1375