commands.c revision 63662
129088Smarkm/*
229088Smarkm * Copyright (c) 1988, 1990, 1993
329088Smarkm *	The Regents of the University of California.  All rights reserved.
429088Smarkm *
529088Smarkm * Redistribution and use in source and binary forms, with or without
629088Smarkm * modification, are permitted provided that the following conditions
729088Smarkm * are met:
829088Smarkm * 1. Redistributions of source code must retain the above copyright
929088Smarkm *    notice, this list of conditions and the following disclaimer.
1029088Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1129088Smarkm *    notice, this list of conditions and the following disclaimer in the
1229088Smarkm *    documentation and/or other materials provided with the distribution.
1329088Smarkm * 3. All advertising materials mentioning features or use of this software
1429088Smarkm *    must display the following acknowledgement:
1529088Smarkm *	This product includes software developed by the University of
1629088Smarkm *	California, Berkeley and its contributors.
1729088Smarkm * 4. Neither the name of the University nor the names of its contributors
1829088Smarkm *    may be used to endorse or promote products derived from this software
1929088Smarkm *    without specific prior written permission.
2029088Smarkm *
2129088Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2229088Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2329088Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2429088Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2529088Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2629088Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2729088Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2829088Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2929088Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3029088Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3129088Smarkm * SUCH DAMAGE.
3256668Sshin *
3356668Sshin * $FreeBSD: head/contrib/telnet/telnet/commands.c 63662 2000-07-20 14:54:04Z ume $
3429088Smarkm */
3529088Smarkm
3629088Smarkm#ifndef lint
3729181Smarkmstatic const char sccsid[] = "@(#)commands.c	8.4 (Berkeley) 5/30/95";
3829088Smarkm#endif /* not lint */
3929088Smarkm
4029088Smarkm#if	defined(unix)
4129088Smarkm#include <sys/param.h>
4229088Smarkm#if	defined(CRAY) || defined(sysV88)
4329088Smarkm#include <sys/types.h>
4429088Smarkm#endif
4529088Smarkm#include <sys/file.h>
4629088Smarkm#else
4729088Smarkm#include <sys/types.h>
4829088Smarkm#endif	/* defined(unix) */
4929088Smarkm#include <sys/socket.h>
5029088Smarkm#include <netinet/in.h>
5129088Smarkm#ifdef	CRAY
5229088Smarkm#include <fcntl.h>
5329088Smarkm#endif	/* CRAY */
5429088Smarkm
5529088Smarkm#include <signal.h>
5629088Smarkm#include <netdb.h>
5729088Smarkm#include <ctype.h>
5829088Smarkm#include <pwd.h>
5929088Smarkm#include <varargs.h>
6029088Smarkm#include <errno.h>
6129181Smarkm#include <unistd.h>
6229181Smarkm#include <stdlib.h>
6329088Smarkm
6429088Smarkm#include <arpa/telnet.h>
6529088Smarkm
6629088Smarkm#include "general.h"
6729088Smarkm
6829088Smarkm#include "ring.h"
6929088Smarkm
7029088Smarkm#include "externs.h"
7129088Smarkm#include "defines.h"
7229088Smarkm#include "types.h"
7329088Smarkm
7429181Smarkm#if	defined(AUTHENTICATION)
7529181Smarkm#include <libtelnet/auth.h>
7629181Smarkm#endif
7729181Smarkm#if	defined(ENCRYPTION)
7829181Smarkm#include <libtelnet/encrypt.h>
7929181Smarkm#endif
8029181Smarkm
8129088Smarkm#if !defined(CRAY) && !defined(sysV88)
8229088Smarkm#include <netinet/in_systm.h>
8329088Smarkm# if (defined(vax) || defined(tahoe) || defined(hp300)) && !defined(ultrix)
8429088Smarkm# include <machine/endian.h>
8529088Smarkm# endif /* vax */
8629088Smarkm#endif /* !defined(CRAY) && !defined(sysV88) */
8729088Smarkm#include <netinet/ip.h>
8856668Sshin#include <netinet/ip6.h>
8929088Smarkm
9029088Smarkm
9129088Smarkm#ifndef	MAXHOSTNAMELEN
9229088Smarkm#define	MAXHOSTNAMELEN 64
9329088Smarkm#endif	MAXHOSTNAMELEN
9429088Smarkm
9529088Smarkm#if	defined(IPPROTO_IP) && defined(IP_TOS)
9629088Smarkmint tos = -1;
9729088Smarkm#endif	/* defined(IPPROTO_IP) && defined(IP_TOS) */
9829088Smarkm
9929088Smarkmchar	*hostname;
10029088Smarkmstatic char _hostname[MAXHOSTNAMELEN];
10129088Smarkm
10229088Smarkmextern char *getenv();
10329088Smarkm
10429088Smarkmextern int isprefix();
10529088Smarkmextern char **genget();
10629088Smarkmextern int Ambiguous();
10729088Smarkm
10829181Smarkmstatic int help(int argc, char *argv[]);
10929181Smarkmstatic int call();
11029181Smarkmstatic void cmdrc(char *m1, char *m2);
11157125Sshinstatic int switch_af(struct addrinfo **aip);
11229088Smarkm
11329181Smarkmint quit(void);
11429181Smarkm
11529088Smarkmtypedef struct {
11629088Smarkm	char	*name;		/* command name */
11729088Smarkm	char	*help;		/* help string (NULL for no help) */
11829088Smarkm	int	(*handler)();	/* routine which executes command */
11929088Smarkm	int	needconnect;	/* Do we need to be connected to execute? */
12029088Smarkm} Command;
12129088Smarkm
12229088Smarkmstatic char line[256];
12329088Smarkmstatic char saveline[256];
12429088Smarkmstatic int margc;
12529088Smarkmstatic char *margv[20];
12629088Smarkm
12729181Smarkm#if	defined(SKEY)
12829181Smarkm#include <sys/wait.h>
12929181Smarkm#define PATH_SKEY	"/usr/bin/key"
13029181Smarkm    int
13129181Smarkmskey_calc(argc, argv)
13229181Smarkm	int argc;
13329181Smarkm	char **argv;
13429181Smarkm{
13529181Smarkm	int status;
13629181Smarkm
13729181Smarkm	if(argc != 3) {
13829181Smarkm		printf("%s sequence challenge\n", argv[0]);
13929181Smarkm		return;
14029181Smarkm	}
14129181Smarkm
14229181Smarkm	switch(fork()) {
14329181Smarkm	case 0:
14429181Smarkm		execv(PATH_SKEY, argv);
14529181Smarkm		exit (1);
14629181Smarkm	case -1:
14729181Smarkm		perror("fork");
14829181Smarkm		break;
14929181Smarkm	default:
15029181Smarkm		(void) wait(&status);
15129181Smarkm		if (WIFEXITED(status))
15229181Smarkm			return (WEXITSTATUS(status));
15329181Smarkm		return (0);
15429181Smarkm	}
15529181Smarkm}
15629181Smarkm#endif
15729181Smarkm
15829088Smarkm    static void
15929088Smarkmmakeargv()
16029088Smarkm{
16129088Smarkm    register char *cp, *cp2, c;
16229088Smarkm    register char **argp = margv;
16329088Smarkm
16429088Smarkm    margc = 0;
16529088Smarkm    cp = line;
16629088Smarkm    if (*cp == '!') {		/* Special case shell escape */
16729088Smarkm	strcpy(saveline, line);	/* save for shell command */
16829088Smarkm	*argp++ = "!";		/* No room in string to get this */
16929088Smarkm	margc++;
17029088Smarkm	cp++;
17129088Smarkm    }
17229181Smarkm    while ((c = *cp)) {
17329088Smarkm	register int inquote = 0;
17429088Smarkm	while (isspace(c))
17529088Smarkm	    c = *++cp;
17629088Smarkm	if (c == '\0')
17729088Smarkm	    break;
17829088Smarkm	*argp++ = cp;
17929088Smarkm	margc += 1;
18029088Smarkm	for (cp2 = cp; c != '\0'; c = *++cp) {
18129088Smarkm	    if (inquote) {
18229088Smarkm		if (c == inquote) {
18329088Smarkm		    inquote = 0;
18429088Smarkm		    continue;
18529088Smarkm		}
18629088Smarkm	    } else {
18729088Smarkm		if (c == '\\') {
18829088Smarkm		    if ((c = *++cp) == '\0')
18929088Smarkm			break;
19029088Smarkm		} else if (c == '"') {
19129088Smarkm		    inquote = '"';
19229088Smarkm		    continue;
19329088Smarkm		} else if (c == '\'') {
19429088Smarkm		    inquote = '\'';
19529088Smarkm		    continue;
19629088Smarkm		} else if (isspace(c))
19729088Smarkm		    break;
19829088Smarkm	    }
19929088Smarkm	    *cp2++ = c;
20029088Smarkm	}
20129088Smarkm	*cp2 = '\0';
20229088Smarkm	if (c == '\0')
20329088Smarkm	    break;
20429088Smarkm	cp++;
20529088Smarkm    }
20629088Smarkm    *argp++ = 0;
20729088Smarkm}
20829088Smarkm
20929088Smarkm/*
21029088Smarkm * Make a character string into a number.
21129088Smarkm *
21229088Smarkm * Todo:  1.  Could take random integers (12, 0x12, 012, 0b1).
21329088Smarkm */
21429088Smarkm
21529181Smarkm	static int
21629088Smarkmspecial(s)
21729088Smarkm	register char *s;
21829088Smarkm{
21929088Smarkm	register char c;
22029088Smarkm	char b;
22129088Smarkm
22229088Smarkm	switch (*s) {
22329088Smarkm	case '^':
22429088Smarkm		b = *++s;
22529088Smarkm		if (b == '?') {
22629088Smarkm		    c = b | 0x40;		/* DEL */
22729088Smarkm		} else {
22829088Smarkm		    c = b & 0x1f;
22929088Smarkm		}
23029088Smarkm		break;
23129088Smarkm	default:
23229088Smarkm		c = *s;
23329088Smarkm		break;
23429088Smarkm	}
23529088Smarkm	return c;
23629088Smarkm}
23729088Smarkm
23829088Smarkm/*
23929088Smarkm * Construct a control character sequence
24029088Smarkm * for a special character.
24129088Smarkm */
24229088Smarkm	static char *
24329088Smarkmcontrol(c)
24429088Smarkm	register cc_t c;
24529088Smarkm{
24629088Smarkm	static char buf[5];
24729088Smarkm	/*
24829088Smarkm	 * The only way I could get the Sun 3.5 compiler
24929088Smarkm	 * to shut up about
25029088Smarkm	 *	if ((unsigned int)c >= 0x80)
25129088Smarkm	 * was to assign "c" to an unsigned int variable...
25229088Smarkm	 * Arggg....
25329088Smarkm	 */
25429088Smarkm	register unsigned int uic = (unsigned int)c;
25529088Smarkm
25629088Smarkm	if (uic == 0x7f)
25729088Smarkm		return ("^?");
25829088Smarkm	if (c == (cc_t)_POSIX_VDISABLE) {
25929088Smarkm		return "off";
26029088Smarkm	}
26129088Smarkm	if (uic >= 0x80) {
26229088Smarkm		buf[0] = '\\';
26329088Smarkm		buf[1] = ((c>>6)&07) + '0';
26429088Smarkm		buf[2] = ((c>>3)&07) + '0';
26529088Smarkm		buf[3] = (c&07) + '0';
26629088Smarkm		buf[4] = 0;
26729088Smarkm	} else if (uic >= 0x20) {
26829088Smarkm		buf[0] = c;
26929088Smarkm		buf[1] = 0;
27029088Smarkm	} else {
27129088Smarkm		buf[0] = '^';
27229088Smarkm		buf[1] = '@'+c;
27329088Smarkm		buf[2] = 0;
27429088Smarkm	}
27529088Smarkm	return (buf);
27629088Smarkm}
27729088Smarkm
27829088Smarkm
27929088Smarkm
28029088Smarkm/*
28129088Smarkm *	The following are data structures and routines for
28229088Smarkm *	the "send" command.
28329088Smarkm *
28429088Smarkm */
28529088Smarkm
28629088Smarkmstruct sendlist {
28729088Smarkm    char	*name;		/* How user refers to it (case independent) */
28829088Smarkm    char	*help;		/* Help information (0 ==> no help) */
28929088Smarkm    int		needconnect;	/* Need to be connected */
29029088Smarkm    int		narg;		/* Number of arguments */
29129088Smarkm    int		(*handler)();	/* Routine to perform (for special ops) */
29229088Smarkm    int		nbyte;		/* Number of bytes to send this command */
29329088Smarkm    int		what;		/* Character to be sent (<0 ==> special) */
29429088Smarkm};
29529088Smarkm
29629088Smarkm
29729088Smarkmstatic int
29829088Smarkm	send_esc P((void)),
29929088Smarkm	send_help P((void)),
30029088Smarkm	send_docmd P((char *)),
30129088Smarkm	send_dontcmd P((char *)),
30229088Smarkm	send_willcmd P((char *)),
30329088Smarkm	send_wontcmd P((char *));
30429088Smarkm
30529088Smarkmstatic struct sendlist Sendlist[] = {
30629088Smarkm    { "ao",	"Send Telnet Abort output",		1, 0, 0, 2, AO },
30729088Smarkm    { "ayt",	"Send Telnet 'Are You There'",		1, 0, 0, 2, AYT },
30829088Smarkm    { "brk",	"Send Telnet Break",			1, 0, 0, 2, BREAK },
30929088Smarkm    { "break",	0,					1, 0, 0, 2, BREAK },
31029088Smarkm    { "ec",	"Send Telnet Erase Character",		1, 0, 0, 2, EC },
31129088Smarkm    { "el",	"Send Telnet Erase Line",		1, 0, 0, 2, EL },
31229088Smarkm    { "escape",	"Send current escape character",	1, 0, send_esc, 1, 0 },
31329088Smarkm    { "ga",	"Send Telnet 'Go Ahead' sequence",	1, 0, 0, 2, GA },
31429088Smarkm    { "ip",	"Send Telnet Interrupt Process",	1, 0, 0, 2, IP },
31529088Smarkm    { "intp",	0,					1, 0, 0, 2, IP },
31629088Smarkm    { "interrupt", 0,					1, 0, 0, 2, IP },
31729088Smarkm    { "intr",	0,					1, 0, 0, 2, IP },
31829088Smarkm    { "nop",	"Send Telnet 'No operation'",		1, 0, 0, 2, NOP },
31929088Smarkm    { "eor",	"Send Telnet 'End of Record'",		1, 0, 0, 2, EOR },
32029088Smarkm    { "abort",	"Send Telnet 'Abort Process'",		1, 0, 0, 2, ABORT },
32129088Smarkm    { "susp",	"Send Telnet 'Suspend Process'",	1, 0, 0, 2, SUSP },
32229088Smarkm    { "eof",	"Send Telnet End of File Character",	1, 0, 0, 2, xEOF },
32329088Smarkm    { "synch",	"Perform Telnet 'Synch operation'",	1, 0, dosynch, 2, 0 },
32429088Smarkm    { "getstatus", "Send request for STATUS",		1, 0, get_status, 6, 0 },
32529088Smarkm    { "?",	"Display send options",			0, 0, send_help, 0, 0 },
32629088Smarkm    { "help",	0,					0, 0, send_help, 0, 0 },
32729088Smarkm    { "do",	0,					0, 1, send_docmd, 3, 0 },
32829088Smarkm    { "dont",	0,					0, 1, send_dontcmd, 3, 0 },
32929088Smarkm    { "will",	0,					0, 1, send_willcmd, 3, 0 },
33029088Smarkm    { "wont",	0,					0, 1, send_wontcmd, 3, 0 },
33129088Smarkm    { 0 }
33229088Smarkm};
33329088Smarkm
33429088Smarkm#define	GETSEND(name) ((struct sendlist *) genget(name, (char **) Sendlist, \
33529088Smarkm				sizeof(struct sendlist)))
33629088Smarkm
33729088Smarkm    static int
33829088Smarkmsendcmd(argc, argv)
33929088Smarkm    int  argc;
34029088Smarkm    char **argv;
34129088Smarkm{
34229088Smarkm    int count;		/* how many bytes we are going to need to send */
34329088Smarkm    int i;
34429088Smarkm    struct sendlist *s;	/* pointer to current command */
34529088Smarkm    int success = 0;
34629088Smarkm    int needconnect = 0;
34729088Smarkm
34829088Smarkm    if (argc < 2) {
34929088Smarkm	printf("need at least one argument for 'send' command\n");
35029088Smarkm	printf("'send ?' for help\n");
35129088Smarkm	return 0;
35229088Smarkm    }
35329088Smarkm    /*
35429088Smarkm     * First, validate all the send arguments.
35529088Smarkm     * In addition, we see how much space we are going to need, and
35629088Smarkm     * whether or not we will be doing a "SYNCH" operation (which
35729088Smarkm     * flushes the network queue).
35829088Smarkm     */
35929088Smarkm    count = 0;
36029088Smarkm    for (i = 1; i < argc; i++) {
36129088Smarkm	s = GETSEND(argv[i]);
36229088Smarkm	if (s == 0) {
36329088Smarkm	    printf("Unknown send argument '%s'\n'send ?' for help.\n",
36429088Smarkm			argv[i]);
36529088Smarkm	    return 0;
36629088Smarkm	} else if (Ambiguous(s)) {
36729088Smarkm	    printf("Ambiguous send argument '%s'\n'send ?' for help.\n",
36829088Smarkm			argv[i]);
36929088Smarkm	    return 0;
37029088Smarkm	}
37129088Smarkm	if (i + s->narg >= argc) {
37229088Smarkm	    fprintf(stderr,
37329088Smarkm	    "Need %d argument%s to 'send %s' command.  'send %s ?' for help.\n",
37429088Smarkm		s->narg, s->narg == 1 ? "" : "s", s->name, s->name);
37529088Smarkm	    return 0;
37629088Smarkm	}
37729088Smarkm	count += s->nbyte;
37829088Smarkm	if (s->handler == send_help) {
37929088Smarkm	    send_help();
38029088Smarkm	    return 0;
38129088Smarkm	}
38229088Smarkm
38329088Smarkm	i += s->narg;
38429088Smarkm	needconnect += s->needconnect;
38529088Smarkm    }
38629088Smarkm    if (!connected && needconnect) {
38729088Smarkm	printf("?Need to be connected first.\n");
38829088Smarkm	printf("'send ?' for help\n");
38929088Smarkm	return 0;
39029088Smarkm    }
39129088Smarkm    /* Now, do we have enough room? */
39229088Smarkm    if (NETROOM() < count) {
39329088Smarkm	printf("There is not enough room in the buffer TO the network\n");
39429088Smarkm	printf("to process your request.  Nothing will be done.\n");
39529088Smarkm	printf("('send synch' will throw away most data in the network\n");
39629088Smarkm	printf("buffer, if this might help.)\n");
39729088Smarkm	return 0;
39829088Smarkm    }
39929088Smarkm    /* OK, they are all OK, now go through again and actually send */
40029088Smarkm    count = 0;
40129088Smarkm    for (i = 1; i < argc; i++) {
40229088Smarkm	if ((s = GETSEND(argv[i])) == 0) {
40329088Smarkm	    fprintf(stderr, "Telnet 'send' error - argument disappeared!\n");
40429088Smarkm	    (void) quit();
40529088Smarkm	    /*NOTREACHED*/
40629088Smarkm	}
40729088Smarkm	if (s->handler) {
40829088Smarkm	    count++;
40929088Smarkm	    success += (*s->handler)((s->narg > 0) ? argv[i+1] : 0,
41029088Smarkm				  (s->narg > 1) ? argv[i+2] : 0);
41129088Smarkm	    i += s->narg;
41229088Smarkm	} else {
41329088Smarkm	    NET2ADD(IAC, s->what);
41429088Smarkm	    printoption("SENT", IAC, s->what);
41529088Smarkm	}
41629088Smarkm    }
41729088Smarkm    return (count == success);
41829088Smarkm}
41929088Smarkm
42029088Smarkm    static int
42129088Smarkmsend_esc()
42229088Smarkm{
42329088Smarkm    NETADD(escape);
42429088Smarkm    return 1;
42529088Smarkm}
42629088Smarkm
42729088Smarkm    static int
42829088Smarkmsend_docmd(name)
42929088Smarkm    char *name;
43029088Smarkm{
43129088Smarkm    return(send_tncmd(send_do, "do", name));
43229088Smarkm}
43329088Smarkm
43429088Smarkm    static int
43529088Smarkmsend_dontcmd(name)
43629088Smarkm    char *name;
43729088Smarkm{
43829088Smarkm    return(send_tncmd(send_dont, "dont", name));
43929088Smarkm}
44029088Smarkm    static int
44129088Smarkmsend_willcmd(name)
44229088Smarkm    char *name;
44329088Smarkm{
44429088Smarkm    return(send_tncmd(send_will, "will", name));
44529088Smarkm}
44629088Smarkm    static int
44729088Smarkmsend_wontcmd(name)
44829088Smarkm    char *name;
44929088Smarkm{
45029088Smarkm    return(send_tncmd(send_wont, "wont", name));
45129088Smarkm}
45229088Smarkm
45329088Smarkm    int
45429088Smarkmsend_tncmd(func, cmd, name)
45529088Smarkm    void	(*func)();
45629088Smarkm    char	*cmd, *name;
45729088Smarkm{
45829088Smarkm    char **cpp;
45929088Smarkm    extern char *telopts[];
46029088Smarkm    register int val = 0;
46129088Smarkm
46229088Smarkm    if (isprefix(name, "help") || isprefix(name, "?")) {
46329088Smarkm	register int col, len;
46429088Smarkm
46529088Smarkm	printf("Usage: send %s <value|option>\n", cmd);
46629088Smarkm	printf("\"value\" must be from 0 to 255\n");
46729088Smarkm	printf("Valid options are:\n\t");
46829088Smarkm
46929088Smarkm	col = 8;
47029088Smarkm	for (cpp = telopts; *cpp; cpp++) {
47129088Smarkm	    len = strlen(*cpp) + 3;
47229088Smarkm	    if (col + len > 65) {
47329088Smarkm		printf("\n\t");
47429088Smarkm		col = 8;
47529088Smarkm	    }
47629088Smarkm	    printf(" \"%s\"", *cpp);
47729088Smarkm	    col += len;
47829088Smarkm	}
47929088Smarkm	printf("\n");
48029088Smarkm	return 0;
48129088Smarkm    }
48229088Smarkm    cpp = (char **)genget(name, telopts, sizeof(char *));
48329088Smarkm    if (Ambiguous(cpp)) {
48429088Smarkm	fprintf(stderr,"'%s': ambiguous argument ('send %s ?' for help).\n",
48529088Smarkm					name, cmd);
48629088Smarkm	return 0;
48729088Smarkm    }
48829088Smarkm    if (cpp) {
48929088Smarkm	val = cpp - telopts;
49029088Smarkm    } else {
49129088Smarkm	register char *cp = name;
49229088Smarkm
49329088Smarkm	while (*cp >= '0' && *cp <= '9') {
49429088Smarkm	    val *= 10;
49529088Smarkm	    val += *cp - '0';
49629088Smarkm	    cp++;
49729088Smarkm	}
49829088Smarkm	if (*cp != 0) {
49929088Smarkm	    fprintf(stderr, "'%s': unknown argument ('send %s ?' for help).\n",
50029088Smarkm					name, cmd);
50129088Smarkm	    return 0;
50229088Smarkm	} else if (val < 0 || val > 255) {
50329088Smarkm	    fprintf(stderr, "'%s': bad value ('send %s ?' for help).\n",
50429088Smarkm					name, cmd);
50529088Smarkm	    return 0;
50629088Smarkm	}
50729088Smarkm    }
50829088Smarkm    if (!connected) {
50929088Smarkm	printf("?Need to be connected first.\n");
51029088Smarkm	return 0;
51129088Smarkm    }
51229088Smarkm    (*func)(val, 1);
51329088Smarkm    return 1;
51429088Smarkm}
51529088Smarkm
51629088Smarkm    static int
51729088Smarkmsend_help()
51829088Smarkm{
51929088Smarkm    struct sendlist *s;	/* pointer to current command */
52029088Smarkm    for (s = Sendlist; s->name; s++) {
52129088Smarkm	if (s->help)
52229088Smarkm	    printf("%-15s %s\n", s->name, s->help);
52329088Smarkm    }
52429088Smarkm    return(0);
52529088Smarkm}
52629088Smarkm
52729088Smarkm/*
52829088Smarkm * The following are the routines and data structures referred
52929088Smarkm * to by the arguments to the "toggle" command.
53029088Smarkm */
53129088Smarkm
53229088Smarkm    static int
53329088Smarkmlclchars()
53429088Smarkm{
53529088Smarkm    donelclchars = 1;
53629088Smarkm    return 1;
53729088Smarkm}
53829088Smarkm
53929088Smarkm    static int
54029088Smarkmtogdebug()
54129088Smarkm{
54229088Smarkm#ifndef	NOT43
54329088Smarkm    if (net > 0 &&
54429088Smarkm	(SetSockOpt(net, SOL_SOCKET, SO_DEBUG, debug)) < 0) {
54529088Smarkm	    perror("setsockopt (SO_DEBUG)");
54629088Smarkm    }
54729088Smarkm#else	/* NOT43 */
54829088Smarkm    if (debug) {
54929181Smarkm	if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0)
55029088Smarkm	    perror("setsockopt (SO_DEBUG)");
55129088Smarkm    } else
55229088Smarkm	printf("Cannot turn off socket debugging\n");
55329088Smarkm#endif	/* NOT43 */
55429088Smarkm    return 1;
55529088Smarkm}
55629088Smarkm
55729088Smarkm
55829088Smarkm    static int
55929088Smarkmtogcrlf()
56029088Smarkm{
56129088Smarkm    if (crlf) {
56229088Smarkm	printf("Will send carriage returns as telnet <CR><LF>.\n");
56329088Smarkm    } else {
56429088Smarkm	printf("Will send carriage returns as telnet <CR><NUL>.\n");
56529088Smarkm    }
56629088Smarkm    return 1;
56729088Smarkm}
56829088Smarkm
56929088Smarkmint binmode;
57029088Smarkm
57129088Smarkm    static int
57229088Smarkmtogbinary(val)
57329088Smarkm    int val;
57429088Smarkm{
57529088Smarkm    donebinarytoggle = 1;
57629088Smarkm
57729088Smarkm    if (val >= 0) {
57829088Smarkm	binmode = val;
57929088Smarkm    } else {
58029088Smarkm	if (my_want_state_is_will(TELOPT_BINARY) &&
58129088Smarkm				my_want_state_is_do(TELOPT_BINARY)) {
58229088Smarkm	    binmode = 1;
58329088Smarkm	} else if (my_want_state_is_wont(TELOPT_BINARY) &&
58429088Smarkm				my_want_state_is_dont(TELOPT_BINARY)) {
58529088Smarkm	    binmode = 0;
58629088Smarkm	}
58729088Smarkm	val = binmode ? 0 : 1;
58829088Smarkm    }
58929088Smarkm
59029088Smarkm    if (val == 1) {
59129088Smarkm	if (my_want_state_is_will(TELOPT_BINARY) &&
59229088Smarkm					my_want_state_is_do(TELOPT_BINARY)) {
59329088Smarkm	    printf("Already operating in binary mode with remote host.\n");
59429088Smarkm	} else {
59529088Smarkm	    printf("Negotiating binary mode with remote host.\n");
59629088Smarkm	    tel_enter_binary(3);
59729088Smarkm	}
59829088Smarkm    } else {
59929088Smarkm	if (my_want_state_is_wont(TELOPT_BINARY) &&
60029088Smarkm					my_want_state_is_dont(TELOPT_BINARY)) {
60129088Smarkm	    printf("Already in network ascii mode with remote host.\n");
60229088Smarkm	} else {
60329088Smarkm	    printf("Negotiating network ascii mode with remote host.\n");
60429088Smarkm	    tel_leave_binary(3);
60529088Smarkm	}
60629088Smarkm    }
60729088Smarkm    return 1;
60829088Smarkm}
60929088Smarkm
61029088Smarkm    static int
61129088Smarkmtogrbinary(val)
61229088Smarkm    int val;
61329088Smarkm{
61429088Smarkm    donebinarytoggle = 1;
61529088Smarkm
61629088Smarkm    if (val == -1)
61729088Smarkm	val = my_want_state_is_do(TELOPT_BINARY) ? 0 : 1;
61829088Smarkm
61929088Smarkm    if (val == 1) {
62029088Smarkm	if (my_want_state_is_do(TELOPT_BINARY)) {
62129088Smarkm	    printf("Already receiving in binary mode.\n");
62229088Smarkm	} else {
62329088Smarkm	    printf("Negotiating binary mode on input.\n");
62429088Smarkm	    tel_enter_binary(1);
62529088Smarkm	}
62629088Smarkm    } else {
62729088Smarkm	if (my_want_state_is_dont(TELOPT_BINARY)) {
62829088Smarkm	    printf("Already receiving in network ascii mode.\n");
62929088Smarkm	} else {
63029088Smarkm	    printf("Negotiating network ascii mode on input.\n");
63129088Smarkm	    tel_leave_binary(1);
63229088Smarkm	}
63329088Smarkm    }
63429088Smarkm    return 1;
63529088Smarkm}
63629088Smarkm
63729088Smarkm    static int
63829088Smarkmtogxbinary(val)
63929088Smarkm    int val;
64029088Smarkm{
64129088Smarkm    donebinarytoggle = 1;
64229088Smarkm
64329088Smarkm    if (val == -1)
64429088Smarkm	val = my_want_state_is_will(TELOPT_BINARY) ? 0 : 1;
64529088Smarkm
64629088Smarkm    if (val == 1) {
64729088Smarkm	if (my_want_state_is_will(TELOPT_BINARY)) {
64829088Smarkm	    printf("Already transmitting in binary mode.\n");
64929088Smarkm	} else {
65029088Smarkm	    printf("Negotiating binary mode on output.\n");
65129088Smarkm	    tel_enter_binary(2);
65229088Smarkm	}
65329088Smarkm    } else {
65429088Smarkm	if (my_want_state_is_wont(TELOPT_BINARY)) {
65529088Smarkm	    printf("Already transmitting in network ascii mode.\n");
65629088Smarkm	} else {
65729088Smarkm	    printf("Negotiating network ascii mode on output.\n");
65829088Smarkm	    tel_leave_binary(2);
65929088Smarkm	}
66029088Smarkm    }
66129088Smarkm    return 1;
66229088Smarkm}
66329088Smarkm
66429088Smarkm
66529088Smarkmstatic int togglehelp P((void));
66629088Smarkm#if	defined(AUTHENTICATION)
66729088Smarkmextern int auth_togdebug P((int));
66829088Smarkm#endif
66929088Smarkm#ifdef	ENCRYPTION
67029088Smarkmextern int EncryptAutoEnc P((int));
67129088Smarkmextern int EncryptAutoDec P((int));
67229088Smarkmextern int EncryptDebug P((int));
67329088Smarkmextern int EncryptVerbose P((int));
67429088Smarkm#endif	/* ENCRYPTION */
67529088Smarkm
67629088Smarkmstruct togglelist {
67729088Smarkm    char	*name;		/* name of toggle */
67829088Smarkm    char	*help;		/* help message */
67929088Smarkm    int		(*handler)();	/* routine to do actual setting */
68029088Smarkm    int		*variable;
68129088Smarkm    char	*actionexplanation;
68229088Smarkm};
68329088Smarkm
68429088Smarkmstatic struct togglelist Togglelist[] = {
68529088Smarkm    { "autoflush",
68629088Smarkm	"flushing of output when sending interrupt characters",
68729088Smarkm	    0,
68829088Smarkm		&autoflush,
68929088Smarkm		    "flush output when sending interrupt characters" },
69029088Smarkm    { "autosynch",
69129088Smarkm	"automatic sending of interrupt characters in urgent mode",
69229088Smarkm	    0,
69329088Smarkm		&autosynch,
69429088Smarkm		    "send interrupt characters in urgent mode" },
69529088Smarkm#if	defined(AUTHENTICATION)
69629088Smarkm    { "autologin",
69729088Smarkm	"automatic sending of login and/or authentication info",
69829088Smarkm	    0,
69929088Smarkm		&autologin,
70029088Smarkm		    "send login name and/or authentication information" },
70129088Smarkm    { "authdebug",
70229088Smarkm	"Toggle authentication debugging",
70329088Smarkm	    auth_togdebug,
70429088Smarkm		0,
70529088Smarkm		     "print authentication debugging information" },
70629088Smarkm#endif
70729088Smarkm#ifdef	ENCRYPTION
70829088Smarkm    { "autoencrypt",
70929088Smarkm	"automatic encryption of data stream",
71029088Smarkm	    EncryptAutoEnc,
71129088Smarkm		0,
71229088Smarkm		    "automatically encrypt output" },
71329088Smarkm    { "autodecrypt",
71429088Smarkm	"automatic decryption of data stream",
71529088Smarkm	    EncryptAutoDec,
71629088Smarkm		0,
71729088Smarkm		    "automatically decrypt input" },
71829088Smarkm    { "verbose_encrypt",
71929088Smarkm	"Toggle verbose encryption output",
72029088Smarkm	    EncryptVerbose,
72129088Smarkm		0,
72229088Smarkm		    "print verbose encryption output" },
72329088Smarkm    { "encdebug",
72429088Smarkm	"Toggle encryption debugging",
72529088Smarkm	    EncryptDebug,
72629088Smarkm		0,
72729088Smarkm		    "print encryption debugging information" },
72829088Smarkm#endif	/* ENCRYPTION */
72929088Smarkm    { "skiprc",
73029088Smarkm	"don't read ~/.telnetrc file",
73129088Smarkm	    0,
73229088Smarkm		&skiprc,
73329088Smarkm		    "skip reading of ~/.telnetrc file" },
73429088Smarkm    { "binary",
73529088Smarkm	"sending and receiving of binary data",
73629088Smarkm	    togbinary,
73729088Smarkm		0,
73829088Smarkm		    0 },
73929088Smarkm    { "inbinary",
74029088Smarkm	"receiving of binary data",
74129088Smarkm	    togrbinary,
74229088Smarkm		0,
74329088Smarkm		    0 },
74429088Smarkm    { "outbinary",
74529088Smarkm	"sending of binary data",
74629088Smarkm	    togxbinary,
74729088Smarkm		0,
74829088Smarkm		    0 },
74929088Smarkm    { "crlf",
75029088Smarkm	"sending carriage returns as telnet <CR><LF>",
75129088Smarkm	    togcrlf,
75229088Smarkm		&crlf,
75329088Smarkm		    0 },
75429088Smarkm    { "crmod",
75529088Smarkm	"mapping of received carriage returns",
75629088Smarkm	    0,
75729088Smarkm		&crmod,
75829088Smarkm		    "map carriage return on output" },
75929088Smarkm    { "localchars",
76029088Smarkm	"local recognition of certain control characters",
76129088Smarkm	    lclchars,
76229088Smarkm		&localchars,
76329088Smarkm		    "recognize certain control characters" },
76429088Smarkm    { " ", "", 0 },		/* empty line */
76529088Smarkm#if	defined(unix) && defined(TN3270)
76629088Smarkm    { "apitrace",
76729088Smarkm	"(debugging) toggle tracing of API transactions",
76829088Smarkm	    0,
76929088Smarkm		&apitrace,
77029088Smarkm		    "trace API transactions" },
77129088Smarkm    { "cursesdata",
77229088Smarkm	"(debugging) toggle printing of hexadecimal curses data",
77329088Smarkm	    0,
77429088Smarkm		&cursesdata,
77529088Smarkm		    "print hexadecimal representation of curses data" },
77629088Smarkm#endif	/* defined(unix) && defined(TN3270) */
77729088Smarkm    { "debug",
77829088Smarkm	"debugging",
77929088Smarkm	    togdebug,
78029088Smarkm		&debug,
78129088Smarkm		    "turn on socket level debugging" },
78229088Smarkm    { "netdata",
78329088Smarkm	"printing of hexadecimal network data (debugging)",
78429088Smarkm	    0,
78529088Smarkm		&netdata,
78629088Smarkm		    "print hexadecimal representation of network traffic" },
78729088Smarkm    { "prettydump",
78829088Smarkm	"output of \"netdata\" to user readable format (debugging)",
78929088Smarkm	    0,
79029088Smarkm		&prettydump,
79129088Smarkm		    "print user readable output for \"netdata\"" },
79229088Smarkm    { "options",
79329088Smarkm	"viewing of options processing (debugging)",
79429088Smarkm	    0,
79529088Smarkm		&showoptions,
79629088Smarkm		    "show option processing" },
79729088Smarkm#if	defined(unix)
79829088Smarkm    { "termdata",
79929088Smarkm	"(debugging) toggle printing of hexadecimal terminal data",
80029088Smarkm	    0,
80129088Smarkm		&termdata,
80229088Smarkm		    "print hexadecimal representation of terminal traffic" },
80329088Smarkm#endif	/* defined(unix) */
80429088Smarkm    { "?",
80529088Smarkm	0,
80629088Smarkm	    togglehelp },
80729088Smarkm    { "help",
80829088Smarkm	0,
80929088Smarkm	    togglehelp },
81029088Smarkm    { 0 }
81129088Smarkm};
81229088Smarkm
81329088Smarkm    static int
81429088Smarkmtogglehelp()
81529088Smarkm{
81629088Smarkm    struct togglelist *c;
81729088Smarkm
81829088Smarkm    for (c = Togglelist; c->name; c++) {
81929088Smarkm	if (c->help) {
82029088Smarkm	    if (*c->help)
82129088Smarkm		printf("%-15s toggle %s\n", c->name, c->help);
82229088Smarkm	    else
82329088Smarkm		printf("\n");
82429088Smarkm	}
82529088Smarkm    }
82629088Smarkm    printf("\n");
82729088Smarkm    printf("%-15s %s\n", "?", "display help information");
82829088Smarkm    return 0;
82929088Smarkm}
83029088Smarkm
83129088Smarkm    static void
83229088Smarkmsettogglehelp(set)
83329088Smarkm    int set;
83429088Smarkm{
83529088Smarkm    struct togglelist *c;
83629088Smarkm
83729088Smarkm    for (c = Togglelist; c->name; c++) {
83829088Smarkm	if (c->help) {
83929088Smarkm	    if (*c->help)
84029088Smarkm		printf("%-15s %s %s\n", c->name, set ? "enable" : "disable",
84129088Smarkm						c->help);
84229088Smarkm	    else
84329088Smarkm		printf("\n");
84429088Smarkm	}
84529088Smarkm    }
84629088Smarkm}
84729088Smarkm
84829088Smarkm#define	GETTOGGLE(name) (struct togglelist *) \
84929088Smarkm		genget(name, (char **) Togglelist, sizeof(struct togglelist))
85029088Smarkm
85129088Smarkm    static int
85229088Smarkmtoggle(argc, argv)
85329088Smarkm    int  argc;
85429088Smarkm    char *argv[];
85529088Smarkm{
85629088Smarkm    int retval = 1;
85729088Smarkm    char *name;
85829088Smarkm    struct togglelist *c;
85929088Smarkm
86029088Smarkm    if (argc < 2) {
86129088Smarkm	fprintf(stderr,
86229088Smarkm	    "Need an argument to 'toggle' command.  'toggle ?' for help.\n");
86329088Smarkm	return 0;
86429088Smarkm    }
86529088Smarkm    argc--;
86629088Smarkm    argv++;
86729088Smarkm    while (argc--) {
86829088Smarkm	name = *argv++;
86929088Smarkm	c = GETTOGGLE(name);
87029088Smarkm	if (Ambiguous(c)) {
87129088Smarkm	    fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n",
87229088Smarkm					name);
87329088Smarkm	    return 0;
87429088Smarkm	} else if (c == 0) {
87529088Smarkm	    fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n",
87629088Smarkm					name);
87729088Smarkm	    return 0;
87829088Smarkm	} else {
87929088Smarkm	    if (c->variable) {
88029088Smarkm		*c->variable = !*c->variable;		/* invert it */
88129088Smarkm		if (c->actionexplanation) {
88229088Smarkm		    printf("%s %s.\n", *c->variable? "Will" : "Won't",
88329088Smarkm							c->actionexplanation);
88429088Smarkm		}
88529088Smarkm	    }
88629088Smarkm	    if (c->handler) {
88729088Smarkm		retval &= (*c->handler)(-1);
88829088Smarkm	    }
88929088Smarkm	}
89029088Smarkm    }
89129088Smarkm    return retval;
89229088Smarkm}
89329088Smarkm
89429088Smarkm/*
89529088Smarkm * The following perform the "set" command.
89629088Smarkm */
89729088Smarkm
89829088Smarkm#ifdef	USE_TERMIO
89929088Smarkmstruct termio new_tc = { 0 };
90029088Smarkm#endif
90129088Smarkm
90229088Smarkmstruct setlist {
90329088Smarkm    char *name;				/* name */
90429088Smarkm    char *help;				/* help information */
90529088Smarkm    void (*handler)();
90629088Smarkm    cc_t *charp;			/* where it is located at */
90729088Smarkm};
90829088Smarkm
90929088Smarkmstatic struct setlist Setlist[] = {
91029088Smarkm#ifdef	KLUDGELINEMODE
91129088Smarkm    { "echo", 	"character to toggle local echoing on/off", 0, &echoc },
91229088Smarkm#endif
91329088Smarkm    { "escape",	"character to escape back to telnet command mode", 0, &escape },
91429088Smarkm    { "rlogin", "rlogin escape character", 0, &rlogin },
91529088Smarkm    { "tracefile", "file to write trace information to", SetNetTrace, (cc_t *)NetTraceFile},
91629088Smarkm    { " ", "" },
91729088Smarkm    { " ", "The following need 'localchars' to be toggled true", 0, 0 },
91829088Smarkm    { "flushoutput", "character to cause an Abort Output", 0, termFlushCharp },
91929088Smarkm    { "interrupt", "character to cause an Interrupt Process", 0, termIntCharp },
92029088Smarkm    { "quit",	"character to cause an Abort process", 0, termQuitCharp },
92129088Smarkm    { "eof",	"character to cause an EOF ", 0, termEofCharp },
92229088Smarkm    { " ", "" },
92329088Smarkm    { " ", "The following are for local editing in linemode", 0, 0 },
92429088Smarkm    { "erase",	"character to use to erase a character", 0, termEraseCharp },
92529088Smarkm    { "kill",	"character to use to erase a line", 0, termKillCharp },
92629088Smarkm    { "lnext",	"character to use for literal next", 0, termLiteralNextCharp },
92729088Smarkm    { "susp",	"character to cause a Suspend Process", 0, termSuspCharp },
92829088Smarkm    { "reprint", "character to use for line reprint", 0, termRprntCharp },
92929088Smarkm    { "worderase", "character to use to erase a word", 0, termWerasCharp },
93029088Smarkm    { "start",	"character to use for XON", 0, termStartCharp },
93129088Smarkm    { "stop",	"character to use for XOFF", 0, termStopCharp },
93229088Smarkm    { "forw1",	"alternate end of line character", 0, termForw1Charp },
93329088Smarkm    { "forw2",	"alternate end of line character", 0, termForw2Charp },
93429088Smarkm    { "ayt",	"alternate AYT character", 0, termAytCharp },
93529088Smarkm    { 0 }
93629088Smarkm};
93729088Smarkm
93829088Smarkm#if	defined(CRAY) && !defined(__STDC__)
93929088Smarkm/* Work around compiler bug in pcc 4.1.5 */
94029088Smarkm    void
94129088Smarkm_setlist_init()
94229088Smarkm{
94329088Smarkm#ifndef	KLUDGELINEMODE
94429088Smarkm#define	N 5
94529088Smarkm#else
94629088Smarkm#define	N 6
94729088Smarkm#endif
94829088Smarkm	Setlist[N+0].charp = &termFlushChar;
94929088Smarkm	Setlist[N+1].charp = &termIntChar;
95029088Smarkm	Setlist[N+2].charp = &termQuitChar;
95129088Smarkm	Setlist[N+3].charp = &termEofChar;
95229088Smarkm	Setlist[N+6].charp = &termEraseChar;
95329088Smarkm	Setlist[N+7].charp = &termKillChar;
95429088Smarkm	Setlist[N+8].charp = &termLiteralNextChar;
95529088Smarkm	Setlist[N+9].charp = &termSuspChar;
95629088Smarkm	Setlist[N+10].charp = &termRprntChar;
95729088Smarkm	Setlist[N+11].charp = &termWerasChar;
95829088Smarkm	Setlist[N+12].charp = &termStartChar;
95929088Smarkm	Setlist[N+13].charp = &termStopChar;
96029088Smarkm	Setlist[N+14].charp = &termForw1Char;
96129088Smarkm	Setlist[N+15].charp = &termForw2Char;
96229088Smarkm	Setlist[N+16].charp = &termAytChar;
96329088Smarkm#undef	N
96429088Smarkm}
96529088Smarkm#endif	/* defined(CRAY) && !defined(__STDC__) */
96629088Smarkm
96729088Smarkm    static struct setlist *
96829088Smarkmgetset(name)
96929088Smarkm    char *name;
97029088Smarkm{
97129088Smarkm    return (struct setlist *)
97229088Smarkm		genget(name, (char **) Setlist, sizeof(struct setlist));
97329088Smarkm}
97429088Smarkm
97529088Smarkm    void
97629088Smarkmset_escape_char(s)
97729088Smarkm    char *s;
97829088Smarkm{
97929088Smarkm	if (rlogin != _POSIX_VDISABLE) {
98029088Smarkm		rlogin = (s && *s) ? special(s) : _POSIX_VDISABLE;
98129088Smarkm		printf("Telnet rlogin escape character is '%s'.\n",
98229088Smarkm					control(rlogin));
98329088Smarkm	} else {
98429088Smarkm		escape = (s && *s) ? special(s) : _POSIX_VDISABLE;
98529088Smarkm		printf("Telnet escape character is '%s'.\n", control(escape));
98629088Smarkm	}
98729088Smarkm}
98829088Smarkm
98929088Smarkm    static int
99029088Smarkmsetcmd(argc, argv)
99129088Smarkm    int  argc;
99229088Smarkm    char *argv[];
99329088Smarkm{
99429088Smarkm    int value;
99529088Smarkm    struct setlist *ct;
99629088Smarkm    struct togglelist *c;
99729088Smarkm
99829088Smarkm    if (argc < 2 || argc > 3) {
99929088Smarkm	printf("Format is 'set Name Value'\n'set ?' for help.\n");
100029088Smarkm	return 0;
100129088Smarkm    }
100229088Smarkm    if ((argc == 2) && (isprefix(argv[1], "?") || isprefix(argv[1], "help"))) {
100329088Smarkm	for (ct = Setlist; ct->name; ct++)
100429088Smarkm	    printf("%-15s %s\n", ct->name, ct->help);
100529088Smarkm	printf("\n");
100629088Smarkm	settogglehelp(1);
100729088Smarkm	printf("%-15s %s\n", "?", "display help information");
100829088Smarkm	return 0;
100929088Smarkm    }
101029088Smarkm
101129088Smarkm    ct = getset(argv[1]);
101229088Smarkm    if (ct == 0) {
101329088Smarkm	c = GETTOGGLE(argv[1]);
101429088Smarkm	if (c == 0) {
101529088Smarkm	    fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n",
101629088Smarkm			argv[1]);
101729088Smarkm	    return 0;
101829088Smarkm	} else if (Ambiguous(c)) {
101929088Smarkm	    fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
102029088Smarkm			argv[1]);
102129088Smarkm	    return 0;
102229088Smarkm	}
102329088Smarkm	if (c->variable) {
102429088Smarkm	    if ((argc == 2) || (strcmp("on", argv[2]) == 0))
102529088Smarkm		*c->variable = 1;
102629088Smarkm	    else if (strcmp("off", argv[2]) == 0)
102729088Smarkm		*c->variable = 0;
102829088Smarkm	    else {
102929088Smarkm		printf("Format is 'set togglename [on|off]'\n'set ?' for help.\n");
103029088Smarkm		return 0;
103129088Smarkm	    }
103229088Smarkm	    if (c->actionexplanation) {
103329088Smarkm		printf("%s %s.\n", *c->variable? "Will" : "Won't",
103429088Smarkm							c->actionexplanation);
103529088Smarkm	    }
103629088Smarkm	}
103729088Smarkm	if (c->handler)
103829088Smarkm	    (*c->handler)(1);
103929088Smarkm    } else if (argc != 3) {
104029088Smarkm	printf("Format is 'set Name Value'\n'set ?' for help.\n");
104129088Smarkm	return 0;
104229088Smarkm    } else if (Ambiguous(ct)) {
104329088Smarkm	fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
104429088Smarkm			argv[1]);
104529088Smarkm	return 0;
104629088Smarkm    } else if (ct->handler) {
104729088Smarkm	(*ct->handler)(argv[2]);
104829088Smarkm	printf("%s set to \"%s\".\n", ct->name, (char *)ct->charp);
104929088Smarkm    } else {
105029088Smarkm	if (strcmp("off", argv[2])) {
105129088Smarkm	    value = special(argv[2]);
105229088Smarkm	} else {
105329088Smarkm	    value = _POSIX_VDISABLE;
105429088Smarkm	}
105529088Smarkm	*(ct->charp) = (cc_t)value;
105629088Smarkm	printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
105729088Smarkm    }
105829088Smarkm    slc_check();
105929088Smarkm    return 1;
106029088Smarkm}
106129088Smarkm
106229088Smarkm    static int
106329088Smarkmunsetcmd(argc, argv)
106429088Smarkm    int  argc;
106529088Smarkm    char *argv[];
106629088Smarkm{
106729088Smarkm    struct setlist *ct;
106829088Smarkm    struct togglelist *c;
106929088Smarkm    register char *name;
107029088Smarkm
107129088Smarkm    if (argc < 2) {
107229088Smarkm	fprintf(stderr,
107329088Smarkm	    "Need an argument to 'unset' command.  'unset ?' for help.\n");
107429088Smarkm	return 0;
107529088Smarkm    }
107629088Smarkm    if (isprefix(argv[1], "?") || isprefix(argv[1], "help")) {
107729088Smarkm	for (ct = Setlist; ct->name; ct++)
107829088Smarkm	    printf("%-15s %s\n", ct->name, ct->help);
107929088Smarkm	printf("\n");
108029088Smarkm	settogglehelp(0);
108129088Smarkm	printf("%-15s %s\n", "?", "display help information");
108229088Smarkm	return 0;
108329088Smarkm    }
108429088Smarkm
108529088Smarkm    argc--;
108629088Smarkm    argv++;
108729088Smarkm    while (argc--) {
108829088Smarkm	name = *argv++;
108929088Smarkm	ct = getset(name);
109029088Smarkm	if (ct == 0) {
109129088Smarkm	    c = GETTOGGLE(name);
109229088Smarkm	    if (c == 0) {
109329088Smarkm		fprintf(stderr, "'%s': unknown argument ('unset ?' for help).\n",
109429088Smarkm			name);
109529088Smarkm		return 0;
109629088Smarkm	    } else if (Ambiguous(c)) {
109729088Smarkm		fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n",
109829088Smarkm			name);
109929088Smarkm		return 0;
110029088Smarkm	    }
110129088Smarkm	    if (c->variable) {
110229088Smarkm		*c->variable = 0;
110329088Smarkm		if (c->actionexplanation) {
110429088Smarkm		    printf("%s %s.\n", *c->variable? "Will" : "Won't",
110529088Smarkm							c->actionexplanation);
110629088Smarkm		}
110729088Smarkm	    }
110829088Smarkm	    if (c->handler)
110929088Smarkm		(*c->handler)(0);
111029088Smarkm	} else if (Ambiguous(ct)) {
111129088Smarkm	    fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n",
111229088Smarkm			name);
111329088Smarkm	    return 0;
111429088Smarkm	} else if (ct->handler) {
111529088Smarkm	    (*ct->handler)(0);
111629088Smarkm	    printf("%s reset to \"%s\".\n", ct->name, (char *)ct->charp);
111729088Smarkm	} else {
111829088Smarkm	    *(ct->charp) = _POSIX_VDISABLE;
111929088Smarkm	    printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
112029088Smarkm	}
112129088Smarkm    }
112229088Smarkm    return 1;
112329088Smarkm}
112429088Smarkm
112529088Smarkm/*
112629088Smarkm * The following are the data structures and routines for the
112729088Smarkm * 'mode' command.
112829088Smarkm */
112929088Smarkm#ifdef	KLUDGELINEMODE
113029088Smarkmextern int kludgelinemode;
113129088Smarkm
113247973Sru    static int
113329088Smarkmdokludgemode()
113429088Smarkm{
113529088Smarkm    kludgelinemode = 1;
113629088Smarkm    send_wont(TELOPT_LINEMODE, 1);
113729088Smarkm    send_dont(TELOPT_SGA, 1);
113829088Smarkm    send_dont(TELOPT_ECHO, 1);
113949861Snsayer    return 1;
114029088Smarkm}
114129088Smarkm#endif
114229088Smarkm
114329088Smarkm    static int
114429088Smarkmdolinemode()
114529088Smarkm{
114629088Smarkm#ifdef	KLUDGELINEMODE
114729088Smarkm    if (kludgelinemode)
114829088Smarkm	send_dont(TELOPT_SGA, 1);
114929088Smarkm#endif
115029088Smarkm    send_will(TELOPT_LINEMODE, 1);
115129088Smarkm    send_dont(TELOPT_ECHO, 1);
115229088Smarkm    return 1;
115329088Smarkm}
115429088Smarkm
115529088Smarkm    static int
115629088Smarkmdocharmode()
115729088Smarkm{
115829088Smarkm#ifdef	KLUDGELINEMODE
115929088Smarkm    if (kludgelinemode)
116029088Smarkm	send_do(TELOPT_SGA, 1);
116129088Smarkm    else
116229088Smarkm#endif
116329088Smarkm    send_wont(TELOPT_LINEMODE, 1);
116429088Smarkm    send_do(TELOPT_ECHO, 1);
116529088Smarkm    return 1;
116629088Smarkm}
116729088Smarkm
116829088Smarkm    static int
116929088Smarkmdolmmode(bit, on)
117029088Smarkm    int bit, on;
117129088Smarkm{
117229088Smarkm    unsigned char c;
117329088Smarkm    extern int linemode;
117429088Smarkm
117529088Smarkm    if (my_want_state_is_wont(TELOPT_LINEMODE)) {
117629088Smarkm	printf("?Need to have LINEMODE option enabled first.\n");
117729088Smarkm	printf("'mode ?' for help.\n");
117829088Smarkm	return 0;
117929088Smarkm    }
118029088Smarkm
118129088Smarkm    if (on)
118229088Smarkm	c = (linemode | bit);
118329088Smarkm    else
118429088Smarkm	c = (linemode & ~bit);
118529088Smarkm    lm_mode(&c, 1, 1);
118629088Smarkm    return 1;
118729088Smarkm}
118829088Smarkm
118929088Smarkm    int
119029181Smarkmsetmod(bit)
119129088Smarkm{
119229088Smarkm    return dolmmode(bit, 1);
119329088Smarkm}
119429088Smarkm
119529088Smarkm    int
119629088Smarkmclearmode(bit)
119729088Smarkm{
119829088Smarkm    return dolmmode(bit, 0);
119929088Smarkm}
120029088Smarkm
120129088Smarkmstruct modelist {
120229088Smarkm	char	*name;		/* command name */
120329088Smarkm	char	*help;		/* help string */
120429088Smarkm	int	(*handler)();	/* routine which executes command */
120529088Smarkm	int	needconnect;	/* Do we need to be connected to execute? */
120629088Smarkm	int	arg1;
120729088Smarkm};
120829088Smarkm
120929088Smarkmextern int modehelp();
121029088Smarkm
121129088Smarkmstatic struct modelist ModeList[] = {
121229088Smarkm    { "character", "Disable LINEMODE option",	docharmode, 1 },
121329088Smarkm#ifdef	KLUDGELINEMODE
121429088Smarkm    { "",	"(or disable obsolete line-by-line mode)", 0 },
121529088Smarkm#endif
121629088Smarkm    { "line",	"Enable LINEMODE option",	dolinemode, 1 },
121729088Smarkm#ifdef	KLUDGELINEMODE
121829088Smarkm    { "",	"(or enable obsolete line-by-line mode)", 0 },
121929088Smarkm#endif
122029088Smarkm    { "", "", 0 },
122129088Smarkm    { "",	"These require the LINEMODE option to be enabled", 0 },
122229181Smarkm    { "isig",	"Enable signal trapping",	setmod, 1, MODE_TRAPSIG },
122329181Smarkm    { "+isig",	0,				setmod, 1, MODE_TRAPSIG },
122429088Smarkm    { "-isig",	"Disable signal trapping",	clearmode, 1, MODE_TRAPSIG },
122529181Smarkm    { "edit",	"Enable character editing",	setmod, 1, MODE_EDIT },
122629181Smarkm    { "+edit",	0,				setmod, 1, MODE_EDIT },
122729088Smarkm    { "-edit",	"Disable character editing",	clearmode, 1, MODE_EDIT },
122829181Smarkm    { "softtabs", "Enable tab expansion",	setmod, 1, MODE_SOFT_TAB },
122929181Smarkm    { "+softtabs", 0,				setmod, 1, MODE_SOFT_TAB },
123029088Smarkm    { "-softtabs", "Disable character editing",	clearmode, 1, MODE_SOFT_TAB },
123129181Smarkm    { "litecho", "Enable literal character echo", setmod, 1, MODE_LIT_ECHO },
123229181Smarkm    { "+litecho", 0,				setmod, 1, MODE_LIT_ECHO },
123329088Smarkm    { "-litecho", "Disable literal character echo", clearmode, 1, MODE_LIT_ECHO },
123429088Smarkm    { "help",	0,				modehelp, 0 },
123529088Smarkm#ifdef	KLUDGELINEMODE
123629088Smarkm    { "kludgeline", 0,				dokludgemode, 1 },
123729088Smarkm#endif
123829088Smarkm    { "", "", 0 },
123929088Smarkm    { "?",	"Print help information",	modehelp, 0 },
124029088Smarkm    { 0 },
124129088Smarkm};
124229088Smarkm
124329088Smarkm
124429088Smarkm    int
124529088Smarkmmodehelp()
124629088Smarkm{
124729088Smarkm    struct modelist *mt;
124829088Smarkm
124929088Smarkm    printf("format is:  'mode Mode', where 'Mode' is one of:\n\n");
125029088Smarkm    for (mt = ModeList; mt->name; mt++) {
125129088Smarkm	if (mt->help) {
125229088Smarkm	    if (*mt->help)
125329088Smarkm		printf("%-15s %s\n", mt->name, mt->help);
125429088Smarkm	    else
125529088Smarkm		printf("\n");
125629088Smarkm	}
125729088Smarkm    }
125829088Smarkm    return 0;
125929088Smarkm}
126029088Smarkm
126129088Smarkm#define	GETMODECMD(name) (struct modelist *) \
126229088Smarkm		genget(name, (char **) ModeList, sizeof(struct modelist))
126329088Smarkm
126429088Smarkm    static int
126529088Smarkmmodecmd(argc, argv)
126629088Smarkm    int  argc;
126729088Smarkm    char *argv[];
126829088Smarkm{
126929088Smarkm    struct modelist *mt;
127029088Smarkm
127129088Smarkm    if (argc != 2) {
127229088Smarkm	printf("'mode' command requires an argument\n");
127329088Smarkm	printf("'mode ?' for help.\n");
127429088Smarkm    } else if ((mt = GETMODECMD(argv[1])) == 0) {
127529088Smarkm	fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]);
127629088Smarkm    } else if (Ambiguous(mt)) {
127729088Smarkm	fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]);
127829088Smarkm    } else if (mt->needconnect && !connected) {
127929088Smarkm	printf("?Need to be connected first.\n");
128029088Smarkm	printf("'mode ?' for help.\n");
128129088Smarkm    } else if (mt->handler) {
128229088Smarkm	return (*mt->handler)(mt->arg1);
128329088Smarkm    }
128429088Smarkm    return 0;
128529088Smarkm}
128629088Smarkm
128729088Smarkm/*
128829088Smarkm * The following data structures and routines implement the
128929088Smarkm * "display" command.
129029088Smarkm */
129129088Smarkm
129229088Smarkm    static int
129329088Smarkmdisplay(argc, argv)
129429088Smarkm    int  argc;
129529088Smarkm    char *argv[];
129629088Smarkm{
129729088Smarkm    struct togglelist *tl;
129829088Smarkm    struct setlist *sl;
129929088Smarkm
130029088Smarkm#define	dotog(tl)	if (tl->variable && tl->actionexplanation) { \
130129088Smarkm			    if (*tl->variable) { \
130229088Smarkm				printf("will"); \
130329088Smarkm			    } else { \
130429088Smarkm				printf("won't"); \
130529088Smarkm			    } \
130629088Smarkm			    printf(" %s.\n", tl->actionexplanation); \
130729088Smarkm			}
130829088Smarkm
130929088Smarkm#define	doset(sl)   if (sl->name && *sl->name != ' ') { \
131029088Smarkm			if (sl->handler == 0) \
131129088Smarkm			    printf("%-15s [%s]\n", sl->name, control(*sl->charp)); \
131229088Smarkm			else \
131329088Smarkm			    printf("%-15s \"%s\"\n", sl->name, (char *)sl->charp); \
131429088Smarkm		    }
131529088Smarkm
131629088Smarkm    if (argc == 1) {
131729088Smarkm	for (tl = Togglelist; tl->name; tl++) {
131829088Smarkm	    dotog(tl);
131929088Smarkm	}
132029088Smarkm	printf("\n");
132129088Smarkm	for (sl = Setlist; sl->name; sl++) {
132229088Smarkm	    doset(sl);
132329088Smarkm	}
132429088Smarkm    } else {
132529088Smarkm	int i;
132629088Smarkm
132729088Smarkm	for (i = 1; i < argc; i++) {
132829088Smarkm	    sl = getset(argv[i]);
132929088Smarkm	    tl = GETTOGGLE(argv[i]);
133029088Smarkm	    if (Ambiguous(sl) || Ambiguous(tl)) {
133129088Smarkm		printf("?Ambiguous argument '%s'.\n", argv[i]);
133229088Smarkm		return 0;
133329088Smarkm	    } else if (!sl && !tl) {
133429088Smarkm		printf("?Unknown argument '%s'.\n", argv[i]);
133529088Smarkm		return 0;
133629088Smarkm	    } else {
133729088Smarkm		if (tl) {
133829088Smarkm		    dotog(tl);
133929088Smarkm		}
134029088Smarkm		if (sl) {
134129088Smarkm		    doset(sl);
134229088Smarkm		}
134329088Smarkm	    }
134429088Smarkm	}
134529088Smarkm    }
134629088Smarkm/*@*/optionstatus();
134729088Smarkm#ifdef	ENCRYPTION
134829088Smarkm    EncryptStatus();
134929088Smarkm#endif	/* ENCRYPTION */
135029088Smarkm    return 1;
135129088Smarkm#undef	doset
135229088Smarkm#undef	dotog
135329088Smarkm}
135429088Smarkm
135529088Smarkm/*
135629088Smarkm * The following are the data structures, and many of the routines,
135729088Smarkm * relating to command processing.
135829088Smarkm */
135929088Smarkm
136029088Smarkm/*
136129088Smarkm * Set the escape character.
136229088Smarkm */
136329088Smarkm	static int
136429088Smarkmsetescape(argc, argv)
136529088Smarkm	int argc;
136629088Smarkm	char *argv[];
136729088Smarkm{
136829088Smarkm	register char *arg;
136929088Smarkm	char buf[50];
137029088Smarkm
137129088Smarkm	printf(
137229088Smarkm	    "Deprecated usage - please use 'set escape%s%s' in the future.\n",
137329088Smarkm				(argc > 2)? " ":"", (argc > 2)? argv[1]: "");
137429088Smarkm	if (argc > 2)
137529088Smarkm		arg = argv[1];
137629088Smarkm	else {
137729088Smarkm		printf("new escape character: ");
137829088Smarkm		(void) fgets(buf, sizeof(buf), stdin);
137929088Smarkm		arg = buf;
138029088Smarkm	}
138129088Smarkm	if (arg[0] != '\0')
138229088Smarkm		escape = arg[0];
138329088Smarkm	if (!In3270) {
138429088Smarkm		printf("Escape character is '%s'.\n", control(escape));
138529088Smarkm	}
138629088Smarkm	(void) fflush(stdout);
138729088Smarkm	return 1;
138829088Smarkm}
138929088Smarkm
139029088Smarkm    /*VARARGS*/
139129088Smarkm    static int
139229088Smarkmtogcrmod()
139329088Smarkm{
139429088Smarkm    crmod = !crmod;
139529088Smarkm    printf("Deprecated usage - please use 'toggle crmod' in the future.\n");
139629088Smarkm    printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't");
139729088Smarkm    (void) fflush(stdout);
139829088Smarkm    return 1;
139929088Smarkm}
140029088Smarkm
140129088Smarkm    /*VARARGS*/
140229088Smarkm    int
140329088Smarkmsuspend()
140429088Smarkm{
140529088Smarkm#ifdef	SIGTSTP
140629088Smarkm    setcommandmode();
140729088Smarkm    {
140829088Smarkm	long oldrows, oldcols, newrows, newcols, err;
140929088Smarkm
141029088Smarkm	err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0;
141129088Smarkm	(void) kill(0, SIGTSTP);
141229088Smarkm	/*
141329088Smarkm	 * If we didn't get the window size before the SUSPEND, but we
141429088Smarkm	 * can get them now (?), then send the NAWS to make sure that
141529088Smarkm	 * we are set up for the right window size.
141629088Smarkm	 */
141729088Smarkm	if (TerminalWindowSize(&newrows, &newcols) && connected &&
141829088Smarkm	    (err || ((oldrows != newrows) || (oldcols != newcols)))) {
141929088Smarkm		sendnaws();
142029088Smarkm	}
142129088Smarkm    }
142229088Smarkm    /* reget parameters in case they were changed */
142329088Smarkm    TerminalSaveState();
142429088Smarkm    setconnmode(0);
142529088Smarkm#else
142629088Smarkm    printf("Suspend is not supported.  Try the '!' command instead\n");
142729088Smarkm#endif
142829088Smarkm    return 1;
142929088Smarkm}
143029088Smarkm
143129088Smarkm#if	!defined(TN3270)
143229088Smarkm    /*ARGSUSED*/
143329088Smarkm    int
143429088Smarkmshell(argc, argv)
143529088Smarkm    int argc;
143629088Smarkm    char *argv[];
143729088Smarkm{
143829088Smarkm    long oldrows, oldcols, newrows, newcols, err;
143929088Smarkm
144029088Smarkm    setcommandmode();
144129088Smarkm
144229088Smarkm    err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0;
144329088Smarkm    switch(vfork()) {
144429088Smarkm    case -1:
144529088Smarkm	perror("Fork failed\n");
144629088Smarkm	break;
144729088Smarkm
144829088Smarkm    case 0:
144929088Smarkm	{
145029088Smarkm	    /*
145129088Smarkm	     * Fire up the shell in the child.
145229088Smarkm	     */
145329088Smarkm	    register char *shellp, *shellname;
145429088Smarkm	    extern char *strrchr();
145529088Smarkm
145629088Smarkm	    shellp = getenv("SHELL");
145729088Smarkm	    if (shellp == NULL)
145829088Smarkm		shellp = "/bin/sh";
145929088Smarkm	    if ((shellname = strrchr(shellp, '/')) == 0)
146029088Smarkm		shellname = shellp;
146129088Smarkm	    else
146229088Smarkm		shellname++;
146329088Smarkm	    if (argc > 1)
146429088Smarkm		execl(shellp, shellname, "-c", &saveline[1], 0);
146529088Smarkm	    else
146629088Smarkm		execl(shellp, shellname, 0);
146729088Smarkm	    perror("Execl");
146829088Smarkm	    _exit(1);
146929088Smarkm	}
147029088Smarkm    default:
147129088Smarkm	    (void)wait((int *)0);	/* Wait for the shell to complete */
147229088Smarkm
147329088Smarkm	    if (TerminalWindowSize(&newrows, &newcols) && connected &&
147429088Smarkm		(err || ((oldrows != newrows) || (oldcols != newcols)))) {
147529088Smarkm		    sendnaws();
147629088Smarkm	    }
147729088Smarkm	    break;
147829088Smarkm    }
147929088Smarkm    return 1;
148029088Smarkm}
148129088Smarkm#else	/* !defined(TN3270) */
148229088Smarkmextern int shell();
148329088Smarkm#endif	/* !defined(TN3270) */
148429088Smarkm
148529088Smarkm    /*VARARGS*/
148629181Smarkm    static int
148729088Smarkmbye(argc, argv)
148829088Smarkm    int  argc;		/* Number of arguments */
148929088Smarkm    char *argv[];	/* arguments */
149029088Smarkm{
149129088Smarkm    extern int resettermname;
149229088Smarkm
149329088Smarkm    if (connected) {
149429088Smarkm	(void) shutdown(net, 2);
149529088Smarkm	printf("Connection closed.\n");
149629088Smarkm	(void) NetClose(net);
149729088Smarkm	connected = 0;
149829088Smarkm	resettermname = 1;
149929088Smarkm#if	defined(AUTHENTICATION) || defined(ENCRYPTION)
150029088Smarkm	auth_encrypt_connect(connected);
150129088Smarkm#endif	/* defined(AUTHENTICATION) || defined(ENCRYPTION) */
150229088Smarkm	/* reset options */
150329088Smarkm	tninit();
150429088Smarkm#if	defined(TN3270)
150529088Smarkm	SetIn3270();		/* Get out of 3270 mode */
150629088Smarkm#endif	/* defined(TN3270) */
150729088Smarkm    }
150829088Smarkm    if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) {
150929088Smarkm	longjmp(toplevel, 1);
151029088Smarkm	/* NOTREACHED */
151129088Smarkm    }
151229088Smarkm    return 1;			/* Keep lint, etc., happy */
151329088Smarkm}
151429088Smarkm
151529088Smarkm/*VARARGS*/
151629181Smarkm	int
151729088Smarkmquit()
151829088Smarkm{
151929088Smarkm	(void) call(bye, "bye", "fromquit", 0);
152029088Smarkm	Exit(0);
152129088Smarkm	/*NOTREACHED*/
152229088Smarkm}
152329088Smarkm
152429088Smarkm/*VARARGS*/
152529088Smarkm	int
152629088Smarkmlogout()
152729088Smarkm{
152829088Smarkm	send_do(TELOPT_LOGOUT, 1);
152929088Smarkm	(void) netflush();
153029088Smarkm	return 1;
153129088Smarkm}
153229088Smarkm
153329088Smarkm
153429088Smarkm/*
153529088Smarkm * The SLC command.
153629088Smarkm */
153729088Smarkm
153829088Smarkmstruct slclist {
153929088Smarkm	char	*name;
154029088Smarkm	char	*help;
154129088Smarkm	void	(*handler)();
154229088Smarkm	int	arg;
154329088Smarkm};
154429088Smarkm
154529088Smarkmstatic void slc_help();
154629088Smarkm
154729088Smarkmstruct slclist SlcList[] = {
154829088Smarkm    { "export",	"Use local special character definitions",
154929088Smarkm						slc_mode_export,	0 },
155029088Smarkm    { "import",	"Use remote special character definitions",
155129088Smarkm						slc_mode_import,	1 },
155229088Smarkm    { "check",	"Verify remote special character definitions",
155329088Smarkm						slc_mode_import,	0 },
155429088Smarkm    { "help",	0,				slc_help,		0 },
155529088Smarkm    { "?",	"Print help information",	slc_help,		0 },
155629088Smarkm    { 0 },
155729088Smarkm};
155829088Smarkm
155929088Smarkm    static void
156029088Smarkmslc_help()
156129088Smarkm{
156229088Smarkm    struct slclist *c;
156329088Smarkm
156429088Smarkm    for (c = SlcList; c->name; c++) {
156529088Smarkm	if (c->help) {
156629088Smarkm	    if (*c->help)
156729088Smarkm		printf("%-15s %s\n", c->name, c->help);
156829088Smarkm	    else
156929088Smarkm		printf("\n");
157029088Smarkm	}
157129088Smarkm    }
157229088Smarkm}
157329088Smarkm
157429088Smarkm    static struct slclist *
157529088Smarkmgetslc(name)
157629088Smarkm    char *name;
157729088Smarkm{
157829088Smarkm    return (struct slclist *)
157929088Smarkm		genget(name, (char **) SlcList, sizeof(struct slclist));
158029088Smarkm}
158129088Smarkm
158229181Smarkm    static int
158329088Smarkmslccmd(argc, argv)
158429088Smarkm    int  argc;
158529088Smarkm    char *argv[];
158629088Smarkm{
158729088Smarkm    struct slclist *c;
158829088Smarkm
158929088Smarkm    if (argc != 2) {
159029088Smarkm	fprintf(stderr,
159129088Smarkm	    "Need an argument to 'slc' command.  'slc ?' for help.\n");
159229088Smarkm	return 0;
159329088Smarkm    }
159429088Smarkm    c = getslc(argv[1]);
159529088Smarkm    if (c == 0) {
159629088Smarkm	fprintf(stderr, "'%s': unknown argument ('slc ?' for help).\n",
159729088Smarkm    				argv[1]);
159829088Smarkm	return 0;
159929088Smarkm    }
160029088Smarkm    if (Ambiguous(c)) {
160129088Smarkm	fprintf(stderr, "'%s': ambiguous argument ('slc ?' for help).\n",
160229088Smarkm    				argv[1]);
160329088Smarkm	return 0;
160429088Smarkm    }
160529088Smarkm    (*c->handler)(c->arg);
160629088Smarkm    slcstate();
160729088Smarkm    return 1;
160829088Smarkm}
160929088Smarkm
161029088Smarkm/*
161129088Smarkm * The ENVIRON command.
161229088Smarkm */
161329088Smarkm
161429088Smarkmstruct envlist {
161529088Smarkm	char	*name;
161629088Smarkm	char	*help;
161729088Smarkm	void	(*handler)();
161829088Smarkm	int	narg;
161929088Smarkm};
162029088Smarkm
162129088Smarkmextern struct env_lst *
162229088Smarkm	env_define P((unsigned char *, unsigned char *));
162329088Smarkmextern void
162429088Smarkm	env_undefine P((unsigned char *)),
162529088Smarkm	env_export P((unsigned char *)),
162629088Smarkm	env_unexport P((unsigned char *)),
162729088Smarkm	env_send P((unsigned char *)),
162829088Smarkm#if defined(OLD_ENVIRON) && defined(ENV_HACK)
162929088Smarkm	env_varval P((unsigned char *)),
163029088Smarkm#endif
163129088Smarkm	env_list P((void));
163229088Smarkmstatic void
163329088Smarkm	env_help P((void));
163429088Smarkm
163529088Smarkmstruct envlist EnvList[] = {
163629088Smarkm    { "define",	"Define an environment variable",
163729088Smarkm						(void (*)())env_define,	2 },
163829088Smarkm    { "undefine", "Undefine an environment variable",
163929088Smarkm						env_undefine,	1 },
164029088Smarkm    { "export",	"Mark an environment variable for automatic export",
164129088Smarkm						env_export,	1 },
164229088Smarkm    { "unexport", "Don't mark an environment variable for automatic export",
164329088Smarkm						env_unexport,	1 },
164429088Smarkm    { "send",	"Send an environment variable", env_send,	1 },
164529088Smarkm    { "list",	"List the current environment variables",
164629088Smarkm						env_list,	0 },
164729088Smarkm#if defined(OLD_ENVIRON) && defined(ENV_HACK)
164829088Smarkm    { "varval", "Reverse VAR and VALUE (auto, right, wrong, status)",
164929088Smarkm						env_varval,    1 },
165029088Smarkm#endif
165129088Smarkm    { "help",	0,				env_help,		0 },
165229088Smarkm    { "?",	"Print help information",	env_help,		0 },
165329088Smarkm    { 0 },
165429088Smarkm};
165529088Smarkm
165629088Smarkm    static void
165729088Smarkmenv_help()
165829088Smarkm{
165929088Smarkm    struct envlist *c;
166029088Smarkm
166129088Smarkm    for (c = EnvList; c->name; c++) {
166229088Smarkm	if (c->help) {
166329088Smarkm	    if (*c->help)
166429088Smarkm		printf("%-15s %s\n", c->name, c->help);
166529088Smarkm	    else
166629088Smarkm		printf("\n");
166729088Smarkm	}
166829088Smarkm    }
166929088Smarkm}
167029088Smarkm
167129088Smarkm    static struct envlist *
167229088Smarkmgetenvcmd(name)
167329088Smarkm    char *name;
167429088Smarkm{
167529088Smarkm    return (struct envlist *)
167629088Smarkm		genget(name, (char **) EnvList, sizeof(struct envlist));
167729088Smarkm}
167829088Smarkm
167929181Smarkm	int
168029088Smarkmenv_cmd(argc, argv)
168129088Smarkm    int  argc;
168229088Smarkm    char *argv[];
168329088Smarkm{
168429088Smarkm    struct envlist *c;
168529088Smarkm
168629088Smarkm    if (argc < 2) {
168729088Smarkm	fprintf(stderr,
168829088Smarkm	    "Need an argument to 'environ' command.  'environ ?' for help.\n");
168929088Smarkm	return 0;
169029088Smarkm    }
169129088Smarkm    c = getenvcmd(argv[1]);
169229088Smarkm    if (c == 0) {
169329088Smarkm	fprintf(stderr, "'%s': unknown argument ('environ ?' for help).\n",
169429088Smarkm    				argv[1]);
169529088Smarkm	return 0;
169629088Smarkm    }
169729088Smarkm    if (Ambiguous(c)) {
169829088Smarkm	fprintf(stderr, "'%s': ambiguous argument ('environ ?' for help).\n",
169929088Smarkm    				argv[1]);
170029088Smarkm	return 0;
170129088Smarkm    }
170229088Smarkm    if (c->narg + 2 != argc) {
170329088Smarkm	fprintf(stderr,
170429088Smarkm	    "Need %s%d argument%s to 'environ %s' command.  'environ ?' for help.\n",
170529088Smarkm		c->narg < argc + 2 ? "only " : "",
170629088Smarkm		c->narg, c->narg == 1 ? "" : "s", c->name);
170729088Smarkm	return 0;
170829088Smarkm    }
170929088Smarkm    (*c->handler)(argv[2], argv[3]);
171029088Smarkm    return 1;
171129088Smarkm}
171229088Smarkm
171329088Smarkmstruct env_lst {
171429088Smarkm	struct env_lst *next;	/* pointer to next structure */
171529088Smarkm	struct env_lst *prev;	/* pointer to previous structure */
171629088Smarkm	unsigned char *var;	/* pointer to variable name */
171729088Smarkm	unsigned char *value;	/* pointer to variable value */
171829088Smarkm	int export;		/* 1 -> export with default list of variables */
171929088Smarkm	int welldefined;	/* A well defined variable */
172029088Smarkm};
172129088Smarkm
172229088Smarkmstruct env_lst envlisthead;
172329088Smarkm
172429088Smarkm	struct env_lst *
172529088Smarkmenv_find(var)
172629088Smarkm	unsigned char *var;
172729088Smarkm{
172829088Smarkm	register struct env_lst *ep;
172929088Smarkm
173029088Smarkm	for (ep = envlisthead.next; ep; ep = ep->next) {
173129088Smarkm		if (strcmp((char *)ep->var, (char *)var) == 0)
173229088Smarkm			return(ep);
173329088Smarkm	}
173429088Smarkm	return(NULL);
173529088Smarkm}
173629088Smarkm
173729088Smarkm	void
173829088Smarkmenv_init()
173929088Smarkm{
174029088Smarkm	extern char **environ;
174129088Smarkm	register char **epp, *cp;
174229088Smarkm	register struct env_lst *ep;
174329088Smarkm	extern char *strchr();
174429088Smarkm
174529088Smarkm	for (epp = environ; *epp; epp++) {
174629181Smarkm		if ((cp = strchr(*epp, '='))) {
174729088Smarkm			*cp = '\0';
174829088Smarkm			ep = env_define((unsigned char *)*epp,
174929088Smarkm					(unsigned char *)cp+1);
175029088Smarkm			ep->export = 0;
175129088Smarkm			*cp = '=';
175229088Smarkm		}
175329088Smarkm	}
175429088Smarkm	/*
175529088Smarkm	 * Special case for DISPLAY variable.  If it is ":0.0" or
175629088Smarkm	 * "unix:0.0", we have to get rid of "unix" and insert our
175729088Smarkm	 * hostname.
175829088Smarkm	 */
175929088Smarkm	if ((ep = env_find("DISPLAY"))
176029088Smarkm	    && ((*ep->value == ':')
176129088Smarkm		|| (strncmp((char *)ep->value, "unix:", 5) == 0))) {
176229088Smarkm		char hbuf[256+1];
176329088Smarkm		char *cp2 = strchr((char *)ep->value, ':');
176429088Smarkm
176529088Smarkm		gethostname(hbuf, 256);
176629088Smarkm		hbuf[256] = '\0';
176729088Smarkm		cp = (char *)malloc(strlen(hbuf) + strlen(cp2) + 1);
176829088Smarkm		sprintf((char *)cp, "%s%s", hbuf, cp2);
176929088Smarkm		free(ep->value);
177029088Smarkm		ep->value = (unsigned char *)cp;
177129088Smarkm	}
177229088Smarkm	/*
177329088Smarkm	 * If USER is not defined, but LOGNAME is, then add
177429088Smarkm	 * USER with the value from LOGNAME.  By default, we
177529088Smarkm	 * don't export the USER variable.
177629088Smarkm	 */
177729088Smarkm	if ((env_find("USER") == NULL) && (ep = env_find("LOGNAME"))) {
177829088Smarkm		env_define((unsigned char *)"USER", ep->value);
177929088Smarkm		env_unexport((unsigned char *)"USER");
178029088Smarkm	}
178129088Smarkm	env_export((unsigned char *)"DISPLAY");
178229088Smarkm	env_export((unsigned char *)"PRINTER");
178329088Smarkm}
178429088Smarkm
178529088Smarkm	struct env_lst *
178629088Smarkmenv_define(var, value)
178729088Smarkm	unsigned char *var, *value;
178829088Smarkm{
178929088Smarkm	register struct env_lst *ep;
179029088Smarkm
179129181Smarkm	if ((ep = env_find(var))) {
179229088Smarkm		if (ep->var)
179329088Smarkm			free(ep->var);
179429088Smarkm		if (ep->value)
179529088Smarkm			free(ep->value);
179629088Smarkm	} else {
179729088Smarkm		ep = (struct env_lst *)malloc(sizeof(struct env_lst));
179829088Smarkm		ep->next = envlisthead.next;
179929088Smarkm		envlisthead.next = ep;
180029088Smarkm		ep->prev = &envlisthead;
180129088Smarkm		if (ep->next)
180229088Smarkm			ep->next->prev = ep;
180329088Smarkm	}
180429088Smarkm	ep->welldefined = opt_welldefined(var);
180529088Smarkm	ep->export = 1;
180629088Smarkm	ep->var = (unsigned char *)strdup((char *)var);
180729088Smarkm	ep->value = (unsigned char *)strdup((char *)value);
180829088Smarkm	return(ep);
180929088Smarkm}
181029088Smarkm
181129088Smarkm	void
181229088Smarkmenv_undefine(var)
181329088Smarkm	unsigned char *var;
181429088Smarkm{
181529088Smarkm	register struct env_lst *ep;
181629088Smarkm
181729181Smarkm	if ((ep = env_find(var))) {
181829088Smarkm		ep->prev->next = ep->next;
181929088Smarkm		if (ep->next)
182029088Smarkm			ep->next->prev = ep->prev;
182129088Smarkm		if (ep->var)
182229088Smarkm			free(ep->var);
182329088Smarkm		if (ep->value)
182429088Smarkm			free(ep->value);
182529088Smarkm		free(ep);
182629088Smarkm	}
182729088Smarkm}
182829088Smarkm
182929088Smarkm	void
183029088Smarkmenv_export(var)
183129088Smarkm	unsigned char *var;
183229088Smarkm{
183329088Smarkm	register struct env_lst *ep;
183429088Smarkm
183529181Smarkm	if ((ep = env_find(var)))
183629088Smarkm		ep->export = 1;
183729088Smarkm}
183829088Smarkm
183929088Smarkm	void
184029088Smarkmenv_unexport(var)
184129088Smarkm	unsigned char *var;
184229088Smarkm{
184329088Smarkm	register struct env_lst *ep;
184429088Smarkm
184529181Smarkm	if ((ep = env_find(var)))
184629088Smarkm		ep->export = 0;
184729088Smarkm}
184829088Smarkm
184929088Smarkm	void
185029088Smarkmenv_send(var)
185129088Smarkm	unsigned char *var;
185229088Smarkm{
185329088Smarkm	register struct env_lst *ep;
185429088Smarkm
185529088Smarkm	if (my_state_is_wont(TELOPT_NEW_ENVIRON)
185629088Smarkm#ifdef	OLD_ENVIRON
185729088Smarkm	    && my_state_is_wont(TELOPT_OLD_ENVIRON)
185829088Smarkm#endif
185929088Smarkm		) {
186029088Smarkm		fprintf(stderr,
186129088Smarkm		    "Cannot send '%s': Telnet ENVIRON option not enabled\n",
186229088Smarkm									var);
186329088Smarkm		return;
186429088Smarkm	}
186529088Smarkm	ep = env_find(var);
186629088Smarkm	if (ep == 0) {
186729088Smarkm		fprintf(stderr, "Cannot send '%s': variable not defined\n",
186829088Smarkm									var);
186929088Smarkm		return;
187029088Smarkm	}
187129088Smarkm	env_opt_start_info();
187229088Smarkm	env_opt_add(ep->var);
187329088Smarkm	env_opt_end(0);
187429088Smarkm}
187529088Smarkm
187629088Smarkm	void
187729088Smarkmenv_list()
187829088Smarkm{
187929088Smarkm	register struct env_lst *ep;
188029088Smarkm
188129088Smarkm	for (ep = envlisthead.next; ep; ep = ep->next) {
188229088Smarkm		printf("%c %-20s %s\n", ep->export ? '*' : ' ',
188329088Smarkm					ep->var, ep->value);
188429088Smarkm	}
188529088Smarkm}
188629088Smarkm
188729088Smarkm	unsigned char *
188829088Smarkmenv_default(init, welldefined)
188929088Smarkm	int init;
189029088Smarkm{
189129088Smarkm	static struct env_lst *nep = NULL;
189229088Smarkm
189329088Smarkm	if (init) {
189429088Smarkm		nep = &envlisthead;
189529181Smarkm		return(NULL);
189629088Smarkm	}
189729088Smarkm	if (nep) {
189829181Smarkm		while ((nep = nep->next)) {
189929088Smarkm			if (nep->export && (nep->welldefined == welldefined))
190029088Smarkm				return(nep->var);
190129088Smarkm		}
190229088Smarkm	}
190329088Smarkm	return(NULL);
190429088Smarkm}
190529088Smarkm
190629088Smarkm	unsigned char *
190729088Smarkmenv_getvalue(var)
190829088Smarkm	unsigned char *var;
190929088Smarkm{
191029088Smarkm	register struct env_lst *ep;
191129088Smarkm
191229181Smarkm	if ((ep = env_find(var)))
191329088Smarkm		return(ep->value);
191429088Smarkm	return(NULL);
191529088Smarkm}
191629088Smarkm
191729088Smarkm#if defined(OLD_ENVIRON) && defined(ENV_HACK)
191829088Smarkm	void
191929088Smarkmenv_varval(what)
192029088Smarkm	unsigned char *what;
192129088Smarkm{
192229088Smarkm	extern int old_env_var, old_env_value, env_auto;
192329088Smarkm	int len = strlen((char *)what);
192429088Smarkm
192529088Smarkm	if (len == 0)
192629088Smarkm		goto unknown;
192729088Smarkm
192829088Smarkm	if (strncasecmp((char *)what, "status", len) == 0) {
192929088Smarkm		if (env_auto)
193029088Smarkm			printf("%s%s", "VAR and VALUE are/will be ",
193129088Smarkm					"determined automatically\n");
193229088Smarkm		if (old_env_var == OLD_ENV_VAR)
193329088Smarkm			printf("VAR and VALUE set to correct definitions\n");
193429088Smarkm		else
193529088Smarkm			printf("VAR and VALUE definitions are reversed\n");
193629088Smarkm	} else if (strncasecmp((char *)what, "auto", len) == 0) {
193729088Smarkm		env_auto = 1;
193829088Smarkm		old_env_var = OLD_ENV_VALUE;
193929088Smarkm		old_env_value = OLD_ENV_VAR;
194029088Smarkm	} else if (strncasecmp((char *)what, "right", len) == 0) {
194129088Smarkm		env_auto = 0;
194229088Smarkm		old_env_var = OLD_ENV_VAR;
194329088Smarkm		old_env_value = OLD_ENV_VALUE;
194429088Smarkm	} else if (strncasecmp((char *)what, "wrong", len) == 0) {
194529088Smarkm		env_auto = 0;
194629088Smarkm		old_env_var = OLD_ENV_VALUE;
194729088Smarkm		old_env_value = OLD_ENV_VAR;
194829088Smarkm	} else {
194929088Smarkmunknown:
195029088Smarkm		printf("Unknown \"varval\" command. (\"auto\", \"right\", \"wrong\", \"status\")\n");
195129088Smarkm	}
195229088Smarkm}
195329088Smarkm#endif
195429088Smarkm
195529088Smarkm#if	defined(AUTHENTICATION)
195629088Smarkm/*
195729088Smarkm * The AUTHENTICATE command.
195829088Smarkm */
195929088Smarkm
196029088Smarkmstruct authlist {
196129088Smarkm	char	*name;
196229088Smarkm	char	*help;
196329088Smarkm	int	(*handler)();
196429088Smarkm	int	narg;
196529088Smarkm};
196629088Smarkm
196729088Smarkmextern int
196829088Smarkm	auth_enable P((char *)),
196929088Smarkm	auth_disable P((char *)),
197029088Smarkm	auth_status P((void));
197129088Smarkmstatic int
197229088Smarkm	auth_help P((void));
197329088Smarkm
197429088Smarkmstruct authlist AuthList[] = {
197529088Smarkm    { "status",	"Display current status of authentication information",
197629088Smarkm						auth_status,	0 },
197729088Smarkm    { "disable", "Disable an authentication type ('auth disable ?' for more)",
197829088Smarkm						auth_disable,	1 },
197929088Smarkm    { "enable", "Enable an authentication type ('auth enable ?' for more)",
198029088Smarkm						auth_enable,	1 },
198129088Smarkm    { "help",	0,				auth_help,		0 },
198229088Smarkm    { "?",	"Print help information",	auth_help,		0 },
198329088Smarkm    { 0 },
198429088Smarkm};
198529088Smarkm
198629088Smarkm    static int
198729088Smarkmauth_help()
198829088Smarkm{
198929088Smarkm    struct authlist *c;
199029088Smarkm
199129088Smarkm    for (c = AuthList; c->name; c++) {
199229088Smarkm	if (c->help) {
199329088Smarkm	    if (*c->help)
199429088Smarkm		printf("%-15s %s\n", c->name, c->help);
199529088Smarkm	    else
199629088Smarkm		printf("\n");
199729088Smarkm	}
199829088Smarkm    }
199929088Smarkm    return 0;
200029088Smarkm}
200129088Smarkm
200229181Smarkm	int
200329088Smarkmauth_cmd(argc, argv)
200429088Smarkm    int  argc;
200529088Smarkm    char *argv[];
200629088Smarkm{
200729088Smarkm    struct authlist *c;
200829088Smarkm
200929088Smarkm    if (argc < 2) {
201029088Smarkm	fprintf(stderr,
201129088Smarkm	    "Need an argument to 'auth' command.  'auth ?' for help.\n");
201229088Smarkm	return 0;
201329088Smarkm    }
201429088Smarkm
201529088Smarkm    c = (struct authlist *)
201629088Smarkm		genget(argv[1], (char **) AuthList, sizeof(struct authlist));
201729088Smarkm    if (c == 0) {
201829088Smarkm	fprintf(stderr, "'%s': unknown argument ('auth ?' for help).\n",
201929088Smarkm    				argv[1]);
202029088Smarkm	return 0;
202129088Smarkm    }
202229088Smarkm    if (Ambiguous(c)) {
202329088Smarkm	fprintf(stderr, "'%s': ambiguous argument ('auth ?' for help).\n",
202429088Smarkm    				argv[1]);
202529088Smarkm	return 0;
202629088Smarkm    }
202729088Smarkm    if (c->narg + 2 != argc) {
202829088Smarkm	fprintf(stderr,
202929088Smarkm	    "Need %s%d argument%s to 'auth %s' command.  'auth ?' for help.\n",
203029088Smarkm		c->narg < argc + 2 ? "only " : "",
203129088Smarkm		c->narg, c->narg == 1 ? "" : "s", c->name);
203229088Smarkm	return 0;
203329088Smarkm    }
203429088Smarkm    return((*c->handler)(argv[2], argv[3]));
203529088Smarkm}
203629088Smarkm#endif
203729088Smarkm
203829088Smarkm#ifdef	ENCRYPTION
203929088Smarkm/*
204029088Smarkm * The ENCRYPT command.
204129088Smarkm */
204229088Smarkm
204329088Smarkmstruct encryptlist {
204429088Smarkm	char	*name;
204529088Smarkm	char	*help;
204629088Smarkm	int	(*handler)();
204729088Smarkm	int	needconnect;
204829088Smarkm	int	minarg;
204929088Smarkm	int	maxarg;
205029088Smarkm};
205129088Smarkm
205229088Smarkmextern int
205329088Smarkm	EncryptEnable P((char *, char *)),
205429088Smarkm	EncryptDisable P((char *, char *)),
205529088Smarkm	EncryptType P((char *, char *)),
205629088Smarkm	EncryptStart P((char *)),
205729088Smarkm	EncryptStartInput P((void)),
205829088Smarkm	EncryptStartOutput P((void)),
205929088Smarkm	EncryptStop P((char *)),
206029088Smarkm	EncryptStopInput P((void)),
206129088Smarkm	EncryptStopOutput P((void)),
206229088Smarkm	EncryptStatus P((void));
206329088Smarkmstatic int
206429088Smarkm	EncryptHelp P((void));
206529088Smarkm
206629088Smarkmstruct encryptlist EncryptList[] = {
206729088Smarkm    { "enable", "Enable encryption. ('encrypt enable ?' for more)",
206829088Smarkm						EncryptEnable, 1, 1, 2 },
206929088Smarkm    { "disable", "Disable encryption. ('encrypt enable ?' for more)",
207029088Smarkm						EncryptDisable, 0, 1, 2 },
207129088Smarkm    { "type", "Set encryption type. ('encrypt type ?' for more)",
207229088Smarkm						EncryptType, 0, 1, 1 },
207329088Smarkm    { "start", "Start encryption. ('encrypt start ?' for more)",
207429088Smarkm						EncryptStart, 1, 0, 1 },
207529088Smarkm    { "stop", "Stop encryption. ('encrypt stop ?' for more)",
207629088Smarkm						EncryptStop, 1, 0, 1 },
207729088Smarkm    { "input", "Start encrypting the input stream",
207829088Smarkm						EncryptStartInput, 1, 0, 0 },
207929088Smarkm    { "-input", "Stop encrypting the input stream",
208029088Smarkm						EncryptStopInput, 1, 0, 0 },
208129088Smarkm    { "output", "Start encrypting the output stream",
208229088Smarkm						EncryptStartOutput, 1, 0, 0 },
208329088Smarkm    { "-output", "Stop encrypting the output stream",
208429088Smarkm						EncryptStopOutput, 1, 0, 0 },
208529088Smarkm
208629088Smarkm    { "status",	"Display current status of authentication information",
208729088Smarkm						EncryptStatus,	0, 0, 0 },
208829088Smarkm    { "help",	0,				EncryptHelp,	0, 0, 0 },
208929088Smarkm    { "?",	"Print help information",	EncryptHelp,	0, 0, 0 },
209029088Smarkm    { 0 },
209129088Smarkm};
209229088Smarkm
209329088Smarkm    static int
209429088SmarkmEncryptHelp()
209529088Smarkm{
209629088Smarkm    struct encryptlist *c;
209729088Smarkm
209829088Smarkm    for (c = EncryptList; c->name; c++) {
209929088Smarkm	if (c->help) {
210029088Smarkm	    if (*c->help)
210129088Smarkm		printf("%-15s %s\n", c->name, c->help);
210229088Smarkm	    else
210329088Smarkm		printf("\n");
210429088Smarkm	}
210529088Smarkm    }
210629088Smarkm    return 0;
210729088Smarkm}
210829088Smarkm
210929181Smarkm	int
211029088Smarkmencrypt_cmd(argc, argv)
211129088Smarkm    int  argc;
211229088Smarkm    char *argv[];
211329088Smarkm{
211429088Smarkm    struct encryptlist *c;
211529088Smarkm
211629088Smarkm    if (argc < 2) {
211729088Smarkm	fprintf(stderr,
211829088Smarkm	    "Need an argument to 'encrypt' command.  'encrypt ?' for help.\n");
211929088Smarkm	return 0;
212029088Smarkm    }
212129088Smarkm
212229088Smarkm    c = (struct encryptlist *)
212329088Smarkm		genget(argv[1], (char **) EncryptList, sizeof(struct encryptlist));
212429088Smarkm    if (c == 0) {
212529088Smarkm	fprintf(stderr, "'%s': unknown argument ('encrypt ?' for help).\n",
212629088Smarkm    				argv[1]);
212729088Smarkm	return 0;
212829088Smarkm    }
212929088Smarkm    if (Ambiguous(c)) {
213029088Smarkm	fprintf(stderr, "'%s': ambiguous argument ('encrypt ?' for help).\n",
213129088Smarkm    				argv[1]);
213229088Smarkm	return 0;
213329088Smarkm    }
213429088Smarkm    argc -= 2;
213529088Smarkm    if (argc < c->minarg || argc > c->maxarg) {
213629088Smarkm	if (c->minarg == c->maxarg) {
213729088Smarkm	    fprintf(stderr, "Need %s%d argument%s ",
213829088Smarkm		c->minarg < argc ? "only " : "", c->minarg,
213929088Smarkm		c->minarg == 1 ? "" : "s");
214029088Smarkm	} else {
214129088Smarkm	    fprintf(stderr, "Need %s%d-%d arguments ",
214229088Smarkm		c->maxarg < argc ? "only " : "", c->minarg, c->maxarg);
214329088Smarkm	}
214429088Smarkm	fprintf(stderr, "to 'encrypt %s' command.  'encrypt ?' for help.\n",
214529088Smarkm		c->name);
214629088Smarkm	return 0;
214729088Smarkm    }
214829088Smarkm    if (c->needconnect && !connected) {
214929088Smarkm	if (!(argc && (isprefix(argv[2], "help") || isprefix(argv[2], "?")))) {
215029088Smarkm	    printf("?Need to be connected first.\n");
215129088Smarkm	    return 0;
215229088Smarkm	}
215329088Smarkm    }
215429088Smarkm    return ((*c->handler)(argc > 0 ? argv[2] : 0,
215529088Smarkm			argc > 1 ? argv[3] : 0,
215629088Smarkm			argc > 2 ? argv[4] : 0));
215729088Smarkm}
215829088Smarkm#endif	/* ENCRYPTION */
215929088Smarkm
216029088Smarkm#if	defined(unix) && defined(TN3270)
216129088Smarkm    static void
216229088Smarkmfilestuff(fd)
216329088Smarkm    int fd;
216429088Smarkm{
216529088Smarkm    int res;
216629088Smarkm
216729088Smarkm#ifdef	F_GETOWN
216829088Smarkm    setconnmode(0);
216929088Smarkm    res = fcntl(fd, F_GETOWN, 0);
217029088Smarkm    setcommandmode();
217129088Smarkm
217229088Smarkm    if (res == -1) {
217329088Smarkm	perror("fcntl");
217429088Smarkm	return;
217529088Smarkm    }
217629088Smarkm    printf("\tOwner is %d.\n", res);
217729088Smarkm#endif
217829088Smarkm
217929088Smarkm    setconnmode(0);
218029088Smarkm    res = fcntl(fd, F_GETFL, 0);
218129088Smarkm    setcommandmode();
218229088Smarkm
218329088Smarkm    if (res == -1) {
218429088Smarkm	perror("fcntl");
218529088Smarkm	return;
218629088Smarkm    }
218729088Smarkm#ifdef notdef
218829088Smarkm    printf("\tFlags are 0x%x: %s\n", res, decodeflags(res));
218929088Smarkm#endif
219029088Smarkm}
219129088Smarkm#endif /* defined(unix) && defined(TN3270) */
219229088Smarkm
219329088Smarkm/*
219429088Smarkm * Print status about the connection.
219529088Smarkm */
219629088Smarkm    /*ARGSUSED*/
219729181Smarkm    static int
219829088Smarkmstatus(argc, argv)
219929088Smarkm    int	 argc;
220029088Smarkm    char *argv[];
220129088Smarkm{
220229088Smarkm    if (connected) {
220329088Smarkm	printf("Connected to %s.\n", hostname);
220429088Smarkm	if ((argc < 2) || strcmp(argv[1], "notmuch")) {
220529088Smarkm	    int mode = getconnmode();
220629088Smarkm
220729088Smarkm	    if (my_want_state_is_will(TELOPT_LINEMODE)) {
220829088Smarkm		printf("Operating with LINEMODE option\n");
220929088Smarkm		printf("%s line editing\n", (mode&MODE_EDIT) ? "Local" : "No");
221029088Smarkm		printf("%s catching of signals\n",
221129088Smarkm					(mode&MODE_TRAPSIG) ? "Local" : "No");
221229088Smarkm		slcstate();
221329088Smarkm#ifdef	KLUDGELINEMODE
221429088Smarkm	    } else if (kludgelinemode && my_want_state_is_dont(TELOPT_SGA)) {
221529088Smarkm		printf("Operating in obsolete linemode\n");
221629088Smarkm#endif
221729088Smarkm	    } else {
221829088Smarkm		printf("Operating in single character mode\n");
221929088Smarkm		if (localchars)
222029088Smarkm		    printf("Catching signals locally\n");
222129088Smarkm	    }
222229088Smarkm	    printf("%s character echo\n", (mode&MODE_ECHO) ? "Local" : "Remote");
222329088Smarkm	    if (my_want_state_is_will(TELOPT_LFLOW))
222429088Smarkm		printf("%s flow control\n", (mode&MODE_FLOW) ? "Local" : "No");
222529088Smarkm#ifdef	ENCRYPTION
222629088Smarkm	    encrypt_display();
222729088Smarkm#endif	/* ENCRYPTION */
222829088Smarkm	}
222929088Smarkm    } else {
223029088Smarkm	printf("No connection.\n");
223129088Smarkm    }
223229088Smarkm#   if !defined(TN3270)
223329088Smarkm    printf("Escape character is '%s'.\n", control(escape));
223429088Smarkm    (void) fflush(stdout);
223529088Smarkm#   else /* !defined(TN3270) */
223629088Smarkm    if ((!In3270) && ((argc < 2) || strcmp(argv[1], "notmuch"))) {
223729088Smarkm	printf("Escape character is '%s'.\n", control(escape));
223829088Smarkm    }
223929088Smarkm#   if defined(unix)
224029088Smarkm    if ((argc >= 2) && !strcmp(argv[1], "everything")) {
224129088Smarkm	printf("SIGIO received %d time%s.\n",
224229088Smarkm				sigiocount, (sigiocount == 1)? "":"s");
224329088Smarkm	if (In3270) {
224429088Smarkm	    printf("Process ID %d, process group %d.\n",
224529088Smarkm					    getpid(), getpgrp(getpid()));
224629088Smarkm	    printf("Terminal input:\n");
224729088Smarkm	    filestuff(tin);
224829088Smarkm	    printf("Terminal output:\n");
224929088Smarkm	    filestuff(tout);
225029088Smarkm	    printf("Network socket:\n");
225129088Smarkm	    filestuff(net);
225229088Smarkm	}
225329088Smarkm    }
225429088Smarkm    if (In3270 && transcom) {
225529088Smarkm       printf("Transparent mode command is '%s'.\n", transcom);
225629088Smarkm    }
225729088Smarkm#   endif /* defined(unix) */
225829088Smarkm    (void) fflush(stdout);
225929088Smarkm    if (In3270) {
226029088Smarkm	return 0;
226129088Smarkm    }
226229088Smarkm#   endif /* defined(TN3270) */
226329088Smarkm    return 1;
226429088Smarkm}
226529088Smarkm
226629088Smarkm#ifdef	SIGINFO
226729088Smarkm/*
226829088Smarkm * Function that gets called when SIGINFO is received.
226929088Smarkm */
227029181Smarkm	void
227129088Smarkmayt_status()
227229088Smarkm{
227329088Smarkm    (void) call(status, "status", "notmuch", 0);
227429088Smarkm}
227529088Smarkm#endif
227629088Smarkm
227756668Sshinstatic const char *
227856668Sshinsockaddr_ntop(sa)
227956668Sshin    struct sockaddr *sa;
228056668Sshin{
228156668Sshin    void *addr;
228256668Sshin    static char addrbuf[INET6_ADDRSTRLEN];
228329088Smarkm
228456668Sshin    switch (sa->sa_family) {
228556668Sshin    case AF_INET:
228656668Sshin	addr = &((struct sockaddr_in *)sa)->sin_addr;
228756668Sshin	break;
228856668Sshin#ifdef INET6
228956668Sshin    case AF_INET6:
229056668Sshin	addr = &((struct sockaddr_in6 *)sa)->sin6_addr;
229156668Sshin	break;
229256668Sshin#endif
229356668Sshin    default:
229456668Sshin	return NULL;
229556668Sshin    }
229656668Sshin    inet_ntop(sa->sa_family, addr, addrbuf, sizeof(addrbuf));
229756668Sshin    return addrbuf;
229856668Sshin}
229956668Sshin
230056668Sshin#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
230156668Sshinstatic int
230256668Sshinsetpolicy(net, res, policy)
230356668Sshin	int net;
230456668Sshin	struct addrinfo *res;
230556668Sshin	char *policy;
230656668Sshin{
230756668Sshin	char *buf;
230856668Sshin	int level;
230956668Sshin	int optname;
231056668Sshin
231156668Sshin	if (policy == NULL)
231256668Sshin		return 0;
231356668Sshin
231456668Sshin	buf = ipsec_set_policy(policy, strlen(policy));
231556668Sshin	if (buf == NULL) {
231656668Sshin		printf("%s\n", ipsec_strerror());
231756668Sshin		return -1;
231856668Sshin	}
231956668Sshin	level = res->ai_family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6;
232056668Sshin	optname = res->ai_family == AF_INET ? IP_IPSEC_POLICY : IPV6_IPSEC_POLICY;
232156668Sshin	if (setsockopt(net, level, optname, buf, ipsec_get_policylen(buf)) < 0){
232256668Sshin		perror("setsockopt");
232356668Sshin		return -1;
232456668Sshin	}
232556668Sshin
232656668Sshin	free(buf);
232756668Sshin}
232856668Sshin#endif
232956668Sshin
233057125Sshin#ifdef INET6
233157125Sshin/*
233257125Sshin * When an Address Family related error happend, check if retry with
233357125Sshin * another AF is possible or not.
233457125Sshin * Return 1, if retry with another af is OK. Else, return 0.
233557125Sshin */
233657125Sshinstatic int
233757125Sshinswitch_af(aip)
233857125Sshin    struct addrinfo **aip;
233957125Sshin{
234057125Sshin    int nextaf;
234157125Sshin    struct addrinfo *ai;
234257125Sshin
234357125Sshin    ai = *aip;
234457125Sshin    nextaf = (ai->ai_family == AF_INET) ? AF_INET6 : AF_INET;
234557125Sshin    do
234657125Sshin        ai=ai->ai_next;
234757125Sshin    while (ai != NULL && ai->ai_family != nextaf);
234857125Sshin    *aip = ai;
234957125Sshin    if (*aip != NULL) {
235057125Sshin        return 1;
235157125Sshin    }
235257125Sshin    return 0;
235357125Sshin}
235457125Sshin#endif
235557125Sshin
235629088Smarkm    int
235729088Smarkmtn(argc, argv)
235829088Smarkm    int argc;
235929088Smarkm    char *argv[];
236029088Smarkm{
236129088Smarkm    char *srp = 0, *strrchr();
236256668Sshin    int proto, opt;
236356668Sshin    int sourceroute(), srlen;
236456668Sshin    int srcroute = 0, result;
236529088Smarkm    char *cmd, *hostp = 0, *portp = 0, *user = 0;
236647973Sru    char *src_addr = NULL;
236757125Sshin    struct addrinfo hints, *res, *res0 = NULL, *src_res, *src_res0 = NULL;
236857125Sshin    int error = 0, af_error = 0;
236929088Smarkm
237029088Smarkm    if (connected) {
237129088Smarkm	printf("?Already connected to %s\n", hostname);
237229088Smarkm	setuid(getuid());
237329088Smarkm	return 0;
237429088Smarkm    }
237529088Smarkm    if (argc < 2) {
237629088Smarkm	(void) strcpy(line, "open ");
237729088Smarkm	printf("(to) ");
237829088Smarkm	(void) fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin);
237929088Smarkm	makeargv();
238029088Smarkm	argc = margc;
238129088Smarkm	argv = margv;
238229088Smarkm    }
238329088Smarkm    cmd = *argv;
238429088Smarkm    --argc; ++argv;
238529088Smarkm    while (argc) {
238629088Smarkm	if (strcmp(*argv, "help") == 0 || isprefix(*argv, "?"))
238729088Smarkm	    goto usage;
238829088Smarkm	if (strcmp(*argv, "-l") == 0) {
238929088Smarkm	    --argc; ++argv;
239029088Smarkm	    if (argc == 0)
239129088Smarkm		goto usage;
239229088Smarkm	    user = *argv++;
239329088Smarkm	    --argc;
239429088Smarkm	    continue;
239529088Smarkm	}
239629088Smarkm	if (strcmp(*argv, "-a") == 0) {
239729088Smarkm	    --argc; ++argv;
239829088Smarkm	    autologin = 1;
239929088Smarkm	    continue;
240029088Smarkm	}
240147973Sru	if (strcmp(*argv, "-s") == 0) {
240247973Sru	    --argc; ++argv;
240347973Sru	    if (argc == 0)
240447973Sru		goto usage;
240547973Sru	    src_addr = *argv++;
240647973Sru	    --argc;
240747973Sru	    continue;
240847973Sru	}
240929088Smarkm	if (hostp == 0) {
241029088Smarkm	    hostp = *argv++;
241129088Smarkm	    --argc;
241229088Smarkm	    continue;
241329088Smarkm	}
241429088Smarkm	if (portp == 0) {
241529088Smarkm	    portp = *argv++;
241629088Smarkm	    --argc;
241729088Smarkm	    continue;
241829088Smarkm	}
241929088Smarkm    usage:
242047973Sru	printf("usage: %s [-l user] [-a] [-s src_addr] host-name [port]\n", cmd);
242129088Smarkm	setuid(getuid());
242229088Smarkm	return 0;
242329088Smarkm    }
242429088Smarkm    if (hostp == 0)
242529088Smarkm	goto usage;
242629088Smarkm
242747973Sru    if (src_addr != NULL) {
242856668Sshin	memset(&hints, 0, sizeof(hints));
242956668Sshin	hints.ai_flags = AI_NUMERICHOST;
243056668Sshin	hints.ai_family = family;
243156668Sshin	hints.ai_socktype = SOCK_STREAM;
243257125Sshin	error = getaddrinfo(src_addr, 0, &hints, &src_res);
243362805Sume	if (error == EAI_NODATA) {
243456668Sshin		hints.ai_flags = 0;
243557125Sshin		error = getaddrinfo(src_addr, 0, &hints, &src_res);
243656668Sshin	}
243756668Sshin	if (error != 0) {
243856668Sshin		fprintf(stderr, "%s: %s\n", src_addr, gai_strerror(error));
243956668Sshin		if (error == EAI_SYSTEM)
244056668Sshin			fprintf(stderr, "%s: %s\n", src_addr, strerror(errno));
244157125Sshin		setuid(getuid());
244247973Sru		return 0;
244347973Sru	}
244457125Sshin	src_res0 = src_res;
244547973Sru    }
244629088Smarkm    if (hostp[0] == '@' || hostp[0] == '!') {
244756668Sshin	if (
244856668Sshin#ifdef INET6
244956668Sshin	    family == AF_INET6 ||
245056668Sshin#endif
245156668Sshin	    (hostname = strrchr(hostp, ':')) == NULL)
245229088Smarkm	    hostname = strrchr(hostp, '@');
245329088Smarkm	hostname++;
245456668Sshin	srcroute = 1;
245556668Sshin    } else
245656668Sshin        hostname = hostp;
245756668Sshin    if (!portp) {
245856668Sshin      telnetport = 1;
245956668Sshin      portp = "telnet";
246056668Sshin    } else if (*portp == '-') {
246156668Sshin      portp++;
246256668Sshin      telnetport = 1;
246356668Sshin    } else
246456668Sshin      telnetport = 0;
246556668Sshin
246656668Sshin    memset(&hints, 0, sizeof(hints));
246756668Sshin    hints.ai_flags = AI_NUMERICHOST;
246856668Sshin    hints.ai_family = family;
246956668Sshin    hints.ai_socktype = SOCK_STREAM;
247056668Sshin    error = getaddrinfo(hostname, portp, &hints, &res);
247162773Sitojun    if (error) {
247262773Sitojun        hints.ai_flags = AI_CANONNAME;
247362773Sitojun	error = getaddrinfo(hostname, portp, &hints, &res);
247462773Sitojun    }
247562773Sitojun    if (error != 0) {
247662773Sitojun	fprintf(stderr, "%s: %s\n", hostname, gai_strerror(error));
247762773Sitojun	if (error == EAI_SYSTEM)
247862773Sitojun	    fprintf(stderr, "%s: %s\n", hostname, strerror(errno));
247962773Sitojun	setuid(getuid());
248062773Sitojun	goto fail;
248162773Sitojun    }
248262773Sitojun    if (hints.ai_flags == AI_NUMERICHOST) {
248362773Sitojun	/* hostname has numeric */
248456668Sshin        int gni_err = 1;
248556668Sshin
248656668Sshin	if (doaddrlookup)
248756668Sshin	    gni_err = getnameinfo(res->ai_addr, res->ai_addr->sa_len,
248856668Sshin				  _hostname, sizeof(_hostname) - 1, NULL, 0,
248956870Sshin				  NI_NAMEREQD);
249056668Sshin	if (gni_err != 0)
249162773Sitojun	    (void) strncpy(_hostname, hostp, sizeof(_hostname) - 1);
249256668Sshin	_hostname[sizeof(_hostname)-1] = '\0';
249356668Sshin	hostname = _hostname;
249462773Sitojun    } else {
249562773Sitojun	/* hostname has FQDN */
249656668Sshin	if (srcroute != 0)
249756668Sshin	    (void) strncpy(_hostname, hostname, sizeof(_hostname) - 1);
249856668Sshin	else if (res->ai_canonname != NULL)
249956668Sshin	  strcpy(_hostname, res->ai_canonname);
250056668Sshin	else
250156668Sshin	  (void) strncpy(_hostname, hostp, sizeof(_hostname) - 1);
250256668Sshin	_hostname[sizeof(_hostname)-1] = '\0';
250356668Sshin	hostname = _hostname;
250456668Sshin    }
250557125Sshin    res0 = res;
250657233Sshin af_again:
250756668Sshin    if (srcroute != 0) {
250857343Sshin        static char hostbuf[BUFSIZ];
250957125Sshin
251057233Sshin	if (af_error == 0) { /* save intermediate hostnames for retry */
251157233Sshin		strncpy(hostbuf, hostp, BUFSIZ - 1);
251257233Sshin		hostbuf[BUFSIZ - 1] = '\0';
251357233Sshin	} else
251457125Sshin		hostp = hostbuf;
251529088Smarkm	srp = 0;
251656668Sshin	result = sourceroute(res, hostp, &srp, &srlen, &proto, &opt);
251756668Sshin	if (result == 0) {
251857125Sshin#ifdef INET6
251957125Sshin	    if (family == AF_UNSPEC && af_error == 0 &&
252057125Sshin		switch_af(&res) == 1) {
252157125Sshin	        af_error = 1;
252257125Sshin		goto af_again;
252357125Sshin	    }
252457125Sshin#endif
252529088Smarkm	    setuid(getuid());
252657125Sshin	    goto fail;
252756668Sshin	} else if (result == -1) {
252829088Smarkm	    printf("Bad source route option: %s\n", hostp);
252929088Smarkm	    setuid(getuid());
253057125Sshin	    goto fail;
253129088Smarkm	}
253229088Smarkm    }
253329088Smarkm    do {
253457342Sshin        printf("Trying %s...\n", sockaddr_ntop(res->ai_addr));
253556668Sshin	net = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
253629088Smarkm	setuid(getuid());
253729088Smarkm	if (net < 0) {
253857125Sshin#ifdef INET6
253957125Sshin	    if (family == AF_UNSPEC && af_error == 0 &&
254057125Sshin		switch_af(&res) == 1) {
254157125Sshin	        af_error = 1;
254257125Sshin		goto af_again;
254357125Sshin	    }
254457125Sshin#endif
254529088Smarkm	    perror("telnet: socket");
254657125Sshin	    goto fail;
254729088Smarkm	}
254856668Sshin	if (srp && setsockopt(net, proto, opt, (char *)srp, srlen) < 0)
254956668Sshin		perror("setsockopt (source route)");
255029088Smarkm#if	defined(IPPROTO_IP) && defined(IP_TOS)
255156668Sshin	if (res->ai_family == PF_INET) {
255229088Smarkm# if	defined(HAS_GETTOS)
255329088Smarkm	    struct tosent *tp;
255429088Smarkm	    if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
255529088Smarkm		tos = tp->t_tos;
255629088Smarkm# endif
255729088Smarkm	    if (tos < 0)
255829088Smarkm		tos = 020;	/* Low Delay bit */
255929088Smarkm	    if (tos
256029088Smarkm		&& (setsockopt(net, IPPROTO_IP, IP_TOS,
256129088Smarkm		    (char *)&tos, sizeof(int)) < 0)
256229088Smarkm		&& (errno != ENOPROTOOPT))
256329088Smarkm		    perror("telnet: setsockopt (IP_TOS) (ignored)");
256429088Smarkm	}
256529088Smarkm#endif	/* defined(IPPROTO_IP) && defined(IP_TOS) */
256629088Smarkm
256729088Smarkm	if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) {
256829088Smarkm		perror("setsockopt (SO_DEBUG)");
256929088Smarkm	}
257029088Smarkm
257147973Sru	if (src_addr != NULL) {
257257125Sshin	    for (src_res = src_res0; src_res != 0; src_res = src_res->ai_next)
257357233Sshin	        if (src_res->ai_family == res->ai_family)
257457233Sshin		    break;
257557125Sshin	    if (src_res == NULL)
257657125Sshin		src_res = src_res0;
257757125Sshin	    if (bind(net, src_res->ai_addr, src_res->ai_addrlen) == -1) {
257857125Sshin#ifdef INET6
257957125Sshin	        if (family == AF_UNSPEC && af_error == 0 &&
258057125Sshin		    switch_af(&res) == 1) {
258157125Sshin		    af_error = 1;
258257233Sshin		    (void) NetClose(net);
258357125Sshin		    goto af_again;
258457125Sshin		}
258557125Sshin#endif
258647973Sru		perror("bind");
258757233Sshin		(void) NetClose(net);
258857125Sshin		goto fail;
258947973Sru	    }
259047973Sru	}
259156668Sshin#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
259257233Sshin	if (setpolicy(net, res, ipsec_policy_in) < 0) {
259357233Sshin		(void) NetClose(net);
259457125Sshin		goto fail;
259557233Sshin	}
259657233Sshin	if (setpolicy(net, res, ipsec_policy_out) < 0) {
259757233Sshin		(void) NetClose(net);
259857125Sshin		goto fail;
259957233Sshin	}
260056668Sshin#endif
260147973Sru
260256668Sshin	if (connect(net, res->ai_addr, res->ai_addrlen) < 0) {
260357125Sshin	    struct addrinfo *next;
260457125Sshin
260557125Sshin	    next = res->ai_next;
260657125Sshin	    /* If already an af failed, only try same af. */
260757125Sshin	    if (af_error != 0)
260857125Sshin		while (next != NULL && next->ai_family != res->ai_family)
260957125Sshin		    next = next->ai_next;
261057342Sshin	    warn("connect to address %s", sockaddr_ntop(res->ai_addr));
261157125Sshin	    if (next != NULL) {
261257125Sshin		res = next;
261329088Smarkm		(void) NetClose(net);
261429088Smarkm		continue;
261529088Smarkm	    }
261657342Sshin	    warnx("Unable to connect to remote host");
261757233Sshin	    (void) NetClose(net);
261857125Sshin	    goto fail;
261929088Smarkm	}
262029088Smarkm	connected++;
262129088Smarkm#if	defined(AUTHENTICATION) || defined(ENCRYPTION)
262229088Smarkm	auth_encrypt_connect(connected);
262329088Smarkm#endif	/* defined(AUTHENTICATION) || defined(ENCRYPTION) */
262429088Smarkm    } while (connected == 0);
262557125Sshin    freeaddrinfo(res0);
262657125Sshin    if (src_res0 != NULL)
262757125Sshin        freeaddrinfo(src_res0);
262829088Smarkm    cmdrc(hostp, hostname);
262929088Smarkm    if (autologin && user == NULL) {
263029088Smarkm	struct passwd *pw;
263129088Smarkm
263229088Smarkm	user = getenv("USER");
263329088Smarkm	if (user == NULL ||
263429181Smarkm	    ((pw = getpwnam(user)) && pw->pw_uid != getuid())) {
263529181Smarkm		if ((pw = getpwuid(getuid())))
263629088Smarkm			user = pw->pw_name;
263729088Smarkm		else
263829088Smarkm			user = NULL;
263929088Smarkm	}
264029088Smarkm    }
264129088Smarkm    if (user) {
264229088Smarkm	env_define((unsigned char *)"USER", (unsigned char *)user);
264329088Smarkm	env_export((unsigned char *)"USER");
264429088Smarkm    }
264529088Smarkm    (void) call(status, "status", "notmuch", 0);
264629088Smarkm    if (setjmp(peerdied) == 0)
264729088Smarkm	telnet(user);
264829088Smarkm    (void) NetClose(net);
264929088Smarkm    ExitString("Connection closed by foreign host.\n",1);
265029088Smarkm    /*NOTREACHED*/
265157125Sshin fail:
265257125Sshin    if (res0 != NULL)
265357125Sshin        freeaddrinfo(res0);
265457125Sshin    if (src_res0 != NULL)
265557125Sshin        freeaddrinfo(src_res0);
265657125Sshin    return 0;
265729088Smarkm}
265829088Smarkm
265929088Smarkm#define HELPINDENT (sizeof ("connect"))
266029088Smarkm
266129088Smarkmstatic char
266229088Smarkm	openhelp[] =	"connect to a site",
266329088Smarkm	closehelp[] =	"close current connection",
266429088Smarkm	logouthelp[] =	"forcibly logout remote user and close the connection",
266529088Smarkm	quithelp[] =	"exit telnet",
266629088Smarkm	statushelp[] =	"print status information",
266729088Smarkm	helphelp[] =	"print help information",
266829088Smarkm	sendhelp[] =	"transmit special characters ('send ?' for more)",
266929088Smarkm	sethelp[] = 	"set operating parameters ('set ?' for more)",
267029088Smarkm	unsethelp[] = 	"unset operating parameters ('unset ?' for more)",
267129088Smarkm	togglestring[] ="toggle operating parameters ('toggle ?' for more)",
267229088Smarkm	slchelp[] =	"change state of special charaters ('slc ?' for more)",
267329088Smarkm	displayhelp[] =	"display operating parameters",
267429088Smarkm#if	defined(TN3270) && defined(unix)
267529088Smarkm	transcomhelp[] = "specify Unix command for transparent mode pipe",
267629088Smarkm#endif	/* defined(TN3270) && defined(unix) */
267729088Smarkm#if	defined(AUTHENTICATION)
267829088Smarkm	authhelp[] =	"turn on (off) authentication ('auth ?' for more)",
267929088Smarkm#endif
268029088Smarkm#ifdef	ENCRYPTION
268129088Smarkm	encrypthelp[] =	"turn on (off) encryption ('encrypt ?' for more)",
268229088Smarkm#endif	/* ENCRYPTION */
268329088Smarkm#if	defined(unix)
268429088Smarkm	zhelp[] =	"suspend telnet",
268529088Smarkm#endif	/* defined(unix) */
268629181Smarkm#if	defined(SKEY)
268729181Smarkm	skeyhelp[] =    "compute response to s/key challenge",
268829181Smarkm#endif
268929088Smarkm	shellhelp[] =	"invoke a subshell",
269029088Smarkm	envhelp[] =	"change environment variables ('environ ?' for more)",
269129088Smarkm	modestring[] = "try to enter line or character mode ('mode ?' for more)";
269229088Smarkm
269329088Smarkmstatic Command cmdtab[] = {
269429088Smarkm	{ "close",	closehelp,	bye,		1 },
269529088Smarkm	{ "logout",	logouthelp,	logout,		1 },
269629088Smarkm	{ "display",	displayhelp,	display,	0 },
269729088Smarkm	{ "mode",	modestring,	modecmd,	0 },
269829088Smarkm	{ "open",	openhelp,	tn,		0 },
269929088Smarkm	{ "quit",	quithelp,	quit,		0 },
270029088Smarkm	{ "send",	sendhelp,	sendcmd,	0 },
270129088Smarkm	{ "set",	sethelp,	setcmd,		0 },
270229088Smarkm	{ "unset",	unsethelp,	unsetcmd,	0 },
270329088Smarkm	{ "status",	statushelp,	status,		0 },
270429088Smarkm	{ "toggle",	togglestring,	toggle,		0 },
270529088Smarkm	{ "slc",	slchelp,	slccmd,		0 },
270629088Smarkm#if	defined(TN3270) && defined(unix)
270729088Smarkm	{ "transcom",	transcomhelp,	settranscom,	0 },
270829088Smarkm#endif	/* defined(TN3270) && defined(unix) */
270929088Smarkm#if	defined(AUTHENTICATION)
271029088Smarkm	{ "auth",	authhelp,	auth_cmd,	0 },
271129088Smarkm#endif
271229088Smarkm#ifdef	ENCRYPTION
271329088Smarkm	{ "encrypt",	encrypthelp,	encrypt_cmd,	0 },
271429088Smarkm#endif	/* ENCRYPTION */
271529088Smarkm#if	defined(unix)
271629088Smarkm	{ "z",		zhelp,		suspend,	0 },
271729088Smarkm#endif	/* defined(unix) */
271829088Smarkm#if	defined(TN3270)
271929088Smarkm	{ "!",		shellhelp,	shell,		1 },
272029088Smarkm#else
272129088Smarkm	{ "!",		shellhelp,	shell,		0 },
272229088Smarkm#endif
272329088Smarkm	{ "environ",	envhelp,	env_cmd,	0 },
272429088Smarkm	{ "?",		helphelp,	help,		0 },
272529181Smarkm#if	defined(SKEY)
272629181Smarkm	{ "skey",       skeyhelp,       skey_calc,      0 },
272729181Smarkm#endif
272829181Smarkm	{ 0, 0, 0, 0 }
272929088Smarkm};
273029088Smarkm
273129088Smarkmstatic char	crmodhelp[] =	"deprecated command -- use 'toggle crmod' instead";
273229088Smarkmstatic char	escapehelp[] =	"deprecated command -- use 'set escape' instead";
273329088Smarkm
273429088Smarkmstatic Command cmdtab2[] = {
273529088Smarkm	{ "help",	0,		help,		0 },
273629088Smarkm	{ "escape",	escapehelp,	setescape,	0 },
273729088Smarkm	{ "crmod",	crmodhelp,	togcrmod,	0 },
273829181Smarkm	{ 0, 0, 0, 0 }
273929088Smarkm};
274029088Smarkm
274129088Smarkm
274229088Smarkm/*
274329088Smarkm * Call routine with argc, argv set from args (terminated by 0).
274429088Smarkm */
274529088Smarkm
274629088Smarkm    /*VARARGS1*/
274729181Smarkm    static int
274829088Smarkmcall(va_alist)
274929088Smarkm    va_dcl
275029088Smarkm{
275129088Smarkm    va_list ap;
275229088Smarkm    typedef int (*intrtn_t)();
275329088Smarkm    intrtn_t routine;
275429088Smarkm    char *args[100];
275529088Smarkm    int argno = 0;
275629088Smarkm
275729088Smarkm    va_start(ap);
275829088Smarkm    routine = (va_arg(ap, intrtn_t));
275929088Smarkm    while ((args[argno++] = va_arg(ap, char *)) != 0) {
276029088Smarkm	;
276129088Smarkm    }
276229088Smarkm    va_end(ap);
276329088Smarkm    return (*routine)(argno-1, args);
276429088Smarkm}
276529088Smarkm
276629088Smarkm
276729088Smarkm    static Command *
276829088Smarkmgetcmd(name)
276929088Smarkm    char *name;
277029088Smarkm{
277129088Smarkm    Command *cm;
277229088Smarkm
277329181Smarkm    if ((cm = (Command *) genget(name, (char **) cmdtab, sizeof(Command))))
277429088Smarkm	return cm;
277529088Smarkm    return (Command *) genget(name, (char **) cmdtab2, sizeof(Command));
277629088Smarkm}
277729088Smarkm
277829088Smarkm    void
277929088Smarkmcommand(top, tbuf, cnt)
278029088Smarkm    int top;
278129088Smarkm    char *tbuf;
278229088Smarkm    int cnt;
278329088Smarkm{
278429088Smarkm    register Command *c;
278529088Smarkm
278629088Smarkm    setcommandmode();
278729088Smarkm    if (!top) {
278829088Smarkm	putchar('\n');
278929088Smarkm#if	defined(unix)
279029088Smarkm    } else {
279129088Smarkm	(void) signal(SIGINT, SIG_DFL);
279229088Smarkm	(void) signal(SIGQUIT, SIG_DFL);
279329088Smarkm#endif	/* defined(unix) */
279429088Smarkm    }
279529088Smarkm    for (;;) {
279629088Smarkm	if (rlogin == _POSIX_VDISABLE)
279729088Smarkm		printf("%s> ", prompt);
279829088Smarkm	if (tbuf) {
279929088Smarkm	    register char *cp;
280029088Smarkm	    cp = line;
280129088Smarkm	    while (cnt > 0 && (*cp++ = *tbuf++) != '\n')
280229088Smarkm		cnt--;
280329088Smarkm	    tbuf = 0;
280429088Smarkm	    if (cp == line || *--cp != '\n' || cp == line)
280529088Smarkm		goto getline;
280629088Smarkm	    *cp = '\0';
280729088Smarkm	    if (rlogin == _POSIX_VDISABLE)
280829088Smarkm		printf("%s\n", line);
280929088Smarkm	} else {
281029088Smarkm	getline:
281129088Smarkm	    if (rlogin != _POSIX_VDISABLE)
281229088Smarkm		printf("%s> ", prompt);
281329088Smarkm	    if (fgets(line, sizeof(line), stdin) == NULL) {
281429088Smarkm		if (feof(stdin) || ferror(stdin)) {
281529088Smarkm		    (void) quit();
281629088Smarkm		    /*NOTREACHED*/
281729088Smarkm		}
281829088Smarkm		break;
281929088Smarkm	    }
282029088Smarkm	}
282129088Smarkm	if (line[0] == 0)
282229088Smarkm	    break;
282329088Smarkm	makeargv();
282429088Smarkm	if (margv[0] == 0) {
282529088Smarkm	    break;
282629088Smarkm	}
282729088Smarkm	c = getcmd(margv[0]);
282829088Smarkm	if (Ambiguous(c)) {
282929088Smarkm	    printf("?Ambiguous command\n");
283029088Smarkm	    continue;
283129088Smarkm	}
283229088Smarkm	if (c == 0) {
283329088Smarkm	    printf("?Invalid command\n");
283429088Smarkm	    continue;
283529088Smarkm	}
283629088Smarkm	if (c->needconnect && !connected) {
283729088Smarkm	    printf("?Need to be connected first.\n");
283829088Smarkm	    continue;
283929088Smarkm	}
284029088Smarkm	if ((*c->handler)(margc, margv)) {
284129088Smarkm	    break;
284229088Smarkm	}
284329088Smarkm    }
284429088Smarkm    if (!top) {
284529088Smarkm	if (!connected) {
284629088Smarkm	    longjmp(toplevel, 1);
284729088Smarkm	    /*NOTREACHED*/
284829088Smarkm	}
284929088Smarkm#if	defined(TN3270)
285029088Smarkm	if (shell_active == 0) {
285129088Smarkm	    setconnmode(0);
285229088Smarkm	}
285329088Smarkm#else	/* defined(TN3270) */
285429088Smarkm	setconnmode(0);
285529088Smarkm#endif	/* defined(TN3270) */
285629088Smarkm    }
285729088Smarkm}
285829088Smarkm
285929088Smarkm/*
286029088Smarkm * Help command.
286129088Smarkm */
286229181Smarkm	static int
286329088Smarkmhelp(argc, argv)
286429088Smarkm	int argc;
286529088Smarkm	char *argv[];
286629088Smarkm{
286729088Smarkm	register Command *c;
286829088Smarkm
286929088Smarkm	if (argc == 1) {
287029088Smarkm		printf("Commands may be abbreviated.  Commands are:\n\n");
287129088Smarkm		for (c = cmdtab; c->name; c++)
287229088Smarkm			if (c->help) {
287329088Smarkm				printf("%-*s\t%s\n", HELPINDENT, c->name,
287429088Smarkm								    c->help);
287529088Smarkm			}
287629088Smarkm	}
287729181Smarkm	else while (--argc > 0) {
287829088Smarkm		register char *arg;
287929088Smarkm		arg = *++argv;
288029088Smarkm		c = getcmd(arg);
288129088Smarkm		if (Ambiguous(c))
288229088Smarkm			printf("?Ambiguous help command %s\n", arg);
288329088Smarkm		else if (c == (Command *)0)
288429088Smarkm			printf("?Invalid help command %s\n", arg);
288529088Smarkm		else
288629088Smarkm			printf("%s\n", c->help);
288729088Smarkm	}
288829181Smarkm	return(0);
288929088Smarkm}
289029088Smarkm
289129088Smarkmstatic char *rcname = 0;
289229088Smarkmstatic char rcbuf[128];
289329088Smarkm
289429181Smarkm	void
289529088Smarkmcmdrc(m1, m2)
289629088Smarkm	char *m1, *m2;
289729088Smarkm{
289829088Smarkm    register Command *c;
289929088Smarkm    FILE *rcfile;
290029088Smarkm    int gotmachine = 0;
290129088Smarkm    int l1 = strlen(m1);
290229088Smarkm    int l2 = strlen(m2);
290329088Smarkm    char m1save[64];
290429088Smarkm
290529088Smarkm    if (skiprc)
290629088Smarkm	return;
290729088Smarkm
290829088Smarkm    strcpy(m1save, m1);
290929088Smarkm    m1 = m1save;
291029088Smarkm
291129088Smarkm    if (rcname == 0) {
291229088Smarkm	rcname = getenv("HOME");
291329181Smarkm	if (rcname && (strlen(rcname) + 10) < sizeof(rcbuf))
291429088Smarkm	    strcpy(rcbuf, rcname);
291529088Smarkm	else
291629088Smarkm	    rcbuf[0] = '\0';
291729088Smarkm	strcat(rcbuf, "/.telnetrc");
291829088Smarkm	rcname = rcbuf;
291929088Smarkm    }
292029088Smarkm
292129088Smarkm    if ((rcfile = fopen(rcname, "r")) == 0) {
292229088Smarkm	return;
292329088Smarkm    }
292429088Smarkm
292529088Smarkm    for (;;) {
292629088Smarkm	if (fgets(line, sizeof(line), rcfile) == NULL)
292729088Smarkm	    break;
292829088Smarkm	if (line[0] == 0)
292929088Smarkm	    break;
293029088Smarkm	if (line[0] == '#')
293129088Smarkm	    continue;
293229088Smarkm	if (gotmachine) {
293329088Smarkm	    if (!isspace(line[0]))
293429088Smarkm		gotmachine = 0;
293529088Smarkm	}
293629088Smarkm	if (gotmachine == 0) {
293729088Smarkm	    if (isspace(line[0]))
293829088Smarkm		continue;
293929088Smarkm	    if (strncasecmp(line, m1, l1) == 0)
294029088Smarkm		strncpy(line, &line[l1], sizeof(line) - l1);
294129088Smarkm	    else if (strncasecmp(line, m2, l2) == 0)
294229088Smarkm		strncpy(line, &line[l2], sizeof(line) - l2);
294329088Smarkm	    else if (strncasecmp(line, "DEFAULT", 7) == 0)
294429088Smarkm		strncpy(line, &line[7], sizeof(line) - 7);
294529088Smarkm	    else
294629088Smarkm		continue;
294729088Smarkm	    if (line[0] != ' ' && line[0] != '\t' && line[0] != '\n')
294829088Smarkm		continue;
294929088Smarkm	    gotmachine = 1;
295029088Smarkm	}
295129088Smarkm	makeargv();
295229088Smarkm	if (margv[0] == 0)
295329088Smarkm	    continue;
295429088Smarkm	c = getcmd(margv[0]);
295529088Smarkm	if (Ambiguous(c)) {
295629088Smarkm	    printf("?Ambiguous command: %s\n", margv[0]);
295729088Smarkm	    continue;
295829088Smarkm	}
295929088Smarkm	if (c == 0) {
296029088Smarkm	    printf("?Invalid command: %s\n", margv[0]);
296129088Smarkm	    continue;
296229088Smarkm	}
296329088Smarkm	/*
296429088Smarkm	 * This should never happen...
296529088Smarkm	 */
296629088Smarkm	if (c->needconnect && !connected) {
296729088Smarkm	    printf("?Need to be connected first for %s.\n", margv[0]);
296829088Smarkm	    continue;
296929088Smarkm	}
297029088Smarkm	(*c->handler)(margc, margv);
297129088Smarkm    }
297229088Smarkm    fclose(rcfile);
297329088Smarkm}
297429088Smarkm
297529088Smarkm/*
297629088Smarkm * Source route is handed in as
297729088Smarkm *	[!]@hop1@hop2...[@|:]dst
297829088Smarkm * If the leading ! is present, it is a
297929088Smarkm * strict source route, otherwise it is
298029088Smarkm * assmed to be a loose source route.
298129088Smarkm *
298229088Smarkm * We fill in the source route option as
298329088Smarkm *	hop1,hop2,hop3...dest
298429088Smarkm * and return a pointer to hop1, which will
298529088Smarkm * be the address to connect() to.
298629088Smarkm *
298729088Smarkm * Arguments:
298856668Sshin *
298956668Sshin *	res:	ponter to addrinfo structure which contains sockaddr to
299056668Sshin *		the host to connect to.
299156668Sshin *
299229088Smarkm *	arg:	pointer to route list to decipher
299329088Smarkm *
299429088Smarkm *	cpp: 	If *cpp is not equal to NULL, this is a
299529088Smarkm *		pointer to a pointer to a character array
299629088Smarkm *		that should be filled in with the option.
299729088Smarkm *
299829088Smarkm *	lenp:	pointer to an integer that contains the
299929088Smarkm *		length of *cpp if *cpp != NULL.
300029088Smarkm *
300156668Sshin *	protop:	pointer to an integer that should be filled in with
300256668Sshin *		appropriate protocol for setsockopt, as socket
300356668Sshin *		protocol family.
300456668Sshin *
300556668Sshin *	optp:	pointer to an integer that should be filled in with
300656668Sshin *		appropriate option for setsockopt, as socket protocol
300756668Sshin *		family.
300856668Sshin *
300929088Smarkm * Return values:
301029088Smarkm *
301156668Sshin *	If the return value is 1, then all operations are
301256668Sshin *	successful. If the
301329088Smarkm *	return value is -1, there was a syntax error in the
301429088Smarkm *	option, either unknown characters, or too many hosts.
301529088Smarkm *	If the return value is 0, one of the hostnames in the
301629088Smarkm *	path is unknown, and *cpp is set to point to the bad
301729088Smarkm *	hostname.
301829088Smarkm *
301929088Smarkm *	*cpp:	If *cpp was equal to NULL, it will be filled
302029088Smarkm *		in with a pointer to our static area that has
302129088Smarkm *		the option filled in.  This will be 32bit aligned.
302229088Smarkm *
302329088Smarkm *	*lenp:	This will be filled in with how long the option
302429088Smarkm *		pointed to by *cpp is.
302529088Smarkm *
302656668Sshin *	*protop: This will be filled in with appropriate protocol for
302756668Sshin *		 setsockopt, as socket protocol family.
302856668Sshin *
302956668Sshin *	*optp:	This will be filled in with appropriate option for
303056668Sshin *		setsockopt, as socket protocol family.
303129088Smarkm */
303256668Sshinint
303356668Sshinsourceroute(ai, arg, cpp, lenp, protop, optp)
303456668Sshin	struct addrinfo *ai;
303529088Smarkm	char	*arg;
303629088Smarkm	char	**cpp;
303729088Smarkm	int	*lenp;
303856668Sshin	int	*protop;
303956668Sshin	int	*optp;
304029088Smarkm{
304163662Sume	static char buf[1024 + ALIGNBYTES];	/*XXX*/
304256668Sshin	struct cmsghdr *cmsg;
304329088Smarkm#ifdef	sysV88
304429088Smarkm	static IOPTN ipopt;
304529088Smarkm#endif
304656668Sshin	char *cp, *cp2, *lsrp, *ep;
304729088Smarkm	register int tmp;
304856668Sshin	struct sockaddr_in *sin;
304956668Sshin	struct sockaddr_in6 *sin6;
305056668Sshin	struct addrinfo hints, *res;
305156668Sshin	int error;
305229088Smarkm	register char c;
305329088Smarkm
305429088Smarkm	/*
305529088Smarkm	 * Verify the arguments, and make sure we have
305629088Smarkm	 * at least 7 bytes for the option.
305729088Smarkm	 */
305829088Smarkm	if (cpp == NULL || lenp == NULL)
305957724Sshin		return -1;
306056668Sshin	if (*cpp != NULL) {
306156668Sshin		switch (res->ai_family) {
306256668Sshin		case AF_INET:
306356668Sshin			if (*lenp < 7)
306457724Sshin				return -1;
306556668Sshin			break;
306656668Sshin#ifdef INET6
306756668Sshin		case AF_INET6:
306857724Sshin			if (*lenp < CMSG_SPACE(sizeof(struct ip6_rthdr) +
306957724Sshin				               sizeof(struct in6_addr)))
307057724Sshin				return -1;
307156668Sshin			break;
307256668Sshin#endif
307356668Sshin		}
307456668Sshin	}
307529088Smarkm	/*
307629088Smarkm	 * Decide whether we have a buffer passed to us,
307729088Smarkm	 * or if we need to use our own static buffer.
307829088Smarkm	 */
307929088Smarkm	if (*cpp) {
308029088Smarkm		lsrp = *cpp;
308156668Sshin		ep = lsrp + *lenp;
308229088Smarkm	} else {
308363662Sume		*cpp = lsrp = (char *)ALIGN(buf);
308456668Sshin		ep = lsrp + 1024;
308529088Smarkm	}
308629088Smarkm
308729088Smarkm	cp = arg;
308829088Smarkm
308956668Sshin#ifdef INET6
309056668Sshin	if (ai->ai_family == AF_INET6) {
309156668Sshin		cmsg = inet6_rthdr_init(*cpp, IPV6_RTHDR_TYPE_0);
309256668Sshin		if (*cp != '@')
309356668Sshin			return -1;
309456668Sshin		*protop = IPPROTO_IPV6;
309556668Sshin		*optp = IPV6_PKTOPTIONS;
309656668Sshin	} else
309756668Sshin#endif
309856668Sshin      {
309929088Smarkm	/*
310029088Smarkm	 * Next, decide whether we have a loose source
310129088Smarkm	 * route or a strict source route, and fill in
310229088Smarkm	 * the begining of the option.
310329088Smarkm	 */
310429088Smarkm#ifndef	sysV88
310529088Smarkm	if (*cp == '!') {
310629088Smarkm		cp++;
310729088Smarkm		*lsrp++ = IPOPT_SSRR;
310829088Smarkm	} else
310929088Smarkm		*lsrp++ = IPOPT_LSRR;
311029088Smarkm#else
311129088Smarkm	if (*cp == '!') {
311229088Smarkm		cp++;
311329088Smarkm		ipopt.io_type = IPOPT_SSRR;
311429088Smarkm	} else
311529088Smarkm		ipopt.io_type = IPOPT_LSRR;
311629088Smarkm#endif
311729088Smarkm
311829088Smarkm	if (*cp != '@')
311957724Sshin		return -1;
312029088Smarkm
312129088Smarkm#ifndef	sysV88
312229088Smarkm	lsrp++;		/* skip over length, we'll fill it in later */
312329088Smarkm	*lsrp++ = 4;
312429088Smarkm#endif
312556668Sshin	*protop = IPPROTO_IP;
312656668Sshin	*optp = IP_OPTIONS;
312756668Sshin      }
312829088Smarkm
312929088Smarkm	cp++;
313056668Sshin	memset(&hints, 0, sizeof(hints));
313156668Sshin	hints.ai_family = ai->ai_family;
313256668Sshin	hints.ai_socktype = SOCK_STREAM;
313329088Smarkm	for (c = 0;;) {
313456668Sshin		if (
313556668Sshin#ifdef INET6
313656668Sshin		    ai->ai_family != AF_INET6 &&
313756668Sshin#endif
313856668Sshin		    c == ':')
313929088Smarkm			cp2 = 0;
314029181Smarkm		else for (cp2 = cp; (c = *cp2); cp2++) {
314129088Smarkm			if (c == ',') {
314229088Smarkm				*cp2++ = '\0';
314329088Smarkm				if (*cp2 == '@')
314429088Smarkm					cp2++;
314529088Smarkm			} else if (c == '@') {
314629088Smarkm				*cp2++ = '\0';
314756668Sshin			} else if (
314856668Sshin#ifdef INET6
314956668Sshin				   ai->ai_family != AF_INET6 &&
315056668Sshin#endif
315156668Sshin				   c == ':') {
315229088Smarkm				*cp2++ = '\0';
315329088Smarkm			} else
315429088Smarkm				continue;
315529088Smarkm			break;
315629088Smarkm		}
315729088Smarkm		if (!c)
315829088Smarkm			cp2 = 0;
315929088Smarkm
316056668Sshin		hints.ai_flags = AI_NUMERICHOST;
316156668Sshin 		error = getaddrinfo(cp, NULL, &hints, &res);
316262805Sume		if (error == EAI_NODATA) {
316356668Sshin			hints.ai_flags = 0;
316456668Sshin			error = getaddrinfo(cp, NULL, &hints, &res);
316556668Sshin		}
316656668Sshin		if (error != 0) {
316756668Sshin			fprintf(stderr, "%s: %s\n", cp, gai_strerror(error));
316856668Sshin			if (error == EAI_SYSTEM)
316956668Sshin				fprintf(stderr, "%s: %s\n", cp,
317056668Sshin					strerror(errno));
317129088Smarkm			*cpp = cp;
317229088Smarkm			return(0);
317329088Smarkm		}
317456668Sshin#ifdef INET6
317556668Sshin		if (res->ai_family == AF_INET6) {
317656668Sshin			sin6 = (struct sockaddr_in6 *)res->ai_addr;
317756668Sshin			inet6_rthdr_add(cmsg, &sin6->sin6_addr,
317856668Sshin					IPV6_RTHDR_LOOSE);
317956668Sshin		} else
318056668Sshin#endif
318156668Sshin	      {
318256668Sshin		sin = (struct sockaddr_in *)res->ai_addr;
318356668Sshin		memcpy(lsrp, (char *)&sin->sin_addr, 4);
318429088Smarkm		lsrp += 4;
318556668Sshin	      }
318629088Smarkm		if (cp2)
318729088Smarkm			cp = cp2;
318829088Smarkm		else
318929088Smarkm			break;
319029088Smarkm		/*
319129088Smarkm		 * Check to make sure there is space for next address
319229088Smarkm		 */
319356668Sshin#ifdef INET6
319456668Sshin		if (res->ai_family == AF_INET6) {
319557724Sshin			if (((char *)CMSG_DATA(cmsg) +
319656668Sshin			     sizeof(struct ip6_rthdr) +
319756668Sshin			     ((inet6_rthdr_segments(cmsg) + 1) *
319856668Sshin			      sizeof(struct in6_addr))) > ep)
319957724Sshin			return -1;
320056668Sshin		} else
320156668Sshin#endif
320256668Sshin		if (lsrp + 4 > ep)
320357724Sshin			return -1;
320456668Sshin		freeaddrinfo(res);
320529088Smarkm	}
320656668Sshin#ifdef INET6
320756668Sshin	if (res->ai_family == AF_INET6) {
320856668Sshin		inet6_rthdr_lasthop(cmsg, IPV6_RTHDR_LOOSE);
320956668Sshin		*lenp = cmsg->cmsg_len;
321056668Sshin	} else
321156668Sshin#endif
321256668Sshin      {
321329088Smarkm#ifndef	sysV88
321429088Smarkm	if ((*(*cpp+IPOPT_OLEN) = lsrp - *cpp) <= 7) {
321529088Smarkm		*cpp = 0;
321629088Smarkm		*lenp = 0;
321757724Sshin		return -1;
321829088Smarkm	}
321929088Smarkm	*lsrp++ = IPOPT_NOP; /* 32 bit word align it */
322029088Smarkm	*lenp = lsrp - *cpp;
322129088Smarkm#else
322229088Smarkm	ipopt.io_len = lsrp - *cpp;
322329088Smarkm	if (ipopt.io_len <= 5) {		/* Is 3 better ? */
322429088Smarkm		*cpp = 0;
322529088Smarkm		*lenp = 0;
322657724Sshin		return -1;
322729088Smarkm	}
322829088Smarkm	*lenp = sizeof(ipopt);
322929088Smarkm	*cpp = (char *) &ipopt;
323029088Smarkm#endif
323156668Sshin      }
323256668Sshin	freeaddrinfo(res);
323356668Sshin	return 1;
323429088Smarkm}
323556668Sshin
323656668Sshin
323756668Sshin
3238