xref: /csrg-svn/usr.bin/telnet/telnet.c (revision 27186)
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*27186Sminshall static char sccsid[] = "@(#)telnet.c	5.10 (Berkeley) 04/19/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>
2327178Sminshall #include <sys/time.h>
249217Ssam 
259217Ssam #include <netinet/in.h>
269217Ssam 
2712212Ssam #define	TELOPTS
2812212Ssam #include <arpa/telnet.h>
29*27186Sminshall #include <arpa/inet.h>
3012212Ssam 
316000Sroot #include <stdio.h>
326000Sroot #include <ctype.h>
336000Sroot #include <errno.h>
346000Sroot #include <signal.h>
356000Sroot #include <setjmp.h>
368345Ssam #include <netdb.h>
37*27186Sminshall #include <strings.h>
389217Ssam 
3927178Sminshall 
4027178Sminshall 
4127178Sminshall /*
4227178Sminshall  * The following is defined just in case someone should want to run
4327178Sminshall  * this telnet on a 4.2 system.
4427178Sminshall  *
4527178Sminshall  * This has never been tested, so good luck...
4627178Sminshall  */
4727178Sminshall #ifndef	FD_SETSIZE
4827178Sminshall 
4927178Sminshall typedef long	fd_set;
5027178Sminshall 
5127178Sminshall #define	FD_SET(n, p)	(*(p) |= (1<<(n)))
5227178Sminshall #define	FD_CLR(n, p)	(*(p) &= ~(1<<(n)))
5327178Sminshall #define	FD_ISSET(n, p)	(*(p) & (1<<(n)))
5427178Sminshall #define FD_ZERO(p)	(*(p) = 0)
5527178Sminshall 
5627178Sminshall #endif
5727178Sminshall 
58*27186Sminshall #define	strip(x)	((x)&0x3f)
596000Sroot 
606000Sroot char	ttyobuf[BUFSIZ], *tfrontp = ttyobuf, *tbackp = ttyobuf;
61*27186Sminshall #define	TTYADD(c)	{ if (!SYNCHing) { *tfrontp++ = c; } }
6227088Sminshall 
638378Ssam char	netobuf[BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf;
6427088Sminshall #define	NETADD(c)	{ *nfrontp++ = c; }
6527088Sminshall #define	NET2ADD(c1,c2)	{ NETADD(c1); NETADD(c2); }
6627088Sminshall #define NETLOC()	(nfrontp)
6727088Sminshall char	*neturg = 0;		/* one past last byte of urgent data */
686000Sroot 
696000Sroot char	hisopts[256];
706000Sroot char	myopts[256];
716000Sroot 
726000Sroot char	doopt[] = { IAC, DO, '%', 'c', 0 };
736000Sroot char	dont[] = { IAC, DONT, '%', 'c', 0 };
746000Sroot char	will[] = { IAC, WILL, '%', 'c', 0 };
756000Sroot char	wont[] = { IAC, WONT, '%', 'c', 0 };
766000Sroot 
7727088Sminshall struct cmd {
7827088Sminshall 	char	*name;		/* command name */
7927088Sminshall 	char	*help;		/* help string */
8027088Sminshall 	int	(*handler)();	/* routine which executes command */
8127088Sminshall 	int	dohelp;		/* Should we give general help information? */
8227088Sminshall 	int	needconnect;	/* Do we need to be connected to execute? */
8327088Sminshall };
8427088Sminshall 
856000Sroot int	connected;
866000Sroot int	net;
8727088Sminshall int	tout;
889972Ssam int	showoptions = 0;
8910339Ssam int	debug = 0;
909972Ssam int	crmod = 0;
9127088Sminshall int	netdata = 0;
9227021Sminshall static FILE	*NetTrace;
9325289Skarels int	telnetport = 1;
9427088Sminshall 
9527088Sminshall 
966000Sroot char	*prompt;
979972Ssam char	escape = CTRL(]);
9827110Sminshall char	echoc = CTRL(E);
996000Sroot 
100*27186Sminshall int	SYNCHing = 0;		/* we are in TELNET SYNCH mode */
101*27186Sminshall int	flushout = 0;		/* flush output */
102*27186Sminshall int	autosynch = 0;		/* send interrupt characters with SYNCH? */
103*27186Sminshall int	localsigs = 0;		/* we recognize interrupt/quit */
104*27186Sminshall int	donelclsigs = 0;	/* the user has set "localsigs" */
105*27186Sminshall int	doechocharrecognition = 1;	/* in line mode recognize echo toggle */
106*27186Sminshall int	dontlecho = 0;		/* do we suppress local echoing right now? */
107*27186Sminshall 
1086000Sroot char	line[200];
1096000Sroot int	margc;
1106000Sroot char	*margv[20];
1116000Sroot 
1126000Sroot jmp_buf	toplevel;
1136000Sroot jmp_buf	peerdied;
1146000Sroot 
1156000Sroot extern	int errno;
1166000Sroot 
1176000Sroot 
1189972Ssam struct sockaddr_in sin;
1196000Sroot 
1206000Sroot struct	cmd *getcmd();
1218345Ssam struct	servent *sp;
1226000Sroot 
12327110Sminshall struct	tchars otc, ntc;
12413076Ssam struct	ltchars oltc;
12527110Sminshall struct	sgttyb ottyb, nttyb;
12627110Sminshall int	globalmode = 0;
12727110Sminshall int	flushline = 1;
1288378Ssam 
12927110Sminshall char	*hostname;
13027110Sminshall char	hnamebuf[32];
13127110Sminshall 
13227110Sminshall /*
13327110Sminshall  * The following are some clocks used to decide how to interpret
13427178Sminshall  * the relationship between various variables.
13527110Sminshall  */
13627110Sminshall 
13727110Sminshall struct {
13827110Sminshall     int
13927110Sminshall 	system,			/* what the current time is */
14027110Sminshall 	echotoggle,		/* last time user entered echo character */
14127178Sminshall 	modenegotiated,		/* last time operating mode negotiated */
14227178Sminshall 	didnetreceive,		/* last time we read data from network */
14327178Sminshall 	gotDM;			/* when did we last see a data mark */
144*27186Sminshall } clocks;
14527110Sminshall 
146*27186Sminshall #define	settimer(x)	clocks.x = clocks.system++
14727110Sminshall 
14827110Sminshall /*
14927110Sminshall  * Various utility routines.
15027110Sminshall  */
1516000Sroot 
152*27186Sminshall char *ambiguous;		/* special return value */
153*27186Sminshall #define Ambiguous(t)	((t)&ambiguous)
154*27186Sminshall 
155*27186Sminshall 
15627088Sminshall char **
15727088Sminshall genget(name, table, next)
15827088Sminshall char	*name;		/* name to match */
15927088Sminshall char	**table;		/* name entry in table */
16027088Sminshall char	**(*next)();	/* routine to return next entry in table */
1616000Sroot {
16227088Sminshall 	register char *p, *q;
16327088Sminshall 	register char **c, **found;
16427088Sminshall 	register int nmatches, longest;
1656000Sroot 
16627088Sminshall 	longest = 0;
16727088Sminshall 	nmatches = 0;
16827088Sminshall 	found = 0;
16927088Sminshall 	for (c = table; p = *c; c = (*next)(c)) {
17027088Sminshall 		for (q = name; *q == *p++; q++)
17127088Sminshall 			if (*q == 0)		/* exact match? */
17227088Sminshall 				return (c);
17327088Sminshall 		if (!*q) {			/* the name was a prefix */
17427088Sminshall 			if (q - name > longest) {
17527088Sminshall 				longest = q - name;
17627088Sminshall 				nmatches = 1;
17727088Sminshall 				found = c;
17827088Sminshall 			} else if (q - name == longest)
17927088Sminshall 				nmatches++;
1808377Ssam 		}
1816000Sroot 	}
18227088Sminshall 	if (nmatches > 1)
183*27186Sminshall 		return Ambiguous(char **);
18427088Sminshall 	return (found);
1856000Sroot }
1866000Sroot 
18727110Sminshall /*
18827110Sminshall  * Make a character string into a number.
18927110Sminshall  *
190*27186Sminshall  * Todo:  1.  Could take random integers (12, 0x12, 012, 0b1).
19127110Sminshall  */
1926000Sroot 
19327110Sminshall special(s)
19427110Sminshall register char *s;
19527110Sminshall {
19627110Sminshall 	register char c;
19727110Sminshall 	char b;
19827110Sminshall 
19927110Sminshall 	switch (*s) {
20027110Sminshall 	case '^':
20127110Sminshall 		b = *++s;
20227110Sminshall 		if (b == '?') {
20327110Sminshall 		    c = b | 0x80;		/* DEL */
20427110Sminshall 		} else {
20527110Sminshall 		    c = b & 0x1f;
20627110Sminshall 		}
20727110Sminshall 		break;
20827110Sminshall 	default:
20927110Sminshall 		c = *s;
21027110Sminshall 		break;
21127110Sminshall 	}
21227110Sminshall 	return c;
21327110Sminshall }
214*27186Sminshall 
215*27186Sminshall /*
216*27186Sminshall  * Construct a control character sequence
217*27186Sminshall  * for a special character.
218*27186Sminshall  */
219*27186Sminshall char *
220*27186Sminshall control(c)
221*27186Sminshall 	register int c;
222*27186Sminshall {
223*27186Sminshall 	static char buf[3];
224*27186Sminshall 
225*27186Sminshall 	if (c == 0x3f)
226*27186Sminshall 		return ("^?");
227*27186Sminshall 	if (c == '\377') {
228*27186Sminshall 		return "off";
229*27186Sminshall 	}
230*27186Sminshall 	if (c >= 0x20) {
231*27186Sminshall 		buf[0] = c;
232*27186Sminshall 		buf[1] = 0;
233*27186Sminshall 	} else {
234*27186Sminshall 		buf[0] = '^';
235*27186Sminshall 		buf[1] = '@'+c;
236*27186Sminshall 		buf[2] = 0;
237*27186Sminshall 	}
238*27186Sminshall 	return (buf);
239*27186Sminshall }
24027110Sminshall 
24127110Sminshall /*
242*27186Sminshall  * Check to see if any out-of-band data exists on a socket (for
243*27186Sminshall  * Telnet "synch" processing).
244*27186Sminshall  */
245*27186Sminshall 
246*27186Sminshall int
247*27186Sminshall stilloob(s)
248*27186Sminshall int	s;		/* socket number */
249*27186Sminshall {
250*27186Sminshall     static struct timeval timeout = { 0 };
251*27186Sminshall     fd_set	excepts;
252*27186Sminshall     int value;
253*27186Sminshall 
254*27186Sminshall     do {
255*27186Sminshall 	FD_ZERO(&excepts);
256*27186Sminshall 	FD_SET(s, &excepts);
257*27186Sminshall 	value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout);
258*27186Sminshall     } while ((value == -1) && (errno = EINTR));
259*27186Sminshall 
260*27186Sminshall     if (value < 0) {
261*27186Sminshall 	perror("select");
262*27186Sminshall 	quit();
263*27186Sminshall     }
264*27186Sminshall     if (FD_ISSET(s, &excepts)) {
265*27186Sminshall 	return 1;
266*27186Sminshall     } else {
267*27186Sminshall 	return 0;
268*27186Sminshall     }
269*27186Sminshall }
270*27186Sminshall 
271*27186Sminshall 
272*27186Sminshall /*
273*27186Sminshall  *  netflush
274*27186Sminshall  *		Send as much data as possible to the network,
275*27186Sminshall  *	handling requests for urgent data.
276*27186Sminshall  */
277*27186Sminshall 
278*27186Sminshall 
279*27186Sminshall netflush(fd)
280*27186Sminshall {
281*27186Sminshall     int n;
282*27186Sminshall 
283*27186Sminshall     if ((n = nfrontp - nbackp) > 0) {
284*27186Sminshall 	if (!neturg) {
285*27186Sminshall 	    n = write(fd, nbackp, n);	/* normal write */
286*27186Sminshall 	} else {
287*27186Sminshall 	    n = neturg - nbackp;
288*27186Sminshall 	    /*
289*27186Sminshall 	     * In 4.2 (and 4.3) systems, there is some question about
290*27186Sminshall 	     * what byte in a sendOOB operation is the "OOB" data.
291*27186Sminshall 	     * To make ourselves compatible, we only send ONE byte
292*27186Sminshall 	     * out of band, the one WE THINK should be OOB (though
293*27186Sminshall 	     * we really have more the TCP philosophy of urgent data
294*27186Sminshall 	     * rather than the Unix philosophy of OOB data).
295*27186Sminshall 	     */
296*27186Sminshall 	    if (n > 1) {
297*27186Sminshall 		n = send(fd, nbackp, n-1, 0);	/* send URGENT all by itself */
298*27186Sminshall 	    } else {
299*27186Sminshall 		n = send(fd, nbackp, n, MSG_OOB);	/* URGENT data */
300*27186Sminshall 	    }
301*27186Sminshall 	}
302*27186Sminshall     }
303*27186Sminshall     if (n < 0) {
304*27186Sminshall 	if (errno != ENOBUFS && errno != EWOULDBLOCK) {
305*27186Sminshall 	    setcommandmode();
306*27186Sminshall 	    perror(hostname);
307*27186Sminshall 	    close(fd);
308*27186Sminshall 	    neturg = 0;
309*27186Sminshall 	    longjmp(peerdied, -1);
310*27186Sminshall 	    /*NOTREACHED*/
311*27186Sminshall 	}
312*27186Sminshall 	n = 0;
313*27186Sminshall     }
314*27186Sminshall     if (netdata && n) {
315*27186Sminshall 	Dump('>', nbackp, n);
316*27186Sminshall     }
317*27186Sminshall     nbackp += n;
318*27186Sminshall     if (nbackp >= neturg) {
319*27186Sminshall 	neturg = 0;
320*27186Sminshall     }
321*27186Sminshall     if (nbackp == nfrontp) {
322*27186Sminshall 	nbackp = nfrontp = netobuf;
323*27186Sminshall     }
324*27186Sminshall }
325*27186Sminshall 
326*27186Sminshall /*
327*27186Sminshall  * Send as much data as possible to the terminal.
328*27186Sminshall  */
329*27186Sminshall 
330*27186Sminshall 
331*27186Sminshall ttyflush()
332*27186Sminshall {
333*27186Sminshall     int n;
334*27186Sminshall 
335*27186Sminshall     if ((n = tfrontp - tbackp) > 0) {
336*27186Sminshall 	if (!SYNCHing) {
337*27186Sminshall 	    n = write(tout, tbackp, n);
338*27186Sminshall 	} else {
339*27186Sminshall 	    ioctl(fileno(stdout), TIOCFLUSH, (char *) 0);
340*27186Sminshall 	}
341*27186Sminshall     }
342*27186Sminshall     if (n < 0) {
343*27186Sminshall 	return;
344*27186Sminshall     }
345*27186Sminshall     tbackp += n;
346*27186Sminshall     if (tbackp == tfrontp) {
347*27186Sminshall 	tbackp = tfrontp = ttyobuf;
348*27186Sminshall     }
349*27186Sminshall }
350*27186Sminshall 
351*27186Sminshall /*
35227110Sminshall  * Various signal handling routines.
35327110Sminshall  */
35427110Sminshall 
35527110Sminshall deadpeer()
35627110Sminshall {
35727110Sminshall 	setcommandmode();
35827110Sminshall 	longjmp(peerdied, -1);
35927110Sminshall }
36027110Sminshall 
36127110Sminshall intr()
36227110Sminshall {
36327110Sminshall     if (localsigs) {
36427110Sminshall 	intp();
365*27186Sminshall 	if (autosynch) {
366*27186Sminshall 	    dosynch();
367*27186Sminshall 	}
36827110Sminshall 	return;
36927110Sminshall     }
37027110Sminshall     setcommandmode();
37127110Sminshall     longjmp(toplevel, -1);
37227110Sminshall }
37327110Sminshall 
37427110Sminshall intr2()
37527110Sminshall {
37627110Sminshall     if (localsigs) {
37727110Sminshall 	sendbrk();
378*27186Sminshall 	if (autosynch) {
379*27186Sminshall 	    dosynch();
380*27186Sminshall 	}
38127110Sminshall 	return;
38227110Sminshall     }
38327110Sminshall }
38427110Sminshall 
38527110Sminshall doescape()
38627110Sminshall {
38727110Sminshall     command(0);
38827110Sminshall }
38927110Sminshall 
39027110Sminshall /*
391*27186Sminshall  * The following are routines used to print out debugging information.
392*27186Sminshall  */
393*27186Sminshall 
394*27186Sminshall 
395*27186Sminshall static
396*27186Sminshall Dump(direction, buffer, length)
397*27186Sminshall char	direction;
398*27186Sminshall char	*buffer;
399*27186Sminshall int	length;
400*27186Sminshall {
401*27186Sminshall #   define BYTES_PER_LINE	32
402*27186Sminshall #   define min(x,y)	((x<y)? x:y)
403*27186Sminshall     char *pThis;
404*27186Sminshall     int offset;
405*27186Sminshall 
406*27186Sminshall     offset = 0;
407*27186Sminshall 
408*27186Sminshall     while (length) {
409*27186Sminshall 	/* print one line */
410*27186Sminshall 	fprintf(NetTrace, "%c 0x%x\t", direction, offset);
411*27186Sminshall 	pThis = buffer;
412*27186Sminshall 	buffer = buffer+min(length, BYTES_PER_LINE);
413*27186Sminshall 	while (pThis < buffer) {
414*27186Sminshall 	    fprintf(NetTrace, "%.2x", (*pThis)&0xff);
415*27186Sminshall 	    pThis++;
416*27186Sminshall 	}
417*27186Sminshall 	fprintf(NetTrace, "\n");
418*27186Sminshall 	length -= BYTES_PER_LINE;
419*27186Sminshall 	offset += BYTES_PER_LINE;
420*27186Sminshall 	if (length < 0) {
421*27186Sminshall 	    return;
422*27186Sminshall 	}
423*27186Sminshall 	/* find next unique line */
424*27186Sminshall     }
425*27186Sminshall }
426*27186Sminshall 
427*27186Sminshall 
428*27186Sminshall /*VARARGS*/
429*27186Sminshall printoption(direction, fmt, option, what)
430*27186Sminshall 	char *direction, *fmt;
431*27186Sminshall 	int option, what;
432*27186Sminshall {
433*27186Sminshall 	if (!showoptions)
434*27186Sminshall 		return;
435*27186Sminshall 	printf("%s ", direction);
436*27186Sminshall 	if (fmt == doopt)
437*27186Sminshall 		fmt = "do";
438*27186Sminshall 	else if (fmt == dont)
439*27186Sminshall 		fmt = "dont";
440*27186Sminshall 	else if (fmt == will)
441*27186Sminshall 		fmt = "will";
442*27186Sminshall 	else if (fmt == wont)
443*27186Sminshall 		fmt = "wont";
444*27186Sminshall 	else
445*27186Sminshall 		fmt = "???";
446*27186Sminshall 	if (option < TELOPT_SUPDUP)
447*27186Sminshall 		printf("%s %s", fmt, telopts[option]);
448*27186Sminshall 	else
449*27186Sminshall 		printf("%s %d", fmt, option);
450*27186Sminshall 	if (*direction == '<') {
451*27186Sminshall 		printf("\r\n");
452*27186Sminshall 		return;
453*27186Sminshall 	}
454*27186Sminshall 	printf(" (%s)\r\n", what ? "reply" : "don't reply");
455*27186Sminshall }
456*27186Sminshall 
457*27186Sminshall /*
45827110Sminshall  * Mode - set up terminal to a specific mode.
45927110Sminshall  */
46027110Sminshall 
46113076Ssam struct	tchars notc =	{ -1, -1, -1, -1, -1, -1 };
46227110Sminshall struct	tchars notc2;
46313076Ssam struct	ltchars noltc =	{ -1, -1, -1, -1, -1, -1 };
46427110Sminshall struct	ltchars noltc2;
4659972Ssam 
4666000Sroot mode(f)
4676000Sroot 	register int f;
4686000Sroot {
4698378Ssam 	static int prevmode = 0;
47013076Ssam 	struct tchars *tc;
47113076Ssam 	struct ltchars *ltc;
47213076Ssam 	struct sgttyb sb;
47313076Ssam 	int onoff, old;
4746000Sroot 
47527110Sminshall 	globalmode = f;
4768378Ssam 	if (prevmode == f)
477*27186Sminshall 		return;
4788378Ssam 	old = prevmode;
4798378Ssam 	prevmode = f;
48027110Sminshall 	sb = nttyb;
4816000Sroot 	switch (f) {
4828378Ssam 
4836000Sroot 	case 0:
4846000Sroot 		onoff = 0;
4859972Ssam 		tc = &otc;
48613076Ssam 		ltc = &oltc;
4876000Sroot 		break;
4886000Sroot 
48927110Sminshall 	case 1:		/* remote character processing, remote echo */
49027110Sminshall 	case 2:		/* remote character processing, local echo */
49113076Ssam 		sb.sg_flags |= CBREAK;
4928378Ssam 		if (f == 1)
49313076Ssam 			sb.sg_flags &= ~(ECHO|CRMOD);
4948378Ssam 		else
49513076Ssam 			sb.sg_flags |= ECHO|CRMOD;
49613076Ssam 		sb.sg_erase = sb.sg_kill = -1;
4979972Ssam 		tc = &notc;
49827110Sminshall 		/*
49927110Sminshall 		 * If user hasn't specified one way or the other,
50027110Sminshall 		 * then default to not trapping signals.
50127110Sminshall 		 */
50227110Sminshall 		if (!donelclsigs)
50327110Sminshall 			localsigs = 0;
50427110Sminshall 		if (localsigs) {
50527110Sminshall 			notc2 = notc;
50627110Sminshall 			notc2.t_intrc = ntc.t_intrc;
50727110Sminshall 			notc2.t_quitc = ntc.t_quitc;
50827110Sminshall 			notc2.t_eofc = ntc.t_eofc;
50927110Sminshall 			tc = &notc2;
51027110Sminshall 		} else
51127110Sminshall 			tc = &notc;
51213076Ssam 		ltc = &noltc;
5136000Sroot 		onoff = 1;
5149972Ssam 		break;
51527110Sminshall 	case 3:		/* local character processing, remote echo */
51627110Sminshall 	case 4:		/* local character processing, local echo */
51727110Sminshall 	case 5:		/* local character processing, no echo */
51827110Sminshall 		sb.sg_flags &= ~CBREAK;
51927110Sminshall 		sb.sg_flags |= CRMOD;
52027110Sminshall 		if (f == 4)
52127110Sminshall 			sb.sg_flags |= ECHO;
52227110Sminshall 		else
52327110Sminshall 			sb.sg_flags &= ~ECHO;
52427110Sminshall 		/*
52527110Sminshall 		 * If user hasn't specified one way or the other,
52627110Sminshall 		 * then default to trapping signals.
52727110Sminshall 		 */
52827110Sminshall 		if (!donelclsigs)
52927110Sminshall 			localsigs = 1;
53027110Sminshall 		if (localsigs)
53127110Sminshall 			tc = &ntc;
53227110Sminshall 		else {
53327110Sminshall 			notc2 = ntc;
53427110Sminshall 			notc2.t_intrc = notc2.t_quitc = -1;
53527110Sminshall 			tc = &notc2;
53627110Sminshall 		}
53727110Sminshall 		noltc2 = oltc;
53827110Sminshall 		noltc2.t_suspc = escape;
53927110Sminshall 		noltc2.t_dsuspc = -1;
54027110Sminshall 		ltc = &noltc2;
54127110Sminshall 		onoff = 1;
54227110Sminshall 		break;
5439972Ssam 
5449972Ssam 	default:
5459972Ssam 		return;
5466000Sroot 	}
54713076Ssam 	ioctl(fileno(stdin), TIOCSLTC, (char *)ltc);
54813076Ssam 	ioctl(fileno(stdin), TIOCSETC, (char *)tc);
54913076Ssam 	ioctl(fileno(stdin), TIOCSETP, (char *)&sb);
550*27186Sminshall 	ioctl(fileno(stdin), FIONBIO, (char *)&onoff);
551*27186Sminshall 	ioctl(fileno(stdout), FIONBIO, (char *)&onoff);
55227110Sminshall 	if (f >= 3)
55327110Sminshall 		signal(SIGTSTP, doescape);
55427110Sminshall 	else if (old >= 3) {
55527110Sminshall 		signal(SIGTSTP, SIG_DFL);
55627110Sminshall 		sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
55727110Sminshall 	}
5586000Sroot }
559*27186Sminshall 
56027110Sminshall /*
56127110Sminshall  * These routines decides on what the mode should be (based on the values
56227110Sminshall  * of various global variables).
56327110Sminshall  */
56427110Sminshall 
56527178Sminshall char *modedescriptions[] = {
56627178Sminshall 	"telnet command mode",					/* 0 */
56727178Sminshall 	"character-at-a-time mode",				/* 1 */
56827178Sminshall 	"character-at-a-time mode (local echo)",		/* 2 */
56927178Sminshall 	"line-by-line mode (remote echo)",			/* 3 */
57027178Sminshall 	"line-by-line mode",					/* 4 */
57127178Sminshall 	"line-by-line mode (local echoing suppressed)",		/* 5 */
57227178Sminshall };
57327178Sminshall 
57427178Sminshall getconnmode()
57527110Sminshall {
57627110Sminshall     static char newmode[8] = { 4, 5, 3, 3, 2, 2, 1, 1 };
577*27186Sminshall     int modeindex = 0;
57827110Sminshall 
57927110Sminshall     if (hisopts[TELOPT_ECHO]) {
580*27186Sminshall 	modeindex += 2;
58127110Sminshall     }
58227110Sminshall     if (hisopts[TELOPT_SGA]) {
583*27186Sminshall 	modeindex += 4;
58427110Sminshall     }
585*27186Sminshall     if (dontlecho && (clocks.echotoggle > clocks.modenegotiated)) {
586*27186Sminshall 	modeindex += 1;
58727110Sminshall     }
588*27186Sminshall     return newmode[modeindex];
58927110Sminshall }
59027110Sminshall 
59127178Sminshall setconnmode()
59227178Sminshall {
59327178Sminshall     mode(getconnmode());
59427178Sminshall }
59527110Sminshall 
59627178Sminshall 
59727110Sminshall setcommandmode()
59827110Sminshall {
59927110Sminshall     mode(0);
60027110Sminshall }
60127110Sminshall 
6026000Sroot char	sibuf[BUFSIZ], *sbp;
6036000Sroot char	tibuf[BUFSIZ], *tbp;
6046000Sroot int	scc, tcc;
6056000Sroot 
6066000Sroot /*
6076000Sroot  * Select from tty and network...
6086000Sroot  */
60927088Sminshall telnet()
6106000Sroot {
6116000Sroot 	register int c;
61227088Sminshall 	int tin = fileno(stdin);
6136000Sroot 	int on = 1;
6146000Sroot 
61527088Sminshall 	tout = fileno(stdout);
61627110Sminshall 	setconnmode();
617*27186Sminshall 	ioctl(net, FIONBIO, (char *)&on);
61827178Sminshall #if	defined(IOCTL_TO_DO_UNIX_OOB_IN_TCP_WAY)
61927178Sminshall 	ioctl(net, asdf, asdf);		/* handle urgent data in band */
62027178Sminshall #endif	/* defined(IOCTL_TO_DO_UNIX_OOB_IN_TCP_WAY) */
62127088Sminshall 	if (telnetport && !hisopts[TELOPT_SGA]) {
62217922Sralph 		willoption(TELOPT_SGA);
62327088Sminshall 	}
6246000Sroot 	for (;;) {
62527110Sminshall 		fd_set ibits, obits, xbits;
6266000Sroot 
62727110Sminshall 		if (scc < 0 && tcc < 0) {
6286000Sroot 			break;
62927110Sminshall 		}
63027110Sminshall 
63127110Sminshall 		FD_ZERO(&ibits);
63227110Sminshall 		FD_ZERO(&obits);
63327110Sminshall 		FD_ZERO(&xbits);
63427110Sminshall 
63527110Sminshall 		if (((globalmode < 4) || flushline) && (nfrontp - nbackp)) {
63627110Sminshall 			FD_SET(net, &obits);
63727088Sminshall 		} else {
63827110Sminshall 			FD_SET(tin, &ibits);
63927088Sminshall 		}
64027110Sminshall 		if (tfrontp - tbackp) {
64127110Sminshall 			FD_SET(tout, &obits);
64227110Sminshall 		} else {
64327110Sminshall 			FD_SET(net, &ibits);
64427110Sminshall 		}
645*27186Sminshall 		if (!SYNCHing) {
64627110Sminshall 			FD_SET(net, &xbits);
64727110Sminshall 		}
648*27186Sminshall 		if ((c = select(16, &ibits, &obits, &xbits,
649*27186Sminshall 						(struct timeval *)0)) < 1) {
65027110Sminshall 			if (c == -1) {
65127110Sminshall 				/*
65227110Sminshall 				 * we can get EINTR if we are in line mode,
65327110Sminshall 				 * and the user does an escape (TSTP), or
65427110Sminshall 				 * some other signal generator.
65527110Sminshall 				 */
65627110Sminshall 				if (errno == EINTR) {
65727110Sminshall 					continue;
65827110Sminshall 				}
65927110Sminshall 			}
6606000Sroot 			sleep(5);
6616000Sroot 			continue;
6626000Sroot 		}
6636000Sroot 
6646000Sroot 		/*
66527088Sminshall 		 * Any urgent data?
66627088Sminshall 		 */
66727110Sminshall 		if (FD_ISSET(net, &xbits)) {
668*27186Sminshall 		    SYNCHing = 1;
66927088Sminshall 		    ttyflush();	/* flush already enqueued data */
67027088Sminshall 		}
67127088Sminshall 
67227088Sminshall 		/*
6736000Sroot 		 * Something to read from the network...
6746000Sroot 		 */
67527110Sminshall 		if (FD_ISSET(net, &ibits)) {
67627178Sminshall #if	!defined(IOCTL_TO_DO_UNIX_OOB_IN_TCP_WAY)
67727178Sminshall 			/*
67827178Sminshall 			 * In 4.2 (and some early 4.3) systems, the
67927178Sminshall 			 * OOB indication and data handling in the kernel
68027178Sminshall 			 * is such that if two separate TCP Urgent requests
68127178Sminshall 			 * come in, one byte of TCP data will be overlaid.
68227178Sminshall 			 * This is fatal for Telnet, but we try to live
68327178Sminshall 			 * with it.
68427178Sminshall 			 *
68527178Sminshall 			 * In addition, in 4.2 (and...), a special protocol
68627178Sminshall 			 * is needed to pick up the TCP Urgent data in
68727178Sminshall 			 * the correct sequence.
68827178Sminshall 			 *
68927178Sminshall 			 * What we do is:  if we think we are in urgent
69027178Sminshall 			 * mode, we look to see if we are "at the mark".
69127178Sminshall 			 * If we are, we do an OOB receive.  If we run
69227178Sminshall 			 * this twice, we will do the OOB receive twice,
69327178Sminshall 			 * but the second will fail, since the second
69427178Sminshall 			 * time we were "at the mark", but there wasn't
69527178Sminshall 			 * any data there (the kernel doesn't reset
69627178Sminshall 			 * "at the mark" until we do a normal read).
69727178Sminshall 			 * Once we've read the OOB data, we go ahead
69827178Sminshall 			 * and do normal reads.
69927178Sminshall 			 *
70027178Sminshall 			 * There is also another problem, which is that
70127178Sminshall 			 * since the OOB byte we read doesn't put us
70227178Sminshall 			 * out of OOB state, and since that byte is most
70327178Sminshall 			 * likely the TELNET DM (data mark), we would
704*27186Sminshall 			 * stay in the TELNET SYNCH (SYNCHing) state.
70527178Sminshall 			 * So, clocks to the rescue.  If we've "just"
70627178Sminshall 			 * received a DM, then we test for the
70727178Sminshall 			 * presence of OOB data when the receive OOB
70827178Sminshall 			 * fails (and AFTER we did the normal mode read
70927178Sminshall 			 * to clear "at the mark").
71027178Sminshall 			 */
711*27186Sminshall 		    if (SYNCHing) {
71227178Sminshall 			int atmark;
71327178Sminshall 
714*27186Sminshall 			ioctl(net, SIOCATMARK, (char *)&atmark);
71527178Sminshall 			if (atmark) {
71627178Sminshall 			    scc = recv(net, sibuf, sizeof (sibuf), MSG_OOB);
71727178Sminshall 			    if ((scc == -1) && (errno == EINVAL)) {
71827178Sminshall 				scc = read(net, sibuf, sizeof (sibuf));
719*27186Sminshall 				if (clocks.didnetreceive < clocks.gotDM) {
720*27186Sminshall 				    SYNCHing = stilloob(net);
72127021Sminshall 				}
72227178Sminshall 			    }
72327178Sminshall 			} else {
72427178Sminshall 			    scc = read(net, sibuf, sizeof (sibuf));
7256000Sroot 			}
72627178Sminshall 		    } else {
72727178Sminshall 			scc = read(net, sibuf, sizeof (sibuf));
72827178Sminshall 		    }
72927178Sminshall 		    settimer(didnetreceive);
73027178Sminshall #else	/* !defined(IOCTL_TO_DO_UNIX_OOB_IN_TCP_WAY) */
73127178Sminshall 		    scc = read(net, sibuf, sizeof (sibuf));
73227178Sminshall #endif	/* !defined(IOCTL_TO_DO_UNIX_OOB_IN_TCP_WAY) */
73327178Sminshall 		    if (scc < 0 && errno == EWOULDBLOCK)
73427178Sminshall 			scc = 0;
73527178Sminshall 		    else {
73627178Sminshall 			if (scc <= 0) {
73727178Sminshall 			    break;
73827178Sminshall 			}
73927178Sminshall 			sbp = sibuf;
74027178Sminshall 			if (netdata) {
74127178Sminshall 			    Dump('<', sbp, scc);
74227178Sminshall 			}
74327178Sminshall 		    }
7446000Sroot 		}
7456000Sroot 
7466000Sroot 		/*
7476000Sroot 		 * Something to read from the tty...
7486000Sroot 		 */
74927110Sminshall 		if (FD_ISSET(tin, &ibits)) {
7508378Ssam 			tcc = read(tin, tibuf, sizeof (tibuf));
7516000Sroot 			if (tcc < 0 && errno == EWOULDBLOCK)
7526000Sroot 				tcc = 0;
7536000Sroot 			else {
7546000Sroot 				if (tcc <= 0)
7556000Sroot 					break;
7566000Sroot 				tbp = tibuf;
7576000Sroot 			}
7586000Sroot 		}
7596000Sroot 
7606000Sroot 		while (tcc > 0) {
761*27186Sminshall 			register int sc;
7626000Sroot 
76327110Sminshall 			if ((&netobuf[BUFSIZ] - nfrontp) < 2) {
76427110Sminshall 				flushline = 1;
7656000Sroot 				break;
76627110Sminshall 			}
767*27186Sminshall 			c = *tbp++ & 0xff, sc = strip(c), tcc--;
768*27186Sminshall 			if (sc == escape) {
7696000Sroot 				command(0);
7706000Sroot 				tcc = 0;
77127110Sminshall 				flushline = 1;
7726000Sroot 				break;
77327110Sminshall 			} else if ((globalmode >= 4) && doechocharrecognition &&
774*27186Sminshall 							(sc == echoc)) {
77527110Sminshall 				if (tcc > 0 && strip(*tbp) == echoc) {
77627110Sminshall 					tbp++;
77727110Sminshall 					tcc--;
77827110Sminshall 				} else {
77927110Sminshall 					dontlecho = !dontlecho;
78027110Sminshall 					settimer(echotoggle);
78127110Sminshall 					setconnmode();
78227110Sminshall 					tcc = 0;
78327110Sminshall 					flushline = 1;
78427110Sminshall 					break;
78527110Sminshall 				}
7866000Sroot 			}
78727110Sminshall 			if (localsigs) {
788*27186Sminshall 				if (sc == ntc.t_intrc) {
78927110Sminshall 					intp();
79027110Sminshall 					break;
791*27186Sminshall 				} else if (sc == ntc.t_quitc) {
79227110Sminshall 					sendbrk();
79327110Sminshall 					break;
79427110Sminshall 				} else if (globalmode > 2) {
79527110Sminshall 					;
796*27186Sminshall 				} else if (sc == nttyb.sg_kill) {
79727110Sminshall 					NET2ADD(IAC, EL);
79827110Sminshall 					break;
799*27186Sminshall 				} else if (sc == nttyb.sg_erase) {
80027110Sminshall 					NET2ADD(IAC, EC);
80127110Sminshall 					break;
80227110Sminshall 				}
80327110Sminshall 			}
80417922Sralph 			switch (c) {
80517922Sralph 			case '\n':
80627021Sminshall 				/*
80727021Sminshall 				 * If echoing is happening locally,
80827021Sminshall 				 * then a newline (unix) is CRLF (TELNET).
80927021Sminshall 				 */
81027088Sminshall 				if (!hisopts[TELOPT_ECHO]) {
81127088Sminshall 					NETADD('\r');
81227088Sminshall 				}
81327088Sminshall 				NETADD('\n');
81427110Sminshall 				flushline = 1;
81517922Sralph 				break;
81617922Sralph 			case '\r':
81727088Sminshall 				NET2ADD('\r', '\0');
81827110Sminshall 				flushline = 1;
81917922Sralph 				break;
82017922Sralph 			case IAC:
82127088Sminshall 				NET2ADD(IAC, IAC);
82227021Sminshall 				break;
82317922Sralph 			default:
82427088Sminshall 				NETADD(c);
82517922Sralph 				break;
82617922Sralph 			}
8276000Sroot 		}
82827110Sminshall 		if (((globalmode < 4) || flushline) &&
82927110Sminshall 		    (FD_ISSET(net, &obits) && (nfrontp - nbackp) > 0)) {
83027088Sminshall 			netflush(net);
83127110Sminshall 		}
8326000Sroot 		if (scc > 0)
8336000Sroot 			telrcv();
83427110Sminshall 		if (FD_ISSET(tout, &obits) && (tfrontp - tbackp) > 0)
83527088Sminshall 			ttyflush();
8366000Sroot 	}
83727110Sminshall 	setcommandmode();
8386000Sroot }
83927110Sminshall 
8406000Sroot /*
8416000Sroot  * Telnet receiver states for fsm
8426000Sroot  */
8436000Sroot #define	TS_DATA		0
8446000Sroot #define	TS_IAC		1
8456000Sroot #define	TS_WILL		2
8466000Sroot #define	TS_WONT		3
8476000Sroot #define	TS_DO		4
8486000Sroot #define	TS_DONT		5
84927021Sminshall #define	TS_CR		6
8506000Sroot 
8516000Sroot telrcv()
8526000Sroot {
8536000Sroot 	register int c;
8546000Sroot 	static int state = TS_DATA;
8556000Sroot 
8566000Sroot 	while (scc > 0) {
857*27186Sminshall 		c = *sbp++ & 0xff, scc--;
8586000Sroot 		switch (state) {
8596000Sroot 
86027021Sminshall 		case TS_CR:
86127021Sminshall 			state = TS_DATA;
86227021Sminshall 			if ((c == '\0') || (c == '\n')) {
86327021Sminshall 			    break;	/* by now, we ignore \n */
86427021Sminshall 			}
86527021Sminshall 
8666000Sroot 		case TS_DATA:
8679972Ssam 			if (c == IAC) {
8686000Sroot 				state = TS_IAC;
8699972Ssam 				continue;
8709972Ssam 			}
87127021Sminshall 			if (c == '\r') {
87227021Sminshall 				if (scc > 0) {
873*27186Sminshall 					c = *sbp&0xff;
87427021Sminshall 					if (c == 0) {
87527021Sminshall 						sbp++, scc--;
87627088Sminshall 						TTYADD('\r');
87727021Sminshall 				/*
87827021Sminshall 				 * The following hack is needed since we can't
87927021Sminshall 				 * set CRMOD on output only.  Machines like
88027021Sminshall 				 * MULTICS like to send \r without \n; since
88127021Sminshall 				 * we must turn off CRMOD to get proper input,
88227021Sminshall 				 * the mapping is done here (sigh).
88327021Sminshall 				 */
88427021Sminshall 						if (crmod) {
88527088Sminshall 							TTYADD('\n');
88627021Sminshall 						}
88727021Sminshall 					} else if (!hisopts[TELOPT_ECHO] &&
88827021Sminshall 								(c == '\n')) {
88927021Sminshall 						sbp++, scc--;
89027088Sminshall 						TTYADD('\n');
89127021Sminshall 					} else {
89227088Sminshall 						TTYADD('\r');
89327021Sminshall 					}
89427021Sminshall 				} else {
89527021Sminshall 					state = TS_CR;
89627088Sminshall 					TTYADD('\r');
89727021Sminshall 				}
89827021Sminshall 			} else {
89927088Sminshall 				TTYADD(c);
90027021Sminshall 			}
9016000Sroot 			continue;
9026000Sroot 
9036000Sroot 		case TS_IAC:
9046000Sroot 			switch (c) {
9056000Sroot 
9066000Sroot 			case WILL:
9076000Sroot 				state = TS_WILL;
9086000Sroot 				continue;
9096000Sroot 
9106000Sroot 			case WONT:
9116000Sroot 				state = TS_WONT;
9126000Sroot 				continue;
9136000Sroot 
9146000Sroot 			case DO:
9156000Sroot 				state = TS_DO;
9166000Sroot 				continue;
9176000Sroot 
9186000Sroot 			case DONT:
9196000Sroot 				state = TS_DONT;
9206000Sroot 				continue;
9216000Sroot 
9226000Sroot 			case DM:
92327088Sminshall 				/*
92427088Sminshall 				 * We may have missed an urgent notification,
92527088Sminshall 				 * so make sure we flush whatever is in the
92627088Sminshall 				 * buffer currently.
92727088Sminshall 				 */
928*27186Sminshall 				SYNCHing = 1;
92927088Sminshall 				ttyflush();
930*27186Sminshall 				SYNCHing = stilloob(net);
93127178Sminshall 				settimer(gotDM);
9326000Sroot 				break;
9336000Sroot 
9346000Sroot 			case NOP:
9356000Sroot 			case GA:
9366000Sroot 				break;
9376000Sroot 
9386000Sroot 			default:
9396000Sroot 				break;
9406000Sroot 			}
9416000Sroot 			state = TS_DATA;
9426000Sroot 			continue;
9436000Sroot 
9446000Sroot 		case TS_WILL:
9458345Ssam 			printoption("RCVD", will, c, !hisopts[c]);
94627110Sminshall 			if (c == TELOPT_TM) {
94727110Sminshall 				if (flushout) {
948*27186Sminshall 					flushout = 0;
94927110Sminshall 				}
95027110Sminshall 			} else if (!hisopts[c]) {
9516000Sroot 				willoption(c);
95227110Sminshall 			}
9536000Sroot 			state = TS_DATA;
9546000Sroot 			continue;
9556000Sroot 
9566000Sroot 		case TS_WONT:
9578345Ssam 			printoption("RCVD", wont, c, hisopts[c]);
95827110Sminshall 			if (c == TELOPT_TM) {
95927110Sminshall 				if (flushout) {
960*27186Sminshall 					flushout = 0;
96127110Sminshall 				}
96227110Sminshall 			} else if (hisopts[c]) {
9636000Sroot 				wontoption(c);
96427110Sminshall 			}
9656000Sroot 			state = TS_DATA;
9666000Sroot 			continue;
9676000Sroot 
9686000Sroot 		case TS_DO:
9698345Ssam 			printoption("RCVD", doopt, c, !myopts[c]);
9706000Sroot 			if (!myopts[c])
9716000Sroot 				dooption(c);
9726000Sroot 			state = TS_DATA;
9736000Sroot 			continue;
9746000Sroot 
9756000Sroot 		case TS_DONT:
9768345Ssam 			printoption("RCVD", dont, c, myopts[c]);
9776000Sroot 			if (myopts[c]) {
9786000Sroot 				myopts[c] = 0;
9796000Sroot 				sprintf(nfrontp, wont, c);
9808378Ssam 				nfrontp += sizeof (wont) - 2;
98127110Sminshall 				flushline = 1;
98227110Sminshall 				setconnmode();	/* set new tty mode (maybe) */
9838345Ssam 				printoption("SENT", wont, c);
9846000Sroot 			}
9856000Sroot 			state = TS_DATA;
9866000Sroot 			continue;
9876000Sroot 		}
9886000Sroot 	}
9896000Sroot }
99027110Sminshall 
9916000Sroot willoption(option)
9926000Sroot 	int option;
9936000Sroot {
9946000Sroot 	char *fmt;
9956000Sroot 
9966000Sroot 	switch (option) {
9976000Sroot 
9986000Sroot 	case TELOPT_ECHO:
9996000Sroot 	case TELOPT_SGA:
100027110Sminshall 		settimer(modenegotiated);
10016000Sroot 		hisopts[option] = 1;
10026000Sroot 		fmt = doopt;
100327110Sminshall 		setconnmode();		/* possibly set new tty mode */
10046000Sroot 		break;
10056000Sroot 
10066000Sroot 	case TELOPT_TM:
100727110Sminshall 		return;			/* Never reply to TM will's/wont's */
10086000Sroot 
10096000Sroot 	default:
10106000Sroot 		fmt = dont;
10116000Sroot 		break;
10126000Sroot 	}
10136024Ssam 	sprintf(nfrontp, fmt, option);
10148378Ssam 	nfrontp += sizeof (dont) - 2;
10158345Ssam 	printoption("SENT", fmt, option);
10166000Sroot }
10176000Sroot 
10186000Sroot wontoption(option)
10196000Sroot 	int option;
10206000Sroot {
10216000Sroot 	char *fmt;
10226000Sroot 
10236000Sroot 	switch (option) {
10246000Sroot 
10256000Sroot 	case TELOPT_ECHO:
10266000Sroot 	case TELOPT_SGA:
102727110Sminshall 		settimer(modenegotiated);
10286000Sroot 		hisopts[option] = 0;
10296000Sroot 		fmt = dont;
103027110Sminshall 		setconnmode();			/* Set new tty mode */
10316000Sroot 		break;
10326000Sroot 
103327110Sminshall 	case TELOPT_TM:
103427110Sminshall 		return;		/* Never reply to TM will's/wont's */
103527110Sminshall 
10366000Sroot 	default:
10376000Sroot 		fmt = dont;
10386000Sroot 	}
10396000Sroot 	sprintf(nfrontp, fmt, option);
10408378Ssam 	nfrontp += sizeof (doopt) - 2;
10418345Ssam 	printoption("SENT", fmt, option);
10426000Sroot }
10436000Sroot 
10446000Sroot dooption(option)
10456000Sroot 	int option;
10466000Sroot {
10476000Sroot 	char *fmt;
10486000Sroot 
10496000Sroot 	switch (option) {
10506000Sroot 
10516000Sroot 	case TELOPT_TM:
105213231Ssam 		fmt = will;
105313231Ssam 		break;
105413231Ssam 
105527110Sminshall 	case TELOPT_SGA:		/* no big deal */
10566000Sroot 		fmt = will;
105727110Sminshall 		myopts[option] = 1;
10586000Sroot 		break;
10596000Sroot 
106027110Sminshall 	case TELOPT_ECHO:		/* We're never going to echo... */
10616000Sroot 	default:
10626000Sroot 		fmt = wont;
10636000Sroot 		break;
10646000Sroot 	}
10656000Sroot 	sprintf(nfrontp, fmt, option);
10668378Ssam 	nfrontp += sizeof (doopt) - 2;
10678345Ssam 	printoption("SENT", fmt, option);
10686000Sroot }
106927110Sminshall 
10706000Sroot /*
107127088Sminshall  *	The following are data structures and routines for
107227088Sminshall  *	the "send" command.
107327088Sminshall  *
107427088Sminshall  */
107527088Sminshall 
107627088Sminshall struct sendlist {
107727088Sminshall     char	*name;		/* How user refers to it (case independent) */
107827088Sminshall     int		what;		/* Character to be sent (<0 ==> special) */
107927088Sminshall     char	*help;		/* Help information (0 ==> no help) */
108027088Sminshall     int		(*routine)();	/* Routine to perform (for special ops) */
108127088Sminshall };
108227088Sminshall 
1083*27186Sminshall /*ARGSUSED*/
108427088Sminshall dosynch(s)
108527088Sminshall struct sendlist *s;
108627088Sminshall {
108727088Sminshall     /* XXX We really should purge the buffer to the network */
108827088Sminshall     NET2ADD(IAC, DM);
1089*27186Sminshall     neturg = NETLOC()-1;	/* Some systems are off by one XXX */
109027088Sminshall }
109127088Sminshall 
109227088Sminshall intp()
109327088Sminshall {
109427110Sminshall     NET2ADD(IAC, IP);
109527088Sminshall }
109627088Sminshall 
109727110Sminshall sendbrk()
109827110Sminshall {
1099*27186Sminshall #if	0
1100*27186Sminshall     /*
1101*27186Sminshall      * There is a question here.  Should we send a TM to flush the stream?
1102*27186Sminshall      * Should we also send a TELNET SYNCH also?
1103*27186Sminshall      */
110427110Sminshall     *nfrontp++ = IAC;
110527110Sminshall     *nfrontp++ = DO;
110627110Sminshall     *nfrontp++ = TELOPT_TM;
110727110Sminshall     flushout = 1;
1108*27186Sminshall     printoption("SENT", doopt, TELOPT_TM);
1109*27186Sminshall #endif	/* 0 */
1110*27186Sminshall     NET2ADD(IAC, BREAK);
111127110Sminshall     flushline = 1;
111227110Sminshall }
111327088Sminshall 
111427110Sminshall 
111527088Sminshall #define	SENDQUESTION	-1
111627088Sminshall #define	SEND2QUESTION	-2
111727088Sminshall #define	SENDESCAPE	-3
111827088Sminshall 
111927088Sminshall struct sendlist Sendlist[] = {
112027088Sminshall     { "synch", SYNCH, "Perform Telnet 'Synch operation'", dosynch },
112127088Sminshall     { "brk", BREAK, "Send Telnet Break" },
112227088Sminshall 	{ "break", BREAK, 0 },
112327088Sminshall     { "ip", IP, "Send Telnet Interrupt Process" },
112427088Sminshall 	{ "intp", IP, 0 },
112527088Sminshall 	{ "interrupt", IP, 0 },
112627088Sminshall 	{ "intr", IP, 0 },
112727088Sminshall     { "ao", AO, "Send Telnet Abort output" },
112827088Sminshall 	{ "abort", AO, 0 },
112927088Sminshall     { "ayt", AYT, "Send Telnet 'Are You There'" },
113027088Sminshall 	{ "are", AYT, 0 },
113127088Sminshall 	{ "hello", AYT, 0 },
113227088Sminshall     { "ec", EC, "Send Telnet Erase Character" },
113327088Sminshall     { "el", EL, "Send Telnet Erase Line" },
113427088Sminshall     { "ga", GA, "Send Telnet 'Go Ahead' sequence" },
113527088Sminshall 	{ "go", GA, 0 },
113627088Sminshall     { "nop", NOP, "Send Telnet 'No operation'" },
113727088Sminshall     { "escape", SENDESCAPE, "Send current escape character" },
113827088Sminshall     { "?", SENDQUESTION, "Display send options" },
113927088Sminshall 	{ "help", SENDQUESTION, 0 },
114027088Sminshall     { "??", SEND2QUESTION, "Display all send options (including aliases)" },
114127088Sminshall     { 0 }
114227088Sminshall };
114327088Sminshall 
114427088Sminshall char **
114527088Sminshall getnextsend(name)
114627088Sminshall char *name;
114727088Sminshall {
114827088Sminshall     struct sendlist *c = (struct sendlist *) name;
114927088Sminshall 
115027088Sminshall     return (char **) (c+1);
115127088Sminshall }
115227088Sminshall 
115327088Sminshall struct sendlist *
115427088Sminshall getsend(name)
115527088Sminshall char *name;
115627088Sminshall {
115727088Sminshall     return (struct sendlist *) genget(name, (char **) Sendlist, getnextsend);
115827088Sminshall }
115927088Sminshall 
116027088Sminshall sendcmd(argc, argv)
116127088Sminshall int	argc;
116227088Sminshall char	**argv;
116327088Sminshall {
116427088Sminshall     int what;		/* what we are sending this time */
116527088Sminshall     int count;		/* how many bytes we are going to need to send */
116627088Sminshall     int hadsynch;	/* are we going to process a "synch"? */
116727088Sminshall     int i;
116827088Sminshall     struct sendlist *s;	/* pointer to current command */
116927088Sminshall 
117027088Sminshall     if (argc < 2) {
117127088Sminshall 	printf("need at least one argument for 'send' command\n");
117227088Sminshall 	printf("'send ?' for help\n");
117327088Sminshall 	return;
117427088Sminshall     }
117527088Sminshall     /*
117627088Sminshall      * First, validate all the send arguments.
117727088Sminshall      * In addition, we see how much space we are going to need, and
117827088Sminshall      * whether or not we will be doing a "SYNCH" operation (which
117927088Sminshall      * flushes the network queue).
118027088Sminshall      */
118127088Sminshall     count = 0;
118227088Sminshall     hadsynch = 0;
118327088Sminshall     for (i = 1; i < argc; i++) {
118427088Sminshall 	s = getsend(argv[i]);
118527088Sminshall 	if (s == 0) {
118627088Sminshall 	    printf("Unknown send argument '%s'\n'send ?' for help.\n",
118727088Sminshall 			argv[i]);
118827088Sminshall 	    return;
1189*27186Sminshall 	} else if (s == Ambiguous(struct sendlist *)) {
119027088Sminshall 	    printf("Ambiguous send argument '%s'\n'send ?' for help.\n",
119127088Sminshall 			argv[i]);
119227088Sminshall 	    return;
119327088Sminshall 	}
119427088Sminshall 	switch (s->what) {
119527088Sminshall 	case SENDQUESTION:
119627088Sminshall 	case SEND2QUESTION:
119727088Sminshall 	    break;
119827088Sminshall 	case SENDESCAPE:
119927088Sminshall 	    count += 1;
120027088Sminshall 	    break;
120127088Sminshall 	case SYNCH:
120227088Sminshall 	    hadsynch = 1;
120327088Sminshall 	    count += 2;
120427088Sminshall 	    break;
120527088Sminshall 	default:
120627088Sminshall 	    count += 2;
120727088Sminshall 	    break;
120827088Sminshall 	}
120927088Sminshall     }
121027088Sminshall     /* Now, do we have enough room? */
121127088Sminshall     if (netobuf+sizeof netobuf-nfrontp-1 < count) {
121227088Sminshall 	printf("There is not enough room in the buffer TO the network\n");
121327088Sminshall 	printf("to process your request.  Nothing will be done.\n");
121427088Sminshall 	printf("('send synch' will throw away most data in the network\n");
121527088Sminshall 	printf("buffer, if this might help.)\n");
121627088Sminshall 	return;
121727088Sminshall     }
121827088Sminshall     /* OK, they are all OK, now go through again and actually send */
121927088Sminshall     for (i = 1; i < argc; i++) {
122027088Sminshall 	if (!(s = getsend(argv[i]))) {
122127088Sminshall 	    fprintf(stderr, "Telnet 'send' error - argument disappeared!\n");
122227088Sminshall 	    quit();
122327088Sminshall 	    /*NOTREACHED*/
122427088Sminshall 	}
122527088Sminshall 	if (s->routine) {
122627088Sminshall 	    (*s->routine)(s);
122727088Sminshall 	} else {
122827088Sminshall 	    switch (what = s->what) {
122927088Sminshall 	    case SENDQUESTION:
123027088Sminshall 	    case SEND2QUESTION:
123127088Sminshall 		for (s = Sendlist; s->name; s++) {
123227088Sminshall 		    if (s->help || (what == SEND2QUESTION)) {
123327088Sminshall 			printf(s->name);
123427088Sminshall 			if (s->help) {
123527088Sminshall 			    printf("\t%s", s->help);
123627088Sminshall 			}
123727088Sminshall 			printf("\n");
123827088Sminshall 		    }
123927088Sminshall 		}
124027088Sminshall 		break;
124127088Sminshall 	    case SENDESCAPE:
124227088Sminshall 		NETADD(escape);
124327088Sminshall 		break;
124427088Sminshall 	    default:
124527088Sminshall 		NET2ADD(IAC, what);
124627088Sminshall 		break;
124727088Sminshall 	    }
124827088Sminshall 	}
124927088Sminshall     }
125027088Sminshall }
125127088Sminshall 
125227088Sminshall /*
125327088Sminshall  * The following are the routines and data structures referred
125427088Sminshall  * to by the arguments to the "toggle" command.
125527088Sminshall  */
125627088Sminshall 
125727110Sminshall lclsigs()
125827110Sminshall {
125927110Sminshall     donelclsigs = 1;
126027110Sminshall }
126127110Sminshall 
126227110Sminshall /*VARARGS*/
126327178Sminshall togcrmod()
126427110Sminshall {
126527110Sminshall     crmod = !crmod;
1266*27186Sminshall     printf("Deprecated usage - please use 'toggle crmod' in the future.\n");
126727110Sminshall     printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't");
126827110Sminshall     fflush(stdout);
126927110Sminshall }
127027110Sminshall 
127127178Sminshall togdebug()
127227088Sminshall {
127327110Sminshall     if (net > 0 &&
1274*27186Sminshall 	setsockopt(net, SOL_SOCKET, SO_DEBUG, (char *)&debug, sizeof(debug))
1275*27186Sminshall 									< 0) {
127627110Sminshall 	    perror("setsockopt (SO_DEBUG)");
1277*27186Sminshall     }
127827088Sminshall }
127927088Sminshall 
128027088Sminshall 
128127088Sminshall 
128227088Sminshall int togglehelp();
128327088Sminshall 
128427110Sminshall char	crmodhelp[] =	"toggle mapping of received carriage returns";
128527110Sminshall 
128627178Sminshall struct togglelist {
128727178Sminshall     char	*name;		/* name of toggle */
128827178Sminshall     char	*help;		/* help message */
1289*27186Sminshall     int		(*handler)();	/* routine to do actual setting */
129027178Sminshall     int		dohelp;		/* should we display help information */
129127178Sminshall     int		*variable;
129227178Sminshall     char	*actionexplanation;
129327178Sminshall };
129427178Sminshall 
129527178Sminshall struct togglelist Togglelist[] = {
129627178Sminshall     { "localchars",
129727178Sminshall 	"toggle local recognition of control characters",
129827178Sminshall 	    lclsigs,
129927178Sminshall 		1,
130027178Sminshall 		    &localsigs,
130127178Sminshall 			"recognize interrupt/quit characters" },
130227178Sminshall     { "echochar",
130327178Sminshall 	"toggle recognition of echo toggle character",
1304*27186Sminshall 	    0,
130527178Sminshall 		1,
130627178Sminshall 		    &doechocharrecognition,
130727178Sminshall 			"recognize echo toggle character" },
1308*27186Sminshall     { "autosynch",
1309*27186Sminshall 	"toggle automatic sending of interrupt characters in urgent mode",
1310*27186Sminshall 	    0,
1311*27186Sminshall 		1,
1312*27186Sminshall 		    &autosynch,
1313*27186Sminshall 			"send interrupt characters in urgent mode" },
131427178Sminshall     { "crmod",
131527178Sminshall 	crmodhelp,
1316*27186Sminshall 	    0,
131727178Sminshall 		1,
131827178Sminshall 		    &crmod,
131927178Sminshall 			"map carriage return on output" },
132027110Sminshall     { " ", "", 0, 1 },		/* empty line */
132127178Sminshall     { "debug",
132227178Sminshall 	"(debugging) toggle debugging",
132327178Sminshall 	    togdebug,
132427178Sminshall 		1,
132527178Sminshall 		    &debug,
132627178Sminshall 			"turn on socket level debugging" },
132727178Sminshall     { "options",
132827178Sminshall 	"(debugging) toggle viewing of options processing",
1329*27186Sminshall 	    0,
133027178Sminshall 		1,
133127178Sminshall 		    &showoptions,
133227178Sminshall 			"show option processing" },
133327178Sminshall     { "netdata",
133427178Sminshall 	"(debugging) toggle printing of hexadecimal network data",
1335*27186Sminshall 	    0,
133627178Sminshall 		1,
133727178Sminshall 		    &netdata,
133827178Sminshall 			"print hexadecimal representation of network traffic" },
133927178Sminshall     { "?",
134027178Sminshall 	"display help information",
134127178Sminshall 	    togglehelp,
134227178Sminshall 		1 },
134327178Sminshall     { "help",
134427178Sminshall 	"display help information",
134527178Sminshall 	    togglehelp,
134627178Sminshall 		0 },
134727088Sminshall     { 0 }
134827088Sminshall };
134927088Sminshall 
135027088Sminshall togglehelp()
135127088Sminshall {
135227178Sminshall     struct togglelist *c;
135327088Sminshall 
135427178Sminshall     for (c = Togglelist; c->name; c++) {
135527088Sminshall 	if (c->dohelp) {
135627088Sminshall 	    printf("%s\t%s\n", c->name, c->help);
135727088Sminshall 	}
135827088Sminshall     }
135927088Sminshall }
136027088Sminshall 
136127088Sminshall char **
136227088Sminshall getnexttoggle(name)
136327088Sminshall char *name;
136427088Sminshall {
136527178Sminshall     struct togglelist *c = (struct togglelist *) name;
136627088Sminshall 
136727088Sminshall     return (char **) (c+1);
136827088Sminshall }
136927088Sminshall 
137027178Sminshall struct togglelist *
137127088Sminshall gettoggle(name)
137227088Sminshall char *name;
137327088Sminshall {
137427178Sminshall     return (struct togglelist *)
137527178Sminshall 			genget(name, (char **) Togglelist, getnexttoggle);
137627088Sminshall }
137727088Sminshall 
137827088Sminshall toggle(argc, argv)
137927088Sminshall int	argc;
138027088Sminshall char	*argv[];
138127088Sminshall {
138227088Sminshall     char *name;
138327178Sminshall     struct togglelist *c;
138427088Sminshall 
138527088Sminshall     if (argc < 2) {
138627088Sminshall 	fprintf(stderr,
138727088Sminshall 	    "Need an argument to 'toggle' command.  'toggle ?' for help.\n");
138827088Sminshall 	return;
138927088Sminshall     }
139027088Sminshall     argc--;
139127088Sminshall     argv++;
139227088Sminshall     while (argc--) {
139327088Sminshall 	name = *argv++;
139427088Sminshall 	c = gettoggle(name);
1395*27186Sminshall 	if (c == Ambiguous(struct togglelist *)) {
139627088Sminshall 	    fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n",
139727088Sminshall 					name);
139827088Sminshall 	} else if (c == 0) {
139927088Sminshall 	    fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n",
140027088Sminshall 					name);
140127088Sminshall 	} else {
1402*27186Sminshall 	    if (c->variable) {
1403*27186Sminshall 		*c->variable = !*c->variable;		/* invert it */
1404*27186Sminshall 		printf("%s %s.\n", *c->variable? "Will" : "Won't",
1405*27186Sminshall 							c->actionexplanation);
1406*27186Sminshall 	    }
1407*27186Sminshall 	    if (c->handler) {
1408*27186Sminshall 		(*c->handler)(c);
1409*27186Sminshall 	    }
141027088Sminshall 	}
141127088Sminshall     }
141227088Sminshall }
141327088Sminshall 
141427088Sminshall /*
141527110Sminshall  * The following perform the "set" command.
141627110Sminshall  */
141727110Sminshall 
141827178Sminshall struct setlist {
141927178Sminshall     char *name;				/* name */
142027110Sminshall     char *help;				/* help information */
142127110Sminshall     char *charp;			/* where it is located at */
142227110Sminshall };
142327110Sminshall 
142427178Sminshall struct setlist Setlist[] = {
142527110Sminshall     { "echo", 	"character to toggle local echoing on/off", &echoc },
142627110Sminshall     { "escape",	"character to escape back to telnet command mode", &escape },
142727110Sminshall     { "interrupt", "character to cause an Interrupt Process", &ntc.t_intrc },
142827110Sminshall     { "quit",	"character to cause a Break", &ntc.t_quitc },
142927110Sminshall     { "erase",	"character to cause an Erase Character", &nttyb.sg_erase },
143027110Sminshall     { "kill",	"character to cause an Erase Line", &nttyb.sg_kill },
143127110Sminshall     { 0 }
143227110Sminshall };
143327110Sminshall 
143427110Sminshall char **
143527178Sminshall getnextset(name)
143627110Sminshall char *name;
143727110Sminshall {
143827178Sminshall     struct setlist *c = (struct setlist *)name;
143927110Sminshall 
144027110Sminshall     return (char **) (c+1);
144127110Sminshall }
144227110Sminshall 
144327178Sminshall struct setlist *
144427178Sminshall getset(name)
144527110Sminshall char *name;
144627110Sminshall {
144727178Sminshall     return (struct setlist *) genget(name, (char **) Setlist, getnextset);
144827110Sminshall }
144927110Sminshall 
145027110Sminshall setcmd(argc, argv)
145127110Sminshall int	argc;
145227110Sminshall char	*argv[];
145327110Sminshall {
145427110Sminshall     int value;
145527178Sminshall     struct setlist *ct;
145627110Sminshall 
145727110Sminshall     /* XXX back we go... sigh */
145827110Sminshall     if (argc != 3) {
145927110Sminshall 	printf("Format is 'set Name Value', where 'Name' is one of:\n\n");
146027178Sminshall 	for (ct = Setlist; ct->name; ct++) {
146127178Sminshall 	    printf("%s\t%s\n", ct->name, ct->help);
146227110Sminshall 	}
146327110Sminshall 	return;
146427110Sminshall     }
146527110Sminshall 
146627178Sminshall     ct = getset(argv[1]);
146727110Sminshall     if (ct == 0) {
146827110Sminshall 	fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n",
146927110Sminshall 			argv[1]);
1470*27186Sminshall     } else if (ct == Ambiguous(struct setlist *)) {
147127110Sminshall 	fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
147227110Sminshall 			argv[1]);
147327110Sminshall     } else {
147427110Sminshall 	if (strcmp("off", argv[2])) {
147527110Sminshall 	    value = special(argv[2]);
147627110Sminshall 	} else {
147727110Sminshall 	    value = -1;
147827110Sminshall 	}
147927110Sminshall 	*(ct->charp) = value;
148027178Sminshall 	printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
148127110Sminshall     }
148227110Sminshall }
148327110Sminshall 
148427110Sminshall /*
148527110Sminshall  * The following are the data structures and routines for the
148627110Sminshall  * 'mode' command.
148727110Sminshall  */
148827110Sminshall 
148927110Sminshall dolinemode()
149027110Sminshall {
149127110Sminshall     if (hisopts[TELOPT_SGA]) {
1492*27186Sminshall 	wontoption(TELOPT_SGA);
149327110Sminshall     }
149427110Sminshall     if (hisopts[TELOPT_ECHO]) {
1495*27186Sminshall 	wontoption(TELOPT_ECHO);
149627110Sminshall     }
149727110Sminshall }
149827110Sminshall 
149927110Sminshall docharmode()
150027110Sminshall {
150127110Sminshall     if (!hisopts[TELOPT_SGA]) {
1502*27186Sminshall 	willoption(TELOPT_SGA);
150327110Sminshall     }
150427110Sminshall     if (!hisopts[TELOPT_ECHO]) {
1505*27186Sminshall 	willoption(TELOPT_ECHO);
150627110Sminshall     }
150727110Sminshall }
150827110Sminshall 
150927110Sminshall struct cmd Modelist[] = {
151027110Sminshall     { "line",		"line-by-line mode",		dolinemode, 1, 1 },
151127110Sminshall     { "character",	"character-at-a-time mode",	docharmode, 1, 1 },
151227110Sminshall     { 0 },
151327110Sminshall };
151427110Sminshall 
151527110Sminshall char **
151627110Sminshall getnextmode(name)
151727110Sminshall char *name;
151827110Sminshall {
151927110Sminshall     struct cmd *c = (struct cmd *) name;
152027110Sminshall 
152127110Sminshall     return (char **) (c+1);
152227110Sminshall }
152327110Sminshall 
152427110Sminshall struct cmd *
152527110Sminshall getmodecmd(name)
152627110Sminshall char *name;
152727110Sminshall {
152827110Sminshall     return (struct cmd *) genget(name, (char **) Modelist, getnextmode);
152927110Sminshall }
153027110Sminshall 
153127110Sminshall modecmd(argc, argv)
153227110Sminshall int	argc;
153327110Sminshall char	*argv[];
153427110Sminshall {
153527110Sminshall     struct cmd *mt;
153627110Sminshall 
153727110Sminshall     if ((argc != 2) || !strcmp(argv[1], "?") || !strcmp(argv[1], "help")) {
153827110Sminshall 	printf("format is:  'mode Mode', where 'Mode' is one of:\n\n");
153927110Sminshall 	for (mt = Modelist; mt->name; mt++) {
154027110Sminshall 	    printf("%s\t%s\n", mt->name, mt->help);
154127110Sminshall 	}
154227110Sminshall 	return;
154327110Sminshall     }
154427110Sminshall     mt = getmodecmd(argv[1]);
154527110Sminshall     if (mt == 0) {
154627110Sminshall 	fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]);
1547*27186Sminshall     } else if (mt == Ambiguous(struct cmd *)) {
154827110Sminshall 	fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]);
154927110Sminshall     } else {
155027110Sminshall 	(*mt->handler)();
155127110Sminshall     }
155227110Sminshall }
155327110Sminshall 
155427110Sminshall /*
155527178Sminshall  * The following data structures and routines implement the
155627178Sminshall  * "display" command.
155727178Sminshall  */
155827178Sminshall 
155927178Sminshall display(argc, argv)
156027178Sminshall int	argc;
156127178Sminshall char	*argv[];
156227178Sminshall {
156327178Sminshall #define	dotog(tl)	if (tl->variable && tl->actionexplanation) { \
156427178Sminshall 			    if (*tl->variable) { \
156527178Sminshall 				printf("will"); \
156627178Sminshall 			    } else { \
156727178Sminshall 				printf("won't"); \
156827178Sminshall 			    } \
156927178Sminshall 			    printf(" %s.\n", tl->actionexplanation); \
157027178Sminshall 			}
157127178Sminshall 
157227178Sminshall #define	doset(sl)	printf("[%s]\t%s.\n", control(*sl->charp), sl->name);
157327178Sminshall 
157427178Sminshall     struct togglelist *tl;
157527178Sminshall     struct setlist *sl;
157627178Sminshall 
157727178Sminshall     if (argc == 1) {
157827178Sminshall 	for (tl = Togglelist; tl->name; tl++) {
157927178Sminshall 	    dotog(tl);
158027178Sminshall 	}
158127178Sminshall 	for (sl = Setlist; sl->name; sl++) {
158227178Sminshall 	    doset(sl);
158327178Sminshall 	}
158427178Sminshall     } else {
158527178Sminshall 	int i;
158627178Sminshall 
158727178Sminshall 	for (i = 1; i < argc; i++) {
158827178Sminshall 	    sl = getset(argv[i]);
158927178Sminshall 	    tl = gettoggle(argv[i]);
1590*27186Sminshall 	    if ((sl == Ambiguous(struct setlist *)) ||
1591*27186Sminshall 				(tl == Ambiguous(struct togglelist *))) {
159227178Sminshall 		printf("?Ambiguous argument '%s'.\n", argv[i]);
159327178Sminshall 	    } else if (!sl && !tl) {
159427178Sminshall 		printf("?Unknown argument '%s'.\n", argv[i]);
159527178Sminshall 	    } else {
1596*27186Sminshall 		if (tl) {
1597*27186Sminshall 		    dotog(tl);
1598*27186Sminshall 		}
1599*27186Sminshall 		if (sl) {
1600*27186Sminshall 		    doset(sl);
1601*27186Sminshall 		}
160227178Sminshall 	    }
160327178Sminshall 	}
160427178Sminshall     }
160527178Sminshall #undef	doset(sl)
160627178Sminshall #undef	dotog(tl)
160727178Sminshall }
160827178Sminshall 
160927178Sminshall /*
161027088Sminshall  * The following are the data structures, and many of the routines,
161127088Sminshall  * relating to command processing.
161227088Sminshall  */
161327088Sminshall 
161427088Sminshall /*
161527088Sminshall  * Set the escape character.
161627088Sminshall  */
161727088Sminshall setescape(argc, argv)
161827088Sminshall 	int argc;
161927088Sminshall 	char *argv[];
162027088Sminshall {
162127088Sminshall 	register char *arg;
162227088Sminshall 	char buf[50];
162327088Sminshall 
1624*27186Sminshall 	printf(
1625*27186Sminshall 	    "Deprecated usage - please use 'set escape%s%s' in the future.\n",
1626*27186Sminshall 				(argc > 2)? " ":"", (argc > 2)? argv[1]: "");
162727088Sminshall 	if (argc > 2)
162827088Sminshall 		arg = argv[1];
162927088Sminshall 	else {
163027088Sminshall 		printf("new escape character: ");
163127088Sminshall 		gets(buf);
163227088Sminshall 		arg = buf;
163327088Sminshall 	}
163427088Sminshall 	if (arg[0] != '\0')
163527088Sminshall 		escape = arg[0];
163627088Sminshall 	printf("Escape character is '%s'.\n", control(escape));
163727088Sminshall 	fflush(stdout);
163827088Sminshall }
163927088Sminshall 
164027088Sminshall /*VARARGS*/
164127088Sminshall suspend()
164227088Sminshall {
164327110Sminshall 	setcommandmode();
164427088Sminshall 	kill(0, SIGTSTP);
164527088Sminshall 	/* reget parameters in case they were changed */
164627088Sminshall 	ioctl(0, TIOCGETP, (char *)&ottyb);
164727088Sminshall 	ioctl(0, TIOCGETC, (char *)&otc);
164827088Sminshall 	ioctl(0, TIOCGLTC, (char *)&oltc);
164927088Sminshall }
165027088Sminshall 
165127088Sminshall /*VARARGS*/
165227088Sminshall bye()
165327088Sminshall {
165427088Sminshall 	register char *op;
165527088Sminshall 
165627088Sminshall 	if (connected) {
165727088Sminshall 		shutdown(net, 2);
165827088Sminshall 		printf("Connection closed.\n");
165927088Sminshall 		close(net);
166027088Sminshall 		connected = 0;
166127088Sminshall 		/* reset his options */
166227088Sminshall 		for (op = hisopts; op < &hisopts[256]; op++)
166327088Sminshall 			*op = 0;
166427088Sminshall 	}
166527088Sminshall }
166627088Sminshall 
166727088Sminshall /*VARARGS*/
166827088Sminshall quit()
166927088Sminshall {
167027088Sminshall 	call(bye, "bye", 0);
167127088Sminshall 	exit(0);
167227088Sminshall }
167327088Sminshall 
167427088Sminshall /*
167527088Sminshall  * Print status about the connection.
167627088Sminshall  */
1677*27186Sminshall /*ARGSUSED*/
167827178Sminshall status(argc, argv)
167927178Sminshall int	argc;
168027178Sminshall char	*argv[];
168127088Sminshall {
168227178Sminshall     if (connected) {
168327178Sminshall 	printf("Connected to %s.\n", hostname);
168427178Sminshall 	if (argc < 2) {
168527178Sminshall 	    printf("Operating in %s.\n", modedescriptions[getconnmode()]);
168627178Sminshall 	    if (localsigs || ((!donelclsigs) && (getconnmode() >= 3))) {
168727178Sminshall 		printf("Catching signals locally.\n");
168827178Sminshall 	    }
168927110Sminshall 	}
169027178Sminshall     } else {
169127178Sminshall 	printf("No connection.\n");
169227178Sminshall     }
169327178Sminshall     printf("Escape character is '%s'.\n", control(escape));
169427178Sminshall     fflush(stdout);
169527088Sminshall }
169627088Sminshall 
169727088Sminshall tn(argc, argv)
169827088Sminshall 	int argc;
169927088Sminshall 	char *argv[];
170027088Sminshall {
170127088Sminshall 	register struct hostent *host = 0;
170227088Sminshall 
170327088Sminshall 	if (connected) {
170427088Sminshall 		printf("?Already connected to %s\n", hostname);
170527088Sminshall 		return;
170627088Sminshall 	}
170727088Sminshall 	if (argc < 2) {
1708*27186Sminshall 		(void) strcpy(line, "Connect ");
170927088Sminshall 		printf("(to) ");
171027088Sminshall 		gets(&line[strlen(line)]);
171127088Sminshall 		makeargv();
171227088Sminshall 		argc = margc;
171327088Sminshall 		argv = margv;
171427088Sminshall 	}
171527088Sminshall 	if (argc > 3) {
171627088Sminshall 		printf("usage: %s host-name [port]\n", argv[0]);
171727088Sminshall 		return;
171827088Sminshall 	}
171927088Sminshall 	sin.sin_addr.s_addr = inet_addr(argv[1]);
172027088Sminshall 	if (sin.sin_addr.s_addr != -1) {
172127088Sminshall 		sin.sin_family = AF_INET;
1722*27186Sminshall 		(void) strcpy(hnamebuf, argv[1]);
172327088Sminshall 		hostname = hnamebuf;
172427088Sminshall 	} else {
172527088Sminshall 		host = gethostbyname(argv[1]);
172627088Sminshall 		if (host) {
172727088Sminshall 			sin.sin_family = host->h_addrtype;
172827088Sminshall 			bcopy(host->h_addr_list[0], (caddr_t)&sin.sin_addr,
172927088Sminshall 				host->h_length);
173027088Sminshall 			hostname = host->h_name;
173127088Sminshall 		} else {
173227088Sminshall 			printf("%s: unknown host\n", argv[1]);
173327088Sminshall 			return;
173427088Sminshall 		}
173527088Sminshall 	}
173627088Sminshall 	sin.sin_port = sp->s_port;
173727088Sminshall 	if (argc == 3) {
173827088Sminshall 		sin.sin_port = atoi(argv[2]);
1739*27186Sminshall 		if (sin.sin_port == 0) {
174027088Sminshall 			sp = getservbyname(argv[2], "tcp");
174127088Sminshall 			if (sp)
174227088Sminshall 				sin.sin_port = sp->s_port;
174327088Sminshall 			else {
174427088Sminshall 				printf("%s: bad port number\n", argv[2]);
174527088Sminshall 				return;
174627088Sminshall 			}
174727088Sminshall 		} else {
174827088Sminshall 			sin.sin_port = atoi(argv[2]);
174927088Sminshall 			sin.sin_port = htons(sin.sin_port);
175027088Sminshall 		}
175127088Sminshall 		telnetport = 0;
175227110Sminshall 	} else {
175327110Sminshall 		telnetport = 1;
175427088Sminshall 	}
175527088Sminshall 	signal(SIGINT, intr);
175627110Sminshall 	signal(SIGQUIT, intr2);
175727088Sminshall 	signal(SIGPIPE, deadpeer);
175827088Sminshall 	printf("Trying...\n");
175927088Sminshall 	do {
176027088Sminshall 		net = socket(AF_INET, SOCK_STREAM, 0);
176127088Sminshall 		if (net < 0) {
176227088Sminshall 			perror("telnet: socket");
176327088Sminshall 			return;
176427088Sminshall 		}
1765*27186Sminshall 		if (debug &&
1766*27186Sminshall 				setsockopt(net, SOL_SOCKET, SO_DEBUG,
1767*27186Sminshall 					(char *)&debug, sizeof(debug)) < 0) {
176827088Sminshall 			perror("setsockopt (SO_DEBUG)");
1769*27186Sminshall 		}
1770*27186Sminshall 		if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
177127088Sminshall 			if (host && host->h_addr_list[1]) {
177227088Sminshall 				int oerrno = errno;
177327088Sminshall 
177427088Sminshall 				fprintf(stderr,
177527088Sminshall 				    "telnet: connect to address %s: ",
177627088Sminshall 				    inet_ntoa(sin.sin_addr));
177727088Sminshall 				errno = oerrno;
1778*27186Sminshall 				perror((char *)0);
177927088Sminshall 				host->h_addr_list++;
178027088Sminshall 				bcopy(host->h_addr_list[0],
178127088Sminshall 				    (caddr_t)&sin.sin_addr, host->h_length);
178227088Sminshall 				fprintf(stderr, "Trying %s...\n",
178327088Sminshall 					inet_ntoa(sin.sin_addr));
178427088Sminshall 				(void) close(net);
178527088Sminshall 				continue;
178627088Sminshall 			}
178727088Sminshall 			perror("telnet: connect");
178827088Sminshall 			signal(SIGINT, SIG_DFL);
178927088Sminshall 			return;
179027088Sminshall 		}
179127088Sminshall 		connected++;
179227088Sminshall 	} while (connected == 0);
179327178Sminshall 	call(status, "status", "notmuch", 0);
179427088Sminshall 	if (setjmp(peerdied) == 0)
179527088Sminshall 		telnet();
179627088Sminshall 	fprintf(stderr, "Connection closed by foreign host.\n");
179727088Sminshall 	exit(1);
179827088Sminshall }
179927088Sminshall 
180027088Sminshall 
180127088Sminshall #define HELPINDENT (sizeof ("connect"))
180227088Sminshall 
180327088Sminshall char	openhelp[] =	"connect to a site";
180427088Sminshall char	closehelp[] =	"close current connection";
180527088Sminshall char	quithelp[] =	"exit telnet";
180627088Sminshall char	zhelp[] =	"suspend telnet";
180727088Sminshall char	escapehelp[] =	"set escape character";
180827088Sminshall char	statushelp[] =	"print status information";
180927088Sminshall char	helphelp[] =	"print help information";
181027110Sminshall char	sendhelp[] =	"transmit special characters ('send ?' for more)";
181127178Sminshall char	sethelp[] = 	"set operating parameters ('set ?' for more)";
181227178Sminshall char	togglestring[] ="toggle operating parameters ('toggle ?' for more)";
181327178Sminshall char	displayhelp[] =	"display operating parameters";
181427178Sminshall char	modehelp[] =
181527178Sminshall 		"try to enter line-by-line or character-at-a-time mode";
181627088Sminshall 
181727088Sminshall int	help();
181827088Sminshall 
181927088Sminshall struct cmd cmdtab[] = {
182027110Sminshall 	{ "open",	openhelp,	tn,		1, 0 },
182127110Sminshall 	{ "close",	closehelp,	bye,		1, 1 },
182227110Sminshall 	{ "quit",	quithelp,	quit,		1, 0 },
182327110Sminshall 	{ "z",		zhelp,		suspend,	1, 0 },
182427110Sminshall 	{ "escape",	escapehelp,	setescape,	1, 0 },
182527110Sminshall 	{ "status",	statushelp,	status,		1, 0 },
182627178Sminshall 	{ "crmod",	crmodhelp,	togcrmod,	1, 0 },
182727110Sminshall 	{ "send",	sendhelp,	sendcmd,	1, 1 },
182827110Sminshall 	{ "transmit",	sendhelp,	sendcmd,	0, 1 },
182927110Sminshall 	{ "xmit",	sendhelp,	sendcmd,	0, 1 },
183027178Sminshall 	{ "set",	sethelp,	setcmd,		1, 0 },
183127110Sminshall 	{ "toggle",	togglestring,	toggle,		1, 0 },
183227178Sminshall 	{ "display",	displayhelp,	display,	1, 0 },
183327178Sminshall 	{ "mode",	modehelp,	modecmd,	1, 1 },
183427110Sminshall 	{ "?",		helphelp,	help,		1, 0 },
183527110Sminshall 	{ "help",	helphelp,	help,		0, 0 },
183627088Sminshall 	0
183727088Sminshall };
183827088Sminshall 
183927088Sminshall 
184027088Sminshall /*
184127088Sminshall  * Help command.
184227088Sminshall  */
184327088Sminshall help(argc, argv)
184427088Sminshall 	int argc;
184527088Sminshall 	char *argv[];
184627088Sminshall {
184727088Sminshall 	register struct cmd *c;
184827088Sminshall 
184927088Sminshall 	if (argc == 1) {
185027088Sminshall 		printf("Commands may be abbreviated.  Commands are:\n\n");
185127088Sminshall 		for (c = cmdtab; c->name; c++)
185227088Sminshall 			if (c->dohelp) {
185327088Sminshall 				printf("%-*s\t%s\n", HELPINDENT, c->name,
185427088Sminshall 								    c->help);
185527088Sminshall 			}
185627088Sminshall 		return;
185727088Sminshall 	}
185827088Sminshall 	while (--argc > 0) {
185927088Sminshall 		register char *arg;
186027088Sminshall 		arg = *++argv;
186127088Sminshall 		c = getcmd(arg);
1862*27186Sminshall 		if (c == Ambiguous(struct cmd *))
186327088Sminshall 			printf("?Ambiguous help command %s\n", arg);
186427088Sminshall 		else if (c == (struct cmd *)0)
186527088Sminshall 			printf("?Invalid help command %s\n", arg);
186627088Sminshall 		else
186727088Sminshall 			printf("%s\n", c->help);
186827088Sminshall 	}
186927088Sminshall }
187027088Sminshall /*
187127088Sminshall  * Call routine with argc, argv set from args (terminated by 0).
187227088Sminshall  * VARARGS2
187327088Sminshall  */
187427088Sminshall call(routine, args)
187527088Sminshall 	int (*routine)();
1876*27186Sminshall 	char *args;
187727088Sminshall {
1878*27186Sminshall 	register char **argp;
187927088Sminshall 	register int argc;
188027088Sminshall 
188127088Sminshall 	for (argc = 0, argp = &args; *argp++ != 0; argc++)
188227088Sminshall 		;
188327088Sminshall 	(*routine)(argc, &args);
188427088Sminshall }
188527088Sminshall 
188627088Sminshall makeargv()
188727088Sminshall {
188827088Sminshall 	register char *cp;
188927088Sminshall 	register char **argp = margv;
189027088Sminshall 
189127088Sminshall 	margc = 0;
189227088Sminshall 	for (cp = line; *cp;) {
189327088Sminshall 		while (isspace(*cp))
189427088Sminshall 			cp++;
189527088Sminshall 		if (*cp == '\0')
189627088Sminshall 			break;
189727088Sminshall 		*argp++ = cp;
189827088Sminshall 		margc += 1;
189927088Sminshall 		while (*cp != '\0' && !isspace(*cp))
190027088Sminshall 			cp++;
190127088Sminshall 		if (*cp == '\0')
190227088Sminshall 			break;
190327088Sminshall 		*cp++ = '\0';
190427088Sminshall 	}
190527088Sminshall 	*argp++ = 0;
190627088Sminshall }
190727088Sminshall 
190827088Sminshall char **
190927088Sminshall getnextcmd(name)
191027088Sminshall char *name;
191127088Sminshall {
191227088Sminshall     struct cmd *c = (struct cmd *) name;
191327088Sminshall 
191427088Sminshall     return (char **) (c+1);
191527088Sminshall }
191627088Sminshall 
191727088Sminshall struct cmd *
191827088Sminshall getcmd(name)
191927088Sminshall char *name;
192027088Sminshall {
192127088Sminshall     return (struct cmd *) genget(name, (char **) cmdtab, getnextcmd);
192227088Sminshall }
192327088Sminshall 
192427088Sminshall command(top)
192527088Sminshall 	int top;
192627088Sminshall {
192727088Sminshall 	register struct cmd *c;
192827088Sminshall 
192927110Sminshall 	setcommandmode();
193027088Sminshall 	if (!top)
193127088Sminshall 		putchar('\n');
193227088Sminshall 	else
193327088Sminshall 		signal(SIGINT, SIG_DFL);
193427088Sminshall 	for (;;) {
193527088Sminshall 		printf("%s> ", prompt);
193627088Sminshall 		if (gets(line) == 0) {
193727088Sminshall 			if (feof(stdin))
193827088Sminshall 				quit();
193927088Sminshall 			break;
194027088Sminshall 		}
194127088Sminshall 		if (line[0] == 0)
194227088Sminshall 			break;
194327088Sminshall 		makeargv();
194427088Sminshall 		c = getcmd(margv[0]);
1945*27186Sminshall 		if (c == Ambiguous(struct cmd *)) {
194627088Sminshall 			printf("?Ambiguous command\n");
194727088Sminshall 			continue;
194827088Sminshall 		}
194927088Sminshall 		if (c == 0) {
195027088Sminshall 			printf("?Invalid command\n");
195127088Sminshall 			continue;
195227088Sminshall 		}
195327088Sminshall 		if (c->needconnect && !connected) {
195427088Sminshall 			printf("?Need to be connected first.\n");
195527088Sminshall 			continue;
195627088Sminshall 		}
195727088Sminshall 		(*c->handler)(margc, margv);
195827088Sminshall 		if (c->handler != help)
195927088Sminshall 			break;
196027088Sminshall 	}
196127088Sminshall 	if (!top) {
196227110Sminshall 		if (!connected) {
196327088Sminshall 			longjmp(toplevel, 1);
196427110Sminshall 			/*NOTREACHED*/
196527110Sminshall 		}
196627110Sminshall 		setconnmode();
196727088Sminshall 	}
196827088Sminshall }
1969*27186Sminshall 
1970*27186Sminshall /*
1971*27186Sminshall  * main.  Parse arguments, invoke the protocol or command parser.
1972*27186Sminshall  */
1973*27186Sminshall 
1974*27186Sminshall 
1975*27186Sminshall main(argc, argv)
1976*27186Sminshall 	int argc;
1977*27186Sminshall 	char *argv[];
1978*27186Sminshall {
1979*27186Sminshall 	sp = getservbyname("telnet", "tcp");
1980*27186Sminshall 	if (sp == 0) {
1981*27186Sminshall 		fprintf(stderr, "telnet: tcp/telnet: unknown service\n");
1982*27186Sminshall 		exit(1);
1983*27186Sminshall 	}
1984*27186Sminshall 	NetTrace = stdout;
1985*27186Sminshall 	ioctl(0, TIOCGETP, (char *)&ottyb);
1986*27186Sminshall 	ioctl(0, TIOCGETC, (char *)&otc);
1987*27186Sminshall 	ioctl(0, TIOCGLTC, (char *)&oltc);
1988*27186Sminshall 	ntc = otc;
1989*27186Sminshall 	ntc.t_eofc = -1;		/* we don't want to use EOF */
1990*27186Sminshall 	nttyb = ottyb;
1991*27186Sminshall 	setbuf(stdin, (char *)0);
1992*27186Sminshall 	setbuf(stdout, (char *)0);
1993*27186Sminshall 	prompt = argv[0];
1994*27186Sminshall 	if (argc > 1 && !strcmp(argv[1], "-d")) {
1995*27186Sminshall 		debug = 1;
1996*27186Sminshall 		argv++;
1997*27186Sminshall 		argc--;
1998*27186Sminshall 	}
1999*27186Sminshall 	if (argc > 1 && !strcmp(argv[1], "-n")) {
2000*27186Sminshall 	    argv++;
2001*27186Sminshall 	    argc--;
2002*27186Sminshall 	    if (argc > 1) {		/* get file name */
2003*27186Sminshall 		NetTrace = fopen(argv[1], "w");
2004*27186Sminshall 		argv++;
2005*27186Sminshall 		argc--;
2006*27186Sminshall 		if (NetTrace == NULL) {
2007*27186Sminshall 		    NetTrace = stdout;
2008*27186Sminshall 		}
2009*27186Sminshall 	    }
2010*27186Sminshall 	}
2011*27186Sminshall 	if (argc != 1) {
2012*27186Sminshall 		if (setjmp(toplevel) != 0)
2013*27186Sminshall 			exit(0);
2014*27186Sminshall 		tn(argc, argv);
2015*27186Sminshall 	}
2016*27186Sminshall 	setjmp(toplevel);
2017*27186Sminshall 	for (;;)
2018*27186Sminshall 		command(1);
2019*27186Sminshall }
2020