xref: /csrg-svn/usr.bin/telnet/commands.c (revision 46815)
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*46815Sdab static char sccsid[] = "@(#)commands.c	5.4 (Berkeley) 03/01/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 
57*46815Sdab #if	defined(IPPROTO_IP) && defined(IP_TOS)
58*46815Sdab int tos = -1;
59*46815Sdab #endif	/* defined(IPPROTO_IP) && defined(IP_TOS) */
60*46815Sdab 
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));
58132144Sminshall 
58232144Sminshall struct togglelist {
58332144Sminshall     char	*name;		/* name of toggle */
58432144Sminshall     char	*help;		/* help message */
58532144Sminshall     int		(*handler)();	/* routine to do actual setting */
58632144Sminshall     int		*variable;
58732144Sminshall     char	*actionexplanation;
58832144Sminshall };
58932144Sminshall 
59032144Sminshall static struct togglelist Togglelist[] = {
59132144Sminshall     { "autoflush",
59238689Sborman 	"flushing of output when sending interrupt characters",
59332144Sminshall 	    0,
59438689Sborman 		&autoflush,
59538689Sborman 		    "flush output when sending interrupt characters" },
59632144Sminshall     { "autosynch",
59738689Sborman 	"automatic sending of interrupt characters in urgent mode",
59832144Sminshall 	    0,
59938689Sborman 		&autosynch,
60038689Sborman 		    "send interrupt characters in urgent mode" },
60132144Sminshall     { "binary",
60238689Sborman 	"sending and receiving of binary data",
60332144Sminshall 	    togbinary,
60438689Sborman 		0,
60538689Sborman 		    0 },
60638909Sborman     { "inbinary",
60738909Sborman 	"receiving of binary data",
60838909Sborman 	    togrbinary,
60938909Sborman 		0,
61038909Sborman 		    0 },
61138909Sborman     { "outbinary",
61238909Sborman 	"sending of binary data",
61338909Sborman 	    togxbinary,
61438909Sborman 		0,
61538909Sborman 		    0 },
61632144Sminshall     { "crlf",
61738689Sborman 	"sending carriage returns as telnet <CR><LF>",
61832144Sminshall 	    togcrlf,
61938689Sborman 		&crlf,
62038689Sborman 		    0 },
62132144Sminshall     { "crmod",
62238689Sborman 	"mapping of received carriage returns",
62332144Sminshall 	    0,
62438689Sborman 		&crmod,
62538689Sborman 		    "map carriage return on output" },
62632144Sminshall     { "localchars",
62738689Sborman 	"local recognition of certain control characters",
62832144Sminshall 	    lclchars,
62938689Sborman 		&localchars,
63038689Sborman 		    "recognize certain control characters" },
63138689Sborman     { " ", "", 0 },		/* empty line */
63238208Sminshall #if	defined(unix) && defined(TN3270)
63338920Sminshall     { "apitrace",
63438920Sminshall 	"(debugging) toggle tracing of API transactions",
63538920Sminshall 	    0,
63638920Sminshall 		&apitrace,
63738920Sminshall 		    "trace API transactions" },
63838208Sminshall     { "cursesdata",
63938208Sminshall 	"(debugging) toggle printing of hexadecimal curses data",
64038208Sminshall 	    0,
64138689Sborman 		&cursesdata,
64238689Sborman 		    "print hexadecimal representation of curses data" },
64338208Sminshall #endif	/* defined(unix) && defined(TN3270) */
64432144Sminshall     { "debug",
64538689Sborman 	"debugging",
64632144Sminshall 	    togdebug,
64738689Sborman 		&debug,
64838689Sborman 		    "turn on socket level debugging" },
64932144Sminshall     { "netdata",
65038689Sborman 	"printing of hexadecimal network data (debugging)",
65132144Sminshall 	    0,
65238689Sborman 		&netdata,
65338689Sborman 		    "print hexadecimal representation of network traffic" },
65438689Sborman     { "prettydump",
65538689Sborman 	"output of \"netdata\" to user readable format (debugging)",
65638689Sborman 	    0,
65738689Sborman 		&prettydump,
65838689Sborman 		    "print user readable output for \"netdata\"" },
65932144Sminshall     { "options",
66038689Sborman 	"viewing of options processing (debugging)",
66132144Sminshall 	    0,
66238689Sborman 		&showoptions,
66338689Sborman 		    "show option processing" },
66438208Sminshall #if	defined(unix)
66538208Sminshall     { "termdata",
66638208Sminshall 	"(debugging) toggle printing of hexadecimal terminal data",
66738208Sminshall 	    0,
66838689Sborman 		&termdata,
66938689Sborman 		    "print hexadecimal representation of terminal traffic" },
67038208Sminshall #endif	/* defined(unix) */
67132144Sminshall     { "?",
67238689Sborman 	0,
67338689Sborman 	    togglehelp },
67432144Sminshall     { "help",
67538689Sborman 	0,
67638689Sborman 	    togglehelp },
67732144Sminshall     { 0 }
67832144Sminshall };
67932144Sminshall 
68046808Sdab     static int
68132144Sminshall togglehelp()
68232144Sminshall {
68332144Sminshall     struct togglelist *c;
68432144Sminshall 
68532144Sminshall     for (c = Togglelist; c->name; c++) {
68638689Sborman 	if (c->help) {
68738689Sborman 	    if (*c->help)
68838689Sborman 		printf("%-15s toggle %s\n", c->name, c->help);
68938689Sborman 	    else
69038689Sborman 		printf("\n");
69132144Sminshall 	}
69232144Sminshall     }
69338689Sborman     printf("\n");
69438689Sborman     printf("%-15s %s\n", "?", "display help information");
69532144Sminshall     return 0;
69632144Sminshall }
69732144Sminshall 
69846808Sdab     static void
69938689Sborman settogglehelp(set)
70046808Sdab     int set;
70138689Sborman {
70238689Sborman     struct togglelist *c;
70338689Sborman 
70438689Sborman     for (c = Togglelist; c->name; c++) {
70538689Sborman 	if (c->help) {
70638689Sborman 	    if (*c->help)
70738689Sborman 		printf("%-15s %s %s\n", c->name, set ? "enable" : "disable",
70838689Sborman 						c->help);
70938689Sborman 	    else
71038689Sborman 		printf("\n");
71138689Sborman 	}
71238689Sborman     }
71338689Sborman }
71438689Sborman 
71546808Sdab #define	GETTOGGLE(name) (struct togglelist *) \
71646808Sdab 		genget(name, (char **) Togglelist, sizeof(struct togglelist))
71732144Sminshall 
71846808Sdab     static int
71932144Sminshall toggle(argc, argv)
72046808Sdab     int  argc;
72146808Sdab     char *argv[];
72232144Sminshall {
72332144Sminshall     int retval = 1;
72432144Sminshall     char *name;
72532144Sminshall     struct togglelist *c;
72632144Sminshall 
72732144Sminshall     if (argc < 2) {
72832144Sminshall 	fprintf(stderr,
72932144Sminshall 	    "Need an argument to 'toggle' command.  'toggle ?' for help.\n");
73032144Sminshall 	return 0;
73132144Sminshall     }
73232144Sminshall     argc--;
73332144Sminshall     argv++;
73432144Sminshall     while (argc--) {
73532144Sminshall 	name = *argv++;
73646808Sdab 	c = GETTOGGLE(name);
73732144Sminshall 	if (Ambiguous(c)) {
73832144Sminshall 	    fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n",
73932144Sminshall 					name);
74032144Sminshall 	    return 0;
74132144Sminshall 	} else if (c == 0) {
74232144Sminshall 	    fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n",
74332144Sminshall 					name);
74432144Sminshall 	    return 0;
74532144Sminshall 	} else {
74632144Sminshall 	    if (c->variable) {
74732144Sminshall 		*c->variable = !*c->variable;		/* invert it */
74832144Sminshall 		if (c->actionexplanation) {
74932144Sminshall 		    printf("%s %s.\n", *c->variable? "Will" : "Won't",
75032144Sminshall 							c->actionexplanation);
75132144Sminshall 		}
75232144Sminshall 	    }
75332144Sminshall 	    if (c->handler) {
75438689Sborman 		retval &= (*c->handler)(-1);
75532144Sminshall 	    }
75632144Sminshall 	}
75732144Sminshall     }
75832144Sminshall     return retval;
75932144Sminshall }
76032144Sminshall 
76132144Sminshall /*
76232144Sminshall  * The following perform the "set" command.
76332144Sminshall  */
76432144Sminshall 
76538689Sborman #ifdef	USE_TERMIO
76638689Sborman struct termio new_tc = { 0 };
76738689Sborman #endif
76838689Sborman 
76932144Sminshall struct setlist {
77032144Sminshall     char *name;				/* name */
77132144Sminshall     char *help;				/* help information */
77238689Sborman     void (*handler)();
77340245Sborman     cc_t *charp;			/* where it is located at */
77432144Sminshall };
77532144Sminshall 
77632144Sminshall static struct setlist Setlist[] = {
77744361Sborman #ifdef	KLUDGELINEMODE
77838689Sborman     { "echo", 	"character to toggle local echoing on/off", 0, &echoc },
77944361Sborman #endif
78038689Sborman     { "escape",	"character to escape back to telnet command mode", 0, &escape },
78146808Sdab     { "rlogin", "rlogin escape character", 0, &rlogin },
78245233Sborman     { "tracefile", "file to write trace information to", SetNetTrace, (cc_t *)NetTraceFile},
78332144Sminshall     { " ", "" },
78438689Sborman     { " ", "The following need 'localchars' to be toggled true", 0, 0 },
78545233Sborman     { "flushoutput", "character to cause an Abort Output", 0, termFlushCharp },
78638689Sborman     { "interrupt", "character to cause an Interrupt Process", 0, termIntCharp },
78738689Sborman     { "quit",	"character to cause an Abort process", 0, termQuitCharp },
78838689Sborman     { "eof",	"character to cause an EOF ", 0, termEofCharp },
78938689Sborman     { " ", "" },
79038689Sborman     { " ", "The following are for local editing in linemode", 0, 0 },
79138689Sborman     { "erase",	"character to use to erase a character", 0, termEraseCharp },
79238689Sborman     { "kill",	"character to use to erase a line", 0, termKillCharp },
79338689Sborman     { "lnext",	"character to use for literal next", 0, termLiteralNextCharp },
79444361Sborman     { "susp",	"character to cause a Suspend Process", 0, termSuspCharp },
79538689Sborman     { "reprint", "character to use for line reprint", 0, termRprntCharp },
79638689Sborman     { "worderase", "character to use to erase a word", 0, termWerasCharp },
79738689Sborman     { "start",	"character to use for XON", 0, termStartCharp },
79844361Sborman     { "stop",	"character to use for XOFF", 0, termStopCharp },
79944361Sborman     { "forw1",	"alternate end of line character", 0, termForw1Charp },
80044361Sborman     { "forw2",	"alternate end of line character", 0, termForw2Charp },
80145233Sborman     { "ayt",	"alternate AYT character", 0, termAytCharp },
80232144Sminshall     { 0 }
80332144Sminshall };
80432144Sminshall 
80545233Sborman #if	defined(CRAY) && !defined(__STDC__)
80645233Sborman /* Work around compiler bug in pcc 4.1.5 */
80746808Sdab     void
80838689Sborman _setlist_init()
80938689Sborman {
81044361Sborman #ifndef	KLUDGELINEMODE
81146808Sdab #define	N 5
81244361Sborman #else
81346808Sdab #define	N 6
81444361Sborman #endif
81544361Sborman 	Setlist[N+0].charp = &termFlushChar;
81644361Sborman 	Setlist[N+1].charp = &termIntChar;
81744361Sborman 	Setlist[N+2].charp = &termQuitChar;
81844361Sborman 	Setlist[N+3].charp = &termEofChar;
81944361Sborman 	Setlist[N+6].charp = &termEraseChar;
82044361Sborman 	Setlist[N+7].charp = &termKillChar;
82144361Sborman 	Setlist[N+8].charp = &termLiteralNextChar;
82244361Sborman 	Setlist[N+9].charp = &termSuspChar;
82344361Sborman 	Setlist[N+10].charp = &termRprntChar;
82444361Sborman 	Setlist[N+11].charp = &termWerasChar;
82544361Sborman 	Setlist[N+12].charp = &termStartChar;
82644361Sborman 	Setlist[N+13].charp = &termStopChar;
82744361Sborman 	Setlist[N+14].charp = &termForw1Char;
82844361Sborman 	Setlist[N+15].charp = &termForw2Char;
82945233Sborman 	Setlist[N+16].charp = &termAytChar;
83044361Sborman #undef	N
83138689Sborman }
83245233Sborman #endif	/* defined(CRAY) && !defined(__STDC__) */
83338689Sborman 
83446808Sdab     static struct setlist *
83532144Sminshall getset(name)
83646808Sdab     char *name;
83732144Sminshall {
83846808Sdab     return (struct setlist *)
83946808Sdab 		genget(name, (char **) Setlist, sizeof(struct setlist));
84032144Sminshall }
84132144Sminshall 
84246808Sdab     void
84344361Sborman set_escape_char(s)
84446808Sdab     char *s;
84544361Sborman {
84646808Sdab 	if (rlogin != _POSIX_VDISABLE) {
84746808Sdab 		rlogin = (s && *s) ? special(s) : _POSIX_VDISABLE;
84846808Sdab 		printf("Telnet rlogin escape character is '%s'.\n",
84946808Sdab 					control(rlogin));
85046808Sdab 	} else {
85146808Sdab 		escape = (s && *s) ? special(s) : _POSIX_VDISABLE;
85246808Sdab 		printf("Telnet escape character is '%s'.\n", control(escape));
85346808Sdab 	}
85444361Sborman }
85544361Sborman 
85646808Sdab     static int
85732144Sminshall setcmd(argc, argv)
85846808Sdab     int  argc;
85946808Sdab     char *argv[];
86032144Sminshall {
86132144Sminshall     int value;
86232144Sminshall     struct setlist *ct;
86338689Sborman     struct togglelist *c;
86432144Sminshall 
86538689Sborman     if (argc < 2 || argc > 3) {
86638689Sborman 	printf("Format is 'set Name Value'\n'set ?' for help.\n");
86732144Sminshall 	return 0;
86832144Sminshall     }
86946808Sdab     if ((argc == 2) && (isprefix(argv[1], "?") || isprefix(argv[1], "help"))) {
87038689Sborman 	for (ct = Setlist; ct->name; ct++)
87138689Sborman 	    printf("%-15s %s\n", ct->name, ct->help);
87238689Sborman 	printf("\n");
87338689Sborman 	settogglehelp(1);
87438689Sborman 	printf("%-15s %s\n", "?", "display help information");
87538689Sborman 	return 0;
87638689Sborman     }
87732144Sminshall 
87832144Sminshall     ct = getset(argv[1]);
87932144Sminshall     if (ct == 0) {
88046808Sdab 	c = GETTOGGLE(argv[1]);
88138689Sborman 	if (c == 0) {
88238689Sborman 	    fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n",
88332144Sminshall 			argv[1]);
88438689Sborman 	    return 0;
88538689Sborman 	} else if (Ambiguous(c)) {
88638689Sborman 	    fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
88738689Sborman 			argv[1]);
88838689Sborman 	    return 0;
88938689Sborman 	}
89038689Sborman 	if (c->variable) {
89138689Sborman 	    if ((argc == 2) || (strcmp("on", argv[2]) == 0))
89238689Sborman 		*c->variable = 1;
89338689Sborman 	    else if (strcmp("off", argv[2]) == 0)
89438689Sborman 		*c->variable = 0;
89538689Sborman 	    else {
89638689Sborman 		printf("Format is 'set togglename [on|off]'\n'set ?' for help.\n");
89738689Sborman 		return 0;
89838689Sborman 	    }
89938689Sborman 	    if (c->actionexplanation) {
90038689Sborman 		printf("%s %s.\n", *c->variable? "Will" : "Won't",
90138689Sborman 							c->actionexplanation);
90238689Sborman 	    }
90338689Sborman 	}
90438689Sborman 	if (c->handler)
90538689Sborman 	    (*c->handler)(1);
90638689Sborman     } else if (argc != 3) {
90738689Sborman 	printf("Format is 'set Name Value'\n'set ?' for help.\n");
90832144Sminshall 	return 0;
90932144Sminshall     } else if (Ambiguous(ct)) {
91032144Sminshall 	fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
91132144Sminshall 			argv[1]);
91232144Sminshall 	return 0;
91338689Sborman     } else if (ct->handler) {
91438689Sborman 	(*ct->handler)(argv[2]);
91544361Sborman 	printf("%s set to \"%s\".\n", ct->name, (char *)ct->charp);
91632144Sminshall     } else {
91732144Sminshall 	if (strcmp("off", argv[2])) {
91832144Sminshall 	    value = special(argv[2]);
91932144Sminshall 	} else {
92045233Sborman 	    value = _POSIX_VDISABLE;
92132144Sminshall 	}
92240245Sborman 	*(ct->charp) = (cc_t)value;
92332144Sminshall 	printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
92432144Sminshall     }
92538689Sborman     slc_check();
92632144Sminshall     return 1;
92732144Sminshall }
92838689Sborman 
92946808Sdab     static int
93038689Sborman unsetcmd(argc, argv)
93146808Sdab     int  argc;
93246808Sdab     char *argv[];
93338689Sborman {
93438689Sborman     struct setlist *ct;
93538689Sborman     struct togglelist *c;
93638689Sborman     register char *name;
93738689Sborman 
93838689Sborman     if (argc < 2) {
93938689Sborman 	fprintf(stderr,
94038689Sborman 	    "Need an argument to 'unset' command.  'unset ?' for help.\n");
94138689Sborman 	return 0;
94238689Sborman     }
94346808Sdab     if (isprefix(argv[1], "?") || isprefix(argv[1], "help")) {
94438689Sborman 	for (ct = Setlist; ct->name; ct++)
94538689Sborman 	    printf("%-15s %s\n", ct->name, ct->help);
94638689Sborman 	printf("\n");
94738689Sborman 	settogglehelp(0);
94838689Sborman 	printf("%-15s %s\n", "?", "display help information");
94938689Sborman 	return 0;
95038689Sborman     }
95138689Sborman 
95238689Sborman     argc--;
95338689Sborman     argv++;
95438689Sborman     while (argc--) {
95538689Sborman 	name = *argv++;
95638689Sborman 	ct = getset(name);
95738689Sborman 	if (ct == 0) {
95846808Sdab 	    c = GETTOGGLE(name);
95938689Sborman 	    if (c == 0) {
96038689Sborman 		fprintf(stderr, "'%s': unknown argument ('unset ?' for help).\n",
96138689Sborman 			name);
96238689Sborman 		return 0;
96338689Sborman 	    } else if (Ambiguous(c)) {
96438689Sborman 		fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n",
96538689Sborman 			name);
96638689Sborman 		return 0;
96738689Sborman 	    }
96838689Sborman 	    if (c->variable) {
96938689Sborman 		*c->variable = 0;
97038689Sborman 		if (c->actionexplanation) {
97138689Sborman 		    printf("%s %s.\n", *c->variable? "Will" : "Won't",
97238689Sborman 							c->actionexplanation);
97338689Sborman 		}
97438689Sborman 	    }
97538689Sborman 	    if (c->handler)
97638689Sborman 		(*c->handler)(0);
97738689Sborman 	} else if (Ambiguous(ct)) {
97838689Sborman 	    fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n",
97938689Sborman 			name);
98038689Sborman 	    return 0;
98138689Sborman 	} else if (ct->handler) {
98238689Sborman 	    (*ct->handler)(0);
98344361Sborman 	    printf("%s reset to \"%s\".\n", ct->name, (char *)ct->charp);
98438689Sborman 	} else {
98545233Sborman 	    *(ct->charp) = _POSIX_VDISABLE;
98638689Sborman 	    printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
98738689Sborman 	}
98838689Sborman     }
98938689Sborman     return 1;
99038689Sborman }
99132144Sminshall 
99232144Sminshall /*
99332144Sminshall  * The following are the data structures and routines for the
99432144Sminshall  * 'mode' command.
99532144Sminshall  */
99638689Sborman #ifdef	KLUDGELINEMODE
99738689Sborman extern int kludgelinemode;
99844361Sborman 
99946808Sdab     static int
100044361Sborman dokludgemode()
100144361Sborman {
100244361Sborman     kludgelinemode = 1;
100344361Sborman     send_wont(TELOPT_LINEMODE, 1);
100444361Sborman     send_dont(TELOPT_SGA, 1);
100544361Sborman     send_dont(TELOPT_ECHO, 1);
100644361Sborman }
100738689Sborman #endif
100832144Sminshall 
100946808Sdab     static int
101032144Sminshall dolinemode()
101132144Sminshall {
101238689Sborman #ifdef	KLUDGELINEMODE
101338689Sborman     if (kludgelinemode)
101438689Sborman 	send_dont(TELOPT_SGA, 1);
101538689Sborman #endif
101638689Sborman     send_will(TELOPT_LINEMODE, 1);
101738689Sborman     send_dont(TELOPT_ECHO, 1);
101832144Sminshall     return 1;
101932144Sminshall }
102032144Sminshall 
102146808Sdab     static int
102232144Sminshall docharmode()
102332144Sminshall {
102438689Sborman #ifdef	KLUDGELINEMODE
102538689Sborman     if (kludgelinemode)
102638689Sborman 	send_do(TELOPT_SGA, 1);
102738689Sborman     else
102838689Sborman #endif
102938689Sborman     send_wont(TELOPT_LINEMODE, 1);
103038689Sborman     send_do(TELOPT_ECHO, 1);
103138689Sborman     return 1;
103238689Sborman }
103338689Sborman 
103446808Sdab     static int
103538689Sborman dolmmode(bit, on)
103646808Sdab     int bit, on;
103738689Sborman {
103846808Sdab     unsigned char c;
103938689Sborman     extern int linemode;
104038689Sborman 
104138689Sborman     if (my_want_state_is_wont(TELOPT_LINEMODE)) {
104238689Sborman 	printf("?Need to have LINEMODE option enabled first.\n");
104338689Sborman 	printf("'mode ?' for help.\n");
104438689Sborman 	return 0;
104532144Sminshall     }
104638689Sborman 
104738689Sborman     if (on)
104838689Sborman 	c = (linemode | bit);
104938689Sborman     else
105038689Sborman 	c = (linemode & ~bit);
105138689Sborman     lm_mode(&c, 1, 1);
105232144Sminshall     return 1;
105332144Sminshall }
105432144Sminshall 
105546808Sdab     int
105646808Sdab setmode(bit)
105746808Sdab {
105846808Sdab     return dolmmode(bit, 1);
105946808Sdab }
106046808Sdab 
106146808Sdab     int
106246808Sdab clearmode(bit)
106346808Sdab {
106446808Sdab     return dolmmode(bit, 0);
106546808Sdab }
106646808Sdab 
106738689Sborman struct modelist {
106838689Sborman 	char	*name;		/* command name */
106938689Sborman 	char	*help;		/* help string */
107038689Sborman 	int	(*handler)();	/* routine which executes command */
107138689Sborman 	int	needconnect;	/* Do we need to be connected to execute? */
107238689Sborman 	int	arg1;
107338689Sborman };
107438689Sborman 
107538689Sborman extern int modehelp();
107638689Sborman 
107738689Sborman static struct modelist ModeList[] = {
107838689Sborman     { "character", "Disable LINEMODE option",	docharmode, 1 },
107939529Sborman #ifdef	KLUDGELINEMODE
108039529Sborman     { "",	"(or disable obsolete line-by-line mode)", 0 },
108138689Sborman #endif
108238689Sborman     { "line",	"Enable LINEMODE option",	dolinemode, 1 },
108339529Sborman #ifdef	KLUDGELINEMODE
108439529Sborman     { "",	"(or enable obsolete line-by-line mode)", 0 },
108538689Sborman #endif
108638689Sborman     { "", "", 0 },
108738689Sborman     { "",	"These require the LINEMODE option to be enabled", 0 },
108838689Sborman     { "isig",	"Enable signal trapping",	setmode, 1, MODE_TRAPSIG },
108938689Sborman     { "+isig",	0,				setmode, 1, MODE_TRAPSIG },
109038689Sborman     { "-isig",	"Disable signal trapping",	clearmode, 1, MODE_TRAPSIG },
109138689Sborman     { "edit",	"Enable character editing",	setmode, 1, MODE_EDIT },
109238689Sborman     { "+edit",	0,				setmode, 1, MODE_EDIT },
109338689Sborman     { "-edit",	"Disable character editing",	clearmode, 1, MODE_EDIT },
109444361Sborman     { "softtabs", "Enable tab expansion",	setmode, 1, MODE_SOFT_TAB },
109544361Sborman     { "+softtabs", 0,				setmode, 1, MODE_SOFT_TAB },
109644361Sborman     { "-softtabs", "Disable character editing",	clearmode, 1, MODE_SOFT_TAB },
109744361Sborman     { "litecho", "Enable literal character echo", setmode, 1, MODE_LIT_ECHO },
109844361Sborman     { "+litecho", 0,				setmode, 1, MODE_LIT_ECHO },
109944361Sborman     { "-litecho", "Disable literal character echo", clearmode, 1, MODE_LIT_ECHO },
110038689Sborman     { "help",	0,				modehelp, 0 },
110144361Sborman #ifdef	KLUDGELINEMODE
110244361Sborman     { "kludgeline", 0,				dokludgemode, 1 },
110344361Sborman #endif
110444361Sborman     { "", "", 0 },
110538689Sborman     { "?",	"Print help information",	modehelp, 0 },
110632144Sminshall     { 0 },
110732144Sminshall };
110832144Sminshall 
110932144Sminshall 
111046808Sdab     int
111138689Sborman modehelp()
111238689Sborman {
111338689Sborman     struct modelist *mt;
111438689Sborman 
111538689Sborman     printf("format is:  'mode Mode', where 'Mode' is one of:\n\n");
111638689Sborman     for (mt = ModeList; mt->name; mt++) {
111738689Sborman 	if (mt->help) {
111838689Sborman 	    if (*mt->help)
111938689Sborman 		printf("%-15s %s\n", mt->name, mt->help);
112038689Sborman 	    else
112138689Sborman 		printf("\n");
112238689Sborman 	}
112338689Sborman     }
112438689Sborman     return 0;
112538689Sborman }
112638689Sborman 
112746808Sdab #define	GETMODECMD(name) (struct modelist *) \
112846808Sdab 		genget(name, (char **) ModeList, sizeof(struct modelist))
112946808Sdab 
113046808Sdab     static int
113132144Sminshall modecmd(argc, argv)
113246808Sdab     int  argc;
113346808Sdab     char *argv[];
113432144Sminshall {
113538689Sborman     struct modelist *mt;
113632144Sminshall 
113738689Sborman     if (argc != 2) {
113838689Sborman 	printf("'mode' command requires an argument\n");
113938689Sborman 	printf("'mode ?' for help.\n");
114046808Sdab     } else if ((mt = GETMODECMD(argv[1])) == 0) {
114132144Sminshall 	fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]);
114232144Sminshall     } else if (Ambiguous(mt)) {
114332144Sminshall 	fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]);
114438689Sborman     } else if (mt->needconnect && !connected) {
114538689Sborman 	printf("?Need to be connected first.\n");
114638689Sborman 	printf("'mode ?' for help.\n");
114738689Sborman     } else if (mt->handler) {
114838689Sborman 	return (*mt->handler)(mt->arg1);
114932144Sminshall     }
115038689Sborman     return 0;
115132144Sminshall }
115232144Sminshall 
115332144Sminshall /*
115432144Sminshall  * The following data structures and routines implement the
115532144Sminshall  * "display" command.
115632144Sminshall  */
115732144Sminshall 
115846808Sdab     static int
115932144Sminshall display(argc, argv)
116046808Sdab     int  argc;
116146808Sdab     char *argv[];
116232144Sminshall {
116346808Sdab     struct togglelist *tl;
116446808Sdab     struct setlist *sl;
116546808Sdab 
116632144Sminshall #define	dotog(tl)	if (tl->variable && tl->actionexplanation) { \
116732144Sminshall 			    if (*tl->variable) { \
116832144Sminshall 				printf("will"); \
116932144Sminshall 			    } else { \
117032144Sminshall 				printf("won't"); \
117132144Sminshall 			    } \
117232144Sminshall 			    printf(" %s.\n", tl->actionexplanation); \
117332144Sminshall 			}
117432144Sminshall 
117532144Sminshall #define	doset(sl)   if (sl->name && *sl->name != ' ') { \
117638689Sborman 			if (sl->handler == 0) \
117738689Sborman 			    printf("%-15s [%s]\n", sl->name, control(*sl->charp)); \
117838689Sborman 			else \
117944361Sborman 			    printf("%-15s \"%s\"\n", sl->name, (char *)sl->charp); \
118032144Sminshall 		    }
118132144Sminshall 
118232144Sminshall     if (argc == 1) {
118332144Sminshall 	for (tl = Togglelist; tl->name; tl++) {
118432144Sminshall 	    dotog(tl);
118532144Sminshall 	}
118632144Sminshall 	printf("\n");
118732144Sminshall 	for (sl = Setlist; sl->name; sl++) {
118832144Sminshall 	    doset(sl);
118932144Sminshall 	}
119032144Sminshall     } else {
119132144Sminshall 	int i;
119232144Sminshall 
119332144Sminshall 	for (i = 1; i < argc; i++) {
119432144Sminshall 	    sl = getset(argv[i]);
119546808Sdab 	    tl = GETTOGGLE(argv[i]);
119632144Sminshall 	    if (Ambiguous(sl) || Ambiguous(tl)) {
119732144Sminshall 		printf("?Ambiguous argument '%s'.\n", argv[i]);
119832144Sminshall 		return 0;
119932144Sminshall 	    } else if (!sl && !tl) {
120032144Sminshall 		printf("?Unknown argument '%s'.\n", argv[i]);
120132144Sminshall 		return 0;
120232144Sminshall 	    } else {
120332144Sminshall 		if (tl) {
120432144Sminshall 		    dotog(tl);
120532144Sminshall 		}
120632144Sminshall 		if (sl) {
120732144Sminshall 		    doset(sl);
120832144Sminshall 		}
120932144Sminshall 	    }
121032144Sminshall 	}
121132144Sminshall     }
121238689Sborman /*@*/optionstatus();
121346808Sdab #if	defined(ENCRYPT)
121446808Sdab     EncryptStatus();
121546808Sdab #endif
121632144Sminshall     return 1;
121732144Sminshall #undef	doset
121832144Sminshall #undef	dotog
121932144Sminshall }
122032144Sminshall 
122132144Sminshall /*
122232144Sminshall  * The following are the data structures, and many of the routines,
122332144Sminshall  * relating to command processing.
122432144Sminshall  */
122532144Sminshall 
122632144Sminshall /*
122732144Sminshall  * Set the escape character.
122832144Sminshall  */
122946808Sdab 	static int
123032144Sminshall setescape(argc, argv)
123132144Sminshall 	int argc;
123232144Sminshall 	char *argv[];
123332144Sminshall {
123432144Sminshall 	register char *arg;
123532144Sminshall 	char buf[50];
123632144Sminshall 
123732144Sminshall 	printf(
123832144Sminshall 	    "Deprecated usage - please use 'set escape%s%s' in the future.\n",
123932144Sminshall 				(argc > 2)? " ":"", (argc > 2)? argv[1]: "");
124032144Sminshall 	if (argc > 2)
124132144Sminshall 		arg = argv[1];
124232144Sminshall 	else {
124332144Sminshall 		printf("new escape character: ");
124446808Sdab 		(void) fgets(buf, sizeof(buf), stdin);
124532144Sminshall 		arg = buf;
124632144Sminshall 	}
124732144Sminshall 	if (arg[0] != '\0')
124832144Sminshall 		escape = arg[0];
124932144Sminshall 	if (!In3270) {
125032144Sminshall 		printf("Escape character is '%s'.\n", control(escape));
125132144Sminshall 	}
125234849Sminshall 	(void) fflush(stdout);
125332144Sminshall 	return 1;
125432144Sminshall }
125532144Sminshall 
125646808Sdab     /*VARARGS*/
125746808Sdab     static int
125832144Sminshall togcrmod()
125932144Sminshall {
126032144Sminshall     crmod = !crmod;
126132144Sminshall     printf("Deprecated usage - please use 'toggle crmod' in the future.\n");
126232144Sminshall     printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't");
126334849Sminshall     (void) fflush(stdout);
126432144Sminshall     return 1;
126532144Sminshall }
126632144Sminshall 
126746808Sdab     /*VARARGS*/
126846808Sdab     int
126932144Sminshall suspend()
127032144Sminshall {
127138689Sborman #ifdef	SIGTSTP
127237219Sminshall     setcommandmode();
127337219Sminshall     {
127444361Sborman 	long oldrows, oldcols, newrows, newcols, err;
127537219Sminshall 
127644361Sborman 	err = TerminalWindowSize(&oldrows, &oldcols);
127734849Sminshall 	(void) kill(0, SIGTSTP);
127844361Sborman 	err += TerminalWindowSize(&newrows, &newcols);
127944361Sborman 	if (connected && !err &&
128044361Sborman 	    ((oldrows != newrows) || (oldcols != newcols))) {
128137219Sminshall 		sendnaws();
128237219Sminshall 	}
128337219Sminshall     }
128437219Sminshall     /* reget parameters in case they were changed */
128537219Sminshall     TerminalSaveState();
128638689Sborman     setconnmode(0);
128738689Sborman #else
128838689Sborman     printf("Suspend is not supported.  Try the '!' command instead\n");
128938689Sborman #endif
129037219Sminshall     return 1;
129132144Sminshall }
129232144Sminshall 
129338689Sborman #if	!defined(TN3270)
129446808Sdab     /*ARGSUSED*/
129546808Sdab     int
129638689Sborman shell(argc, argv)
129746808Sdab     int argc;
129846808Sdab     char *argv[];
129938689Sborman {
130038689Sborman     setcommandmode();
130138689Sborman     switch(vfork()) {
130238689Sborman     case -1:
130338689Sborman 	perror("Fork failed\n");
130438689Sborman 	break;
130538689Sborman 
130638689Sborman     case 0:
130738689Sborman 	{
130838689Sborman 	    /*
130938689Sborman 	     * Fire up the shell in the child.
131038689Sborman 	     */
131146808Sdab 	    register char *shellp, *shellname;
131246808Sdab 	    extern char *rindex();
131338689Sborman 
131446808Sdab 	    shellp = getenv("SHELL");
131546808Sdab 	    if (shellp == NULL)
131646808Sdab 		shellp = "/bin/sh";
131746808Sdab 	    if ((shellname = rindex(shellp, '/')) == 0)
131846808Sdab 		shellname = shellp;
131938689Sborman 	    else
132038689Sborman 		shellname++;
132138689Sborman 	    if (argc > 1)
132246808Sdab 		execl(shellp, shellname, "-c", &saveline[1], 0);
132338689Sborman 	    else
132446808Sdab 		execl(shellp, shellname, 0);
132538689Sborman 	    perror("Execl");
132638689Sborman 	    _exit(1);
132738689Sborman 	}
132838689Sborman     default:
132944361Sborman 	    (void)wait((int *)0);	/* Wait for the shell to complete */
133038689Sborman     }
133146808Sdab     return 1;
133238689Sborman }
133338689Sborman #endif	/* !defined(TN3270) */
133438689Sborman 
133546808Sdab     /*VARARGS*/
133646808Sdab     static
133732144Sminshall bye(argc, argv)
133846808Sdab     int  argc;		/* Number of arguments */
133946808Sdab     char *argv[];	/* arguments */
134032144Sminshall {
134146808Sdab     extern int resettermname;
134246808Sdab 
134332144Sminshall     if (connected) {
134434849Sminshall 	(void) shutdown(net, 2);
134532144Sminshall 	printf("Connection closed.\n");
134634849Sminshall 	(void) NetClose(net);
134732144Sminshall 	connected = 0;
134846808Sdab 	resettermname = 1;
134946808Sdab #if	defined(AUTHENTICATE) || defined(ENCRYPT)
135046808Sdab 	auth_encrypt_connect(connected);
135146808Sdab #endif
135232144Sminshall 	/* reset options */
135332144Sminshall 	tninit();
135432144Sminshall #if	defined(TN3270)
135532144Sminshall 	SetIn3270();		/* Get out of 3270 mode */
135632144Sminshall #endif	/* defined(TN3270) */
135732144Sminshall     }
135832144Sminshall     if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) {
135932144Sminshall 	longjmp(toplevel, 1);
136032144Sminshall 	/* NOTREACHED */
136132144Sminshall     }
136232144Sminshall     return 1;			/* Keep lint, etc., happy */
136332144Sminshall }
136432144Sminshall 
136532144Sminshall /*VARARGS*/
136632144Sminshall quit()
136732144Sminshall {
136832144Sminshall 	(void) call(bye, "bye", "fromquit", 0);
136932144Sminshall 	Exit(0);
137044361Sborman 	/*NOTREACHED*/
137132144Sminshall }
137246808Sdab 
137346808Sdab /*VARARGS*/
137446808Sdab 	int
137546808Sdab logout()
137646808Sdab {
137746808Sdab 	send_do(TELOPT_LOGOUT, 1);
137846808Sdab 	(void) netflush();
137946808Sdab 	return 1;
138046808Sdab }
138146808Sdab 
138238689Sborman 
138338689Sborman /*
138438689Sborman  * The SLC command.
138538689Sborman  */
138632144Sminshall 
138738689Sborman struct slclist {
138838689Sborman 	char	*name;
138938689Sborman 	char	*help;
139046808Sdab 	void	(*handler)();
139138689Sborman 	int	arg;
139238689Sborman };
139338689Sborman 
139446808Sdab extern void slc_help();
139538689Sborman 
139638689Sborman struct slclist SlcList[] = {
139738689Sborman     { "export",	"Use local special character definitions",
139838689Sborman 						slc_mode_export,	0 },
139938689Sborman     { "import",	"Use remote special character definitions",
140038689Sborman 						slc_mode_import,	1 },
140138689Sborman     { "check",	"Verify remote special character definitions",
140238689Sborman 						slc_mode_import,	0 },
140338689Sborman     { "help",	0,				slc_help,		0 },
140438689Sborman     { "?",	"Print help information",	slc_help,		0 },
140538689Sborman     { 0 },
140638689Sborman };
140738689Sborman 
140846808Sdab     static void
140938689Sborman slc_help()
141038689Sborman {
141138689Sborman     struct slclist *c;
141238689Sborman 
141338689Sborman     for (c = SlcList; c->name; c++) {
141438689Sborman 	if (c->help) {
141538689Sborman 	    if (*c->help)
141638689Sborman 		printf("%-15s %s\n", c->name, c->help);
141738689Sborman 	    else
141838689Sborman 		printf("\n");
141938689Sborman 	}
142038689Sborman     }
142138689Sborman }
142238689Sborman 
142346808Sdab     static struct slclist *
142438689Sborman getslc(name)
142546808Sdab     char *name;
142638689Sborman {
142746808Sdab     return (struct slclist *)
142846808Sdab 		genget(name, (char **) SlcList, sizeof(struct slclist));
142938689Sborman }
143038689Sborman 
143146808Sdab     static
143238689Sborman slccmd(argc, argv)
143346808Sdab     int  argc;
143446808Sdab     char *argv[];
143538689Sborman {
143638689Sborman     struct slclist *c;
143738689Sborman 
143838689Sborman     if (argc != 2) {
143938689Sborman 	fprintf(stderr,
144038689Sborman 	    "Need an argument to 'slc' command.  'slc ?' for help.\n");
144138689Sborman 	return 0;
144238689Sborman     }
144338689Sborman     c = getslc(argv[1]);
144438689Sborman     if (c == 0) {
144538689Sborman         fprintf(stderr, "'%s': unknown argument ('slc ?' for help).\n",
144638689Sborman     				argv[1]);
144738689Sborman         return 0;
144838689Sborman     }
144938689Sborman     if (Ambiguous(c)) {
145038689Sborman         fprintf(stderr, "'%s': ambiguous argument ('slc ?' for help).\n",
145138689Sborman     				argv[1]);
145238689Sborman         return 0;
145338689Sborman     }
145438689Sborman     (*c->handler)(c->arg);
145538689Sborman     slcstate();
145638689Sborman     return 1;
145738689Sborman }
145844361Sborman 
145944361Sborman /*
146044361Sborman  * The ENVIRON command.
146144361Sborman  */
146238689Sborman 
146344361Sborman struct envlist {
146444361Sborman 	char	*name;
146544361Sborman 	char	*help;
146646808Sdab 	void	(*handler)();
146744361Sborman 	int	narg;
146844361Sborman };
146944361Sborman 
147046808Sdab extern struct env_lst *
147146808Sdab 	env_define P((unsigned char *, unsigned char *));
147246808Sdab extern void
147346808Sdab 	env_undefine P((unsigned char *)),
147446808Sdab 	env_export P((unsigned char *)),
147546808Sdab 	env_unexport P((unsigned char *)),
147646808Sdab 	env_send P((unsigned char *)),
147746808Sdab 	env_list P((void)),
147846808Sdab 	env_help P((void));
147944361Sborman 
148044361Sborman struct envlist EnvList[] = {
148144361Sborman     { "define",	"Define an environment variable",
148246808Sdab 						(void (*)())env_define,	2 },
148344361Sborman     { "undefine", "Undefine an environment variable",
148444361Sborman 						env_undefine,	1 },
148544361Sborman     { "export",	"Mark an environment variable for automatic export",
148644361Sborman 						env_export,	1 },
148746808Sdab     { "unexport", "Don't mark an environment variable for automatic export",
148844361Sborman 						env_unexport,	1 },
148945233Sborman     { "send",	"Send an environment variable", env_send,	1 },
149044361Sborman     { "list",	"List the current environment variables",
149144361Sborman 						env_list,	0 },
149244361Sborman     { "help",	0,				env_help,		0 },
149344361Sborman     { "?",	"Print help information",	env_help,		0 },
149444361Sborman     { 0 },
149544361Sborman };
149644361Sborman 
149746808Sdab     static void
149844361Sborman env_help()
149944361Sborman {
150044361Sborman     struct envlist *c;
150144361Sborman 
150244361Sborman     for (c = EnvList; c->name; c++) {
150344361Sborman 	if (c->help) {
150444361Sborman 	    if (*c->help)
150544361Sborman 		printf("%-15s %s\n", c->name, c->help);
150644361Sborman 	    else
150744361Sborman 		printf("\n");
150844361Sborman 	}
150944361Sborman     }
151044361Sborman }
151144361Sborman 
151246808Sdab     static struct envlist *
151344361Sborman getenvcmd(name)
151446808Sdab     char *name;
151544361Sborman {
151646808Sdab     return (struct envlist *)
151746808Sdab 		genget(name, (char **) EnvList, sizeof(struct envlist));
151844361Sborman }
151944361Sborman 
152044361Sborman env_cmd(argc, argv)
152146808Sdab     int  argc;
152246808Sdab     char *argv[];
152344361Sborman {
152444361Sborman     struct envlist *c;
152544361Sborman 
152644361Sborman     if (argc < 2) {
152744361Sborman 	fprintf(stderr,
152844361Sborman 	    "Need an argument to 'environ' command.  'environ ?' for help.\n");
152944361Sborman 	return 0;
153044361Sborman     }
153144361Sborman     c = getenvcmd(argv[1]);
153244361Sborman     if (c == 0) {
153344361Sborman         fprintf(stderr, "'%s': unknown argument ('environ ?' for help).\n",
153444361Sborman     				argv[1]);
153544361Sborman         return 0;
153644361Sborman     }
153744361Sborman     if (Ambiguous(c)) {
153844361Sborman         fprintf(stderr, "'%s': ambiguous argument ('environ ?' for help).\n",
153944361Sborman     				argv[1]);
154044361Sborman         return 0;
154144361Sborman     }
154244361Sborman     if (c->narg + 2 != argc) {
154344361Sborman 	fprintf(stderr,
154444361Sborman 	    "Need %s%d argument%s to 'environ %s' command.  'environ ?' for help.\n",
154544361Sborman 		c->narg < argc + 2 ? "only " : "",
154644361Sborman 		c->narg, c->narg == 1 ? "" : "s", c->name);
154744361Sborman 	return 0;
154844361Sborman     }
154946808Sdab     (*c->handler)(argv[2], argv[3]);
155044361Sborman     return 1;
155144361Sborman }
155244361Sborman 
155344361Sborman struct env_lst {
155444361Sborman 	struct env_lst *next;	/* pointer to next structure */
155544361Sborman 	struct env_lst *prev;	/* pointer to next structure */
155646808Sdab 	unsigned char *var;	/* pointer to variable name */
155746808Sdab 	unsigned char *value;	/* pointer to varialbe value */
155844361Sborman 	int export;		/* 1 -> export with default list of variables */
155944361Sborman };
156044361Sborman 
156144361Sborman struct env_lst envlisthead;
156244361Sborman 
156346808Sdab 	struct env_lst *
156444361Sborman env_find(var)
156546808Sdab 	unsigned char *var;
156644361Sborman {
156744361Sborman 	register struct env_lst *ep;
156844361Sborman 
156944361Sborman 	for (ep = envlisthead.next; ep; ep = ep->next) {
157046808Sdab 		if (strcmp((char *)ep->var, (char *)var) == 0)
157144361Sborman 			return(ep);
157244361Sborman 	}
157344361Sborman 	return(NULL);
157444361Sborman }
157544361Sborman 
157646808Sdab 	void
157744361Sborman env_init()
157844361Sborman {
157946808Sdab 	extern char **environ;
158044361Sborman 	register char **epp, *cp;
158144361Sborman 	register struct env_lst *ep;
158246808Sdab 	extern char *index();
158344361Sborman 
158444361Sborman 	for (epp = environ; *epp; epp++) {
158544361Sborman 		if (cp = index(*epp, '=')) {
158644361Sborman 			*cp = '\0';
158746808Sdab 			ep = env_define((unsigned char *)*epp,
158846808Sdab 					(unsigned char *)cp+1);
158944361Sborman 			ep->export = 0;
159044361Sborman 			*cp = '=';
159144361Sborman 		}
159244361Sborman 	}
159344361Sborman 	/*
159444361Sborman 	 * Special case for DISPLAY variable.  If it is ":0.0" or
159544361Sborman 	 * "unix:0.0", we have to get rid of "unix" and insert our
159644361Sborman 	 * hostname.
159744361Sborman 	 */
159846808Sdab 	if ((ep = env_find("DISPLAY"))
159946808Sdab 	    && ((*ep->value == ':')
160046808Sdab 	        || (strncmp((char *)ep->value, "unix:", 5) == 0))) {
160144361Sborman 		char hbuf[256+1];
160246808Sdab 		char *cp2 = index((char *)ep->value, ':');
160344361Sborman 
160444361Sborman 		gethostname(hbuf, 256);
160544361Sborman 		hbuf[256] = '\0';
160644361Sborman 		cp = (char *)malloc(strlen(hbuf) + strlen(cp2) + 1);
160746808Sdab 		sprintf((char *)cp, "%s%s", hbuf, cp2);
160844361Sborman 		free(ep->value);
160946808Sdab 		ep->value = (unsigned char *)cp;
161044361Sborman 	}
161144361Sborman 	/*
161244361Sborman 	 * If USER is not defined, but LOGNAME is, then add
161345233Sborman 	 * USER with the value from LOGNAME.  By default, we
161445233Sborman 	 * don't export the USER variable.
161544361Sborman 	 */
161645233Sborman 	if ((env_find("USER") == NULL) && (ep = env_find("LOGNAME"))) {
161746808Sdab 		env_define((unsigned char *)"USER", ep->value);
161846808Sdab 		env_unexport((unsigned char *)"USER");
161945233Sborman 	}
162046808Sdab 	env_export((unsigned char *)"DISPLAY");
162146808Sdab 	env_export((unsigned char *)"PRINTER");
162244361Sborman }
162344361Sborman 
162446808Sdab 	struct env_lst *
162544361Sborman env_define(var, value)
162646808Sdab 	unsigned char *var, *value;
162744361Sborman {
162844361Sborman 	register struct env_lst *ep;
162944361Sborman 
163044361Sborman 	if (ep = env_find(var)) {
163144361Sborman 		if (ep->var)
163244361Sborman 			free(ep->var);
163344361Sborman 		if (ep->value)
163444361Sborman 			free(ep->value);
163544361Sborman 	} else {
163644361Sborman 		ep = (struct env_lst *)malloc(sizeof(struct env_lst));
163744361Sborman 		ep->next = envlisthead.next;
163844361Sborman 		envlisthead.next = ep;
163944361Sborman 		ep->prev = &envlisthead;
164044361Sborman 		if (ep->next)
164144361Sborman 			ep->next->prev = ep;
164244361Sborman 	}
164345009Skarels 	ep->export = 1;
164446808Sdab 	ep->var = (unsigned char *)strdup((char *)var);
164546808Sdab 	ep->value = (unsigned char *)strdup((char *)value);
164644361Sborman 	return(ep);
164744361Sborman }
164844361Sborman 
164946808Sdab 	void
165044361Sborman env_undefine(var)
165146808Sdab 	unsigned char *var;
165244361Sborman {
165344361Sborman 	register struct env_lst *ep;
165444361Sborman 
165544361Sborman 	if (ep = env_find(var)) {
165644361Sborman 		ep->prev->next = ep->next;
165745233Sborman 		if (ep->next)
165845233Sborman 			ep->next->prev = ep->prev;
165944361Sborman 		if (ep->var)
166044361Sborman 			free(ep->var);
166144361Sborman 		if (ep->value)
166244361Sborman 			free(ep->value);
166344361Sborman 		free(ep);
166444361Sborman 	}
166544361Sborman }
166644361Sborman 
166746808Sdab 	void
166844361Sborman env_export(var)
166946808Sdab 	unsigned char *var;
167044361Sborman {
167144361Sborman 	register struct env_lst *ep;
167244361Sborman 
167344361Sborman 	if (ep = env_find(var))
167444361Sborman 		ep->export = 1;
167544361Sborman }
167644361Sborman 
167746808Sdab 	void
167844361Sborman env_unexport(var)
167946808Sdab 	unsigned char *var;
168044361Sborman {
168144361Sborman 	register struct env_lst *ep;
168244361Sborman 
168344361Sborman 	if (ep = env_find(var))
168444361Sborman 		ep->export = 0;
168544361Sborman }
168644361Sborman 
168746808Sdab 	void
168845233Sborman env_send(var)
168946808Sdab 	unsigned char *var;
169045233Sborman {
169145233Sborman 	register struct env_lst *ep;
169245233Sborman 
169345233Sborman         if (my_state_is_wont(TELOPT_ENVIRON)) {
169445233Sborman 		fprintf(stderr,
169545233Sborman 		    "Cannot send '%s': Telnet ENVIRON option not enabled\n",
169645233Sborman 									var);
169745233Sborman 		return;
169845233Sborman 	}
169945233Sborman 	ep = env_find(var);
170045233Sborman 	if (ep == 0) {
170145233Sborman 		fprintf(stderr, "Cannot send '%s': variable not defined\n",
170245233Sborman 									var);
170345233Sborman 		return;
170445233Sborman 	}
170545233Sborman 	env_opt_start_info();
170645233Sborman 	env_opt_add(ep->var);
170745233Sborman 	env_opt_end(0);
170845233Sborman }
170945233Sborman 
171046808Sdab 	void
171144361Sborman env_list()
171244361Sborman {
171344361Sborman 	register struct env_lst *ep;
171444361Sborman 
171544361Sborman 	for (ep = envlisthead.next; ep; ep = ep->next) {
171644361Sborman 		printf("%c %-20s %s\n", ep->export ? '*' : ' ',
171744361Sborman 					ep->var, ep->value);
171844361Sborman 	}
171944361Sborman }
172044361Sborman 
172146808Sdab 	unsigned char *
172244361Sborman env_default(init)
172346808Sdab 	int init;
172444361Sborman {
172544361Sborman 	static struct env_lst *nep = NULL;
172644361Sborman 
172744361Sborman 	if (init) {
172844361Sborman 		nep = &envlisthead;
172944361Sborman 		return;
173044361Sborman 	}
173144361Sborman 	if (nep) {
173244361Sborman 		while (nep = nep->next) {
173344361Sborman 			if (nep->export)
173444361Sborman 				return(nep->var);
173544361Sborman 		}
173644361Sborman 	}
173744361Sborman 	return(NULL);
173844361Sborman }
173944361Sborman 
174046808Sdab 	unsigned char *
174144361Sborman env_getvalue(var)
174246808Sdab 	unsigned char *var;
174344361Sborman {
174444361Sborman 	register struct env_lst *ep;
174544361Sborman 
174644361Sborman 	if (ep = env_find(var))
174744361Sborman 		return(ep->value);
174844361Sborman 	return(NULL);
174944361Sborman }
175044361Sborman 
175146808Sdab #if	defined(AUTHENTICATE)
175246808Sdab /*
175346808Sdab  * The AUTHENTICATE command.
175446808Sdab  */
175546808Sdab 
175646808Sdab struct authlist {
175746808Sdab 	char	*name;
175846808Sdab 	char	*help;
175946808Sdab 	int	(*handler)();
176046808Sdab 	int	narg;
176146808Sdab };
176246808Sdab 
176346808Sdab extern int
176446808Sdab 	auth_enable P((int)),
176546808Sdab 	auth_disable P((int)),
176646808Sdab 	auth_status P((void)),
176746808Sdab 	auth_togdebug P((void)),
176846808Sdab 	auth_help P((void));
176946808Sdab 
177046808Sdab struct authlist AuthList[] = {
177146808Sdab     { "status",	"Display current status of authentication information",
177246808Sdab 						auth_status,	0 },
177346808Sdab     { "debug",	"Toggle authentication debugging",
177446808Sdab 						auth_togdebug,	0 },
177546808Sdab     { "disable", "Disable an authentication type ('auth disable ?' for more)",
177646808Sdab 						auth_disable,	1 },
177746808Sdab     { "enable", "Enable an authentication type ('auth enable ?' for more)",
177846808Sdab 						auth_enable,	1 },
177946808Sdab     { "help",	0,				auth_help,		0 },
178046808Sdab     { "?",	"Print help information",	auth_help,		0 },
178146808Sdab     { 0 },
178246808Sdab };
178346808Sdab 
178446808Sdab     static int
178546808Sdab auth_help()
178644361Sborman {
178746808Sdab     struct authlist *c;
178846808Sdab 
178946808Sdab     for (c = AuthList; c->name; c++) {
179046808Sdab 	if (c->help) {
179146808Sdab 	    if (*c->help)
179246808Sdab 		printf("%-15s %s\n", c->name, c->help);
179346808Sdab 	    else
179446808Sdab 		printf("\n");
179546808Sdab 	}
179646808Sdab     }
179746808Sdab     return 0;
179844361Sborman }
179946808Sdab 
180046808Sdab auth_cmd(argc, argv)
180146808Sdab     int  argc;
180246808Sdab     char *argv[];
180346808Sdab {
180446808Sdab     struct authlist *c;
180546808Sdab 
180646808Sdab     c = (struct authlist *)
180746808Sdab 		genget(argv[1], (char **) AuthList, sizeof(struct authlist));
180846808Sdab     if (c == 0) {
180946808Sdab         fprintf(stderr, "'%s': unknown argument ('auth ?' for help).\n",
181046808Sdab     				argv[1]);
181146808Sdab         return 0;
181246808Sdab     }
181346808Sdab     if (Ambiguous(c)) {
181446808Sdab         fprintf(stderr, "'%s': ambiguous argument ('auth ?' for help).\n",
181546808Sdab     				argv[1]);
181646808Sdab         return 0;
181746808Sdab     }
181846808Sdab     if (c->narg + 2 != argc) {
181946808Sdab 	fprintf(stderr,
182046808Sdab 	    "Need %s%d argument%s to 'auth %s' command.  'auth ?' for help.\n",
182146808Sdab 		c->narg < argc + 2 ? "only " : "",
182246808Sdab 		c->narg, c->narg == 1 ? "" : "s", c->name);
182346808Sdab 	return 0;
182446808Sdab     }
182546808Sdab     return((*c->handler)(argv[2], argv[3]));
182646808Sdab }
182745233Sborman #endif
182844361Sborman 
182946808Sdab #if	defined(ENCRYPT)
183032144Sminshall /*
183146808Sdab  * The ENCRYPT command.
183236274Sminshall  */
183336274Sminshall 
183446808Sdab struct encryptlist {
183546808Sdab 	char	*name;
183646808Sdab 	char	*help;
183746808Sdab 	int	(*handler)();
183846808Sdab 	int	needconnect;
183946808Sdab 	int	minarg;
184046808Sdab 	int	maxarg;
184146808Sdab };
184246808Sdab 
184346808Sdab extern int
184446808Sdab 	EncryptEnable P((char *, char *)),
184546808Sdab 	EncryptType P((char *, char *)),
184646808Sdab 	EncryptStart P((char *)),
184746808Sdab 	EncryptStartInput P((void)),
184846808Sdab 	EncryptStartOutput P((void)),
184946808Sdab 	EncryptStop P((char *)),
185046808Sdab 	EncryptStopInput P((void)),
185146808Sdab 	EncryptStopOutput P((void)),
185246808Sdab 	EncryptTogAuto P((void)),
185346808Sdab 	EncryptTogDebug P((void)),
185446808Sdab 	EncryptTogVerbose P((void)),
185546808Sdab 	EncryptStatus P((void)),
185646808Sdab 	EncryptHelp P((void));
185746808Sdab 
185846808Sdab struct encryptlist EncryptList[] = {
185946808Sdab     { "enable", "Enable encryption. ('encrypt enable ?' for more)",
186046808Sdab 						EncryptEnable, 1, 1, 2 },
186146808Sdab     { "type", "Set encryptiong type. ('encrypt type ?' for more)",
186246808Sdab 						EncryptType, 0, 1, 1 },
186346808Sdab     { "start", "Start encryption. ('encrypt start ?' for more)",
186446808Sdab 						EncryptStart, 1, 0, 1 },
186546808Sdab     { "stop", "Stop encryption. ('encrypt stop ?' for more)",
186646808Sdab 						EncryptStop, 1, 0, 1 },
186746808Sdab     { "input", "Start encrypting the input stream",
186846808Sdab 						EncryptStartInput, 1, 0, 0 },
186946808Sdab     { "-input", "Stop encrypting the input stream",
187046808Sdab 						EncryptStopInput, 1, 0, 0 },
187146808Sdab     { "output", "Start encrypting the output stream",
187246808Sdab 						EncryptStartOutput, 1, 0, 0 },
187346808Sdab     { "-output", "Stop encrypting the output stream",
187446808Sdab 						EncryptStopOutput, 1, 0, 0 },
187546808Sdab 
187646808Sdab     { "status",	"Display current status of authentication information",
187746808Sdab 						EncryptStatus,	0, 0, 0 },
187846808Sdab     { "auto", "Toggle automatic enabling of encryption",
187946808Sdab 						EncryptTogAuto, 0, 0, 0 },
188046808Sdab     { "verbose", "Toggle verbose encryption output",
188146808Sdab 						EncryptTogVerbose, 0, 0, 0 },
188246808Sdab     { "debug",	"Toggle encryption debugging",
188346808Sdab 						EncryptTogDebug, 0, 0, 0 },
188446808Sdab     { "help",	0,				EncryptHelp,	0, 0, 0 },
188546808Sdab     { "?",	"Print help information",	EncryptHelp,	0, 0, 0 },
188646808Sdab     { 0 },
188746808Sdab };
188846808Sdab 
188946808Sdab     static int
189046808Sdab EncryptHelp()
189136274Sminshall {
189246808Sdab     struct encryptlist *c;
189346808Sdab 
189446808Sdab     for (c = EncryptList; c->name; c++) {
189546808Sdab 	if (c->help) {
189646808Sdab 	    if (*c->help)
189746808Sdab 		printf("%-15s %s\n", c->name, c->help);
189846808Sdab 	    else
189946808Sdab 		printf("\n");
190036274Sminshall 	}
190146808Sdab     }
190246808Sdab     return 0;
190346808Sdab }
190436274Sminshall 
190546808Sdab encrypt_cmd(argc, argv)
190646808Sdab     int  argc;
190746808Sdab     char *argv[];
190846808Sdab {
190946808Sdab     struct encryptlist *c;
191036274Sminshall 
191146808Sdab     c = (struct encryptlist *)
191246808Sdab 		genget(argv[1], (char **) EncryptList, sizeof(struct encryptlist));
191346808Sdab     if (c == 0) {
191446808Sdab         fprintf(stderr, "'%s': unknown argument ('encrypt ?' for help).\n",
191546808Sdab     				argv[1]);
191646808Sdab         return 0;
191746808Sdab     }
191846808Sdab     if (Ambiguous(c)) {
191946808Sdab         fprintf(stderr, "'%s': ambiguous argument ('encrypt ?' for help).\n",
192046808Sdab     				argv[1]);
192146808Sdab         return 0;
192246808Sdab     }
192346808Sdab     argc -= 2;
192446808Sdab     if (argc < c->minarg || argc > c->maxarg) {
192546808Sdab 	if (c->minarg == c->maxarg) {
192646808Sdab 	    fprintf(stderr, "Need %s%d argument%s ",
192746808Sdab 		c->minarg < argc ? "only " : "", c->minarg,
192846808Sdab 		c->minarg == 1 ? "" : "s");
192946808Sdab 	} else {
193046808Sdab 	    fprintf(stderr, "Need %s%d-%d arguments ",
193146808Sdab 		c->maxarg < argc ? "only " : "", c->minarg, c->maxarg);
193246808Sdab 	}
193346808Sdab 	fprintf(stderr, "to 'encrypt %s' command.  'encrypt ?' for help.\n",
193446808Sdab 		c->name);
193546808Sdab 	return 0;
193646808Sdab     }
193746808Sdab     if (c->needconnect && !connected) {
193846808Sdab 	if (!(argc && (isprefix(argv[2], "help") || isprefix(argv[2], "?")))) {
193946808Sdab 	    printf("?Need to be connected first.\n");
194046808Sdab 	    return 0;
194146808Sdab 	}
194246808Sdab     }
194346808Sdab     return ((*c->handler)(argc > 0 ? argv[2] : 0,
194446808Sdab 			argc > 1 ? argv[3] : 0,
194546808Sdab 			argc > 2 ? argv[4] : 0));
194646808Sdab }
194736274Sminshall #endif
194836274Sminshall 
194946808Sdab #if	defined(unix) && defined(TN3270)
195046808Sdab     static void
195136274Sminshall filestuff(fd)
195246808Sdab     int fd;
195336274Sminshall {
195436274Sminshall     int res;
195536274Sminshall 
195638689Sborman #ifdef	F_GETOWN
195738689Sborman     setconnmode(0);
195836274Sminshall     res = fcntl(fd, F_GETOWN, 0);
195936274Sminshall     setcommandmode();
196036274Sminshall 
196136274Sminshall     if (res == -1) {
196236274Sminshall 	perror("fcntl");
196336274Sminshall 	return;
196436274Sminshall     }
196536274Sminshall     printf("\tOwner is %d.\n", res);
196638689Sborman #endif
196736274Sminshall 
196838689Sborman     setconnmode(0);
196936274Sminshall     res = fcntl(fd, F_GETFL, 0);
197036274Sminshall     setcommandmode();
197136274Sminshall 
197236274Sminshall     if (res == -1) {
197336274Sminshall 	perror("fcntl");
197436274Sminshall 	return;
197536274Sminshall     }
197636274Sminshall     printf("\tFlags are 0x%x: %s\n", res, decodeflags(res));
197736274Sminshall }
197846808Sdab #endif /* defined(unix) && defined(TN3270) */
197936274Sminshall 
198036274Sminshall /*
198132144Sminshall  * Print status about the connection.
198232144Sminshall  */
198346808Sdab     /*ARGSUSED*/
198446808Sdab     static
198532144Sminshall status(argc, argv)
198646808Sdab     int	 argc;
198746808Sdab     char *argv[];
198832144Sminshall {
198932144Sminshall     if (connected) {
199032144Sminshall 	printf("Connected to %s.\n", hostname);
199136242Sminshall 	if ((argc < 2) || strcmp(argv[1], "notmuch")) {
199238689Sborman 	    int mode = getconnmode();
199338689Sborman 
199438689Sborman 	    if (my_want_state_is_will(TELOPT_LINEMODE)) {
199538689Sborman 		printf("Operating with LINEMODE option\n");
199638689Sborman 		printf("%s line editing\n", (mode&MODE_EDIT) ? "Local" : "No");
199738689Sborman 		printf("%s catching of signals\n",
199838689Sborman 					(mode&MODE_TRAPSIG) ? "Local" : "No");
199938689Sborman 		slcstate();
200038689Sborman #ifdef	KLUDGELINEMODE
200139529Sborman 	    } else if (kludgelinemode && my_want_state_is_dont(TELOPT_SGA)) {
200238689Sborman 		printf("Operating in obsolete linemode\n");
200338689Sborman #endif
200438689Sborman 	    } else {
200538689Sborman 		printf("Operating in single character mode\n");
200638689Sborman 		if (localchars)
200738689Sborman 		    printf("Catching signals locally\n");
200832144Sminshall 	    }
200938689Sborman 	    printf("%s character echo\n", (mode&MODE_ECHO) ? "Local" : "Remote");
201038689Sborman 	    if (my_want_state_is_will(TELOPT_LFLOW))
201138689Sborman 		printf("%s flow control\n", (mode&MODE_FLOW) ? "Local" : "No");
201246808Sdab #if	defined(ENCRYPT)
201346808Sdab 	    encrypt_display();
201446808Sdab #endif
201532144Sminshall 	}
201632144Sminshall     } else {
201732144Sminshall 	printf("No connection.\n");
201832144Sminshall     }
201932144Sminshall #   if !defined(TN3270)
202032144Sminshall     printf("Escape character is '%s'.\n", control(escape));
202134849Sminshall     (void) fflush(stdout);
202232144Sminshall #   else /* !defined(TN3270) */
202332144Sminshall     if ((!In3270) && ((argc < 2) || strcmp(argv[1], "notmuch"))) {
202432144Sminshall 	printf("Escape character is '%s'.\n", control(escape));
202532144Sminshall     }
202632144Sminshall #   if defined(unix)
202736242Sminshall     if ((argc >= 2) && !strcmp(argv[1], "everything")) {
202836242Sminshall 	printf("SIGIO received %d time%s.\n",
202936242Sminshall 				sigiocount, (sigiocount == 1)? "":"s");
203036274Sminshall 	if (In3270) {
203136274Sminshall 	    printf("Process ID %d, process group %d.\n",
203236274Sminshall 					    getpid(), getpgrp(getpid()));
203336274Sminshall 	    printf("Terminal input:\n");
203436274Sminshall 	    filestuff(tin);
203536274Sminshall 	    printf("Terminal output:\n");
203636274Sminshall 	    filestuff(tout);
203736274Sminshall 	    printf("Network socket:\n");
203836274Sminshall 	    filestuff(net);
203936274Sminshall 	}
204036242Sminshall     }
204132144Sminshall     if (In3270 && transcom) {
204232144Sminshall        printf("Transparent mode command is '%s'.\n", transcom);
204332144Sminshall     }
204432144Sminshall #   endif /* defined(unix) */
204534849Sminshall     (void) fflush(stdout);
204632144Sminshall     if (In3270) {
204732144Sminshall 	return 0;
204832144Sminshall     }
204932144Sminshall #   endif /* defined(TN3270) */
205032144Sminshall     return 1;
205132144Sminshall }
205232144Sminshall 
205345233Sborman #ifdef	SIGINFO
205445233Sborman /*
205545233Sborman  * Function that gets called when SIGINFO is received.
205645233Sborman  */
205745233Sborman ayt_status()
205845233Sborman {
205945233Sborman     (void) call(status, "status", "notmuch", 0);
206045233Sborman }
206145233Sborman #endif
206232144Sminshall 
206346808Sdab     int
206432144Sminshall tn(argc, argv)
206546808Sdab     int argc;
206646808Sdab     char *argv[];
206732144Sminshall {
206832144Sminshall     register struct hostent *host = 0;
206932144Sminshall     struct sockaddr_in sin;
207032144Sminshall     struct servent *sp = 0;
207138689Sborman     unsigned long temp, inet_addr();
207237219Sminshall     extern char *inet_ntoa();
207346808Sdab #if	defined(IP_OPTIONS) && defined(IPPROTO_IP)
207438689Sborman     char *srp = 0, *strrchr();
207538689Sborman     unsigned long sourceroute(), srlen;
207638689Sborman #endif
207744361Sborman     char *cmd, *hostp = 0, *portp = 0, *user = 0;
207832144Sminshall 
207945233Sborman     /* clear the socket address prior to use */
208045233Sborman     bzero((char *)&sin, sizeof(sin));
208132144Sminshall 
208232144Sminshall     if (connected) {
208332144Sminshall 	printf("?Already connected to %s\n", hostname);
208446808Sdab 	setuid(getuid());
208532144Sminshall 	return 0;
208632144Sminshall     }
208732144Sminshall     if (argc < 2) {
208846808Sdab 	(void) strcpy(line, "open ");
208932144Sminshall 	printf("(to) ");
209046808Sdab 	(void) fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin);
209132144Sminshall 	makeargv();
209232144Sminshall 	argc = margc;
209332144Sminshall 	argv = margv;
209432144Sminshall     }
209544361Sborman     cmd = *argv;
209644361Sborman     --argc; ++argv;
209744361Sborman     while (argc) {
209846808Sdab 	if (isprefix(*argv, "help") || isprefix(*argv, "?"))
209946808Sdab 	    goto usage;
210044361Sborman 	if (strcmp(*argv, "-l") == 0) {
210144361Sborman 	    --argc; ++argv;
210244361Sborman 	    if (argc == 0)
210344361Sborman 		goto usage;
210444361Sborman 	    user = *argv++;
210544361Sborman 	    --argc;
210644361Sborman 	    continue;
210744361Sborman 	}
210845233Sborman 	if (strcmp(*argv, "-a") == 0) {
210945233Sborman 	    --argc; ++argv;
211045233Sborman 	    autologin = 1;
211145233Sborman 	    continue;
211245233Sborman 	}
211344361Sborman 	if (hostp == 0) {
211444361Sborman 	    hostp = *argv++;
211544361Sborman 	    --argc;
211644361Sborman 	    continue;
211744361Sborman 	}
211844361Sborman 	if (portp == 0) {
211944361Sborman 	    portp = *argv++;
212044361Sborman 	    --argc;
212144361Sborman 	    continue;
212244361Sborman 	}
212344361Sborman     usage:
212445233Sborman 	printf("usage: %s [-l user] [-a] host-name [port]\n", cmd);
212546808Sdab 	setuid(getuid());
212632144Sminshall 	return 0;
212732144Sminshall     }
212846808Sdab     if (hostp == 0)
212946808Sdab 	goto usage;
213046808Sdab 
213146808Sdab #if	defined(IP_OPTIONS) && defined(IPPROTO_IP)
213244361Sborman     if (hostp[0] == '@' || hostp[0] == '!') {
213344361Sborman 	if ((hostname = strrchr(hostp, ':')) == NULL)
213444361Sborman 	    hostname = strrchr(hostp, '@');
213538689Sborman 	hostname++;
213638689Sborman 	srp = 0;
213744361Sborman 	temp = sourceroute(hostp, &srp, &srlen);
213838689Sborman 	if (temp == 0) {
213938689Sborman 	    herror(srp);
214046808Sdab 	    setuid(getuid());
214138689Sborman 	    return 0;
214238689Sborman 	} else if (temp == -1) {
214344361Sborman 	    printf("Bad source route option: %s\n", hostp);
214446808Sdab 	    setuid(getuid());
214538689Sborman 	    return 0;
214638689Sborman 	} else {
214738689Sborman 	    sin.sin_addr.s_addr = temp;
214838689Sborman 	    sin.sin_family = AF_INET;
214938689Sborman 	}
215032144Sminshall     } else {
215138689Sborman #endif
215244361Sborman 	temp = inet_addr(hostp);
215338689Sborman 	if (temp != (unsigned long) -1) {
215438689Sborman 	    sin.sin_addr.s_addr = temp;
215538689Sborman 	    sin.sin_family = AF_INET;
215646808Sdab 	    (void) strcpy(_hostname, hostp);
215746808Sdab 	    hostname = _hostname;
215838689Sborman 	} else {
215944361Sborman 	    host = gethostbyname(hostp);
216038689Sborman 	    if (host) {
216138689Sborman 		sin.sin_family = host->h_addrtype;
216232144Sminshall #if	defined(h_addr)		/* In 4.3, this is a #define */
216338689Sborman 		memcpy((caddr_t)&sin.sin_addr,
216432144Sminshall 				host->h_addr_list[0], host->h_length);
216532144Sminshall #else	/* defined(h_addr) */
216638689Sborman 		memcpy((caddr_t)&sin.sin_addr, host->h_addr, host->h_length);
216732144Sminshall #endif	/* defined(h_addr) */
216846808Sdab 		strncpy(_hostname, host->h_name, sizeof(_hostname));
216946808Sdab 		_hostname[sizeof(_hostname)-1] = '\0';
217046808Sdab 		hostname = _hostname;
217138689Sborman 	    } else {
217244361Sborman 		herror(hostp);
217346808Sdab 	        setuid(getuid());
217438689Sborman 		return 0;
217538689Sborman 	    }
217632144Sminshall 	}
217746808Sdab #if	defined(IP_OPTIONS) && defined(IPPROTO_IP)
217832144Sminshall     }
217938689Sborman #endif
218044361Sborman     if (portp) {
218144361Sborman 	if (*portp == '-') {
218244361Sborman 	    portp++;
218338689Sborman 	    telnetport = 1;
218438689Sborman 	} else
218538689Sborman 	    telnetport = 0;
218644361Sborman 	sin.sin_port = atoi(portp);
218732144Sminshall 	if (sin.sin_port == 0) {
218844361Sborman 	    sp = getservbyname(portp, "tcp");
218932144Sminshall 	    if (sp)
219032144Sminshall 		sin.sin_port = sp->s_port;
219132144Sminshall 	    else {
219244361Sborman 		printf("%s: bad port number\n", portp);
219346808Sdab 	        setuid(getuid());
219432144Sminshall 		return 0;
219532144Sminshall 	    }
219632144Sminshall 	} else {
219734849Sminshall #if	!defined(htons)
219834849Sminshall 	    u_short htons();
219934849Sminshall #endif	/* !defined(htons) */
220032144Sminshall 	    sin.sin_port = htons(sin.sin_port);
220132144Sminshall 	}
220232144Sminshall     } else {
220332144Sminshall 	if (sp == 0) {
220432144Sminshall 	    sp = getservbyname("telnet", "tcp");
220532144Sminshall 	    if (sp == 0) {
220634849Sminshall 		fprintf(stderr, "telnet: tcp/telnet: unknown service\n");
220746808Sdab 	        setuid(getuid());
220832144Sminshall 		return 0;
220932144Sminshall 	    }
221032144Sminshall 	    sin.sin_port = sp->s_port;
221132144Sminshall 	}
221232144Sminshall 	telnetport = 1;
221332144Sminshall     }
221437219Sminshall     printf("Trying %s...\n", inet_ntoa(sin.sin_addr));
221532144Sminshall     do {
221632144Sminshall 	net = socket(AF_INET, SOCK_STREAM, 0);
221746808Sdab 	setuid(getuid());
221832144Sminshall 	if (net < 0) {
221932144Sminshall 	    perror("telnet: socket");
222032144Sminshall 	    return 0;
222132144Sminshall 	}
222246808Sdab #if	defined(IP_OPTIONS) && defined(IPPROTO_IP)
222338689Sborman 	if (srp && setsockopt(net, IPPROTO_IP, IP_OPTIONS, (char *)srp, srlen) < 0)
222438689Sborman 		perror("setsockopt (IP_OPTIONS)");
222538689Sborman #endif
222646808Sdab #if	defined(IPPROTO_IP) && defined(IP_TOS)
222746808Sdab 	{
222846808Sdab # if	defined(HAS_GETTOS)
222946808Sdab 	    struct tosent *tp;
2230*46815Sdab 	    if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
223146808Sdab 		tos = tp->t_tos;
223246808Sdab # endif
2233*46815Sdab 	    if (tos < 0)
2234*46815Sdab 		tos = 020;	/* Low Delay bit */
2235*46815Sdab 	    if (tos
2236*46815Sdab 		&& (setsockopt(net, IPPROTO_IP, IP_TOS, &tos, sizeof(int)) < 0)
2237*46815Sdab 		&& (errno != ENOPROTOOPT))
2238*46815Sdab 		    perror("telnet: setsockopt (IP_TOS) (ignored)");
223946808Sdab 	}
224046808Sdab #endif	/* defined(IPPROTO_IP) && defined(IP_TOS) */
224140245Sborman 
224232144Sminshall 	if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) {
224332144Sminshall 		perror("setsockopt (SO_DEBUG)");
224432144Sminshall 	}
224532144Sminshall 
224632144Sminshall 	if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
224732144Sminshall #if	defined(h_addr)		/* In 4.3, this is a #define */
224832144Sminshall 	    if (host && host->h_addr_list[1]) {
224932144Sminshall 		int oerrno = errno;
225032144Sminshall 
225132144Sminshall 		fprintf(stderr, "telnet: connect to address %s: ",
225232144Sminshall 						inet_ntoa(sin.sin_addr));
225332144Sminshall 		errno = oerrno;
225432144Sminshall 		perror((char *)0);
225532144Sminshall 		host->h_addr_list++;
225632144Sminshall 		memcpy((caddr_t)&sin.sin_addr,
225732144Sminshall 			host->h_addr_list[0], host->h_length);
225832144Sminshall 		(void) NetClose(net);
225932144Sminshall 		continue;
226032144Sminshall 	    }
226132144Sminshall #endif	/* defined(h_addr) */
226232144Sminshall 	    perror("telnet: Unable to connect to remote host");
226332144Sminshall 	    return 0;
226437219Sminshall 	}
226532144Sminshall 	connected++;
226646808Sdab #if	defined(AUTHENTICATE) || defined(ENCRYPT)
226746808Sdab 	auth_encrypt_connect(connected);
226846808Sdab #endif
226932144Sminshall     } while (connected == 0);
227044361Sborman     cmdrc(hostp, hostname);
227145008Skarels     if (autologin && user == NULL) {
227245008Skarels 	struct passwd *pw;
227345008Skarels 
227445233Sborman 	user = getenv("USER");
227545008Skarels 	if (user == NULL ||
227645233Sborman 	    (pw = getpwnam(user)) && pw->pw_uid != getuid()) {
227745233Sborman 		if (pw = getpwuid(getuid()))
227845008Skarels 			user = pw->pw_name;
227945008Skarels 		else
228045008Skarels 			user = NULL;
228145233Sborman 	}
228245008Skarels     }
228345008Skarels     if (user) {
228446808Sdab 	env_define((unsigned char *)"USER", (unsigned char *)user);
228546808Sdab 	env_export((unsigned char *)"USER");
228645008Skarels     }
228734849Sminshall     (void) call(status, "status", "notmuch", 0);
228832144Sminshall     if (setjmp(peerdied) == 0)
228946808Sdab 	telnet(user);
229034849Sminshall     (void) NetClose(net);
229132381Sminshall     ExitString("Connection closed by foreign host.\n",1);
229232144Sminshall     /*NOTREACHED*/
229332144Sminshall }
229432144Sminshall 
229532144Sminshall #define HELPINDENT (sizeof ("connect"))
229632144Sminshall 
229732144Sminshall static char
229832144Sminshall 	openhelp[] =	"connect to a site",
229932144Sminshall 	closehelp[] =	"close current connection",
230046808Sdab 	logouthelp[] =	"forcibly logout remote user and close the connection",
230132144Sminshall 	quithelp[] =	"exit telnet",
230232144Sminshall 	statushelp[] =	"print status information",
230332144Sminshall 	helphelp[] =	"print help information",
230432144Sminshall 	sendhelp[] =	"transmit special characters ('send ?' for more)",
230532144Sminshall 	sethelp[] = 	"set operating parameters ('set ?' for more)",
230638689Sborman 	unsethelp[] = 	"unset operating parameters ('unset ?' for more)",
230732144Sminshall 	togglestring[] ="toggle operating parameters ('toggle ?' for more)",
230838689Sborman 	slchelp[] =	"change state of special charaters ('slc ?' for more)",
230932144Sminshall 	displayhelp[] =	"display operating parameters",
231032144Sminshall #if	defined(TN3270) && defined(unix)
231132144Sminshall 	transcomhelp[] = "specify Unix command for transparent mode pipe",
231232144Sminshall #endif	/* defined(TN3270) && defined(unix) */
231346808Sdab #if	defined(AUTHENTICATE)
231446808Sdab 	authhelp[] =	"turn on (off) authentication ('auth ?' for more)",
231546808Sdab #endif
231646808Sdab #if	defined(ENCRYPT)
231746808Sdab 	encrypthelp[] =	"turn on (off) encryption ('encrypt ?' for more)",
231846808Sdab #endif
231932144Sminshall #if	defined(unix)
232032144Sminshall 	zhelp[] =	"suspend telnet",
232143317Skfall #endif	/* defined(unix) */
232232144Sminshall 	shellhelp[] =	"invoke a subshell",
232344361Sborman 	envhelp[] =	"change environment variables ('environ ?' for more)",
232444361Sborman 	modestring[] = "try to enter line or character mode ('mode ?' for more)";
232532144Sminshall 
232646808Sdab extern int	help();
232732144Sminshall 
232832144Sminshall static Command cmdtab[] = {
232938689Sborman 	{ "close",	closehelp,	bye,		1 },
233046808Sdab 	{ "logout",	logouthelp,	logout,		1 },
233138689Sborman 	{ "display",	displayhelp,	display,	0 },
233238689Sborman 	{ "mode",	modestring,	modecmd,	0 },
233338689Sborman 	{ "open",	openhelp,	tn,		0 },
233438689Sborman 	{ "quit",	quithelp,	quit,		0 },
233538689Sborman 	{ "send",	sendhelp,	sendcmd,	0 },
233638689Sborman 	{ "set",	sethelp,	setcmd,		0 },
233738689Sborman 	{ "unset",	unsethelp,	unsetcmd,	0 },
233838689Sborman 	{ "status",	statushelp,	status,		0 },
233938689Sborman 	{ "toggle",	togglestring,	toggle,		0 },
234038689Sborman 	{ "slc",	slchelp,	slccmd,		0 },
234132144Sminshall #if	defined(TN3270) && defined(unix)
234238689Sborman 	{ "transcom",	transcomhelp,	settranscom,	0 },
234332144Sminshall #endif	/* defined(TN3270) && defined(unix) */
234446808Sdab #if	defined(AUTHENTICATE)
234546808Sdab 	{ "auth",	authhelp,	auth_cmd,	0 },
234646808Sdab #endif
234746808Sdab #if	defined(ENCRYPT)
234846808Sdab 	{ "encrypt",	encrypthelp,	encrypt_cmd,	0 },
234946808Sdab #endif
235032144Sminshall #if	defined(unix)
235138689Sborman 	{ "z",		zhelp,		suspend,	0 },
235232144Sminshall #endif	/* defined(unix) */
235332144Sminshall #if	defined(TN3270)
235438689Sborman 	{ "!",		shellhelp,	shell,		1 },
235538689Sborman #else
235638689Sborman 	{ "!",		shellhelp,	shell,		0 },
235738689Sborman #endif
235844361Sborman 	{ "environ",	envhelp,	env_cmd,	0 },
235938689Sborman 	{ "?",		helphelp,	help,		0 },
236032144Sminshall 	0
236132144Sminshall };
236232144Sminshall 
236332144Sminshall static char	crmodhelp[] =	"deprecated command -- use 'toggle crmod' instead";
236432144Sminshall static char	escapehelp[] =	"deprecated command -- use 'set escape' instead";
236532144Sminshall 
236632144Sminshall static Command cmdtab2[] = {
236738689Sborman 	{ "help",	0,		help,		0 },
236838689Sborman 	{ "escape",	escapehelp,	setescape,	0 },
236938689Sborman 	{ "crmod",	crmodhelp,	togcrmod,	0 },
237032144Sminshall 	0
237132144Sminshall };
237232144Sminshall 
237335298Sminshall 
237432144Sminshall /*
237532144Sminshall  * Call routine with argc, argv set from args (terminated by 0).
237632144Sminshall  */
237735298Sminshall 
237846808Sdab     /*VARARGS1*/
237946808Sdab     static
238035298Sminshall call(va_alist)
238146808Sdab     va_dcl
238232144Sminshall {
238335298Sminshall     va_list ap;
238435298Sminshall     typedef int (*intrtn_t)();
238535298Sminshall     intrtn_t routine;
238635298Sminshall     char *args[100];
238735298Sminshall     int argno = 0;
238835298Sminshall 
238935298Sminshall     va_start(ap);
239035298Sminshall     routine = (va_arg(ap, intrtn_t));
239135495Sminshall     while ((args[argno++] = va_arg(ap, char *)) != 0) {
239235298Sminshall 	;
239335495Sminshall     }
239435298Sminshall     va_end(ap);
239535495Sminshall     return (*routine)(argno-1, args);
239632144Sminshall }
239732144Sminshall 
239835298Sminshall 
239946808Sdab     static Command *
240032144Sminshall getcmd(name)
240146808Sdab     char *name;
240232144Sminshall {
240332144Sminshall     Command *cm;
240432144Sminshall 
240546808Sdab     if (cm = (Command *) genget(name, (char **) cmdtab, sizeof(Command)))
240632144Sminshall 	return cm;
240746808Sdab     return (Command *) genget(name, (char **) cmdtab2, sizeof(Command));
240832144Sminshall }
240932144Sminshall 
241046808Sdab     void
241138689Sborman command(top, tbuf, cnt)
241246808Sdab     int top;
241346808Sdab     char *tbuf;
241446808Sdab     int cnt;
241532144Sminshall {
241632144Sminshall     register Command *c;
241732144Sminshall 
241832144Sminshall     setcommandmode();
241932144Sminshall     if (!top) {
242032144Sminshall 	putchar('\n');
242137219Sminshall #if	defined(unix)
242232144Sminshall     } else {
242344361Sborman 	(void) signal(SIGINT, SIG_DFL);
242444361Sborman 	(void) signal(SIGQUIT, SIG_DFL);
242532144Sminshall #endif	/* defined(unix) */
242632144Sminshall     }
242732144Sminshall     for (;;) {
242846808Sdab 	if (rlogin == _POSIX_VDISABLE)
242946808Sdab 		printf("%s> ", prompt);
243038689Sborman 	if (tbuf) {
243138689Sborman 	    register char *cp;
243238689Sborman 	    cp = line;
243338689Sborman 	    while (cnt > 0 && (*cp++ = *tbuf++) != '\n')
243438689Sborman 		cnt--;
243538689Sborman 	    tbuf = 0;
243638689Sborman 	    if (cp == line || *--cp != '\n' || cp == line)
243738689Sborman 		goto getline;
243838689Sborman 	    *cp = '\0';
243946808Sdab 	    if (rlogin == _POSIX_VDISABLE)
244046808Sdab 	        printf("%s\n", line);
244138689Sborman 	} else {
244238689Sborman 	getline:
244346808Sdab 	    if (rlogin != _POSIX_VDISABLE)
244446808Sdab 		printf("%s> ", prompt);
244546808Sdab 	    if (fgets(line, sizeof(line), stdin) == NULL) {
244644361Sborman 		if (feof(stdin) || ferror(stdin)) {
244744361Sborman 		    (void) quit();
244844361Sborman 		    /*NOTREACHED*/
244944361Sborman 		}
245038689Sborman 		break;
245138689Sborman 	    }
245232144Sminshall 	}
245332144Sminshall 	if (line[0] == 0)
245432144Sminshall 	    break;
245532144Sminshall 	makeargv();
245637219Sminshall 	if (margv[0] == 0) {
245737219Sminshall 	    break;
245837219Sminshall 	}
245932144Sminshall 	c = getcmd(margv[0]);
246032144Sminshall 	if (Ambiguous(c)) {
246132144Sminshall 	    printf("?Ambiguous command\n");
246232144Sminshall 	    continue;
246332144Sminshall 	}
246432144Sminshall 	if (c == 0) {
246532144Sminshall 	    printf("?Invalid command\n");
246632144Sminshall 	    continue;
246732144Sminshall 	}
246832144Sminshall 	if (c->needconnect && !connected) {
246932144Sminshall 	    printf("?Need to be connected first.\n");
247032144Sminshall 	    continue;
247132144Sminshall 	}
247232144Sminshall 	if ((*c->handler)(margc, margv)) {
247332144Sminshall 	    break;
247432144Sminshall 	}
247532144Sminshall     }
247632144Sminshall     if (!top) {
247732144Sminshall 	if (!connected) {
247832144Sminshall 	    longjmp(toplevel, 1);
247932144Sminshall 	    /*NOTREACHED*/
248032144Sminshall 	}
248132144Sminshall #if	defined(TN3270)
248232144Sminshall 	if (shell_active == 0) {
248338689Sborman 	    setconnmode(0);
248432144Sminshall 	}
248532144Sminshall #else	/* defined(TN3270) */
248638689Sborman 	setconnmode(0);
248732144Sminshall #endif	/* defined(TN3270) */
248832144Sminshall     }
248932144Sminshall }
249032144Sminshall 
249132144Sminshall /*
249232144Sminshall  * Help command.
249332144Sminshall  */
249446808Sdab 	static
249532144Sminshall help(argc, argv)
249632144Sminshall 	int argc;
249732144Sminshall 	char *argv[];
249832144Sminshall {
249932144Sminshall 	register Command *c;
250032144Sminshall 
250132144Sminshall 	if (argc == 1) {
250232144Sminshall 		printf("Commands may be abbreviated.  Commands are:\n\n");
250332144Sminshall 		for (c = cmdtab; c->name; c++)
250438689Sborman 			if (c->help) {
250532144Sminshall 				printf("%-*s\t%s\n", HELPINDENT, c->name,
250632144Sminshall 								    c->help);
250732144Sminshall 			}
250832144Sminshall 		return 0;
250932144Sminshall 	}
251032144Sminshall 	while (--argc > 0) {
251132144Sminshall 		register char *arg;
251232144Sminshall 		arg = *++argv;
251332144Sminshall 		c = getcmd(arg);
251432144Sminshall 		if (Ambiguous(c))
251532144Sminshall 			printf("?Ambiguous help command %s\n", arg);
251632144Sminshall 		else if (c == (Command *)0)
251732144Sminshall 			printf("?Invalid help command %s\n", arg);
251832144Sminshall 		else
251932144Sminshall 			printf("%s\n", c->help);
252032144Sminshall 	}
252132144Sminshall 	return 0;
252232144Sminshall }
252338689Sborman 
252438689Sborman static char *rcname = 0;
252538689Sborman static char rcbuf[128];
252638689Sborman 
252738689Sborman cmdrc(m1, m2)
252838689Sborman 	char *m1, *m2;
252938689Sborman {
253038689Sborman     register Command *c;
253138689Sborman     FILE *rcfile;
253238689Sborman     int gotmachine = 0;
253338689Sborman     int l1 = strlen(m1);
253438689Sborman     int l2 = strlen(m2);
253538689Sborman     char m1save[64];
253638689Sborman 
253738689Sborman     strcpy(m1save, m1);
253838689Sborman     m1 = m1save;
253938689Sborman 
254038689Sborman     if (rcname == 0) {
254138689Sborman 	rcname = getenv("HOME");
254238689Sborman 	if (rcname)
254338689Sborman 	    strcpy(rcbuf, rcname);
254438689Sborman 	else
254538689Sborman 	    rcbuf[0] = '\0';
254638689Sborman 	strcat(rcbuf, "/.telnetrc");
254738689Sborman 	rcname = rcbuf;
254838689Sborman     }
254938689Sborman 
255038689Sborman     if ((rcfile = fopen(rcname, "r")) == 0) {
255138689Sborman 	return;
255238689Sborman     }
255338689Sborman 
255438689Sborman     for (;;) {
255538689Sborman 	if (fgets(line, sizeof(line), rcfile) == NULL)
255638689Sborman 	    break;
255738689Sborman 	if (line[0] == 0)
255838689Sborman 	    break;
255938689Sborman 	if (line[0] == '#')
256038689Sborman 	    continue;
256138689Sborman 	if (gotmachine == 0) {
256238689Sborman 	    if (isspace(line[0]))
256338689Sborman 		continue;
256438689Sborman 	    if (strncasecmp(line, m1, l1) == 0)
256538689Sborman 		strncpy(line, &line[l1], sizeof(line) - l1);
256638689Sborman 	    else if (strncasecmp(line, m2, l2) == 0)
256738689Sborman 		strncpy(line, &line[l2], sizeof(line) - l2);
256838689Sborman 	    else
256938689Sborman 		continue;
257038689Sborman 	    gotmachine = 1;
257138689Sborman 	} else {
257238689Sborman 	    if (!isspace(line[0])) {
257338689Sborman 		gotmachine = 0;
257438689Sborman 		continue;
257538689Sborman 	    }
257638689Sborman 	}
257738689Sborman 	makeargv();
257838689Sborman 	if (margv[0] == 0)
257938689Sborman 	    continue;
258038689Sborman 	c = getcmd(margv[0]);
258138689Sborman 	if (Ambiguous(c)) {
258238689Sborman 	    printf("?Ambiguous command: %s\n", margv[0]);
258338689Sborman 	    continue;
258438689Sborman 	}
258538689Sborman 	if (c == 0) {
258638689Sborman 	    printf("?Invalid command: %s\n", margv[0]);
258738689Sborman 	    continue;
258838689Sborman 	}
258938689Sborman 	/*
259038689Sborman 	 * This should never happen...
259138689Sborman 	 */
259238689Sborman 	if (c->needconnect && !connected) {
259338689Sborman 	    printf("?Need to be connected first for %s.\n", margv[0]);
259438689Sborman 	    continue;
259538689Sborman 	}
259638689Sborman 	(*c->handler)(margc, margv);
259738689Sborman     }
259838689Sborman     fclose(rcfile);
259938689Sborman }
260038689Sborman 
260146808Sdab #if	defined(IP_OPTIONS) && defined(IPPROTO_IP)
260238689Sborman 
260338689Sborman /*
260438689Sborman  * Source route is handed in as
260538689Sborman  *	[!]@hop1@hop2...[@|:]dst
260638689Sborman  * If the leading ! is present, it is a
260738689Sborman  * strict source route, otherwise it is
260838689Sborman  * assmed to be a loose source route.
260938689Sborman  *
261038689Sborman  * We fill in the source route option as
261138689Sborman  *	hop1,hop2,hop3...dest
261238689Sborman  * and return a pointer to hop1, which will
261338689Sborman  * be the address to connect() to.
261438689Sborman  *
261538689Sborman  * Arguments:
261638689Sborman  *	arg:	pointer to route list to decipher
261738689Sborman  *
261838689Sborman  *	cpp: 	If *cpp is not equal to NULL, this is a
261938689Sborman  *		pointer to a pointer to a character array
262038689Sborman  *		that should be filled in with the option.
262138689Sborman  *
262238689Sborman  *	lenp:	pointer to an integer that contains the
262338689Sborman  *		length of *cpp if *cpp != NULL.
262438689Sborman  *
262538689Sborman  * Return values:
262638689Sborman  *
262738689Sborman  *	Returns the address of the host to connect to.  If the
262838689Sborman  *	return value is -1, there was a syntax error in the
262938689Sborman  *	option, either unknown characters, or too many hosts.
263038689Sborman  *	If the return value is 0, one of the hostnames in the
263138689Sborman  *	path is unknown, and *cpp is set to point to the bad
263238689Sborman  *	hostname.
263338689Sborman  *
263438689Sborman  *	*cpp:	If *cpp was equal to NULL, it will be filled
263538689Sborman  *		in with a pointer to our static area that has
263638689Sborman  *		the option filled in.  This will be 32bit aligned.
263738689Sborman  *
263838689Sborman  *	*lenp:	This will be filled in with how long the option
263938689Sborman  *		pointed to by *cpp is.
264038689Sborman  *
264138689Sborman  */
264246808Sdab 	unsigned long
264338689Sborman sourceroute(arg, cpp, lenp)
264446808Sdab 	char	*arg;
264546808Sdab 	char	**cpp;
264646808Sdab 	int	*lenp;
264738689Sborman {
264838689Sborman 	static char lsr[44];
264946808Sdab 	char *cp, *cp2, *lsrp, *lsrep;
265038689Sborman 	register int tmp;
265138689Sborman 	struct in_addr sin_addr;
265238689Sborman 	register struct hostent *host = 0;
265338689Sborman 	register char c;
265438689Sborman 
265538689Sborman 	/*
265638689Sborman 	 * Verify the arguments, and make sure we have
265738689Sborman 	 * at least 7 bytes for the option.
265838689Sborman 	 */
265938689Sborman 	if (cpp == NULL || lenp == NULL)
266038689Sborman 		return((unsigned long)-1);
266138689Sborman 	if (*cpp != NULL && *lenp < 7)
266238689Sborman 		return((unsigned long)-1);
266338689Sborman 	/*
266438689Sborman 	 * Decide whether we have a buffer passed to us,
266538689Sborman 	 * or if we need to use our own static buffer.
266638689Sborman 	 */
266738689Sborman 	if (*cpp) {
266838689Sborman 		lsrp = *cpp;
266938689Sborman 		lsrep = lsrp + *lenp;
267038689Sborman 	} else {
267138689Sborman 		*cpp = lsrp = lsr;
267238689Sborman 		lsrep = lsrp + 44;
267338689Sborman 	}
267438689Sborman 
267538689Sborman 	cp = arg;
267638689Sborman 
267738689Sborman 	/*
267838689Sborman 	 * Next, decide whether we have a loose source
267938689Sborman 	 * route or a strict source route, and fill in
268038689Sborman 	 * the begining of the option.
268138689Sborman 	 */
268238689Sborman 	if (*cp == '!') {
268338689Sborman 		cp++;
268438689Sborman 		*lsrp++ = IPOPT_SSRR;
268538689Sborman 	} else
268638689Sborman 		*lsrp++ = IPOPT_LSRR;
268738689Sborman 
268838689Sborman 	if (*cp != '@')
268938689Sborman 		return((unsigned long)-1);
269038689Sborman 
269138689Sborman 	lsrp++;		/* skip over length, we'll fill it in later */
269238689Sborman 	*lsrp++ = 4;
269338689Sborman 
269438689Sborman 	cp++;
269538689Sborman 
269638689Sborman 	sin_addr.s_addr = 0;
269738689Sborman 
269838689Sborman 	for (c = 0;;) {
269938689Sborman 		if (c == ':')
270038689Sborman 			cp2 = 0;
270138689Sborman 		else for (cp2 = cp; c = *cp2; cp2++) {
270238689Sborman 			if (c == ',') {
270338689Sborman 				*cp2++ = '\0';
270438689Sborman 				if (*cp2 == '@')
270538689Sborman 					cp2++;
270638689Sborman 			} else if (c == '@') {
270738689Sborman 				*cp2++ = '\0';
270838689Sborman 			} else if (c == ':') {
270938689Sborman 				*cp2++ = '\0';
271038689Sborman 			} else
271138689Sborman 				continue;
271238689Sborman 			break;
271338689Sborman 		}
271438689Sborman 		if (!c)
271538689Sborman 			cp2 = 0;
271638689Sborman 
271738689Sborman 		if ((tmp = inet_addr(cp)) != -1) {
271838689Sborman 			sin_addr.s_addr = tmp;
271938689Sborman 		} else if (host = gethostbyname(cp)) {
272038689Sborman #if	defined(h_addr)
272138689Sborman 			memcpy((caddr_t)&sin_addr,
272238689Sborman 				host->h_addr_list[0], host->h_length);
272338689Sborman #else
272438689Sborman 			memcpy((caddr_t)&sin_addr, host->h_addr, host->h_length);
272538689Sborman #endif
272638689Sborman 		} else {
272738689Sborman 			*cpp = cp;
272838689Sborman 			return(0);
272938689Sborman 		}
273038689Sborman 		memcpy(lsrp, (char *)&sin_addr, 4);
273138689Sborman 		lsrp += 4;
273238689Sborman 		if (cp2)
273338689Sborman 			cp = cp2;
273438689Sborman 		else
273538689Sborman 			break;
273638689Sborman 		/*
273738689Sborman 		 * Check to make sure there is space for next address
273838689Sborman 		 */
273938689Sborman 		if (lsrp + 4 > lsrep)
274038689Sborman 			return((unsigned long)-1);
274138689Sborman 	}
274238689Sborman 	if ((*(*cpp+IPOPT_OLEN) = lsrp - *cpp) <= 7) {
274338689Sborman 		*cpp = 0;
274438689Sborman 		*lenp = 0;
274538689Sborman 		return((unsigned long)-1);
274638689Sborman 	}
274738689Sborman 	*lsrp++ = IPOPT_NOP; /* 32 bit word align it */
274838689Sborman 	*lenp = lsrp - *cpp;
274938689Sborman 	return(sin_addr.s_addr);
275038689Sborman }
275138689Sborman #endif
2752