xref: /csrg-svn/usr.bin/telnet/commands.c (revision 47609)
133685Sbostic /*
245233Sborman  * Copyright (c) 1988, 1990 Regents of the University of California.
333685Sbostic  * All rights reserved.
433685Sbostic  *
542770Sbostic  * %sccs.include.redist.c%
633685Sbostic  */
733685Sbostic 
833685Sbostic #ifndef lint
9*47609Sdab static char sccsid[] = "@(#)commands.c	5.5 (Berkeley) 03/22/91";
1033685Sbostic #endif /* not lint */
1133685Sbostic 
1236274Sminshall #if	defined(unix)
1345241Swilliam #include <sys/param.h>
1446808Sdab #ifdef	CRAY
1546808Sdab #include <sys/types.h>
1646808Sdab #endif
1736274Sminshall #include <sys/file.h>
1845241Swilliam #else
1945241Swilliam #include <sys/types.h>
2036274Sminshall #endif	/* defined(unix) */
2132144Sminshall #include <sys/socket.h>
2232144Sminshall #include <netinet/in.h>
2338689Sborman #ifdef	CRAY
2446808Sdab #include <fcntl.h>
2538810Sborman #endif	/* CRAY */
2632144Sminshall 
2732144Sminshall #include <signal.h>
2832144Sminshall #include <netdb.h>
2932144Sminshall #include <ctype.h>
3045008Skarels #include <pwd.h>
3135298Sminshall #include <varargs.h>
3246808Sdab #include <errno.h>
3332144Sminshall 
3432144Sminshall #include <arpa/telnet.h>
3532144Sminshall 
3634305Sminshall #include "general.h"
3734305Sminshall 
3832381Sminshall #include "ring.h"
3932381Sminshall 
4032144Sminshall #include "externs.h"
4132144Sminshall #include "defines.h"
4232144Sminshall #include "types.h"
4332144Sminshall 
4446808Sdab #ifndef CRAY
4546808Sdab #include <netinet/in_systm.h>
4646808Sdab # if (defined(vax) || defined(tahoe) || defined(hp300)) && !defined(ultrix)
4746808Sdab # include <machine/endian.h>
4846808Sdab # endif /* vax */
4946808Sdab #endif /* CRAY */
5044361Sborman #include <netinet/ip.h>
5138689Sborman 
5238689Sborman 
5346808Sdab #ifndef       MAXHOSTNAMELEN
5446808Sdab #define       MAXHOSTNAMELEN 64
5546808Sdab #endif        MAXHOSTNAMELEN
5640248Sborman 
5746815Sdab #if	defined(IPPROTO_IP) && defined(IP_TOS)
5846815Sdab int tos = -1;
5946815Sdab #endif	/* defined(IPPROTO_IP) && defined(IP_TOS) */
6046815Sdab 
6132144Sminshall char	*hostname;
6246808Sdab static char _hostname[MAXHOSTNAMELEN];
6346808Sdab 
6438689Sborman extern char *getenv();
6532144Sminshall 
6646808Sdab extern int isprefix();
6746808Sdab extern char **genget();
6846808Sdab extern int Ambiguous();
6946808Sdab 
7044361Sborman static call();
7132144Sminshall 
7232144Sminshall typedef struct {
7332144Sminshall 	char	*name;		/* command name */
7438689Sborman 	char	*help;		/* help string (NULL for no help) */
7532144Sminshall 	int	(*handler)();	/* routine which executes command */
7632144Sminshall 	int	needconnect;	/* Do we need to be connected to execute? */
7732144Sminshall } Command;
7832144Sminshall 
7938689Sborman static char line[256];
8038689Sborman static char saveline[256];
8132144Sminshall static int margc;
8232144Sminshall static char *margv[20];
8332144Sminshall 
8446808Sdab     static void
8532144Sminshall makeargv()
8632144Sminshall {
8744361Sborman     register char *cp, *cp2, c;
8832144Sminshall     register char **argp = margv;
8932144Sminshall 
9032144Sminshall     margc = 0;
9132144Sminshall     cp = line;
9232144Sminshall     if (*cp == '!') {		/* Special case shell escape */
9338689Sborman 	strcpy(saveline, line);	/* save for shell command */
9432144Sminshall 	*argp++ = "!";		/* No room in string to get this */
9532144Sminshall 	margc++;
9632144Sminshall 	cp++;
9732144Sminshall     }
9844361Sborman     while (c = *cp) {
9944361Sborman 	register int inquote = 0;
10044361Sborman 	while (isspace(c))
10144361Sborman 	    c = *++cp;
10244361Sborman 	if (c == '\0')
10332144Sminshall 	    break;
10432144Sminshall 	*argp++ = cp;
10532144Sminshall 	margc += 1;
10644361Sborman 	for (cp2 = cp; c != '\0'; c = *++cp) {
10744361Sborman 	    if (inquote) {
10844361Sborman 		if (c == inquote) {
10944361Sborman 		    inquote = 0;
11044361Sborman 		    continue;
11144361Sborman 		}
11244361Sborman 	    } else {
11344361Sborman 		if (c == '\\') {
11444361Sborman 		    if ((c = *++cp) == '\0')
11544361Sborman 			break;
11644361Sborman 		} else if (c == '"') {
11744361Sborman 		    inquote = '"';
11844361Sborman 		    continue;
11944361Sborman 		} else if (c == '\'') {
12044361Sborman 		    inquote = '\'';
12144361Sborman 		    continue;
12244361Sborman 		} else if (isspace(c))
12344361Sborman 		    break;
12444361Sborman 	    }
12544361Sborman 	    *cp2++ = c;
12644361Sborman 	}
12744361Sborman 	*cp2 = '\0';
12844361Sborman 	if (c == '\0')
12932144Sminshall 	    break;
13044361Sborman 	cp++;
13132144Sminshall     }
13232144Sminshall     *argp++ = 0;
13332144Sminshall }
13432144Sminshall 
13532144Sminshall /*
13632144Sminshall  * Make a character string into a number.
13732144Sminshall  *
13832144Sminshall  * Todo:  1.  Could take random integers (12, 0x12, 012, 0b1).
13932144Sminshall  */
14032144Sminshall 
14146808Sdab 	static
14232144Sminshall special(s)
14346808Sdab 	register char *s;
14432144Sminshall {
14532144Sminshall 	register char c;
14632144Sminshall 	char b;
14732144Sminshall 
14832144Sminshall 	switch (*s) {
14932144Sminshall 	case '^':
15032144Sminshall 		b = *++s;
15132144Sminshall 		if (b == '?') {
15232144Sminshall 		    c = b | 0x40;		/* DEL */
15332144Sminshall 		} else {
15432144Sminshall 		    c = b & 0x1f;
15532144Sminshall 		}
15632144Sminshall 		break;
15732144Sminshall 	default:
15832144Sminshall 		c = *s;
15932144Sminshall 		break;
16032144Sminshall 	}
16132144Sminshall 	return c;
16232144Sminshall }
16332144Sminshall 
16432144Sminshall /*
16532144Sminshall  * Construct a control character sequence
16632144Sminshall  * for a special character.
16732144Sminshall  */
16846808Sdab 	static char *
16932144Sminshall control(c)
17040245Sborman 	register cc_t c;
17132144Sminshall {
17244361Sborman 	static char buf[5];
17346808Sdab 	/*
17446808Sdab 	 * The only way I could get the Sun 3.5 compiler
17546808Sdab 	 * to shut up about
17646808Sdab 	 *	if ((unsigned int)c >= 0x80)
17746808Sdab 	 * was to assign "c" to an unsigned int variable...
17846808Sdab 	 * Arggg....
17946808Sdab 	 */
18046808Sdab 	register unsigned int uic = (unsigned int)c;
18132144Sminshall 
18246808Sdab 	if (uic == 0x7f)
18332144Sminshall 		return ("^?");
18445233Sborman 	if (c == (cc_t)_POSIX_VDISABLE) {
18532144Sminshall 		return "off";
18632144Sminshall 	}
18746808Sdab 	if (uic >= 0x80) {
18844361Sborman 		buf[0] = '\\';
18944361Sborman 		buf[1] = ((c>>6)&07) + '0';
19044361Sborman 		buf[2] = ((c>>3)&07) + '0';
19144361Sborman 		buf[3] = (c&07) + '0';
19244361Sborman 		buf[4] = 0;
19346808Sdab 	} else if (uic >= 0x20) {
19432144Sminshall 		buf[0] = c;
19532144Sminshall 		buf[1] = 0;
19632144Sminshall 	} else {
19732144Sminshall 		buf[0] = '^';
19832144Sminshall 		buf[1] = '@'+c;
19932144Sminshall 		buf[2] = 0;
20032144Sminshall 	}
20132144Sminshall 	return (buf);
20232144Sminshall }
20332144Sminshall 
20432144Sminshall 
20532144Sminshall 
20632144Sminshall /*
20732144Sminshall  *	The following are data structures and routines for
20832144Sminshall  *	the "send" command.
20932144Sminshall  *
21032144Sminshall  */
21132144Sminshall 
21232144Sminshall struct sendlist {
21332144Sminshall     char	*name;		/* How user refers to it (case independent) */
21432144Sminshall     char	*help;		/* Help information (0 ==> no help) */
21546808Sdab     int		needconnect;	/* Need to be connected */
21646808Sdab     int		narg;		/* Number of arguments */
21738689Sborman     int		(*handler)();	/* Routine to perform (for special ops) */
21846808Sdab     int		nbyte;		/* Number of bytes to send this command */
21938689Sborman     int		what;		/* Character to be sent (<0 ==> special) */
22032144Sminshall };
22132144Sminshall 
22232144Sminshall 
22346808Sdab extern int
22446808Sdab 	send_esc P((void)),
22546808Sdab 	send_help P((void)),
22646808Sdab 	send_docmd P((char *)),
22746808Sdab 	send_dontcmd P((char *)),
22846808Sdab 	send_willcmd P((char *)),
22946808Sdab 	send_wontcmd P((char *));
23046808Sdab 
23132144Sminshall static struct sendlist Sendlist[] = {
23246808Sdab     { "ao",	"Send Telnet Abort output",		1, 0, 0, 2, AO },
23346808Sdab     { "ayt",	"Send Telnet 'Are You There'",		1, 0, 0, 2, AYT },
23446808Sdab     { "brk",	"Send Telnet Break",			1, 0, 0, 2, BREAK },
23546808Sdab     { "break",	0,					1, 0, 0, 2, BREAK },
23646808Sdab     { "ec",	"Send Telnet Erase Character",		1, 0, 0, 2, EC },
23746808Sdab     { "el",	"Send Telnet Erase Line",		1, 0, 0, 2, EL },
23846808Sdab     { "escape",	"Send current escape character",	1, 0, send_esc, 1, 0 },
23946808Sdab     { "ga",	"Send Telnet 'Go Ahead' sequence",	1, 0, 0, 2, GA },
24046808Sdab     { "ip",	"Send Telnet Interrupt Process",	1, 0, 0, 2, IP },
24146808Sdab     { "intp",	0,					1, 0, 0, 2, IP },
24246808Sdab     { "interrupt", 0,					1, 0, 0, 2, IP },
24346808Sdab     { "intr",	0,					1, 0, 0, 2, IP },
24446808Sdab     { "nop",	"Send Telnet 'No operation'",		1, 0, 0, 2, NOP },
24546808Sdab     { "eor",	"Send Telnet 'End of Record'",		1, 0, 0, 2, EOR },
24646808Sdab     { "abort",	"Send Telnet 'Abort Process'",		1, 0, 0, 2, ABORT },
24746808Sdab     { "susp",	"Send Telnet 'Suspend Process'",	1, 0, 0, 2, SUSP },
24846808Sdab     { "eof",	"Send Telnet End of File Character",	1, 0, 0, 2, xEOF },
24946808Sdab     { "synch",	"Perform Telnet 'Synch operation'",	1, 0, dosynch, 2, 0 },
25046808Sdab     { "getstatus", "Send request for STATUS",		1, 0, get_status, 6, 0 },
25146808Sdab     { "?",	"Display send options",			0, 0, send_help, 0, 0 },
25246808Sdab     { "help",	0,					0, 0, send_help, 0, 0 },
25346808Sdab     { "do",	0,					0, 1, send_docmd, 3, 0 },
25446808Sdab     { "dont",	0,					0, 1, send_dontcmd, 3, 0 },
25546808Sdab     { "will",	0,					0, 1, send_willcmd, 3, 0 },
25646808Sdab     { "wont",	0,					0, 1, send_wontcmd, 3, 0 },
25732144Sminshall     { 0 }
25832144Sminshall };
25932144Sminshall 
26046808Sdab #define	GETSEND(name) ((struct sendlist *) genget(name, (char **) Sendlist, \
26146808Sdab 				sizeof(struct sendlist)))
26232144Sminshall 
26346808Sdab     static int
26432144Sminshall sendcmd(argc, argv)
26546808Sdab     int  argc;
26646808Sdab     char **argv;
26732144Sminshall {
26832144Sminshall     int what;		/* what we are sending this time */
26932144Sminshall     int count;		/* how many bytes we are going to need to send */
27032144Sminshall     int i;
27132144Sminshall     int question = 0;	/* was at least one argument a question */
27232144Sminshall     struct sendlist *s;	/* pointer to current command */
27346808Sdab     int success = 0;
27446808Sdab     int needconnect = 0;
27532144Sminshall 
27632144Sminshall     if (argc < 2) {
27732144Sminshall 	printf("need at least one argument for 'send' command\n");
27832144Sminshall 	printf("'send ?' for help\n");
27932144Sminshall 	return 0;
28032144Sminshall     }
28132144Sminshall     /*
28232144Sminshall      * First, validate all the send arguments.
28332144Sminshall      * In addition, we see how much space we are going to need, and
28432144Sminshall      * whether or not we will be doing a "SYNCH" operation (which
28532144Sminshall      * flushes the network queue).
28632144Sminshall      */
28732144Sminshall     count = 0;
28832144Sminshall     for (i = 1; i < argc; i++) {
28946808Sdab 	s = GETSEND(argv[i]);
29032144Sminshall 	if (s == 0) {
29132144Sminshall 	    printf("Unknown send argument '%s'\n'send ?' for help.\n",
29232144Sminshall 			argv[i]);
29332144Sminshall 	    return 0;
29432144Sminshall 	} else if (Ambiguous(s)) {
29532144Sminshall 	    printf("Ambiguous send argument '%s'\n'send ?' for help.\n",
29632144Sminshall 			argv[i]);
29732144Sminshall 	    return 0;
29832144Sminshall 	}
29946808Sdab 	if (i + s->narg >= argc) {
30046808Sdab 	    fprintf(stderr,
30146808Sdab 	    "Need %d argument%s to 'send %s' command.  'send %s ?' for help.\n",
30246808Sdab 		s->narg, s->narg == 1 ? "" : "s", s->name, s->name);
30346808Sdab 	    return 0;
30432144Sminshall 	}
30546808Sdab 	count += s->nbyte;
30646808Sdab 	if (s->handler == send_help) {
30746808Sdab 	    send_help();
30846808Sdab 	    return 0;
30946808Sdab 	}
31046808Sdab 
31146808Sdab 	i += s->narg;
31246808Sdab 	needconnect += s->needconnect;
31332144Sminshall     }
31446808Sdab     if (!connected && needconnect) {
31546808Sdab 	printf("?Need to be connected first.\n");
31646808Sdab 	printf("'send ?' for help\n");
31746808Sdab 	return 0;
31838689Sborman     }
31932144Sminshall     /* Now, do we have enough room? */
32032144Sminshall     if (NETROOM() < count) {
32132144Sminshall 	printf("There is not enough room in the buffer TO the network\n");
32232144Sminshall 	printf("to process your request.  Nothing will be done.\n");
32332144Sminshall 	printf("('send synch' will throw away most data in the network\n");
32432144Sminshall 	printf("buffer, if this might help.)\n");
32532144Sminshall 	return 0;
32632144Sminshall     }
32732144Sminshall     /* OK, they are all OK, now go through again and actually send */
32846808Sdab     count = 0;
32932144Sminshall     for (i = 1; i < argc; i++) {
33046808Sdab 	if ((s = GETSEND(argv[i])) == 0) {
33132144Sminshall 	    fprintf(stderr, "Telnet 'send' error - argument disappeared!\n");
33244361Sborman 	    (void) quit();
33332144Sminshall 	    /*NOTREACHED*/
33432144Sminshall 	}
33538689Sborman 	if (s->handler) {
33646808Sdab 	    count++;
33746808Sdab 	    success += (*s->handler)((s->narg > 0) ? argv[i+1] : 0,
33846808Sdab 				  (s->narg > 1) ? argv[i+2] : 0);
33946808Sdab 	    i += s->narg;
34032144Sminshall 	} else {
34146808Sdab 	    NET2ADD(IAC, what);
34246808Sdab 	    printoption("SENT", IAC, what);
34346808Sdab 	}
34446808Sdab     }
34546808Sdab     return (count == success);
34646808Sdab }
34746808Sdab 
34846808Sdab     static int
34946808Sdab send_esc()
35046808Sdab {
35146808Sdab     NETADD(escape);
35246808Sdab     return 1;
35346808Sdab }
35446808Sdab 
35546808Sdab     static int
35646808Sdab send_docmd(name)
35746808Sdab     char *name;
35846808Sdab {
35946808Sdab     void send_do();
36046808Sdab     return(send_tncmd(send_do, "do", name));
36146808Sdab }
36246808Sdab 
36346808Sdab     static int
36446808Sdab send_dontcmd(name)
36546808Sdab     char *name;
36646808Sdab {
36746808Sdab     void send_dont();
36846808Sdab     return(send_tncmd(send_dont, "dont", name));
36946808Sdab }
37046808Sdab     static int
37146808Sdab send_willcmd(name)
37246808Sdab     char *name;
37346808Sdab {
37446808Sdab     void send_will();
37546808Sdab     return(send_tncmd(send_will, "will", name));
37646808Sdab }
37746808Sdab     static int
37846808Sdab send_wontcmd(name)
37946808Sdab     char *name;
38046808Sdab {
38146808Sdab     void send_wont();
38246808Sdab     return(send_tncmd(send_wont, "wont", name));
38346808Sdab }
38446808Sdab 
38546808Sdab     int
38646808Sdab send_tncmd(func, cmd, name)
38746808Sdab     void	(*func)();
38846808Sdab     char	*cmd, *name;
38946808Sdab {
39046808Sdab     char **cpp;
39146808Sdab     extern char *telopts[];
39246808Sdab 
39346808Sdab     if (isprefix(name, "help") || isprefix(name, "?")) {
39446808Sdab 	register int col, len;
39546808Sdab 
39646808Sdab 	printf("Usage: send %s <option>\n", cmd);
39746808Sdab 	printf("Valid options are:\n\t");
39846808Sdab 
39946808Sdab 	col = 8;
40046808Sdab 	for (cpp = telopts; *cpp; cpp++) {
40146808Sdab 	    len = strlen(*cpp) + 1;
40246808Sdab 	    if (col + len > 65) {
40346808Sdab 		printf("\n\t");
40446808Sdab 		col = 8;
40532144Sminshall 	    }
40646808Sdab 	    printf(" %s", *cpp);
40746808Sdab 	    col += len;
40832144Sminshall 	}
40946808Sdab 	printf("\n");
41046808Sdab 	return 0;
41132144Sminshall     }
41246808Sdab     cpp = (char **)genget(name, telopts, sizeof(char *));
41346808Sdab     if (Ambiguous(cpp)) {
41446808Sdab 	fprintf(stderr,"'%s': ambiguous argument ('send %s ?' for help).\n",
41546808Sdab 					name, cmd);
41646808Sdab 	return 0;
41746808Sdab     }
41846808Sdab     if (cpp == 0) {
41946808Sdab 	fprintf(stderr, "'%s': unknown argument ('send %s ?' for help).\n",
42046808Sdab 					name, cmd);
42146808Sdab 	return 0;
42246808Sdab     }
42346808Sdab     if (!connected) {
42446808Sdab 	printf("?Need to be connected first.\n");
42546808Sdab 	return 0;
42646808Sdab     }
42746808Sdab     (*func)(cpp - telopts, 1);
42846808Sdab     return 1;
42932144Sminshall }
43046808Sdab 
43146808Sdab     static int
43246808Sdab send_help()
43346808Sdab {
43446808Sdab     struct sendlist *s;	/* pointer to current command */
43546808Sdab     for (s = Sendlist; s->name; s++) {
43646808Sdab 	if (s->help)
43746808Sdab 	    printf("%-15s %s\n", s->name, s->help);
43846808Sdab     }
43946808Sdab     return(0);
44046808Sdab }
44132144Sminshall 
44232144Sminshall /*
44332144Sminshall  * The following are the routines and data structures referred
44432144Sminshall  * to by the arguments to the "toggle" command.
44532144Sminshall  */
44632144Sminshall 
44746808Sdab     static int
44832144Sminshall lclchars()
44932144Sminshall {
45032144Sminshall     donelclchars = 1;
45132144Sminshall     return 1;
45232144Sminshall }
45332144Sminshall 
45446808Sdab     static int
45532144Sminshall togdebug()
45632144Sminshall {
45732144Sminshall #ifndef	NOT43
45832144Sminshall     if (net > 0 &&
45932144Sminshall 	(SetSockOpt(net, SOL_SOCKET, SO_DEBUG, debug)) < 0) {
46032144Sminshall 	    perror("setsockopt (SO_DEBUG)");
46132144Sminshall     }
46232144Sminshall #else	/* NOT43 */
46332144Sminshall     if (debug) {
46432144Sminshall 	if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
46532144Sminshall 	    perror("setsockopt (SO_DEBUG)");
46632144Sminshall     } else
46732144Sminshall 	printf("Cannot turn off socket debugging\n");
46832144Sminshall #endif	/* NOT43 */
46932144Sminshall     return 1;
47032144Sminshall }
47132144Sminshall 
47232144Sminshall 
47346808Sdab     static int
47432144Sminshall togcrlf()
47532144Sminshall {
47632144Sminshall     if (crlf) {
47732144Sminshall 	printf("Will send carriage returns as telnet <CR><LF>.\n");
47832144Sminshall     } else {
47932144Sminshall 	printf("Will send carriage returns as telnet <CR><NUL>.\n");
48032144Sminshall     }
48132144Sminshall     return 1;
48232144Sminshall }
48332144Sminshall 
48438909Sborman int binmode;
48532144Sminshall 
48646808Sdab     static int
48738689Sborman togbinary(val)
48846808Sdab     int val;
48932144Sminshall {
49032144Sminshall     donebinarytoggle = 1;
49132144Sminshall 
49238909Sborman     if (val >= 0) {
49338909Sborman 	binmode = val;
49438909Sborman     } else {
49538909Sborman 	if (my_want_state_is_will(TELOPT_BINARY) &&
49638909Sborman 				my_want_state_is_do(TELOPT_BINARY)) {
49738909Sborman 	    binmode = 1;
49838909Sborman 	} else if (my_want_state_is_wont(TELOPT_BINARY) &&
49938909Sborman 				my_want_state_is_dont(TELOPT_BINARY)) {
50038909Sborman 	    binmode = 0;
50138909Sborman 	}
50238909Sborman 	val = binmode ? 0 : 1;
50338909Sborman     }
50438909Sborman 
50538909Sborman     if (val == 1) {
50638909Sborman 	if (my_want_state_is_will(TELOPT_BINARY) &&
50738909Sborman 					my_want_state_is_do(TELOPT_BINARY)) {
50838689Sborman 	    printf("Already operating in binary mode with remote host.\n");
50938909Sborman 	} else {
51038909Sborman 	    printf("Negotiating binary mode with remote host.\n");
51138909Sborman 	    tel_enter_binary(3);
51238689Sborman 	}
51338909Sborman     } else {
51438909Sborman 	if (my_want_state_is_wont(TELOPT_BINARY) &&
51538909Sborman 					my_want_state_is_dont(TELOPT_BINARY)) {
51638689Sborman 	    printf("Already in network ascii mode with remote host.\n");
51738909Sborman 	} else {
51838909Sborman 	    printf("Negotiating network ascii mode with remote host.\n");
51938909Sborman 	    tel_leave_binary(3);
52038689Sborman 	}
52132144Sminshall     }
52232144Sminshall     return 1;
52332144Sminshall }
52432144Sminshall 
52546808Sdab     static int
52638909Sborman togrbinary(val)
52746808Sdab     int val;
52838909Sborman {
52938909Sborman     donebinarytoggle = 1;
53032144Sminshall 
53138909Sborman     if (val == -1)
53238909Sborman 	val = my_want_state_is_do(TELOPT_BINARY) ? 0 : 1;
53332144Sminshall 
53438909Sborman     if (val == 1) {
53538909Sborman 	if (my_want_state_is_do(TELOPT_BINARY)) {
53638909Sborman 	    printf("Already receiving in binary mode.\n");
53738909Sborman 	} else {
53838909Sborman 	    printf("Negotiating binary mode on input.\n");
53938909Sborman 	    tel_enter_binary(1);
54038909Sborman 	}
54138909Sborman     } else {
54238909Sborman 	if (my_want_state_is_dont(TELOPT_BINARY)) {
54338909Sborman 	    printf("Already receiving in network ascii mode.\n");
54438909Sborman 	} else {
54538909Sborman 	    printf("Negotiating network ascii mode on input.\n");
54638909Sborman 	    tel_leave_binary(1);
54738909Sborman 	}
54838909Sborman     }
54938909Sborman     return 1;
55038909Sborman }
55138909Sborman 
55246808Sdab     static int
55338909Sborman togxbinary(val)
55446808Sdab     int val;
55538909Sborman {
55638909Sborman     donebinarytoggle = 1;
55738909Sborman 
55838909Sborman     if (val == -1)
55938909Sborman 	val = my_want_state_is_will(TELOPT_BINARY) ? 0 : 1;
56038909Sborman 
56138909Sborman     if (val == 1) {
56238909Sborman 	if (my_want_state_is_will(TELOPT_BINARY)) {
56338909Sborman 	    printf("Already transmitting in binary mode.\n");
56438909Sborman 	} else {
56538909Sborman 	    printf("Negotiating binary mode on output.\n");
56638909Sborman 	    tel_enter_binary(2);
56738909Sborman 	}
56838909Sborman     } else {
56938909Sborman 	if (my_want_state_is_wont(TELOPT_BINARY)) {
57038909Sborman 	    printf("Already transmitting in network ascii mode.\n");
57138909Sborman 	} else {
57238909Sborman 	    printf("Negotiating network ascii mode on output.\n");
57338909Sborman 	    tel_leave_binary(2);
57438909Sborman 	}
57538909Sborman     }
57638909Sborman     return 1;
57738909Sborman }
57838909Sborman 
57938909Sborman 
58046808Sdab extern int togglehelp P((void));
581*47609Sdab #if	defined(AUTHENTICATE)
582*47609Sdab extern int auth_togdebug P((int));
583*47609Sdab #endif
584*47609Sdab #if	defined(ENCRYPT)
585*47609Sdab extern int EncryptAutoEnc P((int));
586*47609Sdab extern int EncryptAutoDec P((int));
587*47609Sdab extern int EncryptDebug P((int));
588*47609Sdab extern int EncryptVerbose P((int));
589*47609Sdab #endif
59032144Sminshall 
59132144Sminshall struct togglelist {
59232144Sminshall     char	*name;		/* name of toggle */
59332144Sminshall     char	*help;		/* help message */
59432144Sminshall     int		(*handler)();	/* routine to do actual setting */
59532144Sminshall     int		*variable;
59632144Sminshall     char	*actionexplanation;
59732144Sminshall };
59832144Sminshall 
59932144Sminshall static struct togglelist Togglelist[] = {
60032144Sminshall     { "autoflush",
60138689Sborman 	"flushing of output when sending interrupt characters",
60232144Sminshall 	    0,
60338689Sborman 		&autoflush,
60438689Sborman 		    "flush output when sending interrupt characters" },
60532144Sminshall     { "autosynch",
60638689Sborman 	"automatic sending of interrupt characters in urgent mode",
60732144Sminshall 	    0,
60838689Sborman 		&autosynch,
60938689Sborman 		    "send interrupt characters in urgent mode" },
610*47609Sdab #if	defined(AUTHENTICATE)
611*47609Sdab     { "autologin",
612*47609Sdab 	"automatic sending of login and/or authentication info",
613*47609Sdab 	    0,
614*47609Sdab 		&autologin,
615*47609Sdab 		    "send login name and/or authentication information" },
616*47609Sdab     { "authdebug",
617*47609Sdab 	"Toggle authentication debugging",
618*47609Sdab 	    auth_togdebug,
619*47609Sdab 		0,
620*47609Sdab 		     "print authentication debugging information" },
621*47609Sdab #endif
622*47609Sdab #if	defined(ENCRYPT)
623*47609Sdab     { "autoencrypt",
624*47609Sdab 	"automatic encryption of data stream",
625*47609Sdab 	    EncryptAutoEnc,
626*47609Sdab 		0,
627*47609Sdab 		    "automatically encrypt output" },
628*47609Sdab     { "autodecrypt",
629*47609Sdab 	"automatic decryption of data stream",
630*47609Sdab 	    EncryptAutoDec,
631*47609Sdab 		0,
632*47609Sdab 		    "automatically decrypt input" },
633*47609Sdab     { "verbose_encrypt",
634*47609Sdab 	"Toggle verbose encryption output",
635*47609Sdab 	    EncryptVerbose,
636*47609Sdab 		0,
637*47609Sdab 		    "print verbose encryption output" },
638*47609Sdab     { "encdebug",
639*47609Sdab 	"Toggle encryption debugging",
640*47609Sdab 	    EncryptDebug,
641*47609Sdab 		0,
642*47609Sdab 		    "print encryption debugging information" },
643*47609Sdab #endif
644*47609Sdab     { "skiprc",
645*47609Sdab 	"don't read ~/.telnetrc file",
646*47609Sdab 	    0,
647*47609Sdab 		&skiprc,
648*47609Sdab 		    "read ~/.telnetrc file" },
64932144Sminshall     { "binary",
65038689Sborman 	"sending and receiving of binary data",
65132144Sminshall 	    togbinary,
65238689Sborman 		0,
65338689Sborman 		    0 },
65438909Sborman     { "inbinary",
65538909Sborman 	"receiving of binary data",
65638909Sborman 	    togrbinary,
65738909Sborman 		0,
65838909Sborman 		    0 },
65938909Sborman     { "outbinary",
66038909Sborman 	"sending of binary data",
66138909Sborman 	    togxbinary,
66238909Sborman 		0,
66338909Sborman 		    0 },
66432144Sminshall     { "crlf",
66538689Sborman 	"sending carriage returns as telnet <CR><LF>",
66632144Sminshall 	    togcrlf,
66738689Sborman 		&crlf,
66838689Sborman 		    0 },
66932144Sminshall     { "crmod",
67038689Sborman 	"mapping of received carriage returns",
67132144Sminshall 	    0,
67238689Sborman 		&crmod,
67338689Sborman 		    "map carriage return on output" },
67432144Sminshall     { "localchars",
67538689Sborman 	"local recognition of certain control characters",
67632144Sminshall 	    lclchars,
67738689Sborman 		&localchars,
67838689Sborman 		    "recognize certain control characters" },
67938689Sborman     { " ", "", 0 },		/* empty line */
68038208Sminshall #if	defined(unix) && defined(TN3270)
68138920Sminshall     { "apitrace",
68238920Sminshall 	"(debugging) toggle tracing of API transactions",
68338920Sminshall 	    0,
68438920Sminshall 		&apitrace,
68538920Sminshall 		    "trace API transactions" },
68638208Sminshall     { "cursesdata",
68738208Sminshall 	"(debugging) toggle printing of hexadecimal curses data",
68838208Sminshall 	    0,
68938689Sborman 		&cursesdata,
69038689Sborman 		    "print hexadecimal representation of curses data" },
69138208Sminshall #endif	/* defined(unix) && defined(TN3270) */
69232144Sminshall     { "debug",
69338689Sborman 	"debugging",
69432144Sminshall 	    togdebug,
69538689Sborman 		&debug,
69638689Sborman 		    "turn on socket level debugging" },
69732144Sminshall     { "netdata",
69838689Sborman 	"printing of hexadecimal network data (debugging)",
69932144Sminshall 	    0,
70038689Sborman 		&netdata,
70138689Sborman 		    "print hexadecimal representation of network traffic" },
70238689Sborman     { "prettydump",
70338689Sborman 	"output of \"netdata\" to user readable format (debugging)",
70438689Sborman 	    0,
70538689Sborman 		&prettydump,
70638689Sborman 		    "print user readable output for \"netdata\"" },
70732144Sminshall     { "options",
70838689Sborman 	"viewing of options processing (debugging)",
70932144Sminshall 	    0,
71038689Sborman 		&showoptions,
71138689Sborman 		    "show option processing" },
71238208Sminshall #if	defined(unix)
71338208Sminshall     { "termdata",
71438208Sminshall 	"(debugging) toggle printing of hexadecimal terminal data",
71538208Sminshall 	    0,
71638689Sborman 		&termdata,
71738689Sborman 		    "print hexadecimal representation of terminal traffic" },
71838208Sminshall #endif	/* defined(unix) */
71932144Sminshall     { "?",
72038689Sborman 	0,
72138689Sborman 	    togglehelp },
72232144Sminshall     { "help",
72338689Sborman 	0,
72438689Sborman 	    togglehelp },
72532144Sminshall     { 0 }
72632144Sminshall };
72732144Sminshall 
72846808Sdab     static int
72932144Sminshall togglehelp()
73032144Sminshall {
73132144Sminshall     struct togglelist *c;
73232144Sminshall 
73332144Sminshall     for (c = Togglelist; c->name; c++) {
73438689Sborman 	if (c->help) {
73538689Sborman 	    if (*c->help)
73638689Sborman 		printf("%-15s toggle %s\n", c->name, c->help);
73738689Sborman 	    else
73838689Sborman 		printf("\n");
73932144Sminshall 	}
74032144Sminshall     }
74138689Sborman     printf("\n");
74238689Sborman     printf("%-15s %s\n", "?", "display help information");
74332144Sminshall     return 0;
74432144Sminshall }
74532144Sminshall 
74646808Sdab     static void
74738689Sborman settogglehelp(set)
74846808Sdab     int set;
74938689Sborman {
75038689Sborman     struct togglelist *c;
75138689Sborman 
75238689Sborman     for (c = Togglelist; c->name; c++) {
75338689Sborman 	if (c->help) {
75438689Sborman 	    if (*c->help)
75538689Sborman 		printf("%-15s %s %s\n", c->name, set ? "enable" : "disable",
75638689Sborman 						c->help);
75738689Sborman 	    else
75838689Sborman 		printf("\n");
75938689Sborman 	}
76038689Sborman     }
76138689Sborman }
76238689Sborman 
76346808Sdab #define	GETTOGGLE(name) (struct togglelist *) \
76446808Sdab 		genget(name, (char **) Togglelist, sizeof(struct togglelist))
76532144Sminshall 
76646808Sdab     static int
76732144Sminshall toggle(argc, argv)
76846808Sdab     int  argc;
76946808Sdab     char *argv[];
77032144Sminshall {
77132144Sminshall     int retval = 1;
77232144Sminshall     char *name;
77332144Sminshall     struct togglelist *c;
77432144Sminshall 
77532144Sminshall     if (argc < 2) {
77632144Sminshall 	fprintf(stderr,
77732144Sminshall 	    "Need an argument to 'toggle' command.  'toggle ?' for help.\n");
77832144Sminshall 	return 0;
77932144Sminshall     }
78032144Sminshall     argc--;
78132144Sminshall     argv++;
78232144Sminshall     while (argc--) {
78332144Sminshall 	name = *argv++;
78446808Sdab 	c = GETTOGGLE(name);
78532144Sminshall 	if (Ambiguous(c)) {
78632144Sminshall 	    fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n",
78732144Sminshall 					name);
78832144Sminshall 	    return 0;
78932144Sminshall 	} else if (c == 0) {
79032144Sminshall 	    fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n",
79132144Sminshall 					name);
79232144Sminshall 	    return 0;
79332144Sminshall 	} else {
79432144Sminshall 	    if (c->variable) {
79532144Sminshall 		*c->variable = !*c->variable;		/* invert it */
79632144Sminshall 		if (c->actionexplanation) {
79732144Sminshall 		    printf("%s %s.\n", *c->variable? "Will" : "Won't",
79832144Sminshall 							c->actionexplanation);
79932144Sminshall 		}
80032144Sminshall 	    }
80132144Sminshall 	    if (c->handler) {
80238689Sborman 		retval &= (*c->handler)(-1);
80332144Sminshall 	    }
80432144Sminshall 	}
80532144Sminshall     }
80632144Sminshall     return retval;
80732144Sminshall }
80832144Sminshall 
80932144Sminshall /*
81032144Sminshall  * The following perform the "set" command.
81132144Sminshall  */
81232144Sminshall 
81338689Sborman #ifdef	USE_TERMIO
81438689Sborman struct termio new_tc = { 0 };
81538689Sborman #endif
81638689Sborman 
81732144Sminshall struct setlist {
81832144Sminshall     char *name;				/* name */
81932144Sminshall     char *help;				/* help information */
82038689Sborman     void (*handler)();
82140245Sborman     cc_t *charp;			/* where it is located at */
82232144Sminshall };
82332144Sminshall 
82432144Sminshall static struct setlist Setlist[] = {
82544361Sborman #ifdef	KLUDGELINEMODE
82638689Sborman     { "echo", 	"character to toggle local echoing on/off", 0, &echoc },
82744361Sborman #endif
82838689Sborman     { "escape",	"character to escape back to telnet command mode", 0, &escape },
82946808Sdab     { "rlogin", "rlogin escape character", 0, &rlogin },
83045233Sborman     { "tracefile", "file to write trace information to", SetNetTrace, (cc_t *)NetTraceFile},
83132144Sminshall     { " ", "" },
83238689Sborman     { " ", "The following need 'localchars' to be toggled true", 0, 0 },
83345233Sborman     { "flushoutput", "character to cause an Abort Output", 0, termFlushCharp },
83438689Sborman     { "interrupt", "character to cause an Interrupt Process", 0, termIntCharp },
83538689Sborman     { "quit",	"character to cause an Abort process", 0, termQuitCharp },
83638689Sborman     { "eof",	"character to cause an EOF ", 0, termEofCharp },
83738689Sborman     { " ", "" },
83838689Sborman     { " ", "The following are for local editing in linemode", 0, 0 },
83938689Sborman     { "erase",	"character to use to erase a character", 0, termEraseCharp },
84038689Sborman     { "kill",	"character to use to erase a line", 0, termKillCharp },
84138689Sborman     { "lnext",	"character to use for literal next", 0, termLiteralNextCharp },
84244361Sborman     { "susp",	"character to cause a Suspend Process", 0, termSuspCharp },
84338689Sborman     { "reprint", "character to use for line reprint", 0, termRprntCharp },
84438689Sborman     { "worderase", "character to use to erase a word", 0, termWerasCharp },
84538689Sborman     { "start",	"character to use for XON", 0, termStartCharp },
84644361Sborman     { "stop",	"character to use for XOFF", 0, termStopCharp },
84744361Sborman     { "forw1",	"alternate end of line character", 0, termForw1Charp },
84844361Sborman     { "forw2",	"alternate end of line character", 0, termForw2Charp },
84945233Sborman     { "ayt",	"alternate AYT character", 0, termAytCharp },
85032144Sminshall     { 0 }
85132144Sminshall };
85232144Sminshall 
85345233Sborman #if	defined(CRAY) && !defined(__STDC__)
85445233Sborman /* Work around compiler bug in pcc 4.1.5 */
85546808Sdab     void
85638689Sborman _setlist_init()
85738689Sborman {
85844361Sborman #ifndef	KLUDGELINEMODE
85946808Sdab #define	N 5
86044361Sborman #else
86146808Sdab #define	N 6
86244361Sborman #endif
86344361Sborman 	Setlist[N+0].charp = &termFlushChar;
86444361Sborman 	Setlist[N+1].charp = &termIntChar;
86544361Sborman 	Setlist[N+2].charp = &termQuitChar;
86644361Sborman 	Setlist[N+3].charp = &termEofChar;
86744361Sborman 	Setlist[N+6].charp = &termEraseChar;
86844361Sborman 	Setlist[N+7].charp = &termKillChar;
86944361Sborman 	Setlist[N+8].charp = &termLiteralNextChar;
87044361Sborman 	Setlist[N+9].charp = &termSuspChar;
87144361Sborman 	Setlist[N+10].charp = &termRprntChar;
87244361Sborman 	Setlist[N+11].charp = &termWerasChar;
87344361Sborman 	Setlist[N+12].charp = &termStartChar;
87444361Sborman 	Setlist[N+13].charp = &termStopChar;
87544361Sborman 	Setlist[N+14].charp = &termForw1Char;
87644361Sborman 	Setlist[N+15].charp = &termForw2Char;
87745233Sborman 	Setlist[N+16].charp = &termAytChar;
87844361Sborman #undef	N
87938689Sborman }
88045233Sborman #endif	/* defined(CRAY) && !defined(__STDC__) */
88138689Sborman 
88246808Sdab     static struct setlist *
88332144Sminshall getset(name)
88446808Sdab     char *name;
88532144Sminshall {
88646808Sdab     return (struct setlist *)
88746808Sdab 		genget(name, (char **) Setlist, sizeof(struct setlist));
88832144Sminshall }
88932144Sminshall 
89046808Sdab     void
89144361Sborman set_escape_char(s)
89246808Sdab     char *s;
89344361Sborman {
89446808Sdab 	if (rlogin != _POSIX_VDISABLE) {
89546808Sdab 		rlogin = (s && *s) ? special(s) : _POSIX_VDISABLE;
89646808Sdab 		printf("Telnet rlogin escape character is '%s'.\n",
89746808Sdab 					control(rlogin));
89846808Sdab 	} else {
89946808Sdab 		escape = (s && *s) ? special(s) : _POSIX_VDISABLE;
90046808Sdab 		printf("Telnet escape character is '%s'.\n", control(escape));
90146808Sdab 	}
90244361Sborman }
90344361Sborman 
90446808Sdab     static int
90532144Sminshall setcmd(argc, argv)
90646808Sdab     int  argc;
90746808Sdab     char *argv[];
90832144Sminshall {
90932144Sminshall     int value;
91032144Sminshall     struct setlist *ct;
91138689Sborman     struct togglelist *c;
91232144Sminshall 
91338689Sborman     if (argc < 2 || argc > 3) {
91438689Sborman 	printf("Format is 'set Name Value'\n'set ?' for help.\n");
91532144Sminshall 	return 0;
91632144Sminshall     }
91746808Sdab     if ((argc == 2) && (isprefix(argv[1], "?") || isprefix(argv[1], "help"))) {
91838689Sborman 	for (ct = Setlist; ct->name; ct++)
91938689Sborman 	    printf("%-15s %s\n", ct->name, ct->help);
92038689Sborman 	printf("\n");
92138689Sborman 	settogglehelp(1);
92238689Sborman 	printf("%-15s %s\n", "?", "display help information");
92338689Sborman 	return 0;
92438689Sborman     }
92532144Sminshall 
92632144Sminshall     ct = getset(argv[1]);
92732144Sminshall     if (ct == 0) {
92846808Sdab 	c = GETTOGGLE(argv[1]);
92938689Sborman 	if (c == 0) {
93038689Sborman 	    fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n",
93132144Sminshall 			argv[1]);
93238689Sborman 	    return 0;
93338689Sborman 	} else if (Ambiguous(c)) {
93438689Sborman 	    fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
93538689Sborman 			argv[1]);
93638689Sborman 	    return 0;
93738689Sborman 	}
93838689Sborman 	if (c->variable) {
93938689Sborman 	    if ((argc == 2) || (strcmp("on", argv[2]) == 0))
94038689Sborman 		*c->variable = 1;
94138689Sborman 	    else if (strcmp("off", argv[2]) == 0)
94238689Sborman 		*c->variable = 0;
94338689Sborman 	    else {
94438689Sborman 		printf("Format is 'set togglename [on|off]'\n'set ?' for help.\n");
94538689Sborman 		return 0;
94638689Sborman 	    }
94738689Sborman 	    if (c->actionexplanation) {
94838689Sborman 		printf("%s %s.\n", *c->variable? "Will" : "Won't",
94938689Sborman 							c->actionexplanation);
95038689Sborman 	    }
95138689Sborman 	}
95238689Sborman 	if (c->handler)
95338689Sborman 	    (*c->handler)(1);
95438689Sborman     } else if (argc != 3) {
95538689Sborman 	printf("Format is 'set Name Value'\n'set ?' for help.\n");
95632144Sminshall 	return 0;
95732144Sminshall     } else if (Ambiguous(ct)) {
95832144Sminshall 	fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
95932144Sminshall 			argv[1]);
96032144Sminshall 	return 0;
96138689Sborman     } else if (ct->handler) {
96238689Sborman 	(*ct->handler)(argv[2]);
96344361Sborman 	printf("%s set to \"%s\".\n", ct->name, (char *)ct->charp);
96432144Sminshall     } else {
96532144Sminshall 	if (strcmp("off", argv[2])) {
96632144Sminshall 	    value = special(argv[2]);
96732144Sminshall 	} else {
96845233Sborman 	    value = _POSIX_VDISABLE;
96932144Sminshall 	}
97040245Sborman 	*(ct->charp) = (cc_t)value;
97132144Sminshall 	printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
97232144Sminshall     }
97338689Sborman     slc_check();
97432144Sminshall     return 1;
97532144Sminshall }
97638689Sborman 
97746808Sdab     static int
97838689Sborman unsetcmd(argc, argv)
97946808Sdab     int  argc;
98046808Sdab     char *argv[];
98138689Sborman {
98238689Sborman     struct setlist *ct;
98338689Sborman     struct togglelist *c;
98438689Sborman     register char *name;
98538689Sborman 
98638689Sborman     if (argc < 2) {
98738689Sborman 	fprintf(stderr,
98838689Sborman 	    "Need an argument to 'unset' command.  'unset ?' for help.\n");
98938689Sborman 	return 0;
99038689Sborman     }
99146808Sdab     if (isprefix(argv[1], "?") || isprefix(argv[1], "help")) {
99238689Sborman 	for (ct = Setlist; ct->name; ct++)
99338689Sborman 	    printf("%-15s %s\n", ct->name, ct->help);
99438689Sborman 	printf("\n");
99538689Sborman 	settogglehelp(0);
99638689Sborman 	printf("%-15s %s\n", "?", "display help information");
99738689Sborman 	return 0;
99838689Sborman     }
99938689Sborman 
100038689Sborman     argc--;
100138689Sborman     argv++;
100238689Sborman     while (argc--) {
100338689Sborman 	name = *argv++;
100438689Sborman 	ct = getset(name);
100538689Sborman 	if (ct == 0) {
100646808Sdab 	    c = GETTOGGLE(name);
100738689Sborman 	    if (c == 0) {
100838689Sborman 		fprintf(stderr, "'%s': unknown argument ('unset ?' for help).\n",
100938689Sborman 			name);
101038689Sborman 		return 0;
101138689Sborman 	    } else if (Ambiguous(c)) {
101238689Sborman 		fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n",
101338689Sborman 			name);
101438689Sborman 		return 0;
101538689Sborman 	    }
101638689Sborman 	    if (c->variable) {
101738689Sborman 		*c->variable = 0;
101838689Sborman 		if (c->actionexplanation) {
101938689Sborman 		    printf("%s %s.\n", *c->variable? "Will" : "Won't",
102038689Sborman 							c->actionexplanation);
102138689Sborman 		}
102238689Sborman 	    }
102338689Sborman 	    if (c->handler)
102438689Sborman 		(*c->handler)(0);
102538689Sborman 	} else if (Ambiguous(ct)) {
102638689Sborman 	    fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n",
102738689Sborman 			name);
102838689Sborman 	    return 0;
102938689Sborman 	} else if (ct->handler) {
103038689Sborman 	    (*ct->handler)(0);
103144361Sborman 	    printf("%s reset to \"%s\".\n", ct->name, (char *)ct->charp);
103238689Sborman 	} else {
103345233Sborman 	    *(ct->charp) = _POSIX_VDISABLE;
103438689Sborman 	    printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
103538689Sborman 	}
103638689Sborman     }
103738689Sborman     return 1;
103838689Sborman }
103932144Sminshall 
104032144Sminshall /*
104132144Sminshall  * The following are the data structures and routines for the
104232144Sminshall  * 'mode' command.
104332144Sminshall  */
104438689Sborman #ifdef	KLUDGELINEMODE
104538689Sborman extern int kludgelinemode;
104644361Sborman 
104746808Sdab     static int
104844361Sborman dokludgemode()
104944361Sborman {
105044361Sborman     kludgelinemode = 1;
105144361Sborman     send_wont(TELOPT_LINEMODE, 1);
105244361Sborman     send_dont(TELOPT_SGA, 1);
105344361Sborman     send_dont(TELOPT_ECHO, 1);
105444361Sborman }
105538689Sborman #endif
105632144Sminshall 
105746808Sdab     static int
105832144Sminshall dolinemode()
105932144Sminshall {
106038689Sborman #ifdef	KLUDGELINEMODE
106138689Sborman     if (kludgelinemode)
106238689Sborman 	send_dont(TELOPT_SGA, 1);
106338689Sborman #endif
106438689Sborman     send_will(TELOPT_LINEMODE, 1);
106538689Sborman     send_dont(TELOPT_ECHO, 1);
106632144Sminshall     return 1;
106732144Sminshall }
106832144Sminshall 
106946808Sdab     static int
107032144Sminshall docharmode()
107132144Sminshall {
107238689Sborman #ifdef	KLUDGELINEMODE
107338689Sborman     if (kludgelinemode)
107438689Sborman 	send_do(TELOPT_SGA, 1);
107538689Sborman     else
107638689Sborman #endif
107738689Sborman     send_wont(TELOPT_LINEMODE, 1);
107838689Sborman     send_do(TELOPT_ECHO, 1);
107938689Sborman     return 1;
108038689Sborman }
108138689Sborman 
108246808Sdab     static int
108338689Sborman dolmmode(bit, on)
108446808Sdab     int bit, on;
108538689Sborman {
108646808Sdab     unsigned char c;
108738689Sborman     extern int linemode;
108838689Sborman 
108938689Sborman     if (my_want_state_is_wont(TELOPT_LINEMODE)) {
109038689Sborman 	printf("?Need to have LINEMODE option enabled first.\n");
109138689Sborman 	printf("'mode ?' for help.\n");
109238689Sborman 	return 0;
109332144Sminshall     }
109438689Sborman 
109538689Sborman     if (on)
109638689Sborman 	c = (linemode | bit);
109738689Sborman     else
109838689Sborman 	c = (linemode & ~bit);
109938689Sborman     lm_mode(&c, 1, 1);
110032144Sminshall     return 1;
110132144Sminshall }
110232144Sminshall 
110346808Sdab     int
110446808Sdab setmode(bit)
110546808Sdab {
110646808Sdab     return dolmmode(bit, 1);
110746808Sdab }
110846808Sdab 
110946808Sdab     int
111046808Sdab clearmode(bit)
111146808Sdab {
111246808Sdab     return dolmmode(bit, 0);
111346808Sdab }
111446808Sdab 
111538689Sborman struct modelist {
111638689Sborman 	char	*name;		/* command name */
111738689Sborman 	char	*help;		/* help string */
111838689Sborman 	int	(*handler)();	/* routine which executes command */
111938689Sborman 	int	needconnect;	/* Do we need to be connected to execute? */
112038689Sborman 	int	arg1;
112138689Sborman };
112238689Sborman 
112338689Sborman extern int modehelp();
112438689Sborman 
112538689Sborman static struct modelist ModeList[] = {
112638689Sborman     { "character", "Disable LINEMODE option",	docharmode, 1 },
112739529Sborman #ifdef	KLUDGELINEMODE
112839529Sborman     { "",	"(or disable obsolete line-by-line mode)", 0 },
112938689Sborman #endif
113038689Sborman     { "line",	"Enable LINEMODE option",	dolinemode, 1 },
113139529Sborman #ifdef	KLUDGELINEMODE
113239529Sborman     { "",	"(or enable obsolete line-by-line mode)", 0 },
113338689Sborman #endif
113438689Sborman     { "", "", 0 },
113538689Sborman     { "",	"These require the LINEMODE option to be enabled", 0 },
113638689Sborman     { "isig",	"Enable signal trapping",	setmode, 1, MODE_TRAPSIG },
113738689Sborman     { "+isig",	0,				setmode, 1, MODE_TRAPSIG },
113838689Sborman     { "-isig",	"Disable signal trapping",	clearmode, 1, MODE_TRAPSIG },
113938689Sborman     { "edit",	"Enable character editing",	setmode, 1, MODE_EDIT },
114038689Sborman     { "+edit",	0,				setmode, 1, MODE_EDIT },
114138689Sborman     { "-edit",	"Disable character editing",	clearmode, 1, MODE_EDIT },
114244361Sborman     { "softtabs", "Enable tab expansion",	setmode, 1, MODE_SOFT_TAB },
114344361Sborman     { "+softtabs", 0,				setmode, 1, MODE_SOFT_TAB },
114444361Sborman     { "-softtabs", "Disable character editing",	clearmode, 1, MODE_SOFT_TAB },
114544361Sborman     { "litecho", "Enable literal character echo", setmode, 1, MODE_LIT_ECHO },
114644361Sborman     { "+litecho", 0,				setmode, 1, MODE_LIT_ECHO },
114744361Sborman     { "-litecho", "Disable literal character echo", clearmode, 1, MODE_LIT_ECHO },
114838689Sborman     { "help",	0,				modehelp, 0 },
114944361Sborman #ifdef	KLUDGELINEMODE
115044361Sborman     { "kludgeline", 0,				dokludgemode, 1 },
115144361Sborman #endif
115244361Sborman     { "", "", 0 },
115338689Sborman     { "?",	"Print help information",	modehelp, 0 },
115432144Sminshall     { 0 },
115532144Sminshall };
115632144Sminshall 
115732144Sminshall 
115846808Sdab     int
115938689Sborman modehelp()
116038689Sborman {
116138689Sborman     struct modelist *mt;
116238689Sborman 
116338689Sborman     printf("format is:  'mode Mode', where 'Mode' is one of:\n\n");
116438689Sborman     for (mt = ModeList; mt->name; mt++) {
116538689Sborman 	if (mt->help) {
116638689Sborman 	    if (*mt->help)
116738689Sborman 		printf("%-15s %s\n", mt->name, mt->help);
116838689Sborman 	    else
116938689Sborman 		printf("\n");
117038689Sborman 	}
117138689Sborman     }
117238689Sborman     return 0;
117338689Sborman }
117438689Sborman 
117546808Sdab #define	GETMODECMD(name) (struct modelist *) \
117646808Sdab 		genget(name, (char **) ModeList, sizeof(struct modelist))
117746808Sdab 
117846808Sdab     static int
117932144Sminshall modecmd(argc, argv)
118046808Sdab     int  argc;
118146808Sdab     char *argv[];
118232144Sminshall {
118338689Sborman     struct modelist *mt;
118432144Sminshall 
118538689Sborman     if (argc != 2) {
118638689Sborman 	printf("'mode' command requires an argument\n");
118738689Sborman 	printf("'mode ?' for help.\n");
118846808Sdab     } else if ((mt = GETMODECMD(argv[1])) == 0) {
118932144Sminshall 	fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]);
119032144Sminshall     } else if (Ambiguous(mt)) {
119132144Sminshall 	fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]);
119238689Sborman     } else if (mt->needconnect && !connected) {
119338689Sborman 	printf("?Need to be connected first.\n");
119438689Sborman 	printf("'mode ?' for help.\n");
119538689Sborman     } else if (mt->handler) {
119638689Sborman 	return (*mt->handler)(mt->arg1);
119732144Sminshall     }
119838689Sborman     return 0;
119932144Sminshall }
120032144Sminshall 
120132144Sminshall /*
120232144Sminshall  * The following data structures and routines implement the
120332144Sminshall  * "display" command.
120432144Sminshall  */
120532144Sminshall 
120646808Sdab     static int
120732144Sminshall display(argc, argv)
120846808Sdab     int  argc;
120946808Sdab     char *argv[];
121032144Sminshall {
121146808Sdab     struct togglelist *tl;
121246808Sdab     struct setlist *sl;
121346808Sdab 
121432144Sminshall #define	dotog(tl)	if (tl->variable && tl->actionexplanation) { \
121532144Sminshall 			    if (*tl->variable) { \
121632144Sminshall 				printf("will"); \
121732144Sminshall 			    } else { \
121832144Sminshall 				printf("won't"); \
121932144Sminshall 			    } \
122032144Sminshall 			    printf(" %s.\n", tl->actionexplanation); \
122132144Sminshall 			}
122232144Sminshall 
122332144Sminshall #define	doset(sl)   if (sl->name && *sl->name != ' ') { \
122438689Sborman 			if (sl->handler == 0) \
122538689Sborman 			    printf("%-15s [%s]\n", sl->name, control(*sl->charp)); \
122638689Sborman 			else \
122744361Sborman 			    printf("%-15s \"%s\"\n", sl->name, (char *)sl->charp); \
122832144Sminshall 		    }
122932144Sminshall 
123032144Sminshall     if (argc == 1) {
123132144Sminshall 	for (tl = Togglelist; tl->name; tl++) {
123232144Sminshall 	    dotog(tl);
123332144Sminshall 	}
123432144Sminshall 	printf("\n");
123532144Sminshall 	for (sl = Setlist; sl->name; sl++) {
123632144Sminshall 	    doset(sl);
123732144Sminshall 	}
123832144Sminshall     } else {
123932144Sminshall 	int i;
124032144Sminshall 
124132144Sminshall 	for (i = 1; i < argc; i++) {
124232144Sminshall 	    sl = getset(argv[i]);
124346808Sdab 	    tl = GETTOGGLE(argv[i]);
124432144Sminshall 	    if (Ambiguous(sl) || Ambiguous(tl)) {
124532144Sminshall 		printf("?Ambiguous argument '%s'.\n", argv[i]);
124632144Sminshall 		return 0;
124732144Sminshall 	    } else if (!sl && !tl) {
124832144Sminshall 		printf("?Unknown argument '%s'.\n", argv[i]);
124932144Sminshall 		return 0;
125032144Sminshall 	    } else {
125132144Sminshall 		if (tl) {
125232144Sminshall 		    dotog(tl);
125332144Sminshall 		}
125432144Sminshall 		if (sl) {
125532144Sminshall 		    doset(sl);
125632144Sminshall 		}
125732144Sminshall 	    }
125832144Sminshall 	}
125932144Sminshall     }
126038689Sborman /*@*/optionstatus();
126146808Sdab #if	defined(ENCRYPT)
126246808Sdab     EncryptStatus();
126346808Sdab #endif
126432144Sminshall     return 1;
126532144Sminshall #undef	doset
126632144Sminshall #undef	dotog
126732144Sminshall }
126832144Sminshall 
126932144Sminshall /*
127032144Sminshall  * The following are the data structures, and many of the routines,
127132144Sminshall  * relating to command processing.
127232144Sminshall  */
127332144Sminshall 
127432144Sminshall /*
127532144Sminshall  * Set the escape character.
127632144Sminshall  */
127746808Sdab 	static int
127832144Sminshall setescape(argc, argv)
127932144Sminshall 	int argc;
128032144Sminshall 	char *argv[];
128132144Sminshall {
128232144Sminshall 	register char *arg;
128332144Sminshall 	char buf[50];
128432144Sminshall 
128532144Sminshall 	printf(
128632144Sminshall 	    "Deprecated usage - please use 'set escape%s%s' in the future.\n",
128732144Sminshall 				(argc > 2)? " ":"", (argc > 2)? argv[1]: "");
128832144Sminshall 	if (argc > 2)
128932144Sminshall 		arg = argv[1];
129032144Sminshall 	else {
129132144Sminshall 		printf("new escape character: ");
129246808Sdab 		(void) fgets(buf, sizeof(buf), stdin);
129332144Sminshall 		arg = buf;
129432144Sminshall 	}
129532144Sminshall 	if (arg[0] != '\0')
129632144Sminshall 		escape = arg[0];
129732144Sminshall 	if (!In3270) {
129832144Sminshall 		printf("Escape character is '%s'.\n", control(escape));
129932144Sminshall 	}
130034849Sminshall 	(void) fflush(stdout);
130132144Sminshall 	return 1;
130232144Sminshall }
130332144Sminshall 
130446808Sdab     /*VARARGS*/
130546808Sdab     static int
130632144Sminshall togcrmod()
130732144Sminshall {
130832144Sminshall     crmod = !crmod;
130932144Sminshall     printf("Deprecated usage - please use 'toggle crmod' in the future.\n");
131032144Sminshall     printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't");
131134849Sminshall     (void) fflush(stdout);
131232144Sminshall     return 1;
131332144Sminshall }
131432144Sminshall 
131546808Sdab     /*VARARGS*/
131646808Sdab     int
131732144Sminshall suspend()
131832144Sminshall {
131938689Sborman #ifdef	SIGTSTP
132037219Sminshall     setcommandmode();
132137219Sminshall     {
132244361Sborman 	long oldrows, oldcols, newrows, newcols, err;
132337219Sminshall 
132444361Sborman 	err = TerminalWindowSize(&oldrows, &oldcols);
132534849Sminshall 	(void) kill(0, SIGTSTP);
132644361Sborman 	err += TerminalWindowSize(&newrows, &newcols);
132744361Sborman 	if (connected && !err &&
132844361Sborman 	    ((oldrows != newrows) || (oldcols != newcols))) {
132937219Sminshall 		sendnaws();
133037219Sminshall 	}
133137219Sminshall     }
133237219Sminshall     /* reget parameters in case they were changed */
133337219Sminshall     TerminalSaveState();
133438689Sborman     setconnmode(0);
133538689Sborman #else
133638689Sborman     printf("Suspend is not supported.  Try the '!' command instead\n");
133738689Sborman #endif
133837219Sminshall     return 1;
133932144Sminshall }
134032144Sminshall 
134138689Sborman #if	!defined(TN3270)
134246808Sdab     /*ARGSUSED*/
134346808Sdab     int
134438689Sborman shell(argc, argv)
134546808Sdab     int argc;
134646808Sdab     char *argv[];
134738689Sborman {
134838689Sborman     setcommandmode();
134938689Sborman     switch(vfork()) {
135038689Sborman     case -1:
135138689Sborman 	perror("Fork failed\n");
135238689Sborman 	break;
135338689Sborman 
135438689Sborman     case 0:
135538689Sborman 	{
135638689Sborman 	    /*
135738689Sborman 	     * Fire up the shell in the child.
135838689Sborman 	     */
135946808Sdab 	    register char *shellp, *shellname;
136046808Sdab 	    extern char *rindex();
136138689Sborman 
136246808Sdab 	    shellp = getenv("SHELL");
136346808Sdab 	    if (shellp == NULL)
136446808Sdab 		shellp = "/bin/sh";
136546808Sdab 	    if ((shellname = rindex(shellp, '/')) == 0)
136646808Sdab 		shellname = shellp;
136738689Sborman 	    else
136838689Sborman 		shellname++;
136938689Sborman 	    if (argc > 1)
137046808Sdab 		execl(shellp, shellname, "-c", &saveline[1], 0);
137138689Sborman 	    else
137246808Sdab 		execl(shellp, shellname, 0);
137338689Sborman 	    perror("Execl");
137438689Sborman 	    _exit(1);
137538689Sborman 	}
137638689Sborman     default:
137744361Sborman 	    (void)wait((int *)0);	/* Wait for the shell to complete */
137838689Sborman     }
137946808Sdab     return 1;
138038689Sborman }
138138689Sborman #endif	/* !defined(TN3270) */
138238689Sborman 
138346808Sdab     /*VARARGS*/
138446808Sdab     static
138532144Sminshall bye(argc, argv)
138646808Sdab     int  argc;		/* Number of arguments */
138746808Sdab     char *argv[];	/* arguments */
138832144Sminshall {
138946808Sdab     extern int resettermname;
139046808Sdab 
139132144Sminshall     if (connected) {
139234849Sminshall 	(void) shutdown(net, 2);
139332144Sminshall 	printf("Connection closed.\n");
139434849Sminshall 	(void) NetClose(net);
139532144Sminshall 	connected = 0;
139646808Sdab 	resettermname = 1;
139746808Sdab #if	defined(AUTHENTICATE) || defined(ENCRYPT)
139846808Sdab 	auth_encrypt_connect(connected);
139946808Sdab #endif
140032144Sminshall 	/* reset options */
140132144Sminshall 	tninit();
140232144Sminshall #if	defined(TN3270)
140332144Sminshall 	SetIn3270();		/* Get out of 3270 mode */
140432144Sminshall #endif	/* defined(TN3270) */
140532144Sminshall     }
140632144Sminshall     if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) {
140732144Sminshall 	longjmp(toplevel, 1);
140832144Sminshall 	/* NOTREACHED */
140932144Sminshall     }
141032144Sminshall     return 1;			/* Keep lint, etc., happy */
141132144Sminshall }
141232144Sminshall 
141332144Sminshall /*VARARGS*/
141432144Sminshall quit()
141532144Sminshall {
141632144Sminshall 	(void) call(bye, "bye", "fromquit", 0);
141732144Sminshall 	Exit(0);
141844361Sborman 	/*NOTREACHED*/
141932144Sminshall }
142046808Sdab 
142146808Sdab /*VARARGS*/
142246808Sdab 	int
142346808Sdab logout()
142446808Sdab {
142546808Sdab 	send_do(TELOPT_LOGOUT, 1);
142646808Sdab 	(void) netflush();
142746808Sdab 	return 1;
142846808Sdab }
142946808Sdab 
143038689Sborman 
143138689Sborman /*
143238689Sborman  * The SLC command.
143338689Sborman  */
143432144Sminshall 
143538689Sborman struct slclist {
143638689Sborman 	char	*name;
143738689Sborman 	char	*help;
143846808Sdab 	void	(*handler)();
143938689Sborman 	int	arg;
144038689Sborman };
144138689Sborman 
144246808Sdab extern void slc_help();
144338689Sborman 
144438689Sborman struct slclist SlcList[] = {
144538689Sborman     { "export",	"Use local special character definitions",
144638689Sborman 						slc_mode_export,	0 },
144738689Sborman     { "import",	"Use remote special character definitions",
144838689Sborman 						slc_mode_import,	1 },
144938689Sborman     { "check",	"Verify remote special character definitions",
145038689Sborman 						slc_mode_import,	0 },
145138689Sborman     { "help",	0,				slc_help,		0 },
145238689Sborman     { "?",	"Print help information",	slc_help,		0 },
145338689Sborman     { 0 },
145438689Sborman };
145538689Sborman 
145646808Sdab     static void
145738689Sborman slc_help()
145838689Sborman {
145938689Sborman     struct slclist *c;
146038689Sborman 
146138689Sborman     for (c = SlcList; c->name; c++) {
146238689Sborman 	if (c->help) {
146338689Sborman 	    if (*c->help)
146438689Sborman 		printf("%-15s %s\n", c->name, c->help);
146538689Sborman 	    else
146638689Sborman 		printf("\n");
146738689Sborman 	}
146838689Sborman     }
146938689Sborman }
147038689Sborman 
147146808Sdab     static struct slclist *
147238689Sborman getslc(name)
147346808Sdab     char *name;
147438689Sborman {
147546808Sdab     return (struct slclist *)
147646808Sdab 		genget(name, (char **) SlcList, sizeof(struct slclist));
147738689Sborman }
147838689Sborman 
147946808Sdab     static
148038689Sborman slccmd(argc, argv)
148146808Sdab     int  argc;
148246808Sdab     char *argv[];
148338689Sborman {
148438689Sborman     struct slclist *c;
148538689Sborman 
148638689Sborman     if (argc != 2) {
148738689Sborman 	fprintf(stderr,
148838689Sborman 	    "Need an argument to 'slc' command.  'slc ?' for help.\n");
148938689Sborman 	return 0;
149038689Sborman     }
149138689Sborman     c = getslc(argv[1]);
149238689Sborman     if (c == 0) {
149338689Sborman         fprintf(stderr, "'%s': unknown argument ('slc ?' for help).\n",
149438689Sborman     				argv[1]);
149538689Sborman         return 0;
149638689Sborman     }
149738689Sborman     if (Ambiguous(c)) {
149838689Sborman         fprintf(stderr, "'%s': ambiguous argument ('slc ?' for help).\n",
149938689Sborman     				argv[1]);
150038689Sborman         return 0;
150138689Sborman     }
150238689Sborman     (*c->handler)(c->arg);
150338689Sborman     slcstate();
150438689Sborman     return 1;
150538689Sborman }
150644361Sborman 
150744361Sborman /*
150844361Sborman  * The ENVIRON command.
150944361Sborman  */
151038689Sborman 
151144361Sborman struct envlist {
151244361Sborman 	char	*name;
151344361Sborman 	char	*help;
151446808Sdab 	void	(*handler)();
151544361Sborman 	int	narg;
151644361Sborman };
151744361Sborman 
151846808Sdab extern struct env_lst *
151946808Sdab 	env_define P((unsigned char *, unsigned char *));
152046808Sdab extern void
152146808Sdab 	env_undefine P((unsigned char *)),
152246808Sdab 	env_export P((unsigned char *)),
152346808Sdab 	env_unexport P((unsigned char *)),
152446808Sdab 	env_send P((unsigned char *)),
152546808Sdab 	env_list P((void)),
152646808Sdab 	env_help P((void));
152744361Sborman 
152844361Sborman struct envlist EnvList[] = {
152944361Sborman     { "define",	"Define an environment variable",
153046808Sdab 						(void (*)())env_define,	2 },
153144361Sborman     { "undefine", "Undefine an environment variable",
153244361Sborman 						env_undefine,	1 },
153344361Sborman     { "export",	"Mark an environment variable for automatic export",
153444361Sborman 						env_export,	1 },
153546808Sdab     { "unexport", "Don't mark an environment variable for automatic export",
153644361Sborman 						env_unexport,	1 },
153745233Sborman     { "send",	"Send an environment variable", env_send,	1 },
153844361Sborman     { "list",	"List the current environment variables",
153944361Sborman 						env_list,	0 },
154044361Sborman     { "help",	0,				env_help,		0 },
154144361Sborman     { "?",	"Print help information",	env_help,		0 },
154244361Sborman     { 0 },
154344361Sborman };
154444361Sborman 
154546808Sdab     static void
154644361Sborman env_help()
154744361Sborman {
154844361Sborman     struct envlist *c;
154944361Sborman 
155044361Sborman     for (c = EnvList; c->name; c++) {
155144361Sborman 	if (c->help) {
155244361Sborman 	    if (*c->help)
155344361Sborman 		printf("%-15s %s\n", c->name, c->help);
155444361Sborman 	    else
155544361Sborman 		printf("\n");
155644361Sborman 	}
155744361Sborman     }
155844361Sborman }
155944361Sborman 
156046808Sdab     static struct envlist *
156144361Sborman getenvcmd(name)
156246808Sdab     char *name;
156344361Sborman {
156446808Sdab     return (struct envlist *)
156546808Sdab 		genget(name, (char **) EnvList, sizeof(struct envlist));
156644361Sborman }
156744361Sborman 
156844361Sborman env_cmd(argc, argv)
156946808Sdab     int  argc;
157046808Sdab     char *argv[];
157144361Sborman {
157244361Sborman     struct envlist *c;
157344361Sborman 
157444361Sborman     if (argc < 2) {
157544361Sborman 	fprintf(stderr,
157644361Sborman 	    "Need an argument to 'environ' command.  'environ ?' for help.\n");
157744361Sborman 	return 0;
157844361Sborman     }
157944361Sborman     c = getenvcmd(argv[1]);
158044361Sborman     if (c == 0) {
158144361Sborman         fprintf(stderr, "'%s': unknown argument ('environ ?' for help).\n",
158244361Sborman     				argv[1]);
158344361Sborman         return 0;
158444361Sborman     }
158544361Sborman     if (Ambiguous(c)) {
158644361Sborman         fprintf(stderr, "'%s': ambiguous argument ('environ ?' for help).\n",
158744361Sborman     				argv[1]);
158844361Sborman         return 0;
158944361Sborman     }
159044361Sborman     if (c->narg + 2 != argc) {
159144361Sborman 	fprintf(stderr,
159244361Sborman 	    "Need %s%d argument%s to 'environ %s' command.  'environ ?' for help.\n",
159344361Sborman 		c->narg < argc + 2 ? "only " : "",
159444361Sborman 		c->narg, c->narg == 1 ? "" : "s", c->name);
159544361Sborman 	return 0;
159644361Sborman     }
159746808Sdab     (*c->handler)(argv[2], argv[3]);
159844361Sborman     return 1;
159944361Sborman }
160044361Sborman 
160144361Sborman struct env_lst {
160244361Sborman 	struct env_lst *next;	/* pointer to next structure */
160344361Sborman 	struct env_lst *prev;	/* pointer to next structure */
160446808Sdab 	unsigned char *var;	/* pointer to variable name */
160546808Sdab 	unsigned char *value;	/* pointer to varialbe value */
160644361Sborman 	int export;		/* 1 -> export with default list of variables */
160744361Sborman };
160844361Sborman 
160944361Sborman struct env_lst envlisthead;
161044361Sborman 
161146808Sdab 	struct env_lst *
161244361Sborman env_find(var)
161346808Sdab 	unsigned char *var;
161444361Sborman {
161544361Sborman 	register struct env_lst *ep;
161644361Sborman 
161744361Sborman 	for (ep = envlisthead.next; ep; ep = ep->next) {
161846808Sdab 		if (strcmp((char *)ep->var, (char *)var) == 0)
161944361Sborman 			return(ep);
162044361Sborman 	}
162144361Sborman 	return(NULL);
162244361Sborman }
162344361Sborman 
162446808Sdab 	void
162544361Sborman env_init()
162644361Sborman {
162746808Sdab 	extern char **environ;
162844361Sborman 	register char **epp, *cp;
162944361Sborman 	register struct env_lst *ep;
163046808Sdab 	extern char *index();
163144361Sborman 
163244361Sborman 	for (epp = environ; *epp; epp++) {
163344361Sborman 		if (cp = index(*epp, '=')) {
163444361Sborman 			*cp = '\0';
163546808Sdab 			ep = env_define((unsigned char *)*epp,
163646808Sdab 					(unsigned char *)cp+1);
163744361Sborman 			ep->export = 0;
163844361Sborman 			*cp = '=';
163944361Sborman 		}
164044361Sborman 	}
164144361Sborman 	/*
164244361Sborman 	 * Special case for DISPLAY variable.  If it is ":0.0" or
164344361Sborman 	 * "unix:0.0", we have to get rid of "unix" and insert our
164444361Sborman 	 * hostname.
164544361Sborman 	 */
164646808Sdab 	if ((ep = env_find("DISPLAY"))
164746808Sdab 	    && ((*ep->value == ':')
164846808Sdab 	        || (strncmp((char *)ep->value, "unix:", 5) == 0))) {
164944361Sborman 		char hbuf[256+1];
165046808Sdab 		char *cp2 = index((char *)ep->value, ':');
165144361Sborman 
165244361Sborman 		gethostname(hbuf, 256);
165344361Sborman 		hbuf[256] = '\0';
165444361Sborman 		cp = (char *)malloc(strlen(hbuf) + strlen(cp2) + 1);
165546808Sdab 		sprintf((char *)cp, "%s%s", hbuf, cp2);
165644361Sborman 		free(ep->value);
165746808Sdab 		ep->value = (unsigned char *)cp;
165844361Sborman 	}
165944361Sborman 	/*
166044361Sborman 	 * If USER is not defined, but LOGNAME is, then add
166145233Sborman 	 * USER with the value from LOGNAME.  By default, we
166245233Sborman 	 * don't export the USER variable.
166344361Sborman 	 */
166445233Sborman 	if ((env_find("USER") == NULL) && (ep = env_find("LOGNAME"))) {
166546808Sdab 		env_define((unsigned char *)"USER", ep->value);
166646808Sdab 		env_unexport((unsigned char *)"USER");
166745233Sborman 	}
166846808Sdab 	env_export((unsigned char *)"DISPLAY");
166946808Sdab 	env_export((unsigned char *)"PRINTER");
167044361Sborman }
167144361Sborman 
167246808Sdab 	struct env_lst *
167344361Sborman env_define(var, value)
167446808Sdab 	unsigned char *var, *value;
167544361Sborman {
167644361Sborman 	register struct env_lst *ep;
167744361Sborman 
167844361Sborman 	if (ep = env_find(var)) {
167944361Sborman 		if (ep->var)
168044361Sborman 			free(ep->var);
168144361Sborman 		if (ep->value)
168244361Sborman 			free(ep->value);
168344361Sborman 	} else {
168444361Sborman 		ep = (struct env_lst *)malloc(sizeof(struct env_lst));
168544361Sborman 		ep->next = envlisthead.next;
168644361Sborman 		envlisthead.next = ep;
168744361Sborman 		ep->prev = &envlisthead;
168844361Sborman 		if (ep->next)
168944361Sborman 			ep->next->prev = ep;
169044361Sborman 	}
169145009Skarels 	ep->export = 1;
169246808Sdab 	ep->var = (unsigned char *)strdup((char *)var);
169346808Sdab 	ep->value = (unsigned char *)strdup((char *)value);
169444361Sborman 	return(ep);
169544361Sborman }
169644361Sborman 
169746808Sdab 	void
169844361Sborman env_undefine(var)
169946808Sdab 	unsigned char *var;
170044361Sborman {
170144361Sborman 	register struct env_lst *ep;
170244361Sborman 
170344361Sborman 	if (ep = env_find(var)) {
170444361Sborman 		ep->prev->next = ep->next;
170545233Sborman 		if (ep->next)
170645233Sborman 			ep->next->prev = ep->prev;
170744361Sborman 		if (ep->var)
170844361Sborman 			free(ep->var);
170944361Sborman 		if (ep->value)
171044361Sborman 			free(ep->value);
171144361Sborman 		free(ep);
171244361Sborman 	}
171344361Sborman }
171444361Sborman 
171546808Sdab 	void
171644361Sborman env_export(var)
171746808Sdab 	unsigned char *var;
171844361Sborman {
171944361Sborman 	register struct env_lst *ep;
172044361Sborman 
172144361Sborman 	if (ep = env_find(var))
172244361Sborman 		ep->export = 1;
172344361Sborman }
172444361Sborman 
172546808Sdab 	void
172644361Sborman env_unexport(var)
172746808Sdab 	unsigned char *var;
172844361Sborman {
172944361Sborman 	register struct env_lst *ep;
173044361Sborman 
173144361Sborman 	if (ep = env_find(var))
173244361Sborman 		ep->export = 0;
173344361Sborman }
173444361Sborman 
173546808Sdab 	void
173645233Sborman env_send(var)
173746808Sdab 	unsigned char *var;
173845233Sborman {
173945233Sborman 	register struct env_lst *ep;
174045233Sborman 
174145233Sborman         if (my_state_is_wont(TELOPT_ENVIRON)) {
174245233Sborman 		fprintf(stderr,
174345233Sborman 		    "Cannot send '%s': Telnet ENVIRON option not enabled\n",
174445233Sborman 									var);
174545233Sborman 		return;
174645233Sborman 	}
174745233Sborman 	ep = env_find(var);
174845233Sborman 	if (ep == 0) {
174945233Sborman 		fprintf(stderr, "Cannot send '%s': variable not defined\n",
175045233Sborman 									var);
175145233Sborman 		return;
175245233Sborman 	}
175345233Sborman 	env_opt_start_info();
175445233Sborman 	env_opt_add(ep->var);
175545233Sborman 	env_opt_end(0);
175645233Sborman }
175745233Sborman 
175846808Sdab 	void
175944361Sborman env_list()
176044361Sborman {
176144361Sborman 	register struct env_lst *ep;
176244361Sborman 
176344361Sborman 	for (ep = envlisthead.next; ep; ep = ep->next) {
176444361Sborman 		printf("%c %-20s %s\n", ep->export ? '*' : ' ',
176544361Sborman 					ep->var, ep->value);
176644361Sborman 	}
176744361Sborman }
176844361Sborman 
176946808Sdab 	unsigned char *
177044361Sborman env_default(init)
177146808Sdab 	int init;
177244361Sborman {
177344361Sborman 	static struct env_lst *nep = NULL;
177444361Sborman 
177544361Sborman 	if (init) {
177644361Sborman 		nep = &envlisthead;
177744361Sborman 		return;
177844361Sborman 	}
177944361Sborman 	if (nep) {
178044361Sborman 		while (nep = nep->next) {
178144361Sborman 			if (nep->export)
178244361Sborman 				return(nep->var);
178344361Sborman 		}
178444361Sborman 	}
178544361Sborman 	return(NULL);
178644361Sborman }
178744361Sborman 
178846808Sdab 	unsigned char *
178944361Sborman env_getvalue(var)
179046808Sdab 	unsigned char *var;
179144361Sborman {
179244361Sborman 	register struct env_lst *ep;
179344361Sborman 
179444361Sborman 	if (ep = env_find(var))
179544361Sborman 		return(ep->value);
179644361Sborman 	return(NULL);
179744361Sborman }
179844361Sborman 
179946808Sdab #if	defined(AUTHENTICATE)
180046808Sdab /*
180146808Sdab  * The AUTHENTICATE command.
180246808Sdab  */
180346808Sdab 
180446808Sdab struct authlist {
180546808Sdab 	char	*name;
180646808Sdab 	char	*help;
180746808Sdab 	int	(*handler)();
180846808Sdab 	int	narg;
180946808Sdab };
181046808Sdab 
181146808Sdab extern int
181246808Sdab 	auth_enable P((int)),
181346808Sdab 	auth_disable P((int)),
181446808Sdab 	auth_status P((void)),
181546808Sdab 	auth_help P((void));
181646808Sdab 
181746808Sdab struct authlist AuthList[] = {
181846808Sdab     { "status",	"Display current status of authentication information",
181946808Sdab 						auth_status,	0 },
182046808Sdab     { "disable", "Disable an authentication type ('auth disable ?' for more)",
182146808Sdab 						auth_disable,	1 },
182246808Sdab     { "enable", "Enable an authentication type ('auth enable ?' for more)",
182346808Sdab 						auth_enable,	1 },
182446808Sdab     { "help",	0,				auth_help,		0 },
182546808Sdab     { "?",	"Print help information",	auth_help,		0 },
182646808Sdab     { 0 },
182746808Sdab };
182846808Sdab 
182946808Sdab     static int
183046808Sdab auth_help()
183144361Sborman {
183246808Sdab     struct authlist *c;
183346808Sdab 
183446808Sdab     for (c = AuthList; c->name; c++) {
183546808Sdab 	if (c->help) {
183646808Sdab 	    if (*c->help)
183746808Sdab 		printf("%-15s %s\n", c->name, c->help);
183846808Sdab 	    else
183946808Sdab 		printf("\n");
184046808Sdab 	}
184146808Sdab     }
184246808Sdab     return 0;
184344361Sborman }
184446808Sdab 
184546808Sdab auth_cmd(argc, argv)
184646808Sdab     int  argc;
184746808Sdab     char *argv[];
184846808Sdab {
184946808Sdab     struct authlist *c;
185046808Sdab 
185146808Sdab     c = (struct authlist *)
185246808Sdab 		genget(argv[1], (char **) AuthList, sizeof(struct authlist));
185346808Sdab     if (c == 0) {
185446808Sdab         fprintf(stderr, "'%s': unknown argument ('auth ?' for help).\n",
185546808Sdab     				argv[1]);
185646808Sdab         return 0;
185746808Sdab     }
185846808Sdab     if (Ambiguous(c)) {
185946808Sdab         fprintf(stderr, "'%s': ambiguous argument ('auth ?' for help).\n",
186046808Sdab     				argv[1]);
186146808Sdab         return 0;
186246808Sdab     }
186346808Sdab     if (c->narg + 2 != argc) {
186446808Sdab 	fprintf(stderr,
186546808Sdab 	    "Need %s%d argument%s to 'auth %s' command.  'auth ?' for help.\n",
186646808Sdab 		c->narg < argc + 2 ? "only " : "",
186746808Sdab 		c->narg, c->narg == 1 ? "" : "s", c->name);
186846808Sdab 	return 0;
186946808Sdab     }
187046808Sdab     return((*c->handler)(argv[2], argv[3]));
187146808Sdab }
187245233Sborman #endif
187344361Sborman 
187446808Sdab #if	defined(ENCRYPT)
187532144Sminshall /*
187646808Sdab  * The ENCRYPT command.
187736274Sminshall  */
187836274Sminshall 
187946808Sdab struct encryptlist {
188046808Sdab 	char	*name;
188146808Sdab 	char	*help;
188246808Sdab 	int	(*handler)();
188346808Sdab 	int	needconnect;
188446808Sdab 	int	minarg;
188546808Sdab 	int	maxarg;
188646808Sdab };
188746808Sdab 
188846808Sdab extern int
188946808Sdab 	EncryptEnable P((char *, char *)),
1890*47609Sdab 	EncryptDisable P((char *, char *)),
189146808Sdab 	EncryptType P((char *, char *)),
189246808Sdab 	EncryptStart P((char *)),
189346808Sdab 	EncryptStartInput P((void)),
189446808Sdab 	EncryptStartOutput P((void)),
189546808Sdab 	EncryptStop P((char *)),
189646808Sdab 	EncryptStopInput P((void)),
189746808Sdab 	EncryptStopOutput P((void)),
189846808Sdab 	EncryptStatus P((void)),
189946808Sdab 	EncryptHelp P((void));
190046808Sdab 
190146808Sdab struct encryptlist EncryptList[] = {
190246808Sdab     { "enable", "Enable encryption. ('encrypt enable ?' for more)",
190346808Sdab 						EncryptEnable, 1, 1, 2 },
1904*47609Sdab     { "disable", "Disable encryption. ('encrypt enable ?' for more)",
1905*47609Sdab 						EncryptDisable, 0, 1, 2 },
190646808Sdab     { "type", "Set encryptiong type. ('encrypt type ?' for more)",
190746808Sdab 						EncryptType, 0, 1, 1 },
190846808Sdab     { "start", "Start encryption. ('encrypt start ?' for more)",
190946808Sdab 						EncryptStart, 1, 0, 1 },
191046808Sdab     { "stop", "Stop encryption. ('encrypt stop ?' for more)",
191146808Sdab 						EncryptStop, 1, 0, 1 },
191246808Sdab     { "input", "Start encrypting the input stream",
191346808Sdab 						EncryptStartInput, 1, 0, 0 },
191446808Sdab     { "-input", "Stop encrypting the input stream",
191546808Sdab 						EncryptStopInput, 1, 0, 0 },
191646808Sdab     { "output", "Start encrypting the output stream",
191746808Sdab 						EncryptStartOutput, 1, 0, 0 },
191846808Sdab     { "-output", "Stop encrypting the output stream",
191946808Sdab 						EncryptStopOutput, 1, 0, 0 },
192046808Sdab 
192146808Sdab     { "status",	"Display current status of authentication information",
192246808Sdab 						EncryptStatus,	0, 0, 0 },
192346808Sdab     { "help",	0,				EncryptHelp,	0, 0, 0 },
192446808Sdab     { "?",	"Print help information",	EncryptHelp,	0, 0, 0 },
192546808Sdab     { 0 },
192646808Sdab };
192746808Sdab 
192846808Sdab     static int
192946808Sdab EncryptHelp()
193036274Sminshall {
193146808Sdab     struct encryptlist *c;
193246808Sdab 
193346808Sdab     for (c = EncryptList; c->name; c++) {
193446808Sdab 	if (c->help) {
193546808Sdab 	    if (*c->help)
193646808Sdab 		printf("%-15s %s\n", c->name, c->help);
193746808Sdab 	    else
193846808Sdab 		printf("\n");
193936274Sminshall 	}
194046808Sdab     }
194146808Sdab     return 0;
194246808Sdab }
194336274Sminshall 
194446808Sdab encrypt_cmd(argc, argv)
194546808Sdab     int  argc;
194646808Sdab     char *argv[];
194746808Sdab {
194846808Sdab     struct encryptlist *c;
194936274Sminshall 
195046808Sdab     c = (struct encryptlist *)
195146808Sdab 		genget(argv[1], (char **) EncryptList, sizeof(struct encryptlist));
195246808Sdab     if (c == 0) {
195346808Sdab         fprintf(stderr, "'%s': unknown argument ('encrypt ?' for help).\n",
195446808Sdab     				argv[1]);
195546808Sdab         return 0;
195646808Sdab     }
195746808Sdab     if (Ambiguous(c)) {
195846808Sdab         fprintf(stderr, "'%s': ambiguous argument ('encrypt ?' for help).\n",
195946808Sdab     				argv[1]);
196046808Sdab         return 0;
196146808Sdab     }
196246808Sdab     argc -= 2;
196346808Sdab     if (argc < c->minarg || argc > c->maxarg) {
196446808Sdab 	if (c->minarg == c->maxarg) {
196546808Sdab 	    fprintf(stderr, "Need %s%d argument%s ",
196646808Sdab 		c->minarg < argc ? "only " : "", c->minarg,
196746808Sdab 		c->minarg == 1 ? "" : "s");
196846808Sdab 	} else {
196946808Sdab 	    fprintf(stderr, "Need %s%d-%d arguments ",
197046808Sdab 		c->maxarg < argc ? "only " : "", c->minarg, c->maxarg);
197146808Sdab 	}
197246808Sdab 	fprintf(stderr, "to 'encrypt %s' command.  'encrypt ?' for help.\n",
197346808Sdab 		c->name);
197446808Sdab 	return 0;
197546808Sdab     }
197646808Sdab     if (c->needconnect && !connected) {
197746808Sdab 	if (!(argc && (isprefix(argv[2], "help") || isprefix(argv[2], "?")))) {
197846808Sdab 	    printf("?Need to be connected first.\n");
197946808Sdab 	    return 0;
198046808Sdab 	}
198146808Sdab     }
198246808Sdab     return ((*c->handler)(argc > 0 ? argv[2] : 0,
198346808Sdab 			argc > 1 ? argv[3] : 0,
198446808Sdab 			argc > 2 ? argv[4] : 0));
198546808Sdab }
198636274Sminshall #endif
198736274Sminshall 
198846808Sdab #if	defined(unix) && defined(TN3270)
198946808Sdab     static void
199036274Sminshall filestuff(fd)
199146808Sdab     int fd;
199236274Sminshall {
199336274Sminshall     int res;
199436274Sminshall 
199538689Sborman #ifdef	F_GETOWN
199638689Sborman     setconnmode(0);
199736274Sminshall     res = fcntl(fd, F_GETOWN, 0);
199836274Sminshall     setcommandmode();
199936274Sminshall 
200036274Sminshall     if (res == -1) {
200136274Sminshall 	perror("fcntl");
200236274Sminshall 	return;
200336274Sminshall     }
200436274Sminshall     printf("\tOwner is %d.\n", res);
200538689Sborman #endif
200636274Sminshall 
200738689Sborman     setconnmode(0);
200836274Sminshall     res = fcntl(fd, F_GETFL, 0);
200936274Sminshall     setcommandmode();
201036274Sminshall 
201136274Sminshall     if (res == -1) {
201236274Sminshall 	perror("fcntl");
201336274Sminshall 	return;
201436274Sminshall     }
201536274Sminshall     printf("\tFlags are 0x%x: %s\n", res, decodeflags(res));
201636274Sminshall }
201746808Sdab #endif /* defined(unix) && defined(TN3270) */
201836274Sminshall 
201936274Sminshall /*
202032144Sminshall  * Print status about the connection.
202132144Sminshall  */
202246808Sdab     /*ARGSUSED*/
202346808Sdab     static
202432144Sminshall status(argc, argv)
202546808Sdab     int	 argc;
202646808Sdab     char *argv[];
202732144Sminshall {
202832144Sminshall     if (connected) {
202932144Sminshall 	printf("Connected to %s.\n", hostname);
203036242Sminshall 	if ((argc < 2) || strcmp(argv[1], "notmuch")) {
203138689Sborman 	    int mode = getconnmode();
203238689Sborman 
203338689Sborman 	    if (my_want_state_is_will(TELOPT_LINEMODE)) {
203438689Sborman 		printf("Operating with LINEMODE option\n");
203538689Sborman 		printf("%s line editing\n", (mode&MODE_EDIT) ? "Local" : "No");
203638689Sborman 		printf("%s catching of signals\n",
203738689Sborman 					(mode&MODE_TRAPSIG) ? "Local" : "No");
203838689Sborman 		slcstate();
203938689Sborman #ifdef	KLUDGELINEMODE
204039529Sborman 	    } else if (kludgelinemode && my_want_state_is_dont(TELOPT_SGA)) {
204138689Sborman 		printf("Operating in obsolete linemode\n");
204238689Sborman #endif
204338689Sborman 	    } else {
204438689Sborman 		printf("Operating in single character mode\n");
204538689Sborman 		if (localchars)
204638689Sborman 		    printf("Catching signals locally\n");
204732144Sminshall 	    }
204838689Sborman 	    printf("%s character echo\n", (mode&MODE_ECHO) ? "Local" : "Remote");
204938689Sborman 	    if (my_want_state_is_will(TELOPT_LFLOW))
205038689Sborman 		printf("%s flow control\n", (mode&MODE_FLOW) ? "Local" : "No");
205146808Sdab #if	defined(ENCRYPT)
205246808Sdab 	    encrypt_display();
205346808Sdab #endif
205432144Sminshall 	}
205532144Sminshall     } else {
205632144Sminshall 	printf("No connection.\n");
205732144Sminshall     }
205832144Sminshall #   if !defined(TN3270)
205932144Sminshall     printf("Escape character is '%s'.\n", control(escape));
206034849Sminshall     (void) fflush(stdout);
206132144Sminshall #   else /* !defined(TN3270) */
206232144Sminshall     if ((!In3270) && ((argc < 2) || strcmp(argv[1], "notmuch"))) {
206332144Sminshall 	printf("Escape character is '%s'.\n", control(escape));
206432144Sminshall     }
206532144Sminshall #   if defined(unix)
206636242Sminshall     if ((argc >= 2) && !strcmp(argv[1], "everything")) {
206736242Sminshall 	printf("SIGIO received %d time%s.\n",
206836242Sminshall 				sigiocount, (sigiocount == 1)? "":"s");
206936274Sminshall 	if (In3270) {
207036274Sminshall 	    printf("Process ID %d, process group %d.\n",
207136274Sminshall 					    getpid(), getpgrp(getpid()));
207236274Sminshall 	    printf("Terminal input:\n");
207336274Sminshall 	    filestuff(tin);
207436274Sminshall 	    printf("Terminal output:\n");
207536274Sminshall 	    filestuff(tout);
207636274Sminshall 	    printf("Network socket:\n");
207736274Sminshall 	    filestuff(net);
207836274Sminshall 	}
207936242Sminshall     }
208032144Sminshall     if (In3270 && transcom) {
208132144Sminshall        printf("Transparent mode command is '%s'.\n", transcom);
208232144Sminshall     }
208332144Sminshall #   endif /* defined(unix) */
208434849Sminshall     (void) fflush(stdout);
208532144Sminshall     if (In3270) {
208632144Sminshall 	return 0;
208732144Sminshall     }
208832144Sminshall #   endif /* defined(TN3270) */
208932144Sminshall     return 1;
209032144Sminshall }
209132144Sminshall 
209245233Sborman #ifdef	SIGINFO
209345233Sborman /*
209445233Sborman  * Function that gets called when SIGINFO is received.
209545233Sborman  */
209645233Sborman ayt_status()
209745233Sborman {
209845233Sborman     (void) call(status, "status", "notmuch", 0);
209945233Sborman }
210045233Sborman #endif
210132144Sminshall 
210246808Sdab     int
210332144Sminshall tn(argc, argv)
210446808Sdab     int argc;
210546808Sdab     char *argv[];
210632144Sminshall {
210732144Sminshall     register struct hostent *host = 0;
210832144Sminshall     struct sockaddr_in sin;
210932144Sminshall     struct servent *sp = 0;
211038689Sborman     unsigned long temp, inet_addr();
211137219Sminshall     extern char *inet_ntoa();
211246808Sdab #if	defined(IP_OPTIONS) && defined(IPPROTO_IP)
211338689Sborman     char *srp = 0, *strrchr();
211438689Sborman     unsigned long sourceroute(), srlen;
211538689Sborman #endif
211644361Sborman     char *cmd, *hostp = 0, *portp = 0, *user = 0;
211732144Sminshall 
211845233Sborman     /* clear the socket address prior to use */
211945233Sborman     bzero((char *)&sin, sizeof(sin));
212032144Sminshall 
212132144Sminshall     if (connected) {
212232144Sminshall 	printf("?Already connected to %s\n", hostname);
212346808Sdab 	setuid(getuid());
212432144Sminshall 	return 0;
212532144Sminshall     }
212632144Sminshall     if (argc < 2) {
212746808Sdab 	(void) strcpy(line, "open ");
212832144Sminshall 	printf("(to) ");
212946808Sdab 	(void) fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin);
213032144Sminshall 	makeargv();
213132144Sminshall 	argc = margc;
213232144Sminshall 	argv = margv;
213332144Sminshall     }
213444361Sborman     cmd = *argv;
213544361Sborman     --argc; ++argv;
213644361Sborman     while (argc) {
213746808Sdab 	if (isprefix(*argv, "help") || isprefix(*argv, "?"))
213846808Sdab 	    goto usage;
213944361Sborman 	if (strcmp(*argv, "-l") == 0) {
214044361Sborman 	    --argc; ++argv;
214144361Sborman 	    if (argc == 0)
214244361Sborman 		goto usage;
214344361Sborman 	    user = *argv++;
214444361Sborman 	    --argc;
214544361Sborman 	    continue;
214644361Sborman 	}
214745233Sborman 	if (strcmp(*argv, "-a") == 0) {
214845233Sborman 	    --argc; ++argv;
214945233Sborman 	    autologin = 1;
215045233Sborman 	    continue;
215145233Sborman 	}
215244361Sborman 	if (hostp == 0) {
215344361Sborman 	    hostp = *argv++;
215444361Sborman 	    --argc;
215544361Sborman 	    continue;
215644361Sborman 	}
215744361Sborman 	if (portp == 0) {
215844361Sborman 	    portp = *argv++;
215944361Sborman 	    --argc;
216044361Sborman 	    continue;
216144361Sborman 	}
216244361Sborman     usage:
216345233Sborman 	printf("usage: %s [-l user] [-a] host-name [port]\n", cmd);
216446808Sdab 	setuid(getuid());
216532144Sminshall 	return 0;
216632144Sminshall     }
216746808Sdab     if (hostp == 0)
216846808Sdab 	goto usage;
216946808Sdab 
217046808Sdab #if	defined(IP_OPTIONS) && defined(IPPROTO_IP)
217144361Sborman     if (hostp[0] == '@' || hostp[0] == '!') {
217244361Sborman 	if ((hostname = strrchr(hostp, ':')) == NULL)
217344361Sborman 	    hostname = strrchr(hostp, '@');
217438689Sborman 	hostname++;
217538689Sborman 	srp = 0;
217644361Sborman 	temp = sourceroute(hostp, &srp, &srlen);
217738689Sborman 	if (temp == 0) {
217838689Sborman 	    herror(srp);
217946808Sdab 	    setuid(getuid());
218038689Sborman 	    return 0;
218138689Sborman 	} else if (temp == -1) {
218244361Sborman 	    printf("Bad source route option: %s\n", hostp);
218346808Sdab 	    setuid(getuid());
218438689Sborman 	    return 0;
218538689Sborman 	} else {
218638689Sborman 	    sin.sin_addr.s_addr = temp;
218738689Sborman 	    sin.sin_family = AF_INET;
218838689Sborman 	}
218932144Sminshall     } else {
219038689Sborman #endif
219144361Sborman 	temp = inet_addr(hostp);
219238689Sborman 	if (temp != (unsigned long) -1) {
219338689Sborman 	    sin.sin_addr.s_addr = temp;
219438689Sborman 	    sin.sin_family = AF_INET;
219546808Sdab 	    (void) strcpy(_hostname, hostp);
219646808Sdab 	    hostname = _hostname;
219738689Sborman 	} else {
219844361Sborman 	    host = gethostbyname(hostp);
219938689Sborman 	    if (host) {
220038689Sborman 		sin.sin_family = host->h_addrtype;
220132144Sminshall #if	defined(h_addr)		/* In 4.3, this is a #define */
220238689Sborman 		memcpy((caddr_t)&sin.sin_addr,
220332144Sminshall 				host->h_addr_list[0], host->h_length);
220432144Sminshall #else	/* defined(h_addr) */
220538689Sborman 		memcpy((caddr_t)&sin.sin_addr, host->h_addr, host->h_length);
220632144Sminshall #endif	/* defined(h_addr) */
220746808Sdab 		strncpy(_hostname, host->h_name, sizeof(_hostname));
220846808Sdab 		_hostname[sizeof(_hostname)-1] = '\0';
220946808Sdab 		hostname = _hostname;
221038689Sborman 	    } else {
221144361Sborman 		herror(hostp);
221246808Sdab 	        setuid(getuid());
221338689Sborman 		return 0;
221438689Sborman 	    }
221532144Sminshall 	}
221646808Sdab #if	defined(IP_OPTIONS) && defined(IPPROTO_IP)
221732144Sminshall     }
221838689Sborman #endif
221944361Sborman     if (portp) {
222044361Sborman 	if (*portp == '-') {
222144361Sborman 	    portp++;
222238689Sborman 	    telnetport = 1;
222338689Sborman 	} else
222438689Sborman 	    telnetport = 0;
222544361Sborman 	sin.sin_port = atoi(portp);
222632144Sminshall 	if (sin.sin_port == 0) {
222744361Sborman 	    sp = getservbyname(portp, "tcp");
222832144Sminshall 	    if (sp)
222932144Sminshall 		sin.sin_port = sp->s_port;
223032144Sminshall 	    else {
223144361Sborman 		printf("%s: bad port number\n", portp);
223246808Sdab 	        setuid(getuid());
223332144Sminshall 		return 0;
223432144Sminshall 	    }
223532144Sminshall 	} else {
223634849Sminshall #if	!defined(htons)
223734849Sminshall 	    u_short htons();
223834849Sminshall #endif	/* !defined(htons) */
223932144Sminshall 	    sin.sin_port = htons(sin.sin_port);
224032144Sminshall 	}
224132144Sminshall     } else {
224232144Sminshall 	if (sp == 0) {
224332144Sminshall 	    sp = getservbyname("telnet", "tcp");
224432144Sminshall 	    if (sp == 0) {
224534849Sminshall 		fprintf(stderr, "telnet: tcp/telnet: unknown service\n");
224646808Sdab 	        setuid(getuid());
224732144Sminshall 		return 0;
224832144Sminshall 	    }
224932144Sminshall 	    sin.sin_port = sp->s_port;
225032144Sminshall 	}
225132144Sminshall 	telnetport = 1;
225232144Sminshall     }
225337219Sminshall     printf("Trying %s...\n", inet_ntoa(sin.sin_addr));
225432144Sminshall     do {
225532144Sminshall 	net = socket(AF_INET, SOCK_STREAM, 0);
225646808Sdab 	setuid(getuid());
225732144Sminshall 	if (net < 0) {
225832144Sminshall 	    perror("telnet: socket");
225932144Sminshall 	    return 0;
226032144Sminshall 	}
226146808Sdab #if	defined(IP_OPTIONS) && defined(IPPROTO_IP)
226238689Sborman 	if (srp && setsockopt(net, IPPROTO_IP, IP_OPTIONS, (char *)srp, srlen) < 0)
226338689Sborman 		perror("setsockopt (IP_OPTIONS)");
226438689Sborman #endif
226546808Sdab #if	defined(IPPROTO_IP) && defined(IP_TOS)
226646808Sdab 	{
226746808Sdab # if	defined(HAS_GETTOS)
226846808Sdab 	    struct tosent *tp;
226946815Sdab 	    if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
227046808Sdab 		tos = tp->t_tos;
227146808Sdab # endif
227246815Sdab 	    if (tos < 0)
227346815Sdab 		tos = 020;	/* Low Delay bit */
227446815Sdab 	    if (tos
227546815Sdab 		&& (setsockopt(net, IPPROTO_IP, IP_TOS, &tos, sizeof(int)) < 0)
227646815Sdab 		&& (errno != ENOPROTOOPT))
227746815Sdab 		    perror("telnet: setsockopt (IP_TOS) (ignored)");
227846808Sdab 	}
227946808Sdab #endif	/* defined(IPPROTO_IP) && defined(IP_TOS) */
228040245Sborman 
228132144Sminshall 	if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) {
228232144Sminshall 		perror("setsockopt (SO_DEBUG)");
228332144Sminshall 	}
228432144Sminshall 
228532144Sminshall 	if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
228632144Sminshall #if	defined(h_addr)		/* In 4.3, this is a #define */
228732144Sminshall 	    if (host && host->h_addr_list[1]) {
228832144Sminshall 		int oerrno = errno;
228932144Sminshall 
229032144Sminshall 		fprintf(stderr, "telnet: connect to address %s: ",
229132144Sminshall 						inet_ntoa(sin.sin_addr));
229232144Sminshall 		errno = oerrno;
229332144Sminshall 		perror((char *)0);
229432144Sminshall 		host->h_addr_list++;
229532144Sminshall 		memcpy((caddr_t)&sin.sin_addr,
229632144Sminshall 			host->h_addr_list[0], host->h_length);
229732144Sminshall 		(void) NetClose(net);
229832144Sminshall 		continue;
229932144Sminshall 	    }
230032144Sminshall #endif	/* defined(h_addr) */
230132144Sminshall 	    perror("telnet: Unable to connect to remote host");
230232144Sminshall 	    return 0;
230337219Sminshall 	}
230432144Sminshall 	connected++;
230546808Sdab #if	defined(AUTHENTICATE) || defined(ENCRYPT)
230646808Sdab 	auth_encrypt_connect(connected);
230746808Sdab #endif
230832144Sminshall     } while (connected == 0);
230944361Sborman     cmdrc(hostp, hostname);
231045008Skarels     if (autologin && user == NULL) {
231145008Skarels 	struct passwd *pw;
231245008Skarels 
231345233Sborman 	user = getenv("USER");
231445008Skarels 	if (user == NULL ||
231545233Sborman 	    (pw = getpwnam(user)) && pw->pw_uid != getuid()) {
231645233Sborman 		if (pw = getpwuid(getuid()))
231745008Skarels 			user = pw->pw_name;
231845008Skarels 		else
231945008Skarels 			user = NULL;
232045233Sborman 	}
232145008Skarels     }
232245008Skarels     if (user) {
232346808Sdab 	env_define((unsigned char *)"USER", (unsigned char *)user);
232446808Sdab 	env_export((unsigned char *)"USER");
232545008Skarels     }
232634849Sminshall     (void) call(status, "status", "notmuch", 0);
232732144Sminshall     if (setjmp(peerdied) == 0)
232846808Sdab 	telnet(user);
232934849Sminshall     (void) NetClose(net);
233032381Sminshall     ExitString("Connection closed by foreign host.\n",1);
233132144Sminshall     /*NOTREACHED*/
233232144Sminshall }
233332144Sminshall 
233432144Sminshall #define HELPINDENT (sizeof ("connect"))
233532144Sminshall 
233632144Sminshall static char
233732144Sminshall 	openhelp[] =	"connect to a site",
233832144Sminshall 	closehelp[] =	"close current connection",
233946808Sdab 	logouthelp[] =	"forcibly logout remote user and close the connection",
234032144Sminshall 	quithelp[] =	"exit telnet",
234132144Sminshall 	statushelp[] =	"print status information",
234232144Sminshall 	helphelp[] =	"print help information",
234332144Sminshall 	sendhelp[] =	"transmit special characters ('send ?' for more)",
234432144Sminshall 	sethelp[] = 	"set operating parameters ('set ?' for more)",
234538689Sborman 	unsethelp[] = 	"unset operating parameters ('unset ?' for more)",
234632144Sminshall 	togglestring[] ="toggle operating parameters ('toggle ?' for more)",
234738689Sborman 	slchelp[] =	"change state of special charaters ('slc ?' for more)",
234832144Sminshall 	displayhelp[] =	"display operating parameters",
234932144Sminshall #if	defined(TN3270) && defined(unix)
235032144Sminshall 	transcomhelp[] = "specify Unix command for transparent mode pipe",
235132144Sminshall #endif	/* defined(TN3270) && defined(unix) */
235246808Sdab #if	defined(AUTHENTICATE)
235346808Sdab 	authhelp[] =	"turn on (off) authentication ('auth ?' for more)",
235446808Sdab #endif
235546808Sdab #if	defined(ENCRYPT)
235646808Sdab 	encrypthelp[] =	"turn on (off) encryption ('encrypt ?' for more)",
235746808Sdab #endif
235832144Sminshall #if	defined(unix)
235932144Sminshall 	zhelp[] =	"suspend telnet",
236043317Skfall #endif	/* defined(unix) */
236132144Sminshall 	shellhelp[] =	"invoke a subshell",
236244361Sborman 	envhelp[] =	"change environment variables ('environ ?' for more)",
236344361Sborman 	modestring[] = "try to enter line or character mode ('mode ?' for more)";
236432144Sminshall 
236546808Sdab extern int	help();
236632144Sminshall 
236732144Sminshall static Command cmdtab[] = {
236838689Sborman 	{ "close",	closehelp,	bye,		1 },
236946808Sdab 	{ "logout",	logouthelp,	logout,		1 },
237038689Sborman 	{ "display",	displayhelp,	display,	0 },
237138689Sborman 	{ "mode",	modestring,	modecmd,	0 },
237238689Sborman 	{ "open",	openhelp,	tn,		0 },
237338689Sborman 	{ "quit",	quithelp,	quit,		0 },
237438689Sborman 	{ "send",	sendhelp,	sendcmd,	0 },
237538689Sborman 	{ "set",	sethelp,	setcmd,		0 },
237638689Sborman 	{ "unset",	unsethelp,	unsetcmd,	0 },
237738689Sborman 	{ "status",	statushelp,	status,		0 },
237838689Sborman 	{ "toggle",	togglestring,	toggle,		0 },
237938689Sborman 	{ "slc",	slchelp,	slccmd,		0 },
238032144Sminshall #if	defined(TN3270) && defined(unix)
238138689Sborman 	{ "transcom",	transcomhelp,	settranscom,	0 },
238232144Sminshall #endif	/* defined(TN3270) && defined(unix) */
238346808Sdab #if	defined(AUTHENTICATE)
238446808Sdab 	{ "auth",	authhelp,	auth_cmd,	0 },
238546808Sdab #endif
238646808Sdab #if	defined(ENCRYPT)
238746808Sdab 	{ "encrypt",	encrypthelp,	encrypt_cmd,	0 },
238846808Sdab #endif
238932144Sminshall #if	defined(unix)
239038689Sborman 	{ "z",		zhelp,		suspend,	0 },
239132144Sminshall #endif	/* defined(unix) */
239232144Sminshall #if	defined(TN3270)
239338689Sborman 	{ "!",		shellhelp,	shell,		1 },
239438689Sborman #else
239538689Sborman 	{ "!",		shellhelp,	shell,		0 },
239638689Sborman #endif
239744361Sborman 	{ "environ",	envhelp,	env_cmd,	0 },
239838689Sborman 	{ "?",		helphelp,	help,		0 },
239932144Sminshall 	0
240032144Sminshall };
240132144Sminshall 
240232144Sminshall static char	crmodhelp[] =	"deprecated command -- use 'toggle crmod' instead";
240332144Sminshall static char	escapehelp[] =	"deprecated command -- use 'set escape' instead";
240432144Sminshall 
240532144Sminshall static Command cmdtab2[] = {
240638689Sborman 	{ "help",	0,		help,		0 },
240738689Sborman 	{ "escape",	escapehelp,	setescape,	0 },
240838689Sborman 	{ "crmod",	crmodhelp,	togcrmod,	0 },
240932144Sminshall 	0
241032144Sminshall };
241132144Sminshall 
241235298Sminshall 
241332144Sminshall /*
241432144Sminshall  * Call routine with argc, argv set from args (terminated by 0).
241532144Sminshall  */
241635298Sminshall 
241746808Sdab     /*VARARGS1*/
241846808Sdab     static
241935298Sminshall call(va_alist)
242046808Sdab     va_dcl
242132144Sminshall {
242235298Sminshall     va_list ap;
242335298Sminshall     typedef int (*intrtn_t)();
242435298Sminshall     intrtn_t routine;
242535298Sminshall     char *args[100];
242635298Sminshall     int argno = 0;
242735298Sminshall 
242835298Sminshall     va_start(ap);
242935298Sminshall     routine = (va_arg(ap, intrtn_t));
243035495Sminshall     while ((args[argno++] = va_arg(ap, char *)) != 0) {
243135298Sminshall 	;
243235495Sminshall     }
243335298Sminshall     va_end(ap);
243435495Sminshall     return (*routine)(argno-1, args);
243532144Sminshall }
243632144Sminshall 
243735298Sminshall 
243846808Sdab     static Command *
243932144Sminshall getcmd(name)
244046808Sdab     char *name;
244132144Sminshall {
244232144Sminshall     Command *cm;
244332144Sminshall 
244446808Sdab     if (cm = (Command *) genget(name, (char **) cmdtab, sizeof(Command)))
244532144Sminshall 	return cm;
244646808Sdab     return (Command *) genget(name, (char **) cmdtab2, sizeof(Command));
244732144Sminshall }
244832144Sminshall 
244946808Sdab     void
245038689Sborman command(top, tbuf, cnt)
245146808Sdab     int top;
245246808Sdab     char *tbuf;
245346808Sdab     int cnt;
245432144Sminshall {
245532144Sminshall     register Command *c;
245632144Sminshall 
245732144Sminshall     setcommandmode();
245832144Sminshall     if (!top) {
245932144Sminshall 	putchar('\n');
246037219Sminshall #if	defined(unix)
246132144Sminshall     } else {
246244361Sborman 	(void) signal(SIGINT, SIG_DFL);
246344361Sborman 	(void) signal(SIGQUIT, SIG_DFL);
246432144Sminshall #endif	/* defined(unix) */
246532144Sminshall     }
246632144Sminshall     for (;;) {
246746808Sdab 	if (rlogin == _POSIX_VDISABLE)
246846808Sdab 		printf("%s> ", prompt);
246938689Sborman 	if (tbuf) {
247038689Sborman 	    register char *cp;
247138689Sborman 	    cp = line;
247238689Sborman 	    while (cnt > 0 && (*cp++ = *tbuf++) != '\n')
247338689Sborman 		cnt--;
247438689Sborman 	    tbuf = 0;
247538689Sborman 	    if (cp == line || *--cp != '\n' || cp == line)
247638689Sborman 		goto getline;
247738689Sborman 	    *cp = '\0';
247846808Sdab 	    if (rlogin == _POSIX_VDISABLE)
247946808Sdab 	        printf("%s\n", line);
248038689Sborman 	} else {
248138689Sborman 	getline:
248246808Sdab 	    if (rlogin != _POSIX_VDISABLE)
248346808Sdab 		printf("%s> ", prompt);
248446808Sdab 	    if (fgets(line, sizeof(line), stdin) == NULL) {
248544361Sborman 		if (feof(stdin) || ferror(stdin)) {
248644361Sborman 		    (void) quit();
248744361Sborman 		    /*NOTREACHED*/
248844361Sborman 		}
248938689Sborman 		break;
249038689Sborman 	    }
249132144Sminshall 	}
249232144Sminshall 	if (line[0] == 0)
249332144Sminshall 	    break;
249432144Sminshall 	makeargv();
249537219Sminshall 	if (margv[0] == 0) {
249637219Sminshall 	    break;
249737219Sminshall 	}
249832144Sminshall 	c = getcmd(margv[0]);
249932144Sminshall 	if (Ambiguous(c)) {
250032144Sminshall 	    printf("?Ambiguous command\n");
250132144Sminshall 	    continue;
250232144Sminshall 	}
250332144Sminshall 	if (c == 0) {
250432144Sminshall 	    printf("?Invalid command\n");
250532144Sminshall 	    continue;
250632144Sminshall 	}
250732144Sminshall 	if (c->needconnect && !connected) {
250832144Sminshall 	    printf("?Need to be connected first.\n");
250932144Sminshall 	    continue;
251032144Sminshall 	}
251132144Sminshall 	if ((*c->handler)(margc, margv)) {
251232144Sminshall 	    break;
251332144Sminshall 	}
251432144Sminshall     }
251532144Sminshall     if (!top) {
251632144Sminshall 	if (!connected) {
251732144Sminshall 	    longjmp(toplevel, 1);
251832144Sminshall 	    /*NOTREACHED*/
251932144Sminshall 	}
252032144Sminshall #if	defined(TN3270)
252132144Sminshall 	if (shell_active == 0) {
252238689Sborman 	    setconnmode(0);
252332144Sminshall 	}
252432144Sminshall #else	/* defined(TN3270) */
252538689Sborman 	setconnmode(0);
252632144Sminshall #endif	/* defined(TN3270) */
252732144Sminshall     }
252832144Sminshall }
252932144Sminshall 
253032144Sminshall /*
253132144Sminshall  * Help command.
253232144Sminshall  */
253346808Sdab 	static
253432144Sminshall help(argc, argv)
253532144Sminshall 	int argc;
253632144Sminshall 	char *argv[];
253732144Sminshall {
253832144Sminshall 	register Command *c;
253932144Sminshall 
254032144Sminshall 	if (argc == 1) {
254132144Sminshall 		printf("Commands may be abbreviated.  Commands are:\n\n");
254232144Sminshall 		for (c = cmdtab; c->name; c++)
254338689Sborman 			if (c->help) {
254432144Sminshall 				printf("%-*s\t%s\n", HELPINDENT, c->name,
254532144Sminshall 								    c->help);
254632144Sminshall 			}
254732144Sminshall 		return 0;
254832144Sminshall 	}
254932144Sminshall 	while (--argc > 0) {
255032144Sminshall 		register char *arg;
255132144Sminshall 		arg = *++argv;
255232144Sminshall 		c = getcmd(arg);
255332144Sminshall 		if (Ambiguous(c))
255432144Sminshall 			printf("?Ambiguous help command %s\n", arg);
255532144Sminshall 		else if (c == (Command *)0)
255632144Sminshall 			printf("?Invalid help command %s\n", arg);
255732144Sminshall 		else
255832144Sminshall 			printf("%s\n", c->help);
255932144Sminshall 	}
256032144Sminshall 	return 0;
256132144Sminshall }
256238689Sborman 
256338689Sborman static char *rcname = 0;
256438689Sborman static char rcbuf[128];
256538689Sborman 
256638689Sborman cmdrc(m1, m2)
256738689Sborman 	char *m1, *m2;
256838689Sborman {
256938689Sborman     register Command *c;
257038689Sborman     FILE *rcfile;
257138689Sborman     int gotmachine = 0;
257238689Sborman     int l1 = strlen(m1);
257338689Sborman     int l2 = strlen(m2);
257438689Sborman     char m1save[64];
257538689Sborman 
2576*47609Sdab     if (skiprc)
2577*47609Sdab 	return;
2578*47609Sdab 
257938689Sborman     strcpy(m1save, m1);
258038689Sborman     m1 = m1save;
258138689Sborman 
258238689Sborman     if (rcname == 0) {
258338689Sborman 	rcname = getenv("HOME");
258438689Sborman 	if (rcname)
258538689Sborman 	    strcpy(rcbuf, rcname);
258638689Sborman 	else
258738689Sborman 	    rcbuf[0] = '\0';
258838689Sborman 	strcat(rcbuf, "/.telnetrc");
258938689Sborman 	rcname = rcbuf;
259038689Sborman     }
259138689Sborman 
259238689Sborman     if ((rcfile = fopen(rcname, "r")) == 0) {
259338689Sborman 	return;
259438689Sborman     }
259538689Sborman 
259638689Sborman     for (;;) {
259738689Sborman 	if (fgets(line, sizeof(line), rcfile) == NULL)
259838689Sborman 	    break;
259938689Sborman 	if (line[0] == 0)
260038689Sborman 	    break;
260138689Sborman 	if (line[0] == '#')
260238689Sborman 	    continue;
2603*47609Sdab 	if (gotmachine) {
2604*47609Sdab 	    if (!isspace(line[0]))
2605*47609Sdab 		gotmachine = 0;
2606*47609Sdab 	}
260738689Sborman 	if (gotmachine == 0) {
260838689Sborman 	    if (isspace(line[0]))
260938689Sborman 		continue;
261038689Sborman 	    if (strncasecmp(line, m1, l1) == 0)
261138689Sborman 		strncpy(line, &line[l1], sizeof(line) - l1);
261238689Sborman 	    else if (strncasecmp(line, m2, l2) == 0)
261338689Sborman 		strncpy(line, &line[l2], sizeof(line) - l2);
2614*47609Sdab 	    else if (strncasecmp(line, "DEFAULT", 7) == 0)
2615*47609Sdab 		strncpy(line, &line[7], sizeof(line) - 7);
261638689Sborman 	    else
261738689Sborman 		continue;
2618*47609Sdab 	    if (line[0] != ' ' && line[0] != '\t' && line[0] != '\n')
2619*47609Sdab 		continue;
262038689Sborman 	    gotmachine = 1;
262138689Sborman 	}
262238689Sborman 	makeargv();
262338689Sborman 	if (margv[0] == 0)
262438689Sborman 	    continue;
262538689Sborman 	c = getcmd(margv[0]);
262638689Sborman 	if (Ambiguous(c)) {
262738689Sborman 	    printf("?Ambiguous command: %s\n", margv[0]);
262838689Sborman 	    continue;
262938689Sborman 	}
263038689Sborman 	if (c == 0) {
263138689Sborman 	    printf("?Invalid command: %s\n", margv[0]);
263238689Sborman 	    continue;
263338689Sborman 	}
263438689Sborman 	/*
263538689Sborman 	 * This should never happen...
263638689Sborman 	 */
263738689Sborman 	if (c->needconnect && !connected) {
263838689Sborman 	    printf("?Need to be connected first for %s.\n", margv[0]);
263938689Sborman 	    continue;
264038689Sborman 	}
264138689Sborman 	(*c->handler)(margc, margv);
264238689Sborman     }
264338689Sborman     fclose(rcfile);
264438689Sborman }
264538689Sborman 
264646808Sdab #if	defined(IP_OPTIONS) && defined(IPPROTO_IP)
264738689Sborman 
264838689Sborman /*
264938689Sborman  * Source route is handed in as
265038689Sborman  *	[!]@hop1@hop2...[@|:]dst
265138689Sborman  * If the leading ! is present, it is a
265238689Sborman  * strict source route, otherwise it is
265338689Sborman  * assmed to be a loose source route.
265438689Sborman  *
265538689Sborman  * We fill in the source route option as
265638689Sborman  *	hop1,hop2,hop3...dest
265738689Sborman  * and return a pointer to hop1, which will
265838689Sborman  * be the address to connect() to.
265938689Sborman  *
266038689Sborman  * Arguments:
266138689Sborman  *	arg:	pointer to route list to decipher
266238689Sborman  *
266338689Sborman  *	cpp: 	If *cpp is not equal to NULL, this is a
266438689Sborman  *		pointer to a pointer to a character array
266538689Sborman  *		that should be filled in with the option.
266638689Sborman  *
266738689Sborman  *	lenp:	pointer to an integer that contains the
266838689Sborman  *		length of *cpp if *cpp != NULL.
266938689Sborman  *
267038689Sborman  * Return values:
267138689Sborman  *
267238689Sborman  *	Returns the address of the host to connect to.  If the
267338689Sborman  *	return value is -1, there was a syntax error in the
267438689Sborman  *	option, either unknown characters, or too many hosts.
267538689Sborman  *	If the return value is 0, one of the hostnames in the
267638689Sborman  *	path is unknown, and *cpp is set to point to the bad
267738689Sborman  *	hostname.
267838689Sborman  *
267938689Sborman  *	*cpp:	If *cpp was equal to NULL, it will be filled
268038689Sborman  *		in with a pointer to our static area that has
268138689Sborman  *		the option filled in.  This will be 32bit aligned.
268238689Sborman  *
268338689Sborman  *	*lenp:	This will be filled in with how long the option
268438689Sborman  *		pointed to by *cpp is.
268538689Sborman  *
268638689Sborman  */
268746808Sdab 	unsigned long
268838689Sborman sourceroute(arg, cpp, lenp)
268946808Sdab 	char	*arg;
269046808Sdab 	char	**cpp;
269146808Sdab 	int	*lenp;
269238689Sborman {
269338689Sborman 	static char lsr[44];
269446808Sdab 	char *cp, *cp2, *lsrp, *lsrep;
269538689Sborman 	register int tmp;
269638689Sborman 	struct in_addr sin_addr;
269738689Sborman 	register struct hostent *host = 0;
269838689Sborman 	register char c;
269938689Sborman 
270038689Sborman 	/*
270138689Sborman 	 * Verify the arguments, and make sure we have
270238689Sborman 	 * at least 7 bytes for the option.
270338689Sborman 	 */
270438689Sborman 	if (cpp == NULL || lenp == NULL)
270538689Sborman 		return((unsigned long)-1);
270638689Sborman 	if (*cpp != NULL && *lenp < 7)
270738689Sborman 		return((unsigned long)-1);
270838689Sborman 	/*
270938689Sborman 	 * Decide whether we have a buffer passed to us,
271038689Sborman 	 * or if we need to use our own static buffer.
271138689Sborman 	 */
271238689Sborman 	if (*cpp) {
271338689Sborman 		lsrp = *cpp;
271438689Sborman 		lsrep = lsrp + *lenp;
271538689Sborman 	} else {
271638689Sborman 		*cpp = lsrp = lsr;
271738689Sborman 		lsrep = lsrp + 44;
271838689Sborman 	}
271938689Sborman 
272038689Sborman 	cp = arg;
272138689Sborman 
272238689Sborman 	/*
272338689Sborman 	 * Next, decide whether we have a loose source
272438689Sborman 	 * route or a strict source route, and fill in
272538689Sborman 	 * the begining of the option.
272638689Sborman 	 */
272738689Sborman 	if (*cp == '!') {
272838689Sborman 		cp++;
272938689Sborman 		*lsrp++ = IPOPT_SSRR;
273038689Sborman 	} else
273138689Sborman 		*lsrp++ = IPOPT_LSRR;
273238689Sborman 
273338689Sborman 	if (*cp != '@')
273438689Sborman 		return((unsigned long)-1);
273538689Sborman 
273638689Sborman 	lsrp++;		/* skip over length, we'll fill it in later */
273738689Sborman 	*lsrp++ = 4;
273838689Sborman 
273938689Sborman 	cp++;
274038689Sborman 
274138689Sborman 	sin_addr.s_addr = 0;
274238689Sborman 
274338689Sborman 	for (c = 0;;) {
274438689Sborman 		if (c == ':')
274538689Sborman 			cp2 = 0;
274638689Sborman 		else for (cp2 = cp; c = *cp2; cp2++) {
274738689Sborman 			if (c == ',') {
274838689Sborman 				*cp2++ = '\0';
274938689Sborman 				if (*cp2 == '@')
275038689Sborman 					cp2++;
275138689Sborman 			} else if (c == '@') {
275238689Sborman 				*cp2++ = '\0';
275338689Sborman 			} else if (c == ':') {
275438689Sborman 				*cp2++ = '\0';
275538689Sborman 			} else
275638689Sborman 				continue;
275738689Sborman 			break;
275838689Sborman 		}
275938689Sborman 		if (!c)
276038689Sborman 			cp2 = 0;
276138689Sborman 
276238689Sborman 		if ((tmp = inet_addr(cp)) != -1) {
276338689Sborman 			sin_addr.s_addr = tmp;
276438689Sborman 		} else if (host = gethostbyname(cp)) {
276538689Sborman #if	defined(h_addr)
276638689Sborman 			memcpy((caddr_t)&sin_addr,
276738689Sborman 				host->h_addr_list[0], host->h_length);
276838689Sborman #else
276938689Sborman 			memcpy((caddr_t)&sin_addr, host->h_addr, host->h_length);
277038689Sborman #endif
277138689Sborman 		} else {
277238689Sborman 			*cpp = cp;
277338689Sborman 			return(0);
277438689Sborman 		}
277538689Sborman 		memcpy(lsrp, (char *)&sin_addr, 4);
277638689Sborman 		lsrp += 4;
277738689Sborman 		if (cp2)
277838689Sborman 			cp = cp2;
277938689Sborman 		else
278038689Sborman 			break;
278138689Sborman 		/*
278238689Sborman 		 * Check to make sure there is space for next address
278338689Sborman 		 */
278438689Sborman 		if (lsrp + 4 > lsrep)
278538689Sborman 			return((unsigned long)-1);
278638689Sborman 	}
278738689Sborman 	if ((*(*cpp+IPOPT_OLEN) = lsrp - *cpp) <= 7) {
278838689Sborman 		*cpp = 0;
278938689Sborman 		*lenp = 0;
279038689Sborman 		return((unsigned long)-1);
279138689Sborman 	}
279238689Sborman 	*lsrp++ = IPOPT_NOP; /* 32 bit word align it */
279338689Sborman 	*lenp = lsrp - *cpp;
279438689Sborman 	return(sin_addr.s_addr);
279538689Sborman }
279638689Sborman #endif
2797