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.
13351432Semaste * 3. Neither the name of the University nor the names of its contributors
1429088Smarkm *    may be used to endorse or promote products derived from this software
1529088Smarkm *    without specific prior written permission.
1629088Smarkm *
1729088Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1829088Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1929088Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2029088Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2129088Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2229088Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2329088Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2429088Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2529088Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2629088Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2729088Smarkm * SUCH DAMAGE.
2829088Smarkm */
2929088Smarkm
30114630Sobrien#if 0
3129088Smarkm#ifndef lint
3229181Smarkmstatic const char sccsid[] = "@(#)commands.c	8.4 (Berkeley) 5/30/95";
3387139Smarkm#endif
34114630Sobrien#endif
35114630Sobrien#include <sys/cdefs.h>
36114630Sobrien__FBSDID("$FreeBSD: stable/11/contrib/telnet/telnet/commands.c 351432 2019-08-23 17:40:47Z emaste $");
3729088Smarkm
3829088Smarkm#include <sys/param.h>
3977095Sdillon#include <sys/un.h>
4029088Smarkm#include <sys/file.h>
4129088Smarkm#include <sys/socket.h>
4229088Smarkm#include <netinet/in.h>
4329088Smarkm
44350140Sphilip#include <assert.h>
4587139Smarkm#include <ctype.h>
4687139Smarkm#include <err.h>
4787139Smarkm#include <errno.h>
4829088Smarkm#include <netdb.h>
4929088Smarkm#include <pwd.h>
5087139Smarkm#include <signal.h>
5187139Smarkm#include <stdarg.h>
5287139Smarkm#include <stdlib.h>
5387139Smarkm#include <string.h>
5429181Smarkm#include <unistd.h>
5529088Smarkm
5629088Smarkm#include <arpa/telnet.h>
5781965Smarkm#include <arpa/inet.h>
5829088Smarkm
5929088Smarkm#include "general.h"
6029088Smarkm
6129088Smarkm#include "ring.h"
6229088Smarkm
6329088Smarkm#include "externs.h"
6429088Smarkm#include "defines.h"
6529088Smarkm#include "types.h"
6687139Smarkm#include "misc.h"
6729088Smarkm
6887139Smarkm#ifdef	AUTHENTICATION
6929181Smarkm#include <libtelnet/auth.h>
7029181Smarkm#endif
7187139Smarkm#ifdef	ENCRYPTION
7229181Smarkm#include <libtelnet/encrypt.h>
7329181Smarkm#endif
7429181Smarkm
7529088Smarkm#include <netinet/in_systm.h>
7629088Smarkm#include <netinet/ip.h>
7756668Sshin#include <netinet/ip6.h>
7829088Smarkm
7981965Smarkm#ifndef       MAXHOSTNAMELEN
8081965Smarkm#define       MAXHOSTNAMELEN 256
8196385Salfred#endif
8229088Smarkm
8387139Smarkmtypedef int (*intrtn_t)(int, char **);
8487139Smarkm
8587139Smarkm#ifdef	AUTHENTICATION
8687155Smarkmextern int auth_togdebug(int);
8787139Smarkm#endif
8887139Smarkm#ifdef	ENCRYPTION
8987155Smarkmextern int EncryptAutoEnc(int);
9087155Smarkmextern int EncryptAutoDec(int);
9187155Smarkmextern int EncryptDebug(int);
9287155Smarkmextern int EncryptVerbose(int);
9387139Smarkm#endif	/* ENCRYPTION */
9429088Smarkm#if	defined(IPPROTO_IP) && defined(IP_TOS)
9529088Smarkmint tos = -1;
9629088Smarkm#endif	/* defined(IPPROTO_IP) && defined(IP_TOS) */
9729088Smarkm
9829088Smarkmchar	*hostname;
9929088Smarkmstatic char _hostname[MAXHOSTNAMELEN];
10029088Smarkm
10187139Smarkmstatic int help(int, char **);
10287139Smarkmstatic int call(intrtn_t, ...);
10387139Smarkmstatic void cmdrc(char *, char *);
10487277Sjhay#ifdef INET6
10587139Smarkmstatic int switch_af(struct addrinfo **);
10687277Sjhay#endif
10787139Smarkmstatic int togglehelp(void);
10887139Smarkmstatic int send_tncmd(void (*)(int, int), const char *, char *);
10987139Smarkmstatic int setmod(int);
11087139Smarkmstatic int clearmode(int);
11187139Smarkmstatic int modehelp(void);
112305552Sdimstatic int sourceroute(struct addrinfo *, char *, unsigned char **, int *, int *, int *);
11329088Smarkm
11429088Smarkmtypedef struct {
11587139Smarkm	const char *name;	/* command name */
11687139Smarkm	const char *help;	/* help string (NULL for no help) */
11787139Smarkm	int	(*handler)(int, char **); /* routine which executes command */
11829088Smarkm	int	needconnect;	/* Do we need to be connected to execute? */
11929088Smarkm} Command;
12029088Smarkm
12129088Smarkmstatic char line[256];
12229088Smarkmstatic char saveline[256];
12329088Smarkmstatic int margc;
12429088Smarkmstatic char *margv[20];
12529088Smarkm
12687139Smarkm#ifdef OPIE
12729181Smarkm#include <sys/wait.h>
12881965Smarkm#define PATH_OPIEKEY	"/usr/bin/opiekey"
12987139Smarkmstatic int
13087139Smarkmopie_calc(int argc, char *argv[])
13129181Smarkm{
13229181Smarkm	int status;
13329181Smarkm
13429181Smarkm	if(argc != 3) {
13529181Smarkm		printf("%s sequence challenge\n", argv[0]);
13687139Smarkm		return (0);
13729181Smarkm	}
13829181Smarkm
13929181Smarkm	switch(fork()) {
14029181Smarkm	case 0:
14181965Smarkm		execv(PATH_OPIEKEY, argv);
14229181Smarkm		exit (1);
14329181Smarkm	case -1:
14429181Smarkm		perror("fork");
14529181Smarkm		break;
14629181Smarkm	default:
14729181Smarkm		(void) wait(&status);
14829181Smarkm		if (WIFEXITED(status))
14929181Smarkm			return (WEXITSTATUS(status));
15029181Smarkm	}
15187139Smarkm	return (0);
15229181Smarkm}
15329181Smarkm#endif
15429181Smarkm
15587139Smarkmstatic void
15687139Smarkmmakeargv(void)
15729088Smarkm{
15887139Smarkm    char *cp, *cp2, c;
15987139Smarkm    char **argp = margv;
16029088Smarkm
16129088Smarkm    margc = 0;
16229088Smarkm    cp = line;
16329088Smarkm    if (*cp == '!') {		/* Special case shell escape */
16429088Smarkm	strcpy(saveline, line);	/* save for shell command */
16587139Smarkm	*argp++ = strdup("!");		/* No room in string to get this */
16629088Smarkm	margc++;
16729088Smarkm	cp++;
16829088Smarkm    }
16929181Smarkm    while ((c = *cp)) {
17087139Smarkm	int inquote = 0;
17129088Smarkm	while (isspace(c))
17229088Smarkm	    c = *++cp;
17329088Smarkm	if (c == '\0')
17429088Smarkm	    break;
17529088Smarkm	*argp++ = cp;
17629088Smarkm	margc += 1;
17729088Smarkm	for (cp2 = cp; c != '\0'; c = *++cp) {
17829088Smarkm	    if (inquote) {
17929088Smarkm		if (c == inquote) {
18029088Smarkm		    inquote = 0;
18129088Smarkm		    continue;
18229088Smarkm		}
18329088Smarkm	    } else {
18429088Smarkm		if (c == '\\') {
18529088Smarkm		    if ((c = *++cp) == '\0')
18629088Smarkm			break;
18729088Smarkm		} else if (c == '"') {
18829088Smarkm		    inquote = '"';
18929088Smarkm		    continue;
19029088Smarkm		} else if (c == '\'') {
19129088Smarkm		    inquote = '\'';
19229088Smarkm		    continue;
19329088Smarkm		} else if (isspace(c))
19429088Smarkm		    break;
19529088Smarkm	    }
19629088Smarkm	    *cp2++ = c;
19729088Smarkm	}
19829088Smarkm	*cp2 = '\0';
19929088Smarkm	if (c == '\0')
20029088Smarkm	    break;
20129088Smarkm	cp++;
20229088Smarkm    }
20329088Smarkm    *argp++ = 0;
20429088Smarkm}
20529088Smarkm
20629088Smarkm/*
20729088Smarkm * Make a character string into a number.
20829088Smarkm *
20929088Smarkm * Todo:  1.  Could take random integers (12, 0x12, 012, 0b1).
21029088Smarkm */
21129088Smarkm
21287139Smarkmstatic int
21387139Smarkmspecial(char *s)
21429088Smarkm{
21587139Smarkm	char c;
21629088Smarkm	char b;
21729088Smarkm
21829088Smarkm	switch (*s) {
21929088Smarkm	case '^':
22029088Smarkm		b = *++s;
22129088Smarkm		if (b == '?') {
22229088Smarkm		    c = b | 0x40;		/* DEL */
22329088Smarkm		} else {
22429088Smarkm		    c = b & 0x1f;
22529088Smarkm		}
22629088Smarkm		break;
22729088Smarkm	default:
22829088Smarkm		c = *s;
22929088Smarkm		break;
23029088Smarkm	}
23129088Smarkm	return c;
23229088Smarkm}
23329088Smarkm
23429088Smarkm/*
23529088Smarkm * Construct a control character sequence
23629088Smarkm * for a special character.
23729088Smarkm */
23887139Smarkmstatic const char *
23987139Smarkmcontrol(cc_t c)
24029088Smarkm{
24129088Smarkm	static char buf[5];
24229088Smarkm	/*
24329088Smarkm	 * The only way I could get the Sun 3.5 compiler
24429088Smarkm	 * to shut up about
24529088Smarkm	 *	if ((unsigned int)c >= 0x80)
24629088Smarkm	 * was to assign "c" to an unsigned int variable...
24729088Smarkm	 * Arggg....
24829088Smarkm	 */
24987139Smarkm	unsigned int uic = (unsigned int)c;
25029088Smarkm
25129088Smarkm	if (uic == 0x7f)
25229088Smarkm		return ("^?");
25329088Smarkm	if (c == (cc_t)_POSIX_VDISABLE) {
25429088Smarkm		return "off";
25529088Smarkm	}
25629088Smarkm	if (uic >= 0x80) {
25729088Smarkm		buf[0] = '\\';
25829088Smarkm		buf[1] = ((c>>6)&07) + '0';
25929088Smarkm		buf[2] = ((c>>3)&07) + '0';
26029088Smarkm		buf[3] = (c&07) + '0';
26129088Smarkm		buf[4] = 0;
26229088Smarkm	} else if (uic >= 0x20) {
26329088Smarkm		buf[0] = c;
26429088Smarkm		buf[1] = 0;
26529088Smarkm	} else {
26629088Smarkm		buf[0] = '^';
26729088Smarkm		buf[1] = '@'+c;
26829088Smarkm		buf[2] = 0;
26929088Smarkm	}
27029088Smarkm	return (buf);
27129088Smarkm}
27229088Smarkm
27329088Smarkm/*
27429088Smarkm *	The following are data structures and routines for
27529088Smarkm *	the "send" command.
27629088Smarkm *
27729088Smarkm */
27829088Smarkm
27929088Smarkmstruct sendlist {
28087139Smarkm    const char	*name;		/* How user refers to it (case independent) */
28187139Smarkm    const char	*help;		/* Help information (0 ==> no help) */
28229088Smarkm    int		needconnect;	/* Need to be connected */
28329088Smarkm    int		narg;		/* Number of arguments */
28487139Smarkm    int		(*handler)(char *, ...); /* Routine to perform (for special ops) */
28529088Smarkm    int		nbyte;		/* Number of bytes to send this command */
28629088Smarkm    int		what;		/* Character to be sent (<0 ==> special) */
28729088Smarkm};
28829088Smarkm
28929088Smarkm
29029088Smarkmstatic int
29187155Smarkm	send_esc(void),
29287155Smarkm	send_help(void),
29387155Smarkm	send_docmd(char *),
29487155Smarkm	send_dontcmd(char *),
29587155Smarkm	send_willcmd(char *),
29687155Smarkm	send_wontcmd(char *);
29729088Smarkm
29829088Smarkmstatic struct sendlist Sendlist[] = {
29987139Smarkm    { "ao",	"Send Telnet Abort output",	1, 0, NULL, 2, AO },
30087139Smarkm    { "ayt",	"Send Telnet 'Are You There'",	1, 0, NULL, 2, AYT },
30187139Smarkm    { "brk",	"Send Telnet Break",		1, 0, NULL, 2, BREAK },
30287139Smarkm    { "break",	NULL,				1, 0, NULL, 2, BREAK },
30387139Smarkm    { "ec",	"Send Telnet Erase Character",	1, 0, NULL, 2, EC },
30487139Smarkm    { "el",	"Send Telnet Erase Line",	1, 0, NULL, 2, EL },
30587139Smarkm    { "escape",	"Send current escape character",1, 0, (int (*)(char *, ...))send_esc, 1, 0 },
30687139Smarkm    { "ga",	"Send Telnet 'Go Ahead' sequence", 1, 0, NULL, 2, GA },
30787139Smarkm    { "ip",	"Send Telnet Interrupt Process",1, 0, NULL, 2, IP },
30887139Smarkm    { "intp",	NULL,				1, 0, NULL, 2, IP },
30987139Smarkm    { "interrupt", NULL,			1, 0, NULL, 2, IP },
31087139Smarkm    { "intr",	NULL,				1, 0, NULL, 2, IP },
31187139Smarkm    { "nop",	"Send Telnet 'No operation'",	1, 0, NULL, 2, NOP },
31287139Smarkm    { "eor",	"Send Telnet 'End of Record'",	1, 0, NULL, 2, EOR },
31387139Smarkm    { "abort",	"Send Telnet 'Abort Process'",	1, 0, NULL, 2, ABORT },
31487139Smarkm    { "susp",	"Send Telnet 'Suspend Process'",1, 0, NULL, 2, SUSP },
31587139Smarkm    { "eof",	"Send Telnet End of File Character", 1, 0, NULL, 2, xEOF },
31687139Smarkm    { "synch",	"Perform Telnet 'Synch operation'", 1, 0, (int (*)(char *, ...))dosynch, 2, 0 },
31787139Smarkm    { "getstatus", "Send request for STATUS",	1, 0, (int (*)(char *, ...))get_status, 6, 0 },
31887139Smarkm    { "?",	"Display send options",		0, 0, (int (*)(char *, ...))send_help, 0, 0 },
31987139Smarkm    { "help",	NULL,				0, 0, (int (*)(char *, ...))send_help, 0, 0 },
32087139Smarkm    { "do",	NULL,				0, 1, (int (*)(char *, ...))send_docmd, 3, 0 },
32187139Smarkm    { "dont",	NULL,				0, 1, (int (*)(char *, ...))send_dontcmd, 3, 0 },
32287139Smarkm    { "will",	NULL,				0, 1, (int (*)(char *, ...))send_willcmd, 3, 0 },
32387139Smarkm    { "wont",	NULL,				0, 1, (int (*)(char *, ...))send_wontcmd, 3, 0 },
32487139Smarkm    { NULL,	NULL,				0, 0, NULL, 0, 0 }
32529088Smarkm};
32629088Smarkm
32729088Smarkm#define	GETSEND(name) ((struct sendlist *) genget(name, (char **) Sendlist, \
32829088Smarkm				sizeof(struct sendlist)))
32929088Smarkm
33087139Smarkmstatic int
33187139Smarkmsendcmd(int argc, char *argv[])
33229088Smarkm{
33329088Smarkm    int count;		/* how many bytes we are going to need to send */
33429088Smarkm    int i;
33529088Smarkm    struct sendlist *s;	/* pointer to current command */
33629088Smarkm    int success = 0;
33729088Smarkm    int needconnect = 0;
33829088Smarkm
33929088Smarkm    if (argc < 2) {
34029088Smarkm	printf("need at least one argument for 'send' command\n");
34129088Smarkm	printf("'send ?' for help\n");
34229088Smarkm	return 0;
34329088Smarkm    }
34429088Smarkm    /*
34529088Smarkm     * First, validate all the send arguments.
34629088Smarkm     * In addition, we see how much space we are going to need, and
34729088Smarkm     * whether or not we will be doing a "SYNCH" operation (which
34829088Smarkm     * flushes the network queue).
34929088Smarkm     */
35029088Smarkm    count = 0;
35129088Smarkm    for (i = 1; i < argc; i++) {
35229088Smarkm	s = GETSEND(argv[i]);
35329088Smarkm	if (s == 0) {
35429088Smarkm	    printf("Unknown send argument '%s'\n'send ?' for help.\n",
35529088Smarkm			argv[i]);
35629088Smarkm	    return 0;
35787139Smarkm	} else if (Ambiguous((void *)s)) {
35829088Smarkm	    printf("Ambiguous send argument '%s'\n'send ?' for help.\n",
35929088Smarkm			argv[i]);
36029088Smarkm	    return 0;
36129088Smarkm	}
36229088Smarkm	if (i + s->narg >= argc) {
36329088Smarkm	    fprintf(stderr,
36429088Smarkm	    "Need %d argument%s to 'send %s' command.  'send %s ?' for help.\n",
36529088Smarkm		s->narg, s->narg == 1 ? "" : "s", s->name, s->name);
36629088Smarkm	    return 0;
36729088Smarkm	}
36829088Smarkm	count += s->nbyte;
36987139Smarkm	if ((void *)s->handler == (void *)send_help) {
37029088Smarkm	    send_help();
37129088Smarkm	    return 0;
37229088Smarkm	}
37329088Smarkm
37429088Smarkm	i += s->narg;
37529088Smarkm	needconnect += s->needconnect;
37629088Smarkm    }
37729088Smarkm    if (!connected && needconnect) {
37829088Smarkm	printf("?Need to be connected first.\n");
37929088Smarkm	printf("'send ?' for help\n");
38029088Smarkm	return 0;
38129088Smarkm    }
38229088Smarkm    /* Now, do we have enough room? */
38329088Smarkm    if (NETROOM() < count) {
38429088Smarkm	printf("There is not enough room in the buffer TO the network\n");
38529088Smarkm	printf("to process your request.  Nothing will be done.\n");
38629088Smarkm	printf("('send synch' will throw away most data in the network\n");
38729088Smarkm	printf("buffer, if this might help.)\n");
38829088Smarkm	return 0;
38929088Smarkm    }
39029088Smarkm    /* OK, they are all OK, now go through again and actually send */
39129088Smarkm    count = 0;
39229088Smarkm    for (i = 1; i < argc; i++) {
39329088Smarkm	if ((s = GETSEND(argv[i])) == 0) {
39429088Smarkm	    fprintf(stderr, "Telnet 'send' error - argument disappeared!\n");
39587139Smarkm	    quit();
39629088Smarkm	    /*NOTREACHED*/
39729088Smarkm	}
39829088Smarkm	if (s->handler) {
39929088Smarkm	    count++;
40029088Smarkm	    success += (*s->handler)((s->narg > 0) ? argv[i+1] : 0,
40129088Smarkm				  (s->narg > 1) ? argv[i+2] : 0);
40229088Smarkm	    i += s->narg;
40329088Smarkm	} else {
40429088Smarkm	    NET2ADD(IAC, s->what);
40529088Smarkm	    printoption("SENT", IAC, s->what);
40629088Smarkm	}
40729088Smarkm    }
40829088Smarkm    return (count == success);
40929088Smarkm}
41029088Smarkm
41187139Smarkmstatic int
41287139Smarkmsend_esc(void)
41329088Smarkm{
41429088Smarkm    NETADD(escape);
41529088Smarkm    return 1;
41629088Smarkm}
41729088Smarkm
41887139Smarkmstatic int
41987139Smarkmsend_docmd(char *name)
42029088Smarkm{
42129088Smarkm    return(send_tncmd(send_do, "do", name));
42229088Smarkm}
42329088Smarkm
42487139Smarkmstatic int
42529088Smarkmsend_dontcmd(name)
42629088Smarkm    char *name;
42729088Smarkm{
42829088Smarkm    return(send_tncmd(send_dont, "dont", name));
42929088Smarkm}
43087139Smarkm
43187139Smarkmstatic int
43287139Smarkmsend_willcmd(char *name)
43329088Smarkm{
43429088Smarkm    return(send_tncmd(send_will, "will", name));
43529088Smarkm}
43687139Smarkm
43787139Smarkmstatic int
43887139Smarkmsend_wontcmd(char *name)
43929088Smarkm{
44029088Smarkm    return(send_tncmd(send_wont, "wont", name));
44129088Smarkm}
44229088Smarkm
44387139Smarkmstatic int
44487139Smarkmsend_tncmd(void (*func)(int, int), const char *cmd, char *name)
44529088Smarkm{
44629088Smarkm    char **cpp;
44729088Smarkm    extern char *telopts[];
44887139Smarkm    int val = 0;
44929088Smarkm
45029088Smarkm    if (isprefix(name, "help") || isprefix(name, "?")) {
45187139Smarkm	int col, len;
45229088Smarkm
453103955Smarkm	printf("usage: send %s <value|option>\n", cmd);
45429088Smarkm	printf("\"value\" must be from 0 to 255\n");
45529088Smarkm	printf("Valid options are:\n\t");
45629088Smarkm
45729088Smarkm	col = 8;
45829088Smarkm	for (cpp = telopts; *cpp; cpp++) {
45929088Smarkm	    len = strlen(*cpp) + 3;
46029088Smarkm	    if (col + len > 65) {
46129088Smarkm		printf("\n\t");
46229088Smarkm		col = 8;
46329088Smarkm	    }
46429088Smarkm	    printf(" \"%s\"", *cpp);
46529088Smarkm	    col += len;
46629088Smarkm	}
46729088Smarkm	printf("\n");
46829088Smarkm	return 0;
46929088Smarkm    }
47029088Smarkm    cpp = (char **)genget(name, telopts, sizeof(char *));
47129088Smarkm    if (Ambiguous(cpp)) {
47229088Smarkm	fprintf(stderr,"'%s': ambiguous argument ('send %s ?' for help).\n",
47329088Smarkm					name, cmd);
47429088Smarkm	return 0;
47529088Smarkm    }
47629088Smarkm    if (cpp) {
47729088Smarkm	val = cpp - telopts;
47829088Smarkm    } else {
47987139Smarkm	char *cp = name;
48029088Smarkm
48129088Smarkm	while (*cp >= '0' && *cp <= '9') {
48229088Smarkm	    val *= 10;
48329088Smarkm	    val += *cp - '0';
48429088Smarkm	    cp++;
48529088Smarkm	}
48629088Smarkm	if (*cp != 0) {
48729088Smarkm	    fprintf(stderr, "'%s': unknown argument ('send %s ?' for help).\n",
48829088Smarkm					name, cmd);
48929088Smarkm	    return 0;
49029088Smarkm	} else if (val < 0 || val > 255) {
49129088Smarkm	    fprintf(stderr, "'%s': bad value ('send %s ?' for help).\n",
49229088Smarkm					name, cmd);
49329088Smarkm	    return 0;
49429088Smarkm	}
49529088Smarkm    }
49629088Smarkm    if (!connected) {
49729088Smarkm	printf("?Need to be connected first.\n");
49829088Smarkm	return 0;
49929088Smarkm    }
50029088Smarkm    (*func)(val, 1);
50129088Smarkm    return 1;
50229088Smarkm}
50329088Smarkm
50487139Smarkmstatic int
50587139Smarkmsend_help(void)
50629088Smarkm{
50729088Smarkm    struct sendlist *s;	/* pointer to current command */
50829088Smarkm    for (s = Sendlist; s->name; s++) {
50929088Smarkm	if (s->help)
51029088Smarkm	    printf("%-15s %s\n", s->name, s->help);
51129088Smarkm    }
51229088Smarkm    return(0);
51329088Smarkm}
51429088Smarkm
51529088Smarkm/*
51629088Smarkm * The following are the routines and data structures referred
51729088Smarkm * to by the arguments to the "toggle" command.
51829088Smarkm */
51929088Smarkm
52087139Smarkmstatic int
52187139Smarkmlclchars(void)
52229088Smarkm{
52329088Smarkm    donelclchars = 1;
52429088Smarkm    return 1;
52529088Smarkm}
52629088Smarkm
52787139Smarkmstatic int
52887139Smarkmtogdebug(void)
52929088Smarkm{
53029088Smarkm#ifndef	NOT43
53129088Smarkm    if (net > 0 &&
532114911Smarkm	(SetSockOpt(net, SOL_SOCKET, SO_DEBUG, telnet_debug)) < 0) {
53329088Smarkm	    perror("setsockopt (SO_DEBUG)");
53429088Smarkm    }
53529088Smarkm#else	/* NOT43 */
536114911Smarkm    if (telnet_debug) {
53729181Smarkm	if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0)
53829088Smarkm	    perror("setsockopt (SO_DEBUG)");
53929088Smarkm    } else
54029088Smarkm	printf("Cannot turn off socket debugging\n");
54129088Smarkm#endif	/* NOT43 */
54229088Smarkm    return 1;
54329088Smarkm}
54429088Smarkm
54529088Smarkm
54687139Smarkmstatic int
54787139Smarkmtogcrlf(void)
54829088Smarkm{
54929088Smarkm    if (crlf) {
55029088Smarkm	printf("Will send carriage returns as telnet <CR><LF>.\n");
55129088Smarkm    } else {
55229088Smarkm	printf("Will send carriage returns as telnet <CR><NUL>.\n");
55329088Smarkm    }
55429088Smarkm    return 1;
55529088Smarkm}
55629088Smarkm
55729088Smarkmint binmode;
55829088Smarkm
55987139Smarkmstatic int
56087139Smarkmtogbinary(int val)
56129088Smarkm{
56229088Smarkm    donebinarytoggle = 1;
56329088Smarkm
56429088Smarkm    if (val >= 0) {
56529088Smarkm	binmode = val;
56629088Smarkm    } else {
56729088Smarkm	if (my_want_state_is_will(TELOPT_BINARY) &&
56829088Smarkm				my_want_state_is_do(TELOPT_BINARY)) {
56929088Smarkm	    binmode = 1;
57029088Smarkm	} else if (my_want_state_is_wont(TELOPT_BINARY) &&
57129088Smarkm				my_want_state_is_dont(TELOPT_BINARY)) {
57229088Smarkm	    binmode = 0;
57329088Smarkm	}
57429088Smarkm	val = binmode ? 0 : 1;
57529088Smarkm    }
57629088Smarkm
57729088Smarkm    if (val == 1) {
57829088Smarkm	if (my_want_state_is_will(TELOPT_BINARY) &&
57929088Smarkm					my_want_state_is_do(TELOPT_BINARY)) {
58029088Smarkm	    printf("Already operating in binary mode with remote host.\n");
58129088Smarkm	} else {
58229088Smarkm	    printf("Negotiating binary mode with remote host.\n");
58329088Smarkm	    tel_enter_binary(3);
58429088Smarkm	}
58529088Smarkm    } else {
58629088Smarkm	if (my_want_state_is_wont(TELOPT_BINARY) &&
58729088Smarkm					my_want_state_is_dont(TELOPT_BINARY)) {
58829088Smarkm	    printf("Already in network ascii mode with remote host.\n");
58929088Smarkm	} else {
59029088Smarkm	    printf("Negotiating network ascii mode with remote host.\n");
59129088Smarkm	    tel_leave_binary(3);
59229088Smarkm	}
59329088Smarkm    }
59429088Smarkm    return 1;
59529088Smarkm}
59629088Smarkm
59787139Smarkmstatic int
59887139Smarkmtogrbinary(int val)
59929088Smarkm{
60029088Smarkm    donebinarytoggle = 1;
60129088Smarkm
60229088Smarkm    if (val == -1)
60329088Smarkm	val = my_want_state_is_do(TELOPT_BINARY) ? 0 : 1;
60429088Smarkm
60529088Smarkm    if (val == 1) {
60629088Smarkm	if (my_want_state_is_do(TELOPT_BINARY)) {
60729088Smarkm	    printf("Already receiving in binary mode.\n");
60829088Smarkm	} else {
60929088Smarkm	    printf("Negotiating binary mode on input.\n");
61029088Smarkm	    tel_enter_binary(1);
61129088Smarkm	}
61229088Smarkm    } else {
61329088Smarkm	if (my_want_state_is_dont(TELOPT_BINARY)) {
61429088Smarkm	    printf("Already receiving in network ascii mode.\n");
61529088Smarkm	} else {
61629088Smarkm	    printf("Negotiating network ascii mode on input.\n");
61729088Smarkm	    tel_leave_binary(1);
61829088Smarkm	}
61929088Smarkm    }
62029088Smarkm    return 1;
62129088Smarkm}
62229088Smarkm
62387139Smarkmstatic int
62487139Smarkmtogxbinary(int val)
62529088Smarkm{
62629088Smarkm    donebinarytoggle = 1;
62729088Smarkm
62829088Smarkm    if (val == -1)
62929088Smarkm	val = my_want_state_is_will(TELOPT_BINARY) ? 0 : 1;
63029088Smarkm
63129088Smarkm    if (val == 1) {
63229088Smarkm	if (my_want_state_is_will(TELOPT_BINARY)) {
63329088Smarkm	    printf("Already transmitting in binary mode.\n");
63429088Smarkm	} else {
63529088Smarkm	    printf("Negotiating binary mode on output.\n");
63629088Smarkm	    tel_enter_binary(2);
63729088Smarkm	}
63829088Smarkm    } else {
63929088Smarkm	if (my_want_state_is_wont(TELOPT_BINARY)) {
64029088Smarkm	    printf("Already transmitting in network ascii mode.\n");
64129088Smarkm	} else {
64229088Smarkm	    printf("Negotiating network ascii mode on output.\n");
64329088Smarkm	    tel_leave_binary(2);
64429088Smarkm	}
64529088Smarkm    }
64629088Smarkm    return 1;
64729088Smarkm}
64829088Smarkm
64929088Smarkmstruct togglelist {
65087139Smarkm    const char	*name;		/* name of toggle */
65187139Smarkm    const char	*help;		/* help message */
65287139Smarkm    int		(*handler)(int); /* routine to do actual setting */
65329088Smarkm    int		*variable;
65487139Smarkm    const char	*actionexplanation;
65529088Smarkm};
65629088Smarkm
65729088Smarkmstatic struct togglelist Togglelist[] = {
65829088Smarkm    { "autoflush",
65929088Smarkm	"flushing of output when sending interrupt characters",
66029088Smarkm	    0,
66129088Smarkm		&autoflush,
66229088Smarkm		    "flush output when sending interrupt characters" },
66329088Smarkm    { "autosynch",
66429088Smarkm	"automatic sending of interrupt characters in urgent mode",
66529088Smarkm	    0,
66629088Smarkm		&autosynch,
66729088Smarkm		    "send interrupt characters in urgent mode" },
66887139Smarkm#ifdef	AUTHENTICATION
66929088Smarkm    { "autologin",
67029088Smarkm	"automatic sending of login and/or authentication info",
67129088Smarkm	    0,
67229088Smarkm		&autologin,
67329088Smarkm		    "send login name and/or authentication information" },
67429088Smarkm    { "authdebug",
67529088Smarkm	"Toggle authentication debugging",
67629088Smarkm	    auth_togdebug,
67729088Smarkm		0,
67829088Smarkm		     "print authentication debugging information" },
67929088Smarkm#endif
68029088Smarkm#ifdef	ENCRYPTION
68129088Smarkm    { "autoencrypt",
68229088Smarkm	"automatic encryption of data stream",
68329088Smarkm	    EncryptAutoEnc,
68429088Smarkm		0,
68529088Smarkm		    "automatically encrypt output" },
68629088Smarkm    { "autodecrypt",
68729088Smarkm	"automatic decryption of data stream",
68829088Smarkm	    EncryptAutoDec,
68929088Smarkm		0,
69029088Smarkm		    "automatically decrypt input" },
69129088Smarkm    { "verbose_encrypt",
69229088Smarkm	"Toggle verbose encryption output",
69329088Smarkm	    EncryptVerbose,
69429088Smarkm		0,
69529088Smarkm		    "print verbose encryption output" },
69629088Smarkm    { "encdebug",
69729088Smarkm	"Toggle encryption debugging",
69829088Smarkm	    EncryptDebug,
69929088Smarkm		0,
70029088Smarkm		    "print encryption debugging information" },
70129088Smarkm#endif	/* ENCRYPTION */
70229088Smarkm    { "skiprc",
70329088Smarkm	"don't read ~/.telnetrc file",
70429088Smarkm	    0,
70529088Smarkm		&skiprc,
70629088Smarkm		    "skip reading of ~/.telnetrc file" },
70729088Smarkm    { "binary",
70829088Smarkm	"sending and receiving of binary data",
70929088Smarkm	    togbinary,
71029088Smarkm		0,
71129088Smarkm		    0 },
71229088Smarkm    { "inbinary",
71329088Smarkm	"receiving of binary data",
71429088Smarkm	    togrbinary,
71529088Smarkm		0,
71629088Smarkm		    0 },
71729088Smarkm    { "outbinary",
71829088Smarkm	"sending of binary data",
71929088Smarkm	    togxbinary,
72029088Smarkm		0,
72129088Smarkm		    0 },
72229088Smarkm    { "crlf",
72329088Smarkm	"sending carriage returns as telnet <CR><LF>",
72487139Smarkm	    (int (*)(int))togcrlf,
72529088Smarkm		&crlf,
72629088Smarkm		    0 },
72729088Smarkm    { "crmod",
72829088Smarkm	"mapping of received carriage returns",
72929088Smarkm	    0,
73029088Smarkm		&crmod,
73129088Smarkm		    "map carriage return on output" },
73229088Smarkm    { "localchars",
73329088Smarkm	"local recognition of certain control characters",
73487139Smarkm	    (int (*)(int))lclchars,
73529088Smarkm		&localchars,
73629088Smarkm		    "recognize certain control characters" },
73787139Smarkm    { " ", "", NULL, NULL, NULL },		/* empty line */
73829088Smarkm    { "debug",
73929088Smarkm	"debugging",
74087139Smarkm	    (int (*)(int))togdebug,
741114911Smarkm		&telnet_debug,
74229088Smarkm		    "turn on socket level debugging" },
74329088Smarkm    { "netdata",
74429088Smarkm	"printing of hexadecimal network data (debugging)",
74529088Smarkm	    0,
74629088Smarkm		&netdata,
74729088Smarkm		    "print hexadecimal representation of network traffic" },
74829088Smarkm    { "prettydump",
74929088Smarkm	"output of \"netdata\" to user readable format (debugging)",
75029088Smarkm	    0,
75129088Smarkm		&prettydump,
75229088Smarkm		    "print user readable output for \"netdata\"" },
75329088Smarkm    { "options",
75429088Smarkm	"viewing of options processing (debugging)",
75529088Smarkm	    0,
75629088Smarkm		&showoptions,
75729088Smarkm		    "show option processing" },
75829088Smarkm    { "termdata",
75929088Smarkm	"(debugging) toggle printing of hexadecimal terminal data",
76029088Smarkm	    0,
76129088Smarkm		&termdata,
76229088Smarkm		    "print hexadecimal representation of terminal traffic" },
76329088Smarkm    { "?",
76487139Smarkm	NULL,
76587139Smarkm	    (int (*)(int))togglehelp,
76687139Smarkm		NULL,
76787139Smarkm		    NULL },
76887139Smarkm    { NULL, NULL, NULL, NULL, NULL },
76929088Smarkm    { "help",
77087139Smarkm	NULL,
77187139Smarkm	    (int (*)(int))togglehelp,
77287139Smarkm		NULL,
77387139Smarkm		    NULL },
77487139Smarkm    { NULL, NULL, NULL, NULL, NULL }
77529088Smarkm};
77629088Smarkm
77787139Smarkmstatic int
77887139Smarkmtogglehelp(void)
77929088Smarkm{
78029088Smarkm    struct togglelist *c;
78129088Smarkm
78229088Smarkm    for (c = Togglelist; c->name; c++) {
78329088Smarkm	if (c->help) {
78429088Smarkm	    if (*c->help)
78529088Smarkm		printf("%-15s toggle %s\n", c->name, c->help);
78629088Smarkm	    else
78729088Smarkm		printf("\n");
78829088Smarkm	}
78929088Smarkm    }
79029088Smarkm    printf("\n");
79129088Smarkm    printf("%-15s %s\n", "?", "display help information");
79229088Smarkm    return 0;
79329088Smarkm}
79429088Smarkm
79587139Smarkmstatic void
79687139Smarkmsettogglehelp(int set)
79729088Smarkm{
79829088Smarkm    struct togglelist *c;
79929088Smarkm
80029088Smarkm    for (c = Togglelist; c->name; c++) {
80129088Smarkm	if (c->help) {
80229088Smarkm	    if (*c->help)
80329088Smarkm		printf("%-15s %s %s\n", c->name, set ? "enable" : "disable",
80429088Smarkm						c->help);
80529088Smarkm	    else
80629088Smarkm		printf("\n");
80729088Smarkm	}
80829088Smarkm    }
80929088Smarkm}
81029088Smarkm
81129088Smarkm#define	GETTOGGLE(name) (struct togglelist *) \
81229088Smarkm		genget(name, (char **) Togglelist, sizeof(struct togglelist))
81329088Smarkm
81487139Smarkmstatic int
81587139Smarkmtoggle(int argc, char *argv[])
81629088Smarkm{
81729088Smarkm    int retval = 1;
81829088Smarkm    char *name;
81929088Smarkm    struct togglelist *c;
82029088Smarkm
82129088Smarkm    if (argc < 2) {
82229088Smarkm	fprintf(stderr,
82329088Smarkm	    "Need an argument to 'toggle' command.  'toggle ?' for help.\n");
82429088Smarkm	return 0;
82529088Smarkm    }
82629088Smarkm    argc--;
82729088Smarkm    argv++;
82829088Smarkm    while (argc--) {
82929088Smarkm	name = *argv++;
83029088Smarkm	c = GETTOGGLE(name);
83187139Smarkm	if (Ambiguous((void *)c)) {
83229088Smarkm	    fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n",
83329088Smarkm					name);
83429088Smarkm	    return 0;
83529088Smarkm	} else if (c == 0) {
83629088Smarkm	    fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n",
83729088Smarkm					name);
83829088Smarkm	    return 0;
83929088Smarkm	} else {
84029088Smarkm	    if (c->variable) {
84129088Smarkm		*c->variable = !*c->variable;		/* invert it */
84229088Smarkm		if (c->actionexplanation) {
84329088Smarkm		    printf("%s %s.\n", *c->variable? "Will" : "Won't",
84429088Smarkm							c->actionexplanation);
84529088Smarkm		}
84629088Smarkm	    }
84729088Smarkm	    if (c->handler) {
84829088Smarkm		retval &= (*c->handler)(-1);
84929088Smarkm	    }
85029088Smarkm	}
85129088Smarkm    }
85229088Smarkm    return retval;
85329088Smarkm}
85429088Smarkm
85529088Smarkm/*
85629088Smarkm * The following perform the "set" command.
85729088Smarkm */
85829088Smarkm
85929088Smarkm#ifdef	USE_TERMIO
86087139Smarkmstruct termio new_tc = { 0, 0, 0, 0, {}, 0, 0 };
86129088Smarkm#endif
86229088Smarkm
86329088Smarkmstruct setlist {
86487139Smarkm    const char *name;			/* name */
86587139Smarkm    const char *help;			/* help information */
86687139Smarkm    void (*handler)(char *);
86729088Smarkm    cc_t *charp;			/* where it is located at */
86829088Smarkm};
86929088Smarkm
87029088Smarkmstatic struct setlist Setlist[] = {
87129088Smarkm#ifdef	KLUDGELINEMODE
87287139Smarkm    { "echo", 	"character to toggle local echoing on/off", NULL, &echoc },
87329088Smarkm#endif
87487139Smarkm    { "escape",	"character to escape back to telnet command mode", NULL, &escape },
87529088Smarkm    { "rlogin", "rlogin escape character", 0, &rlogin },
87629088Smarkm    { "tracefile", "file to write trace information to", SetNetTrace, (cc_t *)NetTraceFile},
87787139Smarkm    { " ", "", NULL, NULL },
87887139Smarkm    { " ", "The following need 'localchars' to be toggled true", NULL, NULL },
87987139Smarkm    { "flushoutput", "character to cause an Abort Output", NULL, termFlushCharp },
88087139Smarkm    { "interrupt", "character to cause an Interrupt Process", NULL, termIntCharp },
88187139Smarkm    { "quit",	"character to cause an Abort process", NULL, termQuitCharp },
88287139Smarkm    { "eof",	"character to cause an EOF ", NULL, termEofCharp },
88387139Smarkm    { " ", "", NULL, NULL },
88487139Smarkm    { " ", "The following are for local editing in linemode", NULL, NULL },
88587139Smarkm    { "erase",	"character to use to erase a character", NULL, termEraseCharp },
88687139Smarkm    { "kill",	"character to use to erase a line", NULL, termKillCharp },
88787139Smarkm    { "lnext",	"character to use for literal next", NULL, termLiteralNextCharp },
88887139Smarkm    { "susp",	"character to cause a Suspend Process", NULL, termSuspCharp },
88987139Smarkm    { "reprint", "character to use for line reprint", NULL, termRprntCharp },
89087139Smarkm    { "worderase", "character to use to erase a word", NULL, termWerasCharp },
89187139Smarkm    { "start",	"character to use for XON", NULL, termStartCharp },
89287139Smarkm    { "stop",	"character to use for XOFF", NULL, termStopCharp },
89387139Smarkm    { "forw1",	"alternate end of line character", NULL, termForw1Charp },
89487139Smarkm    { "forw2",	"alternate end of line character", NULL, termForw2Charp },
89587139Smarkm    { "ayt",	"alternate AYT character", NULL, termAytCharp },
896274364Sngie    { "baudrate", "set remote baud rate", DoBaudRate, ComPortBaudRate },
89787139Smarkm    { NULL, NULL, NULL, NULL }
89829088Smarkm};
89929088Smarkm
90087139Smarkmstatic struct setlist *
90187139Smarkmgetset(char *name)
90229088Smarkm{
90329088Smarkm    return (struct setlist *)
90429088Smarkm		genget(name, (char **) Setlist, sizeof(struct setlist));
90529088Smarkm}
90629088Smarkm
90787139Smarkmvoid
90887139Smarkmset_escape_char(char *s)
90929088Smarkm{
91029088Smarkm	if (rlogin != _POSIX_VDISABLE) {
91129088Smarkm		rlogin = (s && *s) ? special(s) : _POSIX_VDISABLE;
91229088Smarkm		printf("Telnet rlogin escape character is '%s'.\n",
91329088Smarkm					control(rlogin));
91429088Smarkm	} else {
91529088Smarkm		escape = (s && *s) ? special(s) : _POSIX_VDISABLE;
91629088Smarkm		printf("Telnet escape character is '%s'.\n", control(escape));
91729088Smarkm	}
91829088Smarkm}
91929088Smarkm
92087139Smarkmstatic int
92187139Smarkmsetcmd(int argc, char *argv[])
92229088Smarkm{
92329088Smarkm    int value;
92429088Smarkm    struct setlist *ct;
92529088Smarkm    struct togglelist *c;
92629088Smarkm
92729088Smarkm    if (argc < 2 || argc > 3) {
92829088Smarkm	printf("Format is 'set Name Value'\n'set ?' for help.\n");
92929088Smarkm	return 0;
93029088Smarkm    }
93129088Smarkm    if ((argc == 2) && (isprefix(argv[1], "?") || isprefix(argv[1], "help"))) {
93229088Smarkm	for (ct = Setlist; ct->name; ct++)
93329088Smarkm	    printf("%-15s %s\n", ct->name, ct->help);
93429088Smarkm	printf("\n");
93529088Smarkm	settogglehelp(1);
93629088Smarkm	printf("%-15s %s\n", "?", "display help information");
93729088Smarkm	return 0;
93829088Smarkm    }
93929088Smarkm
94029088Smarkm    ct = getset(argv[1]);
94129088Smarkm    if (ct == 0) {
94229088Smarkm	c = GETTOGGLE(argv[1]);
94329088Smarkm	if (c == 0) {
94429088Smarkm	    fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n",
94529088Smarkm			argv[1]);
94629088Smarkm	    return 0;
94787139Smarkm	} else if (Ambiguous((void *)c)) {
94829088Smarkm	    fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
94929088Smarkm			argv[1]);
95029088Smarkm	    return 0;
95129088Smarkm	}
95229088Smarkm	if (c->variable) {
95329088Smarkm	    if ((argc == 2) || (strcmp("on", argv[2]) == 0))
95429088Smarkm		*c->variable = 1;
95529088Smarkm	    else if (strcmp("off", argv[2]) == 0)
95629088Smarkm		*c->variable = 0;
95729088Smarkm	    else {
95829088Smarkm		printf("Format is 'set togglename [on|off]'\n'set ?' for help.\n");
95929088Smarkm		return 0;
96029088Smarkm	    }
96129088Smarkm	    if (c->actionexplanation) {
96229088Smarkm		printf("%s %s.\n", *c->variable? "Will" : "Won't",
96329088Smarkm							c->actionexplanation);
96429088Smarkm	    }
96529088Smarkm	}
96629088Smarkm	if (c->handler)
96729088Smarkm	    (*c->handler)(1);
96829088Smarkm    } else if (argc != 3) {
96929088Smarkm	printf("Format is 'set Name Value'\n'set ?' for help.\n");
97029088Smarkm	return 0;
97187139Smarkm    } else if (Ambiguous((void *)ct)) {
97229088Smarkm	fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
97329088Smarkm			argv[1]);
97429088Smarkm	return 0;
97529088Smarkm    } else if (ct->handler) {
97629088Smarkm	(*ct->handler)(argv[2]);
97729088Smarkm	printf("%s set to \"%s\".\n", ct->name, (char *)ct->charp);
97829088Smarkm    } else {
97929088Smarkm	if (strcmp("off", argv[2])) {
98029088Smarkm	    value = special(argv[2]);
98129088Smarkm	} else {
98229088Smarkm	    value = _POSIX_VDISABLE;
98329088Smarkm	}
98429088Smarkm	*(ct->charp) = (cc_t)value;
98529088Smarkm	printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
98629088Smarkm    }
98729088Smarkm    slc_check();
98829088Smarkm    return 1;
98929088Smarkm}
99029088Smarkm
99187139Smarkmstatic int
99287139Smarkmunsetcmd(int argc, char *argv[])
99329088Smarkm{
99429088Smarkm    struct setlist *ct;
99529088Smarkm    struct togglelist *c;
99687139Smarkm    char *name;
99729088Smarkm
99829088Smarkm    if (argc < 2) {
99929088Smarkm	fprintf(stderr,
100029088Smarkm	    "Need an argument to 'unset' command.  'unset ?' for help.\n");
100129088Smarkm	return 0;
100229088Smarkm    }
100329088Smarkm    if (isprefix(argv[1], "?") || isprefix(argv[1], "help")) {
100429088Smarkm	for (ct = Setlist; ct->name; ct++)
100529088Smarkm	    printf("%-15s %s\n", ct->name, ct->help);
100629088Smarkm	printf("\n");
100729088Smarkm	settogglehelp(0);
100829088Smarkm	printf("%-15s %s\n", "?", "display help information");
100929088Smarkm	return 0;
101029088Smarkm    }
101129088Smarkm
101229088Smarkm    argc--;
101329088Smarkm    argv++;
101429088Smarkm    while (argc--) {
101529088Smarkm	name = *argv++;
101629088Smarkm	ct = getset(name);
101729088Smarkm	if (ct == 0) {
101829088Smarkm	    c = GETTOGGLE(name);
101929088Smarkm	    if (c == 0) {
102029088Smarkm		fprintf(stderr, "'%s': unknown argument ('unset ?' for help).\n",
102129088Smarkm			name);
102229088Smarkm		return 0;
102387139Smarkm	    } else if (Ambiguous((void *)c)) {
102429088Smarkm		fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n",
102529088Smarkm			name);
102629088Smarkm		return 0;
102729088Smarkm	    }
102829088Smarkm	    if (c->variable) {
102929088Smarkm		*c->variable = 0;
103029088Smarkm		if (c->actionexplanation) {
103129088Smarkm		    printf("%s %s.\n", *c->variable? "Will" : "Won't",
103229088Smarkm							c->actionexplanation);
103329088Smarkm		}
103429088Smarkm	    }
103529088Smarkm	    if (c->handler)
103629088Smarkm		(*c->handler)(0);
103787139Smarkm	} else if (Ambiguous((void *)ct)) {
103829088Smarkm	    fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n",
103929088Smarkm			name);
104029088Smarkm	    return 0;
104129088Smarkm	} else if (ct->handler) {
104229088Smarkm	    (*ct->handler)(0);
104329088Smarkm	    printf("%s reset to \"%s\".\n", ct->name, (char *)ct->charp);
104429088Smarkm	} else {
104529088Smarkm	    *(ct->charp) = _POSIX_VDISABLE;
104629088Smarkm	    printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
104729088Smarkm	}
104829088Smarkm    }
104929088Smarkm    return 1;
105029088Smarkm}
105129088Smarkm
105229088Smarkm/*
105329088Smarkm * The following are the data structures and routines for the
105429088Smarkm * 'mode' command.
105529088Smarkm */
105629088Smarkm#ifdef	KLUDGELINEMODE
105729088Smarkmextern int kludgelinemode;
105829088Smarkm
105987139Smarkmstatic int
106087139Smarkmdokludgemode(void)
106129088Smarkm{
106229088Smarkm    kludgelinemode = 1;
106329088Smarkm    send_wont(TELOPT_LINEMODE, 1);
106429088Smarkm    send_dont(TELOPT_SGA, 1);
106529088Smarkm    send_dont(TELOPT_ECHO, 1);
106649861Snsayer    return 1;
106729088Smarkm}
106829088Smarkm#endif
106929088Smarkm
107087139Smarkmstatic int
107187139Smarkmdolinemode(void)
107229088Smarkm{
107329088Smarkm#ifdef	KLUDGELINEMODE
107429088Smarkm    if (kludgelinemode)
107529088Smarkm	send_dont(TELOPT_SGA, 1);
107629088Smarkm#endif
107729088Smarkm    send_will(TELOPT_LINEMODE, 1);
107829088Smarkm    send_dont(TELOPT_ECHO, 1);
107929088Smarkm    return 1;
108029088Smarkm}
108129088Smarkm
108287139Smarkmstatic int
108387139Smarkmdocharmode(void)
108429088Smarkm{
108529088Smarkm#ifdef	KLUDGELINEMODE
108629088Smarkm    if (kludgelinemode)
108729088Smarkm	send_do(TELOPT_SGA, 1);
108829088Smarkm    else
108929088Smarkm#endif
109029088Smarkm    send_wont(TELOPT_LINEMODE, 1);
109129088Smarkm    send_do(TELOPT_ECHO, 1);
109229088Smarkm    return 1;
109329088Smarkm}
109429088Smarkm
109587139Smarkmstatic int
109687139Smarkmdolmmode(int bit, int on)
109729088Smarkm{
109829088Smarkm    unsigned char c;
109929088Smarkm    extern int linemode;
110029088Smarkm
110129088Smarkm    if (my_want_state_is_wont(TELOPT_LINEMODE)) {
110229088Smarkm	printf("?Need to have LINEMODE option enabled first.\n");
110329088Smarkm	printf("'mode ?' for help.\n");
110429088Smarkm	return 0;
110529088Smarkm    }
110629088Smarkm
110729088Smarkm    if (on)
110829088Smarkm	c = (linemode | bit);
110929088Smarkm    else
111029088Smarkm	c = (linemode & ~bit);
111129088Smarkm    lm_mode(&c, 1, 1);
111229088Smarkm    return 1;
111329088Smarkm}
111429088Smarkm
111587139Smarkmstatic int
111687139Smarkmsetmod(int bit)
111729088Smarkm{
111829088Smarkm    return dolmmode(bit, 1);
111929088Smarkm}
112029088Smarkm
112187139Smarkmstatic int
112287139Smarkmclearmode(int bit)
112329088Smarkm{
112429088Smarkm    return dolmmode(bit, 0);
112529088Smarkm}
112629088Smarkm
112729088Smarkmstruct modelist {
112887139Smarkm	const char	*name;	/* command name */
112987139Smarkm	const char	*help;	/* help string */
113087139Smarkm	int	(*handler)(int);/* routine which executes command */
113129088Smarkm	int	needconnect;	/* Do we need to be connected to execute? */
113229088Smarkm	int	arg1;
113329088Smarkm};
113429088Smarkm
113529088Smarkmstatic struct modelist ModeList[] = {
113687139Smarkm    { "character", "Disable LINEMODE option",	(int (*)(int))docharmode, 1, 0 },
113729088Smarkm#ifdef	KLUDGELINEMODE
113887139Smarkm    { "",	"(or disable obsolete line-by-line mode)", NULL, 0, 0 },
113929088Smarkm#endif
114087139Smarkm    { "line",	"Enable LINEMODE option",	(int (*)(int))dolinemode, 1, 0 },
114129088Smarkm#ifdef	KLUDGELINEMODE
114287139Smarkm    { "",	"(or enable obsolete line-by-line mode)", NULL, 0, 0 },
114329088Smarkm#endif
114487139Smarkm    { "", "", NULL, 0, 0 },
114587139Smarkm    { "",	"These require the LINEMODE option to be enabled", NULL, 0, 0 },
114629181Smarkm    { "isig",	"Enable signal trapping",	setmod, 1, MODE_TRAPSIG },
114729181Smarkm    { "+isig",	0,				setmod, 1, MODE_TRAPSIG },
114829088Smarkm    { "-isig",	"Disable signal trapping",	clearmode, 1, MODE_TRAPSIG },
114929181Smarkm    { "edit",	"Enable character editing",	setmod, 1, MODE_EDIT },
115029181Smarkm    { "+edit",	0,				setmod, 1, MODE_EDIT },
115129088Smarkm    { "-edit",	"Disable character editing",	clearmode, 1, MODE_EDIT },
115229181Smarkm    { "softtabs", "Enable tab expansion",	setmod, 1, MODE_SOFT_TAB },
115329181Smarkm    { "+softtabs", 0,				setmod, 1, MODE_SOFT_TAB },
115429088Smarkm    { "-softtabs", "Disable character editing",	clearmode, 1, MODE_SOFT_TAB },
115529181Smarkm    { "litecho", "Enable literal character echo", setmod, 1, MODE_LIT_ECHO },
115629181Smarkm    { "+litecho", 0,				setmod, 1, MODE_LIT_ECHO },
115729088Smarkm    { "-litecho", "Disable literal character echo", clearmode, 1, MODE_LIT_ECHO },
115887139Smarkm    { "help",	0,				(int (*)(int))modehelp, 0, 0 },
115929088Smarkm#ifdef	KLUDGELINEMODE
116087139Smarkm    { "kludgeline", 0,				(int (*)(int))dokludgemode, 1, 0 },
116129088Smarkm#endif
116287139Smarkm    { "", "", NULL, 0, 0 },
116387139Smarkm    { "?",	"Print help information",	(int (*)(int))modehelp, 0, 0 },
116487139Smarkm    { NULL, NULL, NULL, 0, 0 },
116529088Smarkm};
116629088Smarkm
116729088Smarkm
116887139Smarkmstatic int
116987139Smarkmmodehelp(void)
117029088Smarkm{
117129088Smarkm    struct modelist *mt;
117229088Smarkm
117329088Smarkm    printf("format is:  'mode Mode', where 'Mode' is one of:\n\n");
117429088Smarkm    for (mt = ModeList; mt->name; mt++) {
117529088Smarkm	if (mt->help) {
117629088Smarkm	    if (*mt->help)
117729088Smarkm		printf("%-15s %s\n", mt->name, mt->help);
117829088Smarkm	    else
117929088Smarkm		printf("\n");
118029088Smarkm	}
118129088Smarkm    }
118229088Smarkm    return 0;
118329088Smarkm}
118429088Smarkm
118529088Smarkm#define	GETMODECMD(name) (struct modelist *) \
118629088Smarkm		genget(name, (char **) ModeList, sizeof(struct modelist))
118729088Smarkm
118887139Smarkmstatic int
118987139Smarkmmodecmd(int argc, char *argv[])
119029088Smarkm{
119129088Smarkm    struct modelist *mt;
119229088Smarkm
119329088Smarkm    if (argc != 2) {
119429088Smarkm	printf("'mode' command requires an argument\n");
119529088Smarkm	printf("'mode ?' for help.\n");
119629088Smarkm    } else if ((mt = GETMODECMD(argv[1])) == 0) {
119729088Smarkm	fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]);
119887139Smarkm    } else if (Ambiguous((void *)mt)) {
119929088Smarkm	fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]);
120029088Smarkm    } else if (mt->needconnect && !connected) {
120129088Smarkm	printf("?Need to be connected first.\n");
120229088Smarkm	printf("'mode ?' for help.\n");
120329088Smarkm    } else if (mt->handler) {
120429088Smarkm	return (*mt->handler)(mt->arg1);
120529088Smarkm    }
120629088Smarkm    return 0;
120729088Smarkm}
120829088Smarkm
120929088Smarkm/*
121029088Smarkm * The following data structures and routines implement the
121129088Smarkm * "display" command.
121229088Smarkm */
121329088Smarkm
121487139Smarkmstatic int
121587139Smarkmdisplay(int argc, char *argv[])
121629088Smarkm{
121729088Smarkm    struct togglelist *tl;
121829088Smarkm    struct setlist *sl;
121929088Smarkm
122029088Smarkm#define	dotog(tl)	if (tl->variable && tl->actionexplanation) { \
122129088Smarkm			    if (*tl->variable) { \
122229088Smarkm				printf("will"); \
122329088Smarkm			    } else { \
122429088Smarkm				printf("won't"); \
122529088Smarkm			    } \
122629088Smarkm			    printf(" %s.\n", tl->actionexplanation); \
122729088Smarkm			}
122829088Smarkm
122929088Smarkm#define	doset(sl)   if (sl->name && *sl->name != ' ') { \
123029088Smarkm			if (sl->handler == 0) \
123129088Smarkm			    printf("%-15s [%s]\n", sl->name, control(*sl->charp)); \
123229088Smarkm			else \
123329088Smarkm			    printf("%-15s \"%s\"\n", sl->name, (char *)sl->charp); \
123429088Smarkm		    }
123529088Smarkm
123629088Smarkm    if (argc == 1) {
123729088Smarkm	for (tl = Togglelist; tl->name; tl++) {
123829088Smarkm	    dotog(tl);
123929088Smarkm	}
124029088Smarkm	printf("\n");
124129088Smarkm	for (sl = Setlist; sl->name; sl++) {
124229088Smarkm	    doset(sl);
124329088Smarkm	}
124429088Smarkm    } else {
124529088Smarkm	int i;
124629088Smarkm
124729088Smarkm	for (i = 1; i < argc; i++) {
124829088Smarkm	    sl = getset(argv[i]);
124929088Smarkm	    tl = GETTOGGLE(argv[i]);
125087139Smarkm	    if (Ambiguous((void *)sl) || Ambiguous((void *)tl)) {
125129088Smarkm		printf("?Ambiguous argument '%s'.\n", argv[i]);
125229088Smarkm		return 0;
125329088Smarkm	    } else if (!sl && !tl) {
125429088Smarkm		printf("?Unknown argument '%s'.\n", argv[i]);
125529088Smarkm		return 0;
125629088Smarkm	    } else {
125729088Smarkm		if (tl) {
125829088Smarkm		    dotog(tl);
125929088Smarkm		}
126029088Smarkm		if (sl) {
126129088Smarkm		    doset(sl);
126229088Smarkm		}
126329088Smarkm	    }
126429088Smarkm	}
126529088Smarkm    }
126629088Smarkm/*@*/optionstatus();
126729088Smarkm#ifdef	ENCRYPTION
126829088Smarkm    EncryptStatus();
126929088Smarkm#endif	/* ENCRYPTION */
127029088Smarkm    return 1;
127129088Smarkm#undef	doset
127229088Smarkm#undef	dotog
127329088Smarkm}
127429088Smarkm
127529088Smarkm/*
127629088Smarkm * The following are the data structures, and many of the routines,
127729088Smarkm * relating to command processing.
127829088Smarkm */
127929088Smarkm
128029088Smarkm/*
128129088Smarkm * Set the escape character.
128229088Smarkm */
128387139Smarkmstatic int
128487139Smarkmsetescape(int argc, char *argv[])
128529088Smarkm{
128687139Smarkm	char *arg;
128729088Smarkm	char buf[50];
128829088Smarkm
128929088Smarkm	printf(
129029088Smarkm	    "Deprecated usage - please use 'set escape%s%s' in the future.\n",
129129088Smarkm				(argc > 2)? " ":"", (argc > 2)? argv[1]: "");
129229088Smarkm	if (argc > 2)
129329088Smarkm		arg = argv[1];
129429088Smarkm	else {
129529088Smarkm		printf("new escape character: ");
129629088Smarkm		(void) fgets(buf, sizeof(buf), stdin);
129729088Smarkm		arg = buf;
129829088Smarkm	}
129929088Smarkm	if (arg[0] != '\0')
130029088Smarkm		escape = arg[0];
130129088Smarkm	(void) fflush(stdout);
130229088Smarkm	return 1;
130329088Smarkm}
130429088Smarkm
130587139Smarkmstatic int
130687139Smarkmtogcrmod(void)
130729088Smarkm{
130829088Smarkm    crmod = !crmod;
130929088Smarkm    printf("Deprecated usage - please use 'toggle crmod' in the future.\n");
131029088Smarkm    printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't");
131129088Smarkm    (void) fflush(stdout);
131229088Smarkm    return 1;
131329088Smarkm}
131429088Smarkm
131587139Smarkmstatic int
131687139Smarkmsuspend(void)
131729088Smarkm{
131829088Smarkm#ifdef	SIGTSTP
131929088Smarkm    setcommandmode();
132029088Smarkm    {
132187139Smarkm	long oldrows, oldcols, newrows, newcols, err_;
132229088Smarkm
132387139Smarkm	err_ = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0;
132429088Smarkm	(void) kill(0, SIGTSTP);
132529088Smarkm	/*
132629088Smarkm	 * If we didn't get the window size before the SUSPEND, but we
132729088Smarkm	 * can get them now (?), then send the NAWS to make sure that
132829088Smarkm	 * we are set up for the right window size.
132929088Smarkm	 */
133029088Smarkm	if (TerminalWindowSize(&newrows, &newcols) && connected &&
133187139Smarkm	    (err_ || ((oldrows != newrows) || (oldcols != newcols)))) {
133229088Smarkm		sendnaws();
133329088Smarkm	}
133429088Smarkm    }
133529088Smarkm    /* reget parameters in case they were changed */
133629088Smarkm    TerminalSaveState();
133729088Smarkm    setconnmode(0);
133829088Smarkm#else
133929088Smarkm    printf("Suspend is not supported.  Try the '!' command instead\n");
134029088Smarkm#endif
134129088Smarkm    return 1;
134229088Smarkm}
134329088Smarkm
134487139Smarkmstatic int
134587139Smarkmshell(int argc, char *argv[] __unused)
134629088Smarkm{
134787139Smarkm    long oldrows, oldcols, newrows, newcols, err_;
134829088Smarkm
134929088Smarkm    setcommandmode();
135029088Smarkm
135187139Smarkm    err_ = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0;
135229088Smarkm    switch(vfork()) {
135329088Smarkm    case -1:
135429088Smarkm	perror("Fork failed\n");
135529088Smarkm	break;
135629088Smarkm
135729088Smarkm    case 0:
135829088Smarkm	{
135929088Smarkm	    /*
136029088Smarkm	     * Fire up the shell in the child.
136129088Smarkm	     */
136287139Smarkm	    const char *shellp, *shellname;
136329088Smarkm
136429088Smarkm	    shellp = getenv("SHELL");
136529088Smarkm	    if (shellp == NULL)
136629088Smarkm		shellp = "/bin/sh";
136729088Smarkm	    if ((shellname = strrchr(shellp, '/')) == 0)
136829088Smarkm		shellname = shellp;
136929088Smarkm	    else
137029088Smarkm		shellname++;
137129088Smarkm	    if (argc > 1)
137281965Smarkm		execl(shellp, shellname, "-c", &saveline[1], (char *)0);
137329088Smarkm	    else
137481965Smarkm		execl(shellp, shellname, (char *)0);
137529088Smarkm	    perror("Execl");
137629088Smarkm	    _exit(1);
137729088Smarkm	}
137829088Smarkm    default:
137929088Smarkm	    (void)wait((int *)0);	/* Wait for the shell to complete */
138029088Smarkm
138129088Smarkm	    if (TerminalWindowSize(&newrows, &newcols) && connected &&
138287139Smarkm		(err_ || ((oldrows != newrows) || (oldcols != newcols)))) {
138329088Smarkm		    sendnaws();
138429088Smarkm	    }
138529088Smarkm	    break;
138629088Smarkm    }
138729088Smarkm    return 1;
138829088Smarkm}
138929088Smarkm
139087139Smarkmstatic int
139187139Smarkmbye(int argc, char *argv[])
139229088Smarkm{
139329088Smarkm    extern int resettermname;
139429088Smarkm
139529088Smarkm    if (connected) {
139629088Smarkm	(void) shutdown(net, 2);
139729088Smarkm	printf("Connection closed.\n");
139829088Smarkm	(void) NetClose(net);
139929088Smarkm	connected = 0;
140029088Smarkm	resettermname = 1;
140187139Smarkm#ifdef	AUTHENTICATION
140287139Smarkm#ifdef	ENCRYPTION
140329088Smarkm	auth_encrypt_connect(connected);
140487139Smarkm#endif
140587139Smarkm#endif
140629088Smarkm	/* reset options */
140729088Smarkm	tninit();
140829088Smarkm    }
140929088Smarkm    if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) {
141029088Smarkm	longjmp(toplevel, 1);
141129088Smarkm	/* NOTREACHED */
141229088Smarkm    }
141329088Smarkm    return 1;			/* Keep lint, etc., happy */
141429088Smarkm}
141529088Smarkm
141687139Smarkmvoid
141787139Smarkmquit(void)
141829088Smarkm{
141929088Smarkm	(void) call(bye, "bye", "fromquit", 0);
142029088Smarkm	Exit(0);
142129088Smarkm}
142229088Smarkm
142387139Smarkmstatic int
142487139Smarkmlogout(void)
142529088Smarkm{
142629088Smarkm	send_do(TELOPT_LOGOUT, 1);
142729088Smarkm	(void) netflush();
142829088Smarkm	return 1;
142929088Smarkm}
143029088Smarkm
143129088Smarkm
143229088Smarkm/*
143329088Smarkm * The SLC command.
143429088Smarkm */
143529088Smarkm
143629088Smarkmstruct slclist {
143787139Smarkm	const char	*name;
143887139Smarkm	const char	*help;
143987139Smarkm	void	(*handler)(int);
144029088Smarkm	int	arg;
144129088Smarkm};
144229088Smarkm
144387139Smarkmstatic void slc_help(void);
144429088Smarkm
144529088Smarkmstruct slclist SlcList[] = {
144629088Smarkm    { "export",	"Use local special character definitions",
144787139Smarkm						(void (*)(int))slc_mode_export,	0 },
144829088Smarkm    { "import",	"Use remote special character definitions",
144929088Smarkm						slc_mode_import,	1 },
145029088Smarkm    { "check",	"Verify remote special character definitions",
145129088Smarkm						slc_mode_import,	0 },
145287139Smarkm    { "help",	NULL,				(void (*)(int))slc_help,		0 },
145387139Smarkm    { "?",	"Print help information",	(void (*)(int))slc_help,		0 },
145487139Smarkm    { NULL, NULL, NULL, 0 },
145529088Smarkm};
145629088Smarkm
145787139Smarkmstatic void
145887139Smarkmslc_help(void)
145929088Smarkm{
146029088Smarkm    struct slclist *c;
146129088Smarkm
146229088Smarkm    for (c = SlcList; c->name; c++) {
146329088Smarkm	if (c->help) {
146429088Smarkm	    if (*c->help)
146529088Smarkm		printf("%-15s %s\n", c->name, c->help);
146629088Smarkm	    else
146729088Smarkm		printf("\n");
146829088Smarkm	}
146929088Smarkm    }
147029088Smarkm}
147129088Smarkm
147287139Smarkmstatic struct slclist *
147387139Smarkmgetslc(char *name)
147429088Smarkm{
147529088Smarkm    return (struct slclist *)
147629088Smarkm		genget(name, (char **) SlcList, sizeof(struct slclist));
147729088Smarkm}
147829088Smarkm
147987139Smarkmstatic int
148087139Smarkmslccmd(int argc, char *argv[])
148129088Smarkm{
148229088Smarkm    struct slclist *c;
148329088Smarkm
148429088Smarkm    if (argc != 2) {
148529088Smarkm	fprintf(stderr,
148629088Smarkm	    "Need an argument to 'slc' command.  'slc ?' for help.\n");
148729088Smarkm	return 0;
148829088Smarkm    }
148929088Smarkm    c = getslc(argv[1]);
149029088Smarkm    if (c == 0) {
149129088Smarkm	fprintf(stderr, "'%s': unknown argument ('slc ?' for help).\n",
149229088Smarkm    				argv[1]);
149329088Smarkm	return 0;
149429088Smarkm    }
149587139Smarkm    if (Ambiguous((void *)c)) {
149629088Smarkm	fprintf(stderr, "'%s': ambiguous argument ('slc ?' for help).\n",
149729088Smarkm    				argv[1]);
149829088Smarkm	return 0;
149929088Smarkm    }
150029088Smarkm    (*c->handler)(c->arg);
150129088Smarkm    slcstate();
150229088Smarkm    return 1;
150329088Smarkm}
150429088Smarkm
150529088Smarkm/*
150629088Smarkm * The ENVIRON command.
150729088Smarkm */
150829088Smarkm
150929088Smarkmstruct envlist {
151087139Smarkm	const char	*name;
151187139Smarkm	const char	*help;
151287139Smarkm	void	(*handler)(unsigned char *, unsigned char *);
151329088Smarkm	int	narg;
151429088Smarkm};
151529088Smarkm
151629088Smarkmextern struct env_lst *
151787155Smarkm	env_define(const unsigned char *, unsigned char *);
151829088Smarkmextern void
151987155Smarkm	env_undefine(unsigned char *),
152087155Smarkm	env_export(const unsigned char *),
152187155Smarkm	env_unexport(const unsigned char *),
152287155Smarkm	env_send(unsigned char *),
152329088Smarkm#if defined(OLD_ENVIRON) && defined(ENV_HACK)
152487155Smarkm	env_varval(unsigned char *),
152529088Smarkm#endif
152687155Smarkm	env_list(void);
152729088Smarkmstatic void
152887155Smarkm	env_help(void);
152929088Smarkm
153029088Smarkmstruct envlist EnvList[] = {
153129088Smarkm    { "define",	"Define an environment variable",
153287139Smarkm						(void (*)(unsigned char *, unsigned char *))env_define,	2 },
153329088Smarkm    { "undefine", "Undefine an environment variable",
153487139Smarkm						(void (*)(unsigned char *, unsigned char *))env_undefine,	1 },
153529088Smarkm    { "export",	"Mark an environment variable for automatic export",
153687139Smarkm						(void (*)(unsigned char *, unsigned char *))env_export,	1 },
153729088Smarkm    { "unexport", "Don't mark an environment variable for automatic export",
153887139Smarkm						(void (*)(unsigned char *, unsigned char *))env_unexport,	1 },
153987139Smarkm    { "send",	"Send an environment variable", (void (*)(unsigned char *, unsigned char *))env_send,	1 },
154029088Smarkm    { "list",	"List the current environment variables",
154187139Smarkm						(void (*)(unsigned char *, unsigned char *))env_list,	0 },
154229088Smarkm#if defined(OLD_ENVIRON) && defined(ENV_HACK)
154329088Smarkm    { "varval", "Reverse VAR and VALUE (auto, right, wrong, status)",
154487139Smarkm						(void (*)(unsigned char *, unsigned char *))env_varval,    1 },
154529088Smarkm#endif
154687139Smarkm    { "help",	NULL,				(void (*)(unsigned char *, unsigned char *))env_help,		0 },
154787139Smarkm    { "?",	"Print help information",	(void (*)(unsigned char *, unsigned char *))env_help,		0 },
154887139Smarkm    { NULL, NULL, NULL, 0 },
154929088Smarkm};
155029088Smarkm
155187139Smarkmstatic void
155287139Smarkmenv_help(void)
155329088Smarkm{
155429088Smarkm    struct envlist *c;
155529088Smarkm
155629088Smarkm    for (c = EnvList; c->name; c++) {
155729088Smarkm	if (c->help) {
155829088Smarkm	    if (*c->help)
155929088Smarkm		printf("%-15s %s\n", c->name, c->help);
156029088Smarkm	    else
156129088Smarkm		printf("\n");
156229088Smarkm	}
156329088Smarkm    }
156429088Smarkm}
156529088Smarkm
156687139Smarkmstatic struct envlist *
156787139Smarkmgetenvcmd(char *name)
156829088Smarkm{
156929088Smarkm    return (struct envlist *)
157029088Smarkm		genget(name, (char **) EnvList, sizeof(struct envlist));
157129088Smarkm}
157229088Smarkm
157387139Smarkmstatic int
157487139Smarkmenv_cmd(int argc, char *argv[])
157529088Smarkm{
157629088Smarkm    struct envlist *c;
157729088Smarkm
157829088Smarkm    if (argc < 2) {
157929088Smarkm	fprintf(stderr,
158029088Smarkm	    "Need an argument to 'environ' command.  'environ ?' for help.\n");
158129088Smarkm	return 0;
158229088Smarkm    }
158329088Smarkm    c = getenvcmd(argv[1]);
158429088Smarkm    if (c == 0) {
158529088Smarkm	fprintf(stderr, "'%s': unknown argument ('environ ?' for help).\n",
158629088Smarkm    				argv[1]);
158729088Smarkm	return 0;
158829088Smarkm    }
158987139Smarkm    if (Ambiguous((void *)c)) {
159029088Smarkm	fprintf(stderr, "'%s': ambiguous argument ('environ ?' for help).\n",
159129088Smarkm    				argv[1]);
159229088Smarkm	return 0;
159329088Smarkm    }
159429088Smarkm    if (c->narg + 2 != argc) {
159529088Smarkm	fprintf(stderr,
159629088Smarkm	    "Need %s%d argument%s to 'environ %s' command.  'environ ?' for help.\n",
159729088Smarkm		c->narg < argc + 2 ? "only " : "",
159829088Smarkm		c->narg, c->narg == 1 ? "" : "s", c->name);
159929088Smarkm	return 0;
160029088Smarkm    }
160129088Smarkm    (*c->handler)(argv[2], argv[3]);
160229088Smarkm    return 1;
160329088Smarkm}
160429088Smarkm
160529088Smarkmstruct env_lst {
160629088Smarkm	struct env_lst *next;	/* pointer to next structure */
160729088Smarkm	struct env_lst *prev;	/* pointer to previous structure */
160829088Smarkm	unsigned char *var;	/* pointer to variable name */
160929088Smarkm	unsigned char *value;	/* pointer to variable value */
161029088Smarkm	int export;		/* 1 -> export with default list of variables */
161129088Smarkm	int welldefined;	/* A well defined variable */
161229088Smarkm};
161329088Smarkm
161429088Smarkmstruct env_lst envlisthead;
161529088Smarkm
161687139Smarkmstatic struct env_lst *
161787139Smarkmenv_find(const unsigned char *var)
161829088Smarkm{
161987139Smarkm	struct env_lst *ep;
162029088Smarkm
162129088Smarkm	for (ep = envlisthead.next; ep; ep = ep->next) {
162287139Smarkm		if (strcmp(ep->var, var) == 0)
162329088Smarkm			return(ep);
162429088Smarkm	}
162529088Smarkm	return(NULL);
162629088Smarkm}
162729088Smarkm
162887139Smarkmvoid
162987139Smarkmenv_init(void)
163029088Smarkm{
163129088Smarkm	extern char **environ;
163287139Smarkm	char **epp, *cp;
163387139Smarkm	struct env_lst *ep;
163429088Smarkm
163529088Smarkm	for (epp = environ; *epp; epp++) {
163629181Smarkm		if ((cp = strchr(*epp, '='))) {
163729088Smarkm			*cp = '\0';
163829088Smarkm			ep = env_define((unsigned char *)*epp,
163929088Smarkm					(unsigned char *)cp+1);
164029088Smarkm			ep->export = 0;
164129088Smarkm			*cp = '=';
164229088Smarkm		}
164329088Smarkm	}
164429088Smarkm	/*
164529088Smarkm	 * Special case for DISPLAY variable.  If it is ":0.0" or
164629088Smarkm	 * "unix:0.0", we have to get rid of "unix" and insert our
164729088Smarkm	 * hostname.
164829088Smarkm	 */
164929088Smarkm	if ((ep = env_find("DISPLAY"))
165029088Smarkm	    && ((*ep->value == ':')
165129088Smarkm		|| (strncmp((char *)ep->value, "unix:", 5) == 0))) {
165229088Smarkm		char hbuf[256+1];
165329088Smarkm		char *cp2 = strchr((char *)ep->value, ':');
165429088Smarkm
1655350140Sphilip		gethostname(hbuf, sizeof(hbuf));
1656350140Sphilip		hbuf[sizeof(hbuf)-1] = '\0';
1657350901Semaste		asprintf(&cp, "%s%s", hbuf, cp2);
1658350140Sphilip		assert(cp != NULL);
165929088Smarkm		free(ep->value);
166029088Smarkm		ep->value = (unsigned char *)cp;
166129088Smarkm	}
166229088Smarkm	/*
166329088Smarkm	 * If USER is not defined, but LOGNAME is, then add
166429088Smarkm	 * USER with the value from LOGNAME.  By default, we
166529088Smarkm	 * don't export the USER variable.
166629088Smarkm	 */
166729088Smarkm	if ((env_find("USER") == NULL) && (ep = env_find("LOGNAME"))) {
166887139Smarkm		env_define("USER", ep->value);
166987139Smarkm		env_unexport("USER");
167029088Smarkm	}
167187139Smarkm	env_export("DISPLAY");
167287139Smarkm	env_export("PRINTER");
167329088Smarkm}
167429088Smarkm
167587139Smarkmstruct env_lst *
167687139Smarkmenv_define(const unsigned char *var, unsigned char *value)
167729088Smarkm{
167887139Smarkm	struct env_lst *ep;
167929088Smarkm
168029181Smarkm	if ((ep = env_find(var))) {
168129088Smarkm		if (ep->var)
168229088Smarkm			free(ep->var);
168329088Smarkm		if (ep->value)
168429088Smarkm			free(ep->value);
168529088Smarkm	} else {
168629088Smarkm		ep = (struct env_lst *)malloc(sizeof(struct env_lst));
168729088Smarkm		ep->next = envlisthead.next;
168829088Smarkm		envlisthead.next = ep;
168929088Smarkm		ep->prev = &envlisthead;
169029088Smarkm		if (ep->next)
169129088Smarkm			ep->next->prev = ep;
169229088Smarkm	}
169329088Smarkm	ep->welldefined = opt_welldefined(var);
169429088Smarkm	ep->export = 1;
169587139Smarkm	ep->var = strdup(var);
169687139Smarkm	ep->value = strdup(value);
169729088Smarkm	return(ep);
169829088Smarkm}
169929088Smarkm
170087139Smarkmvoid
170187139Smarkmenv_undefine(unsigned char *var)
170229088Smarkm{
170387139Smarkm	struct env_lst *ep;
170429088Smarkm
170529181Smarkm	if ((ep = env_find(var))) {
170629088Smarkm		ep->prev->next = ep->next;
170729088Smarkm		if (ep->next)
170829088Smarkm			ep->next->prev = ep->prev;
170929088Smarkm		if (ep->var)
171029088Smarkm			free(ep->var);
171129088Smarkm		if (ep->value)
171229088Smarkm			free(ep->value);
171329088Smarkm		free(ep);
171429088Smarkm	}
171529088Smarkm}
171629088Smarkm
171787139Smarkmvoid
171887139Smarkmenv_export(const unsigned char *var)
171929088Smarkm{
172087139Smarkm	struct env_lst *ep;
172129088Smarkm
172229181Smarkm	if ((ep = env_find(var)))
172329088Smarkm		ep->export = 1;
172429088Smarkm}
172529088Smarkm
172687139Smarkmvoid
172787139Smarkmenv_unexport(const unsigned char *var)
172829088Smarkm{
172987139Smarkm	struct env_lst *ep;
173029088Smarkm
173129181Smarkm	if ((ep = env_find(var)))
173229088Smarkm		ep->export = 0;
173329088Smarkm}
173429088Smarkm
173587139Smarkmvoid
173687139Smarkmenv_send(unsigned char *var)
173729088Smarkm{
173887139Smarkm	struct env_lst *ep;
173929088Smarkm
174029088Smarkm	if (my_state_is_wont(TELOPT_NEW_ENVIRON)
174129088Smarkm#ifdef	OLD_ENVIRON
174229088Smarkm	    && my_state_is_wont(TELOPT_OLD_ENVIRON)
174329088Smarkm#endif
174429088Smarkm		) {
174529088Smarkm		fprintf(stderr,
174629088Smarkm		    "Cannot send '%s': Telnet ENVIRON option not enabled\n",
174729088Smarkm									var);
174829088Smarkm		return;
174929088Smarkm	}
175029088Smarkm	ep = env_find(var);
175129088Smarkm	if (ep == 0) {
175229088Smarkm		fprintf(stderr, "Cannot send '%s': variable not defined\n",
175329088Smarkm									var);
175429088Smarkm		return;
175529088Smarkm	}
175629088Smarkm	env_opt_start_info();
175729088Smarkm	env_opt_add(ep->var);
175829088Smarkm	env_opt_end(0);
175929088Smarkm}
176029088Smarkm
176187139Smarkmvoid
176287139Smarkmenv_list(void)
176329088Smarkm{
176487139Smarkm	struct env_lst *ep;
176529088Smarkm
176629088Smarkm	for (ep = envlisthead.next; ep; ep = ep->next) {
176729088Smarkm		printf("%c %-20s %s\n", ep->export ? '*' : ' ',
176829088Smarkm					ep->var, ep->value);
176929088Smarkm	}
177029088Smarkm}
177129088Smarkm
177287139Smarkmunsigned char *
177387139Smarkmenv_default(int init, int welldefined)
177429088Smarkm{
177529088Smarkm	static struct env_lst *nep = NULL;
177629088Smarkm
177729088Smarkm	if (init) {
177829088Smarkm		nep = &envlisthead;
177929181Smarkm		return(NULL);
178029088Smarkm	}
178129088Smarkm	if (nep) {
178229181Smarkm		while ((nep = nep->next)) {
178329088Smarkm			if (nep->export && (nep->welldefined == welldefined))
178429088Smarkm				return(nep->var);
178529088Smarkm		}
178629088Smarkm	}
178729088Smarkm	return(NULL);
178829088Smarkm}
178929088Smarkm
179087139Smarkmunsigned char *
179187139Smarkmenv_getvalue(const unsigned char *var)
179229088Smarkm{
179387139Smarkm	struct env_lst *ep;
179429088Smarkm
179529181Smarkm	if ((ep = env_find(var)))
179629088Smarkm		return(ep->value);
179729088Smarkm	return(NULL);
179829088Smarkm}
179929088Smarkm
180029088Smarkm#if defined(OLD_ENVIRON) && defined(ENV_HACK)
180187139Smarkmvoid
180287139Smarkmenv_varval(unsigned char *what)
180329088Smarkm{
180429088Smarkm	extern int old_env_var, old_env_value, env_auto;
180529088Smarkm	int len = strlen((char *)what);
180629088Smarkm
180729088Smarkm	if (len == 0)
180829088Smarkm		goto unknown;
180929088Smarkm
181029088Smarkm	if (strncasecmp((char *)what, "status", len) == 0) {
181129088Smarkm		if (env_auto)
181229088Smarkm			printf("%s%s", "VAR and VALUE are/will be ",
181329088Smarkm					"determined automatically\n");
181429088Smarkm		if (old_env_var == OLD_ENV_VAR)
181529088Smarkm			printf("VAR and VALUE set to correct definitions\n");
181629088Smarkm		else
181729088Smarkm			printf("VAR and VALUE definitions are reversed\n");
181829088Smarkm	} else if (strncasecmp((char *)what, "auto", len) == 0) {
181929088Smarkm		env_auto = 1;
182029088Smarkm		old_env_var = OLD_ENV_VALUE;
182129088Smarkm		old_env_value = OLD_ENV_VAR;
182229088Smarkm	} else if (strncasecmp((char *)what, "right", len) == 0) {
182329088Smarkm		env_auto = 0;
182429088Smarkm		old_env_var = OLD_ENV_VAR;
182529088Smarkm		old_env_value = OLD_ENV_VALUE;
182629088Smarkm	} else if (strncasecmp((char *)what, "wrong", len) == 0) {
182729088Smarkm		env_auto = 0;
182829088Smarkm		old_env_var = OLD_ENV_VALUE;
182929088Smarkm		old_env_value = OLD_ENV_VAR;
183029088Smarkm	} else {
183129088Smarkmunknown:
183229088Smarkm		printf("Unknown \"varval\" command. (\"auto\", \"right\", \"wrong\", \"status\")\n");
183329088Smarkm	}
183429088Smarkm}
183529088Smarkm#endif
183629088Smarkm
183787139Smarkm#ifdef	AUTHENTICATION
183829088Smarkm/*
183929088Smarkm * The AUTHENTICATE command.
184029088Smarkm */
184129088Smarkm
184229088Smarkmstruct authlist {
184387139Smarkm	const char	*name;
184487139Smarkm	const char	*help;
184587139Smarkm	int	(*handler)(char *);
184629088Smarkm	int	narg;
184729088Smarkm};
184829088Smarkm
184929088Smarkmextern int
185087155Smarkm	auth_enable(char *),
185187155Smarkm	auth_disable(char *),
185287155Smarkm	auth_status(void);
185329088Smarkmstatic int
185487155Smarkm	auth_help(void);
185529088Smarkm
185629088Smarkmstruct authlist AuthList[] = {
185729088Smarkm    { "status",	"Display current status of authentication information",
185887139Smarkm						(int (*)(char *))auth_status,	0 },
185929088Smarkm    { "disable", "Disable an authentication type ('auth disable ?' for more)",
186029088Smarkm						auth_disable,	1 },
186129088Smarkm    { "enable", "Enable an authentication type ('auth enable ?' for more)",
186229088Smarkm						auth_enable,	1 },
186387139Smarkm    { "help",	NULL,				(int (*)(char *))auth_help,		0 },
186487139Smarkm    { "?",	"Print help information",	(int (*)(char *))auth_help,		0 },
186587139Smarkm    { NULL, NULL, NULL, 0 },
186629088Smarkm};
186729088Smarkm
186887139Smarkmstatic int
186987139Smarkmauth_help(void)
187029088Smarkm{
187129088Smarkm    struct authlist *c;
187229088Smarkm
187329088Smarkm    for (c = AuthList; c->name; c++) {
187429088Smarkm	if (c->help) {
187529088Smarkm	    if (*c->help)
187629088Smarkm		printf("%-15s %s\n", c->name, c->help);
187729088Smarkm	    else
187829088Smarkm		printf("\n");
187929088Smarkm	}
188029088Smarkm    }
188129088Smarkm    return 0;
188229088Smarkm}
188329088Smarkm
188487139Smarkmint
188587139Smarkmauth_cmd(int argc, char *argv[])
188629088Smarkm{
188729088Smarkm    struct authlist *c;
188829088Smarkm
188929088Smarkm    if (argc < 2) {
189029088Smarkm	fprintf(stderr,
189129088Smarkm	    "Need an argument to 'auth' command.  'auth ?' for help.\n");
189229088Smarkm	return 0;
189329088Smarkm    }
189429088Smarkm
189529088Smarkm    c = (struct authlist *)
189629088Smarkm		genget(argv[1], (char **) AuthList, sizeof(struct authlist));
189729088Smarkm    if (c == 0) {
189829088Smarkm	fprintf(stderr, "'%s': unknown argument ('auth ?' for help).\n",
189929088Smarkm    				argv[1]);
190029088Smarkm	return 0;
190129088Smarkm    }
190287139Smarkm    if (Ambiguous((void *)c)) {
190329088Smarkm	fprintf(stderr, "'%s': ambiguous argument ('auth ?' for help).\n",
190429088Smarkm    				argv[1]);
190529088Smarkm	return 0;
190629088Smarkm    }
190729088Smarkm    if (c->narg + 2 != argc) {
190829088Smarkm	fprintf(stderr,
190929088Smarkm	    "Need %s%d argument%s to 'auth %s' command.  'auth ?' for help.\n",
191029088Smarkm		c->narg < argc + 2 ? "only " : "",
191129088Smarkm		c->narg, c->narg == 1 ? "" : "s", c->name);
191229088Smarkm	return 0;
191329088Smarkm    }
191487139Smarkm    return((*c->handler)(argv[2]));
191529088Smarkm}
191629088Smarkm#endif
191729088Smarkm
191829088Smarkm#ifdef	ENCRYPTION
191929088Smarkm/*
192029088Smarkm * The ENCRYPT command.
192129088Smarkm */
192229088Smarkm
192329088Smarkmstruct encryptlist {
192487139Smarkm	const char	*name;
192587139Smarkm	const char	*help;
192687139Smarkm	int	(*handler)(char *, char *);
192729088Smarkm	int	needconnect;
192829088Smarkm	int	minarg;
192929088Smarkm	int	maxarg;
193029088Smarkm};
193129088Smarkm
193229088Smarkmextern int
193387155Smarkm	EncryptEnable(char *, char *),
193487155Smarkm	EncryptDisable(char *, char *),
193587155Smarkm	EncryptType(char *, char *),
193687155Smarkm	EncryptStart(char *),
193787155Smarkm	EncryptStartInput(void),
193887155Smarkm	EncryptStartOutput(void),
193987155Smarkm	EncryptStop(char *),
194087155Smarkm	EncryptStopInput(void),
194187155Smarkm	EncryptStopOutput(void),
194287155Smarkm	EncryptStatus(void);
194329088Smarkmstatic int
194487155Smarkm	EncryptHelp(void);
194529088Smarkm
194629088Smarkmstruct encryptlist EncryptList[] = {
194729088Smarkm    { "enable", "Enable encryption. ('encrypt enable ?' for more)",
194829088Smarkm						EncryptEnable, 1, 1, 2 },
194929088Smarkm    { "disable", "Disable encryption. ('encrypt enable ?' for more)",
195029088Smarkm						EncryptDisable, 0, 1, 2 },
195129088Smarkm    { "type", "Set encryption type. ('encrypt type ?' for more)",
195229088Smarkm						EncryptType, 0, 1, 1 },
195329088Smarkm    { "start", "Start encryption. ('encrypt start ?' for more)",
195487139Smarkm						(int (*)(char *, char *))EncryptStart, 1, 0, 1 },
195529088Smarkm    { "stop", "Stop encryption. ('encrypt stop ?' for more)",
195687139Smarkm						(int (*)(char *, char *))EncryptStop, 1, 0, 1 },
195729088Smarkm    { "input", "Start encrypting the input stream",
195887139Smarkm						(int (*)(char *, char *))EncryptStartInput, 1, 0, 0 },
195929088Smarkm    { "-input", "Stop encrypting the input stream",
196087139Smarkm						(int (*)(char *, char *))EncryptStopInput, 1, 0, 0 },
196129088Smarkm    { "output", "Start encrypting the output stream",
196287139Smarkm						(int (*)(char *, char *))EncryptStartOutput, 1, 0, 0 },
196329088Smarkm    { "-output", "Stop encrypting the output stream",
196487139Smarkm						(int (*)(char *, char *))EncryptStopOutput, 1, 0, 0 },
196529088Smarkm
196629088Smarkm    { "status",	"Display current status of authentication information",
196787139Smarkm						(int (*)(char *, char *))EncryptStatus,	0, 0, 0 },
196887139Smarkm    { "help",	NULL,				(int (*)(char *, char *))EncryptHelp,	0, 0, 0 },
196987139Smarkm    { "?",	"Print help information",	(int (*)(char *, char *))EncryptHelp,	0, 0, 0 },
197087139Smarkm    { NULL, NULL, NULL, 0, 0, 0 },
197129088Smarkm};
197229088Smarkm
197387139Smarkmstatic int
197487139SmarkmEncryptHelp(void)
197529088Smarkm{
197629088Smarkm    struct encryptlist *c;
197729088Smarkm
197829088Smarkm    for (c = EncryptList; c->name; c++) {
197929088Smarkm	if (c->help) {
198029088Smarkm	    if (*c->help)
198129088Smarkm		printf("%-15s %s\n", c->name, c->help);
198229088Smarkm	    else
198329088Smarkm		printf("\n");
198429088Smarkm	}
198529088Smarkm    }
198629088Smarkm    return 0;
198729088Smarkm}
198829088Smarkm
198987139Smarkmstatic int
199087139Smarkmencrypt_cmd(int argc, char *argv[])
199129088Smarkm{
199229088Smarkm    struct encryptlist *c;
199329088Smarkm
199429088Smarkm    if (argc < 2) {
199529088Smarkm	fprintf(stderr,
199629088Smarkm	    "Need an argument to 'encrypt' command.  'encrypt ?' for help.\n");
199729088Smarkm	return 0;
199829088Smarkm    }
199929088Smarkm
200029088Smarkm    c = (struct encryptlist *)
200129088Smarkm		genget(argv[1], (char **) EncryptList, sizeof(struct encryptlist));
200229088Smarkm    if (c == 0) {
200329088Smarkm	fprintf(stderr, "'%s': unknown argument ('encrypt ?' for help).\n",
200429088Smarkm    				argv[1]);
200529088Smarkm	return 0;
200629088Smarkm    }
200787139Smarkm    if (Ambiguous((void *)c)) {
200829088Smarkm	fprintf(stderr, "'%s': ambiguous argument ('encrypt ?' for help).\n",
200929088Smarkm    				argv[1]);
201029088Smarkm	return 0;
201129088Smarkm    }
201229088Smarkm    argc -= 2;
201329088Smarkm    if (argc < c->minarg || argc > c->maxarg) {
201429088Smarkm	if (c->minarg == c->maxarg) {
201529088Smarkm	    fprintf(stderr, "Need %s%d argument%s ",
201629088Smarkm		c->minarg < argc ? "only " : "", c->minarg,
201729088Smarkm		c->minarg == 1 ? "" : "s");
201829088Smarkm	} else {
201929088Smarkm	    fprintf(stderr, "Need %s%d-%d arguments ",
202029088Smarkm		c->maxarg < argc ? "only " : "", c->minarg, c->maxarg);
202129088Smarkm	}
202229088Smarkm	fprintf(stderr, "to 'encrypt %s' command.  'encrypt ?' for help.\n",
202329088Smarkm		c->name);
202429088Smarkm	return 0;
202529088Smarkm    }
202629088Smarkm    if (c->needconnect && !connected) {
202729088Smarkm	if (!(argc && (isprefix(argv[2], "help") || isprefix(argv[2], "?")))) {
202829088Smarkm	    printf("?Need to be connected first.\n");
202929088Smarkm	    return 0;
203029088Smarkm	}
203129088Smarkm    }
203229088Smarkm    return ((*c->handler)(argc > 0 ? argv[2] : 0,
203387139Smarkm			argc > 1 ? argv[3] : 0));
203429088Smarkm}
203529088Smarkm#endif	/* ENCRYPTION */
203629088Smarkm
203729088Smarkm/*
203829088Smarkm * Print status about the connection.
203929088Smarkm */
204087139Smarkm/*ARGSUSED*/
204187139Smarkmstatic int
204287139Smarkmstatus(int argc, char *argv[])
204329088Smarkm{
204429088Smarkm    if (connected) {
204529088Smarkm	printf("Connected to %s.\n", hostname);
204629088Smarkm	if ((argc < 2) || strcmp(argv[1], "notmuch")) {
204729088Smarkm	    int mode = getconnmode();
204829088Smarkm
204929088Smarkm	    if (my_want_state_is_will(TELOPT_LINEMODE)) {
205029088Smarkm		printf("Operating with LINEMODE option\n");
205129088Smarkm		printf("%s line editing\n", (mode&MODE_EDIT) ? "Local" : "No");
205229088Smarkm		printf("%s catching of signals\n",
205329088Smarkm					(mode&MODE_TRAPSIG) ? "Local" : "No");
205429088Smarkm		slcstate();
205529088Smarkm#ifdef	KLUDGELINEMODE
205629088Smarkm	    } else if (kludgelinemode && my_want_state_is_dont(TELOPT_SGA)) {
205729088Smarkm		printf("Operating in obsolete linemode\n");
205829088Smarkm#endif
205929088Smarkm	    } else {
206029088Smarkm		printf("Operating in single character mode\n");
206129088Smarkm		if (localchars)
206229088Smarkm		    printf("Catching signals locally\n");
206329088Smarkm	    }
206429088Smarkm	    printf("%s character echo\n", (mode&MODE_ECHO) ? "Local" : "Remote");
206529088Smarkm	    if (my_want_state_is_will(TELOPT_LFLOW))
206629088Smarkm		printf("%s flow control\n", (mode&MODE_FLOW) ? "Local" : "No");
206729088Smarkm#ifdef	ENCRYPTION
206829088Smarkm	    encrypt_display();
206929088Smarkm#endif	/* ENCRYPTION */
207029088Smarkm	}
207129088Smarkm    } else {
207229088Smarkm	printf("No connection.\n");
207329088Smarkm    }
207429088Smarkm    printf("Escape character is '%s'.\n", control(escape));
207529088Smarkm    (void) fflush(stdout);
207629088Smarkm    return 1;
207729088Smarkm}
207829088Smarkm
207929088Smarkm#ifdef	SIGINFO
208029088Smarkm/*
208129088Smarkm * Function that gets called when SIGINFO is received.
208229088Smarkm */
208387139Smarkmvoid
208487139Smarkmayt_status(void)
208529088Smarkm{
208629088Smarkm    (void) call(status, "status", "notmuch", 0);
208729088Smarkm}
208829088Smarkm#endif
208929088Smarkm
209056668Sshinstatic const char *
209187139Smarkmsockaddr_ntop(struct sockaddr *sa)
209256668Sshin{
209356668Sshin    void *addr;
209456668Sshin    static char addrbuf[INET6_ADDRSTRLEN];
209529088Smarkm
209656668Sshin    switch (sa->sa_family) {
209756668Sshin    case AF_INET:
209856668Sshin	addr = &((struct sockaddr_in *)sa)->sin_addr;
209956668Sshin	break;
210077095Sdillon    case AF_UNIX:
210177095Sdillon	addr = &((struct sockaddr_un *)sa)->sun_path;
210277095Sdillon	break;
210356668Sshin#ifdef INET6
210456668Sshin    case AF_INET6:
210556668Sshin	addr = &((struct sockaddr_in6 *)sa)->sin6_addr;
210656668Sshin	break;
210756668Sshin#endif
210856668Sshin    default:
210956668Sshin	return NULL;
211056668Sshin    }
211156668Sshin    inet_ntop(sa->sa_family, addr, addrbuf, sizeof(addrbuf));
211256668Sshin    return addrbuf;
211356668Sshin}
211456668Sshin
211556668Sshin#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
211656668Sshinstatic int
211787139Smarkmsetpolicy(int lnet, struct addrinfo *res, char *policy)
211856668Sshin{
211956668Sshin	char *buf;
212056668Sshin	int level;
212156668Sshin	int optname;
212256668Sshin
212356668Sshin	if (policy == NULL)
212456668Sshin		return 0;
212556668Sshin
212656668Sshin	buf = ipsec_set_policy(policy, strlen(policy));
212756668Sshin	if (buf == NULL) {
212856668Sshin		printf("%s\n", ipsec_strerror());
212956668Sshin		return -1;
213056668Sshin	}
213156668Sshin	level = res->ai_family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6;
213256668Sshin	optname = res->ai_family == AF_INET ? IP_IPSEC_POLICY : IPV6_IPSEC_POLICY;
213387139Smarkm	if (setsockopt(lnet, level, optname, buf, ipsec_get_policylen(buf)) < 0){
213456668Sshin		perror("setsockopt");
213556668Sshin		return -1;
213656668Sshin	}
213756668Sshin
213856668Sshin	free(buf);
213987139Smarkm	return 0;
214056668Sshin}
214156668Sshin#endif
214256668Sshin
214357125Sshin#ifdef INET6
214457125Sshin/*
214557125Sshin * When an Address Family related error happend, check if retry with
214657125Sshin * another AF is possible or not.
214757125Sshin * Return 1, if retry with another af is OK. Else, return 0.
214857125Sshin */
214957125Sshinstatic int
215087139Smarkmswitch_af(struct addrinfo **aip)
215157125Sshin{
215257125Sshin    int nextaf;
215357125Sshin    struct addrinfo *ai;
215457125Sshin
215557125Sshin    ai = *aip;
215657125Sshin    nextaf = (ai->ai_family == AF_INET) ? AF_INET6 : AF_INET;
215757125Sshin    do
215857125Sshin        ai=ai->ai_next;
215957125Sshin    while (ai != NULL && ai->ai_family != nextaf);
216057125Sshin    *aip = ai;
216157125Sshin    if (*aip != NULL) {
216257125Sshin        return 1;
216357125Sshin    }
216457125Sshin    return 0;
216557125Sshin}
216657125Sshin#endif
216757125Sshin
216887139Smarkmint
216987139Smarkmtn(int argc, char *argv[])
217029088Smarkm{
2171305552Sdim    unsigned char *srp = 0;
217256668Sshin    int proto, opt;
217387139Smarkm    int srlen;
217456668Sshin    int srcroute = 0, result;
217529088Smarkm    char *cmd, *hostp = 0, *portp = 0, *user = 0;
217647973Sru    char *src_addr = NULL;
217757125Sshin    struct addrinfo hints, *res, *res0 = NULL, *src_res, *src_res0 = NULL;
217857125Sshin    int error = 0, af_error = 0;
217929088Smarkm
218029088Smarkm    if (connected) {
218129088Smarkm	printf("?Already connected to %s\n", hostname);
218229088Smarkm	setuid(getuid());
218329088Smarkm	return 0;
218429088Smarkm    }
218529088Smarkm    if (argc < 2) {
218629088Smarkm	(void) strcpy(line, "open ");
218729088Smarkm	printf("(to) ");
218829088Smarkm	(void) fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin);
218929088Smarkm	makeargv();
219029088Smarkm	argc = margc;
219129088Smarkm	argv = margv;
219229088Smarkm    }
219329088Smarkm    cmd = *argv;
219429088Smarkm    --argc; ++argv;
219529088Smarkm    while (argc) {
219629088Smarkm	if (strcmp(*argv, "help") == 0 || isprefix(*argv, "?"))
219729088Smarkm	    goto usage;
219829088Smarkm	if (strcmp(*argv, "-l") == 0) {
219929088Smarkm	    --argc; ++argv;
220029088Smarkm	    if (argc == 0)
220129088Smarkm		goto usage;
220229088Smarkm	    user = *argv++;
220329088Smarkm	    --argc;
220429088Smarkm	    continue;
220529088Smarkm	}
220629088Smarkm	if (strcmp(*argv, "-a") == 0) {
220729088Smarkm	    --argc; ++argv;
220829088Smarkm	    autologin = 1;
220929088Smarkm	    continue;
221029088Smarkm	}
221147973Sru	if (strcmp(*argv, "-s") == 0) {
221247973Sru	    --argc; ++argv;
221347973Sru	    if (argc == 0)
221447973Sru		goto usage;
221547973Sru	    src_addr = *argv++;
221647973Sru	    --argc;
221747973Sru	    continue;
221847973Sru	}
221929088Smarkm	if (hostp == 0) {
222029088Smarkm	    hostp = *argv++;
222129088Smarkm	    --argc;
222229088Smarkm	    continue;
222329088Smarkm	}
222429088Smarkm	if (portp == 0) {
222529088Smarkm	    portp = *argv++;
222629088Smarkm	    --argc;
222729088Smarkm	    continue;
222829088Smarkm	}
222929088Smarkm    usage:
223047973Sru	printf("usage: %s [-l user] [-a] [-s src_addr] host-name [port]\n", cmd);
223129088Smarkm	setuid(getuid());
223229088Smarkm	return 0;
223329088Smarkm    }
223429088Smarkm    if (hostp == 0)
223529088Smarkm	goto usage;
223629088Smarkm
223747973Sru    if (src_addr != NULL) {
223856668Sshin	memset(&hints, 0, sizeof(hints));
223956668Sshin	hints.ai_family = family;
224056668Sshin	hints.ai_socktype = SOCK_STREAM;
224157125Sshin	error = getaddrinfo(src_addr, 0, &hints, &src_res);
2242121425Sume	if (error == EAI_NONAME) {
224356668Sshin		hints.ai_flags = 0;
224457125Sshin		error = getaddrinfo(src_addr, 0, &hints, &src_res);
224556668Sshin	}
224656668Sshin	if (error != 0) {
224756668Sshin		fprintf(stderr, "%s: %s\n", src_addr, gai_strerror(error));
224856668Sshin		if (error == EAI_SYSTEM)
224956668Sshin			fprintf(stderr, "%s: %s\n", src_addr, strerror(errno));
225057125Sshin		setuid(getuid());
225147973Sru		return 0;
225247973Sru	}
225357125Sshin	src_res0 = src_res;
225447973Sru    }
225577095Sdillon    if (hostp[0] == '/') {
225677095Sdillon	struct sockaddr_un su;
225777095Sdillon
225877095Sdillon	if (strlen(hostp) >= sizeof(su.sun_path)) {
225977095Sdillon	    fprintf(stderr, "hostname too long for unix domain socket: %s",
226077095Sdillon		    hostp);
226177095Sdillon		goto fail;
226277095Sdillon	}
2263139687Smaxim	hostname = hostp;
226477095Sdillon	memset(&su, 0, sizeof su);
226577095Sdillon	su.sun_family = AF_UNIX;
226677095Sdillon	strncpy(su.sun_path, hostp, sizeof su.sun_path);
226787139Smarkm	printf("Trying %s...\n", hostp);
226877095Sdillon	net = socket(PF_UNIX, SOCK_STREAM, 0);
226977095Sdillon	if ( net < 0) {
227077095Sdillon	    perror("socket");
227177095Sdillon	    goto fail;
227277095Sdillon	}
227377095Sdillon	if (connect(net, (struct sockaddr *)&su, sizeof su) == -1) {
227477095Sdillon	    perror(su.sun_path);
227577095Sdillon	    (void) NetClose(net);
227677095Sdillon	    goto fail;
227777095Sdillon	}
227877095Sdillon	goto af_unix;
227977095Sdillon    } else if (hostp[0] == '@' || hostp[0] == '!') {
228056668Sshin	if (
228156668Sshin#ifdef INET6
228256668Sshin	    family == AF_INET6 ||
228356668Sshin#endif
228456668Sshin	    (hostname = strrchr(hostp, ':')) == NULL)
228529088Smarkm	    hostname = strrchr(hostp, '@');
2286107299Seric	if (hostname == NULL) {
2287107299Seric	    hostname = hostp;
2288107299Seric	} else {
2289107299Seric	    hostname++;
2290107299Seric	    srcroute = 1;
2291107299Seric	}
229256668Sshin    } else
229356668Sshin        hostname = hostp;
229456668Sshin    if (!portp) {
229556668Sshin      telnetport = 1;
229687139Smarkm      portp = strdup("telnet");
229756668Sshin    } else if (*portp == '-') {
229856668Sshin      portp++;
229956668Sshin      telnetport = 1;
2300142790Stobez    } else if (*portp == '+') {
2301142790Stobez      portp++;
2302142790Stobez      telnetport = -1;
230356668Sshin    } else
230456668Sshin      telnetport = 0;
230556668Sshin
230656668Sshin    memset(&hints, 0, sizeof(hints));
230756668Sshin    hints.ai_flags = AI_NUMERICHOST;
230856668Sshin    hints.ai_family = family;
230956668Sshin    hints.ai_socktype = SOCK_STREAM;
231056668Sshin    error = getaddrinfo(hostname, portp, &hints, &res);
231162773Sitojun    if (error) {
231262773Sitojun        hints.ai_flags = AI_CANONNAME;
231362773Sitojun	error = getaddrinfo(hostname, portp, &hints, &res);
231462773Sitojun    }
231562773Sitojun    if (error != 0) {
231662773Sitojun	fprintf(stderr, "%s: %s\n", hostname, gai_strerror(error));
231762773Sitojun	if (error == EAI_SYSTEM)
231862773Sitojun	    fprintf(stderr, "%s: %s\n", hostname, strerror(errno));
231962773Sitojun	setuid(getuid());
232062773Sitojun	goto fail;
232162773Sitojun    }
232262773Sitojun    if (hints.ai_flags == AI_NUMERICHOST) {
232362773Sitojun	/* hostname has numeric */
232456668Sshin        int gni_err = 1;
232556668Sshin
232656668Sshin	if (doaddrlookup)
232756668Sshin	    gni_err = getnameinfo(res->ai_addr, res->ai_addr->sa_len,
232856668Sshin				  _hostname, sizeof(_hostname) - 1, NULL, 0,
232956870Sshin				  NI_NAMEREQD);
233056668Sshin	if (gni_err != 0)
233162773Sitojun	    (void) strncpy(_hostname, hostp, sizeof(_hostname) - 1);
233256668Sshin	_hostname[sizeof(_hostname)-1] = '\0';
233356668Sshin	hostname = _hostname;
233462773Sitojun    } else {
233562773Sitojun	/* hostname has FQDN */
233656668Sshin	if (srcroute != 0)
233756668Sshin	    (void) strncpy(_hostname, hostname, sizeof(_hostname) - 1);
233856668Sshin	else if (res->ai_canonname != NULL)
233956668Sshin	  strcpy(_hostname, res->ai_canonname);
234056668Sshin	else
234156668Sshin	  (void) strncpy(_hostname, hostp, sizeof(_hostname) - 1);
234256668Sshin	_hostname[sizeof(_hostname)-1] = '\0';
234356668Sshin	hostname = _hostname;
234456668Sshin    }
234557125Sshin    res0 = res;
234687277Sjhay #ifdef INET6
234757233Sshin af_again:
234887277Sjhay #endif
234956668Sshin    if (srcroute != 0) {
235057343Sshin        static char hostbuf[BUFSIZ];
235157125Sshin
235257233Sshin	if (af_error == 0) { /* save intermediate hostnames for retry */
235357233Sshin		strncpy(hostbuf, hostp, BUFSIZ - 1);
235457233Sshin		hostbuf[BUFSIZ - 1] = '\0';
235557233Sshin	} else
235657125Sshin		hostp = hostbuf;
235729088Smarkm	srp = 0;
235856668Sshin	result = sourceroute(res, hostp, &srp, &srlen, &proto, &opt);
235956668Sshin	if (result == 0) {
236057125Sshin#ifdef INET6
236157125Sshin	    if (family == AF_UNSPEC && af_error == 0 &&
236257125Sshin		switch_af(&res) == 1) {
236357125Sshin	        af_error = 1;
236457125Sshin		goto af_again;
236557125Sshin	    }
236657125Sshin#endif
236729088Smarkm	    setuid(getuid());
236857125Sshin	    goto fail;
236956668Sshin	} else if (result == -1) {
237029088Smarkm	    printf("Bad source route option: %s\n", hostp);
237129088Smarkm	    setuid(getuid());
237257125Sshin	    goto fail;
237329088Smarkm	}
237429088Smarkm    }
237529088Smarkm    do {
237657342Sshin        printf("Trying %s...\n", sockaddr_ntop(res->ai_addr));
237756668Sshin	net = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
237829088Smarkm	setuid(getuid());
237929088Smarkm	if (net < 0) {
238057125Sshin#ifdef INET6
238157125Sshin	    if (family == AF_UNSPEC && af_error == 0 &&
238257125Sshin		switch_af(&res) == 1) {
238357125Sshin	        af_error = 1;
238457125Sshin		goto af_again;
238557125Sshin	    }
238657125Sshin#endif
238729088Smarkm	    perror("telnet: socket");
238857125Sshin	    goto fail;
238929088Smarkm	}
239056668Sshin	if (srp && setsockopt(net, proto, opt, (char *)srp, srlen) < 0)
239156668Sshin		perror("setsockopt (source route)");
239229088Smarkm#if	defined(IPPROTO_IP) && defined(IP_TOS)
239356668Sshin	if (res->ai_family == PF_INET) {
239429088Smarkm# if	defined(HAS_GETTOS)
239529088Smarkm	    struct tosent *tp;
239629088Smarkm	    if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
239729088Smarkm		tos = tp->t_tos;
239829088Smarkm# endif
239929088Smarkm	    if (tos < 0)
240081965Smarkm		tos = IPTOS_LOWDELAY;
240129088Smarkm	    if (tos
240229088Smarkm		&& (setsockopt(net, IPPROTO_IP, IP_TOS,
240329088Smarkm		    (char *)&tos, sizeof(int)) < 0)
240429088Smarkm		&& (errno != ENOPROTOOPT))
240529088Smarkm		    perror("telnet: setsockopt (IP_TOS) (ignored)");
240629088Smarkm	}
240729088Smarkm#endif	/* defined(IPPROTO_IP) && defined(IP_TOS) */
240829088Smarkm
2409114911Smarkm	if (telnet_debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) {
241029088Smarkm		perror("setsockopt (SO_DEBUG)");
241129088Smarkm	}
241229088Smarkm
241347973Sru	if (src_addr != NULL) {
241457125Sshin	    for (src_res = src_res0; src_res != 0; src_res = src_res->ai_next)
241557233Sshin	        if (src_res->ai_family == res->ai_family)
241657233Sshin		    break;
241757125Sshin	    if (src_res == NULL)
241857125Sshin		src_res = src_res0;
241957125Sshin	    if (bind(net, src_res->ai_addr, src_res->ai_addrlen) == -1) {
242057125Sshin#ifdef INET6
242157125Sshin	        if (family == AF_UNSPEC && af_error == 0 &&
242257125Sshin		    switch_af(&res) == 1) {
242357125Sshin		    af_error = 1;
242457233Sshin		    (void) NetClose(net);
242557125Sshin		    goto af_again;
242657125Sshin		}
242757125Sshin#endif
242847973Sru		perror("bind");
242957233Sshin		(void) NetClose(net);
243057125Sshin		goto fail;
243147973Sru	    }
243247973Sru	}
243356668Sshin#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
243457233Sshin	if (setpolicy(net, res, ipsec_policy_in) < 0) {
243557233Sshin		(void) NetClose(net);
243657125Sshin		goto fail;
243757233Sshin	}
243857233Sshin	if (setpolicy(net, res, ipsec_policy_out) < 0) {
243957233Sshin		(void) NetClose(net);
244057125Sshin		goto fail;
244157233Sshin	}
244256668Sshin#endif
244347973Sru
244456668Sshin	if (connect(net, res->ai_addr, res->ai_addrlen) < 0) {
244557125Sshin	    struct addrinfo *next;
244657125Sshin
244757125Sshin	    next = res->ai_next;
244857125Sshin	    /* If already an af failed, only try same af. */
244957125Sshin	    if (af_error != 0)
245057125Sshin		while (next != NULL && next->ai_family != res->ai_family)
245157125Sshin		    next = next->ai_next;
245257342Sshin	    warn("connect to address %s", sockaddr_ntop(res->ai_addr));
245357125Sshin	    if (next != NULL) {
245457125Sshin		res = next;
245529088Smarkm		(void) NetClose(net);
245629088Smarkm		continue;
245729088Smarkm	    }
245857342Sshin	    warnx("Unable to connect to remote host");
245957233Sshin	    (void) NetClose(net);
246057125Sshin	    goto fail;
246129088Smarkm	}
246229088Smarkm	connected++;
246387139Smarkm#ifdef	AUTHENTICATION
246487139Smarkm#ifdef	ENCRYPTION
246529088Smarkm	auth_encrypt_connect(connected);
246687139Smarkm#endif
246787139Smarkm#endif
246829088Smarkm    } while (connected == 0);
246957125Sshin    freeaddrinfo(res0);
247057125Sshin    if (src_res0 != NULL)
247157125Sshin        freeaddrinfo(src_res0);
247229088Smarkm    cmdrc(hostp, hostname);
247377095Sdillon af_unix:
2474139687Smaxim    connected = 1;
247529088Smarkm    if (autologin && user == NULL) {
247629088Smarkm	struct passwd *pw;
247729088Smarkm
247829088Smarkm	user = getenv("USER");
247929088Smarkm	if (user == NULL ||
248029181Smarkm	    ((pw = getpwnam(user)) && pw->pw_uid != getuid())) {
248129181Smarkm		if ((pw = getpwuid(getuid())))
248229088Smarkm			user = pw->pw_name;
248329088Smarkm		else
248429088Smarkm			user = NULL;
248529088Smarkm	}
248629088Smarkm    }
248729088Smarkm    if (user) {
248887139Smarkm	env_define("USER", user);
248987139Smarkm	env_export("USER");
249029088Smarkm    }
249129088Smarkm    (void) call(status, "status", "notmuch", 0);
2492207449Sjilles    telnet(user);
249329088Smarkm    (void) NetClose(net);
249429088Smarkm    ExitString("Connection closed by foreign host.\n",1);
249529088Smarkm    /*NOTREACHED*/
249657125Sshin fail:
249757125Sshin    if (res0 != NULL)
249857125Sshin        freeaddrinfo(res0);
249957125Sshin    if (src_res0 != NULL)
250057125Sshin        freeaddrinfo(src_res0);
250157125Sshin    return 0;
250229088Smarkm}
250329088Smarkm
250429088Smarkm#define HELPINDENT (sizeof ("connect"))
250529088Smarkm
250629088Smarkmstatic char
250729088Smarkm	openhelp[] =	"connect to a site",
250829088Smarkm	closehelp[] =	"close current connection",
250929088Smarkm	logouthelp[] =	"forcibly logout remote user and close the connection",
251029088Smarkm	quithelp[] =	"exit telnet",
251129088Smarkm	statushelp[] =	"print status information",
251229088Smarkm	helphelp[] =	"print help information",
251329088Smarkm	sendhelp[] =	"transmit special characters ('send ?' for more)",
251429088Smarkm	sethelp[] = 	"set operating parameters ('set ?' for more)",
251529088Smarkm	unsethelp[] = 	"unset operating parameters ('unset ?' for more)",
251629088Smarkm	togglestring[] ="toggle operating parameters ('toggle ?' for more)",
251729088Smarkm	slchelp[] =	"change state of special charaters ('slc ?' for more)",
251829088Smarkm	displayhelp[] =	"display operating parameters",
251987139Smarkm#ifdef	AUTHENTICATION
252029088Smarkm	authhelp[] =	"turn on (off) authentication ('auth ?' for more)",
252129088Smarkm#endif
252229088Smarkm#ifdef	ENCRYPTION
252329088Smarkm	encrypthelp[] =	"turn on (off) encryption ('encrypt ?' for more)",
252429088Smarkm#endif	/* ENCRYPTION */
252529088Smarkm	zhelp[] =	"suspend telnet",
252687139Smarkm#ifdef OPIE
252781965Smarkm	opiehelp[] =    "compute response to OPIE challenge",
252829181Smarkm#endif
252929088Smarkm	shellhelp[] =	"invoke a subshell",
253029088Smarkm	envhelp[] =	"change environment variables ('environ ?' for more)",
253129088Smarkm	modestring[] = "try to enter line or character mode ('mode ?' for more)";
253229088Smarkm
253329088Smarkmstatic Command cmdtab[] = {
253429088Smarkm	{ "close",	closehelp,	bye,		1 },
253587139Smarkm	{ "logout",	logouthelp,	(int (*)(int, char **))logout,		1 },
253629088Smarkm	{ "display",	displayhelp,	display,	0 },
253729088Smarkm	{ "mode",	modestring,	modecmd,	0 },
253881965Smarkm	{ "telnet",	openhelp,	tn,		0 },
253929088Smarkm	{ "open",	openhelp,	tn,		0 },
254087139Smarkm	{ "quit",	quithelp,	(int (*)(int, char **))quit,		0 },
254129088Smarkm	{ "send",	sendhelp,	sendcmd,	0 },
254229088Smarkm	{ "set",	sethelp,	setcmd,		0 },
254329088Smarkm	{ "unset",	unsethelp,	unsetcmd,	0 },
254429088Smarkm	{ "status",	statushelp,	status,		0 },
254529088Smarkm	{ "toggle",	togglestring,	toggle,		0 },
254629088Smarkm	{ "slc",	slchelp,	slccmd,		0 },
254787139Smarkm#ifdef	AUTHENTICATION
254829088Smarkm	{ "auth",	authhelp,	auth_cmd,	0 },
254929088Smarkm#endif
255029088Smarkm#ifdef	ENCRYPTION
255129088Smarkm	{ "encrypt",	encrypthelp,	encrypt_cmd,	0 },
255229088Smarkm#endif	/* ENCRYPTION */
255387139Smarkm	{ "z",		zhelp,		(int (*)(int, char **))suspend,	0 },
255429088Smarkm	{ "!",		shellhelp,	shell,		1 },
255529088Smarkm	{ "environ",	envhelp,	env_cmd,	0 },
255629088Smarkm	{ "?",		helphelp,	help,		0 },
255787139Smarkm#ifdef OPIE
255881965Smarkm	{ "opie",       opiehelp,       opie_calc,      0 },
255929181Smarkm#endif
256087139Smarkm	{ NULL, NULL, NULL, 0 }
256129088Smarkm};
256229088Smarkm
256329088Smarkmstatic char	crmodhelp[] =	"deprecated command -- use 'toggle crmod' instead";
256429088Smarkmstatic char	escapehelp[] =	"deprecated command -- use 'set escape' instead";
256529088Smarkm
256629088Smarkmstatic Command cmdtab2[] = {
256729088Smarkm	{ "help",	0,		help,		0 },
256829088Smarkm	{ "escape",	escapehelp,	setescape,	0 },
256987139Smarkm	{ "crmod",	crmodhelp,	(int (*)(int, char **))togcrmod,	0 },
257087139Smarkm	{ NULL, NULL, NULL, 0 }
257129088Smarkm};
257229088Smarkm
257329088Smarkm
257429088Smarkm/*
257529088Smarkm * Call routine with argc, argv set from args (terminated by 0).
257629088Smarkm */
257729088Smarkm
257887139Smarkmstatic int
257987139Smarkmcall(intrtn_t routine, ...)
258029088Smarkm{
258129088Smarkm    va_list ap;
258229088Smarkm    char *args[100];
258329088Smarkm    int argno = 0;
258429088Smarkm
258587139Smarkm    va_start(ap, routine);
258687139Smarkm    while ((args[argno++] = va_arg(ap, char *)) != 0);
258729088Smarkm    va_end(ap);
258829088Smarkm    return (*routine)(argno-1, args);
258929088Smarkm}
259029088Smarkm
259129088Smarkm
259287139Smarkmstatic Command *
259387139Smarkmgetcmd(char *name)
259429088Smarkm{
259529088Smarkm    Command *cm;
259629088Smarkm
259729181Smarkm    if ((cm = (Command *) genget(name, (char **) cmdtab, sizeof(Command))))
259829088Smarkm	return cm;
259929088Smarkm    return (Command *) genget(name, (char **) cmdtab2, sizeof(Command));
260029088Smarkm}
260129088Smarkm
260287139Smarkmvoid
260387139Smarkmcommand(int top, const char *tbuf, int cnt)
260429088Smarkm{
260587139Smarkm    Command *c;
260629088Smarkm
260729088Smarkm    setcommandmode();
260829088Smarkm    if (!top) {
260929088Smarkm	putchar('\n');
261029088Smarkm    } else {
261129088Smarkm	(void) signal(SIGINT, SIG_DFL);
261229088Smarkm	(void) signal(SIGQUIT, SIG_DFL);
261329088Smarkm    }
261429088Smarkm    for (;;) {
261529088Smarkm	if (rlogin == _POSIX_VDISABLE)
261629088Smarkm		printf("%s> ", prompt);
261729088Smarkm	if (tbuf) {
261887139Smarkm	    char *cp;
261929088Smarkm	    cp = line;
262029088Smarkm	    while (cnt > 0 && (*cp++ = *tbuf++) != '\n')
262129088Smarkm		cnt--;
262229088Smarkm	    tbuf = 0;
262329088Smarkm	    if (cp == line || *--cp != '\n' || cp == line)
262429088Smarkm		goto getline;
262529088Smarkm	    *cp = '\0';
262629088Smarkm	    if (rlogin == _POSIX_VDISABLE)
262729088Smarkm		printf("%s\n", line);
262829088Smarkm	} else {
262929088Smarkm	getline:
263029088Smarkm	    if (rlogin != _POSIX_VDISABLE)
263129088Smarkm		printf("%s> ", prompt);
263229088Smarkm	    if (fgets(line, sizeof(line), stdin) == NULL) {
263329088Smarkm		if (feof(stdin) || ferror(stdin)) {
263429088Smarkm		    (void) quit();
263529088Smarkm		    /*NOTREACHED*/
263629088Smarkm		}
263729088Smarkm		break;
263829088Smarkm	    }
263929088Smarkm	}
264029088Smarkm	if (line[0] == 0)
264129088Smarkm	    break;
264229088Smarkm	makeargv();
264329088Smarkm	if (margv[0] == 0) {
264429088Smarkm	    break;
264529088Smarkm	}
264629088Smarkm	c = getcmd(margv[0]);
264787139Smarkm	if (Ambiguous((void *)c)) {
264829088Smarkm	    printf("?Ambiguous command\n");
264929088Smarkm	    continue;
265029088Smarkm	}
265129088Smarkm	if (c == 0) {
265229088Smarkm	    printf("?Invalid command\n");
265329088Smarkm	    continue;
265429088Smarkm	}
265529088Smarkm	if (c->needconnect && !connected) {
265629088Smarkm	    printf("?Need to be connected first.\n");
265729088Smarkm	    continue;
265829088Smarkm	}
265929088Smarkm	if ((*c->handler)(margc, margv)) {
266029088Smarkm	    break;
266129088Smarkm	}
266229088Smarkm    }
266329088Smarkm    if (!top) {
266429088Smarkm	if (!connected) {
266529088Smarkm	    longjmp(toplevel, 1);
266629088Smarkm	    /*NOTREACHED*/
266729088Smarkm	}
266829088Smarkm	setconnmode(0);
266929088Smarkm    }
267029088Smarkm}
267129088Smarkm
267229088Smarkm/*
267329088Smarkm * Help command.
267429088Smarkm */
267587139Smarkmstatic int
267687139Smarkmhelp(int argc, char *argv[])
267729088Smarkm{
267887139Smarkm	Command *c;
267929088Smarkm
268029088Smarkm	if (argc == 1) {
268129088Smarkm		printf("Commands may be abbreviated.  Commands are:\n\n");
268229088Smarkm		for (c = cmdtab; c->name; c++)
268329088Smarkm			if (c->help) {
268487266Smarkm				printf("%-*s\t%s\n", (int)HELPINDENT, c->name,
268529088Smarkm								    c->help);
268629088Smarkm			}
268781965Smarkm		return 0;
268829088Smarkm	}
268929181Smarkm	else while (--argc > 0) {
269087139Smarkm		char *arg;
269129088Smarkm		arg = *++argv;
269229088Smarkm		c = getcmd(arg);
269387139Smarkm		if (Ambiguous((void *)c))
269429088Smarkm			printf("?Ambiguous help command %s\n", arg);
269529088Smarkm		else if (c == (Command *)0)
269629088Smarkm			printf("?Invalid help command %s\n", arg);
269729088Smarkm		else
269829088Smarkm			printf("%s\n", c->help);
269929088Smarkm	}
270081965Smarkm	return 0;
270129088Smarkm}
270229088Smarkm
270329088Smarkmstatic char *rcname = 0;
270429088Smarkmstatic char rcbuf[128];
270529088Smarkm
270687139Smarkmvoid
270787139Smarkmcmdrc(char *m1, char *m2)
270829088Smarkm{
270987139Smarkm    Command *c;
271029088Smarkm    FILE *rcfile;
271129088Smarkm    int gotmachine = 0;
271229088Smarkm    int l1 = strlen(m1);
271329088Smarkm    int l2 = strlen(m2);
271468891Skris    char m1save[MAXHOSTNAMELEN];
271529088Smarkm
271629088Smarkm    if (skiprc)
271729088Smarkm	return;
271829088Smarkm
271968891Skris    strlcpy(m1save, m1, sizeof(m1save));
272029088Smarkm    m1 = m1save;
272129088Smarkm
272229088Smarkm    if (rcname == 0) {
272329088Smarkm	rcname = getenv("HOME");
272429181Smarkm	if (rcname && (strlen(rcname) + 10) < sizeof(rcbuf))
272529088Smarkm	    strcpy(rcbuf, rcname);
272629088Smarkm	else
272729088Smarkm	    rcbuf[0] = '\0';
272829088Smarkm	strcat(rcbuf, "/.telnetrc");
272929088Smarkm	rcname = rcbuf;
273029088Smarkm    }
273129088Smarkm
273229088Smarkm    if ((rcfile = fopen(rcname, "r")) == 0) {
273329088Smarkm	return;
273429088Smarkm    }
273529088Smarkm
273629088Smarkm    for (;;) {
273729088Smarkm	if (fgets(line, sizeof(line), rcfile) == NULL)
273829088Smarkm	    break;
273929088Smarkm	if (line[0] == 0)
274029088Smarkm	    break;
274129088Smarkm	if (line[0] == '#')
274229088Smarkm	    continue;
274329088Smarkm	if (gotmachine) {
274429088Smarkm	    if (!isspace(line[0]))
274529088Smarkm		gotmachine = 0;
274629088Smarkm	}
274729088Smarkm	if (gotmachine == 0) {
274829088Smarkm	    if (isspace(line[0]))
274929088Smarkm		continue;
275029088Smarkm	    if (strncasecmp(line, m1, l1) == 0)
275129088Smarkm		strncpy(line, &line[l1], sizeof(line) - l1);
275229088Smarkm	    else if (strncasecmp(line, m2, l2) == 0)
275329088Smarkm		strncpy(line, &line[l2], sizeof(line) - l2);
275429088Smarkm	    else if (strncasecmp(line, "DEFAULT", 7) == 0)
275529088Smarkm		strncpy(line, &line[7], sizeof(line) - 7);
275629088Smarkm	    else
275729088Smarkm		continue;
275829088Smarkm	    if (line[0] != ' ' && line[0] != '\t' && line[0] != '\n')
275929088Smarkm		continue;
276029088Smarkm	    gotmachine = 1;
276129088Smarkm	}
276229088Smarkm	makeargv();
276329088Smarkm	if (margv[0] == 0)
276429088Smarkm	    continue;
276529088Smarkm	c = getcmd(margv[0]);
276687139Smarkm	if (Ambiguous((void *)c)) {
276729088Smarkm	    printf("?Ambiguous command: %s\n", margv[0]);
276829088Smarkm	    continue;
276929088Smarkm	}
277029088Smarkm	if (c == 0) {
277129088Smarkm	    printf("?Invalid command: %s\n", margv[0]);
277229088Smarkm	    continue;
277329088Smarkm	}
277429088Smarkm	/*
277529088Smarkm	 * This should never happen...
277629088Smarkm	 */
277729088Smarkm	if (c->needconnect && !connected) {
277829088Smarkm	    printf("?Need to be connected first for %s.\n", margv[0]);
277929088Smarkm	    continue;
278029088Smarkm	}
278129088Smarkm	(*c->handler)(margc, margv);
278229088Smarkm    }
278329088Smarkm    fclose(rcfile);
278429088Smarkm}
278529088Smarkm
278629088Smarkm/*
278729088Smarkm * Source route is handed in as
278829088Smarkm *	[!]@hop1@hop2...[@|:]dst
278929088Smarkm * If the leading ! is present, it is a
279029088Smarkm * strict source route, otherwise it is
279129088Smarkm * assmed to be a loose source route.
279229088Smarkm *
279329088Smarkm * We fill in the source route option as
279429088Smarkm *	hop1,hop2,hop3...dest
279529088Smarkm * and return a pointer to hop1, which will
279629088Smarkm * be the address to connect() to.
279729088Smarkm *
279829088Smarkm * Arguments:
279956668Sshin *
280056668Sshin *	res:	ponter to addrinfo structure which contains sockaddr to
280156668Sshin *		the host to connect to.
280256668Sshin *
280329088Smarkm *	arg:	pointer to route list to decipher
280429088Smarkm *
280529088Smarkm *	cpp: 	If *cpp is not equal to NULL, this is a
280629088Smarkm *		pointer to a pointer to a character array
280729088Smarkm *		that should be filled in with the option.
280829088Smarkm *
280929088Smarkm *	lenp:	pointer to an integer that contains the
281029088Smarkm *		length of *cpp if *cpp != NULL.
281129088Smarkm *
281256668Sshin *	protop:	pointer to an integer that should be filled in with
281356668Sshin *		appropriate protocol for setsockopt, as socket
281456668Sshin *		protocol family.
281556668Sshin *
281656668Sshin *	optp:	pointer to an integer that should be filled in with
281756668Sshin *		appropriate option for setsockopt, as socket protocol
281856668Sshin *		family.
281956668Sshin *
282029088Smarkm * Return values:
282129088Smarkm *
282256668Sshin *	If the return value is 1, then all operations are
282356668Sshin *	successful. If the
282429088Smarkm *	return value is -1, there was a syntax error in the
282529088Smarkm *	option, either unknown characters, or too many hosts.
282629088Smarkm *	If the return value is 0, one of the hostnames in the
282729088Smarkm *	path is unknown, and *cpp is set to point to the bad
282829088Smarkm *	hostname.
282929088Smarkm *
283029088Smarkm *	*cpp:	If *cpp was equal to NULL, it will be filled
283129088Smarkm *		in with a pointer to our static area that has
283229088Smarkm *		the option filled in.  This will be 32bit aligned.
283329088Smarkm *
283429088Smarkm *	*lenp:	This will be filled in with how long the option
283529088Smarkm *		pointed to by *cpp is.
283629088Smarkm *
283756668Sshin *	*protop: This will be filled in with appropriate protocol for
283856668Sshin *		 setsockopt, as socket protocol family.
283956668Sshin *
284056668Sshin *	*optp:	This will be filled in with appropriate option for
284156668Sshin *		setsockopt, as socket protocol family.
284229088Smarkm */
284387139Smarkmstatic int
2844305552Sdimsourceroute(struct addrinfo *ai, char *arg, unsigned char **cpp, int *lenp, int *protop, int *optp)
284529088Smarkm{
284663662Sume	static char buf[1024 + ALIGNBYTES];	/*XXX*/
2847305552Sdim	unsigned char *cp, *cp2, *lsrp, *ep;
284887139Smarkm	struct sockaddr_in *_sin;
284987277Sjhay#ifdef INET6
285056668Sshin	struct sockaddr_in6 *sin6;
2851121472Sume	struct ip6_rthdr *rth;
285287277Sjhay#endif
285356668Sshin	struct addrinfo hints, *res;
285456668Sshin	int error;
285587139Smarkm	char c;
285629088Smarkm
285729088Smarkm	/*
285829088Smarkm	 * Verify the arguments, and make sure we have
285929088Smarkm	 * at least 7 bytes for the option.
286029088Smarkm	 */
286129088Smarkm	if (cpp == NULL || lenp == NULL)
286257724Sshin		return -1;
286356668Sshin	if (*cpp != NULL) {
286456668Sshin		switch (res->ai_family) {
286556668Sshin		case AF_INET:
286656668Sshin			if (*lenp < 7)
286757724Sshin				return -1;
286856668Sshin			break;
286956668Sshin#ifdef INET6
287056668Sshin		case AF_INET6:
287187139Smarkm			if (*lenp < (int)CMSG_SPACE(sizeof(struct ip6_rthdr) +
287257724Sshin				               sizeof(struct in6_addr)))
287357724Sshin				return -1;
287456668Sshin			break;
287556668Sshin#endif
287656668Sshin		}
287756668Sshin	}
287829088Smarkm	/*
287929088Smarkm	 * Decide whether we have a buffer passed to us,
288029088Smarkm	 * or if we need to use our own static buffer.
288129088Smarkm	 */
288229088Smarkm	if (*cpp) {
288329088Smarkm		lsrp = *cpp;
288456668Sshin		ep = lsrp + *lenp;
288529088Smarkm	} else {
288663662Sume		*cpp = lsrp = (char *)ALIGN(buf);
288756668Sshin		ep = lsrp + 1024;
288829088Smarkm	}
288929088Smarkm
289029088Smarkm	cp = arg;
289129088Smarkm
289256668Sshin#ifdef INET6
289356668Sshin	if (ai->ai_family == AF_INET6) {
2894121472Sume		if ((rth = inet6_rth_init((void *)*cpp, sizeof(buf),
2895121472Sume					  IPV6_RTHDR_TYPE_0, 0)) == NULL)
2896121472Sume			return -1;
289756668Sshin		if (*cp != '@')
289856668Sshin			return -1;
289956668Sshin		*protop = IPPROTO_IPV6;
2900121472Sume		*optp = IPV6_RTHDR;
290156668Sshin	} else
290256668Sshin#endif
290356668Sshin      {
290429088Smarkm	/*
290529088Smarkm	 * Next, decide whether we have a loose source
290629088Smarkm	 * route or a strict source route, and fill in
290729088Smarkm	 * the begining of the option.
290829088Smarkm	 */
290929088Smarkm	if (*cp == '!') {
291029088Smarkm		cp++;
291129088Smarkm		*lsrp++ = IPOPT_SSRR;
291229088Smarkm	} else
291329088Smarkm		*lsrp++ = IPOPT_LSRR;
291429088Smarkm
291529088Smarkm	if (*cp != '@')
291657724Sshin		return -1;
291729088Smarkm
291829088Smarkm	lsrp++;		/* skip over length, we'll fill it in later */
291929088Smarkm	*lsrp++ = 4;
292056668Sshin	*protop = IPPROTO_IP;
292156668Sshin	*optp = IP_OPTIONS;
292256668Sshin      }
292329088Smarkm
292429088Smarkm	cp++;
292556668Sshin	memset(&hints, 0, sizeof(hints));
292656668Sshin	hints.ai_family = ai->ai_family;
292756668Sshin	hints.ai_socktype = SOCK_STREAM;
292829088Smarkm	for (c = 0;;) {
292956668Sshin		if (
293056668Sshin#ifdef INET6
293156668Sshin		    ai->ai_family != AF_INET6 &&
293256668Sshin#endif
293356668Sshin		    c == ':')
293429088Smarkm			cp2 = 0;
293529181Smarkm		else for (cp2 = cp; (c = *cp2); cp2++) {
293629088Smarkm			if (c == ',') {
293729088Smarkm				*cp2++ = '\0';
293829088Smarkm				if (*cp2 == '@')
293929088Smarkm					cp2++;
294029088Smarkm			} else if (c == '@') {
294129088Smarkm				*cp2++ = '\0';
294256668Sshin			} else if (
294356668Sshin#ifdef INET6
294456668Sshin				   ai->ai_family != AF_INET6 &&
294556668Sshin#endif
294656668Sshin				   c == ':') {
294729088Smarkm				*cp2++ = '\0';
294829088Smarkm			} else
294929088Smarkm				continue;
295029088Smarkm			break;
295129088Smarkm		}
295229088Smarkm		if (!c)
295329088Smarkm			cp2 = 0;
295429088Smarkm
295556668Sshin		hints.ai_flags = AI_NUMERICHOST;
295681965Smarkm		error = getaddrinfo(cp, NULL, &hints, &res);
2957121425Sume		if (error == EAI_NONAME) {
295856668Sshin			hints.ai_flags = 0;
295956668Sshin			error = getaddrinfo(cp, NULL, &hints, &res);
296056668Sshin		}
296156668Sshin		if (error != 0) {
296256668Sshin			fprintf(stderr, "%s: %s\n", cp, gai_strerror(error));
296356668Sshin			if (error == EAI_SYSTEM)
296456668Sshin				fprintf(stderr, "%s: %s\n", cp,
296556668Sshin					strerror(errno));
296629088Smarkm			*cpp = cp;
296729088Smarkm			return(0);
296829088Smarkm		}
296956668Sshin#ifdef INET6
297056668Sshin		if (res->ai_family == AF_INET6) {
297156668Sshin			sin6 = (struct sockaddr_in6 *)res->ai_addr;
2972121472Sume			if (inet6_rth_add((void *)rth, &sin6->sin6_addr) == -1)
2973121472Sume				return(0);
297456668Sshin		} else
297556668Sshin#endif
297656668Sshin	      {
297787139Smarkm		_sin = (struct sockaddr_in *)res->ai_addr;
297887139Smarkm		memcpy(lsrp, (char *)&_sin->sin_addr, 4);
297929088Smarkm		lsrp += 4;
298056668Sshin	      }
298129088Smarkm		if (cp2)
298229088Smarkm			cp = cp2;
298329088Smarkm		else
298429088Smarkm			break;
298529088Smarkm		/*
298629088Smarkm		 * Check to make sure there is space for next address
298729088Smarkm		 */
298856668Sshin		if (lsrp + 4 > ep)
298957724Sshin			return -1;
299056668Sshin		freeaddrinfo(res);
299129088Smarkm	}
299256668Sshin#ifdef INET6
299356668Sshin	if (res->ai_family == AF_INET6) {
2994121472Sume		rth->ip6r_len = rth->ip6r_segleft * 2;
2995121472Sume		*lenp = (rth->ip6r_len + 1) << 3;
299656668Sshin	} else
299756668Sshin#endif
299856668Sshin      {
299929088Smarkm	if ((*(*cpp+IPOPT_OLEN) = lsrp - *cpp) <= 7) {
300029088Smarkm		*cpp = 0;
300129088Smarkm		*lenp = 0;
300257724Sshin		return -1;
300329088Smarkm	}
300429088Smarkm	*lsrp++ = IPOPT_NOP; /* 32 bit word align it */
300529088Smarkm	*lenp = lsrp - *cpp;
300656668Sshin      }
300756668Sshin	freeaddrinfo(res);
300856668Sshin	return 1;
300929088Smarkm}
3010