157416Smarkm/*
257416Smarkm * Copyright (c) 1988, 1990, 1993
357416Smarkm *	The Regents of the University of California.  All rights reserved.
457416Smarkm *
557416Smarkm * Redistribution and use in source and binary forms, with or without
657416Smarkm * modification, are permitted provided that the following conditions
757416Smarkm * are met:
857416Smarkm * 1. Redistributions of source code must retain the above copyright
957416Smarkm *    notice, this list of conditions and the following disclaimer.
1057416Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1157416Smarkm *    notice, this list of conditions and the following disclaimer in the
1257416Smarkm *    documentation and/or other materials provided with the distribution.
1357416Smarkm * 3. All advertising materials mentioning features or use of this software
1457416Smarkm *    must display the following acknowledgement:
1557416Smarkm *	This product includes software developed by the University of
1657416Smarkm *	California, Berkeley and its contributors.
1757416Smarkm * 4. Neither the name of the University nor the names of its contributors
1857416Smarkm *    may be used to endorse or promote products derived from this software
1957416Smarkm *    without specific prior written permission.
2057416Smarkm *
2157416Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2257416Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2357416Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2457416Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2557416Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2657416Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2757416Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2857416Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2957416Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3057416Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3157416Smarkm * SUCH DAMAGE.
3257416Smarkm */
3357416Smarkm
3457416Smarkm#include "telnet_locl.h"
3557416Smarkm
36233294SstasRCSID("$Id$");
3757416Smarkm
3857416Smarkm#if	defined(IPPROTO_IP) && defined(IP_TOS)
3957416Smarkmint tos = -1;
4057416Smarkm#endif	/* defined(IPPROTO_IP) && defined(IP_TOS) */
4157416Smarkm
4257416Smarkmchar	*hostname;
4357416Smarkmstatic char _hostname[MaxHostNameLen];
4457416Smarkm
4557416Smarkmtypedef int (*intrtn_t)(int, char**);
4657416Smarkmstatic int call(intrtn_t, ...);
4757416Smarkm
4857416Smarkmtypedef struct {
4957416Smarkm	char	*name;		/* command name */
5057416Smarkm	char	*help;		/* help string (NULL for no help) */
5157416Smarkm	int	(*handler)();	/* routine which executes command */
5257416Smarkm	int	needconnect;	/* Do we need to be connected to execute? */
5357416Smarkm} Command;
5457416Smarkm
5557416Smarkmstatic char line[256];
5657416Smarkmstatic char saveline[256];
5757416Smarkmstatic int margc;
5857416Smarkmstatic char *margv[20];
5957416Smarkm
6057416Smarkmstatic void
6157416Smarkmmakeargv()
6257416Smarkm{
6357416Smarkm    char *cp, *cp2, c;
6457416Smarkm    char **argp = margv;
6557416Smarkm
6657416Smarkm    margc = 0;
6757416Smarkm    cp = line;
6857416Smarkm    if (*cp == '!') {		/* Special case shell escape */
6957416Smarkm	/* save for shell command */
7057416Smarkm	strlcpy(saveline, line, sizeof(saveline));
7157416Smarkm	*argp++ = "!";		/* No room in string to get this */
7257416Smarkm	margc++;
7357416Smarkm	cp++;
7457416Smarkm    }
7557416Smarkm    while ((c = *cp)) {
7657416Smarkm	int inquote = 0;
77178825Sdfr	while (isspace((unsigned char)c))
7857416Smarkm	    c = *++cp;
7957416Smarkm	if (c == '\0')
8057416Smarkm	    break;
8157416Smarkm	*argp++ = cp;
8257416Smarkm	margc += 1;
8357416Smarkm	for (cp2 = cp; c != '\0'; c = *++cp) {
8457416Smarkm	    if (inquote) {
8557416Smarkm		if (c == inquote) {
8657416Smarkm		    inquote = 0;
8757416Smarkm		    continue;
8857416Smarkm		}
8957416Smarkm	    } else {
9057416Smarkm		if (c == '\\') {
9157416Smarkm		    if ((c = *++cp) == '\0')
9257416Smarkm			break;
9357416Smarkm		} else if (c == '"') {
9457416Smarkm		    inquote = '"';
9557416Smarkm		    continue;
9657416Smarkm		} else if (c == '\'') {
9757416Smarkm		    inquote = '\'';
9857416Smarkm		    continue;
99178825Sdfr		} else if (isspace((unsigned char)c))
10057416Smarkm		    break;
10157416Smarkm	    }
10257416Smarkm	    *cp2++ = c;
10357416Smarkm	}
10457416Smarkm	*cp2 = '\0';
10557416Smarkm	if (c == '\0')
10657416Smarkm	    break;
10757416Smarkm	cp++;
10857416Smarkm    }
10957416Smarkm    *argp++ = 0;
11057416Smarkm}
11157416Smarkm
11257416Smarkm/*
11357416Smarkm * Make a character string into a number.
11457416Smarkm *
11557416Smarkm * Todo:  1.  Could take random integers (12, 0x12, 012, 0b1).
11657416Smarkm */
11757416Smarkm
11857416Smarkmstatic char
11957416Smarkmspecial(char *s)
12057416Smarkm{
12157416Smarkm	char c;
12257416Smarkm	char b;
12357416Smarkm
12457416Smarkm	switch (*s) {
12557416Smarkm	case '^':
12657416Smarkm		b = *++s;
12757416Smarkm		if (b == '?') {
12857416Smarkm		    c = b | 0x40;		/* DEL */
12957416Smarkm		} else {
13057416Smarkm		    c = b & 0x1f;
13157416Smarkm		}
13257416Smarkm		break;
13357416Smarkm	default:
13457416Smarkm		c = *s;
13557416Smarkm		break;
13657416Smarkm	}
13757416Smarkm	return c;
13857416Smarkm}
13957416Smarkm
14057416Smarkm/*
14157416Smarkm * Construct a control character sequence
14257416Smarkm * for a special character.
14357416Smarkm */
14457416Smarkmstatic char *
14557416Smarkmcontrol(cc_t c)
14657416Smarkm{
14757416Smarkm	static char buf[5];
14857416Smarkm	/*
14957416Smarkm	 * The only way I could get the Sun 3.5 compiler
15057416Smarkm	 * to shut up about
15157416Smarkm	 *	if ((unsigned int)c >= 0x80)
15257416Smarkm	 * was to assign "c" to an unsigned int variable...
15357416Smarkm	 * Arggg....
15457416Smarkm	 */
15557416Smarkm	unsigned int uic = (unsigned int)c;
15657416Smarkm
15757416Smarkm	if (uic == 0x7f)
15857416Smarkm		return ("^?");
15957416Smarkm	if (c == (cc_t)_POSIX_VDISABLE) {
16057416Smarkm		return "off";
16157416Smarkm	}
16257416Smarkm	if (uic >= 0x80) {
16357416Smarkm		buf[0] = '\\';
16457416Smarkm		buf[1] = ((c>>6)&07) + '0';
16557416Smarkm		buf[2] = ((c>>3)&07) + '0';
16657416Smarkm		buf[3] = (c&07) + '0';
16757416Smarkm		buf[4] = 0;
16857416Smarkm	} else if (uic >= 0x20) {
16957416Smarkm		buf[0] = c;
17057416Smarkm		buf[1] = 0;
17157416Smarkm	} else {
17257416Smarkm		buf[0] = '^';
17357416Smarkm		buf[1] = '@'+c;
17457416Smarkm		buf[2] = 0;
17557416Smarkm	}
17657416Smarkm	return (buf);
17757416Smarkm}
17857416Smarkm
17957416Smarkm
18057416Smarkm
18157416Smarkm/*
18257416Smarkm *	The following are data structures and routines for
18357416Smarkm *	the "send" command.
18457416Smarkm *
18557416Smarkm */
18657416Smarkm
18757416Smarkmstruct sendlist {
18857416Smarkm    char	*name;		/* How user refers to it (case independent) */
18957416Smarkm    char	*help;		/* Help information (0 ==> no help) */
19057416Smarkm    int		needconnect;	/* Need to be connected */
19157416Smarkm    int		narg;		/* Number of arguments */
19257416Smarkm    int		(*handler)();	/* Routine to perform (for special ops) */
19357416Smarkm    int		nbyte;		/* Number of bytes to send this command */
19457416Smarkm    int		what;		/* Character to be sent (<0 ==> special) */
19557416Smarkm};
19657416Smarkm
19757416Smarkm
19857416Smarkmstatic int
19957416Smarkm	send_esc (void),
20057416Smarkm	send_help (void),
20157416Smarkm	send_docmd (char *),
20257416Smarkm	send_dontcmd (char *),
20357416Smarkm	send_willcmd (char *),
20457416Smarkm	send_wontcmd (char *);
20557416Smarkm
20657416Smarkmstatic struct sendlist Sendlist[] = {
20757416Smarkm    { "ao",	"Send Telnet Abort output",		1, 0, 0, 2, AO },
20857416Smarkm    { "ayt",	"Send Telnet 'Are You There'",		1, 0, 0, 2, AYT },
20957416Smarkm    { "brk",	"Send Telnet Break",			1, 0, 0, 2, BREAK },
21057416Smarkm    { "break",	0,					1, 0, 0, 2, BREAK },
21157416Smarkm    { "ec",	"Send Telnet Erase Character",		1, 0, 0, 2, EC },
21257416Smarkm    { "el",	"Send Telnet Erase Line",		1, 0, 0, 2, EL },
21357416Smarkm    { "escape",	"Send current escape character",	1, 0, send_esc, 1, 0 },
21457416Smarkm    { "ga",	"Send Telnet 'Go Ahead' sequence",	1, 0, 0, 2, GA },
21557416Smarkm    { "ip",	"Send Telnet Interrupt Process",	1, 0, 0, 2, IP },
21657416Smarkm    { "intp",	0,					1, 0, 0, 2, IP },
21757416Smarkm    { "interrupt", 0,					1, 0, 0, 2, IP },
21857416Smarkm    { "intr",	0,					1, 0, 0, 2, IP },
21957416Smarkm    { "nop",	"Send Telnet 'No operation'",		1, 0, 0, 2, NOP },
22057416Smarkm    { "eor",	"Send Telnet 'End of Record'",		1, 0, 0, 2, EOR },
22157416Smarkm    { "abort",	"Send Telnet 'Abort Process'",		1, 0, 0, 2, ABORT },
22257416Smarkm    { "susp",	"Send Telnet 'Suspend Process'",	1, 0, 0, 2, SUSP },
22357416Smarkm    { "eof",	"Send Telnet End of File Character",	1, 0, 0, 2, xEOF },
22457416Smarkm    { "synch",	"Perform Telnet 'Synch operation'",	1, 0, dosynch, 2, 0 },
22557416Smarkm    { "getstatus", "Send request for STATUS",		1, 0, get_status, 6, 0 },
22657416Smarkm    { "?",	"Display send options",			0, 0, send_help, 0, 0 },
22757416Smarkm    { "help",	0,					0, 0, send_help, 0, 0 },
22857416Smarkm    { "do",	0,					0, 1, send_docmd, 3, 0 },
22957416Smarkm    { "dont",	0,					0, 1, send_dontcmd, 3, 0 },
23057416Smarkm    { "will",	0,					0, 1, send_willcmd, 3, 0 },
23157416Smarkm    { "wont",	0,					0, 1, send_wontcmd, 3, 0 },
23257416Smarkm    { 0 }
23357416Smarkm};
23457416Smarkm
23557416Smarkm#define	GETSEND(name) ((struct sendlist *) genget(name, (char **) Sendlist, \
23657416Smarkm				sizeof(struct sendlist)))
23757416Smarkm
23857416Smarkmstatic int
23957416Smarkmsendcmd(int argc, char **argv)
24057416Smarkm{
24157416Smarkm    int count;		/* how many bytes we are going to need to send */
24257416Smarkm    int i;
24357416Smarkm    struct sendlist *s;	/* pointer to current command */
24457416Smarkm    int success = 0;
24557416Smarkm    int needconnect = 0;
24657416Smarkm
24757416Smarkm    if (argc < 2) {
24857416Smarkm	printf("need at least one argument for 'send' command\r\n");
24957416Smarkm	printf("'send ?' for help\r\n");
25057416Smarkm	return 0;
25157416Smarkm    }
25257416Smarkm    /*
25357416Smarkm     * First, validate all the send arguments.
25457416Smarkm     * In addition, we see how much space we are going to need, and
25557416Smarkm     * whether or not we will be doing a "SYNCH" operation (which
25657416Smarkm     * flushes the network queue).
25757416Smarkm     */
25857416Smarkm    count = 0;
25957416Smarkm    for (i = 1; i < argc; i++) {
26057416Smarkm	s = GETSEND(argv[i]);
26157416Smarkm	if (s == 0) {
26257416Smarkm	    printf("Unknown send argument '%s'\r\n'send ?' for help.\r\n",
26357416Smarkm			argv[i]);
26457416Smarkm	    return 0;
26557416Smarkm	} else if (Ambiguous(s)) {
26657416Smarkm	    printf("Ambiguous send argument '%s'\r\n'send ?' for help.\r\n",
26757416Smarkm			argv[i]);
26857416Smarkm	    return 0;
26957416Smarkm	}
27057416Smarkm	if (i + s->narg >= argc) {
27157416Smarkm	    fprintf(stderr,
27257416Smarkm	    "Need %d argument%s to 'send %s' command.  'send %s ?' for help.\r\n",
27357416Smarkm		s->narg, s->narg == 1 ? "" : "s", s->name, s->name);
27457416Smarkm	    return 0;
27557416Smarkm	}
27657416Smarkm	count += s->nbyte;
27757416Smarkm	if (s->handler == send_help) {
27857416Smarkm	    send_help();
27957416Smarkm	    return 0;
28057416Smarkm	}
28157416Smarkm
28257416Smarkm	i += s->narg;
28357416Smarkm	needconnect += s->needconnect;
28457416Smarkm    }
28557416Smarkm    if (!connected && needconnect) {
28657416Smarkm	printf("?Need to be connected first.\r\n");
28757416Smarkm	printf("'send ?' for help\r\n");
28857416Smarkm	return 0;
28957416Smarkm    }
29057416Smarkm    /* Now, do we have enough room? */
29157416Smarkm    if (NETROOM() < count) {
29257416Smarkm	printf("There is not enough room in the buffer TO the network\r\n");
29357416Smarkm	printf("to process your request.  Nothing will be done.\r\n");
29457416Smarkm	printf("('send synch' will throw away most data in the network\r\n");
29557416Smarkm	printf("buffer, if this might help.)\r\n");
29657416Smarkm	return 0;
29757416Smarkm    }
29857416Smarkm    /* OK, they are all OK, now go through again and actually send */
29957416Smarkm    count = 0;
30057416Smarkm    for (i = 1; i < argc; i++) {
30157416Smarkm	if ((s = GETSEND(argv[i])) == 0) {
30257416Smarkm	    fprintf(stderr, "Telnet 'send' error - argument disappeared!\r\n");
30357416Smarkm	    quit();
30457416Smarkm	    /*NOTREACHED*/
30557416Smarkm	}
30657416Smarkm	if (s->handler) {
30757416Smarkm	    count++;
30857416Smarkm	    success += (*s->handler)((s->narg > 0) ? argv[i+1] : 0,
30957416Smarkm				  (s->narg > 1) ? argv[i+2] : 0);
31057416Smarkm	    i += s->narg;
31157416Smarkm	} else {
31257416Smarkm	    NET2ADD(IAC, s->what);
31357416Smarkm	    printoption("SENT", IAC, s->what);
31457416Smarkm	}
31557416Smarkm    }
31657416Smarkm    return (count == success);
31757416Smarkm}
31857416Smarkm
31957416Smarkmstatic int
32057416Smarkmsend_tncmd(void (*func)(), char *cmd, char *name);
32157416Smarkm
32257416Smarkmstatic int
32357416Smarkmsend_esc()
32457416Smarkm{
32557416Smarkm    NETADD(escape);
32657416Smarkm    return 1;
32757416Smarkm}
32857416Smarkm
32957416Smarkmstatic int
33057416Smarkmsend_docmd(char *name)
33157416Smarkm{
33257416Smarkm    return(send_tncmd(send_do, "do", name));
33357416Smarkm}
33457416Smarkm
33557416Smarkmstatic int
33657416Smarkmsend_dontcmd(char *name)
33757416Smarkm{
33857416Smarkm    return(send_tncmd(send_dont, "dont", name));
33957416Smarkm}
34057416Smarkm
34157416Smarkmstatic int
34257416Smarkmsend_willcmd(char *name)
34357416Smarkm{
34457416Smarkm    return(send_tncmd(send_will, "will", name));
34557416Smarkm}
34657416Smarkm
34757416Smarkmstatic int
34857416Smarkmsend_wontcmd(char *name)
34957416Smarkm{
35057416Smarkm    return(send_tncmd(send_wont, "wont", name));
35157416Smarkm}
35257416Smarkm
35390926Snectarextern char *telopts[];		/* XXX */
35490926Snectar
35557416Smarkmstatic int
35657416Smarkmsend_tncmd(void (*func)(), char *cmd, char *name)
35757416Smarkm{
35857416Smarkm    char **cpp;
35957416Smarkm    int val = 0;
36057416Smarkm
36157416Smarkm    if (isprefix(name, "help") || isprefix(name, "?")) {
36257416Smarkm	int col, len;
36357416Smarkm
36457416Smarkm	printf("Usage: send %s <value|option>\r\n", cmd);
36557416Smarkm	printf("\"value\" must be from 0 to 255\r\n");
36657416Smarkm	printf("Valid options are:\r\n\t");
36757416Smarkm
36857416Smarkm	col = 8;
36957416Smarkm	for (cpp = telopts; *cpp; cpp++) {
37057416Smarkm	    len = strlen(*cpp) + 3;
37157416Smarkm	    if (col + len > 65) {
37257416Smarkm		printf("\r\n\t");
37357416Smarkm		col = 8;
37457416Smarkm	    }
37557416Smarkm	    printf(" \"%s\"", *cpp);
37657416Smarkm	    col += len;
37757416Smarkm	}
37857416Smarkm	printf("\r\n");
37957416Smarkm	return 0;
38057416Smarkm    }
38157416Smarkm    cpp = genget(name, telopts, sizeof(char *));
38257416Smarkm    if (Ambiguous(cpp)) {
38357416Smarkm	fprintf(stderr,"'%s': ambiguous argument ('send %s ?' for help).\r\n",
38457416Smarkm					name, cmd);
38557416Smarkm	return 0;
38657416Smarkm    }
38757416Smarkm    if (cpp) {
38857416Smarkm	val = cpp - telopts;
38957416Smarkm    } else {
39057416Smarkm	char *cp = name;
39157416Smarkm
39257416Smarkm	while (*cp >= '0' && *cp <= '9') {
39357416Smarkm	    val *= 10;
39457416Smarkm	    val += *cp - '0';
39557416Smarkm	    cp++;
39657416Smarkm	}
39757416Smarkm	if (*cp != 0) {
39857416Smarkm	    fprintf(stderr, "'%s': unknown argument ('send %s ?' for help).\r\n",
39957416Smarkm					name, cmd);
40057416Smarkm	    return 0;
40157416Smarkm	} else if (val < 0 || val > 255) {
40257416Smarkm	    fprintf(stderr, "'%s': bad value ('send %s ?' for help).\r\n",
40357416Smarkm					name, cmd);
40457416Smarkm	    return 0;
40557416Smarkm	}
40657416Smarkm    }
40757416Smarkm    if (!connected) {
40857416Smarkm	printf("?Need to be connected first.\r\n");
40957416Smarkm	return 0;
41057416Smarkm    }
41157416Smarkm    (*func)(val, 1);
41257416Smarkm    return 1;
41357416Smarkm}
41457416Smarkm
41557416Smarkmstatic int
41657416Smarkmsend_help()
41757416Smarkm{
41857416Smarkm    struct sendlist *s;	/* pointer to current command */
41957416Smarkm    for (s = Sendlist; s->name; s++) {
42057416Smarkm	if (s->help)
42157416Smarkm	    printf("%-15s %s\r\n", s->name, s->help);
42257416Smarkm    }
42357416Smarkm    return(0);
42457416Smarkm}
42557416Smarkm
42657416Smarkm/*
42757416Smarkm * The following are the routines and data structures referred
42857416Smarkm * to by the arguments to the "toggle" command.
42957416Smarkm */
43057416Smarkm
43157416Smarkmstatic int
43257416Smarkmlclchars()
43357416Smarkm{
43457416Smarkm    donelclchars = 1;
43557416Smarkm    return 1;
43657416Smarkm}
43757416Smarkm
43857416Smarkmstatic int
43957416Smarkmtogdebug()
44057416Smarkm{
44157416Smarkm#ifndef	NOT43
44257416Smarkm    if (net > 0 &&
44357416Smarkm	(SetSockOpt(net, SOL_SOCKET, SO_DEBUG, debug)) < 0) {
44457416Smarkm	    perror("setsockopt (SO_DEBUG)");
44557416Smarkm    }
44657416Smarkm#else	/* NOT43 */
44757416Smarkm    if (debug) {
44857416Smarkm	if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
44957416Smarkm	    perror("setsockopt (SO_DEBUG)");
45057416Smarkm    } else
45157416Smarkm	printf("Cannot turn off socket debugging\r\n");
45257416Smarkm#endif	/* NOT43 */
45357416Smarkm    return 1;
45457416Smarkm}
45557416Smarkm
45657416Smarkmstatic int
45757416Smarkmtogcrlf()
45857416Smarkm{
45957416Smarkm    if (crlf) {
46057416Smarkm	printf("Will send carriage returns as telnet <CR><LF>.\r\n");
46157416Smarkm    } else {
46257416Smarkm	printf("Will send carriage returns as telnet <CR><NUL>.\r\n");
46357416Smarkm    }
46457416Smarkm    return 1;
46557416Smarkm}
46657416Smarkm
46757416Smarkmint binmode;
46857416Smarkm
46957416Smarkmstatic int
47057416Smarkmtogbinary(int val)
47157416Smarkm{
47257416Smarkm    donebinarytoggle = 1;
47357416Smarkm
47457416Smarkm    if (val >= 0) {
47557416Smarkm	binmode = val;
47657416Smarkm    } else {
47757416Smarkm	if (my_want_state_is_will(TELOPT_BINARY) &&
47857416Smarkm				my_want_state_is_do(TELOPT_BINARY)) {
47957416Smarkm	    binmode = 1;
48057416Smarkm	} else if (my_want_state_is_wont(TELOPT_BINARY) &&
48157416Smarkm				my_want_state_is_dont(TELOPT_BINARY)) {
48257416Smarkm	    binmode = 0;
48357416Smarkm	}
48457416Smarkm	val = binmode ? 0 : 1;
48557416Smarkm    }
48657416Smarkm
48757416Smarkm    if (val == 1) {
48857416Smarkm	if (my_want_state_is_will(TELOPT_BINARY) &&
48957416Smarkm					my_want_state_is_do(TELOPT_BINARY)) {
49057416Smarkm	    printf("Already operating in binary mode with remote host.\r\n");
49157416Smarkm	} else {
49257416Smarkm	    printf("Negotiating binary mode with remote host.\r\n");
49357416Smarkm	    tel_enter_binary(3);
49457416Smarkm	}
49557416Smarkm    } else {
49657416Smarkm	if (my_want_state_is_wont(TELOPT_BINARY) &&
49757416Smarkm					my_want_state_is_dont(TELOPT_BINARY)) {
49857416Smarkm	    printf("Already in network ascii mode with remote host.\r\n");
49957416Smarkm	} else {
50057416Smarkm	    printf("Negotiating network ascii mode with remote host.\r\n");
50157416Smarkm	    tel_leave_binary(3);
50257416Smarkm	}
50357416Smarkm    }
50457416Smarkm    return 1;
50557416Smarkm}
50657416Smarkm
50757416Smarkmstatic int
50857416Smarkmtogrbinary(int val)
50957416Smarkm{
51057416Smarkm    donebinarytoggle = 1;
51157416Smarkm
51257416Smarkm    if (val == -1)
51357416Smarkm	val = my_want_state_is_do(TELOPT_BINARY) ? 0 : 1;
51457416Smarkm
51557416Smarkm    if (val == 1) {
51657416Smarkm	if (my_want_state_is_do(TELOPT_BINARY)) {
51757416Smarkm	    printf("Already receiving in binary mode.\r\n");
51857416Smarkm	} else {
51957416Smarkm	    printf("Negotiating binary mode on input.\r\n");
52057416Smarkm	    tel_enter_binary(1);
52157416Smarkm	}
52257416Smarkm    } else {
52357416Smarkm	if (my_want_state_is_dont(TELOPT_BINARY)) {
52457416Smarkm	    printf("Already receiving in network ascii mode.\r\n");
52557416Smarkm	} else {
52657416Smarkm	    printf("Negotiating network ascii mode on input.\r\n");
52757416Smarkm	    tel_leave_binary(1);
52857416Smarkm	}
52957416Smarkm    }
53057416Smarkm    return 1;
53157416Smarkm}
53257416Smarkm
53357416Smarkmstatic int
53457416Smarkmtogxbinary(int val)
53557416Smarkm{
53657416Smarkm    donebinarytoggle = 1;
53757416Smarkm
53857416Smarkm    if (val == -1)
53957416Smarkm	val = my_want_state_is_will(TELOPT_BINARY) ? 0 : 1;
54057416Smarkm
54157416Smarkm    if (val == 1) {
54257416Smarkm	if (my_want_state_is_will(TELOPT_BINARY)) {
54357416Smarkm	    printf("Already transmitting in binary mode.\r\n");
54457416Smarkm	} else {
54557416Smarkm	    printf("Negotiating binary mode on output.\r\n");
54657416Smarkm	    tel_enter_binary(2);
54757416Smarkm	}
54857416Smarkm    } else {
54957416Smarkm	if (my_want_state_is_wont(TELOPT_BINARY)) {
55057416Smarkm	    printf("Already transmitting in network ascii mode.\r\n");
55157416Smarkm	} else {
55257416Smarkm	    printf("Negotiating network ascii mode on output.\r\n");
55357416Smarkm	    tel_leave_binary(2);
55457416Smarkm	}
55557416Smarkm    }
55657416Smarkm    return 1;
55757416Smarkm}
55857416Smarkm
55957416Smarkm
56057416Smarkmstatic int togglehelp (void);
56157416Smarkm#if	defined(AUTHENTICATION)
56257416Smarkmextern int auth_togdebug (int);
56357416Smarkm#endif
56457416Smarkm#if	defined(ENCRYPTION)
56557416Smarkmextern int EncryptAutoEnc (int);
56657416Smarkmextern int EncryptAutoDec (int);
56757416Smarkmextern int EncryptDebug (int);
56857416Smarkmextern int EncryptVerbose (int);
56957416Smarkm#endif
57057416Smarkm
57157416Smarkmstruct togglelist {
57257416Smarkm    char	*name;		/* name of toggle */
57357416Smarkm    char	*help;		/* help message */
57457416Smarkm    int		(*handler)();	/* routine to do actual setting */
57557416Smarkm    int		*variable;
57657416Smarkm    char	*actionexplanation;
57757416Smarkm};
57857416Smarkm
57957416Smarkmstatic struct togglelist Togglelist[] = {
58057416Smarkm    { "autoflush",
58157416Smarkm	"flushing of output when sending interrupt characters",
58257416Smarkm	    0,
58357416Smarkm		&autoflush,
58457416Smarkm		    "flush output when sending interrupt characters" },
58557416Smarkm    { "autosynch",
58657416Smarkm	"automatic sending of interrupt characters in urgent mode",
58757416Smarkm	    0,
58857416Smarkm		&autosynch,
58957416Smarkm		    "send interrupt characters in urgent mode" },
59057416Smarkm#if	defined(AUTHENTICATION)
59157416Smarkm    { "autologin",
59257416Smarkm	"automatic sending of login and/or authentication info",
59357416Smarkm	    0,
59457416Smarkm		&autologin,
59557416Smarkm		    "send login name and/or authentication information" },
59657416Smarkm    { "authdebug",
597102644Snectar	"authentication debugging",
59857416Smarkm	    auth_togdebug,
59957416Smarkm		0,
60057416Smarkm		     "print authentication debugging information" },
60157416Smarkm#endif
60257416Smarkm#if	defined(ENCRYPTION)
60357416Smarkm    { "autoencrypt",
60457416Smarkm	"automatic encryption of data stream",
60557416Smarkm	    EncryptAutoEnc,
60657416Smarkm		0,
60757416Smarkm		    "automatically encrypt output" },
60857416Smarkm    { "autodecrypt",
60957416Smarkm	"automatic decryption of data stream",
61057416Smarkm	    EncryptAutoDec,
61157416Smarkm		0,
61257416Smarkm		    "automatically decrypt input" },
61357416Smarkm    { "verbose_encrypt",
614102644Snectar	"verbose encryption output",
61557416Smarkm	    EncryptVerbose,
61657416Smarkm		0,
61757416Smarkm		    "print verbose encryption output" },
61857416Smarkm    { "encdebug",
619102644Snectar	"encryption debugging",
62057416Smarkm	    EncryptDebug,
62157416Smarkm		0,
62257416Smarkm		    "print encryption debugging information" },
62357416Smarkm#endif
624102644Snectar#if defined(KRB5)
625102644Snectar    { "forward",
626102644Snectar	"credentials forwarding",
627102644Snectar	    kerberos5_set_forward,
628102644Snectar		0,
629102644Snectar		    "forward credentials" },
630102644Snectar    { "forwardable",
631102644Snectar	"forwardable flag of forwarded credentials",
632102644Snectar	    kerberos5_set_forwardable,
633102644Snectar		0,
634102644Snectar		    "forward forwardable credentials" },
635102644Snectar#endif
636102644Snectar   { "skiprc",
63757416Smarkm	"don't read ~/.telnetrc file",
63857416Smarkm	    0,
63957416Smarkm		&skiprc,
64057416Smarkm		    "skip reading of ~/.telnetrc file" },
64157416Smarkm    { "binary",
64257416Smarkm	"sending and receiving of binary data",
64357416Smarkm	    togbinary,
64457416Smarkm		0,
64557416Smarkm		    0 },
64657416Smarkm    { "inbinary",
64757416Smarkm	"receiving of binary data",
64857416Smarkm	    togrbinary,
64957416Smarkm		0,
65057416Smarkm		    0 },
65157416Smarkm    { "outbinary",
65257416Smarkm	"sending of binary data",
65357416Smarkm	    togxbinary,
65457416Smarkm		0,
65557416Smarkm		    0 },
65657416Smarkm    { "crlf",
65757416Smarkm	"sending carriage returns as telnet <CR><LF>",
65857416Smarkm	    togcrlf,
65957416Smarkm		&crlf,
66057416Smarkm		    0 },
66157416Smarkm    { "crmod",
66257416Smarkm	"mapping of received carriage returns",
66357416Smarkm	    0,
66457416Smarkm		&crmod,
66557416Smarkm		    "map carriage return on output" },
66657416Smarkm    { "localchars",
66757416Smarkm	"local recognition of certain control characters",
66857416Smarkm	    lclchars,
66957416Smarkm		&localchars,
67057416Smarkm		    "recognize certain control characters" },
67157416Smarkm    { " ", "", 0 },		/* empty line */
67257416Smarkm    { "debug",
67357416Smarkm	"debugging",
67457416Smarkm	    togdebug,
67557416Smarkm		&debug,
67657416Smarkm		    "turn on socket level debugging" },
67757416Smarkm    { "netdata",
67857416Smarkm	"printing of hexadecimal network data (debugging)",
67957416Smarkm	    0,
68057416Smarkm		&netdata,
68157416Smarkm		    "print hexadecimal representation of network traffic" },
68257416Smarkm    { "prettydump",
68357416Smarkm	"output of \"netdata\" to user readable format (debugging)",
68457416Smarkm	    0,
68557416Smarkm		&prettydump,
68657416Smarkm		    "print user readable output for \"netdata\"" },
68757416Smarkm    { "options",
68857416Smarkm	"viewing of options processing (debugging)",
68957416Smarkm	    0,
69057416Smarkm		&showoptions,
69157416Smarkm		    "show option processing" },
69257416Smarkm    { "termdata",
693102644Snectar	"printing of hexadecimal terminal data (debugging)",
69457416Smarkm	    0,
69557416Smarkm		&termdata,
69657416Smarkm		    "print hexadecimal representation of terminal traffic" },
69757416Smarkm    { "?",
69857416Smarkm	0,
69957416Smarkm	    togglehelp },
70057416Smarkm    { "help",
70157416Smarkm	0,
70257416Smarkm	    togglehelp },
70357416Smarkm    { 0 }
70457416Smarkm};
70557416Smarkm
70657416Smarkmstatic int
70757416Smarkmtogglehelp()
70857416Smarkm{
70957416Smarkm    struct togglelist *c;
71057416Smarkm
71157416Smarkm    for (c = Togglelist; c->name; c++) {
71257416Smarkm	if (c->help) {
71357416Smarkm	    if (*c->help)
71457416Smarkm		printf("%-15s toggle %s\r\n", c->name, c->help);
71557416Smarkm	    else
71657416Smarkm		printf("\r\n");
71757416Smarkm	}
71857416Smarkm    }
71957416Smarkm    printf("\r\n");
72057416Smarkm    printf("%-15s %s\r\n", "?", "display help information");
72157416Smarkm    return 0;
72257416Smarkm}
72357416Smarkm
72457416Smarkmstatic void
72557416Smarkmsettogglehelp(int set)
72657416Smarkm{
72757416Smarkm    struct togglelist *c;
72857416Smarkm
72957416Smarkm    for (c = Togglelist; c->name; c++) {
73057416Smarkm	if (c->help) {
73157416Smarkm	    if (*c->help)
73257416Smarkm		printf("%-15s %s %s\r\n", c->name, set ? "enable" : "disable",
73357416Smarkm						c->help);
73457416Smarkm	    else
73557416Smarkm		printf("\r\n");
73657416Smarkm	}
73757416Smarkm    }
73857416Smarkm}
73957416Smarkm
74057416Smarkm#define	GETTOGGLE(name) (struct togglelist *) \
74157416Smarkm		genget(name, (char **) Togglelist, sizeof(struct togglelist))
74257416Smarkm
74357416Smarkmstatic int
74457416Smarkmtoggle(int argc, char *argv[])
74557416Smarkm{
74657416Smarkm    int retval = 1;
74757416Smarkm    char *name;
74857416Smarkm    struct togglelist *c;
74957416Smarkm
75057416Smarkm    if (argc < 2) {
75157416Smarkm	fprintf(stderr,
75257416Smarkm	    "Need an argument to 'toggle' command.  'toggle ?' for help.\r\n");
75357416Smarkm	return 0;
75457416Smarkm    }
75557416Smarkm    argc--;
75657416Smarkm    argv++;
75757416Smarkm    while (argc--) {
75857416Smarkm	name = *argv++;
75957416Smarkm	c = GETTOGGLE(name);
76057416Smarkm	if (Ambiguous(c)) {
76157416Smarkm	    fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\r\n",
76257416Smarkm					name);
76357416Smarkm	    return 0;
76457416Smarkm	} else if (c == 0) {
76557416Smarkm	    fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\r\n",
76657416Smarkm					name);
76757416Smarkm	    return 0;
76857416Smarkm	} else {
76957416Smarkm	    if (c->variable) {
77057416Smarkm		*c->variable = !*c->variable;		/* invert it */
77157416Smarkm		if (c->actionexplanation) {
77257416Smarkm		    printf("%s %s.\r\n", *c->variable? "Will" : "Won't",
77357416Smarkm							c->actionexplanation);
77457416Smarkm		}
77557416Smarkm	    }
77657416Smarkm	    if (c->handler) {
77757416Smarkm		retval &= (*c->handler)(-1);
77857416Smarkm	    }
77957416Smarkm	}
78057416Smarkm    }
78157416Smarkm    return retval;
78257416Smarkm}
78357416Smarkm
78457416Smarkm/*
78557416Smarkm * The following perform the "set" command.
78657416Smarkm */
78757416Smarkm
78857416Smarkmstruct termios new_tc = { 0 };
78957416Smarkm
79057416Smarkmstruct setlist {
79157416Smarkm    char *name;				/* name */
79257416Smarkm    char *help;				/* help information */
79357416Smarkm    void (*handler)();
79457416Smarkm    cc_t *charp;			/* where it is located at */
79557416Smarkm};
79657416Smarkm
79757416Smarkmstatic struct setlist Setlist[] = {
79857416Smarkm#ifdef	KLUDGELINEMODE
79957416Smarkm    { "echo", 	"character to toggle local echoing on/off", 0, &echoc },
80057416Smarkm#endif
80157416Smarkm    { "escape",	"character to escape back to telnet command mode", 0, &escape },
80257416Smarkm    { "rlogin", "rlogin escape character", 0, &rlogin },
80357416Smarkm    { "tracefile", "file to write trace information to", SetNetTrace, (cc_t *)NetTraceFile},
80457416Smarkm    { " ", "" },
80557416Smarkm    { " ", "The following need 'localchars' to be toggled true", 0, 0 },
80657416Smarkm    { "flushoutput", "character to cause an Abort Output", 0, &termFlushChar },
80757416Smarkm    { "interrupt", "character to cause an Interrupt Process", 0, &termIntChar },
80857416Smarkm    { "quit",	"character to cause an Abort process", 0, &termQuitChar },
80957416Smarkm    { "eof",	"character to cause an EOF ", 0, &termEofChar },
81057416Smarkm    { " ", "" },
81157416Smarkm    { " ", "The following are for local editing in linemode", 0, 0 },
81257416Smarkm    { "erase",	"character to use to erase a character", 0, &termEraseChar },
81357416Smarkm    { "kill",	"character to use to erase a line", 0, &termKillChar },
81457416Smarkm    { "lnext",	"character to use for literal next", 0, &termLiteralNextChar },
81557416Smarkm    { "susp",	"character to cause a Suspend Process", 0, &termSuspChar },
81657416Smarkm    { "reprint", "character to use for line reprint", 0, &termRprntChar },
81757416Smarkm    { "worderase", "character to use to erase a word", 0, &termWerasChar },
81857416Smarkm    { "start",	"character to use for XON", 0, &termStartChar },
81957416Smarkm    { "stop",	"character to use for XOFF", 0, &termStopChar },
82057416Smarkm    { "forw1",	"alternate end of line character", 0, &termForw1Char },
82157416Smarkm    { "forw2",	"alternate end of line character", 0, &termForw2Char },
82257416Smarkm    { "ayt",	"alternate AYT character", 0, &termAytChar },
82357416Smarkm    { 0 }
82457416Smarkm};
82557416Smarkm
82657416Smarkmstatic struct setlist *
82757416Smarkmgetset(char *name)
82857416Smarkm{
82957416Smarkm    return (struct setlist *)
83057416Smarkm		genget(name, (char **) Setlist, sizeof(struct setlist));
83157416Smarkm}
83257416Smarkm
83357416Smarkmvoid
83457416Smarkmset_escape_char(char *s)
83557416Smarkm{
83657416Smarkm	if (rlogin != _POSIX_VDISABLE) {
83757416Smarkm		rlogin = (s && *s) ? special(s) : _POSIX_VDISABLE;
83857416Smarkm		printf("Telnet rlogin escape character is '%s'.\r\n",
83957416Smarkm					control(rlogin));
84057416Smarkm	} else {
84157416Smarkm		escape = (s && *s) ? special(s) : _POSIX_VDISABLE;
84257416Smarkm		printf("Telnet escape character is '%s'.\r\n", control(escape));
84357416Smarkm	}
84457416Smarkm}
84557416Smarkm
84657416Smarkmstatic int
84757416Smarkmsetcmd(int argc, char *argv[])
84857416Smarkm{
84957416Smarkm    int value;
85057416Smarkm    struct setlist *ct;
85157416Smarkm    struct togglelist *c;
85257416Smarkm
85357416Smarkm    if (argc < 2 || argc > 3) {
85457416Smarkm	printf("Format is 'set Name Value'\r\n'set ?' for help.\r\n");
85557416Smarkm	return 0;
85657416Smarkm    }
85757416Smarkm    if ((argc == 2) && (isprefix(argv[1], "?") || isprefix(argv[1], "help"))) {
85857416Smarkm	for (ct = Setlist; ct->name; ct++)
85957416Smarkm	    printf("%-15s %s\r\n", ct->name, ct->help);
86057416Smarkm	printf("\r\n");
86157416Smarkm	settogglehelp(1);
86257416Smarkm	printf("%-15s %s\r\n", "?", "display help information");
86357416Smarkm	return 0;
86457416Smarkm    }
86557416Smarkm
86657416Smarkm    ct = getset(argv[1]);
86757416Smarkm    if (ct == 0) {
86857416Smarkm	c = GETTOGGLE(argv[1]);
86957416Smarkm	if (c == 0) {
87057416Smarkm	    fprintf(stderr, "'%s': unknown argument ('set ?' for help).\r\n",
87157416Smarkm			argv[1]);
87257416Smarkm	    return 0;
87357416Smarkm	} else if (Ambiguous(c)) {
87457416Smarkm	    fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\r\n",
87557416Smarkm			argv[1]);
87657416Smarkm	    return 0;
87757416Smarkm	}
87857416Smarkm	if (c->variable) {
87957416Smarkm	    if ((argc == 2) || (strcmp("on", argv[2]) == 0))
88057416Smarkm		*c->variable = 1;
88157416Smarkm	    else if (strcmp("off", argv[2]) == 0)
88257416Smarkm		*c->variable = 0;
88357416Smarkm	    else {
88457416Smarkm		printf("Format is 'set togglename [on|off]'\r\n'set ?' for help.\r\n");
88557416Smarkm		return 0;
88657416Smarkm	    }
88757416Smarkm	    if (c->actionexplanation) {
88857416Smarkm		printf("%s %s.\r\n", *c->variable? "Will" : "Won't",
88957416Smarkm							c->actionexplanation);
89057416Smarkm	    }
89157416Smarkm	}
89257416Smarkm	if (c->handler)
89357416Smarkm	    (*c->handler)(1);
89457416Smarkm    } else if (argc != 3) {
89557416Smarkm	printf("Format is 'set Name Value'\r\n'set ?' for help.\r\n");
89657416Smarkm	return 0;
89757416Smarkm    } else if (Ambiguous(ct)) {
89857416Smarkm	fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\r\n",
89957416Smarkm			argv[1]);
90057416Smarkm	return 0;
90157416Smarkm    } else if (ct->handler) {
90257416Smarkm	(*ct->handler)(argv[2]);
90357416Smarkm	printf("%s set to \"%s\".\r\n", ct->name, (char *)ct->charp);
90457416Smarkm    } else {
90557416Smarkm	if (strcmp("off", argv[2])) {
90657416Smarkm	    value = special(argv[2]);
90757416Smarkm	} else {
90857416Smarkm	    value = _POSIX_VDISABLE;
90957416Smarkm	}
91057416Smarkm	*(ct->charp) = (cc_t)value;
91157416Smarkm	printf("%s character is '%s'.\r\n", ct->name, control(*(ct->charp)));
91257416Smarkm    }
91357416Smarkm    slc_check();
91457416Smarkm    return 1;
91557416Smarkm}
91657416Smarkm
91757416Smarkmstatic int
91857416Smarkmunsetcmd(int argc, char *argv[])
91957416Smarkm{
92057416Smarkm    struct setlist *ct;
92157416Smarkm    struct togglelist *c;
92257416Smarkm    char *name;
92357416Smarkm
92457416Smarkm    if (argc < 2) {
92557416Smarkm	fprintf(stderr,
92657416Smarkm	    "Need an argument to 'unset' command.  'unset ?' for help.\r\n");
92757416Smarkm	return 0;
92857416Smarkm    }
92957416Smarkm    if (isprefix(argv[1], "?") || isprefix(argv[1], "help")) {
93057416Smarkm	for (ct = Setlist; ct->name; ct++)
93157416Smarkm	    printf("%-15s %s\r\n", ct->name, ct->help);
93257416Smarkm	printf("\r\n");
93357416Smarkm	settogglehelp(0);
93457416Smarkm	printf("%-15s %s\r\n", "?", "display help information");
93557416Smarkm	return 0;
93657416Smarkm    }
93757416Smarkm
93857416Smarkm    argc--;
93957416Smarkm    argv++;
94057416Smarkm    while (argc--) {
94157416Smarkm	name = *argv++;
94257416Smarkm	ct = getset(name);
94357416Smarkm	if (ct == 0) {
94457416Smarkm	    c = GETTOGGLE(name);
94557416Smarkm	    if (c == 0) {
94657416Smarkm		fprintf(stderr, "'%s': unknown argument ('unset ?' for help).\r\n",
94757416Smarkm			name);
94857416Smarkm		return 0;
94957416Smarkm	    } else if (Ambiguous(c)) {
95057416Smarkm		fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\r\n",
95157416Smarkm			name);
95257416Smarkm		return 0;
95357416Smarkm	    }
95457416Smarkm	    if (c->variable) {
95557416Smarkm		*c->variable = 0;
95657416Smarkm		if (c->actionexplanation) {
95757416Smarkm		    printf("%s %s.\r\n", *c->variable? "Will" : "Won't",
95857416Smarkm							c->actionexplanation);
95957416Smarkm		}
96057416Smarkm	    }
96157416Smarkm	    if (c->handler)
96257416Smarkm		(*c->handler)(0);
96357416Smarkm	} else if (Ambiguous(ct)) {
96457416Smarkm	    fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\r\n",
96557416Smarkm			name);
96657416Smarkm	    return 0;
96757416Smarkm	} else if (ct->handler) {
96857416Smarkm	    (*ct->handler)(0);
96957416Smarkm	    printf("%s reset to \"%s\".\r\n", ct->name, (char *)ct->charp);
97057416Smarkm	} else {
97157416Smarkm	    *(ct->charp) = _POSIX_VDISABLE;
97257416Smarkm	    printf("%s character is '%s'.\r\n", ct->name, control(*(ct->charp)));
97357416Smarkm	}
97457416Smarkm    }
97557416Smarkm    return 1;
97657416Smarkm}
97757416Smarkm
97857416Smarkm/*
97957416Smarkm * The following are the data structures and routines for the
98057416Smarkm * 'mode' command.
98157416Smarkm */
98257416Smarkm#ifdef	KLUDGELINEMODE
98357416Smarkm
98457416Smarkmstatic int
98557416Smarkmdokludgemode(void)
98657416Smarkm{
98757416Smarkm    kludgelinemode = 1;
98857416Smarkm    send_wont(TELOPT_LINEMODE, 1);
98957416Smarkm    send_dont(TELOPT_SGA, 1);
99057416Smarkm    send_dont(TELOPT_ECHO, 1);
99157416Smarkm    return 1;
99257416Smarkm}
99357416Smarkm#endif
99457416Smarkm
99557416Smarkmstatic int
99657416Smarkmdolinemode()
99757416Smarkm{
99857416Smarkm#ifdef	KLUDGELINEMODE
99957416Smarkm    if (kludgelinemode)
100057416Smarkm	send_dont(TELOPT_SGA, 1);
100157416Smarkm#endif
100257416Smarkm    send_will(TELOPT_LINEMODE, 1);
100357416Smarkm    send_dont(TELOPT_ECHO, 1);
100457416Smarkm    return 1;
100557416Smarkm}
100657416Smarkm
100757416Smarkmstatic int
100857416Smarkmdocharmode()
100957416Smarkm{
101057416Smarkm#ifdef	KLUDGELINEMODE
101157416Smarkm    if (kludgelinemode)
101257416Smarkm	send_do(TELOPT_SGA, 1);
101357416Smarkm    else
101457416Smarkm#endif
101557416Smarkm    send_wont(TELOPT_LINEMODE, 1);
101657416Smarkm    send_do(TELOPT_ECHO, 1);
101757416Smarkm    return 1;
101857416Smarkm}
101957416Smarkm
102057416Smarkmstatic int
102157416Smarkmdolmmode(int bit, int on)
102257416Smarkm{
102357416Smarkm    unsigned char c;
102457416Smarkm
102557416Smarkm    if (my_want_state_is_wont(TELOPT_LINEMODE)) {
102657416Smarkm	printf("?Need to have LINEMODE option enabled first.\r\n");
102757416Smarkm	printf("'mode ?' for help.\r\n");
102857416Smarkm 	return 0;
102957416Smarkm    }
103057416Smarkm
103157416Smarkm    if (on)
103257416Smarkm	c = (linemode | bit);
103357416Smarkm    else
103457416Smarkm	c = (linemode & ~bit);
103557416Smarkm    lm_mode(&c, 1, 1);
103657416Smarkm    return 1;
103757416Smarkm}
103857416Smarkm
103957416Smarkmstatic int
104057416Smarkmtn_setmode(int bit)
104157416Smarkm{
104257416Smarkm    return dolmmode(bit, 1);
104357416Smarkm}
104457416Smarkm
104557416Smarkmstatic int
104657416Smarkmtn_clearmode(int bit)
104757416Smarkm{
104857416Smarkm    return dolmmode(bit, 0);
104957416Smarkm}
105057416Smarkm
105157416Smarkmstruct modelist {
105257416Smarkm	char	*name;		/* command name */
105357416Smarkm	char	*help;		/* help string */
105457416Smarkm	int	(*handler)();	/* routine which executes command */
105557416Smarkm	int	needconnect;	/* Do we need to be connected to execute? */
105657416Smarkm	int	arg1;
105757416Smarkm};
105857416Smarkm
105957416Smarkmstatic int modehelp(void);
106057416Smarkm
106157416Smarkmstatic struct modelist ModeList[] = {
106257416Smarkm    { "character", "Disable LINEMODE option",	docharmode, 1 },
106357416Smarkm#ifdef	KLUDGELINEMODE
106457416Smarkm    { "",	"(or disable obsolete line-by-line mode)", 0 },
106557416Smarkm#endif
106657416Smarkm    { "line",	"Enable LINEMODE option",	dolinemode, 1 },
106757416Smarkm#ifdef	KLUDGELINEMODE
106857416Smarkm    { "",	"(or enable obsolete line-by-line mode)", 0 },
106957416Smarkm#endif
107057416Smarkm    { "", "", 0 },
107157416Smarkm    { "",	"These require the LINEMODE option to be enabled", 0 },
107257416Smarkm    { "isig",	"Enable signal trapping",	tn_setmode, 1, MODE_TRAPSIG },
107357416Smarkm    { "+isig",	0,				tn_setmode, 1, MODE_TRAPSIG },
107457416Smarkm    { "-isig",	"Disable signal trapping",	tn_clearmode, 1, MODE_TRAPSIG },
107557416Smarkm    { "edit",	"Enable character editing",	tn_setmode, 1, MODE_EDIT },
107657416Smarkm    { "+edit",	0,				tn_setmode, 1, MODE_EDIT },
107757416Smarkm    { "-edit",	"Disable character editing",	tn_clearmode, 1, MODE_EDIT },
107857416Smarkm    { "softtabs", "Enable tab expansion",	tn_setmode, 1, MODE_SOFT_TAB },
107957416Smarkm    { "+softtabs", 0,				tn_setmode, 1, MODE_SOFT_TAB },
1080102644Snectar    { "-softtabs", "Disable tab expansion",	tn_clearmode, 1, MODE_SOFT_TAB },
108157416Smarkm    { "litecho", "Enable literal character echo", tn_setmode, 1, MODE_LIT_ECHO },
108257416Smarkm    { "+litecho", 0,				tn_setmode, 1, MODE_LIT_ECHO },
108357416Smarkm    { "-litecho", "Disable literal character echo", tn_clearmode, 1, MODE_LIT_ECHO },
108457416Smarkm    { "help",	0,				modehelp, 0 },
108557416Smarkm#ifdef	KLUDGELINEMODE
108657416Smarkm    { "kludgeline", 0,				dokludgemode, 1 },
108757416Smarkm#endif
108857416Smarkm    { "", "", 0 },
108957416Smarkm    { "?",	"Print help information",	modehelp, 0 },
109057416Smarkm    { 0 },
109157416Smarkm};
109257416Smarkm
109357416Smarkm
109457416Smarkmstatic int
109557416Smarkmmodehelp(void)
109657416Smarkm{
109757416Smarkm    struct modelist *mt;
109857416Smarkm
109957416Smarkm    printf("format is:  'mode Mode', where 'Mode' is one of:\r\n\r\n");
110057416Smarkm    for (mt = ModeList; mt->name; mt++) {
110157416Smarkm	if (mt->help) {
110257416Smarkm	    if (*mt->help)
110357416Smarkm		printf("%-15s %s\r\n", mt->name, mt->help);
110457416Smarkm	    else
110557416Smarkm		printf("\r\n");
110657416Smarkm	}
110757416Smarkm    }
110857416Smarkm    return 0;
110957416Smarkm}
111057416Smarkm
111157416Smarkm#define	GETMODECMD(name) (struct modelist *) \
111257416Smarkm		genget(name, (char **) ModeList, sizeof(struct modelist))
111357416Smarkm
111457416Smarkmstatic int
111557416Smarkmmodecmd(int argc, char **argv)
111657416Smarkm{
111757416Smarkm    struct modelist *mt;
111857416Smarkm
111957416Smarkm    if (argc != 2) {
112057416Smarkm	printf("'mode' command requires an argument\r\n");
112157416Smarkm	printf("'mode ?' for help.\r\n");
112257416Smarkm    } else if ((mt = GETMODECMD(argv[1])) == 0) {
112357416Smarkm	fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\r\n", argv[1]);
112457416Smarkm    } else if (Ambiguous(mt)) {
112557416Smarkm	fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\r\n", argv[1]);
112657416Smarkm    } else if (mt->needconnect && !connected) {
112757416Smarkm	printf("?Need to be connected first.\r\n");
112857416Smarkm	printf("'mode ?' for help.\r\n");
112957416Smarkm    } else if (mt->handler) {
113057416Smarkm	return (*mt->handler)(mt->arg1);
113157416Smarkm    }
113257416Smarkm    return 0;
113357416Smarkm}
113457416Smarkm
113557416Smarkm/*
113657416Smarkm * The following data structures and routines implement the
113757416Smarkm * "display" command.
113857416Smarkm */
113957416Smarkm
114057416Smarkmstatic int
114157416Smarkmdisplay(int argc, char *argv[])
114257416Smarkm{
114357416Smarkm    struct togglelist *tl;
114457416Smarkm    struct setlist *sl;
114557416Smarkm
114657416Smarkm#define	dotog(tl)	if (tl->variable && tl->actionexplanation) { \
114757416Smarkm			    if (*tl->variable) { \
114857416Smarkm				printf("will"); \
114957416Smarkm			    } else { \
115057416Smarkm				printf("won't"); \
115157416Smarkm			    } \
115257416Smarkm			    printf(" %s.\r\n", tl->actionexplanation); \
115357416Smarkm			}
115457416Smarkm
115557416Smarkm#define	doset(sl)   if (sl->name && *sl->name != ' ') { \
115657416Smarkm			if (sl->handler == 0) \
115757416Smarkm			    printf("%-15s [%s]\r\n", sl->name, control(*sl->charp)); \
115857416Smarkm			else \
115957416Smarkm			    printf("%-15s \"%s\"\r\n", sl->name, (char *)sl->charp); \
116057416Smarkm		    }
116157416Smarkm
116257416Smarkm    if (argc == 1) {
116357416Smarkm	for (tl = Togglelist; tl->name; tl++) {
116457416Smarkm	    dotog(tl);
116557416Smarkm	}
116657416Smarkm	printf("\r\n");
116757416Smarkm	for (sl = Setlist; sl->name; sl++) {
116857416Smarkm	    doset(sl);
116957416Smarkm	}
117057416Smarkm    } else {
117157416Smarkm	int i;
117257416Smarkm
117357416Smarkm	for (i = 1; i < argc; i++) {
117457416Smarkm	    sl = getset(argv[i]);
117557416Smarkm	    tl = GETTOGGLE(argv[i]);
117657416Smarkm	    if (Ambiguous(sl) || Ambiguous(tl)) {
117757416Smarkm		printf("?Ambiguous argument '%s'.\r\n", argv[i]);
117857416Smarkm		return 0;
117957416Smarkm	    } else if (!sl && !tl) {
118057416Smarkm		printf("?Unknown argument '%s'.\r\n", argv[i]);
118157416Smarkm		return 0;
118257416Smarkm	    } else {
118357416Smarkm		if (tl) {
118457416Smarkm		    dotog(tl);
118557416Smarkm		}
118657416Smarkm		if (sl) {
118757416Smarkm		    doset(sl);
118857416Smarkm		}
118957416Smarkm	    }
119057416Smarkm	}
119157416Smarkm    }
119257416Smarkm/*@*/optionstatus();
119357416Smarkm#if	defined(ENCRYPTION)
119457416Smarkm    EncryptStatus();
119557416Smarkm#endif
119657416Smarkm    return 1;
119757416Smarkm#undef	doset
119857416Smarkm#undef	dotog
119957416Smarkm}
120057416Smarkm
120157416Smarkm/*
120257416Smarkm * The following are the data structures, and many of the routines,
120357416Smarkm * relating to command processing.
120457416Smarkm */
120557416Smarkm
120657416Smarkm/*
120757416Smarkm * Set the escape character.
120857416Smarkm */
120957416Smarkmstatic int
121057416Smarkmsetescape(int argc, char *argv[])
121157416Smarkm{
121257416Smarkm	char *arg;
121357416Smarkm	char buf[50];
121457416Smarkm
121557416Smarkm	printf(
121657416Smarkm	    "Deprecated usage - please use 'set escape%s%s' in the future.\r\n",
121757416Smarkm				(argc > 2)? " ":"", (argc > 2)? argv[1]: "");
121857416Smarkm	if (argc > 2)
121957416Smarkm		arg = argv[1];
122057416Smarkm	else {
122157416Smarkm		printf("new escape character: ");
122257416Smarkm		fgets(buf, sizeof(buf), stdin);
122357416Smarkm		arg = buf;
122457416Smarkm	}
122557416Smarkm	if (arg[0] != '\0')
122657416Smarkm		escape = arg[0];
122757416Smarkm	printf("Escape character is '%s'.\r\n", control(escape));
122857416Smarkm
122957416Smarkm	fflush(stdout);
123057416Smarkm	return 1;
123157416Smarkm}
123257416Smarkm
123357416Smarkmstatic int
123457416Smarkmtogcrmod()
123557416Smarkm{
123657416Smarkm    crmod = !crmod;
123757416Smarkm    printf("Deprecated usage - please use 'toggle crmod' in the future.\r\n");
123857416Smarkm    printf("%s map carriage return on output.\r\n", crmod ? "Will" : "Won't");
123957416Smarkm    fflush(stdout);
124057416Smarkm    return 1;
124157416Smarkm}
124257416Smarkm
124357416Smarkmstatic int
124457416Smarkmtelnetsuspend()
124557416Smarkm{
124657416Smarkm#ifdef	SIGTSTP
124757416Smarkm    setcommandmode();
124857416Smarkm    {
124957416Smarkm	long oldrows, oldcols, newrows, newcols, err;
125057416Smarkm
125157416Smarkm	err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0;
125257416Smarkm	kill(0, SIGTSTP);
125357416Smarkm	/*
125457416Smarkm	 * If we didn't get the window size before the SUSPEND, but we
125557416Smarkm	 * can get them now (?), then send the NAWS to make sure that
125657416Smarkm	 * we are set up for the right window size.
125757416Smarkm	 */
125857416Smarkm	if (TerminalWindowSize(&newrows, &newcols) && connected &&
125957416Smarkm	    (err || ((oldrows != newrows) || (oldcols != newcols)))) {
126057416Smarkm		sendnaws();
126157416Smarkm	}
126257416Smarkm    }
126357416Smarkm    /* reget parameters in case they were changed */
126457416Smarkm    TerminalSaveState();
126557416Smarkm    setconnmode(0);
126657416Smarkm#else
126757416Smarkm    printf("Suspend is not supported.  Try the '!' command instead\r\n");
126857416Smarkm#endif
126957416Smarkm    return 1;
127057416Smarkm}
127157416Smarkm
127257416Smarkmstatic int
127357416Smarkmshell(int argc, char **argv)
127457416Smarkm{
127557416Smarkm    long oldrows, oldcols, newrows, newcols, err;
127657416Smarkm
127757416Smarkm    setcommandmode();
127857416Smarkm
127957416Smarkm    err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0;
128057416Smarkm    switch(fork()) {
128157416Smarkm    case -1:
128257416Smarkm	perror("Fork failed\r\n");
128357416Smarkm	break;
128457416Smarkm
128557416Smarkm    case 0:
128657416Smarkm	{
128757416Smarkm	    /*
128857416Smarkm	     * Fire up the shell in the child.
128957416Smarkm	     */
129057416Smarkm	    char *shellp, *shellname;
129157416Smarkm
129257416Smarkm	    shellp = getenv("SHELL");
129357416Smarkm	    if (shellp == NULL)
129457416Smarkm		shellp = "/bin/sh";
129557416Smarkm	    if ((shellname = strrchr(shellp, '/')) == 0)
129657416Smarkm		shellname = shellp;
129757416Smarkm	    else
129857416Smarkm		shellname++;
129957416Smarkm	    if (argc > 1)
1300178825Sdfr		execl(shellp, shellname, "-c", &saveline[1], NULL);
130157416Smarkm	    else
1302178825Sdfr		execl(shellp, shellname, NULL);
130357416Smarkm	    perror("Execl");
130457416Smarkm	    _exit(1);
130557416Smarkm	}
130657416Smarkm    default:
130757416Smarkm	    wait((int *)0);	/* Wait for the shell to complete */
130857416Smarkm
130957416Smarkm	    if (TerminalWindowSize(&newrows, &newcols) && connected &&
131057416Smarkm		(err || ((oldrows != newrows) || (oldcols != newcols)))) {
131157416Smarkm		    sendnaws();
131257416Smarkm	    }
131357416Smarkm	    break;
131457416Smarkm    }
131557416Smarkm    return 1;
131657416Smarkm}
131757416Smarkm
131857416Smarkmstatic int
131957416Smarkmbye(int argc, char **argv)
132057416Smarkm{
132157416Smarkm    if (connected) {
132257416Smarkm	shutdown(net, 2);
132357416Smarkm	printf("Connection closed.\r\n");
132457416Smarkm	NetClose(net);
132557416Smarkm	connected = 0;
132657416Smarkm	resettermname = 1;
132757416Smarkm#if	defined(AUTHENTICATION) || defined(ENCRYPTION)
132857416Smarkm	auth_encrypt_connect(connected);
132957416Smarkm#endif
133057416Smarkm	/* reset options */
133157416Smarkm	tninit();
133257416Smarkm    }
1333233294Sstas    if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0))
133457416Smarkm	longjmp(toplevel, 1);
133557416Smarkm    return 0;	/* NOTREACHED */
133657416Smarkm}
133757416Smarkm
133857416Smarkmint
133957416Smarkmquit(void)
134057416Smarkm{
134157416Smarkm	call(bye, "bye", "fromquit", 0);
134257416Smarkm	Exit(0);
134357416Smarkm	return 0; /*NOTREACHED*/
134457416Smarkm}
134557416Smarkm
134657416Smarkmstatic int
134757416Smarkmlogout()
134857416Smarkm{
134957416Smarkm	send_do(TELOPT_LOGOUT, 1);
135057416Smarkm	netflush();
135157416Smarkm	return 1;
135257416Smarkm}
135357416Smarkm
135457416Smarkm
135557416Smarkm/*
135657416Smarkm * The SLC command.
135757416Smarkm */
135857416Smarkm
135957416Smarkmstruct slclist {
136057416Smarkm	char	*name;
136157416Smarkm	char	*help;
136257416Smarkm	void	(*handler)();
136357416Smarkm	int	arg;
136457416Smarkm};
136557416Smarkm
136657416Smarkmstatic void slc_help(void);
136757416Smarkm
136857416Smarkmstruct slclist SlcList[] = {
136957416Smarkm    { "export",	"Use local special character definitions",
137057416Smarkm						slc_mode_export,	0 },
137157416Smarkm    { "import",	"Use remote special character definitions",
137257416Smarkm						slc_mode_import,	1 },
137357416Smarkm    { "check",	"Verify remote special character definitions",
137457416Smarkm						slc_mode_import,	0 },
137557416Smarkm    { "help",	0,				slc_help,		0 },
137657416Smarkm    { "?",	"Print help information",	slc_help,		0 },
137757416Smarkm    { 0 },
137857416Smarkm};
137957416Smarkm
138057416Smarkmstatic void
138157416Smarkmslc_help(void)
138257416Smarkm{
138357416Smarkm    struct slclist *c;
138457416Smarkm
138557416Smarkm    for (c = SlcList; c->name; c++) {
138657416Smarkm	if (c->help) {
138757416Smarkm	    if (*c->help)
138857416Smarkm		printf("%-15s %s\r\n", c->name, c->help);
138957416Smarkm	    else
139057416Smarkm		printf("\r\n");
139157416Smarkm	}
139257416Smarkm    }
139357416Smarkm}
139457416Smarkm
139557416Smarkmstatic struct slclist *
139657416Smarkmgetslc(char *name)
139757416Smarkm{
139857416Smarkm    return (struct slclist *)
139957416Smarkm		genget(name, (char **) SlcList, sizeof(struct slclist));
140057416Smarkm}
140157416Smarkm
140257416Smarkmstatic int
140357416Smarkmslccmd(int argc, char **argv)
140457416Smarkm{
140557416Smarkm    struct slclist *c;
140657416Smarkm
140757416Smarkm    if (argc != 2) {
140857416Smarkm	fprintf(stderr,
140957416Smarkm	    "Need an argument to 'slc' command.  'slc ?' for help.\r\n");
141057416Smarkm	return 0;
141157416Smarkm    }
141257416Smarkm    c = getslc(argv[1]);
141357416Smarkm    if (c == 0) {
141457416Smarkm	fprintf(stderr, "'%s': unknown argument ('slc ?' for help).\r\n",
141557416Smarkm    				argv[1]);
141657416Smarkm	return 0;
141757416Smarkm    }
141857416Smarkm    if (Ambiguous(c)) {
141957416Smarkm	fprintf(stderr, "'%s': ambiguous argument ('slc ?' for help).\r\n",
142057416Smarkm    				argv[1]);
142157416Smarkm	return 0;
142257416Smarkm    }
142357416Smarkm    (*c->handler)(c->arg);
142457416Smarkm    slcstate();
142557416Smarkm    return 1;
142657416Smarkm}
142757416Smarkm
142857416Smarkm/*
142957416Smarkm * The ENVIRON command.
143057416Smarkm */
143157416Smarkm
143257416Smarkmstruct envlist {
143357416Smarkm	char	*name;
143457416Smarkm	char	*help;
143557416Smarkm	void	(*handler)();
143657416Smarkm	int	narg;
143757416Smarkm};
143857416Smarkm
143957416Smarkmstatic void env_help (void);
144057416Smarkm
144157416Smarkmstruct envlist EnvList[] = {
144257416Smarkm    { "define",	"Define an environment variable",
144357416Smarkm						(void (*)())env_define,	2 },
144457416Smarkm    { "undefine", "Undefine an environment variable",
144557416Smarkm						env_undefine,	1 },
144657416Smarkm    { "export",	"Mark an environment variable for automatic export",
144757416Smarkm						env_export,	1 },
144857416Smarkm    { "unexport", "Don't mark an environment variable for automatic export",
144957416Smarkm						env_unexport,	1 },
145057416Smarkm    { "send",	"Send an environment variable", env_send,	1 },
145157416Smarkm    { "list",	"List the current environment variables",
145257416Smarkm						env_list,	0 },
145357416Smarkm    { "help",	0,				env_help,		0 },
145457416Smarkm    { "?",	"Print help information",	env_help,		0 },
145557416Smarkm    { 0 },
145657416Smarkm};
145757416Smarkm
145857416Smarkmstatic void
145957416Smarkmenv_help()
146057416Smarkm{
146157416Smarkm    struct envlist *c;
146257416Smarkm
146357416Smarkm    for (c = EnvList; c->name; c++) {
146457416Smarkm	if (c->help) {
146557416Smarkm	    if (*c->help)
146657416Smarkm		printf("%-15s %s\r\n", c->name, c->help);
146757416Smarkm	    else
146857416Smarkm		printf("\r\n");
146957416Smarkm	}
147057416Smarkm    }
147157416Smarkm}
147257416Smarkm
147357416Smarkmstatic struct envlist *
147457416Smarkmgetenvcmd(char *name)
147557416Smarkm{
147657416Smarkm    return (struct envlist *)
147757416Smarkm		genget(name, (char **) EnvList, sizeof(struct envlist));
147857416Smarkm}
147957416Smarkm
148057416Smarkmstatic int
148157416Smarkmenv_cmd(int argc, char **argv)
148257416Smarkm{
148357416Smarkm    struct envlist *c;
148457416Smarkm
148557416Smarkm    if (argc < 2) {
148657416Smarkm	fprintf(stderr,
148757416Smarkm	    "Need an argument to 'environ' command.  'environ ?' for help.\r\n");
148857416Smarkm	return 0;
148957416Smarkm    }
149057416Smarkm    c = getenvcmd(argv[1]);
149157416Smarkm    if (c == 0) {
149257416Smarkm	fprintf(stderr, "'%s': unknown argument ('environ ?' for help).\r\n",
149357416Smarkm    				argv[1]);
149457416Smarkm	return 0;
149557416Smarkm    }
149657416Smarkm    if (Ambiguous(c)) {
149757416Smarkm	fprintf(stderr, "'%s': ambiguous argument ('environ ?' for help).\r\n",
149857416Smarkm    				argv[1]);
149957416Smarkm	return 0;
150057416Smarkm    }
150157416Smarkm    if (c->narg + 2 != argc) {
150257416Smarkm	fprintf(stderr,
150357416Smarkm	    "Need %s%d argument%s to 'environ %s' command.  'environ ?' for help.\r\n",
150457416Smarkm		c->narg < argc + 2 ? "only " : "",
150557416Smarkm		c->narg, c->narg == 1 ? "" : "s", c->name);
150657416Smarkm	return 0;
150757416Smarkm    }
150857416Smarkm    (*c->handler)(argv[2], argv[3]);
150957416Smarkm    return 1;
151057416Smarkm}
151157416Smarkm
151257416Smarkmstruct env_lst {
151357416Smarkm	struct env_lst *next;	/* pointer to next structure */
151457416Smarkm	struct env_lst *prev;	/* pointer to previous structure */
151557416Smarkm	unsigned char *var;	/* pointer to variable name */
151657416Smarkm	unsigned char *value;	/* pointer to variable value */
151757416Smarkm	int export;		/* 1 -> export with default list of variables */
151857416Smarkm	int welldefined;	/* A well defined variable */
151957416Smarkm};
152057416Smarkm
152157416Smarkmstruct env_lst envlisthead;
152257416Smarkm
152357416Smarkmstruct env_lst *
152457416Smarkmenv_find(unsigned char *var)
152557416Smarkm{
152657416Smarkm	struct env_lst *ep;
152757416Smarkm
152857416Smarkm	for (ep = envlisthead.next; ep; ep = ep->next) {
152957416Smarkm		if (strcmp((char *)ep->var, (char *)var) == 0)
153057416Smarkm			return(ep);
153157416Smarkm	}
153257416Smarkm	return(NULL);
153357416Smarkm}
153457416Smarkm
1535233294Sstas#if !HAVE_DECL_ENVIRON
1536233294Sstasextern char **environ;
153757416Smarkm#endif
153857416Smarkm
153957416Smarkmvoid
154057416Smarkmenv_init(void)
154157416Smarkm{
154257416Smarkm	char **epp, *cp;
154357416Smarkm	struct env_lst *ep;
154457416Smarkm
154557416Smarkm	for (epp = environ; *epp; epp++) {
154657416Smarkm		if ((cp = strchr(*epp, '='))) {
154757416Smarkm			*cp = '\0';
154857416Smarkm			ep = env_define((unsigned char *)*epp,
154957416Smarkm					(unsigned char *)cp+1);
155057416Smarkm			ep->export = 0;
155157416Smarkm			*cp = '=';
155257416Smarkm		}
155357416Smarkm	}
155457416Smarkm	/*
155557416Smarkm	 * Special case for DISPLAY variable.  If it is ":0.0" or
155657416Smarkm	 * "unix:0.0", we have to get rid of "unix" and insert our
155757416Smarkm	 * hostname.
155857416Smarkm	 */
155990926Snectar	if ((ep = env_find((unsigned char*)"DISPLAY"))
156057416Smarkm	    && (*ep->value == ':'
156157416Smarkm	    || strncmp((char *)ep->value, "unix:", 5) == 0)) {
156257416Smarkm		char hbuf[256+1];
156357416Smarkm		char *cp2 = strchr((char *)ep->value, ':');
1564178825Sdfr		int error;
156557416Smarkm
156657416Smarkm		/* XXX - should be k_gethostname? */
156757416Smarkm		gethostname(hbuf, 256);
156857416Smarkm		hbuf[256] = '\0';
156957416Smarkm
157057416Smarkm		/* If this is not the full name, try to get it via DNS */
157157416Smarkm		if (strchr(hbuf, '.') == 0) {
157257416Smarkm			struct addrinfo hints, *ai, *a;
157357416Smarkm
157457416Smarkm			memset (&hints, 0, sizeof(hints));
157557416Smarkm			hints.ai_flags = AI_CANONNAME;
157657416Smarkm
157757416Smarkm			error = getaddrinfo (hbuf, NULL, &hints, &ai);
157857416Smarkm			if (error == 0) {
157957416Smarkm				for (a = ai; a != NULL; a = a->ai_next)
158057416Smarkm					if (a->ai_canonname != NULL) {
158157416Smarkm						strlcpy (hbuf,
158257416Smarkm							 ai->ai_canonname,
158357416Smarkm							 256);
158457416Smarkm						break;
158557416Smarkm					}
158657416Smarkm				freeaddrinfo (ai);
158757416Smarkm			}
158857416Smarkm		}
158957416Smarkm
1590178825Sdfr		error = asprintf (&cp, "%s%s", hbuf, cp2);
1591178825Sdfr		if (error != -1) {
1592178825Sdfr		    free (ep->value);
1593178825Sdfr		    ep->value = (unsigned char *)cp;
1594178825Sdfr		}
159557416Smarkm	}
159657416Smarkm	/*
159757416Smarkm	 * If USER is not defined, but LOGNAME is, then add
159857416Smarkm	 * USER with the value from LOGNAME.  By default, we
159957416Smarkm	 * don't export the USER variable.
160057416Smarkm	 */
1601233294Sstas	if ((env_find((unsigned char*)"USER") == NULL) &&
160290926Snectar	    (ep = env_find((unsigned char*)"LOGNAME"))) {
160357416Smarkm		env_define((unsigned char *)"USER", ep->value);
160457416Smarkm		env_unexport((unsigned char *)"USER");
160557416Smarkm	}
160657416Smarkm	env_export((unsigned char *)"DISPLAY");
160757416Smarkm	env_export((unsigned char *)"PRINTER");
160857416Smarkm	env_export((unsigned char *)"XAUTHORITY");
160957416Smarkm}
161057416Smarkm
161157416Smarkmstruct env_lst *
161257416Smarkmenv_define(unsigned char *var, unsigned char *value)
161357416Smarkm{
161457416Smarkm	struct env_lst *ep;
161557416Smarkm
161657416Smarkm	if ((ep = env_find(var))) {
161757416Smarkm		if (ep->var)
161857416Smarkm			free(ep->var);
161957416Smarkm		if (ep->value)
162057416Smarkm			free(ep->value);
162157416Smarkm	} else {
162257416Smarkm		ep = (struct env_lst *)malloc(sizeof(struct env_lst));
162357416Smarkm		ep->next = envlisthead.next;
162457416Smarkm		envlisthead.next = ep;
162557416Smarkm		ep->prev = &envlisthead;
162657416Smarkm		if (ep->next)
162757416Smarkm			ep->next->prev = ep;
162857416Smarkm	}
162957416Smarkm	ep->welldefined = opt_welldefined((char *)var);
163057416Smarkm	ep->export = 1;
163157416Smarkm	ep->var = (unsigned char *)strdup((char *)var);
163257416Smarkm	ep->value = (unsigned char *)strdup((char *)value);
163357416Smarkm	return(ep);
163457416Smarkm}
163557416Smarkm
163657416Smarkmvoid
163757416Smarkmenv_undefine(unsigned char *var)
163857416Smarkm{
163957416Smarkm	struct env_lst *ep;
164057416Smarkm
164157416Smarkm	if ((ep = env_find(var))) {
164257416Smarkm		ep->prev->next = ep->next;
164357416Smarkm		if (ep->next)
164457416Smarkm			ep->next->prev = ep->prev;
164557416Smarkm		if (ep->var)
164657416Smarkm			free(ep->var);
164757416Smarkm		if (ep->value)
164857416Smarkm			free(ep->value);
164957416Smarkm		free(ep);
165057416Smarkm	}
165157416Smarkm}
165257416Smarkm
165357416Smarkmvoid
165457416Smarkmenv_export(unsigned char *var)
165557416Smarkm{
165657416Smarkm	struct env_lst *ep;
165757416Smarkm
165857416Smarkm	if ((ep = env_find(var)))
165957416Smarkm		ep->export = 1;
166057416Smarkm}
166157416Smarkm
166257416Smarkmvoid
166357416Smarkmenv_unexport(unsigned char *var)
166457416Smarkm{
166557416Smarkm	struct env_lst *ep;
166657416Smarkm
166757416Smarkm	if ((ep = env_find(var)))
166857416Smarkm		ep->export = 0;
166957416Smarkm}
167057416Smarkm
167157416Smarkmvoid
167257416Smarkmenv_send(unsigned char *var)
167357416Smarkm{
167457416Smarkm	struct env_lst *ep;
167557416Smarkm
167657416Smarkm	if (my_state_is_wont(TELOPT_NEW_ENVIRON)
167757416Smarkm#ifdef	OLD_ENVIRON
167857416Smarkm	    && my_state_is_wont(TELOPT_OLD_ENVIRON)
167957416Smarkm#endif
168057416Smarkm		) {
168157416Smarkm		fprintf(stderr,
168257416Smarkm		    "Cannot send '%s': Telnet ENVIRON option not enabled\r\n",
168357416Smarkm									var);
168457416Smarkm		return;
168557416Smarkm	}
168657416Smarkm	ep = env_find(var);
168757416Smarkm	if (ep == 0) {
168857416Smarkm		fprintf(stderr, "Cannot send '%s': variable not defined\r\n",
168957416Smarkm									var);
169057416Smarkm		return;
169157416Smarkm	}
169257416Smarkm	env_opt_start_info();
169357416Smarkm	env_opt_add(ep->var);
169457416Smarkm	env_opt_end(0);
169557416Smarkm}
169657416Smarkm
169757416Smarkmvoid
169857416Smarkmenv_list(void)
169957416Smarkm{
170057416Smarkm	struct env_lst *ep;
170157416Smarkm
170257416Smarkm	for (ep = envlisthead.next; ep; ep = ep->next) {
170357416Smarkm		printf("%c %-20s %s\r\n", ep->export ? '*' : ' ',
170457416Smarkm					ep->var, ep->value);
170557416Smarkm	}
170657416Smarkm}
170757416Smarkm
170857416Smarkmunsigned char *
170957416Smarkmenv_default(int init, int welldefined)
171057416Smarkm{
171157416Smarkm	static struct env_lst *nep = NULL;
171257416Smarkm
171357416Smarkm	if (init) {
171457416Smarkm		nep = &envlisthead;
171557416Smarkm		return NULL;
171657416Smarkm	}
171757416Smarkm	if (nep) {
171857416Smarkm		while ((nep = nep->next)) {
171957416Smarkm			if (nep->export && (nep->welldefined == welldefined))
172057416Smarkm				return(nep->var);
172157416Smarkm		}
172257416Smarkm	}
172357416Smarkm	return(NULL);
172457416Smarkm}
172557416Smarkm
172657416Smarkmunsigned char *
172757416Smarkmenv_getvalue(unsigned char *var)
172857416Smarkm{
172957416Smarkm	struct env_lst *ep;
173057416Smarkm
173157416Smarkm	if ((ep = env_find(var)))
173257416Smarkm		return(ep->value);
173357416Smarkm	return(NULL);
173457416Smarkm}
173557416Smarkm
173657416Smarkm
173757416Smarkm#if	defined(AUTHENTICATION)
173857416Smarkm/*
173957416Smarkm * The AUTHENTICATE command.
174057416Smarkm */
174157416Smarkm
174257416Smarkmstruct authlist {
174357416Smarkm	char	*name;
174457416Smarkm	char	*help;
174557416Smarkm	int	(*handler)();
174657416Smarkm	int	narg;
174757416Smarkm};
174857416Smarkm
174957416Smarkmstatic int
175057416Smarkm	auth_help (void);
175157416Smarkm
175257416Smarkmstruct authlist AuthList[] = {
175357416Smarkm    { "status",	"Display current status of authentication information",
175457416Smarkm						auth_status,	0 },
175557416Smarkm    { "disable", "Disable an authentication type ('auth disable ?' for more)",
175657416Smarkm						auth_disable,	1 },
175757416Smarkm    { "enable", "Enable an authentication type ('auth enable ?' for more)",
175857416Smarkm						auth_enable,	1 },
175957416Smarkm    { "help",	0,				auth_help,		0 },
176057416Smarkm    { "?",	"Print help information",	auth_help,		0 },
176157416Smarkm    { 0 },
176257416Smarkm};
176357416Smarkm
176457416Smarkmstatic int
176557416Smarkmauth_help()
176657416Smarkm{
176757416Smarkm    struct authlist *c;
176857416Smarkm
176957416Smarkm    for (c = AuthList; c->name; c++) {
177057416Smarkm	if (c->help) {
177157416Smarkm	    if (*c->help)
177257416Smarkm		printf("%-15s %s\r\n", c->name, c->help);
177357416Smarkm	    else
177457416Smarkm		printf("\r\n");
177557416Smarkm	}
177657416Smarkm    }
177757416Smarkm    return 0;
177857416Smarkm}
177957416Smarkm
178057416Smarkmstatic int
178157416Smarkmauth_cmd(int argc, char **argv)
178257416Smarkm{
178357416Smarkm    struct authlist *c;
178457416Smarkm
178557416Smarkm    if (argc < 2) {
178657416Smarkm	fprintf(stderr,
178757416Smarkm	    "Need an argument to 'auth' command.  'auth ?' for help.\r\n");
178857416Smarkm	return 0;
178957416Smarkm    }
179057416Smarkm
179157416Smarkm    c = (struct authlist *)
179257416Smarkm		genget(argv[1], (char **) AuthList, sizeof(struct authlist));
179357416Smarkm    if (c == 0) {
179457416Smarkm	fprintf(stderr, "'%s': unknown argument ('auth ?' for help).\r\n",
179557416Smarkm    				argv[1]);
179657416Smarkm	return 0;
179757416Smarkm    }
179857416Smarkm    if (Ambiguous(c)) {
179957416Smarkm	fprintf(stderr, "'%s': ambiguous argument ('auth ?' for help).\r\n",
180057416Smarkm    				argv[1]);
180157416Smarkm	return 0;
180257416Smarkm    }
180357416Smarkm    if (c->narg + 2 != argc) {
180457416Smarkm	fprintf(stderr,
180557416Smarkm	    "Need %s%d argument%s to 'auth %s' command.  'auth ?' for help.\r\n",
180657416Smarkm		c->narg < argc + 2 ? "only " : "",
180757416Smarkm		c->narg, c->narg == 1 ? "" : "s", c->name);
180857416Smarkm	return 0;
180957416Smarkm    }
181057416Smarkm    return((*c->handler)(argv[2], argv[3]));
181157416Smarkm}
181257416Smarkm#endif
181357416Smarkm
181457416Smarkm
181557416Smarkm#if	defined(ENCRYPTION)
181657416Smarkm/*
181757416Smarkm * The ENCRYPT command.
181857416Smarkm */
181957416Smarkm
182057416Smarkmstruct encryptlist {
182157416Smarkm	char	*name;
182257416Smarkm	char	*help;
182357416Smarkm	int	(*handler)();
182457416Smarkm	int	needconnect;
182557416Smarkm	int	minarg;
182657416Smarkm	int	maxarg;
182757416Smarkm};
182857416Smarkm
182957416Smarkmstatic int
183057416Smarkm	EncryptHelp (void);
183157416Smarkm
183257416Smarkmstruct encryptlist EncryptList[] = {
183357416Smarkm    { "enable", "Enable encryption. ('encrypt enable ?' for more)",
183457416Smarkm						EncryptEnable, 1, 1, 2 },
183557416Smarkm    { "disable", "Disable encryption. ('encrypt enable ?' for more)",
183657416Smarkm						EncryptDisable, 0, 1, 2 },
183757416Smarkm    { "type", "Set encryptiong type. ('encrypt type ?' for more)",
183857416Smarkm						EncryptType, 0, 1, 1 },
183957416Smarkm    { "start", "Start encryption. ('encrypt start ?' for more)",
184057416Smarkm						EncryptStart, 1, 0, 1 },
184157416Smarkm    { "stop", "Stop encryption. ('encrypt stop ?' for more)",
184257416Smarkm						EncryptStop, 1, 0, 1 },
184357416Smarkm    { "input", "Start encrypting the input stream",
184457416Smarkm						EncryptStartInput, 1, 0, 0 },
184557416Smarkm    { "-input", "Stop encrypting the input stream",
184657416Smarkm						EncryptStopInput, 1, 0, 0 },
184757416Smarkm    { "output", "Start encrypting the output stream",
184857416Smarkm						EncryptStartOutput, 1, 0, 0 },
184957416Smarkm    { "-output", "Stop encrypting the output stream",
185057416Smarkm						EncryptStopOutput, 1, 0, 0 },
185157416Smarkm
185257416Smarkm    { "status",	"Display current status of authentication information",
185357416Smarkm						EncryptStatus,	0, 0, 0 },
185457416Smarkm    { "help",	0,				EncryptHelp,	0, 0, 0 },
185557416Smarkm    { "?",	"Print help information",	EncryptHelp,	0, 0, 0 },
185657416Smarkm    { 0 },
185757416Smarkm};
185857416Smarkm
185957416Smarkmstatic int
186057416SmarkmEncryptHelp()
186157416Smarkm{
186257416Smarkm    struct encryptlist *c;
186357416Smarkm
186457416Smarkm    for (c = EncryptList; c->name; c++) {
186557416Smarkm	if (c->help) {
186657416Smarkm	    if (*c->help)
186757416Smarkm		printf("%-15s %s\r\n", c->name, c->help);
186857416Smarkm	    else
186957416Smarkm		printf("\r\n");
187057416Smarkm	}
187157416Smarkm    }
187257416Smarkm    return 0;
187357416Smarkm}
187457416Smarkm
187557416Smarkmstatic int
187657416Smarkmencrypt_cmd(int argc, char **argv)
187757416Smarkm{
187857416Smarkm    struct encryptlist *c;
187957416Smarkm
188057416Smarkm    c = (struct encryptlist *)
188157416Smarkm		genget(argv[1], (char **) EncryptList, sizeof(struct encryptlist));
188257416Smarkm    if (c == 0) {
188357416Smarkm        fprintf(stderr, "'%s': unknown argument ('encrypt ?' for help).\r\n",
188457416Smarkm    				argv[1]);
188557416Smarkm        return 0;
188657416Smarkm    }
188757416Smarkm    if (Ambiguous(c)) {
188857416Smarkm        fprintf(stderr, "'%s': ambiguous argument ('encrypt ?' for help).\r\n",
188957416Smarkm    				argv[1]);
189057416Smarkm        return 0;
189157416Smarkm    }
189257416Smarkm    argc -= 2;
189357416Smarkm    if (argc < c->minarg || argc > c->maxarg) {
189457416Smarkm	if (c->minarg == c->maxarg) {
189557416Smarkm	    fprintf(stderr, "Need %s%d argument%s ",
189657416Smarkm		c->minarg < argc ? "only " : "", c->minarg,
189757416Smarkm		c->minarg == 1 ? "" : "s");
189857416Smarkm	} else {
189957416Smarkm	    fprintf(stderr, "Need %s%d-%d arguments ",
190057416Smarkm		c->maxarg < argc ? "only " : "", c->minarg, c->maxarg);
190157416Smarkm	}
190257416Smarkm	fprintf(stderr, "to 'encrypt %s' command.  'encrypt ?' for help.\r\n",
190357416Smarkm		c->name);
190457416Smarkm	return 0;
190557416Smarkm    }
190657416Smarkm    if (c->needconnect && !connected) {
190757416Smarkm	if (!(argc && (isprefix(argv[2], "help") || isprefix(argv[2], "?")))) {
190857416Smarkm	    printf("?Need to be connected first.\r\n");
190957416Smarkm	    return 0;
191057416Smarkm	}
191157416Smarkm    }
191257416Smarkm    return ((*c->handler)(argc > 0 ? argv[2] : 0,
191357416Smarkm			argc > 1 ? argv[3] : 0,
191457416Smarkm			argc > 2 ? argv[4] : 0));
191557416Smarkm}
191657416Smarkm#endif
191757416Smarkm
191857416Smarkm
191957416Smarkm/*
192057416Smarkm * Print status about the connection.
192157416Smarkm */
192257416Smarkm
192357416Smarkmstatic int
192457416Smarkmstatus(int argc, char **argv)
192557416Smarkm{
192657416Smarkm    if (connected) {
192757416Smarkm	printf("Connected to %s.\r\n", hostname);
192857416Smarkm	if ((argc < 2) || strcmp(argv[1], "notmuch")) {
192957416Smarkm	    int mode = getconnmode();
193057416Smarkm
193157416Smarkm	    if (my_want_state_is_will(TELOPT_LINEMODE)) {
193257416Smarkm		printf("Operating with LINEMODE option\r\n");
193357416Smarkm		printf("%s line editing\r\n", (mode&MODE_EDIT) ? "Local" : "No");
193457416Smarkm		printf("%s catching of signals\r\n",
193557416Smarkm					(mode&MODE_TRAPSIG) ? "Local" : "No");
193657416Smarkm		slcstate();
193757416Smarkm#ifdef	KLUDGELINEMODE
193857416Smarkm	    } else if (kludgelinemode && my_want_state_is_dont(TELOPT_SGA)) {
193957416Smarkm		printf("Operating in obsolete linemode\r\n");
194057416Smarkm#endif
194157416Smarkm	    } else {
194257416Smarkm		printf("Operating in single character mode\r\n");
194357416Smarkm		if (localchars)
194457416Smarkm		    printf("Catching signals locally\r\n");
194557416Smarkm	    }
194657416Smarkm	    printf("%s character echo\r\n", (mode&MODE_ECHO) ? "Local" : "Remote");
194757416Smarkm	    if (my_want_state_is_will(TELOPT_LFLOW))
194857416Smarkm		printf("%s flow control\r\n", (mode&MODE_FLOW) ? "Local" : "No");
194957416Smarkm#if	defined(ENCRYPTION)
195057416Smarkm	    encrypt_display();
195157416Smarkm#endif
195257416Smarkm	}
195357416Smarkm    } else {
195457416Smarkm	printf("No connection.\r\n");
195557416Smarkm    }
195657416Smarkm    printf("Escape character is '%s'.\r\n", control(escape));
195757416Smarkm    fflush(stdout);
195857416Smarkm    return 1;
195957416Smarkm}
196057416Smarkm
196157416Smarkm#ifdef	SIGINFO
196257416Smarkm/*
196357416Smarkm * Function that gets called when SIGINFO is received.
196457416Smarkm */
196578527SassarRETSIGTYPE
196657416Smarkmayt_status(int ignore)
196757416Smarkm{
196857416Smarkm    call(status, "status", "notmuch", 0);
196957416Smarkm}
197057416Smarkm#endif
197157416Smarkm
197257416Smarkmstatic Command *getcmd(char *name);
197357416Smarkm
197457416Smarkmstatic void
197557416Smarkmcmdrc(char *m1, char *m2)
197657416Smarkm{
197757416Smarkm    static char rcname[128];
197857416Smarkm    Command *c;
197957416Smarkm    FILE *rcfile;
198057416Smarkm    int gotmachine = 0;
198157416Smarkm    int l1 = strlen(m1);
198257416Smarkm    int l2 = strlen(m2);
198357416Smarkm    char m1save[64];
198457416Smarkm
198557416Smarkm    if (skiprc)
198657416Smarkm	return;
198757416Smarkm
198857416Smarkm    strlcpy(m1save, m1, sizeof(m1save));
198957416Smarkm    m1 = m1save;
199057416Smarkm
199157416Smarkm    if (rcname[0] == 0) {
199257416Smarkm	char *home = getenv("HOME");
199357416Smarkm
199457416Smarkm	snprintf (rcname, sizeof(rcname), "%s/.telnetrc",
199557416Smarkm		  home ? home : "");
199657416Smarkm    }
199757416Smarkm
199857416Smarkm    if ((rcfile = fopen(rcname, "r")) == 0) {
199957416Smarkm	return;
200057416Smarkm    }
200157416Smarkm
200257416Smarkm    for (;;) {
200357416Smarkm	if (fgets(line, sizeof(line), rcfile) == NULL)
200457416Smarkm	    break;
200557416Smarkm	if (line[0] == 0)
200657416Smarkm	    break;
200757416Smarkm	if (line[0] == '#')
200857416Smarkm	    continue;
200957416Smarkm	if (gotmachine) {
2010178825Sdfr	    if (!isspace((unsigned char)line[0]))
201157416Smarkm		gotmachine = 0;
201257416Smarkm	}
201357416Smarkm	if (gotmachine == 0) {
2014178825Sdfr	    if (isspace((unsigned char)line[0]))
201557416Smarkm		continue;
201657416Smarkm	    if (strncasecmp(line, m1, l1) == 0)
201757416Smarkm		strncpy(line, &line[l1], sizeof(line) - l1);
201857416Smarkm	    else if (strncasecmp(line, m2, l2) == 0)
201957416Smarkm		strncpy(line, &line[l2], sizeof(line) - l2);
202057416Smarkm	    else if (strncasecmp(line, "DEFAULT", 7) == 0)
202157416Smarkm		strncpy(line, &line[7], sizeof(line) - 7);
202257416Smarkm	    else
202357416Smarkm		continue;
202457416Smarkm	    if (line[0] != ' ' && line[0] != '\t' && line[0] != '\n')
202557416Smarkm		continue;
202657416Smarkm	    gotmachine = 1;
202757416Smarkm	}
202857416Smarkm	makeargv();
202957416Smarkm	if (margv[0] == 0)
203057416Smarkm	    continue;
203157416Smarkm	c = getcmd(margv[0]);
203257416Smarkm	if (Ambiguous(c)) {
203357416Smarkm	    printf("?Ambiguous command: %s\r\n", margv[0]);
203457416Smarkm	    continue;
203557416Smarkm	}
203657416Smarkm	if (c == 0) {
203757416Smarkm	    printf("?Invalid command: %s\r\n", margv[0]);
203857416Smarkm	    continue;
203957416Smarkm	}
204057416Smarkm	/*
204157416Smarkm	 * This should never happen...
204257416Smarkm	 */
204357416Smarkm	if (c->needconnect && !connected) {
204457416Smarkm	    printf("?Need to be connected first for %s.\r\n", margv[0]);
204557416Smarkm	    continue;
204657416Smarkm	}
204757416Smarkm	(*c->handler)(margc, margv);
204857416Smarkm    }
204957416Smarkm    fclose(rcfile);
205057416Smarkm}
205157416Smarkm
205257416Smarkmint
205357416Smarkmtn(int argc, char **argv)
205457416Smarkm{
205557416Smarkm    struct servent *sp = 0;
205657416Smarkm    char *cmd, *hostp = 0, *portp = 0;
205757416Smarkm    char *user = 0;
205857416Smarkm    int port = 0;
205957416Smarkm
206057416Smarkm    /* clear the socket address prior to use */
206157416Smarkm
206257416Smarkm    if (connected) {
206357416Smarkm	printf("?Already connected to %s\r\n", hostname);
206457416Smarkm	return 0;
206557416Smarkm    }
206657416Smarkm    if (argc < 2) {
206757416Smarkm	strlcpy(line, "open ", sizeof(line));
206857416Smarkm	printf("(to) ");
206957416Smarkm	fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin);
207057416Smarkm	makeargv();
207157416Smarkm	argc = margc;
207257416Smarkm	argv = margv;
207357416Smarkm    }
207457416Smarkm    cmd = *argv;
207557416Smarkm    --argc; ++argv;
207657416Smarkm    while (argc) {
207757416Smarkm	if (strcmp(*argv, "help") == 0 || isprefix(*argv, "?"))
207857416Smarkm	    goto usage;
207957416Smarkm	if (strcmp(*argv, "-l") == 0) {
208057416Smarkm	    --argc; ++argv;
208157416Smarkm	    if (argc == 0)
208257416Smarkm		goto usage;
208357416Smarkm	    user = strdup(*argv++);
208457416Smarkm	    --argc;
208557416Smarkm	    continue;
208657416Smarkm	}
208757416Smarkm	if (strcmp(*argv, "-a") == 0) {
208857416Smarkm	    --argc; ++argv;
208957416Smarkm	    autologin = 1;
209057416Smarkm	    continue;
209157416Smarkm	}
209257416Smarkm	if (hostp == 0) {
209357416Smarkm	    hostp = *argv++;
209457416Smarkm	    --argc;
209557416Smarkm	    continue;
209657416Smarkm	}
209757416Smarkm	if (portp == 0) {
209857416Smarkm	    portp = *argv++;
209957416Smarkm	    --argc;
210057416Smarkm	    continue;
210157416Smarkm	}
210257416Smarkm    usage:
210357416Smarkm	printf("usage: %s [-l user] [-a] host-name [port]\r\n", cmd);
210457416Smarkm	return 0;
210557416Smarkm    }
210657416Smarkm    if (hostp == 0)
210757416Smarkm	goto usage;
210857416Smarkm
210972445Sassar    strlcpy (_hostname, hostp, sizeof(_hostname));
211078527Sassar    hostp = _hostname;
211172445Sassar    if (hostp[0] == '@' || hostp[0] == '!') {
211272445Sassar	char *p;
211372445Sassar	hostname = NULL;
211472445Sassar	for (p = hostp + 1; *p; p++) {
211572445Sassar	    if (*p == ',' || *p == '@')
211672445Sassar		hostname = p;
211772445Sassar	}
211872445Sassar	if (hostname == NULL) {
211972445Sassar	    fprintf(stderr, "%s: bad source route specification\n", hostp);
212072445Sassar	    return 0;
212172445Sassar	}
212272445Sassar	*hostname++ = '\0';
212372445Sassar    } else
212472445Sassar	hostname = hostp;
212572445Sassar
212657416Smarkm    if (portp) {
212757416Smarkm	if (*portp == '-') {
212857416Smarkm	    portp++;
212957416Smarkm	    telnetport = 1;
213057416Smarkm	} else
213157416Smarkm	    telnetport = 0;
213257416Smarkm	port = atoi(portp);
213357416Smarkm	if (port == 0) {
213457416Smarkm	    sp = roken_getservbyname(portp, "tcp");
213557416Smarkm	    if (sp)
213657416Smarkm		port = sp->s_port;
213757416Smarkm	    else {
213857416Smarkm		printf("%s: bad port number\r\n", portp);
213957416Smarkm		return 0;
214057416Smarkm	    }
214157416Smarkm	} else {
214257416Smarkm	    port = htons(port);
214357416Smarkm	}
214457416Smarkm    } else {
214557416Smarkm	if (sp == 0) {
214657416Smarkm	    sp = roken_getservbyname("telnet", "tcp");
214757416Smarkm	    if (sp == 0) {
214857416Smarkm		fprintf(stderr, "telnet: tcp/telnet: unknown service\r\n");
214957416Smarkm		return 0;
215057416Smarkm	    }
215157416Smarkm	    port = sp->s_port;
215257416Smarkm	}
215357416Smarkm	telnetport = 1;
215457416Smarkm    }
215557416Smarkm
215657416Smarkm    {
215757416Smarkm	struct addrinfo *ai, *a, hints;
215857416Smarkm	int error;
215957416Smarkm	char portstr[NI_MAXSERV];
216057416Smarkm
216157416Smarkm	memset (&hints, 0, sizeof(hints));
216257416Smarkm	hints.ai_socktype = SOCK_STREAM;
216357416Smarkm	hints.ai_protocol = IPPROTO_TCP;
216457416Smarkm	hints.ai_flags    = AI_CANONNAME;
216557416Smarkm
216657416Smarkm	snprintf (portstr, sizeof(portstr), "%u", ntohs(port));
216757416Smarkm
216872445Sassar	error = getaddrinfo (hostname, portstr, &hints, &ai);
216957416Smarkm	if (error) {
217072445Sassar	    fprintf (stderr, "%s: %s\r\n", hostname, gai_strerror (error));
217157416Smarkm	    return 0;
217257416Smarkm	}
217357416Smarkm
217457416Smarkm	for (a = ai; a != NULL && connected == 0; a = a->ai_next) {
217557416Smarkm	    char addrstr[256];
217657416Smarkm
217757416Smarkm	    if (a->ai_canonname != NULL)
217857416Smarkm		strlcpy (_hostname, a->ai_canonname, sizeof(_hostname));
217957416Smarkm
218057416Smarkm	    if (getnameinfo (a->ai_addr, a->ai_addrlen,
218157416Smarkm			     addrstr, sizeof(addrstr),
218257416Smarkm			     NULL, 0, NI_NUMERICHOST) != 0)
218357416Smarkm		strlcpy (addrstr, "unknown address", sizeof(addrstr));
2184233294Sstas
218557416Smarkm	    printf("Trying %s...\r\n", addrstr);
218657416Smarkm
218757416Smarkm	    net = socket (a->ai_family, a->ai_socktype, a->ai_protocol);
218857416Smarkm	    if (net < 0) {
218972445Sassar		warn ("socket");
219057416Smarkm		continue;
219157416Smarkm	    }
219272445Sassar
219357416Smarkm#if	defined(IP_OPTIONS) && defined(IPPROTO_IP) && defined(HAVE_SETSOCKOPT)
219472445Sassar	if (hostp[0] == '@' || hostp[0] == '!') {
219572445Sassar	    char *srp = 0;
219672445Sassar	    int srlen;
219772445Sassar	    int proto, opt;
219872445Sassar
219972445Sassar	    if ((srlen = sourceroute(a, hostp, &srp, &proto, &opt)) < 0) {
220072445Sassar		(void) NetClose(net);
220172445Sassar		net = -1;
220272445Sassar		continue;
220372445Sassar	    }
220472445Sassar	    if (srp && setsockopt(net, proto, opt, srp, srlen) < 0)
220572445Sassar		perror("setsockopt (source route)");
220672445Sassar	}
220757416Smarkm#endif
220872445Sassar
220957416Smarkm#if	defined(IPPROTO_IP) && defined(IP_TOS)
221057419Smarkm	    if (a->ai_family == AF_INET) {
221157416Smarkm# if	defined(HAVE_GETTOSBYNAME)
221257416Smarkm		struct tosent *tp;
221357416Smarkm		if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
221457416Smarkm		    tos = tp->t_tos;
221557416Smarkm# endif
221657416Smarkm		if (tos < 0)
221757416Smarkm		    tos = 020;	/* Low Delay bit */
221857416Smarkm		if (tos
221957416Smarkm		    && (setsockopt(net, IPPROTO_IP, IP_TOS,
222057416Smarkm				   (void *)&tos, sizeof(int)) < 0)
222157416Smarkm		    && (errno != ENOPROTOOPT))
222257416Smarkm		    perror("telnet: setsockopt (IP_TOS) (ignored)");
222357416Smarkm	    }
222457416Smarkm#endif	/* defined(IPPROTO_IP) && defined(IP_TOS) */
222557416Smarkm	    if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) {
222657416Smarkm		perror("setsockopt (SO_DEBUG)");
222757416Smarkm	    }
222857416Smarkm
222957416Smarkm	    if (connect (net, a->ai_addr, a->ai_addrlen) < 0) {
223057416Smarkm		fprintf (stderr, "telnet: connect to address %s: %s\n",
223157416Smarkm			 addrstr, strerror(errno));
223257416Smarkm		NetClose(net);
223357416Smarkm		if (a->ai_next != NULL) {
223457416Smarkm		    continue;
223557416Smarkm		} else {
223657416Smarkm		    freeaddrinfo (ai);
223757416Smarkm		    return 0;
223857416Smarkm		}
223957416Smarkm	    }
224057416Smarkm	    ++connected;
224157416Smarkm#if	defined(AUTHENTICATION) || defined(ENCRYPTION)
224257416Smarkm	    auth_encrypt_connect(connected);
224357416Smarkm#endif
224457416Smarkm	}
224572445Sassar	freeaddrinfo (ai);
224672445Sassar	if (connected == 0)
224772445Sassar	    return 0;
224857416Smarkm    }
224957416Smarkm    cmdrc(hostp, hostname);
2250102644Snectar    set_forward_options();
225157416Smarkm    if (autologin && user == NULL)
225257416Smarkm	user = (char *)get_default_username ();
225357416Smarkm    if (user) {
225457416Smarkm	env_define((unsigned char *)"USER", (unsigned char *)user);
225557416Smarkm	env_export((unsigned char *)"USER");
225657416Smarkm    }
225757416Smarkm    call(status, "status", "notmuch", 0);
225857416Smarkm    if (setjmp(peerdied) == 0)
225957416Smarkm	my_telnet((char *)user);
226057416Smarkm    NetClose(net);
226157416Smarkm    ExitString("Connection closed by foreign host.\r\n",1);
226257416Smarkm    /*NOTREACHED*/
226357416Smarkm    return 0;
226457416Smarkm}
226557416Smarkm
226657416Smarkm#define HELPINDENT ((int)sizeof ("connect"))
226757416Smarkm
226857416Smarkmstatic char
226957416Smarkm	openhelp[] =	"connect to a site",
227057416Smarkm	closehelp[] =	"close current connection",
227157416Smarkm	logouthelp[] =	"forcibly logout remote user and close the connection",
227257416Smarkm	quithelp[] =	"exit telnet",
227357416Smarkm	statushelp[] =	"print status information",
227457416Smarkm	helphelp[] =	"print help information",
227557416Smarkm	sendhelp[] =	"transmit special characters ('send ?' for more)",
227657416Smarkm	sethelp[] = 	"set operating parameters ('set ?' for more)",
227757416Smarkm	unsethelp[] = 	"unset operating parameters ('unset ?' for more)",
227857416Smarkm	togglestring[] ="toggle operating parameters ('toggle ?' for more)",
227957416Smarkm	slchelp[] =	"change state of special charaters ('slc ?' for more)",
228057416Smarkm	displayhelp[] =	"display operating parameters",
228157416Smarkm#if	defined(AUTHENTICATION)
228257416Smarkm	authhelp[] =	"turn on (off) authentication ('auth ?' for more)",
228357416Smarkm#endif
228457416Smarkm#if	defined(ENCRYPTION)
228557416Smarkm	encrypthelp[] =	"turn on (off) encryption ('encrypt ?' for more)",
228657416Smarkm#endif
228757416Smarkm	zhelp[] =	"suspend telnet",
228857416Smarkm	shellhelp[] =	"invoke a subshell",
228957416Smarkm	envhelp[] =	"change environment variables ('environ ?' for more)",
229057416Smarkm	modestring[] = "try to enter line or character mode ('mode ?' for more)";
229157416Smarkm
229257416Smarkmstatic int help(int argc, char **argv);
229357416Smarkm
229457416Smarkmstatic Command cmdtab[] = {
229557416Smarkm	{ "close",	closehelp,	bye,		1 },
229657416Smarkm	{ "logout",	logouthelp,	logout,		1 },
229757416Smarkm	{ "display",	displayhelp,	display,	0 },
229857416Smarkm	{ "mode",	modestring,	modecmd,	0 },
229957416Smarkm	{ "open",	openhelp,	tn,		0 },
230057416Smarkm	{ "quit",	quithelp,	quit,		0 },
230157416Smarkm	{ "send",	sendhelp,	sendcmd,	0 },
230257416Smarkm	{ "set",	sethelp,	setcmd,		0 },
230357416Smarkm	{ "unset",	unsethelp,	unsetcmd,	0 },
230457416Smarkm	{ "status",	statushelp,	status,		0 },
230557416Smarkm	{ "toggle",	togglestring,	toggle,		0 },
230657416Smarkm	{ "slc",	slchelp,	slccmd,		0 },
230757416Smarkm#if	defined(AUTHENTICATION)
230857416Smarkm	{ "auth",	authhelp,	auth_cmd,	0 },
230957416Smarkm#endif
231057416Smarkm#if	defined(ENCRYPTION)
231157416Smarkm	{ "encrypt",	encrypthelp,	encrypt_cmd,	0 },
231257416Smarkm#endif
231357416Smarkm	{ "z",		zhelp,		telnetsuspend,	0 },
231457416Smarkm	{ "!",		shellhelp,	shell,		0 },
231557416Smarkm	{ "environ",	envhelp,	env_cmd,	0 },
231657416Smarkm	{ "?",		helphelp,	help,		0 },
231757416Smarkm	{ 0,            0,              0,              0 }
231857416Smarkm};
231957416Smarkm
232057416Smarkmstatic char	crmodhelp[] =	"deprecated command -- use 'toggle crmod' instead";
232157416Smarkmstatic char	escapehelp[] =	"deprecated command -- use 'set escape' instead";
232257416Smarkm
232357416Smarkmstatic Command cmdtab2[] = {
232457416Smarkm	{ "help",	0,		help,		0 },
232557416Smarkm	{ "escape",	escapehelp,	setescape,	0 },
232657416Smarkm	{ "crmod",	crmodhelp,	togcrmod,	0 },
232757416Smarkm	{ 0,            0,		0, 		0 }
232857416Smarkm};
232957416Smarkm
233057416Smarkm
233157416Smarkm/*
233257416Smarkm * Call routine with argc, argv set from args (terminated by 0).
233357416Smarkm */
233457416Smarkm
233557416Smarkmstatic int
233657416Smarkmcall(intrtn_t routine, ...)
233757416Smarkm{
233857416Smarkm    va_list ap;
233957416Smarkm    char *args[100];
234057416Smarkm    int argno = 0;
234157416Smarkm
234257416Smarkm    va_start(ap, routine);
234357416Smarkm    while ((args[argno++] = va_arg(ap, char *)) != 0);
234457416Smarkm    va_end(ap);
234557416Smarkm    return (*routine)(argno-1, args);
234657416Smarkm}
234757416Smarkm
234857416Smarkm
234957416Smarkmstatic Command
235057416Smarkm*getcmd(char *name)
235157416Smarkm{
235257416Smarkm    Command *cm;
235357416Smarkm
235457416Smarkm    if ((cm = (Command *) genget(name, (char **) cmdtab, sizeof(Command))))
235557416Smarkm	return cm;
235657416Smarkm    return (Command *) genget(name, (char **) cmdtab2, sizeof(Command));
235757416Smarkm}
235857416Smarkm
235957416Smarkmvoid
236057416Smarkmcommand(int top, char *tbuf, int cnt)
236157416Smarkm{
236257416Smarkm    Command *c;
236357416Smarkm
236457416Smarkm    setcommandmode();
236557416Smarkm    if (!top) {
236657416Smarkm	putchar('\n');
236757416Smarkm    } else {
236857416Smarkm	signal(SIGINT, SIG_DFL);
236957416Smarkm	signal(SIGQUIT, SIG_DFL);
237057416Smarkm    }
237157416Smarkm    for (;;) {
237257416Smarkm	if (rlogin == _POSIX_VDISABLE)
237357416Smarkm		printf("%s> ", prompt);
237457416Smarkm	if (tbuf) {
237557416Smarkm	    char *cp;
237657416Smarkm	    cp = line;
237757416Smarkm	    while (cnt > 0 && (*cp++ = *tbuf++) != '\n')
237857416Smarkm		cnt--;
237957416Smarkm	    tbuf = 0;
238057416Smarkm	    if (cp == line || *--cp != '\n' || cp == line)
238157416Smarkm		goto getline;
238257416Smarkm	    *cp = '\0';
238357416Smarkm	    if (rlogin == _POSIX_VDISABLE)
238457416Smarkm		printf("%s\r\n", line);
238557416Smarkm	} else {
238657416Smarkm	getline:
238757416Smarkm	    if (rlogin != _POSIX_VDISABLE)
238857416Smarkm		printf("%s> ", prompt);
238957416Smarkm	    if (fgets(line, sizeof(line), stdin) == NULL) {
239057416Smarkm		if (feof(stdin) || ferror(stdin)) {
239157416Smarkm		    quit();
239257416Smarkm		    /*NOTREACHED*/
239357416Smarkm		}
239457416Smarkm		break;
239557416Smarkm	    }
239657416Smarkm	}
239757416Smarkm	if (line[0] == 0)
239857416Smarkm	    break;
239957416Smarkm	makeargv();
240057416Smarkm	if (margv[0] == 0) {
240157416Smarkm	    break;
240257416Smarkm	}
240357416Smarkm	c = getcmd(margv[0]);
240457416Smarkm	if (Ambiguous(c)) {
240557416Smarkm	    printf("?Ambiguous command\r\n");
240657416Smarkm	    continue;
240757416Smarkm	}
240857416Smarkm	if (c == 0) {
240957416Smarkm	    printf("?Invalid command\r\n");
241057416Smarkm	    continue;
241157416Smarkm	}
241257416Smarkm	if (c->needconnect && !connected) {
241357416Smarkm	    printf("?Need to be connected first.\r\n");
241457416Smarkm	    continue;
241557416Smarkm	}
241657416Smarkm	if ((*c->handler)(margc, margv)) {
241757416Smarkm	    break;
241857416Smarkm	}
241957416Smarkm    }
242057416Smarkm    if (!top) {
242157416Smarkm	if (!connected) {
242257416Smarkm	    longjmp(toplevel, 1);
242357416Smarkm	    /*NOTREACHED*/
242457416Smarkm	}
242557416Smarkm	setconnmode(0);
242657416Smarkm    }
242757416Smarkm}
242857416Smarkm
242957416Smarkm/*
243057416Smarkm * Help command.
243157416Smarkm */
243257416Smarkmstatic int
243357416Smarkmhelp(int argc, char **argv)
243457416Smarkm{
243557416Smarkm	Command *c;
243657416Smarkm
243757416Smarkm	if (argc == 1) {
243857416Smarkm		printf("Commands may be abbreviated.  Commands are:\r\n\r\n");
243957416Smarkm		for (c = cmdtab; c->name; c++)
244057416Smarkm			if (c->help) {
244157416Smarkm				printf("%-*s\t%s\r\n", HELPINDENT, c->name,
244257416Smarkm								    c->help);
244357416Smarkm			}
244457416Smarkm		return 0;
244557416Smarkm	}
244657416Smarkm	while (--argc > 0) {
244757416Smarkm		char *arg;
244857416Smarkm		arg = *++argv;
244957416Smarkm		c = getcmd(arg);
245057416Smarkm		if (Ambiguous(c))
245157416Smarkm			printf("?Ambiguous help command %s\r\n", arg);
245257416Smarkm		else if (c == (Command *)0)
245357416Smarkm			printf("?Invalid help command %s\r\n", arg);
245457416Smarkm		else
245557416Smarkm			printf("%s\r\n", c->help);
245657416Smarkm	}
245757416Smarkm	return 0;
245857416Smarkm}
245957416Smarkm
246057416Smarkm
246157416Smarkm#if	defined(IP_OPTIONS) && defined(IPPROTO_IP)
246257416Smarkm
246357416Smarkm/*
246457416Smarkm * Source route is handed in as
246572445Sassar *	[!]@hop1@hop2...@dst
246657416Smarkm *
246772445Sassar * If the leading ! is present, it is a strict source route, otherwise it is
246872445Sassar * assmed to be a loose source route.  Note that leading ! is effective
246972445Sassar * only for IPv4 case.
247072445Sassar *
247157416Smarkm * We fill in the source route option as
247257416Smarkm *	hop1,hop2,hop3...dest
247357416Smarkm * and return a pointer to hop1, which will
247457416Smarkm * be the address to connect() to.
247557416Smarkm *
247657416Smarkm * Arguments:
247772445Sassar *	ai:	The address (by struct addrinfo) for the final destination.
247857416Smarkm *
247972445Sassar *	arg:	Pointer to route list to decipher
248057416Smarkm *
248172445Sassar *	cpp: 	Pointer to a pointer, so that sourceroute() can return
248272445Sassar *		the address of result buffer (statically alloc'ed).
248372445Sassar *
248472445Sassar *	protop/optp:
248572445Sassar *		Pointer to an integer.  The pointed variable
248657416Smarkm *	lenp:	pointer to an integer that contains the
248757416Smarkm *		length of *cpp if *cpp != NULL.
248857416Smarkm *
248957416Smarkm * Return values:
249057416Smarkm *
249172445Sassar *	Returns the length of the option pointed to by *cpp.  If the
249257416Smarkm *	return value is -1, there was a syntax error in the
249372445Sassar *	option, either arg contained unknown characters or too many hosts,
249472445Sassar *	or hostname cannot be resolved.
249557416Smarkm *
249672445Sassar *	The caller needs to pass return value (len), *cpp, *protop and *optp
249772445Sassar *	to setsockopt(2).
249857416Smarkm *
249972445Sassar *	*cpp:	Points to the result buffer.  The region is statically
250072445Sassar *		allocated by the function.
250157416Smarkm *
250272445Sassar *	*protop:
250372445Sassar *		protocol # to be passed to setsockopt(2).
250472445Sassar *
250572445Sassar *	*optp:	option # to be passed to setsockopt(2).
250672445Sassar *
250757416Smarkm */
250872445Sassarint
250972445Sassarsourceroute(struct addrinfo *ai,
251072445Sassar	    char *arg,
251172445Sassar	    char **cpp,
251272445Sassar	    int *protop,
251372445Sassar	    int *optp)
251457416Smarkm{
2515102644Snectar	char *cp, *cp2, *lsrp = NULL, *lsrep = NULL;
251672445Sassar	struct addrinfo hints, *res;
251772445Sassar	int len, error;
251872445Sassar	struct sockaddr_in *sin;
251972445Sassar	register char c;
252057416Smarkm	static char lsr[44];
252172445Sassar#ifdef INET6
2522102644Snectar	struct cmsghdr *cmsg = NULL;
252372445Sassar	struct sockaddr_in6 *sin6;
252472445Sassar	static char rhbuf[1024];
252572445Sassar#endif
252657416Smarkm
252757416Smarkm	/*
252872445Sassar	 * Verify the arguments.
252957416Smarkm	 */
253072445Sassar	if (cpp == NULL)
253172445Sassar		return -1;
253257416Smarkm
253357416Smarkm	cp = arg;
253457416Smarkm
253572445Sassar	*cpp = NULL;
253672445Sassar	switch (ai->ai_family) {
253772445Sassar	case AF_INET:
253872445Sassar		lsrp = lsr;
253972445Sassar		lsrep = lsrp + sizeof(lsr);
254072445Sassar
254172445Sassar		/*
254272445Sassar		 * Next, decide whether we have a loose source
254372445Sassar		 * route or a strict source route, and fill in
254472445Sassar		 * the begining of the option.
254572445Sassar		 */
254672445Sassar		if (*cp == '!') {
254772445Sassar			cp++;
254872445Sassar			*lsrp++ = IPOPT_SSRR;
254972445Sassar		} else
255072445Sassar			*lsrp++ = IPOPT_LSRR;
255172445Sassar		if (*cp != '@')
255272445Sassar			return -1;
255372445Sassar		lsrp++;		/* skip over length, we'll fill it in later */
255472445Sassar		*lsrp++ = 4;
255557416Smarkm		cp++;
255672445Sassar		*protop = IPPROTO_IP;
255772445Sassar		*optp = IP_OPTIONS;
255872445Sassar		break;
255972445Sassar#ifdef INET6
256072445Sassar	case AF_INET6:
256172445Sassar/* this needs to be updated for rfc2292bis */
256272445Sassar#ifdef IPV6_PKTOPTIONS
256372445Sassar		cmsg = inet6_rthdr_init(rhbuf, IPV6_RTHDR_TYPE_0);
256472445Sassar		if (*cp != '@')
256572445Sassar			return -1;
256672445Sassar		cp++;
256772445Sassar		*protop = IPPROTO_IPV6;
256872445Sassar		*optp = IPV6_PKTOPTIONS;
256972445Sassar		break;
257072445Sassar#else
257172445Sassar		return -1;
257272445Sassar#endif
257372445Sassar#endif
257472445Sassar	default:
257572445Sassar		return -1;
257672445Sassar	}
257757416Smarkm
257872445Sassar	memset(&hints, 0, sizeof(hints));
257972445Sassar	hints.ai_family = ai->ai_family;
258072445Sassar	hints.ai_socktype = SOCK_STREAM;
258157416Smarkm
258257416Smarkm	for (c = 0;;) {
258357416Smarkm		if (c == ':')
258457416Smarkm			cp2 = 0;
258572445Sassar		else for (cp2 = cp; (c = *cp2) != '\0'; cp2++) {
258657416Smarkm			if (c == ',') {
258757416Smarkm				*cp2++ = '\0';
258857416Smarkm				if (*cp2 == '@')
258957416Smarkm					cp2++;
259057416Smarkm			} else if (c == '@') {
259157416Smarkm				*cp2++ = '\0';
259272445Sassar			}
259372445Sassar#if 0	/*colon conflicts with IPv6 address*/
259472445Sassar			else if (c == ':') {
259557416Smarkm				*cp2++ = '\0';
259672445Sassar			}
259772445Sassar#endif
259872445Sassar			else
259957416Smarkm				continue;
260057416Smarkm			break;
260157416Smarkm		}
260257416Smarkm		if (!c)
260357416Smarkm			cp2 = 0;
260457416Smarkm
260572445Sassar		error = getaddrinfo(cp, NULL, &hints, &res);
260672445Sassar		if (error) {
260772445Sassar			fprintf(stderr, "%s: %s\n", cp, gai_strerror(error));
260872445Sassar			return -1;
260957416Smarkm		}
261072445Sassar		if (ai->ai_family != res->ai_family) {
261172445Sassar			freeaddrinfo(res);
261272445Sassar			return -1;
261372445Sassar		}
261472445Sassar		if (ai->ai_family == AF_INET) {
261572445Sassar			/*
261672445Sassar			 * Check to make sure there is space for address
261772445Sassar			 */
261872445Sassar			if (lsrp + 4 > lsrep) {
261972445Sassar				freeaddrinfo(res);
262072445Sassar				return -1;
262172445Sassar			}
262272445Sassar			sin = (struct sockaddr_in *)res->ai_addr;
262372445Sassar			memcpy(lsrp, &sin->sin_addr, sizeof(struct in_addr));
262472445Sassar			lsrp += sizeof(struct in_addr);
262572445Sassar		}
262672445Sassar#ifdef INET6
262772445Sassar		else if (ai->ai_family == AF_INET6) {
262872445Sassar			sin6 = (struct sockaddr_in6 *)res->ai_addr;
262972445Sassar			inet6_rthdr_add(cmsg, &sin6->sin6_addr,
263072445Sassar				IPV6_RTHDR_LOOSE);
263172445Sassar		}
263272445Sassar#endif
263372445Sassar		else {
263472445Sassar			freeaddrinfo(res);
263572445Sassar			return -1;
263672445Sassar		}
263772445Sassar		freeaddrinfo(res);
263857416Smarkm		if (cp2)
263957416Smarkm			cp = cp2;
264057416Smarkm		else
264157416Smarkm			break;
264272445Sassar	}
264372445Sassar	if (ai->ai_family == AF_INET) {
264472445Sassar		/* record the last hop */
264557416Smarkm		if (lsrp + 4 > lsrep)
264672445Sassar			return -1;
264772445Sassar		sin = (struct sockaddr_in *)ai->ai_addr;
264872445Sassar		memcpy(lsrp, &sin->sin_addr, sizeof(struct in_addr));
264972445Sassar		lsrp += sizeof(struct in_addr);
265072445Sassar#ifndef	sysV88
265172445Sassar		lsr[IPOPT_OLEN] = lsrp - lsr;
265272445Sassar		if (lsr[IPOPT_OLEN] <= 7 || lsr[IPOPT_OLEN] > 40)
265372445Sassar			return -1;
265472445Sassar		*lsrp++ = IPOPT_NOP;	/*32bit word align*/
265572445Sassar		len = lsrp - lsr;
265672445Sassar		*cpp = lsr;
265772445Sassar#else
265872445Sassar		ipopt.io_len = lsrp - lsr;
265972445Sassar		if (ipopt.io_len <= 5)	/*is 3 better?*/
266072445Sassar			return -1;
266172445Sassar		*cpp = (char 8)&ipopt;
266272445Sassar#endif
266357416Smarkm	}
266472445Sassar#ifdef INET6
266572445Sassar	else if (ai->ai_family == AF_INET6) {
266672445Sassar		inet6_rthdr_lasthop(cmsg, IPV6_RTHDR_LOOSE);
266772445Sassar		len = cmsg->cmsg_len;
266872445Sassar		*cpp = rhbuf;
266957416Smarkm	}
267072445Sassar#endif
267172445Sassar	else
267272445Sassar		return -1;
267372445Sassar	return len;
267457416Smarkm}
267557416Smarkm#endif
2676