xref: /csrg-svn/usr.bin/telnet/commands.c (revision 56859)
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*56859Storek static char sccsid[] = "@(#)commands.c	5.7 (Berkeley) 11/16/92";
1033685Sbostic #endif /* not lint */
1133685Sbostic 
1236274Sminshall #if	defined(unix)
1345241Swilliam #include <sys/param.h>
1446808Sdab #ifdef	CRAY
1546808Sdab #include <sys/types.h>
1646808Sdab #endif
1736274Sminshall #include <sys/file.h>
1845241Swilliam #else
1945241Swilliam #include <sys/types.h>
2036274Sminshall #endif	/* defined(unix) */
2132144Sminshall #include <sys/socket.h>
2232144Sminshall #include <netinet/in.h>
2338689Sborman #ifdef	CRAY
2446808Sdab #include <fcntl.h>
2538810Sborman #endif	/* CRAY */
2632144Sminshall 
2732144Sminshall #include <signal.h>
2832144Sminshall #include <netdb.h>
2932144Sminshall #include <ctype.h>
3045008Skarels #include <pwd.h>
3135298Sminshall #include <varargs.h>
3246808Sdab #include <errno.h>
3332144Sminshall 
3432144Sminshall #include <arpa/telnet.h>
3532144Sminshall 
3634305Sminshall #include "general.h"
3734305Sminshall 
3832381Sminshall #include "ring.h"
3932381Sminshall 
4032144Sminshall #include "externs.h"
4132144Sminshall #include "defines.h"
4232144Sminshall #include "types.h"
4332144Sminshall 
4446808Sdab #ifndef CRAY
4546808Sdab #include <netinet/in_systm.h>
4646808Sdab # if (defined(vax) || defined(tahoe) || defined(hp300)) && !defined(ultrix)
4746808Sdab # include <machine/endian.h>
4846808Sdab # endif /* vax */
4946808Sdab #endif /* CRAY */
5044361Sborman #include <netinet/ip.h>
5138689Sborman 
5238689Sborman 
5346808Sdab #ifndef       MAXHOSTNAMELEN
5446808Sdab #define       MAXHOSTNAMELEN 64
5546808Sdab #endif        MAXHOSTNAMELEN
5640248Sborman 
5746815Sdab #if	defined(IPPROTO_IP) && defined(IP_TOS)
5846815Sdab int tos = -1;
5946815Sdab #endif	/* defined(IPPROTO_IP) && defined(IP_TOS) */
6046815Sdab 
6132144Sminshall char	*hostname;
6246808Sdab static char _hostname[MAXHOSTNAMELEN];
6346808Sdab 
6438689Sborman extern char *getenv();
6532144Sminshall 
6646808Sdab extern int isprefix();
6746808Sdab extern char **genget();
6846808Sdab extern int Ambiguous();
6946808Sdab 
7044361Sborman static call();
7132144Sminshall 
7232144Sminshall typedef struct {
7332144Sminshall 	char	*name;		/* command name */
7438689Sborman 	char	*help;		/* help string (NULL for no help) */
7532144Sminshall 	int	(*handler)();	/* routine which executes command */
7632144Sminshall 	int	needconnect;	/* Do we need to be connected to execute? */
7732144Sminshall } Command;
7832144Sminshall 
7938689Sborman static char line[256];
8038689Sborman static char saveline[256];
8132144Sminshall static int margc;
8232144Sminshall static char *margv[20];
8332144Sminshall 
8446808Sdab     static void
8532144Sminshall makeargv()
8632144Sminshall {
8744361Sborman     register char *cp, *cp2, c;
8832144Sminshall     register char **argp = margv;
8932144Sminshall 
9032144Sminshall     margc = 0;
9132144Sminshall     cp = line;
9232144Sminshall     if (*cp == '!') {		/* Special case shell escape */
9338689Sborman 	strcpy(saveline, line);	/* save for shell command */
9432144Sminshall 	*argp++ = "!";		/* No room in string to get this */
9532144Sminshall 	margc++;
9632144Sminshall 	cp++;
9732144Sminshall     }
9844361Sborman     while (c = *cp) {
9944361Sborman 	register int inquote = 0;
10044361Sborman 	while (isspace(c))
10144361Sborman 	    c = *++cp;
10244361Sborman 	if (c == '\0')
10332144Sminshall 	    break;
10432144Sminshall 	*argp++ = cp;
10532144Sminshall 	margc += 1;
10644361Sborman 	for (cp2 = cp; c != '\0'; c = *++cp) {
10744361Sborman 	    if (inquote) {
10844361Sborman 		if (c == inquote) {
10944361Sborman 		    inquote = 0;
11044361Sborman 		    continue;
11144361Sborman 		}
11244361Sborman 	    } else {
11344361Sborman 		if (c == '\\') {
11444361Sborman 		    if ((c = *++cp) == '\0')
11544361Sborman 			break;
11644361Sborman 		} else if (c == '"') {
11744361Sborman 		    inquote = '"';
11844361Sborman 		    continue;
11944361Sborman 		} else if (c == '\'') {
12044361Sborman 		    inquote = '\'';
12144361Sborman 		    continue;
12244361Sborman 		} else if (isspace(c))
12344361Sborman 		    break;
12444361Sborman 	    }
12544361Sborman 	    *cp2++ = c;
12644361Sborman 	}
12744361Sborman 	*cp2 = '\0';
12844361Sborman 	if (c == '\0')
12932144Sminshall 	    break;
13044361Sborman 	cp++;
13132144Sminshall     }
13232144Sminshall     *argp++ = 0;
13332144Sminshall }
13432144Sminshall 
13532144Sminshall /*
13632144Sminshall  * Make a character string into a number.
13732144Sminshall  *
13832144Sminshall  * Todo:  1.  Could take random integers (12, 0x12, 012, 0b1).
13932144Sminshall  */
14032144Sminshall 
14146808Sdab 	static
14232144Sminshall special(s)
14346808Sdab 	register char *s;
14432144Sminshall {
14532144Sminshall 	register char c;
14632144Sminshall 	char b;
14732144Sminshall 
14832144Sminshall 	switch (*s) {
14932144Sminshall 	case '^':
15032144Sminshall 		b = *++s;
15132144Sminshall 		if (b == '?') {
15232144Sminshall 		    c = b | 0x40;		/* DEL */
15332144Sminshall 		} else {
15432144Sminshall 		    c = b & 0x1f;
15532144Sminshall 		}
15632144Sminshall 		break;
15732144Sminshall 	default:
15832144Sminshall 		c = *s;
15932144Sminshall 		break;
16032144Sminshall 	}
16132144Sminshall 	return c;
16232144Sminshall }
16332144Sminshall 
16432144Sminshall /*
16532144Sminshall  * Construct a control character sequence
16632144Sminshall  * for a special character.
16732144Sminshall  */
16846808Sdab 	static char *
16932144Sminshall control(c)
17040245Sborman 	register cc_t c;
17132144Sminshall {
17244361Sborman 	static char buf[5];
17346808Sdab 	/*
17446808Sdab 	 * The only way I could get the Sun 3.5 compiler
17546808Sdab 	 * to shut up about
17646808Sdab 	 *	if ((unsigned int)c >= 0x80)
17746808Sdab 	 * was to assign "c" to an unsigned int variable...
17846808Sdab 	 * Arggg....
17946808Sdab 	 */
18046808Sdab 	register unsigned int uic = (unsigned int)c;
18132144Sminshall 
18246808Sdab 	if (uic == 0x7f)
18332144Sminshall 		return ("^?");
18445233Sborman 	if (c == (cc_t)_POSIX_VDISABLE) {
18532144Sminshall 		return "off";
18632144Sminshall 	}
18746808Sdab 	if (uic >= 0x80) {
18844361Sborman 		buf[0] = '\\';
18944361Sborman 		buf[1] = ((c>>6)&07) + '0';
19044361Sborman 		buf[2] = ((c>>3)&07) + '0';
19144361Sborman 		buf[3] = (c&07) + '0';
19244361Sborman 		buf[4] = 0;
19346808Sdab 	} else if (uic >= 0x20) {
19432144Sminshall 		buf[0] = c;
19532144Sminshall 		buf[1] = 0;
19632144Sminshall 	} else {
19732144Sminshall 		buf[0] = '^';
19832144Sminshall 		buf[1] = '@'+c;
19932144Sminshall 		buf[2] = 0;
20032144Sminshall 	}
20132144Sminshall 	return (buf);
20232144Sminshall }
20332144Sminshall 
20432144Sminshall 
20532144Sminshall 
20632144Sminshall /*
20732144Sminshall  *	The following are data structures and routines for
20832144Sminshall  *	the "send" command.
20932144Sminshall  *
21032144Sminshall  */
21132144Sminshall 
21232144Sminshall struct sendlist {
21332144Sminshall     char	*name;		/* How user refers to it (case independent) */
21432144Sminshall     char	*help;		/* Help information (0 ==> no help) */
21546808Sdab     int		needconnect;	/* Need to be connected */
21646808Sdab     int		narg;		/* Number of arguments */
21738689Sborman     int		(*handler)();	/* Routine to perform (for special ops) */
21846808Sdab     int		nbyte;		/* Number of bytes to send this command */
21938689Sborman     int		what;		/* Character to be sent (<0 ==> special) */
22032144Sminshall };
22132144Sminshall 
22232144Sminshall 
22356642Sralph static 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 count;		/* how many bytes we are going to need to send */
26932144Sminshall     int i;
27032144Sminshall     int question = 0;	/* was at least one argument a question */
27132144Sminshall     struct sendlist *s;	/* pointer to current command */
27246808Sdab     int success = 0;
27346808Sdab     int needconnect = 0;
27432144Sminshall 
27532144Sminshall     if (argc < 2) {
27632144Sminshall 	printf("need at least one argument for 'send' command\n");
27732144Sminshall 	printf("'send ?' for help\n");
27832144Sminshall 	return 0;
27932144Sminshall     }
28032144Sminshall     /*
28132144Sminshall      * First, validate all the send arguments.
28232144Sminshall      * In addition, we see how much space we are going to need, and
28332144Sminshall      * whether or not we will be doing a "SYNCH" operation (which
28432144Sminshall      * flushes the network queue).
28532144Sminshall      */
28632144Sminshall     count = 0;
28732144Sminshall     for (i = 1; i < argc; i++) {
28846808Sdab 	s = GETSEND(argv[i]);
28932144Sminshall 	if (s == 0) {
29032144Sminshall 	    printf("Unknown send argument '%s'\n'send ?' for help.\n",
29132144Sminshall 			argv[i]);
29232144Sminshall 	    return 0;
29332144Sminshall 	} else if (Ambiguous(s)) {
29432144Sminshall 	    printf("Ambiguous send argument '%s'\n'send ?' for help.\n",
29532144Sminshall 			argv[i]);
29632144Sminshall 	    return 0;
29732144Sminshall 	}
29846808Sdab 	if (i + s->narg >= argc) {
29946808Sdab 	    fprintf(stderr,
30046808Sdab 	    "Need %d argument%s to 'send %s' command.  'send %s ?' for help.\n",
30146808Sdab 		s->narg, s->narg == 1 ? "" : "s", s->name, s->name);
30246808Sdab 	    return 0;
30332144Sminshall 	}
30446808Sdab 	count += s->nbyte;
30546808Sdab 	if (s->handler == send_help) {
30646808Sdab 	    send_help();
30746808Sdab 	    return 0;
30846808Sdab 	}
30946808Sdab 
31046808Sdab 	i += s->narg;
31146808Sdab 	needconnect += s->needconnect;
31232144Sminshall     }
31346808Sdab     if (!connected && needconnect) {
31446808Sdab 	printf("?Need to be connected first.\n");
31546808Sdab 	printf("'send ?' for help\n");
31646808Sdab 	return 0;
31738689Sborman     }
31832144Sminshall     /* Now, do we have enough room? */
31932144Sminshall     if (NETROOM() < count) {
32032144Sminshall 	printf("There is not enough room in the buffer TO the network\n");
32132144Sminshall 	printf("to process your request.  Nothing will be done.\n");
32232144Sminshall 	printf("('send synch' will throw away most data in the network\n");
32332144Sminshall 	printf("buffer, if this might help.)\n");
32432144Sminshall 	return 0;
32532144Sminshall     }
32632144Sminshall     /* OK, they are all OK, now go through again and actually send */
32746808Sdab     count = 0;
32832144Sminshall     for (i = 1; i < argc; i++) {
32946808Sdab 	if ((s = GETSEND(argv[i])) == 0) {
33032144Sminshall 	    fprintf(stderr, "Telnet 'send' error - argument disappeared!\n");
33144361Sborman 	    (void) quit();
33232144Sminshall 	    /*NOTREACHED*/
33332144Sminshall 	}
33438689Sborman 	if (s->handler) {
33546808Sdab 	    count++;
33646808Sdab 	    success += (*s->handler)((s->narg > 0) ? argv[i+1] : 0,
33746808Sdab 				  (s->narg > 1) ? argv[i+2] : 0);
33846808Sdab 	    i += s->narg;
33932144Sminshall 	} else {
340*56859Storek 	    NET2ADD(IAC, s->what);
341*56859Storek 	    printoption("SENT", IAC, s->what);
34246808Sdab 	}
34346808Sdab     }
34446808Sdab     return (count == success);
34546808Sdab }
34646808Sdab 
34746808Sdab     static int
34846808Sdab send_esc()
34946808Sdab {
35046808Sdab     NETADD(escape);
35146808Sdab     return 1;
35246808Sdab }
35346808Sdab 
35446808Sdab     static int
35546808Sdab send_docmd(name)
35646808Sdab     char *name;
35746808Sdab {
35846808Sdab     void send_do();
35946808Sdab     return(send_tncmd(send_do, "do", name));
36046808Sdab }
36146808Sdab 
36246808Sdab     static int
36346808Sdab send_dontcmd(name)
36446808Sdab     char *name;
36546808Sdab {
36646808Sdab     void send_dont();
36746808Sdab     return(send_tncmd(send_dont, "dont", name));
36846808Sdab }
36946808Sdab     static int
37046808Sdab send_willcmd(name)
37146808Sdab     char *name;
37246808Sdab {
37346808Sdab     void send_will();
37446808Sdab     return(send_tncmd(send_will, "will", name));
37546808Sdab }
37646808Sdab     static int
37746808Sdab send_wontcmd(name)
37846808Sdab     char *name;
37946808Sdab {
38046808Sdab     void send_wont();
38146808Sdab     return(send_tncmd(send_wont, "wont", name));
38246808Sdab }
38346808Sdab 
38446808Sdab     int
38546808Sdab send_tncmd(func, cmd, name)
38646808Sdab     void	(*func)();
38746808Sdab     char	*cmd, *name;
38846808Sdab {
38946808Sdab     char **cpp;
39046808Sdab     extern char *telopts[];
39146808Sdab 
39246808Sdab     if (isprefix(name, "help") || isprefix(name, "?")) {
39346808Sdab 	register int col, len;
39446808Sdab 
39546808Sdab 	printf("Usage: send %s <option>\n", cmd);
39646808Sdab 	printf("Valid options are:\n\t");
39746808Sdab 
39846808Sdab 	col = 8;
39946808Sdab 	for (cpp = telopts; *cpp; cpp++) {
40046808Sdab 	    len = strlen(*cpp) + 1;
40146808Sdab 	    if (col + len > 65) {
40246808Sdab 		printf("\n\t");
40346808Sdab 		col = 8;
40432144Sminshall 	    }
40546808Sdab 	    printf(" %s", *cpp);
40646808Sdab 	    col += len;
40732144Sminshall 	}
40846808Sdab 	printf("\n");
40946808Sdab 	return 0;
41032144Sminshall     }
41146808Sdab     cpp = (char **)genget(name, telopts, sizeof(char *));
41246808Sdab     if (Ambiguous(cpp)) {
41346808Sdab 	fprintf(stderr,"'%s': ambiguous argument ('send %s ?' for help).\n",
41446808Sdab 					name, cmd);
41546808Sdab 	return 0;
41646808Sdab     }
41746808Sdab     if (cpp == 0) {
41846808Sdab 	fprintf(stderr, "'%s': unknown argument ('send %s ?' for help).\n",
41946808Sdab 					name, cmd);
42046808Sdab 	return 0;
42146808Sdab     }
42246808Sdab     if (!connected) {
42346808Sdab 	printf("?Need to be connected first.\n");
42446808Sdab 	return 0;
42546808Sdab     }
42646808Sdab     (*func)(cpp - telopts, 1);
42746808Sdab     return 1;
42832144Sminshall }
42946808Sdab 
43046808Sdab     static int
43146808Sdab send_help()
43246808Sdab {
43346808Sdab     struct sendlist *s;	/* pointer to current command */
43446808Sdab     for (s = Sendlist; s->name; s++) {
43546808Sdab 	if (s->help)
43646808Sdab 	    printf("%-15s %s\n", s->name, s->help);
43746808Sdab     }
43846808Sdab     return(0);
43946808Sdab }
44032144Sminshall 
44132144Sminshall /*
44232144Sminshall  * The following are the routines and data structures referred
44332144Sminshall  * to by the arguments to the "toggle" command.
44432144Sminshall  */
44532144Sminshall 
44646808Sdab     static int
44732144Sminshall lclchars()
44832144Sminshall {
44932144Sminshall     donelclchars = 1;
45032144Sminshall     return 1;
45132144Sminshall }
45232144Sminshall 
45346808Sdab     static int
45432144Sminshall togdebug()
45532144Sminshall {
45632144Sminshall #ifndef	NOT43
45732144Sminshall     if (net > 0 &&
45832144Sminshall 	(SetSockOpt(net, SOL_SOCKET, SO_DEBUG, debug)) < 0) {
45932144Sminshall 	    perror("setsockopt (SO_DEBUG)");
46032144Sminshall     }
46132144Sminshall #else	/* NOT43 */
46232144Sminshall     if (debug) {
46332144Sminshall 	if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
46432144Sminshall 	    perror("setsockopt (SO_DEBUG)");
46532144Sminshall     } else
46632144Sminshall 	printf("Cannot turn off socket debugging\n");
46732144Sminshall #endif	/* NOT43 */
46832144Sminshall     return 1;
46932144Sminshall }
47032144Sminshall 
47132144Sminshall 
47246808Sdab     static int
47332144Sminshall togcrlf()
47432144Sminshall {
47532144Sminshall     if (crlf) {
47632144Sminshall 	printf("Will send carriage returns as telnet <CR><LF>.\n");
47732144Sminshall     } else {
47832144Sminshall 	printf("Will send carriage returns as telnet <CR><NUL>.\n");
47932144Sminshall     }
48032144Sminshall     return 1;
48132144Sminshall }
48232144Sminshall 
48338909Sborman int binmode;
48432144Sminshall 
48546808Sdab     static int
48638689Sborman togbinary(val)
48746808Sdab     int val;
48832144Sminshall {
48932144Sminshall     donebinarytoggle = 1;
49032144Sminshall 
49138909Sborman     if (val >= 0) {
49238909Sborman 	binmode = val;
49338909Sborman     } else {
49438909Sborman 	if (my_want_state_is_will(TELOPT_BINARY) &&
49538909Sborman 				my_want_state_is_do(TELOPT_BINARY)) {
49638909Sborman 	    binmode = 1;
49738909Sborman 	} else if (my_want_state_is_wont(TELOPT_BINARY) &&
49838909Sborman 				my_want_state_is_dont(TELOPT_BINARY)) {
49938909Sborman 	    binmode = 0;
50038909Sborman 	}
50138909Sborman 	val = binmode ? 0 : 1;
50238909Sborman     }
50338909Sborman 
50438909Sborman     if (val == 1) {
50538909Sborman 	if (my_want_state_is_will(TELOPT_BINARY) &&
50638909Sborman 					my_want_state_is_do(TELOPT_BINARY)) {
50738689Sborman 	    printf("Already operating in binary mode with remote host.\n");
50838909Sborman 	} else {
50938909Sborman 	    printf("Negotiating binary mode with remote host.\n");
51038909Sborman 	    tel_enter_binary(3);
51138689Sborman 	}
51238909Sborman     } else {
51338909Sborman 	if (my_want_state_is_wont(TELOPT_BINARY) &&
51438909Sborman 					my_want_state_is_dont(TELOPT_BINARY)) {
51538689Sborman 	    printf("Already in network ascii mode with remote host.\n");
51638909Sborman 	} else {
51738909Sborman 	    printf("Negotiating network ascii mode with remote host.\n");
51838909Sborman 	    tel_leave_binary(3);
51938689Sborman 	}
52032144Sminshall     }
52132144Sminshall     return 1;
52232144Sminshall }
52332144Sminshall 
52446808Sdab     static int
52538909Sborman togrbinary(val)
52646808Sdab     int val;
52738909Sborman {
52838909Sborman     donebinarytoggle = 1;
52932144Sminshall 
53038909Sborman     if (val == -1)
53138909Sborman 	val = my_want_state_is_do(TELOPT_BINARY) ? 0 : 1;
53232144Sminshall 
53338909Sborman     if (val == 1) {
53438909Sborman 	if (my_want_state_is_do(TELOPT_BINARY)) {
53538909Sborman 	    printf("Already receiving in binary mode.\n");
53638909Sborman 	} else {
53738909Sborman 	    printf("Negotiating binary mode on input.\n");
53838909Sborman 	    tel_enter_binary(1);
53938909Sborman 	}
54038909Sborman     } else {
54138909Sborman 	if (my_want_state_is_dont(TELOPT_BINARY)) {
54238909Sborman 	    printf("Already receiving in network ascii mode.\n");
54338909Sborman 	} else {
54438909Sborman 	    printf("Negotiating network ascii mode on input.\n");
54538909Sborman 	    tel_leave_binary(1);
54638909Sborman 	}
54738909Sborman     }
54838909Sborman     return 1;
54938909Sborman }
55038909Sborman 
55146808Sdab     static int
55238909Sborman togxbinary(val)
55346808Sdab     int val;
55438909Sborman {
55538909Sborman     donebinarytoggle = 1;
55638909Sborman 
55738909Sborman     if (val == -1)
55838909Sborman 	val = my_want_state_is_will(TELOPT_BINARY) ? 0 : 1;
55938909Sborman 
56038909Sborman     if (val == 1) {
56138909Sborman 	if (my_want_state_is_will(TELOPT_BINARY)) {
56238909Sborman 	    printf("Already transmitting in binary mode.\n");
56338909Sborman 	} else {
56438909Sborman 	    printf("Negotiating binary mode on output.\n");
56538909Sborman 	    tel_enter_binary(2);
56638909Sborman 	}
56738909Sborman     } else {
56838909Sborman 	if (my_want_state_is_wont(TELOPT_BINARY)) {
56938909Sborman 	    printf("Already transmitting in network ascii mode.\n");
57038909Sborman 	} else {
57138909Sborman 	    printf("Negotiating network ascii mode on output.\n");
57238909Sborman 	    tel_leave_binary(2);
57338909Sborman 	}
57438909Sborman     }
57538909Sborman     return 1;
57638909Sborman }
57738909Sborman 
57838909Sborman 
57956642Sralph static int togglehelp P((void));
58047609Sdab #if	defined(AUTHENTICATE)
58147609Sdab extern int auth_togdebug P((int));
58247609Sdab #endif
58347609Sdab #if	defined(ENCRYPT)
58447609Sdab extern int EncryptAutoEnc P((int));
58547609Sdab extern int EncryptAutoDec P((int));
58647609Sdab extern int EncryptDebug P((int));
58747609Sdab extern int EncryptVerbose P((int));
58847609Sdab #endif
58932144Sminshall 
59032144Sminshall struct togglelist {
59132144Sminshall     char	*name;		/* name of toggle */
59232144Sminshall     char	*help;		/* help message */
59332144Sminshall     int		(*handler)();	/* routine to do actual setting */
59432144Sminshall     int		*variable;
59532144Sminshall     char	*actionexplanation;
59632144Sminshall };
59732144Sminshall 
59832144Sminshall static struct togglelist Togglelist[] = {
59932144Sminshall     { "autoflush",
60038689Sborman 	"flushing of output when sending interrupt characters",
60132144Sminshall 	    0,
60238689Sborman 		&autoflush,
60338689Sborman 		    "flush output when sending interrupt characters" },
60432144Sminshall     { "autosynch",
60538689Sborman 	"automatic sending of interrupt characters in urgent mode",
60632144Sminshall 	    0,
60738689Sborman 		&autosynch,
60838689Sborman 		    "send interrupt characters in urgent mode" },
60947609Sdab #if	defined(AUTHENTICATE)
61047609Sdab     { "autologin",
61147609Sdab 	"automatic sending of login and/or authentication info",
61247609Sdab 	    0,
61347609Sdab 		&autologin,
61447609Sdab 		    "send login name and/or authentication information" },
61547609Sdab     { "authdebug",
61647609Sdab 	"Toggle authentication debugging",
61747609Sdab 	    auth_togdebug,
61847609Sdab 		0,
61947609Sdab 		     "print authentication debugging information" },
62047609Sdab #endif
62147609Sdab #if	defined(ENCRYPT)
62247609Sdab     { "autoencrypt",
62347609Sdab 	"automatic encryption of data stream",
62447609Sdab 	    EncryptAutoEnc,
62547609Sdab 		0,
62647609Sdab 		    "automatically encrypt output" },
62747609Sdab     { "autodecrypt",
62847609Sdab 	"automatic decryption of data stream",
62947609Sdab 	    EncryptAutoDec,
63047609Sdab 		0,
63147609Sdab 		    "automatically decrypt input" },
63247609Sdab     { "verbose_encrypt",
63347609Sdab 	"Toggle verbose encryption output",
63447609Sdab 	    EncryptVerbose,
63547609Sdab 		0,
63647609Sdab 		    "print verbose encryption output" },
63747609Sdab     { "encdebug",
63847609Sdab 	"Toggle encryption debugging",
63947609Sdab 	    EncryptDebug,
64047609Sdab 		0,
64147609Sdab 		    "print encryption debugging information" },
64247609Sdab #endif
64347609Sdab     { "skiprc",
64447609Sdab 	"don't read ~/.telnetrc file",
64547609Sdab 	    0,
64647609Sdab 		&skiprc,
64747609Sdab 		    "read ~/.telnetrc file" },
64832144Sminshall     { "binary",
64938689Sborman 	"sending and receiving of binary data",
65032144Sminshall 	    togbinary,
65138689Sborman 		0,
65238689Sborman 		    0 },
65338909Sborman     { "inbinary",
65438909Sborman 	"receiving of binary data",
65538909Sborman 	    togrbinary,
65638909Sborman 		0,
65738909Sborman 		    0 },
65838909Sborman     { "outbinary",
65938909Sborman 	"sending of binary data",
66038909Sborman 	    togxbinary,
66138909Sborman 		0,
66238909Sborman 		    0 },
66332144Sminshall     { "crlf",
66438689Sborman 	"sending carriage returns as telnet <CR><LF>",
66532144Sminshall 	    togcrlf,
66638689Sborman 		&crlf,
66738689Sborman 		    0 },
66832144Sminshall     { "crmod",
66938689Sborman 	"mapping of received carriage returns",
67032144Sminshall 	    0,
67138689Sborman 		&crmod,
67238689Sborman 		    "map carriage return on output" },
67332144Sminshall     { "localchars",
67438689Sborman 	"local recognition of certain control characters",
67532144Sminshall 	    lclchars,
67638689Sborman 		&localchars,
67738689Sborman 		    "recognize certain control characters" },
67838689Sborman     { " ", "", 0 },		/* empty line */
67938208Sminshall #if	defined(unix) && defined(TN3270)
68038920Sminshall     { "apitrace",
68138920Sminshall 	"(debugging) toggle tracing of API transactions",
68238920Sminshall 	    0,
68338920Sminshall 		&apitrace,
68438920Sminshall 		    "trace API transactions" },
68538208Sminshall     { "cursesdata",
68638208Sminshall 	"(debugging) toggle printing of hexadecimal curses data",
68738208Sminshall 	    0,
68838689Sborman 		&cursesdata,
68938689Sborman 		    "print hexadecimal representation of curses data" },
69038208Sminshall #endif	/* defined(unix) && defined(TN3270) */
69132144Sminshall     { "debug",
69238689Sborman 	"debugging",
69332144Sminshall 	    togdebug,
69438689Sborman 		&debug,
69538689Sborman 		    "turn on socket level debugging" },
69632144Sminshall     { "netdata",
69738689Sborman 	"printing of hexadecimal network data (debugging)",
69832144Sminshall 	    0,
69938689Sborman 		&netdata,
70038689Sborman 		    "print hexadecimal representation of network traffic" },
70138689Sborman     { "prettydump",
70238689Sborman 	"output of \"netdata\" to user readable format (debugging)",
70338689Sborman 	    0,
70438689Sborman 		&prettydump,
70538689Sborman 		    "print user readable output for \"netdata\"" },
70632144Sminshall     { "options",
70738689Sborman 	"viewing of options processing (debugging)",
70832144Sminshall 	    0,
70938689Sborman 		&showoptions,
71038689Sborman 		    "show option processing" },
71138208Sminshall #if	defined(unix)
71238208Sminshall     { "termdata",
71338208Sminshall 	"(debugging) toggle printing of hexadecimal terminal data",
71438208Sminshall 	    0,
71538689Sborman 		&termdata,
71638689Sborman 		    "print hexadecimal representation of terminal traffic" },
71738208Sminshall #endif	/* defined(unix) */
71832144Sminshall     { "?",
71938689Sborman 	0,
72038689Sborman 	    togglehelp },
72132144Sminshall     { "help",
72238689Sborman 	0,
72338689Sborman 	    togglehelp },
72432144Sminshall     { 0 }
72532144Sminshall };
72632144Sminshall 
72746808Sdab     static int
72832144Sminshall togglehelp()
72932144Sminshall {
73032144Sminshall     struct togglelist *c;
73132144Sminshall 
73232144Sminshall     for (c = Togglelist; c->name; c++) {
73338689Sborman 	if (c->help) {
73438689Sborman 	    if (*c->help)
73538689Sborman 		printf("%-15s toggle %s\n", c->name, c->help);
73638689Sborman 	    else
73738689Sborman 		printf("\n");
73832144Sminshall 	}
73932144Sminshall     }
74038689Sborman     printf("\n");
74138689Sborman     printf("%-15s %s\n", "?", "display help information");
74232144Sminshall     return 0;
74332144Sminshall }
74432144Sminshall 
74546808Sdab     static void
74638689Sborman settogglehelp(set)
74746808Sdab     int set;
74838689Sborman {
74938689Sborman     struct togglelist *c;
75038689Sborman 
75138689Sborman     for (c = Togglelist; c->name; c++) {
75238689Sborman 	if (c->help) {
75338689Sborman 	    if (*c->help)
75438689Sborman 		printf("%-15s %s %s\n", c->name, set ? "enable" : "disable",
75538689Sborman 						c->help);
75638689Sborman 	    else
75738689Sborman 		printf("\n");
75838689Sborman 	}
75938689Sborman     }
76038689Sborman }
76138689Sborman 
76246808Sdab #define	GETTOGGLE(name) (struct togglelist *) \
76346808Sdab 		genget(name, (char **) Togglelist, sizeof(struct togglelist))
76432144Sminshall 
76546808Sdab     static int
76632144Sminshall toggle(argc, argv)
76746808Sdab     int  argc;
76846808Sdab     char *argv[];
76932144Sminshall {
77032144Sminshall     int retval = 1;
77132144Sminshall     char *name;
77232144Sminshall     struct togglelist *c;
77332144Sminshall 
77432144Sminshall     if (argc < 2) {
77532144Sminshall 	fprintf(stderr,
77632144Sminshall 	    "Need an argument to 'toggle' command.  'toggle ?' for help.\n");
77732144Sminshall 	return 0;
77832144Sminshall     }
77932144Sminshall     argc--;
78032144Sminshall     argv++;
78132144Sminshall     while (argc--) {
78232144Sminshall 	name = *argv++;
78346808Sdab 	c = GETTOGGLE(name);
78432144Sminshall 	if (Ambiguous(c)) {
78532144Sminshall 	    fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n",
78632144Sminshall 					name);
78732144Sminshall 	    return 0;
78832144Sminshall 	} else if (c == 0) {
78932144Sminshall 	    fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n",
79032144Sminshall 					name);
79132144Sminshall 	    return 0;
79232144Sminshall 	} else {
79332144Sminshall 	    if (c->variable) {
79432144Sminshall 		*c->variable = !*c->variable;		/* invert it */
79532144Sminshall 		if (c->actionexplanation) {
79632144Sminshall 		    printf("%s %s.\n", *c->variable? "Will" : "Won't",
79732144Sminshall 							c->actionexplanation);
79832144Sminshall 		}
79932144Sminshall 	    }
80032144Sminshall 	    if (c->handler) {
80138689Sborman 		retval &= (*c->handler)(-1);
80232144Sminshall 	    }
80332144Sminshall 	}
80432144Sminshall     }
80532144Sminshall     return retval;
80632144Sminshall }
80732144Sminshall 
80832144Sminshall /*
80932144Sminshall  * The following perform the "set" command.
81032144Sminshall  */
81132144Sminshall 
81238689Sborman #ifdef	USE_TERMIO
81338689Sborman struct termio new_tc = { 0 };
81438689Sborman #endif
81538689Sborman 
81632144Sminshall struct setlist {
81732144Sminshall     char *name;				/* name */
81832144Sminshall     char *help;				/* help information */
81938689Sborman     void (*handler)();
82040245Sborman     cc_t *charp;			/* where it is located at */
82132144Sminshall };
82232144Sminshall 
82332144Sminshall static struct setlist Setlist[] = {
82444361Sborman #ifdef	KLUDGELINEMODE
82538689Sborman     { "echo", 	"character to toggle local echoing on/off", 0, &echoc },
82644361Sborman #endif
82738689Sborman     { "escape",	"character to escape back to telnet command mode", 0, &escape },
82846808Sdab     { "rlogin", "rlogin escape character", 0, &rlogin },
82945233Sborman     { "tracefile", "file to write trace information to", SetNetTrace, (cc_t *)NetTraceFile},
83032144Sminshall     { " ", "" },
83138689Sborman     { " ", "The following need 'localchars' to be toggled true", 0, 0 },
83245233Sborman     { "flushoutput", "character to cause an Abort Output", 0, termFlushCharp },
83338689Sborman     { "interrupt", "character to cause an Interrupt Process", 0, termIntCharp },
83438689Sborman     { "quit",	"character to cause an Abort process", 0, termQuitCharp },
83538689Sborman     { "eof",	"character to cause an EOF ", 0, termEofCharp },
83638689Sborman     { " ", "" },
83738689Sborman     { " ", "The following are for local editing in linemode", 0, 0 },
83838689Sborman     { "erase",	"character to use to erase a character", 0, termEraseCharp },
83938689Sborman     { "kill",	"character to use to erase a line", 0, termKillCharp },
84038689Sborman     { "lnext",	"character to use for literal next", 0, termLiteralNextCharp },
84144361Sborman     { "susp",	"character to cause a Suspend Process", 0, termSuspCharp },
84238689Sborman     { "reprint", "character to use for line reprint", 0, termRprntCharp },
84338689Sborman     { "worderase", "character to use to erase a word", 0, termWerasCharp },
84438689Sborman     { "start",	"character to use for XON", 0, termStartCharp },
84544361Sborman     { "stop",	"character to use for XOFF", 0, termStopCharp },
84644361Sborman     { "forw1",	"alternate end of line character", 0, termForw1Charp },
84744361Sborman     { "forw2",	"alternate end of line character", 0, termForw2Charp },
84845233Sborman     { "ayt",	"alternate AYT character", 0, termAytCharp },
84932144Sminshall     { 0 }
85032144Sminshall };
85132144Sminshall 
85245233Sborman #if	defined(CRAY) && !defined(__STDC__)
85345233Sborman /* Work around compiler bug in pcc 4.1.5 */
85446808Sdab     void
85538689Sborman _setlist_init()
85638689Sborman {
85744361Sborman #ifndef	KLUDGELINEMODE
85846808Sdab #define	N 5
85944361Sborman #else
86046808Sdab #define	N 6
86144361Sborman #endif
86244361Sborman 	Setlist[N+0].charp = &termFlushChar;
86344361Sborman 	Setlist[N+1].charp = &termIntChar;
86444361Sborman 	Setlist[N+2].charp = &termQuitChar;
86544361Sborman 	Setlist[N+3].charp = &termEofChar;
86644361Sborman 	Setlist[N+6].charp = &termEraseChar;
86744361Sborman 	Setlist[N+7].charp = &termKillChar;
86844361Sborman 	Setlist[N+8].charp = &termLiteralNextChar;
86944361Sborman 	Setlist[N+9].charp = &termSuspChar;
87044361Sborman 	Setlist[N+10].charp = &termRprntChar;
87144361Sborman 	Setlist[N+11].charp = &termWerasChar;
87244361Sborman 	Setlist[N+12].charp = &termStartChar;
87344361Sborman 	Setlist[N+13].charp = &termStopChar;
87444361Sborman 	Setlist[N+14].charp = &termForw1Char;
87544361Sborman 	Setlist[N+15].charp = &termForw2Char;
87645233Sborman 	Setlist[N+16].charp = &termAytChar;
87744361Sborman #undef	N
87838689Sborman }
87945233Sborman #endif	/* defined(CRAY) && !defined(__STDC__) */
88038689Sborman 
88146808Sdab     static struct setlist *
88232144Sminshall getset(name)
88346808Sdab     char *name;
88432144Sminshall {
88546808Sdab     return (struct setlist *)
88646808Sdab 		genget(name, (char **) Setlist, sizeof(struct setlist));
88732144Sminshall }
88832144Sminshall 
88946808Sdab     void
89044361Sborman set_escape_char(s)
89146808Sdab     char *s;
89244361Sborman {
89346808Sdab 	if (rlogin != _POSIX_VDISABLE) {
89446808Sdab 		rlogin = (s && *s) ? special(s) : _POSIX_VDISABLE;
89546808Sdab 		printf("Telnet rlogin escape character is '%s'.\n",
89646808Sdab 					control(rlogin));
89746808Sdab 	} else {
89846808Sdab 		escape = (s && *s) ? special(s) : _POSIX_VDISABLE;
89946808Sdab 		printf("Telnet escape character is '%s'.\n", control(escape));
90046808Sdab 	}
90144361Sborman }
90244361Sborman 
90346808Sdab     static int
90432144Sminshall setcmd(argc, argv)
90546808Sdab     int  argc;
90646808Sdab     char *argv[];
90732144Sminshall {
90832144Sminshall     int value;
90932144Sminshall     struct setlist *ct;
91038689Sborman     struct togglelist *c;
91132144Sminshall 
91238689Sborman     if (argc < 2 || argc > 3) {
91338689Sborman 	printf("Format is 'set Name Value'\n'set ?' for help.\n");
91432144Sminshall 	return 0;
91532144Sminshall     }
91646808Sdab     if ((argc == 2) && (isprefix(argv[1], "?") || isprefix(argv[1], "help"))) {
91738689Sborman 	for (ct = Setlist; ct->name; ct++)
91838689Sborman 	    printf("%-15s %s\n", ct->name, ct->help);
91938689Sborman 	printf("\n");
92038689Sborman 	settogglehelp(1);
92138689Sborman 	printf("%-15s %s\n", "?", "display help information");
92238689Sborman 	return 0;
92338689Sborman     }
92432144Sminshall 
92532144Sminshall     ct = getset(argv[1]);
92632144Sminshall     if (ct == 0) {
92746808Sdab 	c = GETTOGGLE(argv[1]);
92838689Sborman 	if (c == 0) {
92938689Sborman 	    fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n",
93032144Sminshall 			argv[1]);
93138689Sborman 	    return 0;
93238689Sborman 	} else if (Ambiguous(c)) {
93338689Sborman 	    fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
93438689Sborman 			argv[1]);
93538689Sborman 	    return 0;
93638689Sborman 	}
93738689Sborman 	if (c->variable) {
93838689Sborman 	    if ((argc == 2) || (strcmp("on", argv[2]) == 0))
93938689Sborman 		*c->variable = 1;
94038689Sborman 	    else if (strcmp("off", argv[2]) == 0)
94138689Sborman 		*c->variable = 0;
94238689Sborman 	    else {
94338689Sborman 		printf("Format is 'set togglename [on|off]'\n'set ?' for help.\n");
94438689Sborman 		return 0;
94538689Sborman 	    }
94638689Sborman 	    if (c->actionexplanation) {
94738689Sborman 		printf("%s %s.\n", *c->variable? "Will" : "Won't",
94838689Sborman 							c->actionexplanation);
94938689Sborman 	    }
95038689Sborman 	}
95138689Sborman 	if (c->handler)
95238689Sborman 	    (*c->handler)(1);
95338689Sborman     } else if (argc != 3) {
95438689Sborman 	printf("Format is 'set Name Value'\n'set ?' for help.\n");
95532144Sminshall 	return 0;
95632144Sminshall     } else if (Ambiguous(ct)) {
95732144Sminshall 	fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
95832144Sminshall 			argv[1]);
95932144Sminshall 	return 0;
96038689Sborman     } else if (ct->handler) {
96138689Sborman 	(*ct->handler)(argv[2]);
96244361Sborman 	printf("%s set to \"%s\".\n", ct->name, (char *)ct->charp);
96332144Sminshall     } else {
96432144Sminshall 	if (strcmp("off", argv[2])) {
96532144Sminshall 	    value = special(argv[2]);
96632144Sminshall 	} else {
96745233Sborman 	    value = _POSIX_VDISABLE;
96832144Sminshall 	}
96940245Sborman 	*(ct->charp) = (cc_t)value;
97032144Sminshall 	printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
97132144Sminshall     }
97238689Sborman     slc_check();
97332144Sminshall     return 1;
97432144Sminshall }
97538689Sborman 
97646808Sdab     static int
97738689Sborman unsetcmd(argc, argv)
97846808Sdab     int  argc;
97946808Sdab     char *argv[];
98038689Sborman {
98138689Sborman     struct setlist *ct;
98238689Sborman     struct togglelist *c;
98338689Sborman     register char *name;
98438689Sborman 
98538689Sborman     if (argc < 2) {
98638689Sborman 	fprintf(stderr,
98738689Sborman 	    "Need an argument to 'unset' command.  'unset ?' for help.\n");
98838689Sborman 	return 0;
98938689Sborman     }
99046808Sdab     if (isprefix(argv[1], "?") || isprefix(argv[1], "help")) {
99138689Sborman 	for (ct = Setlist; ct->name; ct++)
99238689Sborman 	    printf("%-15s %s\n", ct->name, ct->help);
99338689Sborman 	printf("\n");
99438689Sborman 	settogglehelp(0);
99538689Sborman 	printf("%-15s %s\n", "?", "display help information");
99638689Sborman 	return 0;
99738689Sborman     }
99838689Sborman 
99938689Sborman     argc--;
100038689Sborman     argv++;
100138689Sborman     while (argc--) {
100238689Sborman 	name = *argv++;
100338689Sborman 	ct = getset(name);
100438689Sborman 	if (ct == 0) {
100546808Sdab 	    c = GETTOGGLE(name);
100638689Sborman 	    if (c == 0) {
100738689Sborman 		fprintf(stderr, "'%s': unknown argument ('unset ?' for help).\n",
100838689Sborman 			name);
100938689Sborman 		return 0;
101038689Sborman 	    } else if (Ambiguous(c)) {
101138689Sborman 		fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n",
101238689Sborman 			name);
101338689Sborman 		return 0;
101438689Sborman 	    }
101538689Sborman 	    if (c->variable) {
101638689Sborman 		*c->variable = 0;
101738689Sborman 		if (c->actionexplanation) {
101838689Sborman 		    printf("%s %s.\n", *c->variable? "Will" : "Won't",
101938689Sborman 							c->actionexplanation);
102038689Sborman 		}
102138689Sborman 	    }
102238689Sborman 	    if (c->handler)
102338689Sborman 		(*c->handler)(0);
102438689Sborman 	} else if (Ambiguous(ct)) {
102538689Sborman 	    fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n",
102638689Sborman 			name);
102738689Sborman 	    return 0;
102838689Sborman 	} else if (ct->handler) {
102938689Sborman 	    (*ct->handler)(0);
103044361Sborman 	    printf("%s reset to \"%s\".\n", ct->name, (char *)ct->charp);
103138689Sborman 	} else {
103245233Sborman 	    *(ct->charp) = _POSIX_VDISABLE;
103338689Sborman 	    printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
103438689Sborman 	}
103538689Sborman     }
103638689Sborman     return 1;
103738689Sborman }
103832144Sminshall 
103932144Sminshall /*
104032144Sminshall  * The following are the data structures and routines for the
104132144Sminshall  * 'mode' command.
104232144Sminshall  */
104338689Sborman #ifdef	KLUDGELINEMODE
104438689Sborman extern int kludgelinemode;
104544361Sborman 
104646808Sdab     static int
104744361Sborman dokludgemode()
104844361Sborman {
104944361Sborman     kludgelinemode = 1;
105044361Sborman     send_wont(TELOPT_LINEMODE, 1);
105144361Sborman     send_dont(TELOPT_SGA, 1);
105244361Sborman     send_dont(TELOPT_ECHO, 1);
105344361Sborman }
105438689Sborman #endif
105532144Sminshall 
105646808Sdab     static int
105732144Sminshall dolinemode()
105832144Sminshall {
105938689Sborman #ifdef	KLUDGELINEMODE
106038689Sborman     if (kludgelinemode)
106138689Sborman 	send_dont(TELOPT_SGA, 1);
106238689Sborman #endif
106338689Sborman     send_will(TELOPT_LINEMODE, 1);
106438689Sborman     send_dont(TELOPT_ECHO, 1);
106532144Sminshall     return 1;
106632144Sminshall }
106732144Sminshall 
106846808Sdab     static int
106932144Sminshall docharmode()
107032144Sminshall {
107138689Sborman #ifdef	KLUDGELINEMODE
107238689Sborman     if (kludgelinemode)
107338689Sborman 	send_do(TELOPT_SGA, 1);
107438689Sborman     else
107538689Sborman #endif
107638689Sborman     send_wont(TELOPT_LINEMODE, 1);
107738689Sborman     send_do(TELOPT_ECHO, 1);
107838689Sborman     return 1;
107938689Sborman }
108038689Sborman 
108146808Sdab     static int
108238689Sborman dolmmode(bit, on)
108346808Sdab     int bit, on;
108438689Sborman {
108546808Sdab     unsigned char c;
108638689Sborman     extern int linemode;
108738689Sborman 
108838689Sborman     if (my_want_state_is_wont(TELOPT_LINEMODE)) {
108938689Sborman 	printf("?Need to have LINEMODE option enabled first.\n");
109038689Sborman 	printf("'mode ?' for help.\n");
109138689Sborman 	return 0;
109232144Sminshall     }
109338689Sborman 
109438689Sborman     if (on)
109538689Sborman 	c = (linemode | bit);
109638689Sborman     else
109738689Sborman 	c = (linemode & ~bit);
109838689Sborman     lm_mode(&c, 1, 1);
109932144Sminshall     return 1;
110032144Sminshall }
110132144Sminshall 
110246808Sdab     int
110346808Sdab setmode(bit)
110446808Sdab {
110546808Sdab     return dolmmode(bit, 1);
110646808Sdab }
110746808Sdab 
110846808Sdab     int
110946808Sdab clearmode(bit)
111046808Sdab {
111146808Sdab     return dolmmode(bit, 0);
111246808Sdab }
111346808Sdab 
111438689Sborman struct modelist {
111538689Sborman 	char	*name;		/* command name */
111638689Sborman 	char	*help;		/* help string */
111738689Sborman 	int	(*handler)();	/* routine which executes command */
111838689Sborman 	int	needconnect;	/* Do we need to be connected to execute? */
111938689Sborman 	int	arg1;
112038689Sborman };
112138689Sborman 
112238689Sborman extern int modehelp();
112338689Sborman 
112438689Sborman static struct modelist ModeList[] = {
112538689Sborman     { "character", "Disable LINEMODE option",	docharmode, 1 },
112639529Sborman #ifdef	KLUDGELINEMODE
112739529Sborman     { "",	"(or disable obsolete line-by-line mode)", 0 },
112838689Sborman #endif
112938689Sborman     { "line",	"Enable LINEMODE option",	dolinemode, 1 },
113039529Sborman #ifdef	KLUDGELINEMODE
113139529Sborman     { "",	"(or enable obsolete line-by-line mode)", 0 },
113238689Sborman #endif
113338689Sborman     { "", "", 0 },
113438689Sborman     { "",	"These require the LINEMODE option to be enabled", 0 },
113538689Sborman     { "isig",	"Enable signal trapping",	setmode, 1, MODE_TRAPSIG },
113638689Sborman     { "+isig",	0,				setmode, 1, MODE_TRAPSIG },
113738689Sborman     { "-isig",	"Disable signal trapping",	clearmode, 1, MODE_TRAPSIG },
113838689Sborman     { "edit",	"Enable character editing",	setmode, 1, MODE_EDIT },
113938689Sborman     { "+edit",	0,				setmode, 1, MODE_EDIT },
114038689Sborman     { "-edit",	"Disable character editing",	clearmode, 1, MODE_EDIT },
114144361Sborman     { "softtabs", "Enable tab expansion",	setmode, 1, MODE_SOFT_TAB },
114244361Sborman     { "+softtabs", 0,				setmode, 1, MODE_SOFT_TAB },
114344361Sborman     { "-softtabs", "Disable character editing",	clearmode, 1, MODE_SOFT_TAB },
114444361Sborman     { "litecho", "Enable literal character echo", setmode, 1, MODE_LIT_ECHO },
114544361Sborman     { "+litecho", 0,				setmode, 1, MODE_LIT_ECHO },
114644361Sborman     { "-litecho", "Disable literal character echo", clearmode, 1, MODE_LIT_ECHO },
114738689Sborman     { "help",	0,				modehelp, 0 },
114844361Sborman #ifdef	KLUDGELINEMODE
114944361Sborman     { "kludgeline", 0,				dokludgemode, 1 },
115044361Sborman #endif
115144361Sborman     { "", "", 0 },
115238689Sborman     { "?",	"Print help information",	modehelp, 0 },
115332144Sminshall     { 0 },
115432144Sminshall };
115532144Sminshall 
115632144Sminshall 
115746808Sdab     int
115838689Sborman modehelp()
115938689Sborman {
116038689Sborman     struct modelist *mt;
116138689Sborman 
116238689Sborman     printf("format is:  'mode Mode', where 'Mode' is one of:\n\n");
116338689Sborman     for (mt = ModeList; mt->name; mt++) {
116438689Sborman 	if (mt->help) {
116538689Sborman 	    if (*mt->help)
116638689Sborman 		printf("%-15s %s\n", mt->name, mt->help);
116738689Sborman 	    else
116838689Sborman 		printf("\n");
116938689Sborman 	}
117038689Sborman     }
117138689Sborman     return 0;
117238689Sborman }
117338689Sborman 
117446808Sdab #define	GETMODECMD(name) (struct modelist *) \
117546808Sdab 		genget(name, (char **) ModeList, sizeof(struct modelist))
117646808Sdab 
117746808Sdab     static int
117832144Sminshall modecmd(argc, argv)
117946808Sdab     int  argc;
118046808Sdab     char *argv[];
118132144Sminshall {
118238689Sborman     struct modelist *mt;
118332144Sminshall 
118438689Sborman     if (argc != 2) {
118538689Sborman 	printf("'mode' command requires an argument\n");
118638689Sborman 	printf("'mode ?' for help.\n");
118746808Sdab     } else if ((mt = GETMODECMD(argv[1])) == 0) {
118832144Sminshall 	fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]);
118932144Sminshall     } else if (Ambiguous(mt)) {
119032144Sminshall 	fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]);
119138689Sborman     } else if (mt->needconnect && !connected) {
119238689Sborman 	printf("?Need to be connected first.\n");
119338689Sborman 	printf("'mode ?' for help.\n");
119438689Sborman     } else if (mt->handler) {
119538689Sborman 	return (*mt->handler)(mt->arg1);
119632144Sminshall     }
119738689Sborman     return 0;
119832144Sminshall }
119932144Sminshall 
120032144Sminshall /*
120132144Sminshall  * The following data structures and routines implement the
120232144Sminshall  * "display" command.
120332144Sminshall  */
120432144Sminshall 
120546808Sdab     static int
120632144Sminshall display(argc, argv)
120746808Sdab     int  argc;
120846808Sdab     char *argv[];
120932144Sminshall {
121046808Sdab     struct togglelist *tl;
121146808Sdab     struct setlist *sl;
121246808Sdab 
121332144Sminshall #define	dotog(tl)	if (tl->variable && tl->actionexplanation) { \
121432144Sminshall 			    if (*tl->variable) { \
121532144Sminshall 				printf("will"); \
121632144Sminshall 			    } else { \
121732144Sminshall 				printf("won't"); \
121832144Sminshall 			    } \
121932144Sminshall 			    printf(" %s.\n", tl->actionexplanation); \
122032144Sminshall 			}
122132144Sminshall 
122232144Sminshall #define	doset(sl)   if (sl->name && *sl->name != ' ') { \
122338689Sborman 			if (sl->handler == 0) \
122438689Sborman 			    printf("%-15s [%s]\n", sl->name, control(*sl->charp)); \
122538689Sborman 			else \
122644361Sborman 			    printf("%-15s \"%s\"\n", sl->name, (char *)sl->charp); \
122732144Sminshall 		    }
122832144Sminshall 
122932144Sminshall     if (argc == 1) {
123032144Sminshall 	for (tl = Togglelist; tl->name; tl++) {
123132144Sminshall 	    dotog(tl);
123232144Sminshall 	}
123332144Sminshall 	printf("\n");
123432144Sminshall 	for (sl = Setlist; sl->name; sl++) {
123532144Sminshall 	    doset(sl);
123632144Sminshall 	}
123732144Sminshall     } else {
123832144Sminshall 	int i;
123932144Sminshall 
124032144Sminshall 	for (i = 1; i < argc; i++) {
124132144Sminshall 	    sl = getset(argv[i]);
124246808Sdab 	    tl = GETTOGGLE(argv[i]);
124332144Sminshall 	    if (Ambiguous(sl) || Ambiguous(tl)) {
124432144Sminshall 		printf("?Ambiguous argument '%s'.\n", argv[i]);
124532144Sminshall 		return 0;
124632144Sminshall 	    } else if (!sl && !tl) {
124732144Sminshall 		printf("?Unknown argument '%s'.\n", argv[i]);
124832144Sminshall 		return 0;
124932144Sminshall 	    } else {
125032144Sminshall 		if (tl) {
125132144Sminshall 		    dotog(tl);
125232144Sminshall 		}
125332144Sminshall 		if (sl) {
125432144Sminshall 		    doset(sl);
125532144Sminshall 		}
125632144Sminshall 	    }
125732144Sminshall 	}
125832144Sminshall     }
125938689Sborman /*@*/optionstatus();
126046808Sdab #if	defined(ENCRYPT)
126146808Sdab     EncryptStatus();
126246808Sdab #endif
126332144Sminshall     return 1;
126432144Sminshall #undef	doset
126532144Sminshall #undef	dotog
126632144Sminshall }
126732144Sminshall 
126832144Sminshall /*
126932144Sminshall  * The following are the data structures, and many of the routines,
127032144Sminshall  * relating to command processing.
127132144Sminshall  */
127232144Sminshall 
127332144Sminshall /*
127432144Sminshall  * Set the escape character.
127532144Sminshall  */
127646808Sdab 	static int
127732144Sminshall setescape(argc, argv)
127832144Sminshall 	int argc;
127932144Sminshall 	char *argv[];
128032144Sminshall {
128132144Sminshall 	register char *arg;
128232144Sminshall 	char buf[50];
128332144Sminshall 
128432144Sminshall 	printf(
128532144Sminshall 	    "Deprecated usage - please use 'set escape%s%s' in the future.\n",
128632144Sminshall 				(argc > 2)? " ":"", (argc > 2)? argv[1]: "");
128732144Sminshall 	if (argc > 2)
128832144Sminshall 		arg = argv[1];
128932144Sminshall 	else {
129032144Sminshall 		printf("new escape character: ");
129146808Sdab 		(void) fgets(buf, sizeof(buf), stdin);
129232144Sminshall 		arg = buf;
129332144Sminshall 	}
129432144Sminshall 	if (arg[0] != '\0')
129532144Sminshall 		escape = arg[0];
129632144Sminshall 	if (!In3270) {
129732144Sminshall 		printf("Escape character is '%s'.\n", control(escape));
129832144Sminshall 	}
129934849Sminshall 	(void) fflush(stdout);
130032144Sminshall 	return 1;
130132144Sminshall }
130232144Sminshall 
130346808Sdab     /*VARARGS*/
130446808Sdab     static int
130532144Sminshall togcrmod()
130632144Sminshall {
130732144Sminshall     crmod = !crmod;
130832144Sminshall     printf("Deprecated usage - please use 'toggle crmod' in the future.\n");
130932144Sminshall     printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't");
131034849Sminshall     (void) fflush(stdout);
131132144Sminshall     return 1;
131232144Sminshall }
131332144Sminshall 
131446808Sdab     /*VARARGS*/
131546808Sdab     int
131632144Sminshall suspend()
131732144Sminshall {
131838689Sborman #ifdef	SIGTSTP
131937219Sminshall     setcommandmode();
132037219Sminshall     {
132144361Sborman 	long oldrows, oldcols, newrows, newcols, err;
132237219Sminshall 
132344361Sborman 	err = TerminalWindowSize(&oldrows, &oldcols);
132434849Sminshall 	(void) kill(0, SIGTSTP);
132544361Sborman 	err += TerminalWindowSize(&newrows, &newcols);
132644361Sborman 	if (connected && !err &&
132744361Sborman 	    ((oldrows != newrows) || (oldcols != newcols))) {
132837219Sminshall 		sendnaws();
132937219Sminshall 	}
133037219Sminshall     }
133137219Sminshall     /* reget parameters in case they were changed */
133237219Sminshall     TerminalSaveState();
133338689Sborman     setconnmode(0);
133438689Sborman #else
133538689Sborman     printf("Suspend is not supported.  Try the '!' command instead\n");
133638689Sborman #endif
133737219Sminshall     return 1;
133832144Sminshall }
133932144Sminshall 
134038689Sborman #if	!defined(TN3270)
134146808Sdab     /*ARGSUSED*/
134246808Sdab     int
134338689Sborman shell(argc, argv)
134446808Sdab     int argc;
134546808Sdab     char *argv[];
134638689Sborman {
134738689Sborman     setcommandmode();
134838689Sborman     switch(vfork()) {
134938689Sborman     case -1:
135038689Sborman 	perror("Fork failed\n");
135138689Sborman 	break;
135238689Sborman 
135338689Sborman     case 0:
135438689Sborman 	{
135538689Sborman 	    /*
135638689Sborman 	     * Fire up the shell in the child.
135738689Sborman 	     */
135846808Sdab 	    register char *shellp, *shellname;
135946808Sdab 	    extern char *rindex();
136038689Sborman 
136146808Sdab 	    shellp = getenv("SHELL");
136246808Sdab 	    if (shellp == NULL)
136346808Sdab 		shellp = "/bin/sh";
136446808Sdab 	    if ((shellname = rindex(shellp, '/')) == 0)
136546808Sdab 		shellname = shellp;
136638689Sborman 	    else
136738689Sborman 		shellname++;
136838689Sborman 	    if (argc > 1)
136946808Sdab 		execl(shellp, shellname, "-c", &saveline[1], 0);
137038689Sborman 	    else
137146808Sdab 		execl(shellp, shellname, 0);
137238689Sborman 	    perror("Execl");
137338689Sborman 	    _exit(1);
137438689Sborman 	}
137538689Sborman     default:
137644361Sborman 	    (void)wait((int *)0);	/* Wait for the shell to complete */
137738689Sborman     }
137846808Sdab     return 1;
137938689Sborman }
138038689Sborman #endif	/* !defined(TN3270) */
138138689Sborman 
138246808Sdab     /*VARARGS*/
138346808Sdab     static
138432144Sminshall bye(argc, argv)
138546808Sdab     int  argc;		/* Number of arguments */
138646808Sdab     char *argv[];	/* arguments */
138732144Sminshall {
138846808Sdab     extern int resettermname;
138946808Sdab 
139032144Sminshall     if (connected) {
139134849Sminshall 	(void) shutdown(net, 2);
139232144Sminshall 	printf("Connection closed.\n");
139334849Sminshall 	(void) NetClose(net);
139432144Sminshall 	connected = 0;
139546808Sdab 	resettermname = 1;
139646808Sdab #if	defined(AUTHENTICATE) || defined(ENCRYPT)
139746808Sdab 	auth_encrypt_connect(connected);
139846808Sdab #endif
139932144Sminshall 	/* reset options */
140032144Sminshall 	tninit();
140132144Sminshall #if	defined(TN3270)
140232144Sminshall 	SetIn3270();		/* Get out of 3270 mode */
140332144Sminshall #endif	/* defined(TN3270) */
140432144Sminshall     }
140532144Sminshall     if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) {
140632144Sminshall 	longjmp(toplevel, 1);
140732144Sminshall 	/* NOTREACHED */
140832144Sminshall     }
140932144Sminshall     return 1;			/* Keep lint, etc., happy */
141032144Sminshall }
141132144Sminshall 
141232144Sminshall /*VARARGS*/
141332144Sminshall quit()
141432144Sminshall {
141532144Sminshall 	(void) call(bye, "bye", "fromquit", 0);
141632144Sminshall 	Exit(0);
141744361Sborman 	/*NOTREACHED*/
141832144Sminshall }
141946808Sdab 
142046808Sdab /*VARARGS*/
142146808Sdab 	int
142246808Sdab logout()
142346808Sdab {
142446808Sdab 	send_do(TELOPT_LOGOUT, 1);
142546808Sdab 	(void) netflush();
142646808Sdab 	return 1;
142746808Sdab }
142846808Sdab 
142938689Sborman 
143038689Sborman /*
143138689Sborman  * The SLC command.
143238689Sborman  */
143332144Sminshall 
143438689Sborman struct slclist {
143538689Sborman 	char	*name;
143638689Sborman 	char	*help;
143746808Sdab 	void	(*handler)();
143838689Sborman 	int	arg;
143938689Sborman };
144038689Sborman 
144156642Sralph static void slc_help();
144238689Sborman 
144338689Sborman struct slclist SlcList[] = {
144438689Sborman     { "export",	"Use local special character definitions",
144538689Sborman 						slc_mode_export,	0 },
144638689Sborman     { "import",	"Use remote special character definitions",
144738689Sborman 						slc_mode_import,	1 },
144838689Sborman     { "check",	"Verify remote special character definitions",
144938689Sborman 						slc_mode_import,	0 },
145038689Sborman     { "help",	0,				slc_help,		0 },
145138689Sborman     { "?",	"Print help information",	slc_help,		0 },
145238689Sborman     { 0 },
145338689Sborman };
145438689Sborman 
145546808Sdab     static void
145638689Sborman slc_help()
145738689Sborman {
145838689Sborman     struct slclist *c;
145938689Sborman 
146038689Sborman     for (c = SlcList; c->name; c++) {
146138689Sborman 	if (c->help) {
146238689Sborman 	    if (*c->help)
146338689Sborman 		printf("%-15s %s\n", c->name, c->help);
146438689Sborman 	    else
146538689Sborman 		printf("\n");
146638689Sborman 	}
146738689Sborman     }
146838689Sborman }
146938689Sborman 
147046808Sdab     static struct slclist *
147138689Sborman getslc(name)
147246808Sdab     char *name;
147338689Sborman {
147446808Sdab     return (struct slclist *)
147546808Sdab 		genget(name, (char **) SlcList, sizeof(struct slclist));
147638689Sborman }
147738689Sborman 
147846808Sdab     static
147938689Sborman slccmd(argc, argv)
148046808Sdab     int  argc;
148146808Sdab     char *argv[];
148238689Sborman {
148338689Sborman     struct slclist *c;
148438689Sborman 
148538689Sborman     if (argc != 2) {
148638689Sborman 	fprintf(stderr,
148738689Sborman 	    "Need an argument to 'slc' command.  'slc ?' for help.\n");
148838689Sborman 	return 0;
148938689Sborman     }
149038689Sborman     c = getslc(argv[1]);
149138689Sborman     if (c == 0) {
149238689Sborman         fprintf(stderr, "'%s': unknown argument ('slc ?' for help).\n",
149338689Sborman     				argv[1]);
149438689Sborman         return 0;
149538689Sborman     }
149638689Sborman     if (Ambiguous(c)) {
149738689Sborman         fprintf(stderr, "'%s': ambiguous argument ('slc ?' for help).\n",
149838689Sborman     				argv[1]);
149938689Sborman         return 0;
150038689Sborman     }
150138689Sborman     (*c->handler)(c->arg);
150238689Sborman     slcstate();
150338689Sborman     return 1;
150438689Sborman }
150544361Sborman 
150644361Sborman /*
150744361Sborman  * The ENVIRON command.
150844361Sborman  */
150938689Sborman 
151044361Sborman struct envlist {
151144361Sborman 	char	*name;
151244361Sborman 	char	*help;
151346808Sdab 	void	(*handler)();
151444361Sborman 	int	narg;
151544361Sborman };
151644361Sborman 
151746808Sdab extern struct env_lst *
151846808Sdab 	env_define P((unsigned char *, unsigned char *));
151946808Sdab extern void
152046808Sdab 	env_undefine P((unsigned char *)),
152146808Sdab 	env_export P((unsigned char *)),
152246808Sdab 	env_unexport P((unsigned char *)),
152346808Sdab 	env_send P((unsigned char *)),
152456642Sralph 	env_list P((void));
152556642Sralph static void
152646808Sdab 	env_help P((void));
152744361Sborman 
152844361Sborman struct envlist EnvList[] = {
152944361Sborman     { "define",	"Define an environment variable",
153046808Sdab 						(void (*)())env_define,	2 },
153144361Sborman     { "undefine", "Undefine an environment variable",
153244361Sborman 						env_undefine,	1 },
153344361Sborman     { "export",	"Mark an environment variable for automatic export",
153444361Sborman 						env_export,	1 },
153546808Sdab     { "unexport", "Don't mark an environment variable for automatic export",
153644361Sborman 						env_unexport,	1 },
153745233Sborman     { "send",	"Send an environment variable", env_send,	1 },
153844361Sborman     { "list",	"List the current environment variables",
153944361Sborman 						env_list,	0 },
154044361Sborman     { "help",	0,				env_help,		0 },
154144361Sborman     { "?",	"Print help information",	env_help,		0 },
154244361Sborman     { 0 },
154344361Sborman };
154444361Sborman 
154546808Sdab     static void
154644361Sborman env_help()
154744361Sborman {
154844361Sborman     struct envlist *c;
154944361Sborman 
155044361Sborman     for (c = EnvList; c->name; c++) {
155144361Sborman 	if (c->help) {
155244361Sborman 	    if (*c->help)
155344361Sborman 		printf("%-15s %s\n", c->name, c->help);
155444361Sborman 	    else
155544361Sborman 		printf("\n");
155644361Sborman 	}
155744361Sborman     }
155844361Sborman }
155944361Sborman 
156046808Sdab     static struct envlist *
156144361Sborman getenvcmd(name)
156246808Sdab     char *name;
156344361Sborman {
156446808Sdab     return (struct envlist *)
156546808Sdab 		genget(name, (char **) EnvList, sizeof(struct envlist));
156644361Sborman }
156744361Sborman 
156844361Sborman env_cmd(argc, argv)
156946808Sdab     int  argc;
157046808Sdab     char *argv[];
157144361Sborman {
157244361Sborman     struct envlist *c;
157344361Sborman 
157444361Sborman     if (argc < 2) {
157544361Sborman 	fprintf(stderr,
157644361Sborman 	    "Need an argument to 'environ' command.  'environ ?' for help.\n");
157744361Sborman 	return 0;
157844361Sborman     }
157944361Sborman     c = getenvcmd(argv[1]);
158044361Sborman     if (c == 0) {
158144361Sborman         fprintf(stderr, "'%s': unknown argument ('environ ?' for help).\n",
158244361Sborman     				argv[1]);
158344361Sborman         return 0;
158444361Sborman     }
158544361Sborman     if (Ambiguous(c)) {
158644361Sborman         fprintf(stderr, "'%s': ambiguous argument ('environ ?' for help).\n",
158744361Sborman     				argv[1]);
158844361Sborman         return 0;
158944361Sborman     }
159044361Sborman     if (c->narg + 2 != argc) {
159144361Sborman 	fprintf(stderr,
159244361Sborman 	    "Need %s%d argument%s to 'environ %s' command.  'environ ?' for help.\n",
159344361Sborman 		c->narg < argc + 2 ? "only " : "",
159444361Sborman 		c->narg, c->narg == 1 ? "" : "s", c->name);
159544361Sborman 	return 0;
159644361Sborman     }
159746808Sdab     (*c->handler)(argv[2], argv[3]);
159844361Sborman     return 1;
159944361Sborman }
160044361Sborman 
160144361Sborman struct env_lst {
160244361Sborman 	struct env_lst *next;	/* pointer to next structure */
160344361Sborman 	struct env_lst *prev;	/* pointer to next structure */
160446808Sdab 	unsigned char *var;	/* pointer to variable name */
160546808Sdab 	unsigned char *value;	/* pointer to varialbe value */
160644361Sborman 	int export;		/* 1 -> export with default list of variables */
160744361Sborman };
160844361Sborman 
160944361Sborman struct env_lst envlisthead;
161044361Sborman 
161146808Sdab 	struct env_lst *
161244361Sborman env_find(var)
161346808Sdab 	unsigned char *var;
161444361Sborman {
161544361Sborman 	register struct env_lst *ep;
161644361Sborman 
161744361Sborman 	for (ep = envlisthead.next; ep; ep = ep->next) {
161846808Sdab 		if (strcmp((char *)ep->var, (char *)var) == 0)
161944361Sborman 			return(ep);
162044361Sborman 	}
162144361Sborman 	return(NULL);
162244361Sborman }
162344361Sborman 
162446808Sdab 	void
162544361Sborman env_init()
162644361Sborman {
162746808Sdab 	extern char **environ;
162844361Sborman 	register char **epp, *cp;
162944361Sborman 	register struct env_lst *ep;
163046808Sdab 	extern char *index();
163144361Sborman 
163244361Sborman 	for (epp = environ; *epp; epp++) {
163344361Sborman 		if (cp = index(*epp, '=')) {
163444361Sborman 			*cp = '\0';
163546808Sdab 			ep = env_define((unsigned char *)*epp,
163646808Sdab 					(unsigned char *)cp+1);
163744361Sborman 			ep->export = 0;
163844361Sborman 			*cp = '=';
163944361Sborman 		}
164044361Sborman 	}
164144361Sborman 	/*
164244361Sborman 	 * Special case for DISPLAY variable.  If it is ":0.0" or
164344361Sborman 	 * "unix:0.0", we have to get rid of "unix" and insert our
164444361Sborman 	 * hostname.
164544361Sborman 	 */
164646808Sdab 	if ((ep = env_find("DISPLAY"))
164746808Sdab 	    && ((*ep->value == ':')
164846808Sdab 	        || (strncmp((char *)ep->value, "unix:", 5) == 0))) {
164944361Sborman 		char hbuf[256+1];
165046808Sdab 		char *cp2 = index((char *)ep->value, ':');
165144361Sborman 
165244361Sborman 		gethostname(hbuf, 256);
165344361Sborman 		hbuf[256] = '\0';
165444361Sborman 		cp = (char *)malloc(strlen(hbuf) + strlen(cp2) + 1);
165546808Sdab 		sprintf((char *)cp, "%s%s", hbuf, cp2);
165644361Sborman 		free(ep->value);
165746808Sdab 		ep->value = (unsigned char *)cp;
165844361Sborman 	}
165944361Sborman 	/*
166044361Sborman 	 * If USER is not defined, but LOGNAME is, then add
166145233Sborman 	 * USER with the value from LOGNAME.  By default, we
166245233Sborman 	 * don't export the USER variable.
166344361Sborman 	 */
166445233Sborman 	if ((env_find("USER") == NULL) && (ep = env_find("LOGNAME"))) {
166546808Sdab 		env_define((unsigned char *)"USER", ep->value);
166646808Sdab 		env_unexport((unsigned char *)"USER");
166745233Sborman 	}
166846808Sdab 	env_export((unsigned char *)"DISPLAY");
166946808Sdab 	env_export((unsigned char *)"PRINTER");
167044361Sborman }
167144361Sborman 
167246808Sdab 	struct env_lst *
167344361Sborman env_define(var, value)
167446808Sdab 	unsigned char *var, *value;
167544361Sborman {
167644361Sborman 	register struct env_lst *ep;
167744361Sborman 
167844361Sborman 	if (ep = env_find(var)) {
167944361Sborman 		if (ep->var)
168044361Sborman 			free(ep->var);
168144361Sborman 		if (ep->value)
168244361Sborman 			free(ep->value);
168344361Sborman 	} else {
168444361Sborman 		ep = (struct env_lst *)malloc(sizeof(struct env_lst));
168544361Sborman 		ep->next = envlisthead.next;
168644361Sborman 		envlisthead.next = ep;
168744361Sborman 		ep->prev = &envlisthead;
168844361Sborman 		if (ep->next)
168944361Sborman 			ep->next->prev = ep;
169044361Sborman 	}
169145009Skarels 	ep->export = 1;
169246808Sdab 	ep->var = (unsigned char *)strdup((char *)var);
169346808Sdab 	ep->value = (unsigned char *)strdup((char *)value);
169444361Sborman 	return(ep);
169544361Sborman }
169644361Sborman 
169746808Sdab 	void
169844361Sborman env_undefine(var)
169946808Sdab 	unsigned char *var;
170044361Sborman {
170144361Sborman 	register struct env_lst *ep;
170244361Sborman 
170344361Sborman 	if (ep = env_find(var)) {
170444361Sborman 		ep->prev->next = ep->next;
170545233Sborman 		if (ep->next)
170645233Sborman 			ep->next->prev = ep->prev;
170744361Sborman 		if (ep->var)
170844361Sborman 			free(ep->var);
170944361Sborman 		if (ep->value)
171044361Sborman 			free(ep->value);
171144361Sborman 		free(ep);
171244361Sborman 	}
171344361Sborman }
171444361Sborman 
171546808Sdab 	void
171644361Sborman env_export(var)
171746808Sdab 	unsigned char *var;
171844361Sborman {
171944361Sborman 	register struct env_lst *ep;
172044361Sborman 
172144361Sborman 	if (ep = env_find(var))
172244361Sborman 		ep->export = 1;
172344361Sborman }
172444361Sborman 
172546808Sdab 	void
172644361Sborman env_unexport(var)
172746808Sdab 	unsigned char *var;
172844361Sborman {
172944361Sborman 	register struct env_lst *ep;
173044361Sborman 
173144361Sborman 	if (ep = env_find(var))
173244361Sborman 		ep->export = 0;
173344361Sborman }
173444361Sborman 
173546808Sdab 	void
173645233Sborman env_send(var)
173746808Sdab 	unsigned char *var;
173845233Sborman {
173945233Sborman 	register struct env_lst *ep;
174045233Sborman 
174145233Sborman         if (my_state_is_wont(TELOPT_ENVIRON)) {
174245233Sborman 		fprintf(stderr,
174345233Sborman 		    "Cannot send '%s': Telnet ENVIRON option not enabled\n",
174445233Sborman 									var);
174545233Sborman 		return;
174645233Sborman 	}
174745233Sborman 	ep = env_find(var);
174845233Sborman 	if (ep == 0) {
174945233Sborman 		fprintf(stderr, "Cannot send '%s': variable not defined\n",
175045233Sborman 									var);
175145233Sborman 		return;
175245233Sborman 	}
175345233Sborman 	env_opt_start_info();
175445233Sborman 	env_opt_add(ep->var);
175545233Sborman 	env_opt_end(0);
175645233Sborman }
175745233Sborman 
175846808Sdab 	void
175944361Sborman env_list()
176044361Sborman {
176144361Sborman 	register struct env_lst *ep;
176244361Sborman 
176344361Sborman 	for (ep = envlisthead.next; ep; ep = ep->next) {
176444361Sborman 		printf("%c %-20s %s\n", ep->export ? '*' : ' ',
176544361Sborman 					ep->var, ep->value);
176644361Sborman 	}
176744361Sborman }
176844361Sborman 
176946808Sdab 	unsigned char *
177044361Sborman env_default(init)
177146808Sdab 	int init;
177244361Sborman {
177344361Sborman 	static struct env_lst *nep = NULL;
177444361Sborman 
177544361Sborman 	if (init) {
177644361Sborman 		nep = &envlisthead;
177744361Sborman 		return;
177844361Sborman 	}
177944361Sborman 	if (nep) {
178044361Sborman 		while (nep = nep->next) {
178144361Sborman 			if (nep->export)
178244361Sborman 				return(nep->var);
178344361Sborman 		}
178444361Sborman 	}
178544361Sborman 	return(NULL);
178644361Sborman }
178744361Sborman 
178846808Sdab 	unsigned char *
178944361Sborman env_getvalue(var)
179046808Sdab 	unsigned char *var;
179144361Sborman {
179244361Sborman 	register struct env_lst *ep;
179344361Sborman 
179444361Sborman 	if (ep = env_find(var))
179544361Sborman 		return(ep->value);
179644361Sborman 	return(NULL);
179744361Sborman }
179844361Sborman 
179946808Sdab #if	defined(AUTHENTICATE)
180046808Sdab /*
180146808Sdab  * The AUTHENTICATE command.
180246808Sdab  */
180346808Sdab 
180446808Sdab struct authlist {
180546808Sdab 	char	*name;
180646808Sdab 	char	*help;
180746808Sdab 	int	(*handler)();
180846808Sdab 	int	narg;
180946808Sdab };
181046808Sdab 
181146808Sdab extern int
181246808Sdab 	auth_enable P((int)),
181346808Sdab 	auth_disable P((int)),
181456642Sralph 	auth_status P((void));
181556642Sralph static int
181646808Sdab 	auth_help P((void));
181746808Sdab 
181846808Sdab struct authlist AuthList[] = {
181946808Sdab     { "status",	"Display current status of authentication information",
182046808Sdab 						auth_status,	0 },
182146808Sdab     { "disable", "Disable an authentication type ('auth disable ?' for more)",
182246808Sdab 						auth_disable,	1 },
182346808Sdab     { "enable", "Enable an authentication type ('auth enable ?' for more)",
182446808Sdab 						auth_enable,	1 },
182546808Sdab     { "help",	0,				auth_help,		0 },
182646808Sdab     { "?",	"Print help information",	auth_help,		0 },
182746808Sdab     { 0 },
182846808Sdab };
182946808Sdab 
183046808Sdab     static int
183146808Sdab auth_help()
183244361Sborman {
183346808Sdab     struct authlist *c;
183446808Sdab 
183546808Sdab     for (c = AuthList; c->name; c++) {
183646808Sdab 	if (c->help) {
183746808Sdab 	    if (*c->help)
183846808Sdab 		printf("%-15s %s\n", c->name, c->help);
183946808Sdab 	    else
184046808Sdab 		printf("\n");
184146808Sdab 	}
184246808Sdab     }
184346808Sdab     return 0;
184444361Sborman }
184546808Sdab 
184646808Sdab auth_cmd(argc, argv)
184746808Sdab     int  argc;
184846808Sdab     char *argv[];
184946808Sdab {
185046808Sdab     struct authlist *c;
185146808Sdab 
185246808Sdab     c = (struct authlist *)
185346808Sdab 		genget(argv[1], (char **) AuthList, sizeof(struct authlist));
185446808Sdab     if (c == 0) {
185546808Sdab         fprintf(stderr, "'%s': unknown argument ('auth ?' for help).\n",
185646808Sdab     				argv[1]);
185746808Sdab         return 0;
185846808Sdab     }
185946808Sdab     if (Ambiguous(c)) {
186046808Sdab         fprintf(stderr, "'%s': ambiguous argument ('auth ?' for help).\n",
186146808Sdab     				argv[1]);
186246808Sdab         return 0;
186346808Sdab     }
186446808Sdab     if (c->narg + 2 != argc) {
186546808Sdab 	fprintf(stderr,
186646808Sdab 	    "Need %s%d argument%s to 'auth %s' command.  'auth ?' for help.\n",
186746808Sdab 		c->narg < argc + 2 ? "only " : "",
186846808Sdab 		c->narg, c->narg == 1 ? "" : "s", c->name);
186946808Sdab 	return 0;
187046808Sdab     }
187146808Sdab     return((*c->handler)(argv[2], argv[3]));
187246808Sdab }
187345233Sborman #endif
187444361Sborman 
187546808Sdab #if	defined(ENCRYPT)
187632144Sminshall /*
187746808Sdab  * The ENCRYPT command.
187836274Sminshall  */
187936274Sminshall 
188046808Sdab struct encryptlist {
188146808Sdab 	char	*name;
188246808Sdab 	char	*help;
188346808Sdab 	int	(*handler)();
188446808Sdab 	int	needconnect;
188546808Sdab 	int	minarg;
188646808Sdab 	int	maxarg;
188746808Sdab };
188846808Sdab 
188946808Sdab extern int
189046808Sdab 	EncryptEnable P((char *, char *)),
189147609Sdab 	EncryptDisable P((char *, char *)),
189246808Sdab 	EncryptType P((char *, char *)),
189346808Sdab 	EncryptStart P((char *)),
189446808Sdab 	EncryptStartInput P((void)),
189546808Sdab 	EncryptStartOutput P((void)),
189646808Sdab 	EncryptStop P((char *)),
189746808Sdab 	EncryptStopInput P((void)),
189846808Sdab 	EncryptStopOutput P((void)),
189956642Sralph 	EncryptStatus P((void));
190056642Sralph static int
190146808Sdab 	EncryptHelp P((void));
190246808Sdab 
190346808Sdab struct encryptlist EncryptList[] = {
190446808Sdab     { "enable", "Enable encryption. ('encrypt enable ?' for more)",
190546808Sdab 						EncryptEnable, 1, 1, 2 },
190647609Sdab     { "disable", "Disable encryption. ('encrypt enable ?' for more)",
190747609Sdab 						EncryptDisable, 0, 1, 2 },
190846808Sdab     { "type", "Set encryptiong type. ('encrypt type ?' for more)",
190946808Sdab 						EncryptType, 0, 1, 1 },
191046808Sdab     { "start", "Start encryption. ('encrypt start ?' for more)",
191146808Sdab 						EncryptStart, 1, 0, 1 },
191246808Sdab     { "stop", "Stop encryption. ('encrypt stop ?' for more)",
191346808Sdab 						EncryptStop, 1, 0, 1 },
191446808Sdab     { "input", "Start encrypting the input stream",
191546808Sdab 						EncryptStartInput, 1, 0, 0 },
191646808Sdab     { "-input", "Stop encrypting the input stream",
191746808Sdab 						EncryptStopInput, 1, 0, 0 },
191846808Sdab     { "output", "Start encrypting the output stream",
191946808Sdab 						EncryptStartOutput, 1, 0, 0 },
192046808Sdab     { "-output", "Stop encrypting the output stream",
192146808Sdab 						EncryptStopOutput, 1, 0, 0 },
192246808Sdab 
192346808Sdab     { "status",	"Display current status of authentication information",
192446808Sdab 						EncryptStatus,	0, 0, 0 },
192546808Sdab     { "help",	0,				EncryptHelp,	0, 0, 0 },
192646808Sdab     { "?",	"Print help information",	EncryptHelp,	0, 0, 0 },
192746808Sdab     { 0 },
192846808Sdab };
192946808Sdab 
193046808Sdab     static int
193146808Sdab EncryptHelp()
193236274Sminshall {
193346808Sdab     struct encryptlist *c;
193446808Sdab 
193546808Sdab     for (c = EncryptList; c->name; c++) {
193646808Sdab 	if (c->help) {
193746808Sdab 	    if (*c->help)
193846808Sdab 		printf("%-15s %s\n", c->name, c->help);
193946808Sdab 	    else
194046808Sdab 		printf("\n");
194136274Sminshall 	}
194246808Sdab     }
194346808Sdab     return 0;
194446808Sdab }
194536274Sminshall 
194646808Sdab encrypt_cmd(argc, argv)
194746808Sdab     int  argc;
194846808Sdab     char *argv[];
194946808Sdab {
195046808Sdab     struct encryptlist *c;
195136274Sminshall 
195246808Sdab     c = (struct encryptlist *)
195346808Sdab 		genget(argv[1], (char **) EncryptList, sizeof(struct encryptlist));
195446808Sdab     if (c == 0) {
195546808Sdab         fprintf(stderr, "'%s': unknown argument ('encrypt ?' for help).\n",
195646808Sdab     				argv[1]);
195746808Sdab         return 0;
195846808Sdab     }
195946808Sdab     if (Ambiguous(c)) {
196046808Sdab         fprintf(stderr, "'%s': ambiguous argument ('encrypt ?' for help).\n",
196146808Sdab     				argv[1]);
196246808Sdab         return 0;
196346808Sdab     }
196446808Sdab     argc -= 2;
196546808Sdab     if (argc < c->minarg || argc > c->maxarg) {
196646808Sdab 	if (c->minarg == c->maxarg) {
196746808Sdab 	    fprintf(stderr, "Need %s%d argument%s ",
196846808Sdab 		c->minarg < argc ? "only " : "", c->minarg,
196946808Sdab 		c->minarg == 1 ? "" : "s");
197046808Sdab 	} else {
197146808Sdab 	    fprintf(stderr, "Need %s%d-%d arguments ",
197246808Sdab 		c->maxarg < argc ? "only " : "", c->minarg, c->maxarg);
197346808Sdab 	}
197446808Sdab 	fprintf(stderr, "to 'encrypt %s' command.  'encrypt ?' for help.\n",
197546808Sdab 		c->name);
197646808Sdab 	return 0;
197746808Sdab     }
197846808Sdab     if (c->needconnect && !connected) {
197946808Sdab 	if (!(argc && (isprefix(argv[2], "help") || isprefix(argv[2], "?")))) {
198046808Sdab 	    printf("?Need to be connected first.\n");
198146808Sdab 	    return 0;
198246808Sdab 	}
198346808Sdab     }
198446808Sdab     return ((*c->handler)(argc > 0 ? argv[2] : 0,
198546808Sdab 			argc > 1 ? argv[3] : 0,
198646808Sdab 			argc > 2 ? argv[4] : 0));
198746808Sdab }
198836274Sminshall #endif
198936274Sminshall 
199046808Sdab #if	defined(unix) && defined(TN3270)
199146808Sdab     static void
199236274Sminshall filestuff(fd)
199346808Sdab     int fd;
199436274Sminshall {
199536274Sminshall     int res;
199636274Sminshall 
199738689Sborman #ifdef	F_GETOWN
199838689Sborman     setconnmode(0);
199936274Sminshall     res = fcntl(fd, F_GETOWN, 0);
200036274Sminshall     setcommandmode();
200136274Sminshall 
200236274Sminshall     if (res == -1) {
200336274Sminshall 	perror("fcntl");
200436274Sminshall 	return;
200536274Sminshall     }
200636274Sminshall     printf("\tOwner is %d.\n", res);
200738689Sborman #endif
200836274Sminshall 
200938689Sborman     setconnmode(0);
201036274Sminshall     res = fcntl(fd, F_GETFL, 0);
201136274Sminshall     setcommandmode();
201236274Sminshall 
201336274Sminshall     if (res == -1) {
201436274Sminshall 	perror("fcntl");
201536274Sminshall 	return;
201636274Sminshall     }
201736274Sminshall     printf("\tFlags are 0x%x: %s\n", res, decodeflags(res));
201836274Sminshall }
201946808Sdab #endif /* defined(unix) && defined(TN3270) */
202036274Sminshall 
202136274Sminshall /*
202232144Sminshall  * Print status about the connection.
202332144Sminshall  */
202446808Sdab     /*ARGSUSED*/
202546808Sdab     static
202632144Sminshall status(argc, argv)
202746808Sdab     int	 argc;
202846808Sdab     char *argv[];
202932144Sminshall {
203032144Sminshall     if (connected) {
203132144Sminshall 	printf("Connected to %s.\n", hostname);
203236242Sminshall 	if ((argc < 2) || strcmp(argv[1], "notmuch")) {
203338689Sborman 	    int mode = getconnmode();
203438689Sborman 
203538689Sborman 	    if (my_want_state_is_will(TELOPT_LINEMODE)) {
203638689Sborman 		printf("Operating with LINEMODE option\n");
203738689Sborman 		printf("%s line editing\n", (mode&MODE_EDIT) ? "Local" : "No");
203838689Sborman 		printf("%s catching of signals\n",
203938689Sborman 					(mode&MODE_TRAPSIG) ? "Local" : "No");
204038689Sborman 		slcstate();
204138689Sborman #ifdef	KLUDGELINEMODE
204239529Sborman 	    } else if (kludgelinemode && my_want_state_is_dont(TELOPT_SGA)) {
204338689Sborman 		printf("Operating in obsolete linemode\n");
204438689Sborman #endif
204538689Sborman 	    } else {
204638689Sborman 		printf("Operating in single character mode\n");
204738689Sborman 		if (localchars)
204838689Sborman 		    printf("Catching signals locally\n");
204932144Sminshall 	    }
205038689Sborman 	    printf("%s character echo\n", (mode&MODE_ECHO) ? "Local" : "Remote");
205138689Sborman 	    if (my_want_state_is_will(TELOPT_LFLOW))
205238689Sborman 		printf("%s flow control\n", (mode&MODE_FLOW) ? "Local" : "No");
205346808Sdab #if	defined(ENCRYPT)
205446808Sdab 	    encrypt_display();
205546808Sdab #endif
205632144Sminshall 	}
205732144Sminshall     } else {
205832144Sminshall 	printf("No connection.\n");
205932144Sminshall     }
206032144Sminshall #   if !defined(TN3270)
206132144Sminshall     printf("Escape character is '%s'.\n", control(escape));
206234849Sminshall     (void) fflush(stdout);
206332144Sminshall #   else /* !defined(TN3270) */
206432144Sminshall     if ((!In3270) && ((argc < 2) || strcmp(argv[1], "notmuch"))) {
206532144Sminshall 	printf("Escape character is '%s'.\n", control(escape));
206632144Sminshall     }
206732144Sminshall #   if defined(unix)
206836242Sminshall     if ((argc >= 2) && !strcmp(argv[1], "everything")) {
206936242Sminshall 	printf("SIGIO received %d time%s.\n",
207036242Sminshall 				sigiocount, (sigiocount == 1)? "":"s");
207136274Sminshall 	if (In3270) {
207236274Sminshall 	    printf("Process ID %d, process group %d.\n",
207336274Sminshall 					    getpid(), getpgrp(getpid()));
207436274Sminshall 	    printf("Terminal input:\n");
207536274Sminshall 	    filestuff(tin);
207636274Sminshall 	    printf("Terminal output:\n");
207736274Sminshall 	    filestuff(tout);
207836274Sminshall 	    printf("Network socket:\n");
207936274Sminshall 	    filestuff(net);
208036274Sminshall 	}
208136242Sminshall     }
208232144Sminshall     if (In3270 && transcom) {
208332144Sminshall        printf("Transparent mode command is '%s'.\n", transcom);
208432144Sminshall     }
208532144Sminshall #   endif /* defined(unix) */
208634849Sminshall     (void) fflush(stdout);
208732144Sminshall     if (In3270) {
208832144Sminshall 	return 0;
208932144Sminshall     }
209032144Sminshall #   endif /* defined(TN3270) */
209132144Sminshall     return 1;
209232144Sminshall }
209332144Sminshall 
209445233Sborman #ifdef	SIGINFO
209545233Sborman /*
209645233Sborman  * Function that gets called when SIGINFO is received.
209745233Sborman  */
209845233Sborman ayt_status()
209945233Sborman {
210045233Sborman     (void) call(status, "status", "notmuch", 0);
210145233Sborman }
210245233Sborman #endif
210332144Sminshall 
210446808Sdab     int
210532144Sminshall tn(argc, argv)
210646808Sdab     int argc;
210746808Sdab     char *argv[];
210832144Sminshall {
210932144Sminshall     register struct hostent *host = 0;
211032144Sminshall     struct sockaddr_in sin;
211132144Sminshall     struct servent *sp = 0;
211238689Sborman     unsigned long temp, inet_addr();
211337219Sminshall     extern char *inet_ntoa();
211446808Sdab #if	defined(IP_OPTIONS) && defined(IPPROTO_IP)
211538689Sborman     char *srp = 0, *strrchr();
211638689Sborman     unsigned long sourceroute(), srlen;
211738689Sborman #endif
211844361Sborman     char *cmd, *hostp = 0, *portp = 0, *user = 0;
211932144Sminshall 
212045233Sborman     /* clear the socket address prior to use */
212145233Sborman     bzero((char *)&sin, sizeof(sin));
212232144Sminshall 
212332144Sminshall     if (connected) {
212432144Sminshall 	printf("?Already connected to %s\n", hostname);
212546808Sdab 	setuid(getuid());
212632144Sminshall 	return 0;
212732144Sminshall     }
212832144Sminshall     if (argc < 2) {
212946808Sdab 	(void) strcpy(line, "open ");
213032144Sminshall 	printf("(to) ");
213146808Sdab 	(void) fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin);
213232144Sminshall 	makeargv();
213332144Sminshall 	argc = margc;
213432144Sminshall 	argv = margv;
213532144Sminshall     }
213644361Sborman     cmd = *argv;
213744361Sborman     --argc; ++argv;
213844361Sborman     while (argc) {
213946808Sdab 	if (isprefix(*argv, "help") || isprefix(*argv, "?"))
214046808Sdab 	    goto usage;
214144361Sborman 	if (strcmp(*argv, "-l") == 0) {
214244361Sborman 	    --argc; ++argv;
214344361Sborman 	    if (argc == 0)
214444361Sborman 		goto usage;
214544361Sborman 	    user = *argv++;
214644361Sborman 	    --argc;
214744361Sborman 	    continue;
214844361Sborman 	}
214945233Sborman 	if (strcmp(*argv, "-a") == 0) {
215045233Sborman 	    --argc; ++argv;
215145233Sborman 	    autologin = 1;
215245233Sborman 	    continue;
215345233Sborman 	}
215444361Sborman 	if (hostp == 0) {
215544361Sborman 	    hostp = *argv++;
215644361Sborman 	    --argc;
215744361Sborman 	    continue;
215844361Sborman 	}
215944361Sborman 	if (portp == 0) {
216044361Sborman 	    portp = *argv++;
216144361Sborman 	    --argc;
216244361Sborman 	    continue;
216344361Sborman 	}
216444361Sborman     usage:
216545233Sborman 	printf("usage: %s [-l user] [-a] host-name [port]\n", cmd);
216646808Sdab 	setuid(getuid());
216732144Sminshall 	return 0;
216832144Sminshall     }
216946808Sdab     if (hostp == 0)
217046808Sdab 	goto usage;
217146808Sdab 
217246808Sdab #if	defined(IP_OPTIONS) && defined(IPPROTO_IP)
217344361Sborman     if (hostp[0] == '@' || hostp[0] == '!') {
217444361Sborman 	if ((hostname = strrchr(hostp, ':')) == NULL)
217544361Sborman 	    hostname = strrchr(hostp, '@');
217638689Sborman 	hostname++;
217738689Sborman 	srp = 0;
217844361Sborman 	temp = sourceroute(hostp, &srp, &srlen);
217938689Sborman 	if (temp == 0) {
218038689Sborman 	    herror(srp);
218146808Sdab 	    setuid(getuid());
218238689Sborman 	    return 0;
218338689Sborman 	} else if (temp == -1) {
218444361Sborman 	    printf("Bad source route option: %s\n", hostp);
218546808Sdab 	    setuid(getuid());
218638689Sborman 	    return 0;
218738689Sborman 	} else {
218838689Sborman 	    sin.sin_addr.s_addr = temp;
218938689Sborman 	    sin.sin_family = AF_INET;
219038689Sborman 	}
219132144Sminshall     } else {
219238689Sborman #endif
219344361Sborman 	temp = inet_addr(hostp);
219438689Sborman 	if (temp != (unsigned long) -1) {
219538689Sborman 	    sin.sin_addr.s_addr = temp;
219638689Sborman 	    sin.sin_family = AF_INET;
219746808Sdab 	    (void) strcpy(_hostname, hostp);
219846808Sdab 	    hostname = _hostname;
219938689Sborman 	} else {
220044361Sborman 	    host = gethostbyname(hostp);
220138689Sborman 	    if (host) {
220238689Sborman 		sin.sin_family = host->h_addrtype;
220332144Sminshall #if	defined(h_addr)		/* In 4.3, this is a #define */
220438689Sborman 		memcpy((caddr_t)&sin.sin_addr,
220532144Sminshall 				host->h_addr_list[0], host->h_length);
220632144Sminshall #else	/* defined(h_addr) */
220738689Sborman 		memcpy((caddr_t)&sin.sin_addr, host->h_addr, host->h_length);
220832144Sminshall #endif	/* defined(h_addr) */
220946808Sdab 		strncpy(_hostname, host->h_name, sizeof(_hostname));
221046808Sdab 		_hostname[sizeof(_hostname)-1] = '\0';
221146808Sdab 		hostname = _hostname;
221238689Sborman 	    } else {
221344361Sborman 		herror(hostp);
221446808Sdab 	        setuid(getuid());
221538689Sborman 		return 0;
221638689Sborman 	    }
221732144Sminshall 	}
221846808Sdab #if	defined(IP_OPTIONS) && defined(IPPROTO_IP)
221932144Sminshall     }
222038689Sborman #endif
222144361Sborman     if (portp) {
222244361Sborman 	if (*portp == '-') {
222344361Sborman 	    portp++;
222438689Sborman 	    telnetport = 1;
222538689Sborman 	} else
222638689Sborman 	    telnetport = 0;
222744361Sborman 	sin.sin_port = atoi(portp);
222832144Sminshall 	if (sin.sin_port == 0) {
222944361Sborman 	    sp = getservbyname(portp, "tcp");
223032144Sminshall 	    if (sp)
223132144Sminshall 		sin.sin_port = sp->s_port;
223232144Sminshall 	    else {
223344361Sborman 		printf("%s: bad port number\n", portp);
223446808Sdab 	        setuid(getuid());
223532144Sminshall 		return 0;
223632144Sminshall 	    }
223732144Sminshall 	} else {
223832144Sminshall 	    sin.sin_port = htons(sin.sin_port);
223932144Sminshall 	}
224032144Sminshall     } else {
224132144Sminshall 	if (sp == 0) {
224232144Sminshall 	    sp = getservbyname("telnet", "tcp");
224332144Sminshall 	    if (sp == 0) {
224434849Sminshall 		fprintf(stderr, "telnet: tcp/telnet: unknown service\n");
224546808Sdab 	        setuid(getuid());
224632144Sminshall 		return 0;
224732144Sminshall 	    }
224832144Sminshall 	    sin.sin_port = sp->s_port;
224932144Sminshall 	}
225032144Sminshall 	telnetport = 1;
225132144Sminshall     }
225237219Sminshall     printf("Trying %s...\n", inet_ntoa(sin.sin_addr));
225332144Sminshall     do {
225432144Sminshall 	net = socket(AF_INET, SOCK_STREAM, 0);
225546808Sdab 	setuid(getuid());
225632144Sminshall 	if (net < 0) {
225732144Sminshall 	    perror("telnet: socket");
225832144Sminshall 	    return 0;
225932144Sminshall 	}
226046808Sdab #if	defined(IP_OPTIONS) && defined(IPPROTO_IP)
226138689Sborman 	if (srp && setsockopt(net, IPPROTO_IP, IP_OPTIONS, (char *)srp, srlen) < 0)
226238689Sborman 		perror("setsockopt (IP_OPTIONS)");
226338689Sborman #endif
226446808Sdab #if	defined(IPPROTO_IP) && defined(IP_TOS)
226546808Sdab 	{
226646808Sdab # if	defined(HAS_GETTOS)
226746808Sdab 	    struct tosent *tp;
226846815Sdab 	    if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
226946808Sdab 		tos = tp->t_tos;
227046808Sdab # endif
227146815Sdab 	    if (tos < 0)
227246815Sdab 		tos = 020;	/* Low Delay bit */
227346815Sdab 	    if (tos
227446815Sdab 		&& (setsockopt(net, IPPROTO_IP, IP_TOS, &tos, sizeof(int)) < 0)
227546815Sdab 		&& (errno != ENOPROTOOPT))
227646815Sdab 		    perror("telnet: setsockopt (IP_TOS) (ignored)");
227746808Sdab 	}
227846808Sdab #endif	/* defined(IPPROTO_IP) && defined(IP_TOS) */
227940245Sborman 
228032144Sminshall 	if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) {
228132144Sminshall 		perror("setsockopt (SO_DEBUG)");
228232144Sminshall 	}
228332144Sminshall 
228432144Sminshall 	if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
228532144Sminshall #if	defined(h_addr)		/* In 4.3, this is a #define */
228632144Sminshall 	    if (host && host->h_addr_list[1]) {
228732144Sminshall 		int oerrno = errno;
228832144Sminshall 
228932144Sminshall 		fprintf(stderr, "telnet: connect to address %s: ",
229032144Sminshall 						inet_ntoa(sin.sin_addr));
229132144Sminshall 		errno = oerrno;
229232144Sminshall 		perror((char *)0);
229332144Sminshall 		host->h_addr_list++;
229432144Sminshall 		memcpy((caddr_t)&sin.sin_addr,
229532144Sminshall 			host->h_addr_list[0], host->h_length);
229632144Sminshall 		(void) NetClose(net);
229732144Sminshall 		continue;
229832144Sminshall 	    }
229932144Sminshall #endif	/* defined(h_addr) */
230032144Sminshall 	    perror("telnet: Unable to connect to remote host");
230132144Sminshall 	    return 0;
230237219Sminshall 	}
230332144Sminshall 	connected++;
230446808Sdab #if	defined(AUTHENTICATE) || defined(ENCRYPT)
230546808Sdab 	auth_encrypt_connect(connected);
230646808Sdab #endif
230732144Sminshall     } while (connected == 0);
230844361Sborman     cmdrc(hostp, hostname);
230945008Skarels     if (autologin && user == NULL) {
231045008Skarels 	struct passwd *pw;
231145008Skarels 
231245233Sborman 	user = getenv("USER");
231345008Skarels 	if (user == NULL ||
231445233Sborman 	    (pw = getpwnam(user)) && pw->pw_uid != getuid()) {
231545233Sborman 		if (pw = getpwuid(getuid()))
231645008Skarels 			user = pw->pw_name;
231745008Skarels 		else
231845008Skarels 			user = NULL;
231945233Sborman 	}
232045008Skarels     }
232145008Skarels     if (user) {
232246808Sdab 	env_define((unsigned char *)"USER", (unsigned char *)user);
232346808Sdab 	env_export((unsigned char *)"USER");
232445008Skarels     }
232534849Sminshall     (void) call(status, "status", "notmuch", 0);
232632144Sminshall     if (setjmp(peerdied) == 0)
232746808Sdab 	telnet(user);
232834849Sminshall     (void) NetClose(net);
232932381Sminshall     ExitString("Connection closed by foreign host.\n",1);
233032144Sminshall     /*NOTREACHED*/
233132144Sminshall }
233232144Sminshall 
233332144Sminshall #define HELPINDENT (sizeof ("connect"))
233432144Sminshall 
233532144Sminshall static char
233632144Sminshall 	openhelp[] =	"connect to a site",
233732144Sminshall 	closehelp[] =	"close current connection",
233846808Sdab 	logouthelp[] =	"forcibly logout remote user and close the connection",
233932144Sminshall 	quithelp[] =	"exit telnet",
234032144Sminshall 	statushelp[] =	"print status information",
234132144Sminshall 	helphelp[] =	"print help information",
234232144Sminshall 	sendhelp[] =	"transmit special characters ('send ?' for more)",
234332144Sminshall 	sethelp[] = 	"set operating parameters ('set ?' for more)",
234438689Sborman 	unsethelp[] = 	"unset operating parameters ('unset ?' for more)",
234532144Sminshall 	togglestring[] ="toggle operating parameters ('toggle ?' for more)",
234638689Sborman 	slchelp[] =	"change state of special charaters ('slc ?' for more)",
234732144Sminshall 	displayhelp[] =	"display operating parameters",
234832144Sminshall #if	defined(TN3270) && defined(unix)
234932144Sminshall 	transcomhelp[] = "specify Unix command for transparent mode pipe",
235032144Sminshall #endif	/* defined(TN3270) && defined(unix) */
235146808Sdab #if	defined(AUTHENTICATE)
235246808Sdab 	authhelp[] =	"turn on (off) authentication ('auth ?' for more)",
235346808Sdab #endif
235446808Sdab #if	defined(ENCRYPT)
235546808Sdab 	encrypthelp[] =	"turn on (off) encryption ('encrypt ?' for more)",
235646808Sdab #endif
235732144Sminshall #if	defined(unix)
235832144Sminshall 	zhelp[] =	"suspend telnet",
235943317Skfall #endif	/* defined(unix) */
236032144Sminshall 	shellhelp[] =	"invoke a subshell",
236144361Sborman 	envhelp[] =	"change environment variables ('environ ?' for more)",
236244361Sborman 	modestring[] = "try to enter line or character mode ('mode ?' for more)";
236332144Sminshall 
236456642Sralph static int	help();
236532144Sminshall 
236632144Sminshall static Command cmdtab[] = {
236738689Sborman 	{ "close",	closehelp,	bye,		1 },
236846808Sdab 	{ "logout",	logouthelp,	logout,		1 },
236938689Sborman 	{ "display",	displayhelp,	display,	0 },
237038689Sborman 	{ "mode",	modestring,	modecmd,	0 },
237138689Sborman 	{ "open",	openhelp,	tn,		0 },
237238689Sborman 	{ "quit",	quithelp,	quit,		0 },
237338689Sborman 	{ "send",	sendhelp,	sendcmd,	0 },
237438689Sborman 	{ "set",	sethelp,	setcmd,		0 },
237538689Sborman 	{ "unset",	unsethelp,	unsetcmd,	0 },
237638689Sborman 	{ "status",	statushelp,	status,		0 },
237738689Sborman 	{ "toggle",	togglestring,	toggle,		0 },
237838689Sborman 	{ "slc",	slchelp,	slccmd,		0 },
237932144Sminshall #if	defined(TN3270) && defined(unix)
238038689Sborman 	{ "transcom",	transcomhelp,	settranscom,	0 },
238132144Sminshall #endif	/* defined(TN3270) && defined(unix) */
238246808Sdab #if	defined(AUTHENTICATE)
238346808Sdab 	{ "auth",	authhelp,	auth_cmd,	0 },
238446808Sdab #endif
238546808Sdab #if	defined(ENCRYPT)
238646808Sdab 	{ "encrypt",	encrypthelp,	encrypt_cmd,	0 },
238746808Sdab #endif
238832144Sminshall #if	defined(unix)
238938689Sborman 	{ "z",		zhelp,		suspend,	0 },
239032144Sminshall #endif	/* defined(unix) */
239132144Sminshall #if	defined(TN3270)
239238689Sborman 	{ "!",		shellhelp,	shell,		1 },
239338689Sborman #else
239438689Sborman 	{ "!",		shellhelp,	shell,		0 },
239538689Sborman #endif
239644361Sborman 	{ "environ",	envhelp,	env_cmd,	0 },
239738689Sborman 	{ "?",		helphelp,	help,		0 },
239832144Sminshall 	0
239932144Sminshall };
240032144Sminshall 
240132144Sminshall static char	crmodhelp[] =	"deprecated command -- use 'toggle crmod' instead";
240232144Sminshall static char	escapehelp[] =	"deprecated command -- use 'set escape' instead";
240332144Sminshall 
240432144Sminshall static Command cmdtab2[] = {
240538689Sborman 	{ "help",	0,		help,		0 },
240638689Sborman 	{ "escape",	escapehelp,	setescape,	0 },
240738689Sborman 	{ "crmod",	crmodhelp,	togcrmod,	0 },
240832144Sminshall 	0
240932144Sminshall };
241032144Sminshall 
241135298Sminshall 
241232144Sminshall /*
241332144Sminshall  * Call routine with argc, argv set from args (terminated by 0).
241432144Sminshall  */
241535298Sminshall 
241646808Sdab     /*VARARGS1*/
241746808Sdab     static
241835298Sminshall call(va_alist)
241946808Sdab     va_dcl
242032144Sminshall {
242135298Sminshall     va_list ap;
242235298Sminshall     typedef int (*intrtn_t)();
242335298Sminshall     intrtn_t routine;
242435298Sminshall     char *args[100];
242535298Sminshall     int argno = 0;
242635298Sminshall 
242735298Sminshall     va_start(ap);
242835298Sminshall     routine = (va_arg(ap, intrtn_t));
242935495Sminshall     while ((args[argno++] = va_arg(ap, char *)) != 0) {
243035298Sminshall 	;
243135495Sminshall     }
243235298Sminshall     va_end(ap);
243335495Sminshall     return (*routine)(argno-1, args);
243432144Sminshall }
243532144Sminshall 
243635298Sminshall 
243746808Sdab     static Command *
243832144Sminshall getcmd(name)
243946808Sdab     char *name;
244032144Sminshall {
244132144Sminshall     Command *cm;
244232144Sminshall 
244346808Sdab     if (cm = (Command *) genget(name, (char **) cmdtab, sizeof(Command)))
244432144Sminshall 	return cm;
244546808Sdab     return (Command *) genget(name, (char **) cmdtab2, sizeof(Command));
244632144Sminshall }
244732144Sminshall 
244846808Sdab     void
244938689Sborman command(top, tbuf, cnt)
245046808Sdab     int top;
245146808Sdab     char *tbuf;
245246808Sdab     int cnt;
245332144Sminshall {
245432144Sminshall     register Command *c;
245532144Sminshall 
245632144Sminshall     setcommandmode();
245732144Sminshall     if (!top) {
245832144Sminshall 	putchar('\n');
245937219Sminshall #if	defined(unix)
246032144Sminshall     } else {
246144361Sborman 	(void) signal(SIGINT, SIG_DFL);
246244361Sborman 	(void) signal(SIGQUIT, SIG_DFL);
246332144Sminshall #endif	/* defined(unix) */
246432144Sminshall     }
246532144Sminshall     for (;;) {
246646808Sdab 	if (rlogin == _POSIX_VDISABLE)
246746808Sdab 		printf("%s> ", prompt);
246838689Sborman 	if (tbuf) {
246938689Sborman 	    register char *cp;
247038689Sborman 	    cp = line;
247138689Sborman 	    while (cnt > 0 && (*cp++ = *tbuf++) != '\n')
247238689Sborman 		cnt--;
247338689Sborman 	    tbuf = 0;
247438689Sborman 	    if (cp == line || *--cp != '\n' || cp == line)
247538689Sborman 		goto getline;
247638689Sborman 	    *cp = '\0';
247746808Sdab 	    if (rlogin == _POSIX_VDISABLE)
247846808Sdab 	        printf("%s\n", line);
247938689Sborman 	} else {
248038689Sborman 	getline:
248146808Sdab 	    if (rlogin != _POSIX_VDISABLE)
248246808Sdab 		printf("%s> ", prompt);
248346808Sdab 	    if (fgets(line, sizeof(line), stdin) == NULL) {
248444361Sborman 		if (feof(stdin) || ferror(stdin)) {
248544361Sborman 		    (void) quit();
248644361Sborman 		    /*NOTREACHED*/
248744361Sborman 		}
248838689Sborman 		break;
248938689Sborman 	    }
249032144Sminshall 	}
249132144Sminshall 	if (line[0] == 0)
249232144Sminshall 	    break;
249332144Sminshall 	makeargv();
249437219Sminshall 	if (margv[0] == 0) {
249537219Sminshall 	    break;
249637219Sminshall 	}
249732144Sminshall 	c = getcmd(margv[0]);
249832144Sminshall 	if (Ambiguous(c)) {
249932144Sminshall 	    printf("?Ambiguous command\n");
250032144Sminshall 	    continue;
250132144Sminshall 	}
250232144Sminshall 	if (c == 0) {
250332144Sminshall 	    printf("?Invalid command\n");
250432144Sminshall 	    continue;
250532144Sminshall 	}
250632144Sminshall 	if (c->needconnect && !connected) {
250732144Sminshall 	    printf("?Need to be connected first.\n");
250832144Sminshall 	    continue;
250932144Sminshall 	}
251032144Sminshall 	if ((*c->handler)(margc, margv)) {
251132144Sminshall 	    break;
251232144Sminshall 	}
251332144Sminshall     }
251432144Sminshall     if (!top) {
251532144Sminshall 	if (!connected) {
251632144Sminshall 	    longjmp(toplevel, 1);
251732144Sminshall 	    /*NOTREACHED*/
251832144Sminshall 	}
251932144Sminshall #if	defined(TN3270)
252032144Sminshall 	if (shell_active == 0) {
252138689Sborman 	    setconnmode(0);
252232144Sminshall 	}
252332144Sminshall #else	/* defined(TN3270) */
252438689Sborman 	setconnmode(0);
252532144Sminshall #endif	/* defined(TN3270) */
252632144Sminshall     }
252732144Sminshall }
252832144Sminshall 
252932144Sminshall /*
253032144Sminshall  * Help command.
253132144Sminshall  */
253246808Sdab 	static
253332144Sminshall help(argc, argv)
253432144Sminshall 	int argc;
253532144Sminshall 	char *argv[];
253632144Sminshall {
253732144Sminshall 	register Command *c;
253832144Sminshall 
253932144Sminshall 	if (argc == 1) {
254032144Sminshall 		printf("Commands may be abbreviated.  Commands are:\n\n");
254132144Sminshall 		for (c = cmdtab; c->name; c++)
254238689Sborman 			if (c->help) {
254332144Sminshall 				printf("%-*s\t%s\n", HELPINDENT, c->name,
254432144Sminshall 								    c->help);
254532144Sminshall 			}
254632144Sminshall 		return 0;
254732144Sminshall 	}
254832144Sminshall 	while (--argc > 0) {
254932144Sminshall 		register char *arg;
255032144Sminshall 		arg = *++argv;
255132144Sminshall 		c = getcmd(arg);
255232144Sminshall 		if (Ambiguous(c))
255332144Sminshall 			printf("?Ambiguous help command %s\n", arg);
255432144Sminshall 		else if (c == (Command *)0)
255532144Sminshall 			printf("?Invalid help command %s\n", arg);
255632144Sminshall 		else
255732144Sminshall 			printf("%s\n", c->help);
255832144Sminshall 	}
255932144Sminshall 	return 0;
256032144Sminshall }
256138689Sborman 
256238689Sborman static char *rcname = 0;
256338689Sborman static char rcbuf[128];
256438689Sborman 
256538689Sborman cmdrc(m1, m2)
256638689Sborman 	char *m1, *m2;
256738689Sborman {
256838689Sborman     register Command *c;
256938689Sborman     FILE *rcfile;
257038689Sborman     int gotmachine = 0;
257138689Sborman     int l1 = strlen(m1);
257238689Sborman     int l2 = strlen(m2);
257338689Sborman     char m1save[64];
257438689Sborman 
257547609Sdab     if (skiprc)
257647609Sdab 	return;
257747609Sdab 
257838689Sborman     strcpy(m1save, m1);
257938689Sborman     m1 = m1save;
258038689Sborman 
258138689Sborman     if (rcname == 0) {
258238689Sborman 	rcname = getenv("HOME");
258338689Sborman 	if (rcname)
258438689Sborman 	    strcpy(rcbuf, rcname);
258538689Sborman 	else
258638689Sborman 	    rcbuf[0] = '\0';
258738689Sborman 	strcat(rcbuf, "/.telnetrc");
258838689Sborman 	rcname = rcbuf;
258938689Sborman     }
259038689Sborman 
259138689Sborman     if ((rcfile = fopen(rcname, "r")) == 0) {
259238689Sborman 	return;
259338689Sborman     }
259438689Sborman 
259538689Sborman     for (;;) {
259638689Sborman 	if (fgets(line, sizeof(line), rcfile) == NULL)
259738689Sborman 	    break;
259838689Sborman 	if (line[0] == 0)
259938689Sborman 	    break;
260038689Sborman 	if (line[0] == '#')
260138689Sborman 	    continue;
260247609Sdab 	if (gotmachine) {
260347609Sdab 	    if (!isspace(line[0]))
260447609Sdab 		gotmachine = 0;
260547609Sdab 	}
260638689Sborman 	if (gotmachine == 0) {
260738689Sborman 	    if (isspace(line[0]))
260838689Sborman 		continue;
260938689Sborman 	    if (strncasecmp(line, m1, l1) == 0)
261038689Sborman 		strncpy(line, &line[l1], sizeof(line) - l1);
261138689Sborman 	    else if (strncasecmp(line, m2, l2) == 0)
261238689Sborman 		strncpy(line, &line[l2], sizeof(line) - l2);
261347609Sdab 	    else if (strncasecmp(line, "DEFAULT", 7) == 0)
261447609Sdab 		strncpy(line, &line[7], sizeof(line) - 7);
261538689Sborman 	    else
261638689Sborman 		continue;
261747609Sdab 	    if (line[0] != ' ' && line[0] != '\t' && line[0] != '\n')
261847609Sdab 		continue;
261938689Sborman 	    gotmachine = 1;
262038689Sborman 	}
262138689Sborman 	makeargv();
262238689Sborman 	if (margv[0] == 0)
262338689Sborman 	    continue;
262438689Sborman 	c = getcmd(margv[0]);
262538689Sborman 	if (Ambiguous(c)) {
262638689Sborman 	    printf("?Ambiguous command: %s\n", margv[0]);
262738689Sborman 	    continue;
262838689Sborman 	}
262938689Sborman 	if (c == 0) {
263038689Sborman 	    printf("?Invalid command: %s\n", margv[0]);
263138689Sborman 	    continue;
263238689Sborman 	}
263338689Sborman 	/*
263438689Sborman 	 * This should never happen...
263538689Sborman 	 */
263638689Sborman 	if (c->needconnect && !connected) {
263738689Sborman 	    printf("?Need to be connected first for %s.\n", margv[0]);
263838689Sborman 	    continue;
263938689Sborman 	}
264038689Sborman 	(*c->handler)(margc, margv);
264138689Sborman     }
264238689Sborman     fclose(rcfile);
264338689Sborman }
264438689Sborman 
264546808Sdab #if	defined(IP_OPTIONS) && defined(IPPROTO_IP)
264638689Sborman 
264738689Sborman /*
264838689Sborman  * Source route is handed in as
264938689Sborman  *	[!]@hop1@hop2...[@|:]dst
265038689Sborman  * If the leading ! is present, it is a
265138689Sborman  * strict source route, otherwise it is
265238689Sborman  * assmed to be a loose source route.
265338689Sborman  *
265438689Sborman  * We fill in the source route option as
265538689Sborman  *	hop1,hop2,hop3...dest
265638689Sborman  * and return a pointer to hop1, which will
265738689Sborman  * be the address to connect() to.
265838689Sborman  *
265938689Sborman  * Arguments:
266038689Sborman  *	arg:	pointer to route list to decipher
266138689Sborman  *
266238689Sborman  *	cpp: 	If *cpp is not equal to NULL, this is a
266338689Sborman  *		pointer to a pointer to a character array
266438689Sborman  *		that should be filled in with the option.
266538689Sborman  *
266638689Sborman  *	lenp:	pointer to an integer that contains the
266738689Sborman  *		length of *cpp if *cpp != NULL.
266838689Sborman  *
266938689Sborman  * Return values:
267038689Sborman  *
267138689Sborman  *	Returns the address of the host to connect to.  If the
267238689Sborman  *	return value is -1, there was a syntax error in the
267338689Sborman  *	option, either unknown characters, or too many hosts.
267438689Sborman  *	If the return value is 0, one of the hostnames in the
267538689Sborman  *	path is unknown, and *cpp is set to point to the bad
267638689Sborman  *	hostname.
267738689Sborman  *
267838689Sborman  *	*cpp:	If *cpp was equal to NULL, it will be filled
267938689Sborman  *		in with a pointer to our static area that has
268038689Sborman  *		the option filled in.  This will be 32bit aligned.
268138689Sborman  *
268238689Sborman  *	*lenp:	This will be filled in with how long the option
268338689Sborman  *		pointed to by *cpp is.
268438689Sborman  *
268538689Sborman  */
268646808Sdab 	unsigned long
268738689Sborman sourceroute(arg, cpp, lenp)
268846808Sdab 	char	*arg;
268946808Sdab 	char	**cpp;
269046808Sdab 	int	*lenp;
269138689Sborman {
269238689Sborman 	static char lsr[44];
269346808Sdab 	char *cp, *cp2, *lsrp, *lsrep;
269438689Sborman 	register int tmp;
269538689Sborman 	struct in_addr sin_addr;
269638689Sborman 	register struct hostent *host = 0;
269738689Sborman 	register char c;
269838689Sborman 
269938689Sborman 	/*
270038689Sborman 	 * Verify the arguments, and make sure we have
270138689Sborman 	 * at least 7 bytes for the option.
270238689Sborman 	 */
270338689Sborman 	if (cpp == NULL || lenp == NULL)
270438689Sborman 		return((unsigned long)-1);
270538689Sborman 	if (*cpp != NULL && *lenp < 7)
270638689Sborman 		return((unsigned long)-1);
270738689Sborman 	/*
270838689Sborman 	 * Decide whether we have a buffer passed to us,
270938689Sborman 	 * or if we need to use our own static buffer.
271038689Sborman 	 */
271138689Sborman 	if (*cpp) {
271238689Sborman 		lsrp = *cpp;
271338689Sborman 		lsrep = lsrp + *lenp;
271438689Sborman 	} else {
271538689Sborman 		*cpp = lsrp = lsr;
271638689Sborman 		lsrep = lsrp + 44;
271738689Sborman 	}
271838689Sborman 
271938689Sborman 	cp = arg;
272038689Sborman 
272138689Sborman 	/*
272238689Sborman 	 * Next, decide whether we have a loose source
272338689Sborman 	 * route or a strict source route, and fill in
272438689Sborman 	 * the begining of the option.
272538689Sborman 	 */
272638689Sborman 	if (*cp == '!') {
272738689Sborman 		cp++;
272838689Sborman 		*lsrp++ = IPOPT_SSRR;
272938689Sborman 	} else
273038689Sborman 		*lsrp++ = IPOPT_LSRR;
273138689Sborman 
273238689Sborman 	if (*cp != '@')
273338689Sborman 		return((unsigned long)-1);
273438689Sborman 
273538689Sborman 	lsrp++;		/* skip over length, we'll fill it in later */
273638689Sborman 	*lsrp++ = 4;
273738689Sborman 
273838689Sborman 	cp++;
273938689Sborman 
274038689Sborman 	sin_addr.s_addr = 0;
274138689Sborman 
274238689Sborman 	for (c = 0;;) {
274338689Sborman 		if (c == ':')
274438689Sborman 			cp2 = 0;
274538689Sborman 		else for (cp2 = cp; c = *cp2; cp2++) {
274638689Sborman 			if (c == ',') {
274738689Sborman 				*cp2++ = '\0';
274838689Sborman 				if (*cp2 == '@')
274938689Sborman 					cp2++;
275038689Sborman 			} else if (c == '@') {
275138689Sborman 				*cp2++ = '\0';
275238689Sborman 			} else if (c == ':') {
275338689Sborman 				*cp2++ = '\0';
275438689Sborman 			} else
275538689Sborman 				continue;
275638689Sborman 			break;
275738689Sborman 		}
275838689Sborman 		if (!c)
275938689Sborman 			cp2 = 0;
276038689Sborman 
276138689Sborman 		if ((tmp = inet_addr(cp)) != -1) {
276238689Sborman 			sin_addr.s_addr = tmp;
276338689Sborman 		} else if (host = gethostbyname(cp)) {
276438689Sborman #if	defined(h_addr)
276538689Sborman 			memcpy((caddr_t)&sin_addr,
276638689Sborman 				host->h_addr_list[0], host->h_length);
276738689Sborman #else
276838689Sborman 			memcpy((caddr_t)&sin_addr, host->h_addr, host->h_length);
276938689Sborman #endif
277038689Sborman 		} else {
277138689Sborman 			*cpp = cp;
277238689Sborman 			return(0);
277338689Sborman 		}
277438689Sborman 		memcpy(lsrp, (char *)&sin_addr, 4);
277538689Sborman 		lsrp += 4;
277638689Sborman 		if (cp2)
277738689Sborman 			cp = cp2;
277838689Sborman 		else
277938689Sborman 			break;
278038689Sborman 		/*
278138689Sborman 		 * Check to make sure there is space for next address
278238689Sborman 		 */
278338689Sborman 		if (lsrp + 4 > lsrep)
278438689Sborman 			return((unsigned long)-1);
278538689Sborman 	}
278638689Sborman 	if ((*(*cpp+IPOPT_OLEN) = lsrp - *cpp) <= 7) {
278738689Sborman 		*cpp = 0;
278838689Sborman 		*lenp = 0;
278938689Sborman 		return((unsigned long)-1);
279038689Sborman 	}
279138689Sborman 	*lsrp++ = IPOPT_NOP; /* 32 bit word align it */
279238689Sborman 	*lenp = lsrp - *cpp;
279338689Sborman 	return(sin_addr.s_addr);
279438689Sborman }
279538689Sborman #endif
2796