commands.c revision 77095
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 77095 2001-05-23 22:54:07Z dillon $
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>
4277095Sdillon#include <sys/un.h>
4329088Smarkm#if	defined(CRAY) || defined(sysV88)
4429088Smarkm#include <sys/types.h>
4529088Smarkm#endif
4629088Smarkm#include <sys/file.h>
4729088Smarkm#else
4829088Smarkm#include <sys/types.h>
4929088Smarkm#endif	/* defined(unix) */
5029088Smarkm#include <sys/socket.h>
5129088Smarkm#include <netinet/in.h>
5229088Smarkm#ifdef	CRAY
5329088Smarkm#include <fcntl.h>
5429088Smarkm#endif	/* CRAY */
5529088Smarkm
5629088Smarkm#include <signal.h>
5729088Smarkm#include <netdb.h>
5829088Smarkm#include <ctype.h>
5929088Smarkm#include <pwd.h>
6029088Smarkm#include <varargs.h>
6129088Smarkm#include <errno.h>
6229181Smarkm#include <unistd.h>
6329181Smarkm#include <stdlib.h>
6429088Smarkm
6529088Smarkm#include <arpa/telnet.h>
6629088Smarkm
6729088Smarkm#include "general.h"
6829088Smarkm
6929088Smarkm#include "ring.h"
7029088Smarkm
7129088Smarkm#include "externs.h"
7229088Smarkm#include "defines.h"
7329088Smarkm#include "types.h"
7429088Smarkm
7529181Smarkm#if	defined(AUTHENTICATION)
7629181Smarkm#include <libtelnet/auth.h>
7729181Smarkm#endif
7829181Smarkm#if	defined(ENCRYPTION)
7929181Smarkm#include <libtelnet/encrypt.h>
8029181Smarkm#endif
8129181Smarkm
8229088Smarkm#if !defined(CRAY) && !defined(sysV88)
8329088Smarkm#include <netinet/in_systm.h>
8429088Smarkm# if (defined(vax) || defined(tahoe) || defined(hp300)) && !defined(ultrix)
8529088Smarkm# include <machine/endian.h>
8629088Smarkm# endif /* vax */
8729088Smarkm#endif /* !defined(CRAY) && !defined(sysV88) */
8829088Smarkm#include <netinet/ip.h>
8956668Sshin#include <netinet/ip6.h>
9029088Smarkm
9129088Smarkm
9229088Smarkm#ifndef	MAXHOSTNAMELEN
9369223Skris#define	MAXHOSTNAMELEN 256
9429088Smarkm#endif	MAXHOSTNAMELEN
9529088Smarkm
9629088Smarkm#if	defined(IPPROTO_IP) && defined(IP_TOS)
9729088Smarkmint tos = -1;
9829088Smarkm#endif	/* defined(IPPROTO_IP) && defined(IP_TOS) */
9929088Smarkm
10029088Smarkmchar	*hostname;
10129088Smarkmstatic char _hostname[MAXHOSTNAMELEN];
10229088Smarkm
10329088Smarkmextern char *getenv();
10429088Smarkm
10529088Smarkmextern int isprefix();
10629088Smarkmextern char **genget();
10729088Smarkmextern int Ambiguous();
10829088Smarkm
10929181Smarkmstatic int help(int argc, char *argv[]);
11029181Smarkmstatic int call();
11129181Smarkmstatic void cmdrc(char *m1, char *m2);
11257125Sshinstatic int switch_af(struct addrinfo **aip);
11329088Smarkm
11429181Smarkmint quit(void);
11529181Smarkm
11629088Smarkmtypedef struct {
11729088Smarkm	char	*name;		/* command name */
11829088Smarkm	char	*help;		/* help string (NULL for no help) */
11929088Smarkm	int	(*handler)();	/* routine which executes command */
12029088Smarkm	int	needconnect;	/* Do we need to be connected to execute? */
12129088Smarkm} Command;
12229088Smarkm
12329088Smarkmstatic char line[256];
12429088Smarkmstatic char saveline[256];
12529088Smarkmstatic int margc;
12629088Smarkmstatic char *margv[20];
12729088Smarkm
12829181Smarkm#if	defined(SKEY)
12929181Smarkm#include <sys/wait.h>
13029181Smarkm#define PATH_SKEY	"/usr/bin/key"
13129181Smarkm    int
13229181Smarkmskey_calc(argc, argv)
13329181Smarkm	int argc;
13429181Smarkm	char **argv;
13529181Smarkm{
13629181Smarkm	int status;
13729181Smarkm
13829181Smarkm	if(argc != 3) {
13929181Smarkm		printf("%s sequence challenge\n", argv[0]);
14029181Smarkm		return;
14129181Smarkm	}
14229181Smarkm
14329181Smarkm	switch(fork()) {
14429181Smarkm	case 0:
14529181Smarkm		execv(PATH_SKEY, argv);
14629181Smarkm		exit (1);
14729181Smarkm	case -1:
14829181Smarkm		perror("fork");
14929181Smarkm		break;
15029181Smarkm	default:
15129181Smarkm		(void) wait(&status);
15229181Smarkm		if (WIFEXITED(status))
15329181Smarkm			return (WEXITSTATUS(status));
15429181Smarkm		return (0);
15529181Smarkm	}
15629181Smarkm}
15729181Smarkm#endif
15829181Smarkm
15929088Smarkm    static void
16029088Smarkmmakeargv()
16129088Smarkm{
16229088Smarkm    register char *cp, *cp2, c;
16329088Smarkm    register char **argp = margv;
16429088Smarkm
16529088Smarkm    margc = 0;
16629088Smarkm    cp = line;
16729088Smarkm    if (*cp == '!') {		/* Special case shell escape */
16829088Smarkm	strcpy(saveline, line);	/* save for shell command */
16929088Smarkm	*argp++ = "!";		/* No room in string to get this */
17029088Smarkm	margc++;
17129088Smarkm	cp++;
17229088Smarkm    }
17329181Smarkm    while ((c = *cp)) {
17429088Smarkm	register int inquote = 0;
17529088Smarkm	while (isspace(c))
17629088Smarkm	    c = *++cp;
17729088Smarkm	if (c == '\0')
17829088Smarkm	    break;
17929088Smarkm	*argp++ = cp;
18029088Smarkm	margc += 1;
18129088Smarkm	for (cp2 = cp; c != '\0'; c = *++cp) {
18229088Smarkm	    if (inquote) {
18329088Smarkm		if (c == inquote) {
18429088Smarkm		    inquote = 0;
18529088Smarkm		    continue;
18629088Smarkm		}
18729088Smarkm	    } else {
18829088Smarkm		if (c == '\\') {
18929088Smarkm		    if ((c = *++cp) == '\0')
19029088Smarkm			break;
19129088Smarkm		} else if (c == '"') {
19229088Smarkm		    inquote = '"';
19329088Smarkm		    continue;
19429088Smarkm		} else if (c == '\'') {
19529088Smarkm		    inquote = '\'';
19629088Smarkm		    continue;
19729088Smarkm		} else if (isspace(c))
19829088Smarkm		    break;
19929088Smarkm	    }
20029088Smarkm	    *cp2++ = c;
20129088Smarkm	}
20229088Smarkm	*cp2 = '\0';
20329088Smarkm	if (c == '\0')
20429088Smarkm	    break;
20529088Smarkm	cp++;
20629088Smarkm    }
20729088Smarkm    *argp++ = 0;
20829088Smarkm}
20929088Smarkm
21029088Smarkm/*
21129088Smarkm * Make a character string into a number.
21229088Smarkm *
21329088Smarkm * Todo:  1.  Could take random integers (12, 0x12, 012, 0b1).
21429088Smarkm */
21529088Smarkm
21629181Smarkm	static int
21729088Smarkmspecial(s)
21829088Smarkm	register char *s;
21929088Smarkm{
22029088Smarkm	register char c;
22129088Smarkm	char b;
22229088Smarkm
22329088Smarkm	switch (*s) {
22429088Smarkm	case '^':
22529088Smarkm		b = *++s;
22629088Smarkm		if (b == '?') {
22729088Smarkm		    c = b | 0x40;		/* DEL */
22829088Smarkm		} else {
22929088Smarkm		    c = b & 0x1f;
23029088Smarkm		}
23129088Smarkm		break;
23229088Smarkm	default:
23329088Smarkm		c = *s;
23429088Smarkm		break;
23529088Smarkm	}
23629088Smarkm	return c;
23729088Smarkm}
23829088Smarkm
23929088Smarkm/*
24029088Smarkm * Construct a control character sequence
24129088Smarkm * for a special character.
24229088Smarkm */
24329088Smarkm	static char *
24429088Smarkmcontrol(c)
24529088Smarkm	register cc_t c;
24629088Smarkm{
24729088Smarkm	static char buf[5];
24829088Smarkm	/*
24929088Smarkm	 * The only way I could get the Sun 3.5 compiler
25029088Smarkm	 * to shut up about
25129088Smarkm	 *	if ((unsigned int)c >= 0x80)
25229088Smarkm	 * was to assign "c" to an unsigned int variable...
25329088Smarkm	 * Arggg....
25429088Smarkm	 */
25529088Smarkm	register unsigned int uic = (unsigned int)c;
25629088Smarkm
25729088Smarkm	if (uic == 0x7f)
25829088Smarkm		return ("^?");
25929088Smarkm	if (c == (cc_t)_POSIX_VDISABLE) {
26029088Smarkm		return "off";
26129088Smarkm	}
26229088Smarkm	if (uic >= 0x80) {
26329088Smarkm		buf[0] = '\\';
26429088Smarkm		buf[1] = ((c>>6)&07) + '0';
26529088Smarkm		buf[2] = ((c>>3)&07) + '0';
26629088Smarkm		buf[3] = (c&07) + '0';
26729088Smarkm		buf[4] = 0;
26829088Smarkm	} else if (uic >= 0x20) {
26929088Smarkm		buf[0] = c;
27029088Smarkm		buf[1] = 0;
27129088Smarkm	} else {
27229088Smarkm		buf[0] = '^';
27329088Smarkm		buf[1] = '@'+c;
27429088Smarkm		buf[2] = 0;
27529088Smarkm	}
27629088Smarkm	return (buf);
27729088Smarkm}
27829088Smarkm
27929088Smarkm
28029088Smarkm
28129088Smarkm/*
28229088Smarkm *	The following are data structures and routines for
28329088Smarkm *	the "send" command.
28429088Smarkm *
28529088Smarkm */
28629088Smarkm
28729088Smarkmstruct sendlist {
28829088Smarkm    char	*name;		/* How user refers to it (case independent) */
28929088Smarkm    char	*help;		/* Help information (0 ==> no help) */
29029088Smarkm    int		needconnect;	/* Need to be connected */
29129088Smarkm    int		narg;		/* Number of arguments */
29229088Smarkm    int		(*handler)();	/* Routine to perform (for special ops) */
29329088Smarkm    int		nbyte;		/* Number of bytes to send this command */
29429088Smarkm    int		what;		/* Character to be sent (<0 ==> special) */
29529088Smarkm};
29629088Smarkm
29729088Smarkm
29829088Smarkmstatic int
29929088Smarkm	send_esc P((void)),
30029088Smarkm	send_help P((void)),
30129088Smarkm	send_docmd P((char *)),
30229088Smarkm	send_dontcmd P((char *)),
30329088Smarkm	send_willcmd P((char *)),
30429088Smarkm	send_wontcmd P((char *));
30529088Smarkm
30629088Smarkmstatic struct sendlist Sendlist[] = {
30729088Smarkm    { "ao",	"Send Telnet Abort output",		1, 0, 0, 2, AO },
30829088Smarkm    { "ayt",	"Send Telnet 'Are You There'",		1, 0, 0, 2, AYT },
30929088Smarkm    { "brk",	"Send Telnet Break",			1, 0, 0, 2, BREAK },
31029088Smarkm    { "break",	0,					1, 0, 0, 2, BREAK },
31129088Smarkm    { "ec",	"Send Telnet Erase Character",		1, 0, 0, 2, EC },
31229088Smarkm    { "el",	"Send Telnet Erase Line",		1, 0, 0, 2, EL },
31329088Smarkm    { "escape",	"Send current escape character",	1, 0, send_esc, 1, 0 },
31429088Smarkm    { "ga",	"Send Telnet 'Go Ahead' sequence",	1, 0, 0, 2, GA },
31529088Smarkm    { "ip",	"Send Telnet Interrupt Process",	1, 0, 0, 2, IP },
31629088Smarkm    { "intp",	0,					1, 0, 0, 2, IP },
31729088Smarkm    { "interrupt", 0,					1, 0, 0, 2, IP },
31829088Smarkm    { "intr",	0,					1, 0, 0, 2, IP },
31929088Smarkm    { "nop",	"Send Telnet 'No operation'",		1, 0, 0, 2, NOP },
32029088Smarkm    { "eor",	"Send Telnet 'End of Record'",		1, 0, 0, 2, EOR },
32129088Smarkm    { "abort",	"Send Telnet 'Abort Process'",		1, 0, 0, 2, ABORT },
32229088Smarkm    { "susp",	"Send Telnet 'Suspend Process'",	1, 0, 0, 2, SUSP },
32329088Smarkm    { "eof",	"Send Telnet End of File Character",	1, 0, 0, 2, xEOF },
32429088Smarkm    { "synch",	"Perform Telnet 'Synch operation'",	1, 0, dosynch, 2, 0 },
32529088Smarkm    { "getstatus", "Send request for STATUS",		1, 0, get_status, 6, 0 },
32629088Smarkm    { "?",	"Display send options",			0, 0, send_help, 0, 0 },
32729088Smarkm    { "help",	0,					0, 0, send_help, 0, 0 },
32829088Smarkm    { "do",	0,					0, 1, send_docmd, 3, 0 },
32929088Smarkm    { "dont",	0,					0, 1, send_dontcmd, 3, 0 },
33029088Smarkm    { "will",	0,					0, 1, send_willcmd, 3, 0 },
33129088Smarkm    { "wont",	0,					0, 1, send_wontcmd, 3, 0 },
33229088Smarkm    { 0 }
33329088Smarkm};
33429088Smarkm
33529088Smarkm#define	GETSEND(name) ((struct sendlist *) genget(name, (char **) Sendlist, \
33629088Smarkm				sizeof(struct sendlist)))
33729088Smarkm
33829088Smarkm    static int
33929088Smarkmsendcmd(argc, argv)
34029088Smarkm    int  argc;
34129088Smarkm    char **argv;
34229088Smarkm{
34329088Smarkm    int count;		/* how many bytes we are going to need to send */
34429088Smarkm    int i;
34529088Smarkm    struct sendlist *s;	/* pointer to current command */
34629088Smarkm    int success = 0;
34729088Smarkm    int needconnect = 0;
34829088Smarkm
34929088Smarkm    if (argc < 2) {
35029088Smarkm	printf("need at least one argument for 'send' command\n");
35129088Smarkm	printf("'send ?' for help\n");
35229088Smarkm	return 0;
35329088Smarkm    }
35429088Smarkm    /*
35529088Smarkm     * First, validate all the send arguments.
35629088Smarkm     * In addition, we see how much space we are going to need, and
35729088Smarkm     * whether or not we will be doing a "SYNCH" operation (which
35829088Smarkm     * flushes the network queue).
35929088Smarkm     */
36029088Smarkm    count = 0;
36129088Smarkm    for (i = 1; i < argc; i++) {
36229088Smarkm	s = GETSEND(argv[i]);
36329088Smarkm	if (s == 0) {
36429088Smarkm	    printf("Unknown send argument '%s'\n'send ?' for help.\n",
36529088Smarkm			argv[i]);
36629088Smarkm	    return 0;
36729088Smarkm	} else if (Ambiguous(s)) {
36829088Smarkm	    printf("Ambiguous send argument '%s'\n'send ?' for help.\n",
36929088Smarkm			argv[i]);
37029088Smarkm	    return 0;
37129088Smarkm	}
37229088Smarkm	if (i + s->narg >= argc) {
37329088Smarkm	    fprintf(stderr,
37429088Smarkm	    "Need %d argument%s to 'send %s' command.  'send %s ?' for help.\n",
37529088Smarkm		s->narg, s->narg == 1 ? "" : "s", s->name, s->name);
37629088Smarkm	    return 0;
37729088Smarkm	}
37829088Smarkm	count += s->nbyte;
37929088Smarkm	if (s->handler == send_help) {
38029088Smarkm	    send_help();
38129088Smarkm	    return 0;
38229088Smarkm	}
38329088Smarkm
38429088Smarkm	i += s->narg;
38529088Smarkm	needconnect += s->needconnect;
38629088Smarkm    }
38729088Smarkm    if (!connected && needconnect) {
38829088Smarkm	printf("?Need to be connected first.\n");
38929088Smarkm	printf("'send ?' for help\n");
39029088Smarkm	return 0;
39129088Smarkm    }
39229088Smarkm    /* Now, do we have enough room? */
39329088Smarkm    if (NETROOM() < count) {
39429088Smarkm	printf("There is not enough room in the buffer TO the network\n");
39529088Smarkm	printf("to process your request.  Nothing will be done.\n");
39629088Smarkm	printf("('send synch' will throw away most data in the network\n");
39729088Smarkm	printf("buffer, if this might help.)\n");
39829088Smarkm	return 0;
39929088Smarkm    }
40029088Smarkm    /* OK, they are all OK, now go through again and actually send */
40129088Smarkm    count = 0;
40229088Smarkm    for (i = 1; i < argc; i++) {
40329088Smarkm	if ((s = GETSEND(argv[i])) == 0) {
40429088Smarkm	    fprintf(stderr, "Telnet 'send' error - argument disappeared!\n");
40529088Smarkm	    (void) quit();
40629088Smarkm	    /*NOTREACHED*/
40729088Smarkm	}
40829088Smarkm	if (s->handler) {
40929088Smarkm	    count++;
41029088Smarkm	    success += (*s->handler)((s->narg > 0) ? argv[i+1] : 0,
41129088Smarkm				  (s->narg > 1) ? argv[i+2] : 0);
41229088Smarkm	    i += s->narg;
41329088Smarkm	} else {
41429088Smarkm	    NET2ADD(IAC, s->what);
41529088Smarkm	    printoption("SENT", IAC, s->what);
41629088Smarkm	}
41729088Smarkm    }
41829088Smarkm    return (count == success);
41929088Smarkm}
42029088Smarkm
42129088Smarkm    static int
42229088Smarkmsend_esc()
42329088Smarkm{
42429088Smarkm    NETADD(escape);
42529088Smarkm    return 1;
42629088Smarkm}
42729088Smarkm
42829088Smarkm    static int
42929088Smarkmsend_docmd(name)
43029088Smarkm    char *name;
43129088Smarkm{
43229088Smarkm    return(send_tncmd(send_do, "do", name));
43329088Smarkm}
43429088Smarkm
43529088Smarkm    static int
43629088Smarkmsend_dontcmd(name)
43729088Smarkm    char *name;
43829088Smarkm{
43929088Smarkm    return(send_tncmd(send_dont, "dont", name));
44029088Smarkm}
44129088Smarkm    static int
44229088Smarkmsend_willcmd(name)
44329088Smarkm    char *name;
44429088Smarkm{
44529088Smarkm    return(send_tncmd(send_will, "will", name));
44629088Smarkm}
44729088Smarkm    static int
44829088Smarkmsend_wontcmd(name)
44929088Smarkm    char *name;
45029088Smarkm{
45129088Smarkm    return(send_tncmd(send_wont, "wont", name));
45229088Smarkm}
45329088Smarkm
45429088Smarkm    int
45529088Smarkmsend_tncmd(func, cmd, name)
45629088Smarkm    void	(*func)();
45729088Smarkm    char	*cmd, *name;
45829088Smarkm{
45929088Smarkm    char **cpp;
46029088Smarkm    extern char *telopts[];
46129088Smarkm    register int val = 0;
46229088Smarkm
46329088Smarkm    if (isprefix(name, "help") || isprefix(name, "?")) {
46429088Smarkm	register int col, len;
46529088Smarkm
46629088Smarkm	printf("Usage: send %s <value|option>\n", cmd);
46729088Smarkm	printf("\"value\" must be from 0 to 255\n");
46829088Smarkm	printf("Valid options are:\n\t");
46929088Smarkm
47029088Smarkm	col = 8;
47129088Smarkm	for (cpp = telopts; *cpp; cpp++) {
47229088Smarkm	    len = strlen(*cpp) + 3;
47329088Smarkm	    if (col + len > 65) {
47429088Smarkm		printf("\n\t");
47529088Smarkm		col = 8;
47629088Smarkm	    }
47729088Smarkm	    printf(" \"%s\"", *cpp);
47829088Smarkm	    col += len;
47929088Smarkm	}
48029088Smarkm	printf("\n");
48129088Smarkm	return 0;
48229088Smarkm    }
48329088Smarkm    cpp = (char **)genget(name, telopts, sizeof(char *));
48429088Smarkm    if (Ambiguous(cpp)) {
48529088Smarkm	fprintf(stderr,"'%s': ambiguous argument ('send %s ?' for help).\n",
48629088Smarkm					name, cmd);
48729088Smarkm	return 0;
48829088Smarkm    }
48929088Smarkm    if (cpp) {
49029088Smarkm	val = cpp - telopts;
49129088Smarkm    } else {
49229088Smarkm	register char *cp = name;
49329088Smarkm
49429088Smarkm	while (*cp >= '0' && *cp <= '9') {
49529088Smarkm	    val *= 10;
49629088Smarkm	    val += *cp - '0';
49729088Smarkm	    cp++;
49829088Smarkm	}
49929088Smarkm	if (*cp != 0) {
50029088Smarkm	    fprintf(stderr, "'%s': unknown argument ('send %s ?' for help).\n",
50129088Smarkm					name, cmd);
50229088Smarkm	    return 0;
50329088Smarkm	} else if (val < 0 || val > 255) {
50429088Smarkm	    fprintf(stderr, "'%s': bad value ('send %s ?' for help).\n",
50529088Smarkm					name, cmd);
50629088Smarkm	    return 0;
50729088Smarkm	}
50829088Smarkm    }
50929088Smarkm    if (!connected) {
51029088Smarkm	printf("?Need to be connected first.\n");
51129088Smarkm	return 0;
51229088Smarkm    }
51329088Smarkm    (*func)(val, 1);
51429088Smarkm    return 1;
51529088Smarkm}
51629088Smarkm
51729088Smarkm    static int
51829088Smarkmsend_help()
51929088Smarkm{
52029088Smarkm    struct sendlist *s;	/* pointer to current command */
52129088Smarkm    for (s = Sendlist; s->name; s++) {
52229088Smarkm	if (s->help)
52329088Smarkm	    printf("%-15s %s\n", s->name, s->help);
52429088Smarkm    }
52529088Smarkm    return(0);
52629088Smarkm}
52729088Smarkm
52829088Smarkm/*
52929088Smarkm * The following are the routines and data structures referred
53029088Smarkm * to by the arguments to the "toggle" command.
53129088Smarkm */
53229088Smarkm
53329088Smarkm    static int
53429088Smarkmlclchars()
53529088Smarkm{
53629088Smarkm    donelclchars = 1;
53729088Smarkm    return 1;
53829088Smarkm}
53929088Smarkm
54029088Smarkm    static int
54129088Smarkmtogdebug()
54229088Smarkm{
54329088Smarkm#ifndef	NOT43
54429088Smarkm    if (net > 0 &&
54529088Smarkm	(SetSockOpt(net, SOL_SOCKET, SO_DEBUG, debug)) < 0) {
54629088Smarkm	    perror("setsockopt (SO_DEBUG)");
54729088Smarkm    }
54829088Smarkm#else	/* NOT43 */
54929088Smarkm    if (debug) {
55029181Smarkm	if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0)
55129088Smarkm	    perror("setsockopt (SO_DEBUG)");
55229088Smarkm    } else
55329088Smarkm	printf("Cannot turn off socket debugging\n");
55429088Smarkm#endif	/* NOT43 */
55529088Smarkm    return 1;
55629088Smarkm}
55729088Smarkm
55829088Smarkm
55929088Smarkm    static int
56029088Smarkmtogcrlf()
56129088Smarkm{
56229088Smarkm    if (crlf) {
56329088Smarkm	printf("Will send carriage returns as telnet <CR><LF>.\n");
56429088Smarkm    } else {
56529088Smarkm	printf("Will send carriage returns as telnet <CR><NUL>.\n");
56629088Smarkm    }
56729088Smarkm    return 1;
56829088Smarkm}
56929088Smarkm
57029088Smarkmint binmode;
57129088Smarkm
57229088Smarkm    static int
57329088Smarkmtogbinary(val)
57429088Smarkm    int val;
57529088Smarkm{
57629088Smarkm    donebinarytoggle = 1;
57729088Smarkm
57829088Smarkm    if (val >= 0) {
57929088Smarkm	binmode = val;
58029088Smarkm    } else {
58129088Smarkm	if (my_want_state_is_will(TELOPT_BINARY) &&
58229088Smarkm				my_want_state_is_do(TELOPT_BINARY)) {
58329088Smarkm	    binmode = 1;
58429088Smarkm	} else if (my_want_state_is_wont(TELOPT_BINARY) &&
58529088Smarkm				my_want_state_is_dont(TELOPT_BINARY)) {
58629088Smarkm	    binmode = 0;
58729088Smarkm	}
58829088Smarkm	val = binmode ? 0 : 1;
58929088Smarkm    }
59029088Smarkm
59129088Smarkm    if (val == 1) {
59229088Smarkm	if (my_want_state_is_will(TELOPT_BINARY) &&
59329088Smarkm					my_want_state_is_do(TELOPT_BINARY)) {
59429088Smarkm	    printf("Already operating in binary mode with remote host.\n");
59529088Smarkm	} else {
59629088Smarkm	    printf("Negotiating binary mode with remote host.\n");
59729088Smarkm	    tel_enter_binary(3);
59829088Smarkm	}
59929088Smarkm    } else {
60029088Smarkm	if (my_want_state_is_wont(TELOPT_BINARY) &&
60129088Smarkm					my_want_state_is_dont(TELOPT_BINARY)) {
60229088Smarkm	    printf("Already in network ascii mode with remote host.\n");
60329088Smarkm	} else {
60429088Smarkm	    printf("Negotiating network ascii mode with remote host.\n");
60529088Smarkm	    tel_leave_binary(3);
60629088Smarkm	}
60729088Smarkm    }
60829088Smarkm    return 1;
60929088Smarkm}
61029088Smarkm
61129088Smarkm    static int
61229088Smarkmtogrbinary(val)
61329088Smarkm    int val;
61429088Smarkm{
61529088Smarkm    donebinarytoggle = 1;
61629088Smarkm
61729088Smarkm    if (val == -1)
61829088Smarkm	val = my_want_state_is_do(TELOPT_BINARY) ? 0 : 1;
61929088Smarkm
62029088Smarkm    if (val == 1) {
62129088Smarkm	if (my_want_state_is_do(TELOPT_BINARY)) {
62229088Smarkm	    printf("Already receiving in binary mode.\n");
62329088Smarkm	} else {
62429088Smarkm	    printf("Negotiating binary mode on input.\n");
62529088Smarkm	    tel_enter_binary(1);
62629088Smarkm	}
62729088Smarkm    } else {
62829088Smarkm	if (my_want_state_is_dont(TELOPT_BINARY)) {
62929088Smarkm	    printf("Already receiving in network ascii mode.\n");
63029088Smarkm	} else {
63129088Smarkm	    printf("Negotiating network ascii mode on input.\n");
63229088Smarkm	    tel_leave_binary(1);
63329088Smarkm	}
63429088Smarkm    }
63529088Smarkm    return 1;
63629088Smarkm}
63729088Smarkm
63829088Smarkm    static int
63929088Smarkmtogxbinary(val)
64029088Smarkm    int val;
64129088Smarkm{
64229088Smarkm    donebinarytoggle = 1;
64329088Smarkm
64429088Smarkm    if (val == -1)
64529088Smarkm	val = my_want_state_is_will(TELOPT_BINARY) ? 0 : 1;
64629088Smarkm
64729088Smarkm    if (val == 1) {
64829088Smarkm	if (my_want_state_is_will(TELOPT_BINARY)) {
64929088Smarkm	    printf("Already transmitting in binary mode.\n");
65029088Smarkm	} else {
65129088Smarkm	    printf("Negotiating binary mode on output.\n");
65229088Smarkm	    tel_enter_binary(2);
65329088Smarkm	}
65429088Smarkm    } else {
65529088Smarkm	if (my_want_state_is_wont(TELOPT_BINARY)) {
65629088Smarkm	    printf("Already transmitting in network ascii mode.\n");
65729088Smarkm	} else {
65829088Smarkm	    printf("Negotiating network ascii mode on output.\n");
65929088Smarkm	    tel_leave_binary(2);
66029088Smarkm	}
66129088Smarkm    }
66229088Smarkm    return 1;
66329088Smarkm}
66429088Smarkm
66529088Smarkm
66629088Smarkmstatic int togglehelp P((void));
66729088Smarkm#if	defined(AUTHENTICATION)
66829088Smarkmextern int auth_togdebug P((int));
66929088Smarkm#endif
67029088Smarkm#ifdef	ENCRYPTION
67129088Smarkmextern int EncryptAutoEnc P((int));
67229088Smarkmextern int EncryptAutoDec P((int));
67329088Smarkmextern int EncryptDebug P((int));
67429088Smarkmextern int EncryptVerbose P((int));
67529088Smarkm#endif	/* ENCRYPTION */
67629088Smarkm
67729088Smarkmstruct togglelist {
67829088Smarkm    char	*name;		/* name of toggle */
67929088Smarkm    char	*help;		/* help message */
68029088Smarkm    int		(*handler)();	/* routine to do actual setting */
68129088Smarkm    int		*variable;
68229088Smarkm    char	*actionexplanation;
68329088Smarkm};
68429088Smarkm
68529088Smarkmstatic struct togglelist Togglelist[] = {
68629088Smarkm    { "autoflush",
68729088Smarkm	"flushing of output when sending interrupt characters",
68829088Smarkm	    0,
68929088Smarkm		&autoflush,
69029088Smarkm		    "flush output when sending interrupt characters" },
69129088Smarkm    { "autosynch",
69229088Smarkm	"automatic sending of interrupt characters in urgent mode",
69329088Smarkm	    0,
69429088Smarkm		&autosynch,
69529088Smarkm		    "send interrupt characters in urgent mode" },
69629088Smarkm#if	defined(AUTHENTICATION)
69729088Smarkm    { "autologin",
69829088Smarkm	"automatic sending of login and/or authentication info",
69929088Smarkm	    0,
70029088Smarkm		&autologin,
70129088Smarkm		    "send login name and/or authentication information" },
70229088Smarkm    { "authdebug",
70329088Smarkm	"Toggle authentication debugging",
70429088Smarkm	    auth_togdebug,
70529088Smarkm		0,
70629088Smarkm		     "print authentication debugging information" },
70729088Smarkm#endif
70829088Smarkm#ifdef	ENCRYPTION
70929088Smarkm    { "autoencrypt",
71029088Smarkm	"automatic encryption of data stream",
71129088Smarkm	    EncryptAutoEnc,
71229088Smarkm		0,
71329088Smarkm		    "automatically encrypt output" },
71429088Smarkm    { "autodecrypt",
71529088Smarkm	"automatic decryption of data stream",
71629088Smarkm	    EncryptAutoDec,
71729088Smarkm		0,
71829088Smarkm		    "automatically decrypt input" },
71929088Smarkm    { "verbose_encrypt",
72029088Smarkm	"Toggle verbose encryption output",
72129088Smarkm	    EncryptVerbose,
72229088Smarkm		0,
72329088Smarkm		    "print verbose encryption output" },
72429088Smarkm    { "encdebug",
72529088Smarkm	"Toggle encryption debugging",
72629088Smarkm	    EncryptDebug,
72729088Smarkm		0,
72829088Smarkm		    "print encryption debugging information" },
72929088Smarkm#endif	/* ENCRYPTION */
73029088Smarkm    { "skiprc",
73129088Smarkm	"don't read ~/.telnetrc file",
73229088Smarkm	    0,
73329088Smarkm		&skiprc,
73429088Smarkm		    "skip reading of ~/.telnetrc file" },
73529088Smarkm    { "binary",
73629088Smarkm	"sending and receiving of binary data",
73729088Smarkm	    togbinary,
73829088Smarkm		0,
73929088Smarkm		    0 },
74029088Smarkm    { "inbinary",
74129088Smarkm	"receiving of binary data",
74229088Smarkm	    togrbinary,
74329088Smarkm		0,
74429088Smarkm		    0 },
74529088Smarkm    { "outbinary",
74629088Smarkm	"sending of binary data",
74729088Smarkm	    togxbinary,
74829088Smarkm		0,
74929088Smarkm		    0 },
75029088Smarkm    { "crlf",
75129088Smarkm	"sending carriage returns as telnet <CR><LF>",
75229088Smarkm	    togcrlf,
75329088Smarkm		&crlf,
75429088Smarkm		    0 },
75529088Smarkm    { "crmod",
75629088Smarkm	"mapping of received carriage returns",
75729088Smarkm	    0,
75829088Smarkm		&crmod,
75929088Smarkm		    "map carriage return on output" },
76029088Smarkm    { "localchars",
76129088Smarkm	"local recognition of certain control characters",
76229088Smarkm	    lclchars,
76329088Smarkm		&localchars,
76429088Smarkm		    "recognize certain control characters" },
76529088Smarkm    { " ", "", 0 },		/* empty line */
76629088Smarkm#if	defined(unix) && defined(TN3270)
76729088Smarkm    { "apitrace",
76829088Smarkm	"(debugging) toggle tracing of API transactions",
76929088Smarkm	    0,
77029088Smarkm		&apitrace,
77129088Smarkm		    "trace API transactions" },
77229088Smarkm    { "cursesdata",
77329088Smarkm	"(debugging) toggle printing of hexadecimal curses data",
77429088Smarkm	    0,
77529088Smarkm		&cursesdata,
77629088Smarkm		    "print hexadecimal representation of curses data" },
77729088Smarkm#endif	/* defined(unix) && defined(TN3270) */
77829088Smarkm    { "debug",
77929088Smarkm	"debugging",
78029088Smarkm	    togdebug,
78129088Smarkm		&debug,
78229088Smarkm		    "turn on socket level debugging" },
78329088Smarkm    { "netdata",
78429088Smarkm	"printing of hexadecimal network data (debugging)",
78529088Smarkm	    0,
78629088Smarkm		&netdata,
78729088Smarkm		    "print hexadecimal representation of network traffic" },
78829088Smarkm    { "prettydump",
78929088Smarkm	"output of \"netdata\" to user readable format (debugging)",
79029088Smarkm	    0,
79129088Smarkm		&prettydump,
79229088Smarkm		    "print user readable output for \"netdata\"" },
79329088Smarkm    { "options",
79429088Smarkm	"viewing of options processing (debugging)",
79529088Smarkm	    0,
79629088Smarkm		&showoptions,
79729088Smarkm		    "show option processing" },
79829088Smarkm#if	defined(unix)
79929088Smarkm    { "termdata",
80029088Smarkm	"(debugging) toggle printing of hexadecimal terminal data",
80129088Smarkm	    0,
80229088Smarkm		&termdata,
80329088Smarkm		    "print hexadecimal representation of terminal traffic" },
80429088Smarkm#endif	/* defined(unix) */
80529088Smarkm    { "?",
80629088Smarkm	0,
80729088Smarkm	    togglehelp },
80829088Smarkm    { "help",
80929088Smarkm	0,
81029088Smarkm	    togglehelp },
81129088Smarkm    { 0 }
81229088Smarkm};
81329088Smarkm
81429088Smarkm    static int
81529088Smarkmtogglehelp()
81629088Smarkm{
81729088Smarkm    struct togglelist *c;
81829088Smarkm
81929088Smarkm    for (c = Togglelist; c->name; c++) {
82029088Smarkm	if (c->help) {
82129088Smarkm	    if (*c->help)
82229088Smarkm		printf("%-15s toggle %s\n", c->name, c->help);
82329088Smarkm	    else
82429088Smarkm		printf("\n");
82529088Smarkm	}
82629088Smarkm    }
82729088Smarkm    printf("\n");
82829088Smarkm    printf("%-15s %s\n", "?", "display help information");
82929088Smarkm    return 0;
83029088Smarkm}
83129088Smarkm
83229088Smarkm    static void
83329088Smarkmsettogglehelp(set)
83429088Smarkm    int set;
83529088Smarkm{
83629088Smarkm    struct togglelist *c;
83729088Smarkm
83829088Smarkm    for (c = Togglelist; c->name; c++) {
83929088Smarkm	if (c->help) {
84029088Smarkm	    if (*c->help)
84129088Smarkm		printf("%-15s %s %s\n", c->name, set ? "enable" : "disable",
84229088Smarkm						c->help);
84329088Smarkm	    else
84429088Smarkm		printf("\n");
84529088Smarkm	}
84629088Smarkm    }
84729088Smarkm}
84829088Smarkm
84929088Smarkm#define	GETTOGGLE(name) (struct togglelist *) \
85029088Smarkm		genget(name, (char **) Togglelist, sizeof(struct togglelist))
85129088Smarkm
85229088Smarkm    static int
85329088Smarkmtoggle(argc, argv)
85429088Smarkm    int  argc;
85529088Smarkm    char *argv[];
85629088Smarkm{
85729088Smarkm    int retval = 1;
85829088Smarkm    char *name;
85929088Smarkm    struct togglelist *c;
86029088Smarkm
86129088Smarkm    if (argc < 2) {
86229088Smarkm	fprintf(stderr,
86329088Smarkm	    "Need an argument to 'toggle' command.  'toggle ?' for help.\n");
86429088Smarkm	return 0;
86529088Smarkm    }
86629088Smarkm    argc--;
86729088Smarkm    argv++;
86829088Smarkm    while (argc--) {
86929088Smarkm	name = *argv++;
87029088Smarkm	c = GETTOGGLE(name);
87129088Smarkm	if (Ambiguous(c)) {
87229088Smarkm	    fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n",
87329088Smarkm					name);
87429088Smarkm	    return 0;
87529088Smarkm	} else if (c == 0) {
87629088Smarkm	    fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n",
87729088Smarkm					name);
87829088Smarkm	    return 0;
87929088Smarkm	} else {
88029088Smarkm	    if (c->variable) {
88129088Smarkm		*c->variable = !*c->variable;		/* invert it */
88229088Smarkm		if (c->actionexplanation) {
88329088Smarkm		    printf("%s %s.\n", *c->variable? "Will" : "Won't",
88429088Smarkm							c->actionexplanation);
88529088Smarkm		}
88629088Smarkm	    }
88729088Smarkm	    if (c->handler) {
88829088Smarkm		retval &= (*c->handler)(-1);
88929088Smarkm	    }
89029088Smarkm	}
89129088Smarkm    }
89229088Smarkm    return retval;
89329088Smarkm}
89429088Smarkm
89529088Smarkm/*
89629088Smarkm * The following perform the "set" command.
89729088Smarkm */
89829088Smarkm
89929088Smarkm#ifdef	USE_TERMIO
90029088Smarkmstruct termio new_tc = { 0 };
90129088Smarkm#endif
90229088Smarkm
90329088Smarkmstruct setlist {
90429088Smarkm    char *name;				/* name */
90529088Smarkm    char *help;				/* help information */
90629088Smarkm    void (*handler)();
90729088Smarkm    cc_t *charp;			/* where it is located at */
90829088Smarkm};
90929088Smarkm
91029088Smarkmstatic struct setlist Setlist[] = {
91129088Smarkm#ifdef	KLUDGELINEMODE
91229088Smarkm    { "echo", 	"character to toggle local echoing on/off", 0, &echoc },
91329088Smarkm#endif
91429088Smarkm    { "escape",	"character to escape back to telnet command mode", 0, &escape },
91529088Smarkm    { "rlogin", "rlogin escape character", 0, &rlogin },
91629088Smarkm    { "tracefile", "file to write trace information to", SetNetTrace, (cc_t *)NetTraceFile},
91729088Smarkm    { " ", "" },
91829088Smarkm    { " ", "The following need 'localchars' to be toggled true", 0, 0 },
91929088Smarkm    { "flushoutput", "character to cause an Abort Output", 0, termFlushCharp },
92029088Smarkm    { "interrupt", "character to cause an Interrupt Process", 0, termIntCharp },
92129088Smarkm    { "quit",	"character to cause an Abort process", 0, termQuitCharp },
92229088Smarkm    { "eof",	"character to cause an EOF ", 0, termEofCharp },
92329088Smarkm    { " ", "" },
92429088Smarkm    { " ", "The following are for local editing in linemode", 0, 0 },
92529088Smarkm    { "erase",	"character to use to erase a character", 0, termEraseCharp },
92629088Smarkm    { "kill",	"character to use to erase a line", 0, termKillCharp },
92729088Smarkm    { "lnext",	"character to use for literal next", 0, termLiteralNextCharp },
92829088Smarkm    { "susp",	"character to cause a Suspend Process", 0, termSuspCharp },
92929088Smarkm    { "reprint", "character to use for line reprint", 0, termRprntCharp },
93029088Smarkm    { "worderase", "character to use to erase a word", 0, termWerasCharp },
93129088Smarkm    { "start",	"character to use for XON", 0, termStartCharp },
93229088Smarkm    { "stop",	"character to use for XOFF", 0, termStopCharp },
93329088Smarkm    { "forw1",	"alternate end of line character", 0, termForw1Charp },
93429088Smarkm    { "forw2",	"alternate end of line character", 0, termForw2Charp },
93529088Smarkm    { "ayt",	"alternate AYT character", 0, termAytCharp },
93629088Smarkm    { 0 }
93729088Smarkm};
93829088Smarkm
93929088Smarkm#if	defined(CRAY) && !defined(__STDC__)
94029088Smarkm/* Work around compiler bug in pcc 4.1.5 */
94129088Smarkm    void
94229088Smarkm_setlist_init()
94329088Smarkm{
94429088Smarkm#ifndef	KLUDGELINEMODE
94529088Smarkm#define	N 5
94629088Smarkm#else
94729088Smarkm#define	N 6
94829088Smarkm#endif
94929088Smarkm	Setlist[N+0].charp = &termFlushChar;
95029088Smarkm	Setlist[N+1].charp = &termIntChar;
95129088Smarkm	Setlist[N+2].charp = &termQuitChar;
95229088Smarkm	Setlist[N+3].charp = &termEofChar;
95329088Smarkm	Setlist[N+6].charp = &termEraseChar;
95429088Smarkm	Setlist[N+7].charp = &termKillChar;
95529088Smarkm	Setlist[N+8].charp = &termLiteralNextChar;
95629088Smarkm	Setlist[N+9].charp = &termSuspChar;
95729088Smarkm	Setlist[N+10].charp = &termRprntChar;
95829088Smarkm	Setlist[N+11].charp = &termWerasChar;
95929088Smarkm	Setlist[N+12].charp = &termStartChar;
96029088Smarkm	Setlist[N+13].charp = &termStopChar;
96129088Smarkm	Setlist[N+14].charp = &termForw1Char;
96229088Smarkm	Setlist[N+15].charp = &termForw2Char;
96329088Smarkm	Setlist[N+16].charp = &termAytChar;
96429088Smarkm#undef	N
96529088Smarkm}
96629088Smarkm#endif	/* defined(CRAY) && !defined(__STDC__) */
96729088Smarkm
96829088Smarkm    static struct setlist *
96929088Smarkmgetset(name)
97029088Smarkm    char *name;
97129088Smarkm{
97229088Smarkm    return (struct setlist *)
97329088Smarkm		genget(name, (char **) Setlist, sizeof(struct setlist));
97429088Smarkm}
97529088Smarkm
97629088Smarkm    void
97729088Smarkmset_escape_char(s)
97829088Smarkm    char *s;
97929088Smarkm{
98029088Smarkm	if (rlogin != _POSIX_VDISABLE) {
98129088Smarkm		rlogin = (s && *s) ? special(s) : _POSIX_VDISABLE;
98229088Smarkm		printf("Telnet rlogin escape character is '%s'.\n",
98329088Smarkm					control(rlogin));
98429088Smarkm	} else {
98529088Smarkm		escape = (s && *s) ? special(s) : _POSIX_VDISABLE;
98629088Smarkm		printf("Telnet escape character is '%s'.\n", control(escape));
98729088Smarkm	}
98829088Smarkm}
98929088Smarkm
99029088Smarkm    static int
99129088Smarkmsetcmd(argc, argv)
99229088Smarkm    int  argc;
99329088Smarkm    char *argv[];
99429088Smarkm{
99529088Smarkm    int value;
99629088Smarkm    struct setlist *ct;
99729088Smarkm    struct togglelist *c;
99829088Smarkm
99929088Smarkm    if (argc < 2 || argc > 3) {
100029088Smarkm	printf("Format is 'set Name Value'\n'set ?' for help.\n");
100129088Smarkm	return 0;
100229088Smarkm    }
100329088Smarkm    if ((argc == 2) && (isprefix(argv[1], "?") || isprefix(argv[1], "help"))) {
100429088Smarkm	for (ct = Setlist; ct->name; ct++)
100529088Smarkm	    printf("%-15s %s\n", ct->name, ct->help);
100629088Smarkm	printf("\n");
100729088Smarkm	settogglehelp(1);
100829088Smarkm	printf("%-15s %s\n", "?", "display help information");
100929088Smarkm	return 0;
101029088Smarkm    }
101129088Smarkm
101229088Smarkm    ct = getset(argv[1]);
101329088Smarkm    if (ct == 0) {
101429088Smarkm	c = GETTOGGLE(argv[1]);
101529088Smarkm	if (c == 0) {
101629088Smarkm	    fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n",
101729088Smarkm			argv[1]);
101829088Smarkm	    return 0;
101929088Smarkm	} else if (Ambiguous(c)) {
102029088Smarkm	    fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
102129088Smarkm			argv[1]);
102229088Smarkm	    return 0;
102329088Smarkm	}
102429088Smarkm	if (c->variable) {
102529088Smarkm	    if ((argc == 2) || (strcmp("on", argv[2]) == 0))
102629088Smarkm		*c->variable = 1;
102729088Smarkm	    else if (strcmp("off", argv[2]) == 0)
102829088Smarkm		*c->variable = 0;
102929088Smarkm	    else {
103029088Smarkm		printf("Format is 'set togglename [on|off]'\n'set ?' for help.\n");
103129088Smarkm		return 0;
103229088Smarkm	    }
103329088Smarkm	    if (c->actionexplanation) {
103429088Smarkm		printf("%s %s.\n", *c->variable? "Will" : "Won't",
103529088Smarkm							c->actionexplanation);
103629088Smarkm	    }
103729088Smarkm	}
103829088Smarkm	if (c->handler)
103929088Smarkm	    (*c->handler)(1);
104029088Smarkm    } else if (argc != 3) {
104129088Smarkm	printf("Format is 'set Name Value'\n'set ?' for help.\n");
104229088Smarkm	return 0;
104329088Smarkm    } else if (Ambiguous(ct)) {
104429088Smarkm	fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
104529088Smarkm			argv[1]);
104629088Smarkm	return 0;
104729088Smarkm    } else if (ct->handler) {
104829088Smarkm	(*ct->handler)(argv[2]);
104929088Smarkm	printf("%s set to \"%s\".\n", ct->name, (char *)ct->charp);
105029088Smarkm    } else {
105129088Smarkm	if (strcmp("off", argv[2])) {
105229088Smarkm	    value = special(argv[2]);
105329088Smarkm	} else {
105429088Smarkm	    value = _POSIX_VDISABLE;
105529088Smarkm	}
105629088Smarkm	*(ct->charp) = (cc_t)value;
105729088Smarkm	printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
105829088Smarkm    }
105929088Smarkm    slc_check();
106029088Smarkm    return 1;
106129088Smarkm}
106229088Smarkm
106329088Smarkm    static int
106429088Smarkmunsetcmd(argc, argv)
106529088Smarkm    int  argc;
106629088Smarkm    char *argv[];
106729088Smarkm{
106829088Smarkm    struct setlist *ct;
106929088Smarkm    struct togglelist *c;
107029088Smarkm    register char *name;
107129088Smarkm
107229088Smarkm    if (argc < 2) {
107329088Smarkm	fprintf(stderr,
107429088Smarkm	    "Need an argument to 'unset' command.  'unset ?' for help.\n");
107529088Smarkm	return 0;
107629088Smarkm    }
107729088Smarkm    if (isprefix(argv[1], "?") || isprefix(argv[1], "help")) {
107829088Smarkm	for (ct = Setlist; ct->name; ct++)
107929088Smarkm	    printf("%-15s %s\n", ct->name, ct->help);
108029088Smarkm	printf("\n");
108129088Smarkm	settogglehelp(0);
108229088Smarkm	printf("%-15s %s\n", "?", "display help information");
108329088Smarkm	return 0;
108429088Smarkm    }
108529088Smarkm
108629088Smarkm    argc--;
108729088Smarkm    argv++;
108829088Smarkm    while (argc--) {
108929088Smarkm	name = *argv++;
109029088Smarkm	ct = getset(name);
109129088Smarkm	if (ct == 0) {
109229088Smarkm	    c = GETTOGGLE(name);
109329088Smarkm	    if (c == 0) {
109429088Smarkm		fprintf(stderr, "'%s': unknown argument ('unset ?' for help).\n",
109529088Smarkm			name);
109629088Smarkm		return 0;
109729088Smarkm	    } else if (Ambiguous(c)) {
109829088Smarkm		fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n",
109929088Smarkm			name);
110029088Smarkm		return 0;
110129088Smarkm	    }
110229088Smarkm	    if (c->variable) {
110329088Smarkm		*c->variable = 0;
110429088Smarkm		if (c->actionexplanation) {
110529088Smarkm		    printf("%s %s.\n", *c->variable? "Will" : "Won't",
110629088Smarkm							c->actionexplanation);
110729088Smarkm		}
110829088Smarkm	    }
110929088Smarkm	    if (c->handler)
111029088Smarkm		(*c->handler)(0);
111129088Smarkm	} else if (Ambiguous(ct)) {
111229088Smarkm	    fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n",
111329088Smarkm			name);
111429088Smarkm	    return 0;
111529088Smarkm	} else if (ct->handler) {
111629088Smarkm	    (*ct->handler)(0);
111729088Smarkm	    printf("%s reset to \"%s\".\n", ct->name, (char *)ct->charp);
111829088Smarkm	} else {
111929088Smarkm	    *(ct->charp) = _POSIX_VDISABLE;
112029088Smarkm	    printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
112129088Smarkm	}
112229088Smarkm    }
112329088Smarkm    return 1;
112429088Smarkm}
112529088Smarkm
112629088Smarkm/*
112729088Smarkm * The following are the data structures and routines for the
112829088Smarkm * 'mode' command.
112929088Smarkm */
113029088Smarkm#ifdef	KLUDGELINEMODE
113129088Smarkmextern int kludgelinemode;
113229088Smarkm
113347973Sru    static int
113429088Smarkmdokludgemode()
113529088Smarkm{
113629088Smarkm    kludgelinemode = 1;
113729088Smarkm    send_wont(TELOPT_LINEMODE, 1);
113829088Smarkm    send_dont(TELOPT_SGA, 1);
113929088Smarkm    send_dont(TELOPT_ECHO, 1);
114049861Snsayer    return 1;
114129088Smarkm}
114229088Smarkm#endif
114329088Smarkm
114429088Smarkm    static int
114529088Smarkmdolinemode()
114629088Smarkm{
114729088Smarkm#ifdef	KLUDGELINEMODE
114829088Smarkm    if (kludgelinemode)
114929088Smarkm	send_dont(TELOPT_SGA, 1);
115029088Smarkm#endif
115129088Smarkm    send_will(TELOPT_LINEMODE, 1);
115229088Smarkm    send_dont(TELOPT_ECHO, 1);
115329088Smarkm    return 1;
115429088Smarkm}
115529088Smarkm
115629088Smarkm    static int
115729088Smarkmdocharmode()
115829088Smarkm{
115929088Smarkm#ifdef	KLUDGELINEMODE
116029088Smarkm    if (kludgelinemode)
116129088Smarkm	send_do(TELOPT_SGA, 1);
116229088Smarkm    else
116329088Smarkm#endif
116429088Smarkm    send_wont(TELOPT_LINEMODE, 1);
116529088Smarkm    send_do(TELOPT_ECHO, 1);
116629088Smarkm    return 1;
116729088Smarkm}
116829088Smarkm
116929088Smarkm    static int
117029088Smarkmdolmmode(bit, on)
117129088Smarkm    int bit, on;
117229088Smarkm{
117329088Smarkm    unsigned char c;
117429088Smarkm    extern int linemode;
117529088Smarkm
117629088Smarkm    if (my_want_state_is_wont(TELOPT_LINEMODE)) {
117729088Smarkm	printf("?Need to have LINEMODE option enabled first.\n");
117829088Smarkm	printf("'mode ?' for help.\n");
117929088Smarkm	return 0;
118029088Smarkm    }
118129088Smarkm
118229088Smarkm    if (on)
118329088Smarkm	c = (linemode | bit);
118429088Smarkm    else
118529088Smarkm	c = (linemode & ~bit);
118629088Smarkm    lm_mode(&c, 1, 1);
118729088Smarkm    return 1;
118829088Smarkm}
118929088Smarkm
119029088Smarkm    int
119129181Smarkmsetmod(bit)
119229088Smarkm{
119329088Smarkm    return dolmmode(bit, 1);
119429088Smarkm}
119529088Smarkm
119629088Smarkm    int
119729088Smarkmclearmode(bit)
119829088Smarkm{
119929088Smarkm    return dolmmode(bit, 0);
120029088Smarkm}
120129088Smarkm
120229088Smarkmstruct modelist {
120329088Smarkm	char	*name;		/* command name */
120429088Smarkm	char	*help;		/* help string */
120529088Smarkm	int	(*handler)();	/* routine which executes command */
120629088Smarkm	int	needconnect;	/* Do we need to be connected to execute? */
120729088Smarkm	int	arg1;
120829088Smarkm};
120929088Smarkm
121029088Smarkmextern int modehelp();
121129088Smarkm
121229088Smarkmstatic struct modelist ModeList[] = {
121329088Smarkm    { "character", "Disable LINEMODE option",	docharmode, 1 },
121429088Smarkm#ifdef	KLUDGELINEMODE
121529088Smarkm    { "",	"(or disable obsolete line-by-line mode)", 0 },
121629088Smarkm#endif
121729088Smarkm    { "line",	"Enable LINEMODE option",	dolinemode, 1 },
121829088Smarkm#ifdef	KLUDGELINEMODE
121929088Smarkm    { "",	"(or enable obsolete line-by-line mode)", 0 },
122029088Smarkm#endif
122129088Smarkm    { "", "", 0 },
122229088Smarkm    { "",	"These require the LINEMODE option to be enabled", 0 },
122329181Smarkm    { "isig",	"Enable signal trapping",	setmod, 1, MODE_TRAPSIG },
122429181Smarkm    { "+isig",	0,				setmod, 1, MODE_TRAPSIG },
122529088Smarkm    { "-isig",	"Disable signal trapping",	clearmode, 1, MODE_TRAPSIG },
122629181Smarkm    { "edit",	"Enable character editing",	setmod, 1, MODE_EDIT },
122729181Smarkm    { "+edit",	0,				setmod, 1, MODE_EDIT },
122829088Smarkm    { "-edit",	"Disable character editing",	clearmode, 1, MODE_EDIT },
122929181Smarkm    { "softtabs", "Enable tab expansion",	setmod, 1, MODE_SOFT_TAB },
123029181Smarkm    { "+softtabs", 0,				setmod, 1, MODE_SOFT_TAB },
123129088Smarkm    { "-softtabs", "Disable character editing",	clearmode, 1, MODE_SOFT_TAB },
123229181Smarkm    { "litecho", "Enable literal character echo", setmod, 1, MODE_LIT_ECHO },
123329181Smarkm    { "+litecho", 0,				setmod, 1, MODE_LIT_ECHO },
123429088Smarkm    { "-litecho", "Disable literal character echo", clearmode, 1, MODE_LIT_ECHO },
123529088Smarkm    { "help",	0,				modehelp, 0 },
123629088Smarkm#ifdef	KLUDGELINEMODE
123729088Smarkm    { "kludgeline", 0,				dokludgemode, 1 },
123829088Smarkm#endif
123929088Smarkm    { "", "", 0 },
124029088Smarkm    { "?",	"Print help information",	modehelp, 0 },
124129088Smarkm    { 0 },
124229088Smarkm};
124329088Smarkm
124429088Smarkm
124529088Smarkm    int
124629088Smarkmmodehelp()
124729088Smarkm{
124829088Smarkm    struct modelist *mt;
124929088Smarkm
125029088Smarkm    printf("format is:  'mode Mode', where 'Mode' is one of:\n\n");
125129088Smarkm    for (mt = ModeList; mt->name; mt++) {
125229088Smarkm	if (mt->help) {
125329088Smarkm	    if (*mt->help)
125429088Smarkm		printf("%-15s %s\n", mt->name, mt->help);
125529088Smarkm	    else
125629088Smarkm		printf("\n");
125729088Smarkm	}
125829088Smarkm    }
125929088Smarkm    return 0;
126029088Smarkm}
126129088Smarkm
126229088Smarkm#define	GETMODECMD(name) (struct modelist *) \
126329088Smarkm		genget(name, (char **) ModeList, sizeof(struct modelist))
126429088Smarkm
126529088Smarkm    static int
126629088Smarkmmodecmd(argc, argv)
126729088Smarkm    int  argc;
126829088Smarkm    char *argv[];
126929088Smarkm{
127029088Smarkm    struct modelist *mt;
127129088Smarkm
127229088Smarkm    if (argc != 2) {
127329088Smarkm	printf("'mode' command requires an argument\n");
127429088Smarkm	printf("'mode ?' for help.\n");
127529088Smarkm    } else if ((mt = GETMODECMD(argv[1])) == 0) {
127629088Smarkm	fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]);
127729088Smarkm    } else if (Ambiguous(mt)) {
127829088Smarkm	fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]);
127929088Smarkm    } else if (mt->needconnect && !connected) {
128029088Smarkm	printf("?Need to be connected first.\n");
128129088Smarkm	printf("'mode ?' for help.\n");
128229088Smarkm    } else if (mt->handler) {
128329088Smarkm	return (*mt->handler)(mt->arg1);
128429088Smarkm    }
128529088Smarkm    return 0;
128629088Smarkm}
128729088Smarkm
128829088Smarkm/*
128929088Smarkm * The following data structures and routines implement the
129029088Smarkm * "display" command.
129129088Smarkm */
129229088Smarkm
129329088Smarkm    static int
129429088Smarkmdisplay(argc, argv)
129529088Smarkm    int  argc;
129629088Smarkm    char *argv[];
129729088Smarkm{
129829088Smarkm    struct togglelist *tl;
129929088Smarkm    struct setlist *sl;
130029088Smarkm
130129088Smarkm#define	dotog(tl)	if (tl->variable && tl->actionexplanation) { \
130229088Smarkm			    if (*tl->variable) { \
130329088Smarkm				printf("will"); \
130429088Smarkm			    } else { \
130529088Smarkm				printf("won't"); \
130629088Smarkm			    } \
130729088Smarkm			    printf(" %s.\n", tl->actionexplanation); \
130829088Smarkm			}
130929088Smarkm
131029088Smarkm#define	doset(sl)   if (sl->name && *sl->name != ' ') { \
131129088Smarkm			if (sl->handler == 0) \
131229088Smarkm			    printf("%-15s [%s]\n", sl->name, control(*sl->charp)); \
131329088Smarkm			else \
131429088Smarkm			    printf("%-15s \"%s\"\n", sl->name, (char *)sl->charp); \
131529088Smarkm		    }
131629088Smarkm
131729088Smarkm    if (argc == 1) {
131829088Smarkm	for (tl = Togglelist; tl->name; tl++) {
131929088Smarkm	    dotog(tl);
132029088Smarkm	}
132129088Smarkm	printf("\n");
132229088Smarkm	for (sl = Setlist; sl->name; sl++) {
132329088Smarkm	    doset(sl);
132429088Smarkm	}
132529088Smarkm    } else {
132629088Smarkm	int i;
132729088Smarkm
132829088Smarkm	for (i = 1; i < argc; i++) {
132929088Smarkm	    sl = getset(argv[i]);
133029088Smarkm	    tl = GETTOGGLE(argv[i]);
133129088Smarkm	    if (Ambiguous(sl) || Ambiguous(tl)) {
133229088Smarkm		printf("?Ambiguous argument '%s'.\n", argv[i]);
133329088Smarkm		return 0;
133429088Smarkm	    } else if (!sl && !tl) {
133529088Smarkm		printf("?Unknown argument '%s'.\n", argv[i]);
133629088Smarkm		return 0;
133729088Smarkm	    } else {
133829088Smarkm		if (tl) {
133929088Smarkm		    dotog(tl);
134029088Smarkm		}
134129088Smarkm		if (sl) {
134229088Smarkm		    doset(sl);
134329088Smarkm		}
134429088Smarkm	    }
134529088Smarkm	}
134629088Smarkm    }
134729088Smarkm/*@*/optionstatus();
134829088Smarkm#ifdef	ENCRYPTION
134929088Smarkm    EncryptStatus();
135029088Smarkm#endif	/* ENCRYPTION */
135129088Smarkm    return 1;
135229088Smarkm#undef	doset
135329088Smarkm#undef	dotog
135429088Smarkm}
135529088Smarkm
135629088Smarkm/*
135729088Smarkm * The following are the data structures, and many of the routines,
135829088Smarkm * relating to command processing.
135929088Smarkm */
136029088Smarkm
136129088Smarkm/*
136229088Smarkm * Set the escape character.
136329088Smarkm */
136429088Smarkm	static int
136529088Smarkmsetescape(argc, argv)
136629088Smarkm	int argc;
136729088Smarkm	char *argv[];
136829088Smarkm{
136929088Smarkm	register char *arg;
137029088Smarkm	char buf[50];
137129088Smarkm
137229088Smarkm	printf(
137329088Smarkm	    "Deprecated usage - please use 'set escape%s%s' in the future.\n",
137429088Smarkm				(argc > 2)? " ":"", (argc > 2)? argv[1]: "");
137529088Smarkm	if (argc > 2)
137629088Smarkm		arg = argv[1];
137729088Smarkm	else {
137829088Smarkm		printf("new escape character: ");
137929088Smarkm		(void) fgets(buf, sizeof(buf), stdin);
138029088Smarkm		arg = buf;
138129088Smarkm	}
138229088Smarkm	if (arg[0] != '\0')
138329088Smarkm		escape = arg[0];
138429088Smarkm	if (!In3270) {
138529088Smarkm		printf("Escape character is '%s'.\n", control(escape));
138629088Smarkm	}
138729088Smarkm	(void) fflush(stdout);
138829088Smarkm	return 1;
138929088Smarkm}
139029088Smarkm
139129088Smarkm    /*VARARGS*/
139229088Smarkm    static int
139329088Smarkmtogcrmod()
139429088Smarkm{
139529088Smarkm    crmod = !crmod;
139629088Smarkm    printf("Deprecated usage - please use 'toggle crmod' in the future.\n");
139729088Smarkm    printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't");
139829088Smarkm    (void) fflush(stdout);
139929088Smarkm    return 1;
140029088Smarkm}
140129088Smarkm
140229088Smarkm    /*VARARGS*/
140329088Smarkm    int
140429088Smarkmsuspend()
140529088Smarkm{
140629088Smarkm#ifdef	SIGTSTP
140729088Smarkm    setcommandmode();
140829088Smarkm    {
140929088Smarkm	long oldrows, oldcols, newrows, newcols, err;
141029088Smarkm
141129088Smarkm	err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0;
141229088Smarkm	(void) kill(0, SIGTSTP);
141329088Smarkm	/*
141429088Smarkm	 * If we didn't get the window size before the SUSPEND, but we
141529088Smarkm	 * can get them now (?), then send the NAWS to make sure that
141629088Smarkm	 * we are set up for the right window size.
141729088Smarkm	 */
141829088Smarkm	if (TerminalWindowSize(&newrows, &newcols) && connected &&
141929088Smarkm	    (err || ((oldrows != newrows) || (oldcols != newcols)))) {
142029088Smarkm		sendnaws();
142129088Smarkm	}
142229088Smarkm    }
142329088Smarkm    /* reget parameters in case they were changed */
142429088Smarkm    TerminalSaveState();
142529088Smarkm    setconnmode(0);
142629088Smarkm#else
142729088Smarkm    printf("Suspend is not supported.  Try the '!' command instead\n");
142829088Smarkm#endif
142929088Smarkm    return 1;
143029088Smarkm}
143129088Smarkm
143229088Smarkm#if	!defined(TN3270)
143329088Smarkm    /*ARGSUSED*/
143429088Smarkm    int
143529088Smarkmshell(argc, argv)
143629088Smarkm    int argc;
143729088Smarkm    char *argv[];
143829088Smarkm{
143929088Smarkm    long oldrows, oldcols, newrows, newcols, err;
144029088Smarkm
144129088Smarkm    setcommandmode();
144229088Smarkm
144329088Smarkm    err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0;
144429088Smarkm    switch(vfork()) {
144529088Smarkm    case -1:
144629088Smarkm	perror("Fork failed\n");
144729088Smarkm	break;
144829088Smarkm
144929088Smarkm    case 0:
145029088Smarkm	{
145129088Smarkm	    /*
145229088Smarkm	     * Fire up the shell in the child.
145329088Smarkm	     */
145429088Smarkm	    register char *shellp, *shellname;
145529088Smarkm	    extern char *strrchr();
145629088Smarkm
145729088Smarkm	    shellp = getenv("SHELL");
145829088Smarkm	    if (shellp == NULL)
145929088Smarkm		shellp = "/bin/sh";
146029088Smarkm	    if ((shellname = strrchr(shellp, '/')) == 0)
146129088Smarkm		shellname = shellp;
146229088Smarkm	    else
146329088Smarkm		shellname++;
146429088Smarkm	    if (argc > 1)
146529088Smarkm		execl(shellp, shellname, "-c", &saveline[1], 0);
146629088Smarkm	    else
146729088Smarkm		execl(shellp, shellname, 0);
146829088Smarkm	    perror("Execl");
146929088Smarkm	    _exit(1);
147029088Smarkm	}
147129088Smarkm    default:
147229088Smarkm	    (void)wait((int *)0);	/* Wait for the shell to complete */
147329088Smarkm
147429088Smarkm	    if (TerminalWindowSize(&newrows, &newcols) && connected &&
147529088Smarkm		(err || ((oldrows != newrows) || (oldcols != newcols)))) {
147629088Smarkm		    sendnaws();
147729088Smarkm	    }
147829088Smarkm	    break;
147929088Smarkm    }
148029088Smarkm    return 1;
148129088Smarkm}
148229088Smarkm#else	/* !defined(TN3270) */
148329088Smarkmextern int shell();
148429088Smarkm#endif	/* !defined(TN3270) */
148529088Smarkm
148629088Smarkm    /*VARARGS*/
148729181Smarkm    static int
148829088Smarkmbye(argc, argv)
148929088Smarkm    int  argc;		/* Number of arguments */
149029088Smarkm    char *argv[];	/* arguments */
149129088Smarkm{
149229088Smarkm    extern int resettermname;
149329088Smarkm
149429088Smarkm    if (connected) {
149529088Smarkm	(void) shutdown(net, 2);
149629088Smarkm	printf("Connection closed.\n");
149729088Smarkm	(void) NetClose(net);
149829088Smarkm	connected = 0;
149929088Smarkm	resettermname = 1;
150029088Smarkm#if	defined(AUTHENTICATION) || defined(ENCRYPTION)
150129088Smarkm	auth_encrypt_connect(connected);
150229088Smarkm#endif	/* defined(AUTHENTICATION) || defined(ENCRYPTION) */
150329088Smarkm	/* reset options */
150429088Smarkm	tninit();
150529088Smarkm#if	defined(TN3270)
150629088Smarkm	SetIn3270();		/* Get out of 3270 mode */
150729088Smarkm#endif	/* defined(TN3270) */
150829088Smarkm    }
150929088Smarkm    if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) {
151029088Smarkm	longjmp(toplevel, 1);
151129088Smarkm	/* NOTREACHED */
151229088Smarkm    }
151329088Smarkm    return 1;			/* Keep lint, etc., happy */
151429088Smarkm}
151529088Smarkm
151629088Smarkm/*VARARGS*/
151729181Smarkm	int
151829088Smarkmquit()
151929088Smarkm{
152029088Smarkm	(void) call(bye, "bye", "fromquit", 0);
152129088Smarkm	Exit(0);
152229088Smarkm	/*NOTREACHED*/
152329088Smarkm}
152429088Smarkm
152529088Smarkm/*VARARGS*/
152629088Smarkm	int
152729088Smarkmlogout()
152829088Smarkm{
152929088Smarkm	send_do(TELOPT_LOGOUT, 1);
153029088Smarkm	(void) netflush();
153129088Smarkm	return 1;
153229088Smarkm}
153329088Smarkm
153429088Smarkm
153529088Smarkm/*
153629088Smarkm * The SLC command.
153729088Smarkm */
153829088Smarkm
153929088Smarkmstruct slclist {
154029088Smarkm	char	*name;
154129088Smarkm	char	*help;
154229088Smarkm	void	(*handler)();
154329088Smarkm	int	arg;
154429088Smarkm};
154529088Smarkm
154629088Smarkmstatic void slc_help();
154729088Smarkm
154829088Smarkmstruct slclist SlcList[] = {
154929088Smarkm    { "export",	"Use local special character definitions",
155029088Smarkm						slc_mode_export,	0 },
155129088Smarkm    { "import",	"Use remote special character definitions",
155229088Smarkm						slc_mode_import,	1 },
155329088Smarkm    { "check",	"Verify remote special character definitions",
155429088Smarkm						slc_mode_import,	0 },
155529088Smarkm    { "help",	0,				slc_help,		0 },
155629088Smarkm    { "?",	"Print help information",	slc_help,		0 },
155729088Smarkm    { 0 },
155829088Smarkm};
155929088Smarkm
156029088Smarkm    static void
156129088Smarkmslc_help()
156229088Smarkm{
156329088Smarkm    struct slclist *c;
156429088Smarkm
156529088Smarkm    for (c = SlcList; c->name; c++) {
156629088Smarkm	if (c->help) {
156729088Smarkm	    if (*c->help)
156829088Smarkm		printf("%-15s %s\n", c->name, c->help);
156929088Smarkm	    else
157029088Smarkm		printf("\n");
157129088Smarkm	}
157229088Smarkm    }
157329088Smarkm}
157429088Smarkm
157529088Smarkm    static struct slclist *
157629088Smarkmgetslc(name)
157729088Smarkm    char *name;
157829088Smarkm{
157929088Smarkm    return (struct slclist *)
158029088Smarkm		genget(name, (char **) SlcList, sizeof(struct slclist));
158129088Smarkm}
158229088Smarkm
158329181Smarkm    static int
158429088Smarkmslccmd(argc, argv)
158529088Smarkm    int  argc;
158629088Smarkm    char *argv[];
158729088Smarkm{
158829088Smarkm    struct slclist *c;
158929088Smarkm
159029088Smarkm    if (argc != 2) {
159129088Smarkm	fprintf(stderr,
159229088Smarkm	    "Need an argument to 'slc' command.  'slc ?' for help.\n");
159329088Smarkm	return 0;
159429088Smarkm    }
159529088Smarkm    c = getslc(argv[1]);
159629088Smarkm    if (c == 0) {
159729088Smarkm	fprintf(stderr, "'%s': unknown argument ('slc ?' for help).\n",
159829088Smarkm    				argv[1]);
159929088Smarkm	return 0;
160029088Smarkm    }
160129088Smarkm    if (Ambiguous(c)) {
160229088Smarkm	fprintf(stderr, "'%s': ambiguous argument ('slc ?' for help).\n",
160329088Smarkm    				argv[1]);
160429088Smarkm	return 0;
160529088Smarkm    }
160629088Smarkm    (*c->handler)(c->arg);
160729088Smarkm    slcstate();
160829088Smarkm    return 1;
160929088Smarkm}
161029088Smarkm
161129088Smarkm/*
161229088Smarkm * The ENVIRON command.
161329088Smarkm */
161429088Smarkm
161529088Smarkmstruct envlist {
161629088Smarkm	char	*name;
161729088Smarkm	char	*help;
161829088Smarkm	void	(*handler)();
161929088Smarkm	int	narg;
162029088Smarkm};
162129088Smarkm
162229088Smarkmextern struct env_lst *
162329088Smarkm	env_define P((unsigned char *, unsigned char *));
162429088Smarkmextern void
162529088Smarkm	env_undefine P((unsigned char *)),
162629088Smarkm	env_export P((unsigned char *)),
162729088Smarkm	env_unexport P((unsigned char *)),
162829088Smarkm	env_send P((unsigned char *)),
162929088Smarkm#if defined(OLD_ENVIRON) && defined(ENV_HACK)
163029088Smarkm	env_varval P((unsigned char *)),
163129088Smarkm#endif
163229088Smarkm	env_list P((void));
163329088Smarkmstatic void
163429088Smarkm	env_help P((void));
163529088Smarkm
163629088Smarkmstruct envlist EnvList[] = {
163729088Smarkm    { "define",	"Define an environment variable",
163829088Smarkm						(void (*)())env_define,	2 },
163929088Smarkm    { "undefine", "Undefine an environment variable",
164029088Smarkm						env_undefine,	1 },
164129088Smarkm    { "export",	"Mark an environment variable for automatic export",
164229088Smarkm						env_export,	1 },
164329088Smarkm    { "unexport", "Don't mark an environment variable for automatic export",
164429088Smarkm						env_unexport,	1 },
164529088Smarkm    { "send",	"Send an environment variable", env_send,	1 },
164629088Smarkm    { "list",	"List the current environment variables",
164729088Smarkm						env_list,	0 },
164829088Smarkm#if defined(OLD_ENVIRON) && defined(ENV_HACK)
164929088Smarkm    { "varval", "Reverse VAR and VALUE (auto, right, wrong, status)",
165029088Smarkm						env_varval,    1 },
165129088Smarkm#endif
165229088Smarkm    { "help",	0,				env_help,		0 },
165329088Smarkm    { "?",	"Print help information",	env_help,		0 },
165429088Smarkm    { 0 },
165529088Smarkm};
165629088Smarkm
165729088Smarkm    static void
165829088Smarkmenv_help()
165929088Smarkm{
166029088Smarkm    struct envlist *c;
166129088Smarkm
166229088Smarkm    for (c = EnvList; c->name; c++) {
166329088Smarkm	if (c->help) {
166429088Smarkm	    if (*c->help)
166529088Smarkm		printf("%-15s %s\n", c->name, c->help);
166629088Smarkm	    else
166729088Smarkm		printf("\n");
166829088Smarkm	}
166929088Smarkm    }
167029088Smarkm}
167129088Smarkm
167229088Smarkm    static struct envlist *
167329088Smarkmgetenvcmd(name)
167429088Smarkm    char *name;
167529088Smarkm{
167629088Smarkm    return (struct envlist *)
167729088Smarkm		genget(name, (char **) EnvList, sizeof(struct envlist));
167829088Smarkm}
167929088Smarkm
168029181Smarkm	int
168129088Smarkmenv_cmd(argc, argv)
168229088Smarkm    int  argc;
168329088Smarkm    char *argv[];
168429088Smarkm{
168529088Smarkm    struct envlist *c;
168629088Smarkm
168729088Smarkm    if (argc < 2) {
168829088Smarkm	fprintf(stderr,
168929088Smarkm	    "Need an argument to 'environ' command.  'environ ?' for help.\n");
169029088Smarkm	return 0;
169129088Smarkm    }
169229088Smarkm    c = getenvcmd(argv[1]);
169329088Smarkm    if (c == 0) {
169429088Smarkm	fprintf(stderr, "'%s': unknown argument ('environ ?' for help).\n",
169529088Smarkm    				argv[1]);
169629088Smarkm	return 0;
169729088Smarkm    }
169829088Smarkm    if (Ambiguous(c)) {
169929088Smarkm	fprintf(stderr, "'%s': ambiguous argument ('environ ?' for help).\n",
170029088Smarkm    				argv[1]);
170129088Smarkm	return 0;
170229088Smarkm    }
170329088Smarkm    if (c->narg + 2 != argc) {
170429088Smarkm	fprintf(stderr,
170529088Smarkm	    "Need %s%d argument%s to 'environ %s' command.  'environ ?' for help.\n",
170629088Smarkm		c->narg < argc + 2 ? "only " : "",
170729088Smarkm		c->narg, c->narg == 1 ? "" : "s", c->name);
170829088Smarkm	return 0;
170929088Smarkm    }
171029088Smarkm    (*c->handler)(argv[2], argv[3]);
171129088Smarkm    return 1;
171229088Smarkm}
171329088Smarkm
171429088Smarkmstruct env_lst {
171529088Smarkm	struct env_lst *next;	/* pointer to next structure */
171629088Smarkm	struct env_lst *prev;	/* pointer to previous structure */
171729088Smarkm	unsigned char *var;	/* pointer to variable name */
171829088Smarkm	unsigned char *value;	/* pointer to variable value */
171929088Smarkm	int export;		/* 1 -> export with default list of variables */
172029088Smarkm	int welldefined;	/* A well defined variable */
172129088Smarkm};
172229088Smarkm
172329088Smarkmstruct env_lst envlisthead;
172429088Smarkm
172529088Smarkm	struct env_lst *
172629088Smarkmenv_find(var)
172729088Smarkm	unsigned char *var;
172829088Smarkm{
172929088Smarkm	register struct env_lst *ep;
173029088Smarkm
173129088Smarkm	for (ep = envlisthead.next; ep; ep = ep->next) {
173229088Smarkm		if (strcmp((char *)ep->var, (char *)var) == 0)
173329088Smarkm			return(ep);
173429088Smarkm	}
173529088Smarkm	return(NULL);
173629088Smarkm}
173729088Smarkm
173829088Smarkm	void
173929088Smarkmenv_init()
174029088Smarkm{
174129088Smarkm	extern char **environ;
174229088Smarkm	register char **epp, *cp;
174329088Smarkm	register struct env_lst *ep;
174429088Smarkm	extern char *strchr();
174529088Smarkm
174629088Smarkm	for (epp = environ; *epp; epp++) {
174729181Smarkm		if ((cp = strchr(*epp, '='))) {
174829088Smarkm			*cp = '\0';
174929088Smarkm			ep = env_define((unsigned char *)*epp,
175029088Smarkm					(unsigned char *)cp+1);
175129088Smarkm			ep->export = 0;
175229088Smarkm			*cp = '=';
175329088Smarkm		}
175429088Smarkm	}
175529088Smarkm	/*
175629088Smarkm	 * Special case for DISPLAY variable.  If it is ":0.0" or
175729088Smarkm	 * "unix:0.0", we have to get rid of "unix" and insert our
175829088Smarkm	 * hostname.
175929088Smarkm	 */
176029088Smarkm	if ((ep = env_find("DISPLAY"))
176129088Smarkm	    && ((*ep->value == ':')
176229088Smarkm		|| (strncmp((char *)ep->value, "unix:", 5) == 0))) {
176329088Smarkm		char hbuf[256+1];
176429088Smarkm		char *cp2 = strchr((char *)ep->value, ':');
176529088Smarkm
176629088Smarkm		gethostname(hbuf, 256);
176729088Smarkm		hbuf[256] = '\0';
176829088Smarkm		cp = (char *)malloc(strlen(hbuf) + strlen(cp2) + 1);
176929088Smarkm		sprintf((char *)cp, "%s%s", hbuf, cp2);
177029088Smarkm		free(ep->value);
177129088Smarkm		ep->value = (unsigned char *)cp;
177229088Smarkm	}
177329088Smarkm	/*
177429088Smarkm	 * If USER is not defined, but LOGNAME is, then add
177529088Smarkm	 * USER with the value from LOGNAME.  By default, we
177629088Smarkm	 * don't export the USER variable.
177729088Smarkm	 */
177829088Smarkm	if ((env_find("USER") == NULL) && (ep = env_find("LOGNAME"))) {
177929088Smarkm		env_define((unsigned char *)"USER", ep->value);
178029088Smarkm		env_unexport((unsigned char *)"USER");
178129088Smarkm	}
178229088Smarkm	env_export((unsigned char *)"DISPLAY");
178329088Smarkm	env_export((unsigned char *)"PRINTER");
178429088Smarkm}
178529088Smarkm
178629088Smarkm	struct env_lst *
178729088Smarkmenv_define(var, value)
178829088Smarkm	unsigned char *var, *value;
178929088Smarkm{
179029088Smarkm	register struct env_lst *ep;
179129088Smarkm
179229181Smarkm	if ((ep = env_find(var))) {
179329088Smarkm		if (ep->var)
179429088Smarkm			free(ep->var);
179529088Smarkm		if (ep->value)
179629088Smarkm			free(ep->value);
179729088Smarkm	} else {
179829088Smarkm		ep = (struct env_lst *)malloc(sizeof(struct env_lst));
179929088Smarkm		ep->next = envlisthead.next;
180029088Smarkm		envlisthead.next = ep;
180129088Smarkm		ep->prev = &envlisthead;
180229088Smarkm		if (ep->next)
180329088Smarkm			ep->next->prev = ep;
180429088Smarkm	}
180529088Smarkm	ep->welldefined = opt_welldefined(var);
180629088Smarkm	ep->export = 1;
180729088Smarkm	ep->var = (unsigned char *)strdup((char *)var);
180829088Smarkm	ep->value = (unsigned char *)strdup((char *)value);
180929088Smarkm	return(ep);
181029088Smarkm}
181129088Smarkm
181229088Smarkm	void
181329088Smarkmenv_undefine(var)
181429088Smarkm	unsigned char *var;
181529088Smarkm{
181629088Smarkm	register struct env_lst *ep;
181729088Smarkm
181829181Smarkm	if ((ep = env_find(var))) {
181929088Smarkm		ep->prev->next = ep->next;
182029088Smarkm		if (ep->next)
182129088Smarkm			ep->next->prev = ep->prev;
182229088Smarkm		if (ep->var)
182329088Smarkm			free(ep->var);
182429088Smarkm		if (ep->value)
182529088Smarkm			free(ep->value);
182629088Smarkm		free(ep);
182729088Smarkm	}
182829088Smarkm}
182929088Smarkm
183029088Smarkm	void
183129088Smarkmenv_export(var)
183229088Smarkm	unsigned char *var;
183329088Smarkm{
183429088Smarkm	register struct env_lst *ep;
183529088Smarkm
183629181Smarkm	if ((ep = env_find(var)))
183729088Smarkm		ep->export = 1;
183829088Smarkm}
183929088Smarkm
184029088Smarkm	void
184129088Smarkmenv_unexport(var)
184229088Smarkm	unsigned char *var;
184329088Smarkm{
184429088Smarkm	register struct env_lst *ep;
184529088Smarkm
184629181Smarkm	if ((ep = env_find(var)))
184729088Smarkm		ep->export = 0;
184829088Smarkm}
184929088Smarkm
185029088Smarkm	void
185129088Smarkmenv_send(var)
185229088Smarkm	unsigned char *var;
185329088Smarkm{
185429088Smarkm	register struct env_lst *ep;
185529088Smarkm
185629088Smarkm	if (my_state_is_wont(TELOPT_NEW_ENVIRON)
185729088Smarkm#ifdef	OLD_ENVIRON
185829088Smarkm	    && my_state_is_wont(TELOPT_OLD_ENVIRON)
185929088Smarkm#endif
186029088Smarkm		) {
186129088Smarkm		fprintf(stderr,
186229088Smarkm		    "Cannot send '%s': Telnet ENVIRON option not enabled\n",
186329088Smarkm									var);
186429088Smarkm		return;
186529088Smarkm	}
186629088Smarkm	ep = env_find(var);
186729088Smarkm	if (ep == 0) {
186829088Smarkm		fprintf(stderr, "Cannot send '%s': variable not defined\n",
186929088Smarkm									var);
187029088Smarkm		return;
187129088Smarkm	}
187229088Smarkm	env_opt_start_info();
187329088Smarkm	env_opt_add(ep->var);
187429088Smarkm	env_opt_end(0);
187529088Smarkm}
187629088Smarkm
187729088Smarkm	void
187829088Smarkmenv_list()
187929088Smarkm{
188029088Smarkm	register struct env_lst *ep;
188129088Smarkm
188229088Smarkm	for (ep = envlisthead.next; ep; ep = ep->next) {
188329088Smarkm		printf("%c %-20s %s\n", ep->export ? '*' : ' ',
188429088Smarkm					ep->var, ep->value);
188529088Smarkm	}
188629088Smarkm}
188729088Smarkm
188829088Smarkm	unsigned char *
188929088Smarkmenv_default(init, welldefined)
189029088Smarkm	int init;
189129088Smarkm{
189229088Smarkm	static struct env_lst *nep = NULL;
189329088Smarkm
189429088Smarkm	if (init) {
189529088Smarkm		nep = &envlisthead;
189629181Smarkm		return(NULL);
189729088Smarkm	}
189829088Smarkm	if (nep) {
189929181Smarkm		while ((nep = nep->next)) {
190029088Smarkm			if (nep->export && (nep->welldefined == welldefined))
190129088Smarkm				return(nep->var);
190229088Smarkm		}
190329088Smarkm	}
190429088Smarkm	return(NULL);
190529088Smarkm}
190629088Smarkm
190729088Smarkm	unsigned char *
190829088Smarkmenv_getvalue(var)
190929088Smarkm	unsigned char *var;
191029088Smarkm{
191129088Smarkm	register struct env_lst *ep;
191229088Smarkm
191329181Smarkm	if ((ep = env_find(var)))
191429088Smarkm		return(ep->value);
191529088Smarkm	return(NULL);
191629088Smarkm}
191729088Smarkm
191829088Smarkm#if defined(OLD_ENVIRON) && defined(ENV_HACK)
191929088Smarkm	void
192029088Smarkmenv_varval(what)
192129088Smarkm	unsigned char *what;
192229088Smarkm{
192329088Smarkm	extern int old_env_var, old_env_value, env_auto;
192429088Smarkm	int len = strlen((char *)what);
192529088Smarkm
192629088Smarkm	if (len == 0)
192729088Smarkm		goto unknown;
192829088Smarkm
192929088Smarkm	if (strncasecmp((char *)what, "status", len) == 0) {
193029088Smarkm		if (env_auto)
193129088Smarkm			printf("%s%s", "VAR and VALUE are/will be ",
193229088Smarkm					"determined automatically\n");
193329088Smarkm		if (old_env_var == OLD_ENV_VAR)
193429088Smarkm			printf("VAR and VALUE set to correct definitions\n");
193529088Smarkm		else
193629088Smarkm			printf("VAR and VALUE definitions are reversed\n");
193729088Smarkm	} else if (strncasecmp((char *)what, "auto", len) == 0) {
193829088Smarkm		env_auto = 1;
193929088Smarkm		old_env_var = OLD_ENV_VALUE;
194029088Smarkm		old_env_value = OLD_ENV_VAR;
194129088Smarkm	} else if (strncasecmp((char *)what, "right", len) == 0) {
194229088Smarkm		env_auto = 0;
194329088Smarkm		old_env_var = OLD_ENV_VAR;
194429088Smarkm		old_env_value = OLD_ENV_VALUE;
194529088Smarkm	} else if (strncasecmp((char *)what, "wrong", len) == 0) {
194629088Smarkm		env_auto = 0;
194729088Smarkm		old_env_var = OLD_ENV_VALUE;
194829088Smarkm		old_env_value = OLD_ENV_VAR;
194929088Smarkm	} else {
195029088Smarkmunknown:
195129088Smarkm		printf("Unknown \"varval\" command. (\"auto\", \"right\", \"wrong\", \"status\")\n");
195229088Smarkm	}
195329088Smarkm}
195429088Smarkm#endif
195529088Smarkm
195629088Smarkm#if	defined(AUTHENTICATION)
195729088Smarkm/*
195829088Smarkm * The AUTHENTICATE command.
195929088Smarkm */
196029088Smarkm
196129088Smarkmstruct authlist {
196229088Smarkm	char	*name;
196329088Smarkm	char	*help;
196429088Smarkm	int	(*handler)();
196529088Smarkm	int	narg;
196629088Smarkm};
196729088Smarkm
196829088Smarkmextern int
196929088Smarkm	auth_enable P((char *)),
197029088Smarkm	auth_disable P((char *)),
197129088Smarkm	auth_status P((void));
197229088Smarkmstatic int
197329088Smarkm	auth_help P((void));
197429088Smarkm
197529088Smarkmstruct authlist AuthList[] = {
197629088Smarkm    { "status",	"Display current status of authentication information",
197729088Smarkm						auth_status,	0 },
197829088Smarkm    { "disable", "Disable an authentication type ('auth disable ?' for more)",
197929088Smarkm						auth_disable,	1 },
198029088Smarkm    { "enable", "Enable an authentication type ('auth enable ?' for more)",
198129088Smarkm						auth_enable,	1 },
198229088Smarkm    { "help",	0,				auth_help,		0 },
198329088Smarkm    { "?",	"Print help information",	auth_help,		0 },
198429088Smarkm    { 0 },
198529088Smarkm};
198629088Smarkm
198729088Smarkm    static int
198829088Smarkmauth_help()
198929088Smarkm{
199029088Smarkm    struct authlist *c;
199129088Smarkm
199229088Smarkm    for (c = AuthList; c->name; c++) {
199329088Smarkm	if (c->help) {
199429088Smarkm	    if (*c->help)
199529088Smarkm		printf("%-15s %s\n", c->name, c->help);
199629088Smarkm	    else
199729088Smarkm		printf("\n");
199829088Smarkm	}
199929088Smarkm    }
200029088Smarkm    return 0;
200129088Smarkm}
200229088Smarkm
200329181Smarkm	int
200429088Smarkmauth_cmd(argc, argv)
200529088Smarkm    int  argc;
200629088Smarkm    char *argv[];
200729088Smarkm{
200829088Smarkm    struct authlist *c;
200929088Smarkm
201029088Smarkm    if (argc < 2) {
201129088Smarkm	fprintf(stderr,
201229088Smarkm	    "Need an argument to 'auth' command.  'auth ?' for help.\n");
201329088Smarkm	return 0;
201429088Smarkm    }
201529088Smarkm
201629088Smarkm    c = (struct authlist *)
201729088Smarkm		genget(argv[1], (char **) AuthList, sizeof(struct authlist));
201829088Smarkm    if (c == 0) {
201929088Smarkm	fprintf(stderr, "'%s': unknown argument ('auth ?' for help).\n",
202029088Smarkm    				argv[1]);
202129088Smarkm	return 0;
202229088Smarkm    }
202329088Smarkm    if (Ambiguous(c)) {
202429088Smarkm	fprintf(stderr, "'%s': ambiguous argument ('auth ?' for help).\n",
202529088Smarkm    				argv[1]);
202629088Smarkm	return 0;
202729088Smarkm    }
202829088Smarkm    if (c->narg + 2 != argc) {
202929088Smarkm	fprintf(stderr,
203029088Smarkm	    "Need %s%d argument%s to 'auth %s' command.  'auth ?' for help.\n",
203129088Smarkm		c->narg < argc + 2 ? "only " : "",
203229088Smarkm		c->narg, c->narg == 1 ? "" : "s", c->name);
203329088Smarkm	return 0;
203429088Smarkm    }
203529088Smarkm    return((*c->handler)(argv[2], argv[3]));
203629088Smarkm}
203729088Smarkm#endif
203829088Smarkm
203929088Smarkm#ifdef	ENCRYPTION
204029088Smarkm/*
204129088Smarkm * The ENCRYPT command.
204229088Smarkm */
204329088Smarkm
204429088Smarkmstruct encryptlist {
204529088Smarkm	char	*name;
204629088Smarkm	char	*help;
204729088Smarkm	int	(*handler)();
204829088Smarkm	int	needconnect;
204929088Smarkm	int	minarg;
205029088Smarkm	int	maxarg;
205129088Smarkm};
205229088Smarkm
205329088Smarkmextern int
205429088Smarkm	EncryptEnable P((char *, char *)),
205529088Smarkm	EncryptDisable P((char *, char *)),
205629088Smarkm	EncryptType P((char *, char *)),
205729088Smarkm	EncryptStart P((char *)),
205829088Smarkm	EncryptStartInput P((void)),
205929088Smarkm	EncryptStartOutput P((void)),
206029088Smarkm	EncryptStop P((char *)),
206129088Smarkm	EncryptStopInput P((void)),
206229088Smarkm	EncryptStopOutput P((void)),
206329088Smarkm	EncryptStatus P((void));
206429088Smarkmstatic int
206529088Smarkm	EncryptHelp P((void));
206629088Smarkm
206729088Smarkmstruct encryptlist EncryptList[] = {
206829088Smarkm    { "enable", "Enable encryption. ('encrypt enable ?' for more)",
206929088Smarkm						EncryptEnable, 1, 1, 2 },
207029088Smarkm    { "disable", "Disable encryption. ('encrypt enable ?' for more)",
207129088Smarkm						EncryptDisable, 0, 1, 2 },
207229088Smarkm    { "type", "Set encryption type. ('encrypt type ?' for more)",
207329088Smarkm						EncryptType, 0, 1, 1 },
207429088Smarkm    { "start", "Start encryption. ('encrypt start ?' for more)",
207529088Smarkm						EncryptStart, 1, 0, 1 },
207629088Smarkm    { "stop", "Stop encryption. ('encrypt stop ?' for more)",
207729088Smarkm						EncryptStop, 1, 0, 1 },
207829088Smarkm    { "input", "Start encrypting the input stream",
207929088Smarkm						EncryptStartInput, 1, 0, 0 },
208029088Smarkm    { "-input", "Stop encrypting the input stream",
208129088Smarkm						EncryptStopInput, 1, 0, 0 },
208229088Smarkm    { "output", "Start encrypting the output stream",
208329088Smarkm						EncryptStartOutput, 1, 0, 0 },
208429088Smarkm    { "-output", "Stop encrypting the output stream",
208529088Smarkm						EncryptStopOutput, 1, 0, 0 },
208629088Smarkm
208729088Smarkm    { "status",	"Display current status of authentication information",
208829088Smarkm						EncryptStatus,	0, 0, 0 },
208929088Smarkm    { "help",	0,				EncryptHelp,	0, 0, 0 },
209029088Smarkm    { "?",	"Print help information",	EncryptHelp,	0, 0, 0 },
209129088Smarkm    { 0 },
209229088Smarkm};
209329088Smarkm
209429088Smarkm    static int
209529088SmarkmEncryptHelp()
209629088Smarkm{
209729088Smarkm    struct encryptlist *c;
209829088Smarkm
209929088Smarkm    for (c = EncryptList; c->name; c++) {
210029088Smarkm	if (c->help) {
210129088Smarkm	    if (*c->help)
210229088Smarkm		printf("%-15s %s\n", c->name, c->help);
210329088Smarkm	    else
210429088Smarkm		printf("\n");
210529088Smarkm	}
210629088Smarkm    }
210729088Smarkm    return 0;
210829088Smarkm}
210929088Smarkm
211029181Smarkm	int
211129088Smarkmencrypt_cmd(argc, argv)
211229088Smarkm    int  argc;
211329088Smarkm    char *argv[];
211429088Smarkm{
211529088Smarkm    struct encryptlist *c;
211629088Smarkm
211729088Smarkm    if (argc < 2) {
211829088Smarkm	fprintf(stderr,
211929088Smarkm	    "Need an argument to 'encrypt' command.  'encrypt ?' for help.\n");
212029088Smarkm	return 0;
212129088Smarkm    }
212229088Smarkm
212329088Smarkm    c = (struct encryptlist *)
212429088Smarkm		genget(argv[1], (char **) EncryptList, sizeof(struct encryptlist));
212529088Smarkm    if (c == 0) {
212629088Smarkm	fprintf(stderr, "'%s': unknown argument ('encrypt ?' for help).\n",
212729088Smarkm    				argv[1]);
212829088Smarkm	return 0;
212929088Smarkm    }
213029088Smarkm    if (Ambiguous(c)) {
213129088Smarkm	fprintf(stderr, "'%s': ambiguous argument ('encrypt ?' for help).\n",
213229088Smarkm    				argv[1]);
213329088Smarkm	return 0;
213429088Smarkm    }
213529088Smarkm    argc -= 2;
213629088Smarkm    if (argc < c->minarg || argc > c->maxarg) {
213729088Smarkm	if (c->minarg == c->maxarg) {
213829088Smarkm	    fprintf(stderr, "Need %s%d argument%s ",
213929088Smarkm		c->minarg < argc ? "only " : "", c->minarg,
214029088Smarkm		c->minarg == 1 ? "" : "s");
214129088Smarkm	} else {
214229088Smarkm	    fprintf(stderr, "Need %s%d-%d arguments ",
214329088Smarkm		c->maxarg < argc ? "only " : "", c->minarg, c->maxarg);
214429088Smarkm	}
214529088Smarkm	fprintf(stderr, "to 'encrypt %s' command.  'encrypt ?' for help.\n",
214629088Smarkm		c->name);
214729088Smarkm	return 0;
214829088Smarkm    }
214929088Smarkm    if (c->needconnect && !connected) {
215029088Smarkm	if (!(argc && (isprefix(argv[2], "help") || isprefix(argv[2], "?")))) {
215129088Smarkm	    printf("?Need to be connected first.\n");
215229088Smarkm	    return 0;
215329088Smarkm	}
215429088Smarkm    }
215529088Smarkm    return ((*c->handler)(argc > 0 ? argv[2] : 0,
215629088Smarkm			argc > 1 ? argv[3] : 0,
215729088Smarkm			argc > 2 ? argv[4] : 0));
215829088Smarkm}
215929088Smarkm#endif	/* ENCRYPTION */
216029088Smarkm
216129088Smarkm#if	defined(unix) && defined(TN3270)
216229088Smarkm    static void
216329088Smarkmfilestuff(fd)
216429088Smarkm    int fd;
216529088Smarkm{
216629088Smarkm    int res;
216729088Smarkm
216829088Smarkm#ifdef	F_GETOWN
216929088Smarkm    setconnmode(0);
217029088Smarkm    res = fcntl(fd, F_GETOWN, 0);
217129088Smarkm    setcommandmode();
217229088Smarkm
217329088Smarkm    if (res == -1) {
217429088Smarkm	perror("fcntl");
217529088Smarkm	return;
217629088Smarkm    }
217729088Smarkm    printf("\tOwner is %d.\n", res);
217829088Smarkm#endif
217929088Smarkm
218029088Smarkm    setconnmode(0);
218129088Smarkm    res = fcntl(fd, F_GETFL, 0);
218229088Smarkm    setcommandmode();
218329088Smarkm
218429088Smarkm    if (res == -1) {
218529088Smarkm	perror("fcntl");
218629088Smarkm	return;
218729088Smarkm    }
218829088Smarkm#ifdef notdef
218929088Smarkm    printf("\tFlags are 0x%x: %s\n", res, decodeflags(res));
219029088Smarkm#endif
219129088Smarkm}
219229088Smarkm#endif /* defined(unix) && defined(TN3270) */
219329088Smarkm
219429088Smarkm/*
219529088Smarkm * Print status about the connection.
219629088Smarkm */
219729088Smarkm    /*ARGSUSED*/
219829181Smarkm    static int
219929088Smarkmstatus(argc, argv)
220029088Smarkm    int	 argc;
220129088Smarkm    char *argv[];
220229088Smarkm{
220329088Smarkm    if (connected) {
220429088Smarkm	printf("Connected to %s.\n", hostname);
220529088Smarkm	if ((argc < 2) || strcmp(argv[1], "notmuch")) {
220629088Smarkm	    int mode = getconnmode();
220729088Smarkm
220829088Smarkm	    if (my_want_state_is_will(TELOPT_LINEMODE)) {
220929088Smarkm		printf("Operating with LINEMODE option\n");
221029088Smarkm		printf("%s line editing\n", (mode&MODE_EDIT) ? "Local" : "No");
221129088Smarkm		printf("%s catching of signals\n",
221229088Smarkm					(mode&MODE_TRAPSIG) ? "Local" : "No");
221329088Smarkm		slcstate();
221429088Smarkm#ifdef	KLUDGELINEMODE
221529088Smarkm	    } else if (kludgelinemode && my_want_state_is_dont(TELOPT_SGA)) {
221629088Smarkm		printf("Operating in obsolete linemode\n");
221729088Smarkm#endif
221829088Smarkm	    } else {
221929088Smarkm		printf("Operating in single character mode\n");
222029088Smarkm		if (localchars)
222129088Smarkm		    printf("Catching signals locally\n");
222229088Smarkm	    }
222329088Smarkm	    printf("%s character echo\n", (mode&MODE_ECHO) ? "Local" : "Remote");
222429088Smarkm	    if (my_want_state_is_will(TELOPT_LFLOW))
222529088Smarkm		printf("%s flow control\n", (mode&MODE_FLOW) ? "Local" : "No");
222629088Smarkm#ifdef	ENCRYPTION
222729088Smarkm	    encrypt_display();
222829088Smarkm#endif	/* ENCRYPTION */
222929088Smarkm	}
223029088Smarkm    } else {
223129088Smarkm	printf("No connection.\n");
223229088Smarkm    }
223329088Smarkm#   if !defined(TN3270)
223429088Smarkm    printf("Escape character is '%s'.\n", control(escape));
223529088Smarkm    (void) fflush(stdout);
223629088Smarkm#   else /* !defined(TN3270) */
223729088Smarkm    if ((!In3270) && ((argc < 2) || strcmp(argv[1], "notmuch"))) {
223829088Smarkm	printf("Escape character is '%s'.\n", control(escape));
223929088Smarkm    }
224029088Smarkm#   if defined(unix)
224129088Smarkm    if ((argc >= 2) && !strcmp(argv[1], "everything")) {
224229088Smarkm	printf("SIGIO received %d time%s.\n",
224329088Smarkm				sigiocount, (sigiocount == 1)? "":"s");
224429088Smarkm	if (In3270) {
224529088Smarkm	    printf("Process ID %d, process group %d.\n",
224629088Smarkm					    getpid(), getpgrp(getpid()));
224729088Smarkm	    printf("Terminal input:\n");
224829088Smarkm	    filestuff(tin);
224929088Smarkm	    printf("Terminal output:\n");
225029088Smarkm	    filestuff(tout);
225129088Smarkm	    printf("Network socket:\n");
225229088Smarkm	    filestuff(net);
225329088Smarkm	}
225429088Smarkm    }
225529088Smarkm    if (In3270 && transcom) {
225629088Smarkm       printf("Transparent mode command is '%s'.\n", transcom);
225729088Smarkm    }
225829088Smarkm#   endif /* defined(unix) */
225929088Smarkm    (void) fflush(stdout);
226029088Smarkm    if (In3270) {
226129088Smarkm	return 0;
226229088Smarkm    }
226329088Smarkm#   endif /* defined(TN3270) */
226429088Smarkm    return 1;
226529088Smarkm}
226629088Smarkm
226729088Smarkm#ifdef	SIGINFO
226829088Smarkm/*
226929088Smarkm * Function that gets called when SIGINFO is received.
227029088Smarkm */
227129181Smarkm	void
227229088Smarkmayt_status()
227329088Smarkm{
227429088Smarkm    (void) call(status, "status", "notmuch", 0);
227529088Smarkm}
227629088Smarkm#endif
227729088Smarkm
227856668Sshinstatic const char *
227956668Sshinsockaddr_ntop(sa)
228056668Sshin    struct sockaddr *sa;
228156668Sshin{
228256668Sshin    void *addr;
228356668Sshin    static char addrbuf[INET6_ADDRSTRLEN];
228429088Smarkm
228556668Sshin    switch (sa->sa_family) {
228656668Sshin    case AF_INET:
228756668Sshin	addr = &((struct sockaddr_in *)sa)->sin_addr;
228856668Sshin	break;
228977095Sdillon    case AF_UNIX:
229077095Sdillon	addr = &((struct sockaddr_un *)sa)->sun_path;
229177095Sdillon	break;
229256668Sshin#ifdef INET6
229356668Sshin    case AF_INET6:
229456668Sshin	addr = &((struct sockaddr_in6 *)sa)->sin6_addr;
229556668Sshin	break;
229656668Sshin#endif
229756668Sshin    default:
229856668Sshin	return NULL;
229956668Sshin    }
230056668Sshin    inet_ntop(sa->sa_family, addr, addrbuf, sizeof(addrbuf));
230156668Sshin    return addrbuf;
230256668Sshin}
230356668Sshin
230456668Sshin#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
230556668Sshinstatic int
230656668Sshinsetpolicy(net, res, policy)
230756668Sshin	int net;
230856668Sshin	struct addrinfo *res;
230956668Sshin	char *policy;
231056668Sshin{
231156668Sshin	char *buf;
231256668Sshin	int level;
231356668Sshin	int optname;
231456668Sshin
231556668Sshin	if (policy == NULL)
231656668Sshin		return 0;
231756668Sshin
231856668Sshin	buf = ipsec_set_policy(policy, strlen(policy));
231956668Sshin	if (buf == NULL) {
232056668Sshin		printf("%s\n", ipsec_strerror());
232156668Sshin		return -1;
232256668Sshin	}
232356668Sshin	level = res->ai_family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6;
232456668Sshin	optname = res->ai_family == AF_INET ? IP_IPSEC_POLICY : IPV6_IPSEC_POLICY;
232556668Sshin	if (setsockopt(net, level, optname, buf, ipsec_get_policylen(buf)) < 0){
232656668Sshin		perror("setsockopt");
232756668Sshin		return -1;
232856668Sshin	}
232956668Sshin
233056668Sshin	free(buf);
233156668Sshin}
233256668Sshin#endif
233356668Sshin
233457125Sshin#ifdef INET6
233557125Sshin/*
233657125Sshin * When an Address Family related error happend, check if retry with
233757125Sshin * another AF is possible or not.
233857125Sshin * Return 1, if retry with another af is OK. Else, return 0.
233957125Sshin */
234057125Sshinstatic int
234157125Sshinswitch_af(aip)
234257125Sshin    struct addrinfo **aip;
234357125Sshin{
234457125Sshin    int nextaf;
234557125Sshin    struct addrinfo *ai;
234657125Sshin
234757125Sshin    ai = *aip;
234857125Sshin    nextaf = (ai->ai_family == AF_INET) ? AF_INET6 : AF_INET;
234957125Sshin    do
235057125Sshin        ai=ai->ai_next;
235157125Sshin    while (ai != NULL && ai->ai_family != nextaf);
235257125Sshin    *aip = ai;
235357125Sshin    if (*aip != NULL) {
235457125Sshin        return 1;
235557125Sshin    }
235657125Sshin    return 0;
235757125Sshin}
235857125Sshin#endif
235957125Sshin
236029088Smarkm    int
236129088Smarkmtn(argc, argv)
236229088Smarkm    int argc;
236329088Smarkm    char *argv[];
236429088Smarkm{
236529088Smarkm    char *srp = 0, *strrchr();
236656668Sshin    int proto, opt;
236756668Sshin    int sourceroute(), srlen;
236856668Sshin    int srcroute = 0, result;
236929088Smarkm    char *cmd, *hostp = 0, *portp = 0, *user = 0;
237047973Sru    char *src_addr = NULL;
237157125Sshin    struct addrinfo hints, *res, *res0 = NULL, *src_res, *src_res0 = NULL;
237257125Sshin    int error = 0, af_error = 0;
237329088Smarkm
237429088Smarkm    if (connected) {
237529088Smarkm	printf("?Already connected to %s\n", hostname);
237629088Smarkm	setuid(getuid());
237729088Smarkm	return 0;
237829088Smarkm    }
237929088Smarkm    if (argc < 2) {
238029088Smarkm	(void) strcpy(line, "open ");
238129088Smarkm	printf("(to) ");
238229088Smarkm	(void) fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin);
238329088Smarkm	makeargv();
238429088Smarkm	argc = margc;
238529088Smarkm	argv = margv;
238629088Smarkm    }
238729088Smarkm    cmd = *argv;
238829088Smarkm    --argc; ++argv;
238929088Smarkm    while (argc) {
239029088Smarkm	if (strcmp(*argv, "help") == 0 || isprefix(*argv, "?"))
239129088Smarkm	    goto usage;
239229088Smarkm	if (strcmp(*argv, "-l") == 0) {
239329088Smarkm	    --argc; ++argv;
239429088Smarkm	    if (argc == 0)
239529088Smarkm		goto usage;
239629088Smarkm	    user = *argv++;
239729088Smarkm	    --argc;
239829088Smarkm	    continue;
239929088Smarkm	}
240029088Smarkm	if (strcmp(*argv, "-a") == 0) {
240129088Smarkm	    --argc; ++argv;
240229088Smarkm	    autologin = 1;
240329088Smarkm	    continue;
240429088Smarkm	}
240547973Sru	if (strcmp(*argv, "-s") == 0) {
240647973Sru	    --argc; ++argv;
240747973Sru	    if (argc == 0)
240847973Sru		goto usage;
240947973Sru	    src_addr = *argv++;
241047973Sru	    --argc;
241147973Sru	    continue;
241247973Sru	}
241329088Smarkm	if (hostp == 0) {
241429088Smarkm	    hostp = *argv++;
241529088Smarkm	    --argc;
241629088Smarkm	    continue;
241729088Smarkm	}
241829088Smarkm	if (portp == 0) {
241929088Smarkm	    portp = *argv++;
242029088Smarkm	    --argc;
242129088Smarkm	    continue;
242229088Smarkm	}
242329088Smarkm    usage:
242447973Sru	printf("usage: %s [-l user] [-a] [-s src_addr] host-name [port]\n", cmd);
242529088Smarkm	setuid(getuid());
242629088Smarkm	return 0;
242729088Smarkm    }
242829088Smarkm    if (hostp == 0)
242929088Smarkm	goto usage;
243029088Smarkm
243147973Sru    if (src_addr != NULL) {
243256668Sshin	memset(&hints, 0, sizeof(hints));
243356668Sshin	hints.ai_flags = AI_NUMERICHOST;
243456668Sshin	hints.ai_family = family;
243556668Sshin	hints.ai_socktype = SOCK_STREAM;
243657125Sshin	error = getaddrinfo(src_addr, 0, &hints, &src_res);
243762805Sume	if (error == EAI_NODATA) {
243856668Sshin		hints.ai_flags = 0;
243957125Sshin		error = getaddrinfo(src_addr, 0, &hints, &src_res);
244056668Sshin	}
244156668Sshin	if (error != 0) {
244256668Sshin		fprintf(stderr, "%s: %s\n", src_addr, gai_strerror(error));
244356668Sshin		if (error == EAI_SYSTEM)
244456668Sshin			fprintf(stderr, "%s: %s\n", src_addr, strerror(errno));
244557125Sshin		setuid(getuid());
244647973Sru		return 0;
244747973Sru	}
244857125Sshin	src_res0 = src_res;
244947973Sru    }
245077095Sdillon    if (hostp[0] == '/') {
245177095Sdillon	struct sockaddr_un su;
245277095Sdillon
245377095Sdillon	if (strlen(hostp) >= sizeof(su.sun_path)) {
245477095Sdillon	    fprintf(stderr, "hostname too long for unix domain socket: %s",
245577095Sdillon		    hostp);
245677095Sdillon		goto fail;
245777095Sdillon	}
245877095Sdillon	memset(&su, 0, sizeof su);
245977095Sdillon	su.sun_family = AF_UNIX;
246077095Sdillon	strncpy(su.sun_path, hostp, sizeof su.sun_path);
246177095Sdillon	printf("Trying %s...\n", &su.sun_path);
246277095Sdillon	net = socket(PF_UNIX, SOCK_STREAM, 0);
246377095Sdillon	if ( net < 0) {
246477095Sdillon	    perror("socket");
246577095Sdillon	    goto fail;
246677095Sdillon	}
246777095Sdillon	if (connect(net, (struct sockaddr *)&su, sizeof su) == -1) {
246877095Sdillon	    perror(su.sun_path);
246977095Sdillon	    (void) NetClose(net);
247077095Sdillon	    goto fail;
247177095Sdillon	}
247277095Sdillon	goto af_unix;
247377095Sdillon    } else if (hostp[0] == '@' || hostp[0] == '!') {
247456668Sshin	if (
247556668Sshin#ifdef INET6
247656668Sshin	    family == AF_INET6 ||
247756668Sshin#endif
247856668Sshin	    (hostname = strrchr(hostp, ':')) == NULL)
247929088Smarkm	    hostname = strrchr(hostp, '@');
248029088Smarkm	hostname++;
248156668Sshin	srcroute = 1;
248256668Sshin    } else
248356668Sshin        hostname = hostp;
248456668Sshin    if (!portp) {
248556668Sshin      telnetport = 1;
248656668Sshin      portp = "telnet";
248756668Sshin    } else if (*portp == '-') {
248856668Sshin      portp++;
248956668Sshin      telnetport = 1;
249056668Sshin    } else
249156668Sshin      telnetport = 0;
249256668Sshin
249356668Sshin    memset(&hints, 0, sizeof(hints));
249456668Sshin    hints.ai_flags = AI_NUMERICHOST;
249556668Sshin    hints.ai_family = family;
249656668Sshin    hints.ai_socktype = SOCK_STREAM;
249756668Sshin    error = getaddrinfo(hostname, portp, &hints, &res);
249862773Sitojun    if (error) {
249962773Sitojun        hints.ai_flags = AI_CANONNAME;
250062773Sitojun	error = getaddrinfo(hostname, portp, &hints, &res);
250162773Sitojun    }
250262773Sitojun    if (error != 0) {
250362773Sitojun	fprintf(stderr, "%s: %s\n", hostname, gai_strerror(error));
250462773Sitojun	if (error == EAI_SYSTEM)
250562773Sitojun	    fprintf(stderr, "%s: %s\n", hostname, strerror(errno));
250662773Sitojun	setuid(getuid());
250762773Sitojun	goto fail;
250862773Sitojun    }
250962773Sitojun    if (hints.ai_flags == AI_NUMERICHOST) {
251062773Sitojun	/* hostname has numeric */
251156668Sshin        int gni_err = 1;
251256668Sshin
251356668Sshin	if (doaddrlookup)
251456668Sshin	    gni_err = getnameinfo(res->ai_addr, res->ai_addr->sa_len,
251556668Sshin				  _hostname, sizeof(_hostname) - 1, NULL, 0,
251656870Sshin				  NI_NAMEREQD);
251756668Sshin	if (gni_err != 0)
251862773Sitojun	    (void) strncpy(_hostname, hostp, sizeof(_hostname) - 1);
251956668Sshin	_hostname[sizeof(_hostname)-1] = '\0';
252056668Sshin	hostname = _hostname;
252162773Sitojun    } else {
252262773Sitojun	/* hostname has FQDN */
252356668Sshin	if (srcroute != 0)
252456668Sshin	    (void) strncpy(_hostname, hostname, sizeof(_hostname) - 1);
252556668Sshin	else if (res->ai_canonname != NULL)
252656668Sshin	  strcpy(_hostname, res->ai_canonname);
252756668Sshin	else
252856668Sshin	  (void) strncpy(_hostname, hostp, sizeof(_hostname) - 1);
252956668Sshin	_hostname[sizeof(_hostname)-1] = '\0';
253056668Sshin	hostname = _hostname;
253156668Sshin    }
253257125Sshin    res0 = res;
253357233Sshin af_again:
253456668Sshin    if (srcroute != 0) {
253557343Sshin        static char hostbuf[BUFSIZ];
253657125Sshin
253757233Sshin	if (af_error == 0) { /* save intermediate hostnames for retry */
253857233Sshin		strncpy(hostbuf, hostp, BUFSIZ - 1);
253957233Sshin		hostbuf[BUFSIZ - 1] = '\0';
254057233Sshin	} else
254157125Sshin		hostp = hostbuf;
254229088Smarkm	srp = 0;
254356668Sshin	result = sourceroute(res, hostp, &srp, &srlen, &proto, &opt);
254456668Sshin	if (result == 0) {
254557125Sshin#ifdef INET6
254657125Sshin	    if (family == AF_UNSPEC && af_error == 0 &&
254757125Sshin		switch_af(&res) == 1) {
254857125Sshin	        af_error = 1;
254957125Sshin		goto af_again;
255057125Sshin	    }
255157125Sshin#endif
255229088Smarkm	    setuid(getuid());
255357125Sshin	    goto fail;
255456668Sshin	} else if (result == -1) {
255529088Smarkm	    printf("Bad source route option: %s\n", hostp);
255629088Smarkm	    setuid(getuid());
255757125Sshin	    goto fail;
255829088Smarkm	}
255929088Smarkm    }
256029088Smarkm    do {
256157342Sshin        printf("Trying %s...\n", sockaddr_ntop(res->ai_addr));
256256668Sshin	net = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
256329088Smarkm	setuid(getuid());
256429088Smarkm	if (net < 0) {
256557125Sshin#ifdef INET6
256657125Sshin	    if (family == AF_UNSPEC && af_error == 0 &&
256757125Sshin		switch_af(&res) == 1) {
256857125Sshin	        af_error = 1;
256957125Sshin		goto af_again;
257057125Sshin	    }
257157125Sshin#endif
257229088Smarkm	    perror("telnet: socket");
257357125Sshin	    goto fail;
257429088Smarkm	}
257556668Sshin	if (srp && setsockopt(net, proto, opt, (char *)srp, srlen) < 0)
257656668Sshin		perror("setsockopt (source route)");
257729088Smarkm#if	defined(IPPROTO_IP) && defined(IP_TOS)
257856668Sshin	if (res->ai_family == PF_INET) {
257929088Smarkm# if	defined(HAS_GETTOS)
258029088Smarkm	    struct tosent *tp;
258129088Smarkm	    if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
258229088Smarkm		tos = tp->t_tos;
258329088Smarkm# endif
258429088Smarkm	    if (tos < 0)
258529088Smarkm		tos = 020;	/* Low Delay bit */
258629088Smarkm	    if (tos
258729088Smarkm		&& (setsockopt(net, IPPROTO_IP, IP_TOS,
258829088Smarkm		    (char *)&tos, sizeof(int)) < 0)
258929088Smarkm		&& (errno != ENOPROTOOPT))
259029088Smarkm		    perror("telnet: setsockopt (IP_TOS) (ignored)");
259129088Smarkm	}
259229088Smarkm#endif	/* defined(IPPROTO_IP) && defined(IP_TOS) */
259329088Smarkm
259429088Smarkm	if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) {
259529088Smarkm		perror("setsockopt (SO_DEBUG)");
259629088Smarkm	}
259729088Smarkm
259847973Sru	if (src_addr != NULL) {
259957125Sshin	    for (src_res = src_res0; src_res != 0; src_res = src_res->ai_next)
260057233Sshin	        if (src_res->ai_family == res->ai_family)
260157233Sshin		    break;
260257125Sshin	    if (src_res == NULL)
260357125Sshin		src_res = src_res0;
260457125Sshin	    if (bind(net, src_res->ai_addr, src_res->ai_addrlen) == -1) {
260557125Sshin#ifdef INET6
260657125Sshin	        if (family == AF_UNSPEC && af_error == 0 &&
260757125Sshin		    switch_af(&res) == 1) {
260857125Sshin		    af_error = 1;
260957233Sshin		    (void) NetClose(net);
261057125Sshin		    goto af_again;
261157125Sshin		}
261257125Sshin#endif
261347973Sru		perror("bind");
261457233Sshin		(void) NetClose(net);
261557125Sshin		goto fail;
261647973Sru	    }
261747973Sru	}
261856668Sshin#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
261957233Sshin	if (setpolicy(net, res, ipsec_policy_in) < 0) {
262057233Sshin		(void) NetClose(net);
262157125Sshin		goto fail;
262257233Sshin	}
262357233Sshin	if (setpolicy(net, res, ipsec_policy_out) < 0) {
262457233Sshin		(void) NetClose(net);
262557125Sshin		goto fail;
262657233Sshin	}
262756668Sshin#endif
262847973Sru
262956668Sshin	if (connect(net, res->ai_addr, res->ai_addrlen) < 0) {
263057125Sshin	    struct addrinfo *next;
263157125Sshin
263257125Sshin	    next = res->ai_next;
263357125Sshin	    /* If already an af failed, only try same af. */
263457125Sshin	    if (af_error != 0)
263557125Sshin		while (next != NULL && next->ai_family != res->ai_family)
263657125Sshin		    next = next->ai_next;
263757342Sshin	    warn("connect to address %s", sockaddr_ntop(res->ai_addr));
263857125Sshin	    if (next != NULL) {
263957125Sshin		res = next;
264029088Smarkm		(void) NetClose(net);
264129088Smarkm		continue;
264229088Smarkm	    }
264357342Sshin	    warnx("Unable to connect to remote host");
264457233Sshin	    (void) NetClose(net);
264557125Sshin	    goto fail;
264629088Smarkm	}
264729088Smarkm	connected++;
264829088Smarkm#if	defined(AUTHENTICATION) || defined(ENCRYPTION)
264929088Smarkm	auth_encrypt_connect(connected);
265029088Smarkm#endif	/* defined(AUTHENTICATION) || defined(ENCRYPTION) */
265129088Smarkm    } while (connected == 0);
265257125Sshin    freeaddrinfo(res0);
265357125Sshin    if (src_res0 != NULL)
265457125Sshin        freeaddrinfo(src_res0);
265529088Smarkm    cmdrc(hostp, hostname);
265677095Sdillon af_unix:
265729088Smarkm    if (autologin && user == NULL) {
265829088Smarkm	struct passwd *pw;
265929088Smarkm
266029088Smarkm	user = getenv("USER");
266129088Smarkm	if (user == NULL ||
266229181Smarkm	    ((pw = getpwnam(user)) && pw->pw_uid != getuid())) {
266329181Smarkm		if ((pw = getpwuid(getuid())))
266429088Smarkm			user = pw->pw_name;
266529088Smarkm		else
266629088Smarkm			user = NULL;
266729088Smarkm	}
266829088Smarkm    }
266929088Smarkm    if (user) {
267029088Smarkm	env_define((unsigned char *)"USER", (unsigned char *)user);
267129088Smarkm	env_export((unsigned char *)"USER");
267229088Smarkm    }
267329088Smarkm    (void) call(status, "status", "notmuch", 0);
267429088Smarkm    if (setjmp(peerdied) == 0)
267529088Smarkm	telnet(user);
267629088Smarkm    (void) NetClose(net);
267729088Smarkm    ExitString("Connection closed by foreign host.\n",1);
267829088Smarkm    /*NOTREACHED*/
267957125Sshin fail:
268057125Sshin    if (res0 != NULL)
268157125Sshin        freeaddrinfo(res0);
268257125Sshin    if (src_res0 != NULL)
268357125Sshin        freeaddrinfo(src_res0);
268457125Sshin    return 0;
268529088Smarkm}
268629088Smarkm
268729088Smarkm#define HELPINDENT (sizeof ("connect"))
268829088Smarkm
268929088Smarkmstatic char
269029088Smarkm	openhelp[] =	"connect to a site",
269129088Smarkm	closehelp[] =	"close current connection",
269229088Smarkm	logouthelp[] =	"forcibly logout remote user and close the connection",
269329088Smarkm	quithelp[] =	"exit telnet",
269429088Smarkm	statushelp[] =	"print status information",
269529088Smarkm	helphelp[] =	"print help information",
269629088Smarkm	sendhelp[] =	"transmit special characters ('send ?' for more)",
269729088Smarkm	sethelp[] = 	"set operating parameters ('set ?' for more)",
269829088Smarkm	unsethelp[] = 	"unset operating parameters ('unset ?' for more)",
269929088Smarkm	togglestring[] ="toggle operating parameters ('toggle ?' for more)",
270029088Smarkm	slchelp[] =	"change state of special charaters ('slc ?' for more)",
270129088Smarkm	displayhelp[] =	"display operating parameters",
270229088Smarkm#if	defined(TN3270) && defined(unix)
270329088Smarkm	transcomhelp[] = "specify Unix command for transparent mode pipe",
270429088Smarkm#endif	/* defined(TN3270) && defined(unix) */
270529088Smarkm#if	defined(AUTHENTICATION)
270629088Smarkm	authhelp[] =	"turn on (off) authentication ('auth ?' for more)",
270729088Smarkm#endif
270829088Smarkm#ifdef	ENCRYPTION
270929088Smarkm	encrypthelp[] =	"turn on (off) encryption ('encrypt ?' for more)",
271029088Smarkm#endif	/* ENCRYPTION */
271129088Smarkm#if	defined(unix)
271229088Smarkm	zhelp[] =	"suspend telnet",
271329088Smarkm#endif	/* defined(unix) */
271429181Smarkm#if	defined(SKEY)
271529181Smarkm	skeyhelp[] =    "compute response to s/key challenge",
271629181Smarkm#endif
271729088Smarkm	shellhelp[] =	"invoke a subshell",
271829088Smarkm	envhelp[] =	"change environment variables ('environ ?' for more)",
271929088Smarkm	modestring[] = "try to enter line or character mode ('mode ?' for more)";
272029088Smarkm
272129088Smarkmstatic Command cmdtab[] = {
272229088Smarkm	{ "close",	closehelp,	bye,		1 },
272329088Smarkm	{ "logout",	logouthelp,	logout,		1 },
272429088Smarkm	{ "display",	displayhelp,	display,	0 },
272529088Smarkm	{ "mode",	modestring,	modecmd,	0 },
272629088Smarkm	{ "open",	openhelp,	tn,		0 },
272729088Smarkm	{ "quit",	quithelp,	quit,		0 },
272829088Smarkm	{ "send",	sendhelp,	sendcmd,	0 },
272929088Smarkm	{ "set",	sethelp,	setcmd,		0 },
273029088Smarkm	{ "unset",	unsethelp,	unsetcmd,	0 },
273129088Smarkm	{ "status",	statushelp,	status,		0 },
273229088Smarkm	{ "toggle",	togglestring,	toggle,		0 },
273329088Smarkm	{ "slc",	slchelp,	slccmd,		0 },
273429088Smarkm#if	defined(TN3270) && defined(unix)
273529088Smarkm	{ "transcom",	transcomhelp,	settranscom,	0 },
273629088Smarkm#endif	/* defined(TN3270) && defined(unix) */
273729088Smarkm#if	defined(AUTHENTICATION)
273829088Smarkm	{ "auth",	authhelp,	auth_cmd,	0 },
273929088Smarkm#endif
274029088Smarkm#ifdef	ENCRYPTION
274129088Smarkm	{ "encrypt",	encrypthelp,	encrypt_cmd,	0 },
274229088Smarkm#endif	/* ENCRYPTION */
274329088Smarkm#if	defined(unix)
274429088Smarkm	{ "z",		zhelp,		suspend,	0 },
274529088Smarkm#endif	/* defined(unix) */
274629088Smarkm#if	defined(TN3270)
274729088Smarkm	{ "!",		shellhelp,	shell,		1 },
274829088Smarkm#else
274929088Smarkm	{ "!",		shellhelp,	shell,		0 },
275029088Smarkm#endif
275129088Smarkm	{ "environ",	envhelp,	env_cmd,	0 },
275229088Smarkm	{ "?",		helphelp,	help,		0 },
275329181Smarkm#if	defined(SKEY)
275429181Smarkm	{ "skey",       skeyhelp,       skey_calc,      0 },
275529181Smarkm#endif
275629181Smarkm	{ 0, 0, 0, 0 }
275729088Smarkm};
275829088Smarkm
275929088Smarkmstatic char	crmodhelp[] =	"deprecated command -- use 'toggle crmod' instead";
276029088Smarkmstatic char	escapehelp[] =	"deprecated command -- use 'set escape' instead";
276129088Smarkm
276229088Smarkmstatic Command cmdtab2[] = {
276329088Smarkm	{ "help",	0,		help,		0 },
276429088Smarkm	{ "escape",	escapehelp,	setescape,	0 },
276529088Smarkm	{ "crmod",	crmodhelp,	togcrmod,	0 },
276629181Smarkm	{ 0, 0, 0, 0 }
276729088Smarkm};
276829088Smarkm
276929088Smarkm
277029088Smarkm/*
277129088Smarkm * Call routine with argc, argv set from args (terminated by 0).
277229088Smarkm */
277329088Smarkm
277429088Smarkm    /*VARARGS1*/
277529181Smarkm    static int
277629088Smarkmcall(va_alist)
277729088Smarkm    va_dcl
277829088Smarkm{
277929088Smarkm    va_list ap;
278029088Smarkm    typedef int (*intrtn_t)();
278129088Smarkm    intrtn_t routine;
278229088Smarkm    char *args[100];
278329088Smarkm    int argno = 0;
278429088Smarkm
278529088Smarkm    va_start(ap);
278629088Smarkm    routine = (va_arg(ap, intrtn_t));
278729088Smarkm    while ((args[argno++] = va_arg(ap, char *)) != 0) {
278829088Smarkm	;
278929088Smarkm    }
279029088Smarkm    va_end(ap);
279129088Smarkm    return (*routine)(argno-1, args);
279229088Smarkm}
279329088Smarkm
279429088Smarkm
279529088Smarkm    static Command *
279629088Smarkmgetcmd(name)
279729088Smarkm    char *name;
279829088Smarkm{
279929088Smarkm    Command *cm;
280029088Smarkm
280129181Smarkm    if ((cm = (Command *) genget(name, (char **) cmdtab, sizeof(Command))))
280229088Smarkm	return cm;
280329088Smarkm    return (Command *) genget(name, (char **) cmdtab2, sizeof(Command));
280429088Smarkm}
280529088Smarkm
280629088Smarkm    void
280729088Smarkmcommand(top, tbuf, cnt)
280829088Smarkm    int top;
280929088Smarkm    char *tbuf;
281029088Smarkm    int cnt;
281129088Smarkm{
281229088Smarkm    register Command *c;
281329088Smarkm
281429088Smarkm    setcommandmode();
281529088Smarkm    if (!top) {
281629088Smarkm	putchar('\n');
281729088Smarkm#if	defined(unix)
281829088Smarkm    } else {
281929088Smarkm	(void) signal(SIGINT, SIG_DFL);
282029088Smarkm	(void) signal(SIGQUIT, SIG_DFL);
282129088Smarkm#endif	/* defined(unix) */
282229088Smarkm    }
282329088Smarkm    for (;;) {
282429088Smarkm	if (rlogin == _POSIX_VDISABLE)
282529088Smarkm		printf("%s> ", prompt);
282629088Smarkm	if (tbuf) {
282729088Smarkm	    register char *cp;
282829088Smarkm	    cp = line;
282929088Smarkm	    while (cnt > 0 && (*cp++ = *tbuf++) != '\n')
283029088Smarkm		cnt--;
283129088Smarkm	    tbuf = 0;
283229088Smarkm	    if (cp == line || *--cp != '\n' || cp == line)
283329088Smarkm		goto getline;
283429088Smarkm	    *cp = '\0';
283529088Smarkm	    if (rlogin == _POSIX_VDISABLE)
283629088Smarkm		printf("%s\n", line);
283729088Smarkm	} else {
283829088Smarkm	getline:
283929088Smarkm	    if (rlogin != _POSIX_VDISABLE)
284029088Smarkm		printf("%s> ", prompt);
284129088Smarkm	    if (fgets(line, sizeof(line), stdin) == NULL) {
284229088Smarkm		if (feof(stdin) || ferror(stdin)) {
284329088Smarkm		    (void) quit();
284429088Smarkm		    /*NOTREACHED*/
284529088Smarkm		}
284629088Smarkm		break;
284729088Smarkm	    }
284829088Smarkm	}
284929088Smarkm	if (line[0] == 0)
285029088Smarkm	    break;
285129088Smarkm	makeargv();
285229088Smarkm	if (margv[0] == 0) {
285329088Smarkm	    break;
285429088Smarkm	}
285529088Smarkm	c = getcmd(margv[0]);
285629088Smarkm	if (Ambiguous(c)) {
285729088Smarkm	    printf("?Ambiguous command\n");
285829088Smarkm	    continue;
285929088Smarkm	}
286029088Smarkm	if (c == 0) {
286129088Smarkm	    printf("?Invalid command\n");
286229088Smarkm	    continue;
286329088Smarkm	}
286429088Smarkm	if (c->needconnect && !connected) {
286529088Smarkm	    printf("?Need to be connected first.\n");
286629088Smarkm	    continue;
286729088Smarkm	}
286829088Smarkm	if ((*c->handler)(margc, margv)) {
286929088Smarkm	    break;
287029088Smarkm	}
287129088Smarkm    }
287229088Smarkm    if (!top) {
287329088Smarkm	if (!connected) {
287429088Smarkm	    longjmp(toplevel, 1);
287529088Smarkm	    /*NOTREACHED*/
287629088Smarkm	}
287729088Smarkm#if	defined(TN3270)
287829088Smarkm	if (shell_active == 0) {
287929088Smarkm	    setconnmode(0);
288029088Smarkm	}
288129088Smarkm#else	/* defined(TN3270) */
288229088Smarkm	setconnmode(0);
288329088Smarkm#endif	/* defined(TN3270) */
288429088Smarkm    }
288529088Smarkm}
288629088Smarkm
288729088Smarkm/*
288829088Smarkm * Help command.
288929088Smarkm */
289029181Smarkm	static int
289129088Smarkmhelp(argc, argv)
289229088Smarkm	int argc;
289329088Smarkm	char *argv[];
289429088Smarkm{
289529088Smarkm	register Command *c;
289629088Smarkm
289729088Smarkm	if (argc == 1) {
289829088Smarkm		printf("Commands may be abbreviated.  Commands are:\n\n");
289929088Smarkm		for (c = cmdtab; c->name; c++)
290029088Smarkm			if (c->help) {
290129088Smarkm				printf("%-*s\t%s\n", HELPINDENT, c->name,
290229088Smarkm								    c->help);
290329088Smarkm			}
290429088Smarkm	}
290529181Smarkm	else while (--argc > 0) {
290629088Smarkm		register char *arg;
290729088Smarkm		arg = *++argv;
290829088Smarkm		c = getcmd(arg);
290929088Smarkm		if (Ambiguous(c))
291029088Smarkm			printf("?Ambiguous help command %s\n", arg);
291129088Smarkm		else if (c == (Command *)0)
291229088Smarkm			printf("?Invalid help command %s\n", arg);
291329088Smarkm		else
291429088Smarkm			printf("%s\n", c->help);
291529088Smarkm	}
291629181Smarkm	return(0);
291729088Smarkm}
291829088Smarkm
291929088Smarkmstatic char *rcname = 0;
292029088Smarkmstatic char rcbuf[128];
292129088Smarkm
292229181Smarkm	void
292329088Smarkmcmdrc(m1, m2)
292429088Smarkm	char *m1, *m2;
292529088Smarkm{
292629088Smarkm    register Command *c;
292729088Smarkm    FILE *rcfile;
292829088Smarkm    int gotmachine = 0;
292929088Smarkm    int l1 = strlen(m1);
293029088Smarkm    int l2 = strlen(m2);
293168891Skris    char m1save[MAXHOSTNAMELEN];
293229088Smarkm
293329088Smarkm    if (skiprc)
293429088Smarkm	return;
293529088Smarkm
293668891Skris    strlcpy(m1save, m1, sizeof(m1save));
293729088Smarkm    m1 = m1save;
293829088Smarkm
293929088Smarkm    if (rcname == 0) {
294029088Smarkm	rcname = getenv("HOME");
294129181Smarkm	if (rcname && (strlen(rcname) + 10) < sizeof(rcbuf))
294229088Smarkm	    strcpy(rcbuf, rcname);
294329088Smarkm	else
294429088Smarkm	    rcbuf[0] = '\0';
294529088Smarkm	strcat(rcbuf, "/.telnetrc");
294629088Smarkm	rcname = rcbuf;
294729088Smarkm    }
294829088Smarkm
294929088Smarkm    if ((rcfile = fopen(rcname, "r")) == 0) {
295029088Smarkm	return;
295129088Smarkm    }
295229088Smarkm
295329088Smarkm    for (;;) {
295429088Smarkm	if (fgets(line, sizeof(line), rcfile) == NULL)
295529088Smarkm	    break;
295629088Smarkm	if (line[0] == 0)
295729088Smarkm	    break;
295829088Smarkm	if (line[0] == '#')
295929088Smarkm	    continue;
296029088Smarkm	if (gotmachine) {
296129088Smarkm	    if (!isspace(line[0]))
296229088Smarkm		gotmachine = 0;
296329088Smarkm	}
296429088Smarkm	if (gotmachine == 0) {
296529088Smarkm	    if (isspace(line[0]))
296629088Smarkm		continue;
296729088Smarkm	    if (strncasecmp(line, m1, l1) == 0)
296829088Smarkm		strncpy(line, &line[l1], sizeof(line) - l1);
296929088Smarkm	    else if (strncasecmp(line, m2, l2) == 0)
297029088Smarkm		strncpy(line, &line[l2], sizeof(line) - l2);
297129088Smarkm	    else if (strncasecmp(line, "DEFAULT", 7) == 0)
297229088Smarkm		strncpy(line, &line[7], sizeof(line) - 7);
297329088Smarkm	    else
297429088Smarkm		continue;
297529088Smarkm	    if (line[0] != ' ' && line[0] != '\t' && line[0] != '\n')
297629088Smarkm		continue;
297729088Smarkm	    gotmachine = 1;
297829088Smarkm	}
297929088Smarkm	makeargv();
298029088Smarkm	if (margv[0] == 0)
298129088Smarkm	    continue;
298229088Smarkm	c = getcmd(margv[0]);
298329088Smarkm	if (Ambiguous(c)) {
298429088Smarkm	    printf("?Ambiguous command: %s\n", margv[0]);
298529088Smarkm	    continue;
298629088Smarkm	}
298729088Smarkm	if (c == 0) {
298829088Smarkm	    printf("?Invalid command: %s\n", margv[0]);
298929088Smarkm	    continue;
299029088Smarkm	}
299129088Smarkm	/*
299229088Smarkm	 * This should never happen...
299329088Smarkm	 */
299429088Smarkm	if (c->needconnect && !connected) {
299529088Smarkm	    printf("?Need to be connected first for %s.\n", margv[0]);
299629088Smarkm	    continue;
299729088Smarkm	}
299829088Smarkm	(*c->handler)(margc, margv);
299929088Smarkm    }
300029088Smarkm    fclose(rcfile);
300129088Smarkm}
300229088Smarkm
300329088Smarkm/*
300429088Smarkm * Source route is handed in as
300529088Smarkm *	[!]@hop1@hop2...[@|:]dst
300629088Smarkm * If the leading ! is present, it is a
300729088Smarkm * strict source route, otherwise it is
300829088Smarkm * assmed to be a loose source route.
300929088Smarkm *
301029088Smarkm * We fill in the source route option as
301129088Smarkm *	hop1,hop2,hop3...dest
301229088Smarkm * and return a pointer to hop1, which will
301329088Smarkm * be the address to connect() to.
301429088Smarkm *
301529088Smarkm * Arguments:
301656668Sshin *
301756668Sshin *	res:	ponter to addrinfo structure which contains sockaddr to
301856668Sshin *		the host to connect to.
301956668Sshin *
302029088Smarkm *	arg:	pointer to route list to decipher
302129088Smarkm *
302229088Smarkm *	cpp: 	If *cpp is not equal to NULL, this is a
302329088Smarkm *		pointer to a pointer to a character array
302429088Smarkm *		that should be filled in with the option.
302529088Smarkm *
302629088Smarkm *	lenp:	pointer to an integer that contains the
302729088Smarkm *		length of *cpp if *cpp != NULL.
302829088Smarkm *
302956668Sshin *	protop:	pointer to an integer that should be filled in with
303056668Sshin *		appropriate protocol for setsockopt, as socket
303156668Sshin *		protocol family.
303256668Sshin *
303356668Sshin *	optp:	pointer to an integer that should be filled in with
303456668Sshin *		appropriate option for setsockopt, as socket protocol
303556668Sshin *		family.
303656668Sshin *
303729088Smarkm * Return values:
303829088Smarkm *
303956668Sshin *	If the return value is 1, then all operations are
304056668Sshin *	successful. If the
304129088Smarkm *	return value is -1, there was a syntax error in the
304229088Smarkm *	option, either unknown characters, or too many hosts.
304329088Smarkm *	If the return value is 0, one of the hostnames in the
304429088Smarkm *	path is unknown, and *cpp is set to point to the bad
304529088Smarkm *	hostname.
304629088Smarkm *
304729088Smarkm *	*cpp:	If *cpp was equal to NULL, it will be filled
304829088Smarkm *		in with a pointer to our static area that has
304929088Smarkm *		the option filled in.  This will be 32bit aligned.
305029088Smarkm *
305129088Smarkm *	*lenp:	This will be filled in with how long the option
305229088Smarkm *		pointed to by *cpp is.
305329088Smarkm *
305456668Sshin *	*protop: This will be filled in with appropriate protocol for
305556668Sshin *		 setsockopt, as socket protocol family.
305656668Sshin *
305756668Sshin *	*optp:	This will be filled in with appropriate option for
305856668Sshin *		setsockopt, as socket protocol family.
305929088Smarkm */
306056668Sshinint
306156668Sshinsourceroute(ai, arg, cpp, lenp, protop, optp)
306256668Sshin	struct addrinfo *ai;
306329088Smarkm	char	*arg;
306429088Smarkm	char	**cpp;
306529088Smarkm	int	*lenp;
306656668Sshin	int	*protop;
306756668Sshin	int	*optp;
306829088Smarkm{
306963662Sume	static char buf[1024 + ALIGNBYTES];	/*XXX*/
307056668Sshin	struct cmsghdr *cmsg;
307129088Smarkm#ifdef	sysV88
307229088Smarkm	static IOPTN ipopt;
307329088Smarkm#endif
307456668Sshin	char *cp, *cp2, *lsrp, *ep;
307529088Smarkm	register int tmp;
307656668Sshin	struct sockaddr_in *sin;
307756668Sshin	struct sockaddr_in6 *sin6;
307856668Sshin	struct addrinfo hints, *res;
307956668Sshin	int error;
308029088Smarkm	register char c;
308129088Smarkm
308229088Smarkm	/*
308329088Smarkm	 * Verify the arguments, and make sure we have
308429088Smarkm	 * at least 7 bytes for the option.
308529088Smarkm	 */
308629088Smarkm	if (cpp == NULL || lenp == NULL)
308757724Sshin		return -1;
308856668Sshin	if (*cpp != NULL) {
308956668Sshin		switch (res->ai_family) {
309056668Sshin		case AF_INET:
309156668Sshin			if (*lenp < 7)
309257724Sshin				return -1;
309356668Sshin			break;
309456668Sshin#ifdef INET6
309556668Sshin		case AF_INET6:
309657724Sshin			if (*lenp < CMSG_SPACE(sizeof(struct ip6_rthdr) +
309757724Sshin				               sizeof(struct in6_addr)))
309857724Sshin				return -1;
309956668Sshin			break;
310056668Sshin#endif
310156668Sshin		}
310256668Sshin	}
310329088Smarkm	/*
310429088Smarkm	 * Decide whether we have a buffer passed to us,
310529088Smarkm	 * or if we need to use our own static buffer.
310629088Smarkm	 */
310729088Smarkm	if (*cpp) {
310829088Smarkm		lsrp = *cpp;
310956668Sshin		ep = lsrp + *lenp;
311029088Smarkm	} else {
311163662Sume		*cpp = lsrp = (char *)ALIGN(buf);
311256668Sshin		ep = lsrp + 1024;
311329088Smarkm	}
311429088Smarkm
311529088Smarkm	cp = arg;
311629088Smarkm
311756668Sshin#ifdef INET6
311856668Sshin	if (ai->ai_family == AF_INET6) {
311956668Sshin		cmsg = inet6_rthdr_init(*cpp, IPV6_RTHDR_TYPE_0);
312056668Sshin		if (*cp != '@')
312156668Sshin			return -1;
312256668Sshin		*protop = IPPROTO_IPV6;
312356668Sshin		*optp = IPV6_PKTOPTIONS;
312456668Sshin	} else
312556668Sshin#endif
312656668Sshin      {
312729088Smarkm	/*
312829088Smarkm	 * Next, decide whether we have a loose source
312929088Smarkm	 * route or a strict source route, and fill in
313029088Smarkm	 * the begining of the option.
313129088Smarkm	 */
313229088Smarkm#ifndef	sysV88
313329088Smarkm	if (*cp == '!') {
313429088Smarkm		cp++;
313529088Smarkm		*lsrp++ = IPOPT_SSRR;
313629088Smarkm	} else
313729088Smarkm		*lsrp++ = IPOPT_LSRR;
313829088Smarkm#else
313929088Smarkm	if (*cp == '!') {
314029088Smarkm		cp++;
314129088Smarkm		ipopt.io_type = IPOPT_SSRR;
314229088Smarkm	} else
314329088Smarkm		ipopt.io_type = IPOPT_LSRR;
314429088Smarkm#endif
314529088Smarkm
314629088Smarkm	if (*cp != '@')
314757724Sshin		return -1;
314829088Smarkm
314929088Smarkm#ifndef	sysV88
315029088Smarkm	lsrp++;		/* skip over length, we'll fill it in later */
315129088Smarkm	*lsrp++ = 4;
315229088Smarkm#endif
315356668Sshin	*protop = IPPROTO_IP;
315456668Sshin	*optp = IP_OPTIONS;
315556668Sshin      }
315629088Smarkm
315729088Smarkm	cp++;
315856668Sshin	memset(&hints, 0, sizeof(hints));
315956668Sshin	hints.ai_family = ai->ai_family;
316056668Sshin	hints.ai_socktype = SOCK_STREAM;
316129088Smarkm	for (c = 0;;) {
316256668Sshin		if (
316356668Sshin#ifdef INET6
316456668Sshin		    ai->ai_family != AF_INET6 &&
316556668Sshin#endif
316656668Sshin		    c == ':')
316729088Smarkm			cp2 = 0;
316829181Smarkm		else for (cp2 = cp; (c = *cp2); cp2++) {
316929088Smarkm			if (c == ',') {
317029088Smarkm				*cp2++ = '\0';
317129088Smarkm				if (*cp2 == '@')
317229088Smarkm					cp2++;
317329088Smarkm			} else if (c == '@') {
317429088Smarkm				*cp2++ = '\0';
317556668Sshin			} else if (
317656668Sshin#ifdef INET6
317756668Sshin				   ai->ai_family != AF_INET6 &&
317856668Sshin#endif
317956668Sshin				   c == ':') {
318029088Smarkm				*cp2++ = '\0';
318129088Smarkm			} else
318229088Smarkm				continue;
318329088Smarkm			break;
318429088Smarkm		}
318529088Smarkm		if (!c)
318629088Smarkm			cp2 = 0;
318729088Smarkm
318856668Sshin		hints.ai_flags = AI_NUMERICHOST;
318956668Sshin 		error = getaddrinfo(cp, NULL, &hints, &res);
319062805Sume		if (error == EAI_NODATA) {
319156668Sshin			hints.ai_flags = 0;
319256668Sshin			error = getaddrinfo(cp, NULL, &hints, &res);
319356668Sshin		}
319456668Sshin		if (error != 0) {
319556668Sshin			fprintf(stderr, "%s: %s\n", cp, gai_strerror(error));
319656668Sshin			if (error == EAI_SYSTEM)
319756668Sshin				fprintf(stderr, "%s: %s\n", cp,
319856668Sshin					strerror(errno));
319929088Smarkm			*cpp = cp;
320029088Smarkm			return(0);
320129088Smarkm		}
320256668Sshin#ifdef INET6
320356668Sshin		if (res->ai_family == AF_INET6) {
320456668Sshin			sin6 = (struct sockaddr_in6 *)res->ai_addr;
320556668Sshin			inet6_rthdr_add(cmsg, &sin6->sin6_addr,
320656668Sshin					IPV6_RTHDR_LOOSE);
320756668Sshin		} else
320856668Sshin#endif
320956668Sshin	      {
321056668Sshin		sin = (struct sockaddr_in *)res->ai_addr;
321156668Sshin		memcpy(lsrp, (char *)&sin->sin_addr, 4);
321229088Smarkm		lsrp += 4;
321356668Sshin	      }
321429088Smarkm		if (cp2)
321529088Smarkm			cp = cp2;
321629088Smarkm		else
321729088Smarkm			break;
321829088Smarkm		/*
321929088Smarkm		 * Check to make sure there is space for next address
322029088Smarkm		 */
322156668Sshin#ifdef INET6
322256668Sshin		if (res->ai_family == AF_INET6) {
322357724Sshin			if (((char *)CMSG_DATA(cmsg) +
322456668Sshin			     sizeof(struct ip6_rthdr) +
322556668Sshin			     ((inet6_rthdr_segments(cmsg) + 1) *
322656668Sshin			      sizeof(struct in6_addr))) > ep)
322757724Sshin			return -1;
322856668Sshin		} else
322956668Sshin#endif
323056668Sshin		if (lsrp + 4 > ep)
323157724Sshin			return -1;
323256668Sshin		freeaddrinfo(res);
323329088Smarkm	}
323456668Sshin#ifdef INET6
323556668Sshin	if (res->ai_family == AF_INET6) {
323656668Sshin		inet6_rthdr_lasthop(cmsg, IPV6_RTHDR_LOOSE);
323756668Sshin		*lenp = cmsg->cmsg_len;
323856668Sshin	} else
323956668Sshin#endif
324056668Sshin      {
324129088Smarkm#ifndef	sysV88
324229088Smarkm	if ((*(*cpp+IPOPT_OLEN) = lsrp - *cpp) <= 7) {
324329088Smarkm		*cpp = 0;
324429088Smarkm		*lenp = 0;
324557724Sshin		return -1;
324629088Smarkm	}
324729088Smarkm	*lsrp++ = IPOPT_NOP; /* 32 bit word align it */
324829088Smarkm	*lenp = lsrp - *cpp;
324929088Smarkm#else
325029088Smarkm	ipopt.io_len = lsrp - *cpp;
325129088Smarkm	if (ipopt.io_len <= 5) {		/* Is 3 better ? */
325229088Smarkm		*cpp = 0;
325329088Smarkm		*lenp = 0;
325457724Sshin		return -1;
325529088Smarkm	}
325629088Smarkm	*lenp = sizeof(ipopt);
325729088Smarkm	*cpp = (char *) &ipopt;
325829088Smarkm#endif
325956668Sshin      }
326056668Sshin	freeaddrinfo(res);
326156668Sshin	return 1;
326229088Smarkm}
326356668Sshin
326456668Sshin
326556668Sshin
3266