129088Smarkm/*
229088Smarkm * Copyright (c) 1988, 1990, 1993
329088Smarkm *	The Regents of the University of California.  All rights reserved.
429088Smarkm *
529088Smarkm * Redistribution and use in source and binary forms, with or without
629088Smarkm * modification, are permitted provided that the following conditions
729088Smarkm * are met:
829088Smarkm * 1. Redistributions of source code must retain the above copyright
929088Smarkm *    notice, this list of conditions and the following disclaimer.
1029088Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1129088Smarkm *    notice, this list of conditions and the following disclaimer in the
1229088Smarkm *    documentation and/or other materials provided with the distribution.
1329088Smarkm * 3. All advertising materials mentioning features or use of this software
1429088Smarkm *    must display the following acknowledgement:
1529088Smarkm *	This product includes software developed by the University of
1629088Smarkm *	California, Berkeley and its contributors.
1729088Smarkm * 4. Neither the name of the University nor the names of its contributors
1829088Smarkm *    may be used to endorse or promote products derived from this software
1929088Smarkm *    without specific prior written permission.
2029088Smarkm *
2129088Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2229088Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2329088Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2429088Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2529088Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2629088Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2729088Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2829088Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2929088Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3029088Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3129088Smarkm * SUCH DAMAGE.
3229088Smarkm */
3329088Smarkm
34114630Sobrien#if 0
3529088Smarkm#ifndef lint
3629181Smarkmstatic const char sccsid[] = "@(#)commands.c	8.4 (Berkeley) 5/30/95";
3787139Smarkm#endif
38114630Sobrien#endif
39114630Sobrien#include <sys/cdefs.h>
40114630Sobrien__FBSDID("$FreeBSD$");
4129088Smarkm
4229088Smarkm#include <sys/param.h>
4377095Sdillon#include <sys/un.h>
4429088Smarkm#include <sys/file.h>
4529088Smarkm#include <sys/socket.h>
4629088Smarkm#include <netinet/in.h>
4729088Smarkm
4887139Smarkm#include <ctype.h>
4987139Smarkm#include <err.h>
5087139Smarkm#include <errno.h>
5129088Smarkm#include <netdb.h>
5229088Smarkm#include <pwd.h>
5387139Smarkm#include <signal.h>
5487139Smarkm#include <stdarg.h>
5587139Smarkm#include <stdlib.h>
5687139Smarkm#include <string.h>
5729181Smarkm#include <unistd.h>
5829088Smarkm
5929088Smarkm#include <arpa/telnet.h>
6081965Smarkm#include <arpa/inet.h>
6129088Smarkm
6229088Smarkm#include "general.h"
6329088Smarkm
6429088Smarkm#include "ring.h"
6529088Smarkm
6629088Smarkm#include "externs.h"
6729088Smarkm#include "defines.h"
6829088Smarkm#include "types.h"
6987139Smarkm#include "misc.h"
7029088Smarkm
7187139Smarkm#ifdef	AUTHENTICATION
7229181Smarkm#include <libtelnet/auth.h>
7329181Smarkm#endif
7487139Smarkm#ifdef	ENCRYPTION
7529181Smarkm#include <libtelnet/encrypt.h>
7629181Smarkm#endif
7729181Smarkm
7829088Smarkm#include <netinet/in_systm.h>
7929088Smarkm#include <netinet/ip.h>
8056668Sshin#include <netinet/ip6.h>
8129088Smarkm
8281965Smarkm#ifndef       MAXHOSTNAMELEN
8381965Smarkm#define       MAXHOSTNAMELEN 256
8496385Salfred#endif
8529088Smarkm
8687139Smarkmtypedef int (*intrtn_t)(int, char **);
8787139Smarkm
8887139Smarkm#ifdef	AUTHENTICATION
8987155Smarkmextern int auth_togdebug(int);
9087139Smarkm#endif
9187139Smarkm#ifdef	ENCRYPTION
9287155Smarkmextern int EncryptAutoEnc(int);
9387155Smarkmextern int EncryptAutoDec(int);
9487155Smarkmextern int EncryptDebug(int);
9587155Smarkmextern int EncryptVerbose(int);
9687139Smarkm#endif	/* ENCRYPTION */
9729088Smarkm#if	defined(IPPROTO_IP) && defined(IP_TOS)
9829088Smarkmint tos = -1;
9929088Smarkm#endif	/* defined(IPPROTO_IP) && defined(IP_TOS) */
10029088Smarkm
10129088Smarkmchar	*hostname;
10229088Smarkmstatic char _hostname[MAXHOSTNAMELEN];
10329088Smarkm
10487139Smarkmstatic int help(int, char **);
10587139Smarkmstatic int call(intrtn_t, ...);
10687139Smarkmstatic void cmdrc(char *, char *);
10787277Sjhay#ifdef INET6
10887139Smarkmstatic int switch_af(struct addrinfo **);
10987277Sjhay#endif
11087139Smarkmstatic int togglehelp(void);
11187139Smarkmstatic int send_tncmd(void (*)(int, int), const char *, char *);
11287139Smarkmstatic int setmod(int);
11387139Smarkmstatic int clearmode(int);
11487139Smarkmstatic int modehelp(void);
11587139Smarkmstatic int sourceroute(struct addrinfo *, char *, char **, int *, int *, int *);
11629088Smarkm
11729088Smarkmtypedef struct {
11887139Smarkm	const char *name;	/* command name */
11987139Smarkm	const char *help;	/* help string (NULL for no help) */
12087139Smarkm	int	(*handler)(int, char **); /* routine which executes command */
12129088Smarkm	int	needconnect;	/* Do we need to be connected to execute? */
12229088Smarkm} Command;
12329088Smarkm
12429088Smarkmstatic char line[256];
12529088Smarkmstatic char saveline[256];
12629088Smarkmstatic int margc;
12729088Smarkmstatic char *margv[20];
12829088Smarkm
12987139Smarkm#ifdef OPIE
13029181Smarkm#include <sys/wait.h>
13181965Smarkm#define PATH_OPIEKEY	"/usr/bin/opiekey"
13287139Smarkmstatic int
13387139Smarkmopie_calc(int argc, char *argv[])
13429181Smarkm{
13529181Smarkm	int status;
13629181Smarkm
13729181Smarkm	if(argc != 3) {
13829181Smarkm		printf("%s sequence challenge\n", argv[0]);
13987139Smarkm		return (0);
14029181Smarkm	}
14129181Smarkm
14229181Smarkm	switch(fork()) {
14329181Smarkm	case 0:
14481965Smarkm		execv(PATH_OPIEKEY, argv);
14529181Smarkm		exit (1);
14629181Smarkm	case -1:
14729181Smarkm		perror("fork");
14829181Smarkm		break;
14929181Smarkm	default:
15029181Smarkm		(void) wait(&status);
15129181Smarkm		if (WIFEXITED(status))
15229181Smarkm			return (WEXITSTATUS(status));
15329181Smarkm	}
15487139Smarkm	return (0);
15529181Smarkm}
15629181Smarkm#endif
15729181Smarkm
15887139Smarkmstatic void
15987139Smarkmmakeargv(void)
16029088Smarkm{
16187139Smarkm    char *cp, *cp2, c;
16287139Smarkm    char **argp = margv;
16329088Smarkm
16429088Smarkm    margc = 0;
16529088Smarkm    cp = line;
16629088Smarkm    if (*cp == '!') {		/* Special case shell escape */
16729088Smarkm	strcpy(saveline, line);	/* save for shell command */
16887139Smarkm	*argp++ = strdup("!");		/* No room in string to get this */
16929088Smarkm	margc++;
17029088Smarkm	cp++;
17129088Smarkm    }
17229181Smarkm    while ((c = *cp)) {
17387139Smarkm	int inquote = 0;
17429088Smarkm	while (isspace(c))
17529088Smarkm	    c = *++cp;
17629088Smarkm	if (c == '\0')
17729088Smarkm	    break;
17829088Smarkm	*argp++ = cp;
17929088Smarkm	margc += 1;
18029088Smarkm	for (cp2 = cp; c != '\0'; c = *++cp) {
18129088Smarkm	    if (inquote) {
18229088Smarkm		if (c == inquote) {
18329088Smarkm		    inquote = 0;
18429088Smarkm		    continue;
18529088Smarkm		}
18629088Smarkm	    } else {
18729088Smarkm		if (c == '\\') {
18829088Smarkm		    if ((c = *++cp) == '\0')
18929088Smarkm			break;
19029088Smarkm		} else if (c == '"') {
19129088Smarkm		    inquote = '"';
19229088Smarkm		    continue;
19329088Smarkm		} else if (c == '\'') {
19429088Smarkm		    inquote = '\'';
19529088Smarkm		    continue;
19629088Smarkm		} else if (isspace(c))
19729088Smarkm		    break;
19829088Smarkm	    }
19929088Smarkm	    *cp2++ = c;
20029088Smarkm	}
20129088Smarkm	*cp2 = '\0';
20229088Smarkm	if (c == '\0')
20329088Smarkm	    break;
20429088Smarkm	cp++;
20529088Smarkm    }
20629088Smarkm    *argp++ = 0;
20729088Smarkm}
20829088Smarkm
20929088Smarkm/*
21029088Smarkm * Make a character string into a number.
21129088Smarkm *
21229088Smarkm * Todo:  1.  Could take random integers (12, 0x12, 012, 0b1).
21329088Smarkm */
21429088Smarkm
21587139Smarkmstatic int
21687139Smarkmspecial(char *s)
21729088Smarkm{
21887139Smarkm	char c;
21929088Smarkm	char b;
22029088Smarkm
22129088Smarkm	switch (*s) {
22229088Smarkm	case '^':
22329088Smarkm		b = *++s;
22429088Smarkm		if (b == '?') {
22529088Smarkm		    c = b | 0x40;		/* DEL */
22629088Smarkm		} else {
22729088Smarkm		    c = b & 0x1f;
22829088Smarkm		}
22929088Smarkm		break;
23029088Smarkm	default:
23129088Smarkm		c = *s;
23229088Smarkm		break;
23329088Smarkm	}
23429088Smarkm	return c;
23529088Smarkm}
23629088Smarkm
23729088Smarkm/*
23829088Smarkm * Construct a control character sequence
23929088Smarkm * for a special character.
24029088Smarkm */
24187139Smarkmstatic const char *
24287139Smarkmcontrol(cc_t c)
24329088Smarkm{
24429088Smarkm	static char buf[5];
24529088Smarkm	/*
24629088Smarkm	 * The only way I could get the Sun 3.5 compiler
24729088Smarkm	 * to shut up about
24829088Smarkm	 *	if ((unsigned int)c >= 0x80)
24929088Smarkm	 * was to assign "c" to an unsigned int variable...
25029088Smarkm	 * Arggg....
25129088Smarkm	 */
25287139Smarkm	unsigned int uic = (unsigned int)c;
25329088Smarkm
25429088Smarkm	if (uic == 0x7f)
25529088Smarkm		return ("^?");
25629088Smarkm	if (c == (cc_t)_POSIX_VDISABLE) {
25729088Smarkm		return "off";
25829088Smarkm	}
25929088Smarkm	if (uic >= 0x80) {
26029088Smarkm		buf[0] = '\\';
26129088Smarkm		buf[1] = ((c>>6)&07) + '0';
26229088Smarkm		buf[2] = ((c>>3)&07) + '0';
26329088Smarkm		buf[3] = (c&07) + '0';
26429088Smarkm		buf[4] = 0;
26529088Smarkm	} else if (uic >= 0x20) {
26629088Smarkm		buf[0] = c;
26729088Smarkm		buf[1] = 0;
26829088Smarkm	} else {
26929088Smarkm		buf[0] = '^';
27029088Smarkm		buf[1] = '@'+c;
27129088Smarkm		buf[2] = 0;
27229088Smarkm	}
27329088Smarkm	return (buf);
27429088Smarkm}
27529088Smarkm
27629088Smarkm/*
27729088Smarkm *	The following are data structures and routines for
27829088Smarkm *	the "send" command.
27929088Smarkm *
28029088Smarkm */
28129088Smarkm
28229088Smarkmstruct sendlist {
28387139Smarkm    const char	*name;		/* How user refers to it (case independent) */
28487139Smarkm    const char	*help;		/* Help information (0 ==> no help) */
28529088Smarkm    int		needconnect;	/* Need to be connected */
28629088Smarkm    int		narg;		/* Number of arguments */
28787139Smarkm    int		(*handler)(char *, ...); /* Routine to perform (for special ops) */
28829088Smarkm    int		nbyte;		/* Number of bytes to send this command */
28929088Smarkm    int		what;		/* Character to be sent (<0 ==> special) */
29029088Smarkm};
29129088Smarkm
29229088Smarkm
29329088Smarkmstatic int
29487155Smarkm	send_esc(void),
29587155Smarkm	send_help(void),
29687155Smarkm	send_docmd(char *),
29787155Smarkm	send_dontcmd(char *),
29887155Smarkm	send_willcmd(char *),
29987155Smarkm	send_wontcmd(char *);
30029088Smarkm
30129088Smarkmstatic struct sendlist Sendlist[] = {
30287139Smarkm    { "ao",	"Send Telnet Abort output",	1, 0, NULL, 2, AO },
30387139Smarkm    { "ayt",	"Send Telnet 'Are You There'",	1, 0, NULL, 2, AYT },
30487139Smarkm    { "brk",	"Send Telnet Break",		1, 0, NULL, 2, BREAK },
30587139Smarkm    { "break",	NULL,				1, 0, NULL, 2, BREAK },
30687139Smarkm    { "ec",	"Send Telnet Erase Character",	1, 0, NULL, 2, EC },
30787139Smarkm    { "el",	"Send Telnet Erase Line",	1, 0, NULL, 2, EL },
30887139Smarkm    { "escape",	"Send current escape character",1, 0, (int (*)(char *, ...))send_esc, 1, 0 },
30987139Smarkm    { "ga",	"Send Telnet 'Go Ahead' sequence", 1, 0, NULL, 2, GA },
31087139Smarkm    { "ip",	"Send Telnet Interrupt Process",1, 0, NULL, 2, IP },
31187139Smarkm    { "intp",	NULL,				1, 0, NULL, 2, IP },
31287139Smarkm    { "interrupt", NULL,			1, 0, NULL, 2, IP },
31387139Smarkm    { "intr",	NULL,				1, 0, NULL, 2, IP },
31487139Smarkm    { "nop",	"Send Telnet 'No operation'",	1, 0, NULL, 2, NOP },
31587139Smarkm    { "eor",	"Send Telnet 'End of Record'",	1, 0, NULL, 2, EOR },
31687139Smarkm    { "abort",	"Send Telnet 'Abort Process'",	1, 0, NULL, 2, ABORT },
31787139Smarkm    { "susp",	"Send Telnet 'Suspend Process'",1, 0, NULL, 2, SUSP },
31887139Smarkm    { "eof",	"Send Telnet End of File Character", 1, 0, NULL, 2, xEOF },
31987139Smarkm    { "synch",	"Perform Telnet 'Synch operation'", 1, 0, (int (*)(char *, ...))dosynch, 2, 0 },
32087139Smarkm    { "getstatus", "Send request for STATUS",	1, 0, (int (*)(char *, ...))get_status, 6, 0 },
32187139Smarkm    { "?",	"Display send options",		0, 0, (int (*)(char *, ...))send_help, 0, 0 },
32287139Smarkm    { "help",	NULL,				0, 0, (int (*)(char *, ...))send_help, 0, 0 },
32387139Smarkm    { "do",	NULL,				0, 1, (int (*)(char *, ...))send_docmd, 3, 0 },
32487139Smarkm    { "dont",	NULL,				0, 1, (int (*)(char *, ...))send_dontcmd, 3, 0 },
32587139Smarkm    { "will",	NULL,				0, 1, (int (*)(char *, ...))send_willcmd, 3, 0 },
32687139Smarkm    { "wont",	NULL,				0, 1, (int (*)(char *, ...))send_wontcmd, 3, 0 },
32787139Smarkm    { NULL,	NULL,				0, 0, NULL, 0, 0 }
32829088Smarkm};
32929088Smarkm
33029088Smarkm#define	GETSEND(name) ((struct sendlist *) genget(name, (char **) Sendlist, \
33129088Smarkm				sizeof(struct sendlist)))
33229088Smarkm
33387139Smarkmstatic int
33487139Smarkmsendcmd(int argc, char *argv[])
33529088Smarkm{
33629088Smarkm    int count;		/* how many bytes we are going to need to send */
33729088Smarkm    int i;
33829088Smarkm    struct sendlist *s;	/* pointer to current command */
33929088Smarkm    int success = 0;
34029088Smarkm    int needconnect = 0;
34129088Smarkm
34229088Smarkm    if (argc < 2) {
34329088Smarkm	printf("need at least one argument for 'send' command\n");
34429088Smarkm	printf("'send ?' for help\n");
34529088Smarkm	return 0;
34629088Smarkm    }
34729088Smarkm    /*
34829088Smarkm     * First, validate all the send arguments.
34929088Smarkm     * In addition, we see how much space we are going to need, and
35029088Smarkm     * whether or not we will be doing a "SYNCH" operation (which
35129088Smarkm     * flushes the network queue).
35229088Smarkm     */
35329088Smarkm    count = 0;
35429088Smarkm    for (i = 1; i < argc; i++) {
35529088Smarkm	s = GETSEND(argv[i]);
35629088Smarkm	if (s == 0) {
35729088Smarkm	    printf("Unknown send argument '%s'\n'send ?' for help.\n",
35829088Smarkm			argv[i]);
35929088Smarkm	    return 0;
36087139Smarkm	} else if (Ambiguous((void *)s)) {
36129088Smarkm	    printf("Ambiguous send argument '%s'\n'send ?' for help.\n",
36229088Smarkm			argv[i]);
36329088Smarkm	    return 0;
36429088Smarkm	}
36529088Smarkm	if (i + s->narg >= argc) {
36629088Smarkm	    fprintf(stderr,
36729088Smarkm	    "Need %d argument%s to 'send %s' command.  'send %s ?' for help.\n",
36829088Smarkm		s->narg, s->narg == 1 ? "" : "s", s->name, s->name);
36929088Smarkm	    return 0;
37029088Smarkm	}
37129088Smarkm	count += s->nbyte;
37287139Smarkm	if ((void *)s->handler == (void *)send_help) {
37329088Smarkm	    send_help();
37429088Smarkm	    return 0;
37529088Smarkm	}
37629088Smarkm
37729088Smarkm	i += s->narg;
37829088Smarkm	needconnect += s->needconnect;
37929088Smarkm    }
38029088Smarkm    if (!connected && needconnect) {
38129088Smarkm	printf("?Need to be connected first.\n");
38229088Smarkm	printf("'send ?' for help\n");
38329088Smarkm	return 0;
38429088Smarkm    }
38529088Smarkm    /* Now, do we have enough room? */
38629088Smarkm    if (NETROOM() < count) {
38729088Smarkm	printf("There is not enough room in the buffer TO the network\n");
38829088Smarkm	printf("to process your request.  Nothing will be done.\n");
38929088Smarkm	printf("('send synch' will throw away most data in the network\n");
39029088Smarkm	printf("buffer, if this might help.)\n");
39129088Smarkm	return 0;
39229088Smarkm    }
39329088Smarkm    /* OK, they are all OK, now go through again and actually send */
39429088Smarkm    count = 0;
39529088Smarkm    for (i = 1; i < argc; i++) {
39629088Smarkm	if ((s = GETSEND(argv[i])) == 0) {
39729088Smarkm	    fprintf(stderr, "Telnet 'send' error - argument disappeared!\n");
39887139Smarkm	    quit();
39929088Smarkm	    /*NOTREACHED*/
40029088Smarkm	}
40129088Smarkm	if (s->handler) {
40229088Smarkm	    count++;
40329088Smarkm	    success += (*s->handler)((s->narg > 0) ? argv[i+1] : 0,
40429088Smarkm				  (s->narg > 1) ? argv[i+2] : 0);
40529088Smarkm	    i += s->narg;
40629088Smarkm	} else {
40729088Smarkm	    NET2ADD(IAC, s->what);
40829088Smarkm	    printoption("SENT", IAC, s->what);
40929088Smarkm	}
41029088Smarkm    }
41129088Smarkm    return (count == success);
41229088Smarkm}
41329088Smarkm
41487139Smarkmstatic int
41587139Smarkmsend_esc(void)
41629088Smarkm{
41729088Smarkm    NETADD(escape);
41829088Smarkm    return 1;
41929088Smarkm}
42029088Smarkm
42187139Smarkmstatic int
42287139Smarkmsend_docmd(char *name)
42329088Smarkm{
42429088Smarkm    return(send_tncmd(send_do, "do", name));
42529088Smarkm}
42629088Smarkm
42787139Smarkmstatic int
42829088Smarkmsend_dontcmd(name)
42929088Smarkm    char *name;
43029088Smarkm{
43129088Smarkm    return(send_tncmd(send_dont, "dont", name));
43229088Smarkm}
43387139Smarkm
43487139Smarkmstatic int
43587139Smarkmsend_willcmd(char *name)
43629088Smarkm{
43729088Smarkm    return(send_tncmd(send_will, "will", name));
43829088Smarkm}
43987139Smarkm
44087139Smarkmstatic int
44187139Smarkmsend_wontcmd(char *name)
44229088Smarkm{
44329088Smarkm    return(send_tncmd(send_wont, "wont", name));
44429088Smarkm}
44529088Smarkm
44687139Smarkmstatic int
44787139Smarkmsend_tncmd(void (*func)(int, int), const char *cmd, char *name)
44829088Smarkm{
44929088Smarkm    char **cpp;
45029088Smarkm    extern char *telopts[];
45187139Smarkm    int val = 0;
45229088Smarkm
45329088Smarkm    if (isprefix(name, "help") || isprefix(name, "?")) {
45487139Smarkm	int col, len;
45529088Smarkm
456103955Smarkm	printf("usage: send %s <value|option>\n", cmd);
45729088Smarkm	printf("\"value\" must be from 0 to 255\n");
45829088Smarkm	printf("Valid options are:\n\t");
45929088Smarkm
46029088Smarkm	col = 8;
46129088Smarkm	for (cpp = telopts; *cpp; cpp++) {
46229088Smarkm	    len = strlen(*cpp) + 3;
46329088Smarkm	    if (col + len > 65) {
46429088Smarkm		printf("\n\t");
46529088Smarkm		col = 8;
46629088Smarkm	    }
46729088Smarkm	    printf(" \"%s\"", *cpp);
46829088Smarkm	    col += len;
46929088Smarkm	}
47029088Smarkm	printf("\n");
47129088Smarkm	return 0;
47229088Smarkm    }
47329088Smarkm    cpp = (char **)genget(name, telopts, sizeof(char *));
47429088Smarkm    if (Ambiguous(cpp)) {
47529088Smarkm	fprintf(stderr,"'%s': ambiguous argument ('send %s ?' for help).\n",
47629088Smarkm					name, cmd);
47729088Smarkm	return 0;
47829088Smarkm    }
47929088Smarkm    if (cpp) {
48029088Smarkm	val = cpp - telopts;
48129088Smarkm    } else {
48287139Smarkm	char *cp = name;
48329088Smarkm
48429088Smarkm	while (*cp >= '0' && *cp <= '9') {
48529088Smarkm	    val *= 10;
48629088Smarkm	    val += *cp - '0';
48729088Smarkm	    cp++;
48829088Smarkm	}
48929088Smarkm	if (*cp != 0) {
49029088Smarkm	    fprintf(stderr, "'%s': unknown argument ('send %s ?' for help).\n",
49129088Smarkm					name, cmd);
49229088Smarkm	    return 0;
49329088Smarkm	} else if (val < 0 || val > 255) {
49429088Smarkm	    fprintf(stderr, "'%s': bad value ('send %s ?' for help).\n",
49529088Smarkm					name, cmd);
49629088Smarkm	    return 0;
49729088Smarkm	}
49829088Smarkm    }
49929088Smarkm    if (!connected) {
50029088Smarkm	printf("?Need to be connected first.\n");
50129088Smarkm	return 0;
50229088Smarkm    }
50329088Smarkm    (*func)(val, 1);
50429088Smarkm    return 1;
50529088Smarkm}
50629088Smarkm
50787139Smarkmstatic int
50887139Smarkmsend_help(void)
50929088Smarkm{
51029088Smarkm    struct sendlist *s;	/* pointer to current command */
51129088Smarkm    for (s = Sendlist; s->name; s++) {
51229088Smarkm	if (s->help)
51329088Smarkm	    printf("%-15s %s\n", s->name, s->help);
51429088Smarkm    }
51529088Smarkm    return(0);
51629088Smarkm}
51729088Smarkm
51829088Smarkm/*
51929088Smarkm * The following are the routines and data structures referred
52029088Smarkm * to by the arguments to the "toggle" command.
52129088Smarkm */
52229088Smarkm
52387139Smarkmstatic int
52487139Smarkmlclchars(void)
52529088Smarkm{
52629088Smarkm    donelclchars = 1;
52729088Smarkm    return 1;
52829088Smarkm}
52929088Smarkm
53087139Smarkmstatic int
53187139Smarkmtogdebug(void)
53229088Smarkm{
53329088Smarkm#ifndef	NOT43
53429088Smarkm    if (net > 0 &&
535114911Smarkm	(SetSockOpt(net, SOL_SOCKET, SO_DEBUG, telnet_debug)) < 0) {
53629088Smarkm	    perror("setsockopt (SO_DEBUG)");
53729088Smarkm    }
53829088Smarkm#else	/* NOT43 */
539114911Smarkm    if (telnet_debug) {
54029181Smarkm	if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0)
54129088Smarkm	    perror("setsockopt (SO_DEBUG)");
54229088Smarkm    } else
54329088Smarkm	printf("Cannot turn off socket debugging\n");
54429088Smarkm#endif	/* NOT43 */
54529088Smarkm    return 1;
54629088Smarkm}
54729088Smarkm
54829088Smarkm
54987139Smarkmstatic int
55087139Smarkmtogcrlf(void)
55129088Smarkm{
55229088Smarkm    if (crlf) {
55329088Smarkm	printf("Will send carriage returns as telnet <CR><LF>.\n");
55429088Smarkm    } else {
55529088Smarkm	printf("Will send carriage returns as telnet <CR><NUL>.\n");
55629088Smarkm    }
55729088Smarkm    return 1;
55829088Smarkm}
55929088Smarkm
56029088Smarkmint binmode;
56129088Smarkm
56287139Smarkmstatic int
56387139Smarkmtogbinary(int val)
56429088Smarkm{
56529088Smarkm    donebinarytoggle = 1;
56629088Smarkm
56729088Smarkm    if (val >= 0) {
56829088Smarkm	binmode = val;
56929088Smarkm    } else {
57029088Smarkm	if (my_want_state_is_will(TELOPT_BINARY) &&
57129088Smarkm				my_want_state_is_do(TELOPT_BINARY)) {
57229088Smarkm	    binmode = 1;
57329088Smarkm	} else if (my_want_state_is_wont(TELOPT_BINARY) &&
57429088Smarkm				my_want_state_is_dont(TELOPT_BINARY)) {
57529088Smarkm	    binmode = 0;
57629088Smarkm	}
57729088Smarkm	val = binmode ? 0 : 1;
57829088Smarkm    }
57929088Smarkm
58029088Smarkm    if (val == 1) {
58129088Smarkm	if (my_want_state_is_will(TELOPT_BINARY) &&
58229088Smarkm					my_want_state_is_do(TELOPT_BINARY)) {
58329088Smarkm	    printf("Already operating in binary mode with remote host.\n");
58429088Smarkm	} else {
58529088Smarkm	    printf("Negotiating binary mode with remote host.\n");
58629088Smarkm	    tel_enter_binary(3);
58729088Smarkm	}
58829088Smarkm    } else {
58929088Smarkm	if (my_want_state_is_wont(TELOPT_BINARY) &&
59029088Smarkm					my_want_state_is_dont(TELOPT_BINARY)) {
59129088Smarkm	    printf("Already in network ascii mode with remote host.\n");
59229088Smarkm	} else {
59329088Smarkm	    printf("Negotiating network ascii mode with remote host.\n");
59429088Smarkm	    tel_leave_binary(3);
59529088Smarkm	}
59629088Smarkm    }
59729088Smarkm    return 1;
59829088Smarkm}
59929088Smarkm
60087139Smarkmstatic int
60187139Smarkmtogrbinary(int val)
60229088Smarkm{
60329088Smarkm    donebinarytoggle = 1;
60429088Smarkm
60529088Smarkm    if (val == -1)
60629088Smarkm	val = my_want_state_is_do(TELOPT_BINARY) ? 0 : 1;
60729088Smarkm
60829088Smarkm    if (val == 1) {
60929088Smarkm	if (my_want_state_is_do(TELOPT_BINARY)) {
61029088Smarkm	    printf("Already receiving in binary mode.\n");
61129088Smarkm	} else {
61229088Smarkm	    printf("Negotiating binary mode on input.\n");
61329088Smarkm	    tel_enter_binary(1);
61429088Smarkm	}
61529088Smarkm    } else {
61629088Smarkm	if (my_want_state_is_dont(TELOPT_BINARY)) {
61729088Smarkm	    printf("Already receiving in network ascii mode.\n");
61829088Smarkm	} else {
61929088Smarkm	    printf("Negotiating network ascii mode on input.\n");
62029088Smarkm	    tel_leave_binary(1);
62129088Smarkm	}
62229088Smarkm    }
62329088Smarkm    return 1;
62429088Smarkm}
62529088Smarkm
62687139Smarkmstatic int
62787139Smarkmtogxbinary(int val)
62829088Smarkm{
62929088Smarkm    donebinarytoggle = 1;
63029088Smarkm
63129088Smarkm    if (val == -1)
63229088Smarkm	val = my_want_state_is_will(TELOPT_BINARY) ? 0 : 1;
63329088Smarkm
63429088Smarkm    if (val == 1) {
63529088Smarkm	if (my_want_state_is_will(TELOPT_BINARY)) {
63629088Smarkm	    printf("Already transmitting in binary mode.\n");
63729088Smarkm	} else {
63829088Smarkm	    printf("Negotiating binary mode on output.\n");
63929088Smarkm	    tel_enter_binary(2);
64029088Smarkm	}
64129088Smarkm    } else {
64229088Smarkm	if (my_want_state_is_wont(TELOPT_BINARY)) {
64329088Smarkm	    printf("Already transmitting in network ascii mode.\n");
64429088Smarkm	} else {
64529088Smarkm	    printf("Negotiating network ascii mode on output.\n");
64629088Smarkm	    tel_leave_binary(2);
64729088Smarkm	}
64829088Smarkm    }
64929088Smarkm    return 1;
65029088Smarkm}
65129088Smarkm
65229088Smarkmstruct togglelist {
65387139Smarkm    const char	*name;		/* name of toggle */
65487139Smarkm    const char	*help;		/* help message */
65587139Smarkm    int		(*handler)(int); /* routine to do actual setting */
65629088Smarkm    int		*variable;
65787139Smarkm    const char	*actionexplanation;
65829088Smarkm};
65929088Smarkm
66029088Smarkmstatic struct togglelist Togglelist[] = {
66129088Smarkm    { "autoflush",
66229088Smarkm	"flushing of output when sending interrupt characters",
66329088Smarkm	    0,
66429088Smarkm		&autoflush,
66529088Smarkm		    "flush output when sending interrupt characters" },
66629088Smarkm    { "autosynch",
66729088Smarkm	"automatic sending of interrupt characters in urgent mode",
66829088Smarkm	    0,
66929088Smarkm		&autosynch,
67029088Smarkm		    "send interrupt characters in urgent mode" },
67187139Smarkm#ifdef	AUTHENTICATION
67229088Smarkm    { "autologin",
67329088Smarkm	"automatic sending of login and/or authentication info",
67429088Smarkm	    0,
67529088Smarkm		&autologin,
67629088Smarkm		    "send login name and/or authentication information" },
67729088Smarkm    { "authdebug",
67829088Smarkm	"Toggle authentication debugging",
67929088Smarkm	    auth_togdebug,
68029088Smarkm		0,
68129088Smarkm		     "print authentication debugging information" },
68229088Smarkm#endif
68329088Smarkm#ifdef	ENCRYPTION
68429088Smarkm    { "autoencrypt",
68529088Smarkm	"automatic encryption of data stream",
68629088Smarkm	    EncryptAutoEnc,
68729088Smarkm		0,
68829088Smarkm		    "automatically encrypt output" },
68929088Smarkm    { "autodecrypt",
69029088Smarkm	"automatic decryption of data stream",
69129088Smarkm	    EncryptAutoDec,
69229088Smarkm		0,
69329088Smarkm		    "automatically decrypt input" },
69429088Smarkm    { "verbose_encrypt",
69529088Smarkm	"Toggle verbose encryption output",
69629088Smarkm	    EncryptVerbose,
69729088Smarkm		0,
69829088Smarkm		    "print verbose encryption output" },
69929088Smarkm    { "encdebug",
70029088Smarkm	"Toggle encryption debugging",
70129088Smarkm	    EncryptDebug,
70229088Smarkm		0,
70329088Smarkm		    "print encryption debugging information" },
70429088Smarkm#endif	/* ENCRYPTION */
70529088Smarkm    { "skiprc",
70629088Smarkm	"don't read ~/.telnetrc file",
70729088Smarkm	    0,
70829088Smarkm		&skiprc,
70929088Smarkm		    "skip reading of ~/.telnetrc file" },
71029088Smarkm    { "binary",
71129088Smarkm	"sending and receiving of binary data",
71229088Smarkm	    togbinary,
71329088Smarkm		0,
71429088Smarkm		    0 },
71529088Smarkm    { "inbinary",
71629088Smarkm	"receiving of binary data",
71729088Smarkm	    togrbinary,
71829088Smarkm		0,
71929088Smarkm		    0 },
72029088Smarkm    { "outbinary",
72129088Smarkm	"sending of binary data",
72229088Smarkm	    togxbinary,
72329088Smarkm		0,
72429088Smarkm		    0 },
72529088Smarkm    { "crlf",
72629088Smarkm	"sending carriage returns as telnet <CR><LF>",
72787139Smarkm	    (int (*)(int))togcrlf,
72829088Smarkm		&crlf,
72929088Smarkm		    0 },
73029088Smarkm    { "crmod",
73129088Smarkm	"mapping of received carriage returns",
73229088Smarkm	    0,
73329088Smarkm		&crmod,
73429088Smarkm		    "map carriage return on output" },
73529088Smarkm    { "localchars",
73629088Smarkm	"local recognition of certain control characters",
73787139Smarkm	    (int (*)(int))lclchars,
73829088Smarkm		&localchars,
73929088Smarkm		    "recognize certain control characters" },
74087139Smarkm    { " ", "", NULL, NULL, NULL },		/* empty line */
74129088Smarkm    { "debug",
74229088Smarkm	"debugging",
74387139Smarkm	    (int (*)(int))togdebug,
744114911Smarkm		&telnet_debug,
74529088Smarkm		    "turn on socket level debugging" },
74629088Smarkm    { "netdata",
74729088Smarkm	"printing of hexadecimal network data (debugging)",
74829088Smarkm	    0,
74929088Smarkm		&netdata,
75029088Smarkm		    "print hexadecimal representation of network traffic" },
75129088Smarkm    { "prettydump",
75229088Smarkm	"output of \"netdata\" to user readable format (debugging)",
75329088Smarkm	    0,
75429088Smarkm		&prettydump,
75529088Smarkm		    "print user readable output for \"netdata\"" },
75629088Smarkm    { "options",
75729088Smarkm	"viewing of options processing (debugging)",
75829088Smarkm	    0,
75929088Smarkm		&showoptions,
76029088Smarkm		    "show option processing" },
76129088Smarkm    { "termdata",
76229088Smarkm	"(debugging) toggle printing of hexadecimal terminal data",
76329088Smarkm	    0,
76429088Smarkm		&termdata,
76529088Smarkm		    "print hexadecimal representation of terminal traffic" },
76629088Smarkm    { "?",
76787139Smarkm	NULL,
76887139Smarkm	    (int (*)(int))togglehelp,
76987139Smarkm		NULL,
77087139Smarkm		    NULL },
77187139Smarkm    { NULL, NULL, NULL, NULL, NULL },
77229088Smarkm    { "help",
77387139Smarkm	NULL,
77487139Smarkm	    (int (*)(int))togglehelp,
77587139Smarkm		NULL,
77687139Smarkm		    NULL },
77787139Smarkm    { NULL, NULL, NULL, NULL, NULL }
77829088Smarkm};
77929088Smarkm
78087139Smarkmstatic int
78187139Smarkmtogglehelp(void)
78229088Smarkm{
78329088Smarkm    struct togglelist *c;
78429088Smarkm
78529088Smarkm    for (c = Togglelist; c->name; c++) {
78629088Smarkm	if (c->help) {
78729088Smarkm	    if (*c->help)
78829088Smarkm		printf("%-15s toggle %s\n", c->name, c->help);
78929088Smarkm	    else
79029088Smarkm		printf("\n");
79129088Smarkm	}
79229088Smarkm    }
79329088Smarkm    printf("\n");
79429088Smarkm    printf("%-15s %s\n", "?", "display help information");
79529088Smarkm    return 0;
79629088Smarkm}
79729088Smarkm
79887139Smarkmstatic void
79987139Smarkmsettogglehelp(int set)
80029088Smarkm{
80129088Smarkm    struct togglelist *c;
80229088Smarkm
80329088Smarkm    for (c = Togglelist; c->name; c++) {
80429088Smarkm	if (c->help) {
80529088Smarkm	    if (*c->help)
80629088Smarkm		printf("%-15s %s %s\n", c->name, set ? "enable" : "disable",
80729088Smarkm						c->help);
80829088Smarkm	    else
80929088Smarkm		printf("\n");
81029088Smarkm	}
81129088Smarkm    }
81229088Smarkm}
81329088Smarkm
81429088Smarkm#define	GETTOGGLE(name) (struct togglelist *) \
81529088Smarkm		genget(name, (char **) Togglelist, sizeof(struct togglelist))
81629088Smarkm
81787139Smarkmstatic int
81887139Smarkmtoggle(int argc, char *argv[])
81929088Smarkm{
82029088Smarkm    int retval = 1;
82129088Smarkm    char *name;
82229088Smarkm    struct togglelist *c;
82329088Smarkm
82429088Smarkm    if (argc < 2) {
82529088Smarkm	fprintf(stderr,
82629088Smarkm	    "Need an argument to 'toggle' command.  'toggle ?' for help.\n");
82729088Smarkm	return 0;
82829088Smarkm    }
82929088Smarkm    argc--;
83029088Smarkm    argv++;
83129088Smarkm    while (argc--) {
83229088Smarkm	name = *argv++;
83329088Smarkm	c = GETTOGGLE(name);
83487139Smarkm	if (Ambiguous((void *)c)) {
83529088Smarkm	    fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n",
83629088Smarkm					name);
83729088Smarkm	    return 0;
83829088Smarkm	} else if (c == 0) {
83929088Smarkm	    fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n",
84029088Smarkm					name);
84129088Smarkm	    return 0;
84229088Smarkm	} else {
84329088Smarkm	    if (c->variable) {
84429088Smarkm		*c->variable = !*c->variable;		/* invert it */
84529088Smarkm		if (c->actionexplanation) {
84629088Smarkm		    printf("%s %s.\n", *c->variable? "Will" : "Won't",
84729088Smarkm							c->actionexplanation);
84829088Smarkm		}
84929088Smarkm	    }
85029088Smarkm	    if (c->handler) {
85129088Smarkm		retval &= (*c->handler)(-1);
85229088Smarkm	    }
85329088Smarkm	}
85429088Smarkm    }
85529088Smarkm    return retval;
85629088Smarkm}
85729088Smarkm
85829088Smarkm/*
85929088Smarkm * The following perform the "set" command.
86029088Smarkm */
86129088Smarkm
86229088Smarkm#ifdef	USE_TERMIO
86387139Smarkmstruct termio new_tc = { 0, 0, 0, 0, {}, 0, 0 };
86429088Smarkm#endif
86529088Smarkm
86629088Smarkmstruct setlist {
86787139Smarkm    const char *name;			/* name */
86887139Smarkm    const char *help;			/* help information */
86987139Smarkm    void (*handler)(char *);
87029088Smarkm    cc_t *charp;			/* where it is located at */
87129088Smarkm};
87229088Smarkm
87329088Smarkmstatic struct setlist Setlist[] = {
87429088Smarkm#ifdef	KLUDGELINEMODE
87587139Smarkm    { "echo", 	"character to toggle local echoing on/off", NULL, &echoc },
87629088Smarkm#endif
87787139Smarkm    { "escape",	"character to escape back to telnet command mode", NULL, &escape },
87829088Smarkm    { "rlogin", "rlogin escape character", 0, &rlogin },
87929088Smarkm    { "tracefile", "file to write trace information to", SetNetTrace, (cc_t *)NetTraceFile},
88087139Smarkm    { " ", "", NULL, NULL },
88187139Smarkm    { " ", "The following need 'localchars' to be toggled true", NULL, NULL },
88287139Smarkm    { "flushoutput", "character to cause an Abort Output", NULL, termFlushCharp },
88387139Smarkm    { "interrupt", "character to cause an Interrupt Process", NULL, termIntCharp },
88487139Smarkm    { "quit",	"character to cause an Abort process", NULL, termQuitCharp },
88587139Smarkm    { "eof",	"character to cause an EOF ", NULL, termEofCharp },
88687139Smarkm    { " ", "", NULL, NULL },
88787139Smarkm    { " ", "The following are for local editing in linemode", NULL, NULL },
88887139Smarkm    { "erase",	"character to use to erase a character", NULL, termEraseCharp },
88987139Smarkm    { "kill",	"character to use to erase a line", NULL, termKillCharp },
89087139Smarkm    { "lnext",	"character to use for literal next", NULL, termLiteralNextCharp },
89187139Smarkm    { "susp",	"character to cause a Suspend Process", NULL, termSuspCharp },
89287139Smarkm    { "reprint", "character to use for line reprint", NULL, termRprntCharp },
89387139Smarkm    { "worderase", "character to use to erase a word", NULL, termWerasCharp },
89487139Smarkm    { "start",	"character to use for XON", NULL, termStartCharp },
89587139Smarkm    { "stop",	"character to use for XOFF", NULL, termStopCharp },
89687139Smarkm    { "forw1",	"alternate end of line character", NULL, termForw1Charp },
89787139Smarkm    { "forw2",	"alternate end of line character", NULL, termForw2Charp },
89887139Smarkm    { "ayt",	"alternate AYT character", NULL, termAytCharp },
89987139Smarkm    { NULL, NULL, NULL, NULL }
90029088Smarkm};
90129088Smarkm
90287139Smarkmstatic struct setlist *
90387139Smarkmgetset(char *name)
90429088Smarkm{
90529088Smarkm    return (struct setlist *)
90629088Smarkm		genget(name, (char **) Setlist, sizeof(struct setlist));
90729088Smarkm}
90829088Smarkm
90987139Smarkmvoid
91087139Smarkmset_escape_char(char *s)
91129088Smarkm{
91229088Smarkm	if (rlogin != _POSIX_VDISABLE) {
91329088Smarkm		rlogin = (s && *s) ? special(s) : _POSIX_VDISABLE;
91429088Smarkm		printf("Telnet rlogin escape character is '%s'.\n",
91529088Smarkm					control(rlogin));
91629088Smarkm	} else {
91729088Smarkm		escape = (s && *s) ? special(s) : _POSIX_VDISABLE;
91829088Smarkm		printf("Telnet escape character is '%s'.\n", control(escape));
91929088Smarkm	}
92029088Smarkm}
92129088Smarkm
92287139Smarkmstatic int
92387139Smarkmsetcmd(int argc, char *argv[])
92429088Smarkm{
92529088Smarkm    int value;
92629088Smarkm    struct setlist *ct;
92729088Smarkm    struct togglelist *c;
92829088Smarkm
92929088Smarkm    if (argc < 2 || argc > 3) {
93029088Smarkm	printf("Format is 'set Name Value'\n'set ?' for help.\n");
93129088Smarkm	return 0;
93229088Smarkm    }
93329088Smarkm    if ((argc == 2) && (isprefix(argv[1], "?") || isprefix(argv[1], "help"))) {
93429088Smarkm	for (ct = Setlist; ct->name; ct++)
93529088Smarkm	    printf("%-15s %s\n", ct->name, ct->help);
93629088Smarkm	printf("\n");
93729088Smarkm	settogglehelp(1);
93829088Smarkm	printf("%-15s %s\n", "?", "display help information");
93929088Smarkm	return 0;
94029088Smarkm    }
94129088Smarkm
94229088Smarkm    ct = getset(argv[1]);
94329088Smarkm    if (ct == 0) {
94429088Smarkm	c = GETTOGGLE(argv[1]);
94529088Smarkm	if (c == 0) {
94629088Smarkm	    fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n",
94729088Smarkm			argv[1]);
94829088Smarkm	    return 0;
94987139Smarkm	} else if (Ambiguous((void *)c)) {
95029088Smarkm	    fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
95129088Smarkm			argv[1]);
95229088Smarkm	    return 0;
95329088Smarkm	}
95429088Smarkm	if (c->variable) {
95529088Smarkm	    if ((argc == 2) || (strcmp("on", argv[2]) == 0))
95629088Smarkm		*c->variable = 1;
95729088Smarkm	    else if (strcmp("off", argv[2]) == 0)
95829088Smarkm		*c->variable = 0;
95929088Smarkm	    else {
96029088Smarkm		printf("Format is 'set togglename [on|off]'\n'set ?' for help.\n");
96129088Smarkm		return 0;
96229088Smarkm	    }
96329088Smarkm	    if (c->actionexplanation) {
96429088Smarkm		printf("%s %s.\n", *c->variable? "Will" : "Won't",
96529088Smarkm							c->actionexplanation);
96629088Smarkm	    }
96729088Smarkm	}
96829088Smarkm	if (c->handler)
96929088Smarkm	    (*c->handler)(1);
97029088Smarkm    } else if (argc != 3) {
97129088Smarkm	printf("Format is 'set Name Value'\n'set ?' for help.\n");
97229088Smarkm	return 0;
97387139Smarkm    } else if (Ambiguous((void *)ct)) {
97429088Smarkm	fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
97529088Smarkm			argv[1]);
97629088Smarkm	return 0;
97729088Smarkm    } else if (ct->handler) {
97829088Smarkm	(*ct->handler)(argv[2]);
97929088Smarkm	printf("%s set to \"%s\".\n", ct->name, (char *)ct->charp);
98029088Smarkm    } else {
98129088Smarkm	if (strcmp("off", argv[2])) {
98229088Smarkm	    value = special(argv[2]);
98329088Smarkm	} else {
98429088Smarkm	    value = _POSIX_VDISABLE;
98529088Smarkm	}
98629088Smarkm	*(ct->charp) = (cc_t)value;
98729088Smarkm	printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
98829088Smarkm    }
98929088Smarkm    slc_check();
99029088Smarkm    return 1;
99129088Smarkm}
99229088Smarkm
99387139Smarkmstatic int
99487139Smarkmunsetcmd(int argc, char *argv[])
99529088Smarkm{
99629088Smarkm    struct setlist *ct;
99729088Smarkm    struct togglelist *c;
99887139Smarkm    char *name;
99929088Smarkm
100029088Smarkm    if (argc < 2) {
100129088Smarkm	fprintf(stderr,
100229088Smarkm	    "Need an argument to 'unset' command.  'unset ?' for help.\n");
100329088Smarkm	return 0;
100429088Smarkm    }
100529088Smarkm    if (isprefix(argv[1], "?") || isprefix(argv[1], "help")) {
100629088Smarkm	for (ct = Setlist; ct->name; ct++)
100729088Smarkm	    printf("%-15s %s\n", ct->name, ct->help);
100829088Smarkm	printf("\n");
100929088Smarkm	settogglehelp(0);
101029088Smarkm	printf("%-15s %s\n", "?", "display help information");
101129088Smarkm	return 0;
101229088Smarkm    }
101329088Smarkm
101429088Smarkm    argc--;
101529088Smarkm    argv++;
101629088Smarkm    while (argc--) {
101729088Smarkm	name = *argv++;
101829088Smarkm	ct = getset(name);
101929088Smarkm	if (ct == 0) {
102029088Smarkm	    c = GETTOGGLE(name);
102129088Smarkm	    if (c == 0) {
102229088Smarkm		fprintf(stderr, "'%s': unknown argument ('unset ?' for help).\n",
102329088Smarkm			name);
102429088Smarkm		return 0;
102587139Smarkm	    } else if (Ambiguous((void *)c)) {
102629088Smarkm		fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n",
102729088Smarkm			name);
102829088Smarkm		return 0;
102929088Smarkm	    }
103029088Smarkm	    if (c->variable) {
103129088Smarkm		*c->variable = 0;
103229088Smarkm		if (c->actionexplanation) {
103329088Smarkm		    printf("%s %s.\n", *c->variable? "Will" : "Won't",
103429088Smarkm							c->actionexplanation);
103529088Smarkm		}
103629088Smarkm	    }
103729088Smarkm	    if (c->handler)
103829088Smarkm		(*c->handler)(0);
103987139Smarkm	} else if (Ambiguous((void *)ct)) {
104029088Smarkm	    fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n",
104129088Smarkm			name);
104229088Smarkm	    return 0;
104329088Smarkm	} else if (ct->handler) {
104429088Smarkm	    (*ct->handler)(0);
104529088Smarkm	    printf("%s reset to \"%s\".\n", ct->name, (char *)ct->charp);
104629088Smarkm	} else {
104729088Smarkm	    *(ct->charp) = _POSIX_VDISABLE;
104829088Smarkm	    printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
104929088Smarkm	}
105029088Smarkm    }
105129088Smarkm    return 1;
105229088Smarkm}
105329088Smarkm
105429088Smarkm/*
105529088Smarkm * The following are the data structures and routines for the
105629088Smarkm * 'mode' command.
105729088Smarkm */
105829088Smarkm#ifdef	KLUDGELINEMODE
105929088Smarkmextern int kludgelinemode;
106029088Smarkm
106187139Smarkmstatic int
106287139Smarkmdokludgemode(void)
106329088Smarkm{
106429088Smarkm    kludgelinemode = 1;
106529088Smarkm    send_wont(TELOPT_LINEMODE, 1);
106629088Smarkm    send_dont(TELOPT_SGA, 1);
106729088Smarkm    send_dont(TELOPT_ECHO, 1);
106849861Snsayer    return 1;
106929088Smarkm}
107029088Smarkm#endif
107129088Smarkm
107287139Smarkmstatic int
107387139Smarkmdolinemode(void)
107429088Smarkm{
107529088Smarkm#ifdef	KLUDGELINEMODE
107629088Smarkm    if (kludgelinemode)
107729088Smarkm	send_dont(TELOPT_SGA, 1);
107829088Smarkm#endif
107929088Smarkm    send_will(TELOPT_LINEMODE, 1);
108029088Smarkm    send_dont(TELOPT_ECHO, 1);
108129088Smarkm    return 1;
108229088Smarkm}
108329088Smarkm
108487139Smarkmstatic int
108587139Smarkmdocharmode(void)
108629088Smarkm{
108729088Smarkm#ifdef	KLUDGELINEMODE
108829088Smarkm    if (kludgelinemode)
108929088Smarkm	send_do(TELOPT_SGA, 1);
109029088Smarkm    else
109129088Smarkm#endif
109229088Smarkm    send_wont(TELOPT_LINEMODE, 1);
109329088Smarkm    send_do(TELOPT_ECHO, 1);
109429088Smarkm    return 1;
109529088Smarkm}
109629088Smarkm
109787139Smarkmstatic int
109887139Smarkmdolmmode(int bit, int on)
109929088Smarkm{
110029088Smarkm    unsigned char c;
110129088Smarkm    extern int linemode;
110229088Smarkm
110329088Smarkm    if (my_want_state_is_wont(TELOPT_LINEMODE)) {
110429088Smarkm	printf("?Need to have LINEMODE option enabled first.\n");
110529088Smarkm	printf("'mode ?' for help.\n");
110629088Smarkm	return 0;
110729088Smarkm    }
110829088Smarkm
110929088Smarkm    if (on)
111029088Smarkm	c = (linemode | bit);
111129088Smarkm    else
111229088Smarkm	c = (linemode & ~bit);
111329088Smarkm    lm_mode(&c, 1, 1);
111429088Smarkm    return 1;
111529088Smarkm}
111629088Smarkm
111787139Smarkmstatic int
111887139Smarkmsetmod(int bit)
111929088Smarkm{
112029088Smarkm    return dolmmode(bit, 1);
112129088Smarkm}
112229088Smarkm
112387139Smarkmstatic int
112487139Smarkmclearmode(int bit)
112529088Smarkm{
112629088Smarkm    return dolmmode(bit, 0);
112729088Smarkm}
112829088Smarkm
112929088Smarkmstruct modelist {
113087139Smarkm	const char	*name;	/* command name */
113187139Smarkm	const char	*help;	/* help string */
113287139Smarkm	int	(*handler)(int);/* routine which executes command */
113329088Smarkm	int	needconnect;	/* Do we need to be connected to execute? */
113429088Smarkm	int	arg1;
113529088Smarkm};
113629088Smarkm
113729088Smarkmstatic struct modelist ModeList[] = {
113887139Smarkm    { "character", "Disable LINEMODE option",	(int (*)(int))docharmode, 1, 0 },
113929088Smarkm#ifdef	KLUDGELINEMODE
114087139Smarkm    { "",	"(or disable obsolete line-by-line mode)", NULL, 0, 0 },
114129088Smarkm#endif
114287139Smarkm    { "line",	"Enable LINEMODE option",	(int (*)(int))dolinemode, 1, 0 },
114329088Smarkm#ifdef	KLUDGELINEMODE
114487139Smarkm    { "",	"(or enable obsolete line-by-line mode)", NULL, 0, 0 },
114529088Smarkm#endif
114687139Smarkm    { "", "", NULL, 0, 0 },
114787139Smarkm    { "",	"These require the LINEMODE option to be enabled", NULL, 0, 0 },
114829181Smarkm    { "isig",	"Enable signal trapping",	setmod, 1, MODE_TRAPSIG },
114929181Smarkm    { "+isig",	0,				setmod, 1, MODE_TRAPSIG },
115029088Smarkm    { "-isig",	"Disable signal trapping",	clearmode, 1, MODE_TRAPSIG },
115129181Smarkm    { "edit",	"Enable character editing",	setmod, 1, MODE_EDIT },
115229181Smarkm    { "+edit",	0,				setmod, 1, MODE_EDIT },
115329088Smarkm    { "-edit",	"Disable character editing",	clearmode, 1, MODE_EDIT },
115429181Smarkm    { "softtabs", "Enable tab expansion",	setmod, 1, MODE_SOFT_TAB },
115529181Smarkm    { "+softtabs", 0,				setmod, 1, MODE_SOFT_TAB },
115629088Smarkm    { "-softtabs", "Disable character editing",	clearmode, 1, MODE_SOFT_TAB },
115729181Smarkm    { "litecho", "Enable literal character echo", setmod, 1, MODE_LIT_ECHO },
115829181Smarkm    { "+litecho", 0,				setmod, 1, MODE_LIT_ECHO },
115929088Smarkm    { "-litecho", "Disable literal character echo", clearmode, 1, MODE_LIT_ECHO },
116087139Smarkm    { "help",	0,				(int (*)(int))modehelp, 0, 0 },
116129088Smarkm#ifdef	KLUDGELINEMODE
116287139Smarkm    { "kludgeline", 0,				(int (*)(int))dokludgemode, 1, 0 },
116329088Smarkm#endif
116487139Smarkm    { "", "", NULL, 0, 0 },
116587139Smarkm    { "?",	"Print help information",	(int (*)(int))modehelp, 0, 0 },
116687139Smarkm    { NULL, NULL, NULL, 0, 0 },
116729088Smarkm};
116829088Smarkm
116929088Smarkm
117087139Smarkmstatic int
117187139Smarkmmodehelp(void)
117229088Smarkm{
117329088Smarkm    struct modelist *mt;
117429088Smarkm
117529088Smarkm    printf("format is:  'mode Mode', where 'Mode' is one of:\n\n");
117629088Smarkm    for (mt = ModeList; mt->name; mt++) {
117729088Smarkm	if (mt->help) {
117829088Smarkm	    if (*mt->help)
117929088Smarkm		printf("%-15s %s\n", mt->name, mt->help);
118029088Smarkm	    else
118129088Smarkm		printf("\n");
118229088Smarkm	}
118329088Smarkm    }
118429088Smarkm    return 0;
118529088Smarkm}
118629088Smarkm
118729088Smarkm#define	GETMODECMD(name) (struct modelist *) \
118829088Smarkm		genget(name, (char **) ModeList, sizeof(struct modelist))
118929088Smarkm
119087139Smarkmstatic int
119187139Smarkmmodecmd(int argc, char *argv[])
119229088Smarkm{
119329088Smarkm    struct modelist *mt;
119429088Smarkm
119529088Smarkm    if (argc != 2) {
119629088Smarkm	printf("'mode' command requires an argument\n");
119729088Smarkm	printf("'mode ?' for help.\n");
119829088Smarkm    } else if ((mt = GETMODECMD(argv[1])) == 0) {
119929088Smarkm	fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]);
120087139Smarkm    } else if (Ambiguous((void *)mt)) {
120129088Smarkm	fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]);
120229088Smarkm    } else if (mt->needconnect && !connected) {
120329088Smarkm	printf("?Need to be connected first.\n");
120429088Smarkm	printf("'mode ?' for help.\n");
120529088Smarkm    } else if (mt->handler) {
120629088Smarkm	return (*mt->handler)(mt->arg1);
120729088Smarkm    }
120829088Smarkm    return 0;
120929088Smarkm}
121029088Smarkm
121129088Smarkm/*
121229088Smarkm * The following data structures and routines implement the
121329088Smarkm * "display" command.
121429088Smarkm */
121529088Smarkm
121687139Smarkmstatic int
121787139Smarkmdisplay(int argc, char *argv[])
121829088Smarkm{
121929088Smarkm    struct togglelist *tl;
122029088Smarkm    struct setlist *sl;
122129088Smarkm
122229088Smarkm#define	dotog(tl)	if (tl->variable && tl->actionexplanation) { \
122329088Smarkm			    if (*tl->variable) { \
122429088Smarkm				printf("will"); \
122529088Smarkm			    } else { \
122629088Smarkm				printf("won't"); \
122729088Smarkm			    } \
122829088Smarkm			    printf(" %s.\n", tl->actionexplanation); \
122929088Smarkm			}
123029088Smarkm
123129088Smarkm#define	doset(sl)   if (sl->name && *sl->name != ' ') { \
123229088Smarkm			if (sl->handler == 0) \
123329088Smarkm			    printf("%-15s [%s]\n", sl->name, control(*sl->charp)); \
123429088Smarkm			else \
123529088Smarkm			    printf("%-15s \"%s\"\n", sl->name, (char *)sl->charp); \
123629088Smarkm		    }
123729088Smarkm
123829088Smarkm    if (argc == 1) {
123929088Smarkm	for (tl = Togglelist; tl->name; tl++) {
124029088Smarkm	    dotog(tl);
124129088Smarkm	}
124229088Smarkm	printf("\n");
124329088Smarkm	for (sl = Setlist; sl->name; sl++) {
124429088Smarkm	    doset(sl);
124529088Smarkm	}
124629088Smarkm    } else {
124729088Smarkm	int i;
124829088Smarkm
124929088Smarkm	for (i = 1; i < argc; i++) {
125029088Smarkm	    sl = getset(argv[i]);
125129088Smarkm	    tl = GETTOGGLE(argv[i]);
125287139Smarkm	    if (Ambiguous((void *)sl) || Ambiguous((void *)tl)) {
125329088Smarkm		printf("?Ambiguous argument '%s'.\n", argv[i]);
125429088Smarkm		return 0;
125529088Smarkm	    } else if (!sl && !tl) {
125629088Smarkm		printf("?Unknown argument '%s'.\n", argv[i]);
125729088Smarkm		return 0;
125829088Smarkm	    } else {
125929088Smarkm		if (tl) {
126029088Smarkm		    dotog(tl);
126129088Smarkm		}
126229088Smarkm		if (sl) {
126329088Smarkm		    doset(sl);
126429088Smarkm		}
126529088Smarkm	    }
126629088Smarkm	}
126729088Smarkm    }
126829088Smarkm/*@*/optionstatus();
126929088Smarkm#ifdef	ENCRYPTION
127029088Smarkm    EncryptStatus();
127129088Smarkm#endif	/* ENCRYPTION */
127229088Smarkm    return 1;
127329088Smarkm#undef	doset
127429088Smarkm#undef	dotog
127529088Smarkm}
127629088Smarkm
127729088Smarkm/*
127829088Smarkm * The following are the data structures, and many of the routines,
127929088Smarkm * relating to command processing.
128029088Smarkm */
128129088Smarkm
128229088Smarkm/*
128329088Smarkm * Set the escape character.
128429088Smarkm */
128587139Smarkmstatic int
128687139Smarkmsetescape(int argc, char *argv[])
128729088Smarkm{
128887139Smarkm	char *arg;
128929088Smarkm	char buf[50];
129029088Smarkm
129129088Smarkm	printf(
129229088Smarkm	    "Deprecated usage - please use 'set escape%s%s' in the future.\n",
129329088Smarkm				(argc > 2)? " ":"", (argc > 2)? argv[1]: "");
129429088Smarkm	if (argc > 2)
129529088Smarkm		arg = argv[1];
129629088Smarkm	else {
129729088Smarkm		printf("new escape character: ");
129829088Smarkm		(void) fgets(buf, sizeof(buf), stdin);
129929088Smarkm		arg = buf;
130029088Smarkm	}
130129088Smarkm	if (arg[0] != '\0')
130229088Smarkm		escape = arg[0];
130329088Smarkm	(void) fflush(stdout);
130429088Smarkm	return 1;
130529088Smarkm}
130629088Smarkm
130787139Smarkmstatic int
130887139Smarkmtogcrmod(void)
130929088Smarkm{
131029088Smarkm    crmod = !crmod;
131129088Smarkm    printf("Deprecated usage - please use 'toggle crmod' in the future.\n");
131229088Smarkm    printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't");
131329088Smarkm    (void) fflush(stdout);
131429088Smarkm    return 1;
131529088Smarkm}
131629088Smarkm
131787139Smarkmstatic int
131887139Smarkmsuspend(void)
131929088Smarkm{
132029088Smarkm#ifdef	SIGTSTP
132129088Smarkm    setcommandmode();
132229088Smarkm    {
132387139Smarkm	long oldrows, oldcols, newrows, newcols, err_;
132429088Smarkm
132587139Smarkm	err_ = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0;
132629088Smarkm	(void) kill(0, SIGTSTP);
132729088Smarkm	/*
132829088Smarkm	 * If we didn't get the window size before the SUSPEND, but we
132929088Smarkm	 * can get them now (?), then send the NAWS to make sure that
133029088Smarkm	 * we are set up for the right window size.
133129088Smarkm	 */
133229088Smarkm	if (TerminalWindowSize(&newrows, &newcols) && connected &&
133387139Smarkm	    (err_ || ((oldrows != newrows) || (oldcols != newcols)))) {
133429088Smarkm		sendnaws();
133529088Smarkm	}
133629088Smarkm    }
133729088Smarkm    /* reget parameters in case they were changed */
133829088Smarkm    TerminalSaveState();
133929088Smarkm    setconnmode(0);
134029088Smarkm#else
134129088Smarkm    printf("Suspend is not supported.  Try the '!' command instead\n");
134229088Smarkm#endif
134329088Smarkm    return 1;
134429088Smarkm}
134529088Smarkm
134687139Smarkmstatic int
134787139Smarkmshell(int argc, char *argv[] __unused)
134829088Smarkm{
134987139Smarkm    long oldrows, oldcols, newrows, newcols, err_;
135029088Smarkm
135129088Smarkm    setcommandmode();
135229088Smarkm
135387139Smarkm    err_ = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0;
135429088Smarkm    switch(vfork()) {
135529088Smarkm    case -1:
135629088Smarkm	perror("Fork failed\n");
135729088Smarkm	break;
135829088Smarkm
135929088Smarkm    case 0:
136029088Smarkm	{
136129088Smarkm	    /*
136229088Smarkm	     * Fire up the shell in the child.
136329088Smarkm	     */
136487139Smarkm	    const char *shellp, *shellname;
136529088Smarkm
136629088Smarkm	    shellp = getenv("SHELL");
136729088Smarkm	    if (shellp == NULL)
136829088Smarkm		shellp = "/bin/sh";
136929088Smarkm	    if ((shellname = strrchr(shellp, '/')) == 0)
137029088Smarkm		shellname = shellp;
137129088Smarkm	    else
137229088Smarkm		shellname++;
137329088Smarkm	    if (argc > 1)
137481965Smarkm		execl(shellp, shellname, "-c", &saveline[1], (char *)0);
137529088Smarkm	    else
137681965Smarkm		execl(shellp, shellname, (char *)0);
137729088Smarkm	    perror("Execl");
137829088Smarkm	    _exit(1);
137929088Smarkm	}
138029088Smarkm    default:
138129088Smarkm	    (void)wait((int *)0);	/* Wait for the shell to complete */
138229088Smarkm
138329088Smarkm	    if (TerminalWindowSize(&newrows, &newcols) && connected &&
138487139Smarkm		(err_ || ((oldrows != newrows) || (oldcols != newcols)))) {
138529088Smarkm		    sendnaws();
138629088Smarkm	    }
138729088Smarkm	    break;
138829088Smarkm    }
138929088Smarkm    return 1;
139029088Smarkm}
139129088Smarkm
139287139Smarkmstatic int
139387139Smarkmbye(int argc, char *argv[])
139429088Smarkm{
139529088Smarkm    extern int resettermname;
139629088Smarkm
139729088Smarkm    if (connected) {
139829088Smarkm	(void) shutdown(net, 2);
139929088Smarkm	printf("Connection closed.\n");
140029088Smarkm	(void) NetClose(net);
140129088Smarkm	connected = 0;
140229088Smarkm	resettermname = 1;
140387139Smarkm#ifdef	AUTHENTICATION
140487139Smarkm#ifdef	ENCRYPTION
140529088Smarkm	auth_encrypt_connect(connected);
140687139Smarkm#endif
140787139Smarkm#endif
140829088Smarkm	/* reset options */
140929088Smarkm	tninit();
141029088Smarkm    }
141129088Smarkm    if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) {
141229088Smarkm	longjmp(toplevel, 1);
141329088Smarkm	/* NOTREACHED */
141429088Smarkm    }
141529088Smarkm    return 1;			/* Keep lint, etc., happy */
141629088Smarkm}
141729088Smarkm
141887139Smarkmvoid
141987139Smarkmquit(void)
142029088Smarkm{
142129088Smarkm	(void) call(bye, "bye", "fromquit", 0);
142229088Smarkm	Exit(0);
142329088Smarkm}
142429088Smarkm
142587139Smarkmstatic int
142687139Smarkmlogout(void)
142729088Smarkm{
142829088Smarkm	send_do(TELOPT_LOGOUT, 1);
142929088Smarkm	(void) netflush();
143029088Smarkm	return 1;
143129088Smarkm}
143229088Smarkm
143329088Smarkm
143429088Smarkm/*
143529088Smarkm * The SLC command.
143629088Smarkm */
143729088Smarkm
143829088Smarkmstruct slclist {
143987139Smarkm	const char	*name;
144087139Smarkm	const char	*help;
144187139Smarkm	void	(*handler)(int);
144229088Smarkm	int	arg;
144329088Smarkm};
144429088Smarkm
144587139Smarkmstatic void slc_help(void);
144629088Smarkm
144729088Smarkmstruct slclist SlcList[] = {
144829088Smarkm    { "export",	"Use local special character definitions",
144987139Smarkm						(void (*)(int))slc_mode_export,	0 },
145029088Smarkm    { "import",	"Use remote special character definitions",
145129088Smarkm						slc_mode_import,	1 },
145229088Smarkm    { "check",	"Verify remote special character definitions",
145329088Smarkm						slc_mode_import,	0 },
145487139Smarkm    { "help",	NULL,				(void (*)(int))slc_help,		0 },
145587139Smarkm    { "?",	"Print help information",	(void (*)(int))slc_help,		0 },
145687139Smarkm    { NULL, NULL, NULL, 0 },
145729088Smarkm};
145829088Smarkm
145987139Smarkmstatic void
146087139Smarkmslc_help(void)
146129088Smarkm{
146229088Smarkm    struct slclist *c;
146329088Smarkm
146429088Smarkm    for (c = SlcList; c->name; c++) {
146529088Smarkm	if (c->help) {
146629088Smarkm	    if (*c->help)
146729088Smarkm		printf("%-15s %s\n", c->name, c->help);
146829088Smarkm	    else
146929088Smarkm		printf("\n");
147029088Smarkm	}
147129088Smarkm    }
147229088Smarkm}
147329088Smarkm
147487139Smarkmstatic struct slclist *
147587139Smarkmgetslc(char *name)
147629088Smarkm{
147729088Smarkm    return (struct slclist *)
147829088Smarkm		genget(name, (char **) SlcList, sizeof(struct slclist));
147929088Smarkm}
148029088Smarkm
148187139Smarkmstatic int
148287139Smarkmslccmd(int argc, char *argv[])
148329088Smarkm{
148429088Smarkm    struct slclist *c;
148529088Smarkm
148629088Smarkm    if (argc != 2) {
148729088Smarkm	fprintf(stderr,
148829088Smarkm	    "Need an argument to 'slc' command.  'slc ?' for help.\n");
148929088Smarkm	return 0;
149029088Smarkm    }
149129088Smarkm    c = getslc(argv[1]);
149229088Smarkm    if (c == 0) {
149329088Smarkm	fprintf(stderr, "'%s': unknown argument ('slc ?' for help).\n",
149429088Smarkm    				argv[1]);
149529088Smarkm	return 0;
149629088Smarkm    }
149787139Smarkm    if (Ambiguous((void *)c)) {
149829088Smarkm	fprintf(stderr, "'%s': ambiguous argument ('slc ?' for help).\n",
149929088Smarkm    				argv[1]);
150029088Smarkm	return 0;
150129088Smarkm    }
150229088Smarkm    (*c->handler)(c->arg);
150329088Smarkm    slcstate();
150429088Smarkm    return 1;
150529088Smarkm}
150629088Smarkm
150729088Smarkm/*
150829088Smarkm * The ENVIRON command.
150929088Smarkm */
151029088Smarkm
151129088Smarkmstruct envlist {
151287139Smarkm	const char	*name;
151387139Smarkm	const char	*help;
151487139Smarkm	void	(*handler)(unsigned char *, unsigned char *);
151529088Smarkm	int	narg;
151629088Smarkm};
151729088Smarkm
151829088Smarkmextern struct env_lst *
151987155Smarkm	env_define(const unsigned char *, unsigned char *);
152029088Smarkmextern void
152187155Smarkm	env_undefine(unsigned char *),
152287155Smarkm	env_export(const unsigned char *),
152387155Smarkm	env_unexport(const unsigned char *),
152487155Smarkm	env_send(unsigned char *),
152529088Smarkm#if defined(OLD_ENVIRON) && defined(ENV_HACK)
152687155Smarkm	env_varval(unsigned char *),
152729088Smarkm#endif
152887155Smarkm	env_list(void);
152929088Smarkmstatic void
153087155Smarkm	env_help(void);
153129088Smarkm
153229088Smarkmstruct envlist EnvList[] = {
153329088Smarkm    { "define",	"Define an environment variable",
153487139Smarkm						(void (*)(unsigned char *, unsigned char *))env_define,	2 },
153529088Smarkm    { "undefine", "Undefine an environment variable",
153687139Smarkm						(void (*)(unsigned char *, unsigned char *))env_undefine,	1 },
153729088Smarkm    { "export",	"Mark an environment variable for automatic export",
153887139Smarkm						(void (*)(unsigned char *, unsigned char *))env_export,	1 },
153929088Smarkm    { "unexport", "Don't mark an environment variable for automatic export",
154087139Smarkm						(void (*)(unsigned char *, unsigned char *))env_unexport,	1 },
154187139Smarkm    { "send",	"Send an environment variable", (void (*)(unsigned char *, unsigned char *))env_send,	1 },
154229088Smarkm    { "list",	"List the current environment variables",
154387139Smarkm						(void (*)(unsigned char *, unsigned char *))env_list,	0 },
154429088Smarkm#if defined(OLD_ENVIRON) && defined(ENV_HACK)
154529088Smarkm    { "varval", "Reverse VAR and VALUE (auto, right, wrong, status)",
154687139Smarkm						(void (*)(unsigned char *, unsigned char *))env_varval,    1 },
154729088Smarkm#endif
154887139Smarkm    { "help",	NULL,				(void (*)(unsigned char *, unsigned char *))env_help,		0 },
154987139Smarkm    { "?",	"Print help information",	(void (*)(unsigned char *, unsigned char *))env_help,		0 },
155087139Smarkm    { NULL, NULL, NULL, 0 },
155129088Smarkm};
155229088Smarkm
155387139Smarkmstatic void
155487139Smarkmenv_help(void)
155529088Smarkm{
155629088Smarkm    struct envlist *c;
155729088Smarkm
155829088Smarkm    for (c = EnvList; c->name; c++) {
155929088Smarkm	if (c->help) {
156029088Smarkm	    if (*c->help)
156129088Smarkm		printf("%-15s %s\n", c->name, c->help);
156229088Smarkm	    else
156329088Smarkm		printf("\n");
156429088Smarkm	}
156529088Smarkm    }
156629088Smarkm}
156729088Smarkm
156887139Smarkmstatic struct envlist *
156987139Smarkmgetenvcmd(char *name)
157029088Smarkm{
157129088Smarkm    return (struct envlist *)
157229088Smarkm		genget(name, (char **) EnvList, sizeof(struct envlist));
157329088Smarkm}
157429088Smarkm
157587139Smarkmstatic int
157687139Smarkmenv_cmd(int argc, char *argv[])
157729088Smarkm{
157829088Smarkm    struct envlist *c;
157929088Smarkm
158029088Smarkm    if (argc < 2) {
158129088Smarkm	fprintf(stderr,
158229088Smarkm	    "Need an argument to 'environ' command.  'environ ?' for help.\n");
158329088Smarkm	return 0;
158429088Smarkm    }
158529088Smarkm    c = getenvcmd(argv[1]);
158629088Smarkm    if (c == 0) {
158729088Smarkm	fprintf(stderr, "'%s': unknown argument ('environ ?' for help).\n",
158829088Smarkm    				argv[1]);
158929088Smarkm	return 0;
159029088Smarkm    }
159187139Smarkm    if (Ambiguous((void *)c)) {
159229088Smarkm	fprintf(stderr, "'%s': ambiguous argument ('environ ?' for help).\n",
159329088Smarkm    				argv[1]);
159429088Smarkm	return 0;
159529088Smarkm    }
159629088Smarkm    if (c->narg + 2 != argc) {
159729088Smarkm	fprintf(stderr,
159829088Smarkm	    "Need %s%d argument%s to 'environ %s' command.  'environ ?' for help.\n",
159929088Smarkm		c->narg < argc + 2 ? "only " : "",
160029088Smarkm		c->narg, c->narg == 1 ? "" : "s", c->name);
160129088Smarkm	return 0;
160229088Smarkm    }
160329088Smarkm    (*c->handler)(argv[2], argv[3]);
160429088Smarkm    return 1;
160529088Smarkm}
160629088Smarkm
160729088Smarkmstruct env_lst {
160829088Smarkm	struct env_lst *next;	/* pointer to next structure */
160929088Smarkm	struct env_lst *prev;	/* pointer to previous structure */
161029088Smarkm	unsigned char *var;	/* pointer to variable name */
161129088Smarkm	unsigned char *value;	/* pointer to variable value */
161229088Smarkm	int export;		/* 1 -> export with default list of variables */
161329088Smarkm	int welldefined;	/* A well defined variable */
161429088Smarkm};
161529088Smarkm
161629088Smarkmstruct env_lst envlisthead;
161729088Smarkm
161887139Smarkmstatic struct env_lst *
161987139Smarkmenv_find(const unsigned char *var)
162029088Smarkm{
162187139Smarkm	struct env_lst *ep;
162229088Smarkm
162329088Smarkm	for (ep = envlisthead.next; ep; ep = ep->next) {
162487139Smarkm		if (strcmp(ep->var, var) == 0)
162529088Smarkm			return(ep);
162629088Smarkm	}
162729088Smarkm	return(NULL);
162829088Smarkm}
162929088Smarkm
163087139Smarkmvoid
163187139Smarkmenv_init(void)
163229088Smarkm{
163329088Smarkm	extern char **environ;
163487139Smarkm	char **epp, *cp;
163587139Smarkm	struct env_lst *ep;
163629088Smarkm
163729088Smarkm	for (epp = environ; *epp; epp++) {
163829181Smarkm		if ((cp = strchr(*epp, '='))) {
163929088Smarkm			*cp = '\0';
164029088Smarkm			ep = env_define((unsigned char *)*epp,
164129088Smarkm					(unsigned char *)cp+1);
164229088Smarkm			ep->export = 0;
164329088Smarkm			*cp = '=';
164429088Smarkm		}
164529088Smarkm	}
164629088Smarkm	/*
164729088Smarkm	 * Special case for DISPLAY variable.  If it is ":0.0" or
164829088Smarkm	 * "unix:0.0", we have to get rid of "unix" and insert our
164929088Smarkm	 * hostname.
165029088Smarkm	 */
165129088Smarkm	if ((ep = env_find("DISPLAY"))
165229088Smarkm	    && ((*ep->value == ':')
165329088Smarkm		|| (strncmp((char *)ep->value, "unix:", 5) == 0))) {
165429088Smarkm		char hbuf[256+1];
165529088Smarkm		char *cp2 = strchr((char *)ep->value, ':');
165629088Smarkm
165729088Smarkm		gethostname(hbuf, 256);
165829088Smarkm		hbuf[256] = '\0';
165929088Smarkm		cp = (char *)malloc(strlen(hbuf) + strlen(cp2) + 1);
166029088Smarkm		sprintf((char *)cp, "%s%s", hbuf, cp2);
166129088Smarkm		free(ep->value);
166229088Smarkm		ep->value = (unsigned char *)cp;
166329088Smarkm	}
166429088Smarkm	/*
166529088Smarkm	 * If USER is not defined, but LOGNAME is, then add
166629088Smarkm	 * USER with the value from LOGNAME.  By default, we
166729088Smarkm	 * don't export the USER variable.
166829088Smarkm	 */
166929088Smarkm	if ((env_find("USER") == NULL) && (ep = env_find("LOGNAME"))) {
167087139Smarkm		env_define("USER", ep->value);
167187139Smarkm		env_unexport("USER");
167229088Smarkm	}
167387139Smarkm	env_export("DISPLAY");
167487139Smarkm	env_export("PRINTER");
167529088Smarkm}
167629088Smarkm
167787139Smarkmstruct env_lst *
167887139Smarkmenv_define(const unsigned char *var, unsigned char *value)
167929088Smarkm{
168087139Smarkm	struct env_lst *ep;
168129088Smarkm
168229181Smarkm	if ((ep = env_find(var))) {
168329088Smarkm		if (ep->var)
168429088Smarkm			free(ep->var);
168529088Smarkm		if (ep->value)
168629088Smarkm			free(ep->value);
168729088Smarkm	} else {
168829088Smarkm		ep = (struct env_lst *)malloc(sizeof(struct env_lst));
168929088Smarkm		ep->next = envlisthead.next;
169029088Smarkm		envlisthead.next = ep;
169129088Smarkm		ep->prev = &envlisthead;
169229088Smarkm		if (ep->next)
169329088Smarkm			ep->next->prev = ep;
169429088Smarkm	}
169529088Smarkm	ep->welldefined = opt_welldefined(var);
169629088Smarkm	ep->export = 1;
169787139Smarkm	ep->var = strdup(var);
169887139Smarkm	ep->value = strdup(value);
169929088Smarkm	return(ep);
170029088Smarkm}
170129088Smarkm
170287139Smarkmvoid
170387139Smarkmenv_undefine(unsigned char *var)
170429088Smarkm{
170587139Smarkm	struct env_lst *ep;
170629088Smarkm
170729181Smarkm	if ((ep = env_find(var))) {
170829088Smarkm		ep->prev->next = ep->next;
170929088Smarkm		if (ep->next)
171029088Smarkm			ep->next->prev = ep->prev;
171129088Smarkm		if (ep->var)
171229088Smarkm			free(ep->var);
171329088Smarkm		if (ep->value)
171429088Smarkm			free(ep->value);
171529088Smarkm		free(ep);
171629088Smarkm	}
171729088Smarkm}
171829088Smarkm
171987139Smarkmvoid
172087139Smarkmenv_export(const unsigned char *var)
172129088Smarkm{
172287139Smarkm	struct env_lst *ep;
172329088Smarkm
172429181Smarkm	if ((ep = env_find(var)))
172529088Smarkm		ep->export = 1;
172629088Smarkm}
172729088Smarkm
172887139Smarkmvoid
172987139Smarkmenv_unexport(const unsigned char *var)
173029088Smarkm{
173187139Smarkm	struct env_lst *ep;
173229088Smarkm
173329181Smarkm	if ((ep = env_find(var)))
173429088Smarkm		ep->export = 0;
173529088Smarkm}
173629088Smarkm
173787139Smarkmvoid
173887139Smarkmenv_send(unsigned char *var)
173929088Smarkm{
174087139Smarkm	struct env_lst *ep;
174129088Smarkm
174229088Smarkm	if (my_state_is_wont(TELOPT_NEW_ENVIRON)
174329088Smarkm#ifdef	OLD_ENVIRON
174429088Smarkm	    && my_state_is_wont(TELOPT_OLD_ENVIRON)
174529088Smarkm#endif
174629088Smarkm		) {
174729088Smarkm		fprintf(stderr,
174829088Smarkm		    "Cannot send '%s': Telnet ENVIRON option not enabled\n",
174929088Smarkm									var);
175029088Smarkm		return;
175129088Smarkm	}
175229088Smarkm	ep = env_find(var);
175329088Smarkm	if (ep == 0) {
175429088Smarkm		fprintf(stderr, "Cannot send '%s': variable not defined\n",
175529088Smarkm									var);
175629088Smarkm		return;
175729088Smarkm	}
175829088Smarkm	env_opt_start_info();
175929088Smarkm	env_opt_add(ep->var);
176029088Smarkm	env_opt_end(0);
176129088Smarkm}
176229088Smarkm
176387139Smarkmvoid
176487139Smarkmenv_list(void)
176529088Smarkm{
176687139Smarkm	struct env_lst *ep;
176729088Smarkm
176829088Smarkm	for (ep = envlisthead.next; ep; ep = ep->next) {
176929088Smarkm		printf("%c %-20s %s\n", ep->export ? '*' : ' ',
177029088Smarkm					ep->var, ep->value);
177129088Smarkm	}
177229088Smarkm}
177329088Smarkm
177487139Smarkmunsigned char *
177587139Smarkmenv_default(int init, int welldefined)
177629088Smarkm{
177729088Smarkm	static struct env_lst *nep = NULL;
177829088Smarkm
177929088Smarkm	if (init) {
178029088Smarkm		nep = &envlisthead;
178129181Smarkm		return(NULL);
178229088Smarkm	}
178329088Smarkm	if (nep) {
178429181Smarkm		while ((nep = nep->next)) {
178529088Smarkm			if (nep->export && (nep->welldefined == welldefined))
178629088Smarkm				return(nep->var);
178729088Smarkm		}
178829088Smarkm	}
178929088Smarkm	return(NULL);
179029088Smarkm}
179129088Smarkm
179287139Smarkmunsigned char *
179387139Smarkmenv_getvalue(const unsigned char *var)
179429088Smarkm{
179587139Smarkm	struct env_lst *ep;
179629088Smarkm
179729181Smarkm	if ((ep = env_find(var)))
179829088Smarkm		return(ep->value);
179929088Smarkm	return(NULL);
180029088Smarkm}
180129088Smarkm
180229088Smarkm#if defined(OLD_ENVIRON) && defined(ENV_HACK)
180387139Smarkmvoid
180487139Smarkmenv_varval(unsigned char *what)
180529088Smarkm{
180629088Smarkm	extern int old_env_var, old_env_value, env_auto;
180729088Smarkm	int len = strlen((char *)what);
180829088Smarkm
180929088Smarkm	if (len == 0)
181029088Smarkm		goto unknown;
181129088Smarkm
181229088Smarkm	if (strncasecmp((char *)what, "status", len) == 0) {
181329088Smarkm		if (env_auto)
181429088Smarkm			printf("%s%s", "VAR and VALUE are/will be ",
181529088Smarkm					"determined automatically\n");
181629088Smarkm		if (old_env_var == OLD_ENV_VAR)
181729088Smarkm			printf("VAR and VALUE set to correct definitions\n");
181829088Smarkm		else
181929088Smarkm			printf("VAR and VALUE definitions are reversed\n");
182029088Smarkm	} else if (strncasecmp((char *)what, "auto", len) == 0) {
182129088Smarkm		env_auto = 1;
182229088Smarkm		old_env_var = OLD_ENV_VALUE;
182329088Smarkm		old_env_value = OLD_ENV_VAR;
182429088Smarkm	} else if (strncasecmp((char *)what, "right", len) == 0) {
182529088Smarkm		env_auto = 0;
182629088Smarkm		old_env_var = OLD_ENV_VAR;
182729088Smarkm		old_env_value = OLD_ENV_VALUE;
182829088Smarkm	} else if (strncasecmp((char *)what, "wrong", len) == 0) {
182929088Smarkm		env_auto = 0;
183029088Smarkm		old_env_var = OLD_ENV_VALUE;
183129088Smarkm		old_env_value = OLD_ENV_VAR;
183229088Smarkm	} else {
183329088Smarkmunknown:
183429088Smarkm		printf("Unknown \"varval\" command. (\"auto\", \"right\", \"wrong\", \"status\")\n");
183529088Smarkm	}
183629088Smarkm}
183729088Smarkm#endif
183829088Smarkm
183987139Smarkm#ifdef	AUTHENTICATION
184029088Smarkm/*
184129088Smarkm * The AUTHENTICATE command.
184229088Smarkm */
184329088Smarkm
184429088Smarkmstruct authlist {
184587139Smarkm	const char	*name;
184687139Smarkm	const char	*help;
184787139Smarkm	int	(*handler)(char *);
184829088Smarkm	int	narg;
184929088Smarkm};
185029088Smarkm
185129088Smarkmextern int
185287155Smarkm	auth_enable(char *),
185387155Smarkm	auth_disable(char *),
185487155Smarkm	auth_status(void);
185529088Smarkmstatic int
185687155Smarkm	auth_help(void);
185729088Smarkm
185829088Smarkmstruct authlist AuthList[] = {
185929088Smarkm    { "status",	"Display current status of authentication information",
186087139Smarkm						(int (*)(char *))auth_status,	0 },
186129088Smarkm    { "disable", "Disable an authentication type ('auth disable ?' for more)",
186229088Smarkm						auth_disable,	1 },
186329088Smarkm    { "enable", "Enable an authentication type ('auth enable ?' for more)",
186429088Smarkm						auth_enable,	1 },
186587139Smarkm    { "help",	NULL,				(int (*)(char *))auth_help,		0 },
186687139Smarkm    { "?",	"Print help information",	(int (*)(char *))auth_help,		0 },
186787139Smarkm    { NULL, NULL, NULL, 0 },
186829088Smarkm};
186929088Smarkm
187087139Smarkmstatic int
187187139Smarkmauth_help(void)
187229088Smarkm{
187329088Smarkm    struct authlist *c;
187429088Smarkm
187529088Smarkm    for (c = AuthList; c->name; c++) {
187629088Smarkm	if (c->help) {
187729088Smarkm	    if (*c->help)
187829088Smarkm		printf("%-15s %s\n", c->name, c->help);
187929088Smarkm	    else
188029088Smarkm		printf("\n");
188129088Smarkm	}
188229088Smarkm    }
188329088Smarkm    return 0;
188429088Smarkm}
188529088Smarkm
188687139Smarkmint
188787139Smarkmauth_cmd(int argc, char *argv[])
188829088Smarkm{
188929088Smarkm    struct authlist *c;
189029088Smarkm
189129088Smarkm    if (argc < 2) {
189229088Smarkm	fprintf(stderr,
189329088Smarkm	    "Need an argument to 'auth' command.  'auth ?' for help.\n");
189429088Smarkm	return 0;
189529088Smarkm    }
189629088Smarkm
189729088Smarkm    c = (struct authlist *)
189829088Smarkm		genget(argv[1], (char **) AuthList, sizeof(struct authlist));
189929088Smarkm    if (c == 0) {
190029088Smarkm	fprintf(stderr, "'%s': unknown argument ('auth ?' for help).\n",
190129088Smarkm    				argv[1]);
190229088Smarkm	return 0;
190329088Smarkm    }
190487139Smarkm    if (Ambiguous((void *)c)) {
190529088Smarkm	fprintf(stderr, "'%s': ambiguous argument ('auth ?' for help).\n",
190629088Smarkm    				argv[1]);
190729088Smarkm	return 0;
190829088Smarkm    }
190929088Smarkm    if (c->narg + 2 != argc) {
191029088Smarkm	fprintf(stderr,
191129088Smarkm	    "Need %s%d argument%s to 'auth %s' command.  'auth ?' for help.\n",
191229088Smarkm		c->narg < argc + 2 ? "only " : "",
191329088Smarkm		c->narg, c->narg == 1 ? "" : "s", c->name);
191429088Smarkm	return 0;
191529088Smarkm    }
191687139Smarkm    return((*c->handler)(argv[2]));
191729088Smarkm}
191829088Smarkm#endif
191929088Smarkm
192029088Smarkm#ifdef	ENCRYPTION
192129088Smarkm/*
192229088Smarkm * The ENCRYPT command.
192329088Smarkm */
192429088Smarkm
192529088Smarkmstruct encryptlist {
192687139Smarkm	const char	*name;
192787139Smarkm	const char	*help;
192887139Smarkm	int	(*handler)(char *, char *);
192929088Smarkm	int	needconnect;
193029088Smarkm	int	minarg;
193129088Smarkm	int	maxarg;
193229088Smarkm};
193329088Smarkm
193429088Smarkmextern int
193587155Smarkm	EncryptEnable(char *, char *),
193687155Smarkm	EncryptDisable(char *, char *),
193787155Smarkm	EncryptType(char *, char *),
193887155Smarkm	EncryptStart(char *),
193987155Smarkm	EncryptStartInput(void),
194087155Smarkm	EncryptStartOutput(void),
194187155Smarkm	EncryptStop(char *),
194287155Smarkm	EncryptStopInput(void),
194387155Smarkm	EncryptStopOutput(void),
194487155Smarkm	EncryptStatus(void);
194529088Smarkmstatic int
194687155Smarkm	EncryptHelp(void);
194729088Smarkm
194829088Smarkmstruct encryptlist EncryptList[] = {
194929088Smarkm    { "enable", "Enable encryption. ('encrypt enable ?' for more)",
195029088Smarkm						EncryptEnable, 1, 1, 2 },
195129088Smarkm    { "disable", "Disable encryption. ('encrypt enable ?' for more)",
195229088Smarkm						EncryptDisable, 0, 1, 2 },
195329088Smarkm    { "type", "Set encryption type. ('encrypt type ?' for more)",
195429088Smarkm						EncryptType, 0, 1, 1 },
195529088Smarkm    { "start", "Start encryption. ('encrypt start ?' for more)",
195687139Smarkm						(int (*)(char *, char *))EncryptStart, 1, 0, 1 },
195729088Smarkm    { "stop", "Stop encryption. ('encrypt stop ?' for more)",
195887139Smarkm						(int (*)(char *, char *))EncryptStop, 1, 0, 1 },
195929088Smarkm    { "input", "Start encrypting the input stream",
196087139Smarkm						(int (*)(char *, char *))EncryptStartInput, 1, 0, 0 },
196129088Smarkm    { "-input", "Stop encrypting the input stream",
196287139Smarkm						(int (*)(char *, char *))EncryptStopInput, 1, 0, 0 },
196329088Smarkm    { "output", "Start encrypting the output stream",
196487139Smarkm						(int (*)(char *, char *))EncryptStartOutput, 1, 0, 0 },
196529088Smarkm    { "-output", "Stop encrypting the output stream",
196687139Smarkm						(int (*)(char *, char *))EncryptStopOutput, 1, 0, 0 },
196729088Smarkm
196829088Smarkm    { "status",	"Display current status of authentication information",
196987139Smarkm						(int (*)(char *, char *))EncryptStatus,	0, 0, 0 },
197087139Smarkm    { "help",	NULL,				(int (*)(char *, char *))EncryptHelp,	0, 0, 0 },
197187139Smarkm    { "?",	"Print help information",	(int (*)(char *, char *))EncryptHelp,	0, 0, 0 },
197287139Smarkm    { NULL, NULL, NULL, 0, 0, 0 },
197329088Smarkm};
197429088Smarkm
197587139Smarkmstatic int
197687139SmarkmEncryptHelp(void)
197729088Smarkm{
197829088Smarkm    struct encryptlist *c;
197929088Smarkm
198029088Smarkm    for (c = EncryptList; c->name; c++) {
198129088Smarkm	if (c->help) {
198229088Smarkm	    if (*c->help)
198329088Smarkm		printf("%-15s %s\n", c->name, c->help);
198429088Smarkm	    else
198529088Smarkm		printf("\n");
198629088Smarkm	}
198729088Smarkm    }
198829088Smarkm    return 0;
198929088Smarkm}
199029088Smarkm
199187139Smarkmstatic int
199287139Smarkmencrypt_cmd(int argc, char *argv[])
199329088Smarkm{
199429088Smarkm    struct encryptlist *c;
199529088Smarkm
199629088Smarkm    if (argc < 2) {
199729088Smarkm	fprintf(stderr,
199829088Smarkm	    "Need an argument to 'encrypt' command.  'encrypt ?' for help.\n");
199929088Smarkm	return 0;
200029088Smarkm    }
200129088Smarkm
200229088Smarkm    c = (struct encryptlist *)
200329088Smarkm		genget(argv[1], (char **) EncryptList, sizeof(struct encryptlist));
200429088Smarkm    if (c == 0) {
200529088Smarkm	fprintf(stderr, "'%s': unknown argument ('encrypt ?' for help).\n",
200629088Smarkm    				argv[1]);
200729088Smarkm	return 0;
200829088Smarkm    }
200987139Smarkm    if (Ambiguous((void *)c)) {
201029088Smarkm	fprintf(stderr, "'%s': ambiguous argument ('encrypt ?' for help).\n",
201129088Smarkm    				argv[1]);
201229088Smarkm	return 0;
201329088Smarkm    }
201429088Smarkm    argc -= 2;
201529088Smarkm    if (argc < c->minarg || argc > c->maxarg) {
201629088Smarkm	if (c->minarg == c->maxarg) {
201729088Smarkm	    fprintf(stderr, "Need %s%d argument%s ",
201829088Smarkm		c->minarg < argc ? "only " : "", c->minarg,
201929088Smarkm		c->minarg == 1 ? "" : "s");
202029088Smarkm	} else {
202129088Smarkm	    fprintf(stderr, "Need %s%d-%d arguments ",
202229088Smarkm		c->maxarg < argc ? "only " : "", c->minarg, c->maxarg);
202329088Smarkm	}
202429088Smarkm	fprintf(stderr, "to 'encrypt %s' command.  'encrypt ?' for help.\n",
202529088Smarkm		c->name);
202629088Smarkm	return 0;
202729088Smarkm    }
202829088Smarkm    if (c->needconnect && !connected) {
202929088Smarkm	if (!(argc && (isprefix(argv[2], "help") || isprefix(argv[2], "?")))) {
203029088Smarkm	    printf("?Need to be connected first.\n");
203129088Smarkm	    return 0;
203229088Smarkm	}
203329088Smarkm    }
203429088Smarkm    return ((*c->handler)(argc > 0 ? argv[2] : 0,
203587139Smarkm			argc > 1 ? argv[3] : 0));
203629088Smarkm}
203729088Smarkm#endif	/* ENCRYPTION */
203829088Smarkm
203929088Smarkm/*
204029088Smarkm * Print status about the connection.
204129088Smarkm */
204287139Smarkm/*ARGSUSED*/
204387139Smarkmstatic int
204487139Smarkmstatus(int argc, char *argv[])
204529088Smarkm{
204629088Smarkm    if (connected) {
204729088Smarkm	printf("Connected to %s.\n", hostname);
204829088Smarkm	if ((argc < 2) || strcmp(argv[1], "notmuch")) {
204929088Smarkm	    int mode = getconnmode();
205029088Smarkm
205129088Smarkm	    if (my_want_state_is_will(TELOPT_LINEMODE)) {
205229088Smarkm		printf("Operating with LINEMODE option\n");
205329088Smarkm		printf("%s line editing\n", (mode&MODE_EDIT) ? "Local" : "No");
205429088Smarkm		printf("%s catching of signals\n",
205529088Smarkm					(mode&MODE_TRAPSIG) ? "Local" : "No");
205629088Smarkm		slcstate();
205729088Smarkm#ifdef	KLUDGELINEMODE
205829088Smarkm	    } else if (kludgelinemode && my_want_state_is_dont(TELOPT_SGA)) {
205929088Smarkm		printf("Operating in obsolete linemode\n");
206029088Smarkm#endif
206129088Smarkm	    } else {
206229088Smarkm		printf("Operating in single character mode\n");
206329088Smarkm		if (localchars)
206429088Smarkm		    printf("Catching signals locally\n");
206529088Smarkm	    }
206629088Smarkm	    printf("%s character echo\n", (mode&MODE_ECHO) ? "Local" : "Remote");
206729088Smarkm	    if (my_want_state_is_will(TELOPT_LFLOW))
206829088Smarkm		printf("%s flow control\n", (mode&MODE_FLOW) ? "Local" : "No");
206929088Smarkm#ifdef	ENCRYPTION
207029088Smarkm	    encrypt_display();
207129088Smarkm#endif	/* ENCRYPTION */
207229088Smarkm	}
207329088Smarkm    } else {
207429088Smarkm	printf("No connection.\n");
207529088Smarkm    }
207629088Smarkm    printf("Escape character is '%s'.\n", control(escape));
207729088Smarkm    (void) fflush(stdout);
207829088Smarkm    return 1;
207929088Smarkm}
208029088Smarkm
208129088Smarkm#ifdef	SIGINFO
208229088Smarkm/*
208329088Smarkm * Function that gets called when SIGINFO is received.
208429088Smarkm */
208587139Smarkmvoid
208687139Smarkmayt_status(void)
208729088Smarkm{
208829088Smarkm    (void) call(status, "status", "notmuch", 0);
208929088Smarkm}
209029088Smarkm#endif
209129088Smarkm
209256668Sshinstatic const char *
209387139Smarkmsockaddr_ntop(struct sockaddr *sa)
209456668Sshin{
209556668Sshin    void *addr;
209656668Sshin    static char addrbuf[INET6_ADDRSTRLEN];
209729088Smarkm
209856668Sshin    switch (sa->sa_family) {
209956668Sshin    case AF_INET:
210056668Sshin	addr = &((struct sockaddr_in *)sa)->sin_addr;
210156668Sshin	break;
210277095Sdillon    case AF_UNIX:
210377095Sdillon	addr = &((struct sockaddr_un *)sa)->sun_path;
210477095Sdillon	break;
210556668Sshin#ifdef INET6
210656668Sshin    case AF_INET6:
210756668Sshin	addr = &((struct sockaddr_in6 *)sa)->sin6_addr;
210856668Sshin	break;
210956668Sshin#endif
211056668Sshin    default:
211156668Sshin	return NULL;
211256668Sshin    }
211356668Sshin    inet_ntop(sa->sa_family, addr, addrbuf, sizeof(addrbuf));
211456668Sshin    return addrbuf;
211556668Sshin}
211656668Sshin
211756668Sshin#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
211856668Sshinstatic int
211987139Smarkmsetpolicy(int lnet, struct addrinfo *res, char *policy)
212056668Sshin{
212156668Sshin	char *buf;
212256668Sshin	int level;
212356668Sshin	int optname;
212456668Sshin
212556668Sshin	if (policy == NULL)
212656668Sshin		return 0;
212756668Sshin
212856668Sshin	buf = ipsec_set_policy(policy, strlen(policy));
212956668Sshin	if (buf == NULL) {
213056668Sshin		printf("%s\n", ipsec_strerror());
213156668Sshin		return -1;
213256668Sshin	}
213356668Sshin	level = res->ai_family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6;
213456668Sshin	optname = res->ai_family == AF_INET ? IP_IPSEC_POLICY : IPV6_IPSEC_POLICY;
213587139Smarkm	if (setsockopt(lnet, level, optname, buf, ipsec_get_policylen(buf)) < 0){
213656668Sshin		perror("setsockopt");
213756668Sshin		return -1;
213856668Sshin	}
213956668Sshin
214056668Sshin	free(buf);
214187139Smarkm	return 0;
214256668Sshin}
214356668Sshin#endif
214456668Sshin
214557125Sshin#ifdef INET6
214657125Sshin/*
214757125Sshin * When an Address Family related error happend, check if retry with
214857125Sshin * another AF is possible or not.
214957125Sshin * Return 1, if retry with another af is OK. Else, return 0.
215057125Sshin */
215157125Sshinstatic int
215287139Smarkmswitch_af(struct addrinfo **aip)
215357125Sshin{
215457125Sshin    int nextaf;
215557125Sshin    struct addrinfo *ai;
215657125Sshin
215757125Sshin    ai = *aip;
215857125Sshin    nextaf = (ai->ai_family == AF_INET) ? AF_INET6 : AF_INET;
215957125Sshin    do
216057125Sshin        ai=ai->ai_next;
216157125Sshin    while (ai != NULL && ai->ai_family != nextaf);
216257125Sshin    *aip = ai;
216357125Sshin    if (*aip != NULL) {
216457125Sshin        return 1;
216557125Sshin    }
216657125Sshin    return 0;
216757125Sshin}
216857125Sshin#endif
216957125Sshin
217087139Smarkmint
217187139Smarkmtn(int argc, char *argv[])
217229088Smarkm{
217381965Smarkm    char *srp = 0;
217456668Sshin    int proto, opt;
217587139Smarkm    int srlen;
217656668Sshin    int srcroute = 0, result;
217729088Smarkm    char *cmd, *hostp = 0, *portp = 0, *user = 0;
217847973Sru    char *src_addr = NULL;
217957125Sshin    struct addrinfo hints, *res, *res0 = NULL, *src_res, *src_res0 = NULL;
218057125Sshin    int error = 0, af_error = 0;
218129088Smarkm
218229088Smarkm    if (connected) {
218329088Smarkm	printf("?Already connected to %s\n", hostname);
218429088Smarkm	setuid(getuid());
218529088Smarkm	return 0;
218629088Smarkm    }
218729088Smarkm    if (argc < 2) {
218829088Smarkm	(void) strcpy(line, "open ");
218929088Smarkm	printf("(to) ");
219029088Smarkm	(void) fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin);
219129088Smarkm	makeargv();
219229088Smarkm	argc = margc;
219329088Smarkm	argv = margv;
219429088Smarkm    }
219529088Smarkm    cmd = *argv;
219629088Smarkm    --argc; ++argv;
219729088Smarkm    while (argc) {
219829088Smarkm	if (strcmp(*argv, "help") == 0 || isprefix(*argv, "?"))
219929088Smarkm	    goto usage;
220029088Smarkm	if (strcmp(*argv, "-l") == 0) {
220129088Smarkm	    --argc; ++argv;
220229088Smarkm	    if (argc == 0)
220329088Smarkm		goto usage;
220429088Smarkm	    user = *argv++;
220529088Smarkm	    --argc;
220629088Smarkm	    continue;
220729088Smarkm	}
220829088Smarkm	if (strcmp(*argv, "-a") == 0) {
220929088Smarkm	    --argc; ++argv;
221029088Smarkm	    autologin = 1;
221129088Smarkm	    continue;
221229088Smarkm	}
221347973Sru	if (strcmp(*argv, "-s") == 0) {
221447973Sru	    --argc; ++argv;
221547973Sru	    if (argc == 0)
221647973Sru		goto usage;
221747973Sru	    src_addr = *argv++;
221847973Sru	    --argc;
221947973Sru	    continue;
222047973Sru	}
222129088Smarkm	if (hostp == 0) {
222229088Smarkm	    hostp = *argv++;
222329088Smarkm	    --argc;
222429088Smarkm	    continue;
222529088Smarkm	}
222629088Smarkm	if (portp == 0) {
222729088Smarkm	    portp = *argv++;
222829088Smarkm	    --argc;
222929088Smarkm	    continue;
223029088Smarkm	}
223129088Smarkm    usage:
223247973Sru	printf("usage: %s [-l user] [-a] [-s src_addr] host-name [port]\n", cmd);
223329088Smarkm	setuid(getuid());
223429088Smarkm	return 0;
223529088Smarkm    }
223629088Smarkm    if (hostp == 0)
223729088Smarkm	goto usage;
223829088Smarkm
223947973Sru    if (src_addr != NULL) {
224056668Sshin	memset(&hints, 0, sizeof(hints));
224156668Sshin	hints.ai_family = family;
224256668Sshin	hints.ai_socktype = SOCK_STREAM;
224357125Sshin	error = getaddrinfo(src_addr, 0, &hints, &src_res);
2244121425Sume	if (error == EAI_NONAME) {
224556668Sshin		hints.ai_flags = 0;
224657125Sshin		error = getaddrinfo(src_addr, 0, &hints, &src_res);
224756668Sshin	}
224856668Sshin	if (error != 0) {
224956668Sshin		fprintf(stderr, "%s: %s\n", src_addr, gai_strerror(error));
225056668Sshin		if (error == EAI_SYSTEM)
225156668Sshin			fprintf(stderr, "%s: %s\n", src_addr, strerror(errno));
225257125Sshin		setuid(getuid());
225347973Sru		return 0;
225447973Sru	}
225557125Sshin	src_res0 = src_res;
225647973Sru    }
225777095Sdillon    if (hostp[0] == '/') {
225877095Sdillon	struct sockaddr_un su;
225977095Sdillon
226077095Sdillon	if (strlen(hostp) >= sizeof(su.sun_path)) {
226177095Sdillon	    fprintf(stderr, "hostname too long for unix domain socket: %s",
226277095Sdillon		    hostp);
226377095Sdillon		goto fail;
226477095Sdillon	}
2265139687Smaxim	hostname = hostp;
226677095Sdillon	memset(&su, 0, sizeof su);
226777095Sdillon	su.sun_family = AF_UNIX;
226877095Sdillon	strncpy(su.sun_path, hostp, sizeof su.sun_path);
226987139Smarkm	printf("Trying %s...\n", hostp);
227077095Sdillon	net = socket(PF_UNIX, SOCK_STREAM, 0);
227177095Sdillon	if ( net < 0) {
227277095Sdillon	    perror("socket");
227377095Sdillon	    goto fail;
227477095Sdillon	}
227577095Sdillon	if (connect(net, (struct sockaddr *)&su, sizeof su) == -1) {
227677095Sdillon	    perror(su.sun_path);
227777095Sdillon	    (void) NetClose(net);
227877095Sdillon	    goto fail;
227977095Sdillon	}
228077095Sdillon	goto af_unix;
228177095Sdillon    } else if (hostp[0] == '@' || hostp[0] == '!') {
228256668Sshin	if (
228356668Sshin#ifdef INET6
228456668Sshin	    family == AF_INET6 ||
228556668Sshin#endif
228656668Sshin	    (hostname = strrchr(hostp, ':')) == NULL)
228729088Smarkm	    hostname = strrchr(hostp, '@');
2288107299Seric	if (hostname == NULL) {
2289107299Seric	    hostname = hostp;
2290107299Seric	} else {
2291107299Seric	    hostname++;
2292107299Seric	    srcroute = 1;
2293107299Seric	}
229456668Sshin    } else
229556668Sshin        hostname = hostp;
229656668Sshin    if (!portp) {
229756668Sshin      telnetport = 1;
229887139Smarkm      portp = strdup("telnet");
229956668Sshin    } else if (*portp == '-') {
230056668Sshin      portp++;
230156668Sshin      telnetport = 1;
2302142790Stobez    } else if (*portp == '+') {
2303142790Stobez      portp++;
2304142790Stobez      telnetport = -1;
230556668Sshin    } else
230656668Sshin      telnetport = 0;
230756668Sshin
230856668Sshin    memset(&hints, 0, sizeof(hints));
230956668Sshin    hints.ai_flags = AI_NUMERICHOST;
231056668Sshin    hints.ai_family = family;
231156668Sshin    hints.ai_socktype = SOCK_STREAM;
231256668Sshin    error = getaddrinfo(hostname, portp, &hints, &res);
231362773Sitojun    if (error) {
231462773Sitojun        hints.ai_flags = AI_CANONNAME;
231562773Sitojun	error = getaddrinfo(hostname, portp, &hints, &res);
231662773Sitojun    }
231762773Sitojun    if (error != 0) {
231862773Sitojun	fprintf(stderr, "%s: %s\n", hostname, gai_strerror(error));
231962773Sitojun	if (error == EAI_SYSTEM)
232062773Sitojun	    fprintf(stderr, "%s: %s\n", hostname, strerror(errno));
232162773Sitojun	setuid(getuid());
232262773Sitojun	goto fail;
232362773Sitojun    }
232462773Sitojun    if (hints.ai_flags == AI_NUMERICHOST) {
232562773Sitojun	/* hostname has numeric */
232656668Sshin        int gni_err = 1;
232756668Sshin
232856668Sshin	if (doaddrlookup)
232956668Sshin	    gni_err = getnameinfo(res->ai_addr, res->ai_addr->sa_len,
233056668Sshin				  _hostname, sizeof(_hostname) - 1, NULL, 0,
233156870Sshin				  NI_NAMEREQD);
233256668Sshin	if (gni_err != 0)
233362773Sitojun	    (void) strncpy(_hostname, hostp, sizeof(_hostname) - 1);
233456668Sshin	_hostname[sizeof(_hostname)-1] = '\0';
233556668Sshin	hostname = _hostname;
233662773Sitojun    } else {
233762773Sitojun	/* hostname has FQDN */
233856668Sshin	if (srcroute != 0)
233956668Sshin	    (void) strncpy(_hostname, hostname, sizeof(_hostname) - 1);
234056668Sshin	else if (res->ai_canonname != NULL)
234156668Sshin	  strcpy(_hostname, res->ai_canonname);
234256668Sshin	else
234356668Sshin	  (void) strncpy(_hostname, hostp, sizeof(_hostname) - 1);
234456668Sshin	_hostname[sizeof(_hostname)-1] = '\0';
234556668Sshin	hostname = _hostname;
234656668Sshin    }
234757125Sshin    res0 = res;
234887277Sjhay #ifdef INET6
234957233Sshin af_again:
235087277Sjhay #endif
235156668Sshin    if (srcroute != 0) {
235257343Sshin        static char hostbuf[BUFSIZ];
235357125Sshin
235457233Sshin	if (af_error == 0) { /* save intermediate hostnames for retry */
235557233Sshin		strncpy(hostbuf, hostp, BUFSIZ - 1);
235657233Sshin		hostbuf[BUFSIZ - 1] = '\0';
235757233Sshin	} else
235857125Sshin		hostp = hostbuf;
235929088Smarkm	srp = 0;
236056668Sshin	result = sourceroute(res, hostp, &srp, &srlen, &proto, &opt);
236156668Sshin	if (result == 0) {
236257125Sshin#ifdef INET6
236357125Sshin	    if (family == AF_UNSPEC && af_error == 0 &&
236457125Sshin		switch_af(&res) == 1) {
236557125Sshin	        af_error = 1;
236657125Sshin		goto af_again;
236757125Sshin	    }
236857125Sshin#endif
236929088Smarkm	    setuid(getuid());
237057125Sshin	    goto fail;
237156668Sshin	} else if (result == -1) {
237229088Smarkm	    printf("Bad source route option: %s\n", hostp);
237329088Smarkm	    setuid(getuid());
237457125Sshin	    goto fail;
237529088Smarkm	}
237629088Smarkm    }
237729088Smarkm    do {
237857342Sshin        printf("Trying %s...\n", sockaddr_ntop(res->ai_addr));
237956668Sshin	net = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
238029088Smarkm	setuid(getuid());
238129088Smarkm	if (net < 0) {
238257125Sshin#ifdef INET6
238357125Sshin	    if (family == AF_UNSPEC && af_error == 0 &&
238457125Sshin		switch_af(&res) == 1) {
238557125Sshin	        af_error = 1;
238657125Sshin		goto af_again;
238757125Sshin	    }
238857125Sshin#endif
238929088Smarkm	    perror("telnet: socket");
239057125Sshin	    goto fail;
239129088Smarkm	}
239256668Sshin	if (srp && setsockopt(net, proto, opt, (char *)srp, srlen) < 0)
239356668Sshin		perror("setsockopt (source route)");
239429088Smarkm#if	defined(IPPROTO_IP) && defined(IP_TOS)
239556668Sshin	if (res->ai_family == PF_INET) {
239629088Smarkm# if	defined(HAS_GETTOS)
239729088Smarkm	    struct tosent *tp;
239829088Smarkm	    if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
239929088Smarkm		tos = tp->t_tos;
240029088Smarkm# endif
240129088Smarkm	    if (tos < 0)
240281965Smarkm		tos = IPTOS_LOWDELAY;
240329088Smarkm	    if (tos
240429088Smarkm		&& (setsockopt(net, IPPROTO_IP, IP_TOS,
240529088Smarkm		    (char *)&tos, sizeof(int)) < 0)
240629088Smarkm		&& (errno != ENOPROTOOPT))
240729088Smarkm		    perror("telnet: setsockopt (IP_TOS) (ignored)");
240829088Smarkm	}
240929088Smarkm#endif	/* defined(IPPROTO_IP) && defined(IP_TOS) */
241029088Smarkm
2411114911Smarkm	if (telnet_debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) {
241229088Smarkm		perror("setsockopt (SO_DEBUG)");
241329088Smarkm	}
241429088Smarkm
241547973Sru	if (src_addr != NULL) {
241657125Sshin	    for (src_res = src_res0; src_res != 0; src_res = src_res->ai_next)
241757233Sshin	        if (src_res->ai_family == res->ai_family)
241857233Sshin		    break;
241957125Sshin	    if (src_res == NULL)
242057125Sshin		src_res = src_res0;
242157125Sshin	    if (bind(net, src_res->ai_addr, src_res->ai_addrlen) == -1) {
242257125Sshin#ifdef INET6
242357125Sshin	        if (family == AF_UNSPEC && af_error == 0 &&
242457125Sshin		    switch_af(&res) == 1) {
242557125Sshin		    af_error = 1;
242657233Sshin		    (void) NetClose(net);
242757125Sshin		    goto af_again;
242857125Sshin		}
242957125Sshin#endif
243047973Sru		perror("bind");
243157233Sshin		(void) NetClose(net);
243257125Sshin		goto fail;
243347973Sru	    }
243447973Sru	}
243556668Sshin#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
243657233Sshin	if (setpolicy(net, res, ipsec_policy_in) < 0) {
243757233Sshin		(void) NetClose(net);
243857125Sshin		goto fail;
243957233Sshin	}
244057233Sshin	if (setpolicy(net, res, ipsec_policy_out) < 0) {
244157233Sshin		(void) NetClose(net);
244257125Sshin		goto fail;
244357233Sshin	}
244456668Sshin#endif
244547973Sru
244656668Sshin	if (connect(net, res->ai_addr, res->ai_addrlen) < 0) {
244757125Sshin	    struct addrinfo *next;
244857125Sshin
244957125Sshin	    next = res->ai_next;
245057125Sshin	    /* If already an af failed, only try same af. */
245157125Sshin	    if (af_error != 0)
245257125Sshin		while (next != NULL && next->ai_family != res->ai_family)
245357125Sshin		    next = next->ai_next;
245457342Sshin	    warn("connect to address %s", sockaddr_ntop(res->ai_addr));
245557125Sshin	    if (next != NULL) {
245657125Sshin		res = next;
245729088Smarkm		(void) NetClose(net);
245829088Smarkm		continue;
245929088Smarkm	    }
246057342Sshin	    warnx("Unable to connect to remote host");
246157233Sshin	    (void) NetClose(net);
246257125Sshin	    goto fail;
246329088Smarkm	}
246429088Smarkm	connected++;
246587139Smarkm#ifdef	AUTHENTICATION
246687139Smarkm#ifdef	ENCRYPTION
246729088Smarkm	auth_encrypt_connect(connected);
246887139Smarkm#endif
246987139Smarkm#endif
247029088Smarkm    } while (connected == 0);
247157125Sshin    freeaddrinfo(res0);
247257125Sshin    if (src_res0 != NULL)
247357125Sshin        freeaddrinfo(src_res0);
247429088Smarkm    cmdrc(hostp, hostname);
247577095Sdillon af_unix:
2476139687Smaxim    connected = 1;
247729088Smarkm    if (autologin && user == NULL) {
247829088Smarkm	struct passwd *pw;
247929088Smarkm
248029088Smarkm	user = getenv("USER");
248129088Smarkm	if (user == NULL ||
248229181Smarkm	    ((pw = getpwnam(user)) && pw->pw_uid != getuid())) {
248329181Smarkm		if ((pw = getpwuid(getuid())))
248429088Smarkm			user = pw->pw_name;
248529088Smarkm		else
248629088Smarkm			user = NULL;
248729088Smarkm	}
248829088Smarkm    }
248929088Smarkm    if (user) {
249087139Smarkm	env_define("USER", user);
249187139Smarkm	env_export("USER");
249229088Smarkm    }
249329088Smarkm    (void) call(status, "status", "notmuch", 0);
2494207449Sjilles    telnet(user);
249529088Smarkm    (void) NetClose(net);
249629088Smarkm    ExitString("Connection closed by foreign host.\n",1);
249729088Smarkm    /*NOTREACHED*/
249857125Sshin fail:
249957125Sshin    if (res0 != NULL)
250057125Sshin        freeaddrinfo(res0);
250157125Sshin    if (src_res0 != NULL)
250257125Sshin        freeaddrinfo(src_res0);
250357125Sshin    return 0;
250429088Smarkm}
250529088Smarkm
250629088Smarkm#define HELPINDENT (sizeof ("connect"))
250729088Smarkm
250829088Smarkmstatic char
250929088Smarkm	openhelp[] =	"connect to a site",
251029088Smarkm	closehelp[] =	"close current connection",
251129088Smarkm	logouthelp[] =	"forcibly logout remote user and close the connection",
251229088Smarkm	quithelp[] =	"exit telnet",
251329088Smarkm	statushelp[] =	"print status information",
251429088Smarkm	helphelp[] =	"print help information",
251529088Smarkm	sendhelp[] =	"transmit special characters ('send ?' for more)",
251629088Smarkm	sethelp[] = 	"set operating parameters ('set ?' for more)",
251729088Smarkm	unsethelp[] = 	"unset operating parameters ('unset ?' for more)",
251829088Smarkm	togglestring[] ="toggle operating parameters ('toggle ?' for more)",
251929088Smarkm	slchelp[] =	"change state of special charaters ('slc ?' for more)",
252029088Smarkm	displayhelp[] =	"display operating parameters",
252187139Smarkm#ifdef	AUTHENTICATION
252229088Smarkm	authhelp[] =	"turn on (off) authentication ('auth ?' for more)",
252329088Smarkm#endif
252429088Smarkm#ifdef	ENCRYPTION
252529088Smarkm	encrypthelp[] =	"turn on (off) encryption ('encrypt ?' for more)",
252629088Smarkm#endif	/* ENCRYPTION */
252729088Smarkm	zhelp[] =	"suspend telnet",
252887139Smarkm#ifdef OPIE
252981965Smarkm	opiehelp[] =    "compute response to OPIE challenge",
253029181Smarkm#endif
253129088Smarkm	shellhelp[] =	"invoke a subshell",
253229088Smarkm	envhelp[] =	"change environment variables ('environ ?' for more)",
253329088Smarkm	modestring[] = "try to enter line or character mode ('mode ?' for more)";
253429088Smarkm
253529088Smarkmstatic Command cmdtab[] = {
253629088Smarkm	{ "close",	closehelp,	bye,		1 },
253787139Smarkm	{ "logout",	logouthelp,	(int (*)(int, char **))logout,		1 },
253829088Smarkm	{ "display",	displayhelp,	display,	0 },
253929088Smarkm	{ "mode",	modestring,	modecmd,	0 },
254081965Smarkm	{ "telnet",	openhelp,	tn,		0 },
254129088Smarkm	{ "open",	openhelp,	tn,		0 },
254287139Smarkm	{ "quit",	quithelp,	(int (*)(int, char **))quit,		0 },
254329088Smarkm	{ "send",	sendhelp,	sendcmd,	0 },
254429088Smarkm	{ "set",	sethelp,	setcmd,		0 },
254529088Smarkm	{ "unset",	unsethelp,	unsetcmd,	0 },
254629088Smarkm	{ "status",	statushelp,	status,		0 },
254729088Smarkm	{ "toggle",	togglestring,	toggle,		0 },
254829088Smarkm	{ "slc",	slchelp,	slccmd,		0 },
254987139Smarkm#ifdef	AUTHENTICATION
255029088Smarkm	{ "auth",	authhelp,	auth_cmd,	0 },
255129088Smarkm#endif
255229088Smarkm#ifdef	ENCRYPTION
255329088Smarkm	{ "encrypt",	encrypthelp,	encrypt_cmd,	0 },
255429088Smarkm#endif	/* ENCRYPTION */
255587139Smarkm	{ "z",		zhelp,		(int (*)(int, char **))suspend,	0 },
255629088Smarkm	{ "!",		shellhelp,	shell,		1 },
255729088Smarkm	{ "environ",	envhelp,	env_cmd,	0 },
255829088Smarkm	{ "?",		helphelp,	help,		0 },
255987139Smarkm#ifdef OPIE
256081965Smarkm	{ "opie",       opiehelp,       opie_calc,      0 },
256129181Smarkm#endif
256287139Smarkm	{ NULL, NULL, NULL, 0 }
256329088Smarkm};
256429088Smarkm
256529088Smarkmstatic char	crmodhelp[] =	"deprecated command -- use 'toggle crmod' instead";
256629088Smarkmstatic char	escapehelp[] =	"deprecated command -- use 'set escape' instead";
256729088Smarkm
256829088Smarkmstatic Command cmdtab2[] = {
256929088Smarkm	{ "help",	0,		help,		0 },
257029088Smarkm	{ "escape",	escapehelp,	setescape,	0 },
257187139Smarkm	{ "crmod",	crmodhelp,	(int (*)(int, char **))togcrmod,	0 },
257287139Smarkm	{ NULL, NULL, NULL, 0 }
257329088Smarkm};
257429088Smarkm
257529088Smarkm
257629088Smarkm/*
257729088Smarkm * Call routine with argc, argv set from args (terminated by 0).
257829088Smarkm */
257929088Smarkm
258087139Smarkmstatic int
258187139Smarkmcall(intrtn_t routine, ...)
258229088Smarkm{
258329088Smarkm    va_list ap;
258429088Smarkm    char *args[100];
258529088Smarkm    int argno = 0;
258629088Smarkm
258787139Smarkm    va_start(ap, routine);
258887139Smarkm    while ((args[argno++] = va_arg(ap, char *)) != 0);
258929088Smarkm    va_end(ap);
259029088Smarkm    return (*routine)(argno-1, args);
259129088Smarkm}
259229088Smarkm
259329088Smarkm
259487139Smarkmstatic Command *
259587139Smarkmgetcmd(char *name)
259629088Smarkm{
259729088Smarkm    Command *cm;
259829088Smarkm
259929181Smarkm    if ((cm = (Command *) genget(name, (char **) cmdtab, sizeof(Command))))
260029088Smarkm	return cm;
260129088Smarkm    return (Command *) genget(name, (char **) cmdtab2, sizeof(Command));
260229088Smarkm}
260329088Smarkm
260487139Smarkmvoid
260587139Smarkmcommand(int top, const char *tbuf, int cnt)
260629088Smarkm{
260787139Smarkm    Command *c;
260829088Smarkm
260929088Smarkm    setcommandmode();
261029088Smarkm    if (!top) {
261129088Smarkm	putchar('\n');
261229088Smarkm    } else {
261329088Smarkm	(void) signal(SIGINT, SIG_DFL);
261429088Smarkm	(void) signal(SIGQUIT, SIG_DFL);
261529088Smarkm    }
261629088Smarkm    for (;;) {
261729088Smarkm	if (rlogin == _POSIX_VDISABLE)
261829088Smarkm		printf("%s> ", prompt);
261929088Smarkm	if (tbuf) {
262087139Smarkm	    char *cp;
262129088Smarkm	    cp = line;
262229088Smarkm	    while (cnt > 0 && (*cp++ = *tbuf++) != '\n')
262329088Smarkm		cnt--;
262429088Smarkm	    tbuf = 0;
262529088Smarkm	    if (cp == line || *--cp != '\n' || cp == line)
262629088Smarkm		goto getline;
262729088Smarkm	    *cp = '\0';
262829088Smarkm	    if (rlogin == _POSIX_VDISABLE)
262929088Smarkm		printf("%s\n", line);
263029088Smarkm	} else {
263129088Smarkm	getline:
263229088Smarkm	    if (rlogin != _POSIX_VDISABLE)
263329088Smarkm		printf("%s> ", prompt);
263429088Smarkm	    if (fgets(line, sizeof(line), stdin) == NULL) {
263529088Smarkm		if (feof(stdin) || ferror(stdin)) {
263629088Smarkm		    (void) quit();
263729088Smarkm		    /*NOTREACHED*/
263829088Smarkm		}
263929088Smarkm		break;
264029088Smarkm	    }
264129088Smarkm	}
264229088Smarkm	if (line[0] == 0)
264329088Smarkm	    break;
264429088Smarkm	makeargv();
264529088Smarkm	if (margv[0] == 0) {
264629088Smarkm	    break;
264729088Smarkm	}
264829088Smarkm	c = getcmd(margv[0]);
264987139Smarkm	if (Ambiguous((void *)c)) {
265029088Smarkm	    printf("?Ambiguous command\n");
265129088Smarkm	    continue;
265229088Smarkm	}
265329088Smarkm	if (c == 0) {
265429088Smarkm	    printf("?Invalid command\n");
265529088Smarkm	    continue;
265629088Smarkm	}
265729088Smarkm	if (c->needconnect && !connected) {
265829088Smarkm	    printf("?Need to be connected first.\n");
265929088Smarkm	    continue;
266029088Smarkm	}
266129088Smarkm	if ((*c->handler)(margc, margv)) {
266229088Smarkm	    break;
266329088Smarkm	}
266429088Smarkm    }
266529088Smarkm    if (!top) {
266629088Smarkm	if (!connected) {
266729088Smarkm	    longjmp(toplevel, 1);
266829088Smarkm	    /*NOTREACHED*/
266929088Smarkm	}
267029088Smarkm	setconnmode(0);
267129088Smarkm    }
267229088Smarkm}
267329088Smarkm
267429088Smarkm/*
267529088Smarkm * Help command.
267629088Smarkm */
267787139Smarkmstatic int
267887139Smarkmhelp(int argc, char *argv[])
267929088Smarkm{
268087139Smarkm	Command *c;
268129088Smarkm
268229088Smarkm	if (argc == 1) {
268329088Smarkm		printf("Commands may be abbreviated.  Commands are:\n\n");
268429088Smarkm		for (c = cmdtab; c->name; c++)
268529088Smarkm			if (c->help) {
268687266Smarkm				printf("%-*s\t%s\n", (int)HELPINDENT, c->name,
268729088Smarkm								    c->help);
268829088Smarkm			}
268981965Smarkm		return 0;
269029088Smarkm	}
269129181Smarkm	else while (--argc > 0) {
269287139Smarkm		char *arg;
269329088Smarkm		arg = *++argv;
269429088Smarkm		c = getcmd(arg);
269587139Smarkm		if (Ambiguous((void *)c))
269629088Smarkm			printf("?Ambiguous help command %s\n", arg);
269729088Smarkm		else if (c == (Command *)0)
269829088Smarkm			printf("?Invalid help command %s\n", arg);
269929088Smarkm		else
270029088Smarkm			printf("%s\n", c->help);
270129088Smarkm	}
270281965Smarkm	return 0;
270329088Smarkm}
270429088Smarkm
270529088Smarkmstatic char *rcname = 0;
270629088Smarkmstatic char rcbuf[128];
270729088Smarkm
270887139Smarkmvoid
270987139Smarkmcmdrc(char *m1, char *m2)
271029088Smarkm{
271187139Smarkm    Command *c;
271229088Smarkm    FILE *rcfile;
271329088Smarkm    int gotmachine = 0;
271429088Smarkm    int l1 = strlen(m1);
271529088Smarkm    int l2 = strlen(m2);
271668891Skris    char m1save[MAXHOSTNAMELEN];
271729088Smarkm
271829088Smarkm    if (skiprc)
271929088Smarkm	return;
272029088Smarkm
272168891Skris    strlcpy(m1save, m1, sizeof(m1save));
272229088Smarkm    m1 = m1save;
272329088Smarkm
272429088Smarkm    if (rcname == 0) {
272529088Smarkm	rcname = getenv("HOME");
272629181Smarkm	if (rcname && (strlen(rcname) + 10) < sizeof(rcbuf))
272729088Smarkm	    strcpy(rcbuf, rcname);
272829088Smarkm	else
272929088Smarkm	    rcbuf[0] = '\0';
273029088Smarkm	strcat(rcbuf, "/.telnetrc");
273129088Smarkm	rcname = rcbuf;
273229088Smarkm    }
273329088Smarkm
273429088Smarkm    if ((rcfile = fopen(rcname, "r")) == 0) {
273529088Smarkm	return;
273629088Smarkm    }
273729088Smarkm
273829088Smarkm    for (;;) {
273929088Smarkm	if (fgets(line, sizeof(line), rcfile) == NULL)
274029088Smarkm	    break;
274129088Smarkm	if (line[0] == 0)
274229088Smarkm	    break;
274329088Smarkm	if (line[0] == '#')
274429088Smarkm	    continue;
274529088Smarkm	if (gotmachine) {
274629088Smarkm	    if (!isspace(line[0]))
274729088Smarkm		gotmachine = 0;
274829088Smarkm	}
274929088Smarkm	if (gotmachine == 0) {
275029088Smarkm	    if (isspace(line[0]))
275129088Smarkm		continue;
275229088Smarkm	    if (strncasecmp(line, m1, l1) == 0)
275329088Smarkm		strncpy(line, &line[l1], sizeof(line) - l1);
275429088Smarkm	    else if (strncasecmp(line, m2, l2) == 0)
275529088Smarkm		strncpy(line, &line[l2], sizeof(line) - l2);
275629088Smarkm	    else if (strncasecmp(line, "DEFAULT", 7) == 0)
275729088Smarkm		strncpy(line, &line[7], sizeof(line) - 7);
275829088Smarkm	    else
275929088Smarkm		continue;
276029088Smarkm	    if (line[0] != ' ' && line[0] != '\t' && line[0] != '\n')
276129088Smarkm		continue;
276229088Smarkm	    gotmachine = 1;
276329088Smarkm	}
276429088Smarkm	makeargv();
276529088Smarkm	if (margv[0] == 0)
276629088Smarkm	    continue;
276729088Smarkm	c = getcmd(margv[0]);
276887139Smarkm	if (Ambiguous((void *)c)) {
276929088Smarkm	    printf("?Ambiguous command: %s\n", margv[0]);
277029088Smarkm	    continue;
277129088Smarkm	}
277229088Smarkm	if (c == 0) {
277329088Smarkm	    printf("?Invalid command: %s\n", margv[0]);
277429088Smarkm	    continue;
277529088Smarkm	}
277629088Smarkm	/*
277729088Smarkm	 * This should never happen...
277829088Smarkm	 */
277929088Smarkm	if (c->needconnect && !connected) {
278029088Smarkm	    printf("?Need to be connected first for %s.\n", margv[0]);
278129088Smarkm	    continue;
278229088Smarkm	}
278329088Smarkm	(*c->handler)(margc, margv);
278429088Smarkm    }
278529088Smarkm    fclose(rcfile);
278629088Smarkm}
278729088Smarkm
278829088Smarkm/*
278929088Smarkm * Source route is handed in as
279029088Smarkm *	[!]@hop1@hop2...[@|:]dst
279129088Smarkm * If the leading ! is present, it is a
279229088Smarkm * strict source route, otherwise it is
279329088Smarkm * assmed to be a loose source route.
279429088Smarkm *
279529088Smarkm * We fill in the source route option as
279629088Smarkm *	hop1,hop2,hop3...dest
279729088Smarkm * and return a pointer to hop1, which will
279829088Smarkm * be the address to connect() to.
279929088Smarkm *
280029088Smarkm * Arguments:
280156668Sshin *
280256668Sshin *	res:	ponter to addrinfo structure which contains sockaddr to
280356668Sshin *		the host to connect to.
280456668Sshin *
280529088Smarkm *	arg:	pointer to route list to decipher
280629088Smarkm *
280729088Smarkm *	cpp: 	If *cpp is not equal to NULL, this is a
280829088Smarkm *		pointer to a pointer to a character array
280929088Smarkm *		that should be filled in with the option.
281029088Smarkm *
281129088Smarkm *	lenp:	pointer to an integer that contains the
281229088Smarkm *		length of *cpp if *cpp != NULL.
281329088Smarkm *
281456668Sshin *	protop:	pointer to an integer that should be filled in with
281556668Sshin *		appropriate protocol for setsockopt, as socket
281656668Sshin *		protocol family.
281756668Sshin *
281856668Sshin *	optp:	pointer to an integer that should be filled in with
281956668Sshin *		appropriate option for setsockopt, as socket protocol
282056668Sshin *		family.
282156668Sshin *
282229088Smarkm * Return values:
282329088Smarkm *
282456668Sshin *	If the return value is 1, then all operations are
282556668Sshin *	successful. If the
282629088Smarkm *	return value is -1, there was a syntax error in the
282729088Smarkm *	option, either unknown characters, or too many hosts.
282829088Smarkm *	If the return value is 0, one of the hostnames in the
282929088Smarkm *	path is unknown, and *cpp is set to point to the bad
283029088Smarkm *	hostname.
283129088Smarkm *
283229088Smarkm *	*cpp:	If *cpp was equal to NULL, it will be filled
283329088Smarkm *		in with a pointer to our static area that has
283429088Smarkm *		the option filled in.  This will be 32bit aligned.
283529088Smarkm *
283629088Smarkm *	*lenp:	This will be filled in with how long the option
283729088Smarkm *		pointed to by *cpp is.
283829088Smarkm *
283956668Sshin *	*protop: This will be filled in with appropriate protocol for
284056668Sshin *		 setsockopt, as socket protocol family.
284156668Sshin *
284256668Sshin *	*optp:	This will be filled in with appropriate option for
284356668Sshin *		setsockopt, as socket protocol family.
284429088Smarkm */
284587139Smarkmstatic int
284687139Smarkmsourceroute(struct addrinfo *ai, char *arg, char **cpp, int *lenp, int *protop, int *optp)
284729088Smarkm{
284863662Sume	static char buf[1024 + ALIGNBYTES];	/*XXX*/
284956668Sshin	char *cp, *cp2, *lsrp, *ep;
285087139Smarkm	struct sockaddr_in *_sin;
285187277Sjhay#ifdef INET6
285256668Sshin	struct sockaddr_in6 *sin6;
2853121472Sume	struct ip6_rthdr *rth;
285487277Sjhay#endif
285556668Sshin	struct addrinfo hints, *res;
285656668Sshin	int error;
285787139Smarkm	char c;
285829088Smarkm
285929088Smarkm	/*
286029088Smarkm	 * Verify the arguments, and make sure we have
286129088Smarkm	 * at least 7 bytes for the option.
286229088Smarkm	 */
286329088Smarkm	if (cpp == NULL || lenp == NULL)
286457724Sshin		return -1;
286556668Sshin	if (*cpp != NULL) {
286656668Sshin		switch (res->ai_family) {
286756668Sshin		case AF_INET:
286856668Sshin			if (*lenp < 7)
286957724Sshin				return -1;
287056668Sshin			break;
287156668Sshin#ifdef INET6
287256668Sshin		case AF_INET6:
287387139Smarkm			if (*lenp < (int)CMSG_SPACE(sizeof(struct ip6_rthdr) +
287457724Sshin				               sizeof(struct in6_addr)))
287557724Sshin				return -1;
287656668Sshin			break;
287756668Sshin#endif
287856668Sshin		}
287956668Sshin	}
288029088Smarkm	/*
288129088Smarkm	 * Decide whether we have a buffer passed to us,
288229088Smarkm	 * or if we need to use our own static buffer.
288329088Smarkm	 */
288429088Smarkm	if (*cpp) {
288529088Smarkm		lsrp = *cpp;
288656668Sshin		ep = lsrp + *lenp;
288729088Smarkm	} else {
288863662Sume		*cpp = lsrp = (char *)ALIGN(buf);
288956668Sshin		ep = lsrp + 1024;
289029088Smarkm	}
289129088Smarkm
289229088Smarkm	cp = arg;
289329088Smarkm
289456668Sshin#ifdef INET6
289556668Sshin	if (ai->ai_family == AF_INET6) {
2896121472Sume		if ((rth = inet6_rth_init((void *)*cpp, sizeof(buf),
2897121472Sume					  IPV6_RTHDR_TYPE_0, 0)) == NULL)
2898121472Sume			return -1;
289956668Sshin		if (*cp != '@')
290056668Sshin			return -1;
290156668Sshin		*protop = IPPROTO_IPV6;
2902121472Sume		*optp = IPV6_RTHDR;
290356668Sshin	} else
290456668Sshin#endif
290556668Sshin      {
290629088Smarkm	/*
290729088Smarkm	 * Next, decide whether we have a loose source
290829088Smarkm	 * route or a strict source route, and fill in
290929088Smarkm	 * the begining of the option.
291029088Smarkm	 */
291129088Smarkm	if (*cp == '!') {
291229088Smarkm		cp++;
291329088Smarkm		*lsrp++ = IPOPT_SSRR;
291429088Smarkm	} else
291529088Smarkm		*lsrp++ = IPOPT_LSRR;
291629088Smarkm
291729088Smarkm	if (*cp != '@')
291857724Sshin		return -1;
291929088Smarkm
292029088Smarkm	lsrp++;		/* skip over length, we'll fill it in later */
292129088Smarkm	*lsrp++ = 4;
292256668Sshin	*protop = IPPROTO_IP;
292356668Sshin	*optp = IP_OPTIONS;
292456668Sshin      }
292529088Smarkm
292629088Smarkm	cp++;
292756668Sshin	memset(&hints, 0, sizeof(hints));
292856668Sshin	hints.ai_family = ai->ai_family;
292956668Sshin	hints.ai_socktype = SOCK_STREAM;
293029088Smarkm	for (c = 0;;) {
293156668Sshin		if (
293256668Sshin#ifdef INET6
293356668Sshin		    ai->ai_family != AF_INET6 &&
293456668Sshin#endif
293556668Sshin		    c == ':')
293629088Smarkm			cp2 = 0;
293729181Smarkm		else for (cp2 = cp; (c = *cp2); cp2++) {
293829088Smarkm			if (c == ',') {
293929088Smarkm				*cp2++ = '\0';
294029088Smarkm				if (*cp2 == '@')
294129088Smarkm					cp2++;
294229088Smarkm			} else if (c == '@') {
294329088Smarkm				*cp2++ = '\0';
294456668Sshin			} else if (
294556668Sshin#ifdef INET6
294656668Sshin				   ai->ai_family != AF_INET6 &&
294756668Sshin#endif
294856668Sshin				   c == ':') {
294929088Smarkm				*cp2++ = '\0';
295029088Smarkm			} else
295129088Smarkm				continue;
295229088Smarkm			break;
295329088Smarkm		}
295429088Smarkm		if (!c)
295529088Smarkm			cp2 = 0;
295629088Smarkm
295756668Sshin		hints.ai_flags = AI_NUMERICHOST;
295881965Smarkm		error = getaddrinfo(cp, NULL, &hints, &res);
2959121425Sume		if (error == EAI_NONAME) {
296056668Sshin			hints.ai_flags = 0;
296156668Sshin			error = getaddrinfo(cp, NULL, &hints, &res);
296256668Sshin		}
296356668Sshin		if (error != 0) {
296456668Sshin			fprintf(stderr, "%s: %s\n", cp, gai_strerror(error));
296556668Sshin			if (error == EAI_SYSTEM)
296656668Sshin				fprintf(stderr, "%s: %s\n", cp,
296756668Sshin					strerror(errno));
296829088Smarkm			*cpp = cp;
296929088Smarkm			return(0);
297029088Smarkm		}
297156668Sshin#ifdef INET6
297256668Sshin		if (res->ai_family == AF_INET6) {
297356668Sshin			sin6 = (struct sockaddr_in6 *)res->ai_addr;
2974121472Sume			if (inet6_rth_add((void *)rth, &sin6->sin6_addr) == -1)
2975121472Sume				return(0);
297656668Sshin		} else
297756668Sshin#endif
297856668Sshin	      {
297987139Smarkm		_sin = (struct sockaddr_in *)res->ai_addr;
298087139Smarkm		memcpy(lsrp, (char *)&_sin->sin_addr, 4);
298129088Smarkm		lsrp += 4;
298256668Sshin	      }
298329088Smarkm		if (cp2)
298429088Smarkm			cp = cp2;
298529088Smarkm		else
298629088Smarkm			break;
298729088Smarkm		/*
298829088Smarkm		 * Check to make sure there is space for next address
298929088Smarkm		 */
299056668Sshin		if (lsrp + 4 > ep)
299157724Sshin			return -1;
299256668Sshin		freeaddrinfo(res);
299329088Smarkm	}
299456668Sshin#ifdef INET6
299556668Sshin	if (res->ai_family == AF_INET6) {
2996121472Sume		rth->ip6r_len = rth->ip6r_segleft * 2;
2997121472Sume		*lenp = (rth->ip6r_len + 1) << 3;
299856668Sshin	} else
299956668Sshin#endif
300056668Sshin      {
300129088Smarkm	if ((*(*cpp+IPOPT_OLEN) = lsrp - *cpp) <= 7) {
300229088Smarkm		*cpp = 0;
300329088Smarkm		*lenp = 0;
300457724Sshin		return -1;
300529088Smarkm	}
300629088Smarkm	*lsrp++ = IPOPT_NOP; /* 32 bit word align it */
300729088Smarkm	*lenp = lsrp - *cpp;
300856668Sshin      }
300956668Sshin	freeaddrinfo(res);
301056668Sshin	return 1;
301129088Smarkm}
3012