commands.c revision 178825
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
36178825SdfrRCSID("$Id: commands.c 16224 2005-10-22 17:17:44Z lha $");
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
45657416Smarkm#if defined(KRB4) && defined(HAVE_KRB_DISABLE_DEBUG)
45757416Smarkm#include <krb.h>
45857416Smarkm
45957416Smarkmstatic int
46057416Smarkmtogkrbdebug(void)
46157416Smarkm{
46257416Smarkm    if(krb_debug)
46357416Smarkm	krb_enable_debug();
46457416Smarkm    else
46557416Smarkm	krb_disable_debug();
46657416Smarkm    return 1;
46757416Smarkm}
46857416Smarkm#endif
46957416Smarkm
47057416Smarkmstatic int
47157416Smarkmtogcrlf()
47257416Smarkm{
47357416Smarkm    if (crlf) {
47457416Smarkm	printf("Will send carriage returns as telnet <CR><LF>.\r\n");
47557416Smarkm    } else {
47657416Smarkm	printf("Will send carriage returns as telnet <CR><NUL>.\r\n");
47757416Smarkm    }
47857416Smarkm    return 1;
47957416Smarkm}
48057416Smarkm
48157416Smarkmint binmode;
48257416Smarkm
48357416Smarkmstatic int
48457416Smarkmtogbinary(int val)
48557416Smarkm{
48657416Smarkm    donebinarytoggle = 1;
48757416Smarkm
48857416Smarkm    if (val >= 0) {
48957416Smarkm	binmode = val;
49057416Smarkm    } else {
49157416Smarkm	if (my_want_state_is_will(TELOPT_BINARY) &&
49257416Smarkm				my_want_state_is_do(TELOPT_BINARY)) {
49357416Smarkm	    binmode = 1;
49457416Smarkm	} else if (my_want_state_is_wont(TELOPT_BINARY) &&
49557416Smarkm				my_want_state_is_dont(TELOPT_BINARY)) {
49657416Smarkm	    binmode = 0;
49757416Smarkm	}
49857416Smarkm	val = binmode ? 0 : 1;
49957416Smarkm    }
50057416Smarkm
50157416Smarkm    if (val == 1) {
50257416Smarkm	if (my_want_state_is_will(TELOPT_BINARY) &&
50357416Smarkm					my_want_state_is_do(TELOPT_BINARY)) {
50457416Smarkm	    printf("Already operating in binary mode with remote host.\r\n");
50557416Smarkm	} else {
50657416Smarkm	    printf("Negotiating binary mode with remote host.\r\n");
50757416Smarkm	    tel_enter_binary(3);
50857416Smarkm	}
50957416Smarkm    } else {
51057416Smarkm	if (my_want_state_is_wont(TELOPT_BINARY) &&
51157416Smarkm					my_want_state_is_dont(TELOPT_BINARY)) {
51257416Smarkm	    printf("Already in network ascii mode with remote host.\r\n");
51357416Smarkm	} else {
51457416Smarkm	    printf("Negotiating network ascii mode with remote host.\r\n");
51557416Smarkm	    tel_leave_binary(3);
51657416Smarkm	}
51757416Smarkm    }
51857416Smarkm    return 1;
51957416Smarkm}
52057416Smarkm
52157416Smarkmstatic int
52257416Smarkmtogrbinary(int val)
52357416Smarkm{
52457416Smarkm    donebinarytoggle = 1;
52557416Smarkm
52657416Smarkm    if (val == -1)
52757416Smarkm	val = my_want_state_is_do(TELOPT_BINARY) ? 0 : 1;
52857416Smarkm
52957416Smarkm    if (val == 1) {
53057416Smarkm	if (my_want_state_is_do(TELOPT_BINARY)) {
53157416Smarkm	    printf("Already receiving in binary mode.\r\n");
53257416Smarkm	} else {
53357416Smarkm	    printf("Negotiating binary mode on input.\r\n");
53457416Smarkm	    tel_enter_binary(1);
53557416Smarkm	}
53657416Smarkm    } else {
53757416Smarkm	if (my_want_state_is_dont(TELOPT_BINARY)) {
53857416Smarkm	    printf("Already receiving in network ascii mode.\r\n");
53957416Smarkm	} else {
54057416Smarkm	    printf("Negotiating network ascii mode on input.\r\n");
54157416Smarkm	    tel_leave_binary(1);
54257416Smarkm	}
54357416Smarkm    }
54457416Smarkm    return 1;
54557416Smarkm}
54657416Smarkm
54757416Smarkmstatic int
54857416Smarkmtogxbinary(int val)
54957416Smarkm{
55057416Smarkm    donebinarytoggle = 1;
55157416Smarkm
55257416Smarkm    if (val == -1)
55357416Smarkm	val = my_want_state_is_will(TELOPT_BINARY) ? 0 : 1;
55457416Smarkm
55557416Smarkm    if (val == 1) {
55657416Smarkm	if (my_want_state_is_will(TELOPT_BINARY)) {
55757416Smarkm	    printf("Already transmitting in binary mode.\r\n");
55857416Smarkm	} else {
55957416Smarkm	    printf("Negotiating binary mode on output.\r\n");
56057416Smarkm	    tel_enter_binary(2);
56157416Smarkm	}
56257416Smarkm    } else {
56357416Smarkm	if (my_want_state_is_wont(TELOPT_BINARY)) {
56457416Smarkm	    printf("Already transmitting in network ascii mode.\r\n");
56557416Smarkm	} else {
56657416Smarkm	    printf("Negotiating network ascii mode on output.\r\n");
56757416Smarkm	    tel_leave_binary(2);
56857416Smarkm	}
56957416Smarkm    }
57057416Smarkm    return 1;
57157416Smarkm}
57257416Smarkm
57357416Smarkm
57457416Smarkmstatic int togglehelp (void);
57557416Smarkm#if	defined(AUTHENTICATION)
57657416Smarkmextern int auth_togdebug (int);
57757416Smarkm#endif
57857416Smarkm#if	defined(ENCRYPTION)
57957416Smarkmextern int EncryptAutoEnc (int);
58057416Smarkmextern int EncryptAutoDec (int);
58157416Smarkmextern int EncryptDebug (int);
58257416Smarkmextern int EncryptVerbose (int);
58357416Smarkm#endif
58457416Smarkm
58557416Smarkmstruct togglelist {
58657416Smarkm    char	*name;		/* name of toggle */
58757416Smarkm    char	*help;		/* help message */
58857416Smarkm    int		(*handler)();	/* routine to do actual setting */
58957416Smarkm    int		*variable;
59057416Smarkm    char	*actionexplanation;
59157416Smarkm};
59257416Smarkm
59357416Smarkmstatic struct togglelist Togglelist[] = {
59457416Smarkm    { "autoflush",
59557416Smarkm	"flushing of output when sending interrupt characters",
59657416Smarkm	    0,
59757416Smarkm		&autoflush,
59857416Smarkm		    "flush output when sending interrupt characters" },
59957416Smarkm    { "autosynch",
60057416Smarkm	"automatic sending of interrupt characters in urgent mode",
60157416Smarkm	    0,
60257416Smarkm		&autosynch,
60357416Smarkm		    "send interrupt characters in urgent mode" },
60457416Smarkm#if	defined(AUTHENTICATION)
60557416Smarkm    { "autologin",
60657416Smarkm	"automatic sending of login and/or authentication info",
60757416Smarkm	    0,
60857416Smarkm		&autologin,
60957416Smarkm		    "send login name and/or authentication information" },
61057416Smarkm    { "authdebug",
611102644Snectar	"authentication debugging",
61257416Smarkm	    auth_togdebug,
61357416Smarkm		0,
61457416Smarkm		     "print authentication debugging information" },
61557416Smarkm#endif
61657416Smarkm#if	defined(ENCRYPTION)
61757416Smarkm    { "autoencrypt",
61857416Smarkm	"automatic encryption of data stream",
61957416Smarkm	    EncryptAutoEnc,
62057416Smarkm		0,
62157416Smarkm		    "automatically encrypt output" },
62257416Smarkm    { "autodecrypt",
62357416Smarkm	"automatic decryption of data stream",
62457416Smarkm	    EncryptAutoDec,
62557416Smarkm		0,
62657416Smarkm		    "automatically decrypt input" },
62757416Smarkm    { "verbose_encrypt",
628102644Snectar	"verbose encryption output",
62957416Smarkm	    EncryptVerbose,
63057416Smarkm		0,
63157416Smarkm		    "print verbose encryption output" },
63257416Smarkm    { "encdebug",
633102644Snectar	"encryption debugging",
63457416Smarkm	    EncryptDebug,
63557416Smarkm		0,
63657416Smarkm		    "print encryption debugging information" },
63757416Smarkm#endif
638102644Snectar#if defined(KRB5)
639102644Snectar    { "forward",
640102644Snectar	"credentials forwarding",
641102644Snectar	    kerberos5_set_forward,
642102644Snectar		0,
643102644Snectar		    "forward credentials" },
644102644Snectar    { "forwardable",
645102644Snectar	"forwardable flag of forwarded credentials",
646102644Snectar	    kerberos5_set_forwardable,
647102644Snectar		0,
648102644Snectar		    "forward forwardable credentials" },
649102644Snectar#endif
650102644Snectar   { "skiprc",
65157416Smarkm	"don't read ~/.telnetrc file",
65257416Smarkm	    0,
65357416Smarkm		&skiprc,
65457416Smarkm		    "skip reading of ~/.telnetrc file" },
65557416Smarkm    { "binary",
65657416Smarkm	"sending and receiving of binary data",
65757416Smarkm	    togbinary,
65857416Smarkm		0,
65957416Smarkm		    0 },
66057416Smarkm    { "inbinary",
66157416Smarkm	"receiving of binary data",
66257416Smarkm	    togrbinary,
66357416Smarkm		0,
66457416Smarkm		    0 },
66557416Smarkm    { "outbinary",
66657416Smarkm	"sending of binary data",
66757416Smarkm	    togxbinary,
66857416Smarkm		0,
66957416Smarkm		    0 },
67057416Smarkm    { "crlf",
67157416Smarkm	"sending carriage returns as telnet <CR><LF>",
67257416Smarkm	    togcrlf,
67357416Smarkm		&crlf,
67457416Smarkm		    0 },
67557416Smarkm    { "crmod",
67657416Smarkm	"mapping of received carriage returns",
67757416Smarkm	    0,
67857416Smarkm		&crmod,
67957416Smarkm		    "map carriage return on output" },
68057416Smarkm    { "localchars",
68157416Smarkm	"local recognition of certain control characters",
68257416Smarkm	    lclchars,
68357416Smarkm		&localchars,
68457416Smarkm		    "recognize certain control characters" },
68557416Smarkm    { " ", "", 0 },		/* empty line */
68657416Smarkm    { "debug",
68757416Smarkm	"debugging",
68857416Smarkm	    togdebug,
68957416Smarkm		&debug,
69057416Smarkm		    "turn on socket level debugging" },
69157416Smarkm#if defined(KRB4) && defined(HAVE_KRB_DISABLE_DEBUG)
69257416Smarkm    { "krb_debug",
69357416Smarkm      "kerberos 4 debugging",
69457416Smarkm      togkrbdebug,
69557416Smarkm      &krb_debug,
69657416Smarkm      "turn on kerberos 4 debugging" },
69757416Smarkm#endif
69857416Smarkm    { "netdata",
69957416Smarkm	"printing of hexadecimal network data (debugging)",
70057416Smarkm	    0,
70157416Smarkm		&netdata,
70257416Smarkm		    "print hexadecimal representation of network traffic" },
70357416Smarkm    { "prettydump",
70457416Smarkm	"output of \"netdata\" to user readable format (debugging)",
70557416Smarkm	    0,
70657416Smarkm		&prettydump,
70757416Smarkm		    "print user readable output for \"netdata\"" },
70857416Smarkm    { "options",
70957416Smarkm	"viewing of options processing (debugging)",
71057416Smarkm	    0,
71157416Smarkm		&showoptions,
71257416Smarkm		    "show option processing" },
71357416Smarkm    { "termdata",
714102644Snectar	"printing of hexadecimal terminal data (debugging)",
71557416Smarkm	    0,
71657416Smarkm		&termdata,
71757416Smarkm		    "print hexadecimal representation of terminal traffic" },
71857416Smarkm    { "?",
71957416Smarkm	0,
72057416Smarkm	    togglehelp },
72157416Smarkm    { "help",
72257416Smarkm	0,
72357416Smarkm	    togglehelp },
72457416Smarkm    { 0 }
72557416Smarkm};
72657416Smarkm
72757416Smarkmstatic int
72857416Smarkmtogglehelp()
72957416Smarkm{
73057416Smarkm    struct togglelist *c;
73157416Smarkm
73257416Smarkm    for (c = Togglelist; c->name; c++) {
73357416Smarkm	if (c->help) {
73457416Smarkm	    if (*c->help)
73557416Smarkm		printf("%-15s toggle %s\r\n", c->name, c->help);
73657416Smarkm	    else
73757416Smarkm		printf("\r\n");
73857416Smarkm	}
73957416Smarkm    }
74057416Smarkm    printf("\r\n");
74157416Smarkm    printf("%-15s %s\r\n", "?", "display help information");
74257416Smarkm    return 0;
74357416Smarkm}
74457416Smarkm
74557416Smarkmstatic void
74657416Smarkmsettogglehelp(int set)
74757416Smarkm{
74857416Smarkm    struct togglelist *c;
74957416Smarkm
75057416Smarkm    for (c = Togglelist; c->name; c++) {
75157416Smarkm	if (c->help) {
75257416Smarkm	    if (*c->help)
75357416Smarkm		printf("%-15s %s %s\r\n", c->name, set ? "enable" : "disable",
75457416Smarkm						c->help);
75557416Smarkm	    else
75657416Smarkm		printf("\r\n");
75757416Smarkm	}
75857416Smarkm    }
75957416Smarkm}
76057416Smarkm
76157416Smarkm#define	GETTOGGLE(name) (struct togglelist *) \
76257416Smarkm		genget(name, (char **) Togglelist, sizeof(struct togglelist))
76357416Smarkm
76457416Smarkmstatic int
76557416Smarkmtoggle(int argc, char *argv[])
76657416Smarkm{
76757416Smarkm    int retval = 1;
76857416Smarkm    char *name;
76957416Smarkm    struct togglelist *c;
77057416Smarkm
77157416Smarkm    if (argc < 2) {
77257416Smarkm	fprintf(stderr,
77357416Smarkm	    "Need an argument to 'toggle' command.  'toggle ?' for help.\r\n");
77457416Smarkm	return 0;
77557416Smarkm    }
77657416Smarkm    argc--;
77757416Smarkm    argv++;
77857416Smarkm    while (argc--) {
77957416Smarkm	name = *argv++;
78057416Smarkm	c = GETTOGGLE(name);
78157416Smarkm	if (Ambiguous(c)) {
78257416Smarkm	    fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\r\n",
78357416Smarkm					name);
78457416Smarkm	    return 0;
78557416Smarkm	} else if (c == 0) {
78657416Smarkm	    fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\r\n",
78757416Smarkm					name);
78857416Smarkm	    return 0;
78957416Smarkm	} else {
79057416Smarkm	    if (c->variable) {
79157416Smarkm		*c->variable = !*c->variable;		/* invert it */
79257416Smarkm		if (c->actionexplanation) {
79357416Smarkm		    printf("%s %s.\r\n", *c->variable? "Will" : "Won't",
79457416Smarkm							c->actionexplanation);
79557416Smarkm		}
79657416Smarkm	    }
79757416Smarkm	    if (c->handler) {
79857416Smarkm		retval &= (*c->handler)(-1);
79957416Smarkm	    }
80057416Smarkm	}
80157416Smarkm    }
80257416Smarkm    return retval;
80357416Smarkm}
80457416Smarkm
80557416Smarkm/*
80657416Smarkm * The following perform the "set" command.
80757416Smarkm */
80857416Smarkm
80957416Smarkmstruct termios new_tc = { 0 };
81057416Smarkm
81157416Smarkmstruct setlist {
81257416Smarkm    char *name;				/* name */
81357416Smarkm    char *help;				/* help information */
81457416Smarkm    void (*handler)();
81557416Smarkm    cc_t *charp;			/* where it is located at */
81657416Smarkm};
81757416Smarkm
81857416Smarkmstatic struct setlist Setlist[] = {
81957416Smarkm#ifdef	KLUDGELINEMODE
82057416Smarkm    { "echo", 	"character to toggle local echoing on/off", 0, &echoc },
82157416Smarkm#endif
82257416Smarkm    { "escape",	"character to escape back to telnet command mode", 0, &escape },
82357416Smarkm    { "rlogin", "rlogin escape character", 0, &rlogin },
82457416Smarkm    { "tracefile", "file to write trace information to", SetNetTrace, (cc_t *)NetTraceFile},
82557416Smarkm    { " ", "" },
82657416Smarkm    { " ", "The following need 'localchars' to be toggled true", 0, 0 },
82757416Smarkm    { "flushoutput", "character to cause an Abort Output", 0, &termFlushChar },
82857416Smarkm    { "interrupt", "character to cause an Interrupt Process", 0, &termIntChar },
82957416Smarkm    { "quit",	"character to cause an Abort process", 0, &termQuitChar },
83057416Smarkm    { "eof",	"character to cause an EOF ", 0, &termEofChar },
83157416Smarkm    { " ", "" },
83257416Smarkm    { " ", "The following are for local editing in linemode", 0, 0 },
83357416Smarkm    { "erase",	"character to use to erase a character", 0, &termEraseChar },
83457416Smarkm    { "kill",	"character to use to erase a line", 0, &termKillChar },
83557416Smarkm    { "lnext",	"character to use for literal next", 0, &termLiteralNextChar },
83657416Smarkm    { "susp",	"character to cause a Suspend Process", 0, &termSuspChar },
83757416Smarkm    { "reprint", "character to use for line reprint", 0, &termRprntChar },
83857416Smarkm    { "worderase", "character to use to erase a word", 0, &termWerasChar },
83957416Smarkm    { "start",	"character to use for XON", 0, &termStartChar },
84057416Smarkm    { "stop",	"character to use for XOFF", 0, &termStopChar },
84157416Smarkm    { "forw1",	"alternate end of line character", 0, &termForw1Char },
84257416Smarkm    { "forw2",	"alternate end of line character", 0, &termForw2Char },
84357416Smarkm    { "ayt",	"alternate AYT character", 0, &termAytChar },
84457416Smarkm    { 0 }
84557416Smarkm};
84657416Smarkm
84757416Smarkmstatic struct setlist *
84857416Smarkmgetset(char *name)
84957416Smarkm{
85057416Smarkm    return (struct setlist *)
85157416Smarkm		genget(name, (char **) Setlist, sizeof(struct setlist));
85257416Smarkm}
85357416Smarkm
85457416Smarkmvoid
85557416Smarkmset_escape_char(char *s)
85657416Smarkm{
85757416Smarkm	if (rlogin != _POSIX_VDISABLE) {
85857416Smarkm		rlogin = (s && *s) ? special(s) : _POSIX_VDISABLE;
85957416Smarkm		printf("Telnet rlogin escape character is '%s'.\r\n",
86057416Smarkm					control(rlogin));
86157416Smarkm	} else {
86257416Smarkm		escape = (s && *s) ? special(s) : _POSIX_VDISABLE;
86357416Smarkm		printf("Telnet escape character is '%s'.\r\n", control(escape));
86457416Smarkm	}
86557416Smarkm}
86657416Smarkm
86757416Smarkmstatic int
86857416Smarkmsetcmd(int argc, char *argv[])
86957416Smarkm{
87057416Smarkm    int value;
87157416Smarkm    struct setlist *ct;
87257416Smarkm    struct togglelist *c;
87357416Smarkm
87457416Smarkm    if (argc < 2 || argc > 3) {
87557416Smarkm	printf("Format is 'set Name Value'\r\n'set ?' for help.\r\n");
87657416Smarkm	return 0;
87757416Smarkm    }
87857416Smarkm    if ((argc == 2) && (isprefix(argv[1], "?") || isprefix(argv[1], "help"))) {
87957416Smarkm	for (ct = Setlist; ct->name; ct++)
88057416Smarkm	    printf("%-15s %s\r\n", ct->name, ct->help);
88157416Smarkm	printf("\r\n");
88257416Smarkm	settogglehelp(1);
88357416Smarkm	printf("%-15s %s\r\n", "?", "display help information");
88457416Smarkm	return 0;
88557416Smarkm    }
88657416Smarkm
88757416Smarkm    ct = getset(argv[1]);
88857416Smarkm    if (ct == 0) {
88957416Smarkm	c = GETTOGGLE(argv[1]);
89057416Smarkm	if (c == 0) {
89157416Smarkm	    fprintf(stderr, "'%s': unknown argument ('set ?' for help).\r\n",
89257416Smarkm			argv[1]);
89357416Smarkm	    return 0;
89457416Smarkm	} else if (Ambiguous(c)) {
89557416Smarkm	    fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\r\n",
89657416Smarkm			argv[1]);
89757416Smarkm	    return 0;
89857416Smarkm	}
89957416Smarkm	if (c->variable) {
90057416Smarkm	    if ((argc == 2) || (strcmp("on", argv[2]) == 0))
90157416Smarkm		*c->variable = 1;
90257416Smarkm	    else if (strcmp("off", argv[2]) == 0)
90357416Smarkm		*c->variable = 0;
90457416Smarkm	    else {
90557416Smarkm		printf("Format is 'set togglename [on|off]'\r\n'set ?' for help.\r\n");
90657416Smarkm		return 0;
90757416Smarkm	    }
90857416Smarkm	    if (c->actionexplanation) {
90957416Smarkm		printf("%s %s.\r\n", *c->variable? "Will" : "Won't",
91057416Smarkm							c->actionexplanation);
91157416Smarkm	    }
91257416Smarkm	}
91357416Smarkm	if (c->handler)
91457416Smarkm	    (*c->handler)(1);
91557416Smarkm    } else if (argc != 3) {
91657416Smarkm	printf("Format is 'set Name Value'\r\n'set ?' for help.\r\n");
91757416Smarkm	return 0;
91857416Smarkm    } else if (Ambiguous(ct)) {
91957416Smarkm	fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\r\n",
92057416Smarkm			argv[1]);
92157416Smarkm	return 0;
92257416Smarkm    } else if (ct->handler) {
92357416Smarkm	(*ct->handler)(argv[2]);
92457416Smarkm	printf("%s set to \"%s\".\r\n", ct->name, (char *)ct->charp);
92557416Smarkm    } else {
92657416Smarkm	if (strcmp("off", argv[2])) {
92757416Smarkm	    value = special(argv[2]);
92857416Smarkm	} else {
92957416Smarkm	    value = _POSIX_VDISABLE;
93057416Smarkm	}
93157416Smarkm	*(ct->charp) = (cc_t)value;
93257416Smarkm	printf("%s character is '%s'.\r\n", ct->name, control(*(ct->charp)));
93357416Smarkm    }
93457416Smarkm    slc_check();
93557416Smarkm    return 1;
93657416Smarkm}
93757416Smarkm
93857416Smarkmstatic int
93957416Smarkmunsetcmd(int argc, char *argv[])
94057416Smarkm{
94157416Smarkm    struct setlist *ct;
94257416Smarkm    struct togglelist *c;
94357416Smarkm    char *name;
94457416Smarkm
94557416Smarkm    if (argc < 2) {
94657416Smarkm	fprintf(stderr,
94757416Smarkm	    "Need an argument to 'unset' command.  'unset ?' for help.\r\n");
94857416Smarkm	return 0;
94957416Smarkm    }
95057416Smarkm    if (isprefix(argv[1], "?") || isprefix(argv[1], "help")) {
95157416Smarkm	for (ct = Setlist; ct->name; ct++)
95257416Smarkm	    printf("%-15s %s\r\n", ct->name, ct->help);
95357416Smarkm	printf("\r\n");
95457416Smarkm	settogglehelp(0);
95557416Smarkm	printf("%-15s %s\r\n", "?", "display help information");
95657416Smarkm	return 0;
95757416Smarkm    }
95857416Smarkm
95957416Smarkm    argc--;
96057416Smarkm    argv++;
96157416Smarkm    while (argc--) {
96257416Smarkm	name = *argv++;
96357416Smarkm	ct = getset(name);
96457416Smarkm	if (ct == 0) {
96557416Smarkm	    c = GETTOGGLE(name);
96657416Smarkm	    if (c == 0) {
96757416Smarkm		fprintf(stderr, "'%s': unknown argument ('unset ?' for help).\r\n",
96857416Smarkm			name);
96957416Smarkm		return 0;
97057416Smarkm	    } else if (Ambiguous(c)) {
97157416Smarkm		fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\r\n",
97257416Smarkm			name);
97357416Smarkm		return 0;
97457416Smarkm	    }
97557416Smarkm	    if (c->variable) {
97657416Smarkm		*c->variable = 0;
97757416Smarkm		if (c->actionexplanation) {
97857416Smarkm		    printf("%s %s.\r\n", *c->variable? "Will" : "Won't",
97957416Smarkm							c->actionexplanation);
98057416Smarkm		}
98157416Smarkm	    }
98257416Smarkm	    if (c->handler)
98357416Smarkm		(*c->handler)(0);
98457416Smarkm	} else if (Ambiguous(ct)) {
98557416Smarkm	    fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\r\n",
98657416Smarkm			name);
98757416Smarkm	    return 0;
98857416Smarkm	} else if (ct->handler) {
98957416Smarkm	    (*ct->handler)(0);
99057416Smarkm	    printf("%s reset to \"%s\".\r\n", ct->name, (char *)ct->charp);
99157416Smarkm	} else {
99257416Smarkm	    *(ct->charp) = _POSIX_VDISABLE;
99357416Smarkm	    printf("%s character is '%s'.\r\n", ct->name, control(*(ct->charp)));
99457416Smarkm	}
99557416Smarkm    }
99657416Smarkm    return 1;
99757416Smarkm}
99857416Smarkm
99957416Smarkm/*
100057416Smarkm * The following are the data structures and routines for the
100157416Smarkm * 'mode' command.
100257416Smarkm */
100357416Smarkm#ifdef	KLUDGELINEMODE
100457416Smarkm
100557416Smarkmstatic int
100657416Smarkmdokludgemode(void)
100757416Smarkm{
100857416Smarkm    kludgelinemode = 1;
100957416Smarkm    send_wont(TELOPT_LINEMODE, 1);
101057416Smarkm    send_dont(TELOPT_SGA, 1);
101157416Smarkm    send_dont(TELOPT_ECHO, 1);
101257416Smarkm    return 1;
101357416Smarkm}
101457416Smarkm#endif
101557416Smarkm
101657416Smarkmstatic int
101757416Smarkmdolinemode()
101857416Smarkm{
101957416Smarkm#ifdef	KLUDGELINEMODE
102057416Smarkm    if (kludgelinemode)
102157416Smarkm	send_dont(TELOPT_SGA, 1);
102257416Smarkm#endif
102357416Smarkm    send_will(TELOPT_LINEMODE, 1);
102457416Smarkm    send_dont(TELOPT_ECHO, 1);
102557416Smarkm    return 1;
102657416Smarkm}
102757416Smarkm
102857416Smarkmstatic int
102957416Smarkmdocharmode()
103057416Smarkm{
103157416Smarkm#ifdef	KLUDGELINEMODE
103257416Smarkm    if (kludgelinemode)
103357416Smarkm	send_do(TELOPT_SGA, 1);
103457416Smarkm    else
103557416Smarkm#endif
103657416Smarkm    send_wont(TELOPT_LINEMODE, 1);
103757416Smarkm    send_do(TELOPT_ECHO, 1);
103857416Smarkm    return 1;
103957416Smarkm}
104057416Smarkm
104157416Smarkmstatic int
104257416Smarkmdolmmode(int bit, int on)
104357416Smarkm{
104457416Smarkm    unsigned char c;
104557416Smarkm
104657416Smarkm    if (my_want_state_is_wont(TELOPT_LINEMODE)) {
104757416Smarkm	printf("?Need to have LINEMODE option enabled first.\r\n");
104857416Smarkm	printf("'mode ?' for help.\r\n");
104957416Smarkm 	return 0;
105057416Smarkm    }
105157416Smarkm
105257416Smarkm    if (on)
105357416Smarkm	c = (linemode | bit);
105457416Smarkm    else
105557416Smarkm	c = (linemode & ~bit);
105657416Smarkm    lm_mode(&c, 1, 1);
105757416Smarkm    return 1;
105857416Smarkm}
105957416Smarkm
106057416Smarkmstatic int
106157416Smarkmtn_setmode(int bit)
106257416Smarkm{
106357416Smarkm    return dolmmode(bit, 1);
106457416Smarkm}
106557416Smarkm
106657416Smarkmstatic int
106757416Smarkmtn_clearmode(int bit)
106857416Smarkm{
106957416Smarkm    return dolmmode(bit, 0);
107057416Smarkm}
107157416Smarkm
107257416Smarkmstruct modelist {
107357416Smarkm	char	*name;		/* command name */
107457416Smarkm	char	*help;		/* help string */
107557416Smarkm	int	(*handler)();	/* routine which executes command */
107657416Smarkm	int	needconnect;	/* Do we need to be connected to execute? */
107757416Smarkm	int	arg1;
107857416Smarkm};
107957416Smarkm
108057416Smarkmstatic int modehelp(void);
108157416Smarkm
108257416Smarkmstatic struct modelist ModeList[] = {
108357416Smarkm    { "character", "Disable LINEMODE option",	docharmode, 1 },
108457416Smarkm#ifdef	KLUDGELINEMODE
108557416Smarkm    { "",	"(or disable obsolete line-by-line mode)", 0 },
108657416Smarkm#endif
108757416Smarkm    { "line",	"Enable LINEMODE option",	dolinemode, 1 },
108857416Smarkm#ifdef	KLUDGELINEMODE
108957416Smarkm    { "",	"(or enable obsolete line-by-line mode)", 0 },
109057416Smarkm#endif
109157416Smarkm    { "", "", 0 },
109257416Smarkm    { "",	"These require the LINEMODE option to be enabled", 0 },
109357416Smarkm    { "isig",	"Enable signal trapping",	tn_setmode, 1, MODE_TRAPSIG },
109457416Smarkm    { "+isig",	0,				tn_setmode, 1, MODE_TRAPSIG },
109557416Smarkm    { "-isig",	"Disable signal trapping",	tn_clearmode, 1, MODE_TRAPSIG },
109657416Smarkm    { "edit",	"Enable character editing",	tn_setmode, 1, MODE_EDIT },
109757416Smarkm    { "+edit",	0,				tn_setmode, 1, MODE_EDIT },
109857416Smarkm    { "-edit",	"Disable character editing",	tn_clearmode, 1, MODE_EDIT },
109957416Smarkm    { "softtabs", "Enable tab expansion",	tn_setmode, 1, MODE_SOFT_TAB },
110057416Smarkm    { "+softtabs", 0,				tn_setmode, 1, MODE_SOFT_TAB },
1101102644Snectar    { "-softtabs", "Disable tab expansion",	tn_clearmode, 1, MODE_SOFT_TAB },
110257416Smarkm    { "litecho", "Enable literal character echo", tn_setmode, 1, MODE_LIT_ECHO },
110357416Smarkm    { "+litecho", 0,				tn_setmode, 1, MODE_LIT_ECHO },
110457416Smarkm    { "-litecho", "Disable literal character echo", tn_clearmode, 1, MODE_LIT_ECHO },
110557416Smarkm    { "help",	0,				modehelp, 0 },
110657416Smarkm#ifdef	KLUDGELINEMODE
110757416Smarkm    { "kludgeline", 0,				dokludgemode, 1 },
110857416Smarkm#endif
110957416Smarkm    { "", "", 0 },
111057416Smarkm    { "?",	"Print help information",	modehelp, 0 },
111157416Smarkm    { 0 },
111257416Smarkm};
111357416Smarkm
111457416Smarkm
111557416Smarkmstatic int
111657416Smarkmmodehelp(void)
111757416Smarkm{
111857416Smarkm    struct modelist *mt;
111957416Smarkm
112057416Smarkm    printf("format is:  'mode Mode', where 'Mode' is one of:\r\n\r\n");
112157416Smarkm    for (mt = ModeList; mt->name; mt++) {
112257416Smarkm	if (mt->help) {
112357416Smarkm	    if (*mt->help)
112457416Smarkm		printf("%-15s %s\r\n", mt->name, mt->help);
112557416Smarkm	    else
112657416Smarkm		printf("\r\n");
112757416Smarkm	}
112857416Smarkm    }
112957416Smarkm    return 0;
113057416Smarkm}
113157416Smarkm
113257416Smarkm#define	GETMODECMD(name) (struct modelist *) \
113357416Smarkm		genget(name, (char **) ModeList, sizeof(struct modelist))
113457416Smarkm
113557416Smarkmstatic int
113657416Smarkmmodecmd(int argc, char **argv)
113757416Smarkm{
113857416Smarkm    struct modelist *mt;
113957416Smarkm
114057416Smarkm    if (argc != 2) {
114157416Smarkm	printf("'mode' command requires an argument\r\n");
114257416Smarkm	printf("'mode ?' for help.\r\n");
114357416Smarkm    } else if ((mt = GETMODECMD(argv[1])) == 0) {
114457416Smarkm	fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\r\n", argv[1]);
114557416Smarkm    } else if (Ambiguous(mt)) {
114657416Smarkm	fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\r\n", argv[1]);
114757416Smarkm    } else if (mt->needconnect && !connected) {
114857416Smarkm	printf("?Need to be connected first.\r\n");
114957416Smarkm	printf("'mode ?' for help.\r\n");
115057416Smarkm    } else if (mt->handler) {
115157416Smarkm	return (*mt->handler)(mt->arg1);
115257416Smarkm    }
115357416Smarkm    return 0;
115457416Smarkm}
115557416Smarkm
115657416Smarkm/*
115757416Smarkm * The following data structures and routines implement the
115857416Smarkm * "display" command.
115957416Smarkm */
116057416Smarkm
116157416Smarkmstatic int
116257416Smarkmdisplay(int argc, char *argv[])
116357416Smarkm{
116457416Smarkm    struct togglelist *tl;
116557416Smarkm    struct setlist *sl;
116657416Smarkm
116757416Smarkm#define	dotog(tl)	if (tl->variable && tl->actionexplanation) { \
116857416Smarkm			    if (*tl->variable) { \
116957416Smarkm				printf("will"); \
117057416Smarkm			    } else { \
117157416Smarkm				printf("won't"); \
117257416Smarkm			    } \
117357416Smarkm			    printf(" %s.\r\n", tl->actionexplanation); \
117457416Smarkm			}
117557416Smarkm
117657416Smarkm#define	doset(sl)   if (sl->name && *sl->name != ' ') { \
117757416Smarkm			if (sl->handler == 0) \
117857416Smarkm			    printf("%-15s [%s]\r\n", sl->name, control(*sl->charp)); \
117957416Smarkm			else \
118057416Smarkm			    printf("%-15s \"%s\"\r\n", sl->name, (char *)sl->charp); \
118157416Smarkm		    }
118257416Smarkm
118357416Smarkm    if (argc == 1) {
118457416Smarkm	for (tl = Togglelist; tl->name; tl++) {
118557416Smarkm	    dotog(tl);
118657416Smarkm	}
118757416Smarkm	printf("\r\n");
118857416Smarkm	for (sl = Setlist; sl->name; sl++) {
118957416Smarkm	    doset(sl);
119057416Smarkm	}
119157416Smarkm    } else {
119257416Smarkm	int i;
119357416Smarkm
119457416Smarkm	for (i = 1; i < argc; i++) {
119557416Smarkm	    sl = getset(argv[i]);
119657416Smarkm	    tl = GETTOGGLE(argv[i]);
119757416Smarkm	    if (Ambiguous(sl) || Ambiguous(tl)) {
119857416Smarkm		printf("?Ambiguous argument '%s'.\r\n", argv[i]);
119957416Smarkm		return 0;
120057416Smarkm	    } else if (!sl && !tl) {
120157416Smarkm		printf("?Unknown argument '%s'.\r\n", argv[i]);
120257416Smarkm		return 0;
120357416Smarkm	    } else {
120457416Smarkm		if (tl) {
120557416Smarkm		    dotog(tl);
120657416Smarkm		}
120757416Smarkm		if (sl) {
120857416Smarkm		    doset(sl);
120957416Smarkm		}
121057416Smarkm	    }
121157416Smarkm	}
121257416Smarkm    }
121357416Smarkm/*@*/optionstatus();
121457416Smarkm#if	defined(ENCRYPTION)
121557416Smarkm    EncryptStatus();
121657416Smarkm#endif
121757416Smarkm    return 1;
121857416Smarkm#undef	doset
121957416Smarkm#undef	dotog
122057416Smarkm}
122157416Smarkm
122257416Smarkm/*
122357416Smarkm * The following are the data structures, and many of the routines,
122457416Smarkm * relating to command processing.
122557416Smarkm */
122657416Smarkm
122757416Smarkm/*
122857416Smarkm * Set the escape character.
122957416Smarkm */
123057416Smarkmstatic int
123157416Smarkmsetescape(int argc, char *argv[])
123257416Smarkm{
123357416Smarkm	char *arg;
123457416Smarkm	char buf[50];
123557416Smarkm
123657416Smarkm	printf(
123757416Smarkm	    "Deprecated usage - please use 'set escape%s%s' in the future.\r\n",
123857416Smarkm				(argc > 2)? " ":"", (argc > 2)? argv[1]: "");
123957416Smarkm	if (argc > 2)
124057416Smarkm		arg = argv[1];
124157416Smarkm	else {
124257416Smarkm		printf("new escape character: ");
124357416Smarkm		fgets(buf, sizeof(buf), stdin);
124457416Smarkm		arg = buf;
124557416Smarkm	}
124657416Smarkm	if (arg[0] != '\0')
124757416Smarkm		escape = arg[0];
124857416Smarkm	printf("Escape character is '%s'.\r\n", control(escape));
124957416Smarkm
125057416Smarkm	fflush(stdout);
125157416Smarkm	return 1;
125257416Smarkm}
125357416Smarkm
125457416Smarkmstatic int
125557416Smarkmtogcrmod()
125657416Smarkm{
125757416Smarkm    crmod = !crmod;
125857416Smarkm    printf("Deprecated usage - please use 'toggle crmod' in the future.\r\n");
125957416Smarkm    printf("%s map carriage return on output.\r\n", crmod ? "Will" : "Won't");
126057416Smarkm    fflush(stdout);
126157416Smarkm    return 1;
126257416Smarkm}
126357416Smarkm
126457416Smarkmstatic int
126557416Smarkmtelnetsuspend()
126657416Smarkm{
126757416Smarkm#ifdef	SIGTSTP
126857416Smarkm    setcommandmode();
126957416Smarkm    {
127057416Smarkm	long oldrows, oldcols, newrows, newcols, err;
127157416Smarkm
127257416Smarkm	err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0;
127357416Smarkm	kill(0, SIGTSTP);
127457416Smarkm	/*
127557416Smarkm	 * If we didn't get the window size before the SUSPEND, but we
127657416Smarkm	 * can get them now (?), then send the NAWS to make sure that
127757416Smarkm	 * we are set up for the right window size.
127857416Smarkm	 */
127957416Smarkm	if (TerminalWindowSize(&newrows, &newcols) && connected &&
128057416Smarkm	    (err || ((oldrows != newrows) || (oldcols != newcols)))) {
128157416Smarkm		sendnaws();
128257416Smarkm	}
128357416Smarkm    }
128457416Smarkm    /* reget parameters in case they were changed */
128557416Smarkm    TerminalSaveState();
128657416Smarkm    setconnmode(0);
128757416Smarkm#else
128857416Smarkm    printf("Suspend is not supported.  Try the '!' command instead\r\n");
128957416Smarkm#endif
129057416Smarkm    return 1;
129157416Smarkm}
129257416Smarkm
129357416Smarkmstatic int
129457416Smarkmshell(int argc, char **argv)
129557416Smarkm{
129657416Smarkm    long oldrows, oldcols, newrows, newcols, err;
129757416Smarkm
129857416Smarkm    setcommandmode();
129957416Smarkm
130057416Smarkm    err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0;
130157416Smarkm    switch(fork()) {
130257416Smarkm    case -1:
130357416Smarkm	perror("Fork failed\r\n");
130457416Smarkm	break;
130557416Smarkm
130657416Smarkm    case 0:
130757416Smarkm	{
130857416Smarkm	    /*
130957416Smarkm	     * Fire up the shell in the child.
131057416Smarkm	     */
131157416Smarkm	    char *shellp, *shellname;
131257416Smarkm
131357416Smarkm	    shellp = getenv("SHELL");
131457416Smarkm	    if (shellp == NULL)
131557416Smarkm		shellp = "/bin/sh";
131657416Smarkm	    if ((shellname = strrchr(shellp, '/')) == 0)
131757416Smarkm		shellname = shellp;
131857416Smarkm	    else
131957416Smarkm		shellname++;
132057416Smarkm	    if (argc > 1)
1321178825Sdfr		execl(shellp, shellname, "-c", &saveline[1], NULL);
132257416Smarkm	    else
1323178825Sdfr		execl(shellp, shellname, NULL);
132457416Smarkm	    perror("Execl");
132557416Smarkm	    _exit(1);
132657416Smarkm	}
132757416Smarkm    default:
132857416Smarkm	    wait((int *)0);	/* Wait for the shell to complete */
132957416Smarkm
133057416Smarkm	    if (TerminalWindowSize(&newrows, &newcols) && connected &&
133157416Smarkm		(err || ((oldrows != newrows) || (oldcols != newcols)))) {
133257416Smarkm		    sendnaws();
133357416Smarkm	    }
133457416Smarkm	    break;
133557416Smarkm    }
133657416Smarkm    return 1;
133757416Smarkm}
133857416Smarkm
133957416Smarkmstatic int
134057416Smarkmbye(int argc, char **argv)
134157416Smarkm{
134257416Smarkm    if (connected) {
134357416Smarkm	shutdown(net, 2);
134457416Smarkm	printf("Connection closed.\r\n");
134557416Smarkm	NetClose(net);
134657416Smarkm	connected = 0;
134757416Smarkm	resettermname = 1;
134857416Smarkm#if	defined(AUTHENTICATION) || defined(ENCRYPTION)
134957416Smarkm	auth_encrypt_connect(connected);
135057416Smarkm#endif
135157416Smarkm	/* reset options */
135257416Smarkm	tninit();
135357416Smarkm    }
135457416Smarkm    if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0))
135557416Smarkm	longjmp(toplevel, 1);
135657416Smarkm    return 0;	/* NOTREACHED */
135757416Smarkm}
135857416Smarkm
135957416Smarkmint
136057416Smarkmquit(void)
136157416Smarkm{
136257416Smarkm	call(bye, "bye", "fromquit", 0);
136357416Smarkm	Exit(0);
136457416Smarkm	return 0; /*NOTREACHED*/
136557416Smarkm}
136657416Smarkm
136757416Smarkmstatic int
136857416Smarkmlogout()
136957416Smarkm{
137057416Smarkm	send_do(TELOPT_LOGOUT, 1);
137157416Smarkm	netflush();
137257416Smarkm	return 1;
137357416Smarkm}
137457416Smarkm
137557416Smarkm
137657416Smarkm/*
137757416Smarkm * The SLC command.
137857416Smarkm */
137957416Smarkm
138057416Smarkmstruct slclist {
138157416Smarkm	char	*name;
138257416Smarkm	char	*help;
138357416Smarkm	void	(*handler)();
138457416Smarkm	int	arg;
138557416Smarkm};
138657416Smarkm
138757416Smarkmstatic void slc_help(void);
138857416Smarkm
138957416Smarkmstruct slclist SlcList[] = {
139057416Smarkm    { "export",	"Use local special character definitions",
139157416Smarkm						slc_mode_export,	0 },
139257416Smarkm    { "import",	"Use remote special character definitions",
139357416Smarkm						slc_mode_import,	1 },
139457416Smarkm    { "check",	"Verify remote special character definitions",
139557416Smarkm						slc_mode_import,	0 },
139657416Smarkm    { "help",	0,				slc_help,		0 },
139757416Smarkm    { "?",	"Print help information",	slc_help,		0 },
139857416Smarkm    { 0 },
139957416Smarkm};
140057416Smarkm
140157416Smarkmstatic void
140257416Smarkmslc_help(void)
140357416Smarkm{
140457416Smarkm    struct slclist *c;
140557416Smarkm
140657416Smarkm    for (c = SlcList; c->name; c++) {
140757416Smarkm	if (c->help) {
140857416Smarkm	    if (*c->help)
140957416Smarkm		printf("%-15s %s\r\n", c->name, c->help);
141057416Smarkm	    else
141157416Smarkm		printf("\r\n");
141257416Smarkm	}
141357416Smarkm    }
141457416Smarkm}
141557416Smarkm
141657416Smarkmstatic struct slclist *
141757416Smarkmgetslc(char *name)
141857416Smarkm{
141957416Smarkm    return (struct slclist *)
142057416Smarkm		genget(name, (char **) SlcList, sizeof(struct slclist));
142157416Smarkm}
142257416Smarkm
142357416Smarkmstatic int
142457416Smarkmslccmd(int argc, char **argv)
142557416Smarkm{
142657416Smarkm    struct slclist *c;
142757416Smarkm
142857416Smarkm    if (argc != 2) {
142957416Smarkm	fprintf(stderr,
143057416Smarkm	    "Need an argument to 'slc' command.  'slc ?' for help.\r\n");
143157416Smarkm	return 0;
143257416Smarkm    }
143357416Smarkm    c = getslc(argv[1]);
143457416Smarkm    if (c == 0) {
143557416Smarkm	fprintf(stderr, "'%s': unknown argument ('slc ?' for help).\r\n",
143657416Smarkm    				argv[1]);
143757416Smarkm	return 0;
143857416Smarkm    }
143957416Smarkm    if (Ambiguous(c)) {
144057416Smarkm	fprintf(stderr, "'%s': ambiguous argument ('slc ?' for help).\r\n",
144157416Smarkm    				argv[1]);
144257416Smarkm	return 0;
144357416Smarkm    }
144457416Smarkm    (*c->handler)(c->arg);
144557416Smarkm    slcstate();
144657416Smarkm    return 1;
144757416Smarkm}
144857416Smarkm
144957416Smarkm/*
145057416Smarkm * The ENVIRON command.
145157416Smarkm */
145257416Smarkm
145357416Smarkmstruct envlist {
145457416Smarkm	char	*name;
145557416Smarkm	char	*help;
145657416Smarkm	void	(*handler)();
145757416Smarkm	int	narg;
145857416Smarkm};
145957416Smarkm
146057416Smarkmstatic void env_help (void);
146157416Smarkm
146257416Smarkmstruct envlist EnvList[] = {
146357416Smarkm    { "define",	"Define an environment variable",
146457416Smarkm						(void (*)())env_define,	2 },
146557416Smarkm    { "undefine", "Undefine an environment variable",
146657416Smarkm						env_undefine,	1 },
146757416Smarkm    { "export",	"Mark an environment variable for automatic export",
146857416Smarkm						env_export,	1 },
146957416Smarkm    { "unexport", "Don't mark an environment variable for automatic export",
147057416Smarkm						env_unexport,	1 },
147157416Smarkm    { "send",	"Send an environment variable", env_send,	1 },
147257416Smarkm    { "list",	"List the current environment variables",
147357416Smarkm						env_list,	0 },
147457416Smarkm    { "help",	0,				env_help,		0 },
147557416Smarkm    { "?",	"Print help information",	env_help,		0 },
147657416Smarkm    { 0 },
147757416Smarkm};
147857416Smarkm
147957416Smarkmstatic void
148057416Smarkmenv_help()
148157416Smarkm{
148257416Smarkm    struct envlist *c;
148357416Smarkm
148457416Smarkm    for (c = EnvList; c->name; c++) {
148557416Smarkm	if (c->help) {
148657416Smarkm	    if (*c->help)
148757416Smarkm		printf("%-15s %s\r\n", c->name, c->help);
148857416Smarkm	    else
148957416Smarkm		printf("\r\n");
149057416Smarkm	}
149157416Smarkm    }
149257416Smarkm}
149357416Smarkm
149457416Smarkmstatic struct envlist *
149557416Smarkmgetenvcmd(char *name)
149657416Smarkm{
149757416Smarkm    return (struct envlist *)
149857416Smarkm		genget(name, (char **) EnvList, sizeof(struct envlist));
149957416Smarkm}
150057416Smarkm
150157416Smarkmstatic int
150257416Smarkmenv_cmd(int argc, char **argv)
150357416Smarkm{
150457416Smarkm    struct envlist *c;
150557416Smarkm
150657416Smarkm    if (argc < 2) {
150757416Smarkm	fprintf(stderr,
150857416Smarkm	    "Need an argument to 'environ' command.  'environ ?' for help.\r\n");
150957416Smarkm	return 0;
151057416Smarkm    }
151157416Smarkm    c = getenvcmd(argv[1]);
151257416Smarkm    if (c == 0) {
151357416Smarkm	fprintf(stderr, "'%s': unknown argument ('environ ?' for help).\r\n",
151457416Smarkm    				argv[1]);
151557416Smarkm	return 0;
151657416Smarkm    }
151757416Smarkm    if (Ambiguous(c)) {
151857416Smarkm	fprintf(stderr, "'%s': ambiguous argument ('environ ?' for help).\r\n",
151957416Smarkm    				argv[1]);
152057416Smarkm	return 0;
152157416Smarkm    }
152257416Smarkm    if (c->narg + 2 != argc) {
152357416Smarkm	fprintf(stderr,
152457416Smarkm	    "Need %s%d argument%s to 'environ %s' command.  'environ ?' for help.\r\n",
152557416Smarkm		c->narg < argc + 2 ? "only " : "",
152657416Smarkm		c->narg, c->narg == 1 ? "" : "s", c->name);
152757416Smarkm	return 0;
152857416Smarkm    }
152957416Smarkm    (*c->handler)(argv[2], argv[3]);
153057416Smarkm    return 1;
153157416Smarkm}
153257416Smarkm
153357416Smarkmstruct env_lst {
153457416Smarkm	struct env_lst *next;	/* pointer to next structure */
153557416Smarkm	struct env_lst *prev;	/* pointer to previous structure */
153657416Smarkm	unsigned char *var;	/* pointer to variable name */
153757416Smarkm	unsigned char *value;	/* pointer to variable value */
153857416Smarkm	int export;		/* 1 -> export with default list of variables */
153957416Smarkm	int welldefined;	/* A well defined variable */
154057416Smarkm};
154157416Smarkm
154257416Smarkmstruct env_lst envlisthead;
154357416Smarkm
154457416Smarkmstruct env_lst *
154557416Smarkmenv_find(unsigned char *var)
154657416Smarkm{
154757416Smarkm	struct env_lst *ep;
154857416Smarkm
154957416Smarkm	for (ep = envlisthead.next; ep; ep = ep->next) {
155057416Smarkm		if (strcmp((char *)ep->var, (char *)var) == 0)
155157416Smarkm			return(ep);
155257416Smarkm	}
155357416Smarkm	return(NULL);
155457416Smarkm}
155557416Smarkm
1556102644Snectar#ifdef IRIX4
155757416Smarkm#define environ _environ
155857416Smarkm#endif
155957416Smarkm
156057416Smarkmvoid
156157416Smarkmenv_init(void)
156257416Smarkm{
156357416Smarkm	char **epp, *cp;
156457416Smarkm	struct env_lst *ep;
156557416Smarkm
156657416Smarkm	for (epp = environ; *epp; epp++) {
156757416Smarkm		if ((cp = strchr(*epp, '='))) {
156857416Smarkm			*cp = '\0';
156957416Smarkm			ep = env_define((unsigned char *)*epp,
157057416Smarkm					(unsigned char *)cp+1);
157157416Smarkm			ep->export = 0;
157257416Smarkm			*cp = '=';
157357416Smarkm		}
157457416Smarkm	}
157557416Smarkm	/*
157657416Smarkm	 * Special case for DISPLAY variable.  If it is ":0.0" or
157757416Smarkm	 * "unix:0.0", we have to get rid of "unix" and insert our
157857416Smarkm	 * hostname.
157957416Smarkm	 */
158090926Snectar	if ((ep = env_find((unsigned char*)"DISPLAY"))
158157416Smarkm	    && (*ep->value == ':'
158257416Smarkm	    || strncmp((char *)ep->value, "unix:", 5) == 0)) {
158357416Smarkm		char hbuf[256+1];
158457416Smarkm		char *cp2 = strchr((char *)ep->value, ':');
1585178825Sdfr		int error;
158657416Smarkm
158757416Smarkm		/* XXX - should be k_gethostname? */
158857416Smarkm		gethostname(hbuf, 256);
158957416Smarkm		hbuf[256] = '\0';
159057416Smarkm
159157416Smarkm		/* If this is not the full name, try to get it via DNS */
159257416Smarkm		if (strchr(hbuf, '.') == 0) {
159357416Smarkm			struct addrinfo hints, *ai, *a;
159457416Smarkm
159557416Smarkm			memset (&hints, 0, sizeof(hints));
159657416Smarkm			hints.ai_flags = AI_CANONNAME;
159757416Smarkm
159857416Smarkm			error = getaddrinfo (hbuf, NULL, &hints, &ai);
159957416Smarkm			if (error == 0) {
160057416Smarkm				for (a = ai; a != NULL; a = a->ai_next)
160157416Smarkm					if (a->ai_canonname != NULL) {
160257416Smarkm						strlcpy (hbuf,
160357416Smarkm							 ai->ai_canonname,
160457416Smarkm							 256);
160557416Smarkm						break;
160657416Smarkm					}
160757416Smarkm				freeaddrinfo (ai);
160857416Smarkm			}
160957416Smarkm		}
161057416Smarkm
1611178825Sdfr		error = asprintf (&cp, "%s%s", hbuf, cp2);
1612178825Sdfr		if (error != -1) {
1613178825Sdfr		    free (ep->value);
1614178825Sdfr		    ep->value = (unsigned char *)cp;
1615178825Sdfr		}
161657416Smarkm	}
161757416Smarkm	/*
161857416Smarkm	 * If USER is not defined, but LOGNAME is, then add
161957416Smarkm	 * USER with the value from LOGNAME.  By default, we
162057416Smarkm	 * don't export the USER variable.
162157416Smarkm	 */
162290926Snectar	if ((env_find((unsigned char*)"USER") == NULL) &&
162390926Snectar	    (ep = env_find((unsigned char*)"LOGNAME"))) {
162457416Smarkm		env_define((unsigned char *)"USER", ep->value);
162557416Smarkm		env_unexport((unsigned char *)"USER");
162657416Smarkm	}
162757416Smarkm	env_export((unsigned char *)"DISPLAY");
162857416Smarkm	env_export((unsigned char *)"PRINTER");
162957416Smarkm	env_export((unsigned char *)"XAUTHORITY");
163057416Smarkm}
163157416Smarkm
163257416Smarkmstruct env_lst *
163357416Smarkmenv_define(unsigned char *var, unsigned char *value)
163457416Smarkm{
163557416Smarkm	struct env_lst *ep;
163657416Smarkm
163757416Smarkm	if ((ep = env_find(var))) {
163857416Smarkm		if (ep->var)
163957416Smarkm			free(ep->var);
164057416Smarkm		if (ep->value)
164157416Smarkm			free(ep->value);
164257416Smarkm	} else {
164357416Smarkm		ep = (struct env_lst *)malloc(sizeof(struct env_lst));
164457416Smarkm		ep->next = envlisthead.next;
164557416Smarkm		envlisthead.next = ep;
164657416Smarkm		ep->prev = &envlisthead;
164757416Smarkm		if (ep->next)
164857416Smarkm			ep->next->prev = ep;
164957416Smarkm	}
165057416Smarkm	ep->welldefined = opt_welldefined((char *)var);
165157416Smarkm	ep->export = 1;
165257416Smarkm	ep->var = (unsigned char *)strdup((char *)var);
165357416Smarkm	ep->value = (unsigned char *)strdup((char *)value);
165457416Smarkm	return(ep);
165557416Smarkm}
165657416Smarkm
165757416Smarkmvoid
165857416Smarkmenv_undefine(unsigned char *var)
165957416Smarkm{
166057416Smarkm	struct env_lst *ep;
166157416Smarkm
166257416Smarkm	if ((ep = env_find(var))) {
166357416Smarkm		ep->prev->next = ep->next;
166457416Smarkm		if (ep->next)
166557416Smarkm			ep->next->prev = ep->prev;
166657416Smarkm		if (ep->var)
166757416Smarkm			free(ep->var);
166857416Smarkm		if (ep->value)
166957416Smarkm			free(ep->value);
167057416Smarkm		free(ep);
167157416Smarkm	}
167257416Smarkm}
167357416Smarkm
167457416Smarkmvoid
167557416Smarkmenv_export(unsigned char *var)
167657416Smarkm{
167757416Smarkm	struct env_lst *ep;
167857416Smarkm
167957416Smarkm	if ((ep = env_find(var)))
168057416Smarkm		ep->export = 1;
168157416Smarkm}
168257416Smarkm
168357416Smarkmvoid
168457416Smarkmenv_unexport(unsigned char *var)
168557416Smarkm{
168657416Smarkm	struct env_lst *ep;
168757416Smarkm
168857416Smarkm	if ((ep = env_find(var)))
168957416Smarkm		ep->export = 0;
169057416Smarkm}
169157416Smarkm
169257416Smarkmvoid
169357416Smarkmenv_send(unsigned char *var)
169457416Smarkm{
169557416Smarkm	struct env_lst *ep;
169657416Smarkm
169757416Smarkm	if (my_state_is_wont(TELOPT_NEW_ENVIRON)
169857416Smarkm#ifdef	OLD_ENVIRON
169957416Smarkm	    && my_state_is_wont(TELOPT_OLD_ENVIRON)
170057416Smarkm#endif
170157416Smarkm		) {
170257416Smarkm		fprintf(stderr,
170357416Smarkm		    "Cannot send '%s': Telnet ENVIRON option not enabled\r\n",
170457416Smarkm									var);
170557416Smarkm		return;
170657416Smarkm	}
170757416Smarkm	ep = env_find(var);
170857416Smarkm	if (ep == 0) {
170957416Smarkm		fprintf(stderr, "Cannot send '%s': variable not defined\r\n",
171057416Smarkm									var);
171157416Smarkm		return;
171257416Smarkm	}
171357416Smarkm	env_opt_start_info();
171457416Smarkm	env_opt_add(ep->var);
171557416Smarkm	env_opt_end(0);
171657416Smarkm}
171757416Smarkm
171857416Smarkmvoid
171957416Smarkmenv_list(void)
172057416Smarkm{
172157416Smarkm	struct env_lst *ep;
172257416Smarkm
172357416Smarkm	for (ep = envlisthead.next; ep; ep = ep->next) {
172457416Smarkm		printf("%c %-20s %s\r\n", ep->export ? '*' : ' ',
172557416Smarkm					ep->var, ep->value);
172657416Smarkm	}
172757416Smarkm}
172857416Smarkm
172957416Smarkmunsigned char *
173057416Smarkmenv_default(int init, int welldefined)
173157416Smarkm{
173257416Smarkm	static struct env_lst *nep = NULL;
173357416Smarkm
173457416Smarkm	if (init) {
173557416Smarkm		nep = &envlisthead;
173657416Smarkm		return NULL;
173757416Smarkm	}
173857416Smarkm	if (nep) {
173957416Smarkm		while ((nep = nep->next)) {
174057416Smarkm			if (nep->export && (nep->welldefined == welldefined))
174157416Smarkm				return(nep->var);
174257416Smarkm		}
174357416Smarkm	}
174457416Smarkm	return(NULL);
174557416Smarkm}
174657416Smarkm
174757416Smarkmunsigned char *
174857416Smarkmenv_getvalue(unsigned char *var)
174957416Smarkm{
175057416Smarkm	struct env_lst *ep;
175157416Smarkm
175257416Smarkm	if ((ep = env_find(var)))
175357416Smarkm		return(ep->value);
175457416Smarkm	return(NULL);
175557416Smarkm}
175657416Smarkm
175757416Smarkm
175857416Smarkm#if	defined(AUTHENTICATION)
175957416Smarkm/*
176057416Smarkm * The AUTHENTICATE command.
176157416Smarkm */
176257416Smarkm
176357416Smarkmstruct authlist {
176457416Smarkm	char	*name;
176557416Smarkm	char	*help;
176657416Smarkm	int	(*handler)();
176757416Smarkm	int	narg;
176857416Smarkm};
176957416Smarkm
177057416Smarkmstatic int
177157416Smarkm	auth_help (void);
177257416Smarkm
177357416Smarkmstruct authlist AuthList[] = {
177457416Smarkm    { "status",	"Display current status of authentication information",
177557416Smarkm						auth_status,	0 },
177657416Smarkm    { "disable", "Disable an authentication type ('auth disable ?' for more)",
177757416Smarkm						auth_disable,	1 },
177857416Smarkm    { "enable", "Enable an authentication type ('auth enable ?' for more)",
177957416Smarkm						auth_enable,	1 },
178057416Smarkm    { "help",	0,				auth_help,		0 },
178157416Smarkm    { "?",	"Print help information",	auth_help,		0 },
178257416Smarkm    { 0 },
178357416Smarkm};
178457416Smarkm
178557416Smarkmstatic int
178657416Smarkmauth_help()
178757416Smarkm{
178857416Smarkm    struct authlist *c;
178957416Smarkm
179057416Smarkm    for (c = AuthList; c->name; c++) {
179157416Smarkm	if (c->help) {
179257416Smarkm	    if (*c->help)
179357416Smarkm		printf("%-15s %s\r\n", c->name, c->help);
179457416Smarkm	    else
179557416Smarkm		printf("\r\n");
179657416Smarkm	}
179757416Smarkm    }
179857416Smarkm    return 0;
179957416Smarkm}
180057416Smarkm
180157416Smarkmstatic int
180257416Smarkmauth_cmd(int argc, char **argv)
180357416Smarkm{
180457416Smarkm    struct authlist *c;
180557416Smarkm
180657416Smarkm    if (argc < 2) {
180757416Smarkm	fprintf(stderr,
180857416Smarkm	    "Need an argument to 'auth' command.  'auth ?' for help.\r\n");
180957416Smarkm	return 0;
181057416Smarkm    }
181157416Smarkm
181257416Smarkm    c = (struct authlist *)
181357416Smarkm		genget(argv[1], (char **) AuthList, sizeof(struct authlist));
181457416Smarkm    if (c == 0) {
181557416Smarkm	fprintf(stderr, "'%s': unknown argument ('auth ?' for help).\r\n",
181657416Smarkm    				argv[1]);
181757416Smarkm	return 0;
181857416Smarkm    }
181957416Smarkm    if (Ambiguous(c)) {
182057416Smarkm	fprintf(stderr, "'%s': ambiguous argument ('auth ?' for help).\r\n",
182157416Smarkm    				argv[1]);
182257416Smarkm	return 0;
182357416Smarkm    }
182457416Smarkm    if (c->narg + 2 != argc) {
182557416Smarkm	fprintf(stderr,
182657416Smarkm	    "Need %s%d argument%s to 'auth %s' command.  'auth ?' for help.\r\n",
182757416Smarkm		c->narg < argc + 2 ? "only " : "",
182857416Smarkm		c->narg, c->narg == 1 ? "" : "s", c->name);
182957416Smarkm	return 0;
183057416Smarkm    }
183157416Smarkm    return((*c->handler)(argv[2], argv[3]));
183257416Smarkm}
183357416Smarkm#endif
183457416Smarkm
183557416Smarkm
183657416Smarkm#if	defined(ENCRYPTION)
183757416Smarkm/*
183857416Smarkm * The ENCRYPT command.
183957416Smarkm */
184057416Smarkm
184157416Smarkmstruct encryptlist {
184257416Smarkm	char	*name;
184357416Smarkm	char	*help;
184457416Smarkm	int	(*handler)();
184557416Smarkm	int	needconnect;
184657416Smarkm	int	minarg;
184757416Smarkm	int	maxarg;
184857416Smarkm};
184957416Smarkm
185057416Smarkmstatic int
185157416Smarkm	EncryptHelp (void);
185257416Smarkm
185357416Smarkmstruct encryptlist EncryptList[] = {
185457416Smarkm    { "enable", "Enable encryption. ('encrypt enable ?' for more)",
185557416Smarkm						EncryptEnable, 1, 1, 2 },
185657416Smarkm    { "disable", "Disable encryption. ('encrypt enable ?' for more)",
185757416Smarkm						EncryptDisable, 0, 1, 2 },
185857416Smarkm    { "type", "Set encryptiong type. ('encrypt type ?' for more)",
185957416Smarkm						EncryptType, 0, 1, 1 },
186057416Smarkm    { "start", "Start encryption. ('encrypt start ?' for more)",
186157416Smarkm						EncryptStart, 1, 0, 1 },
186257416Smarkm    { "stop", "Stop encryption. ('encrypt stop ?' for more)",
186357416Smarkm						EncryptStop, 1, 0, 1 },
186457416Smarkm    { "input", "Start encrypting the input stream",
186557416Smarkm						EncryptStartInput, 1, 0, 0 },
186657416Smarkm    { "-input", "Stop encrypting the input stream",
186757416Smarkm						EncryptStopInput, 1, 0, 0 },
186857416Smarkm    { "output", "Start encrypting the output stream",
186957416Smarkm						EncryptStartOutput, 1, 0, 0 },
187057416Smarkm    { "-output", "Stop encrypting the output stream",
187157416Smarkm						EncryptStopOutput, 1, 0, 0 },
187257416Smarkm
187357416Smarkm    { "status",	"Display current status of authentication information",
187457416Smarkm						EncryptStatus,	0, 0, 0 },
187557416Smarkm    { "help",	0,				EncryptHelp,	0, 0, 0 },
187657416Smarkm    { "?",	"Print help information",	EncryptHelp,	0, 0, 0 },
187757416Smarkm    { 0 },
187857416Smarkm};
187957416Smarkm
188057416Smarkmstatic int
188157416SmarkmEncryptHelp()
188257416Smarkm{
188357416Smarkm    struct encryptlist *c;
188457416Smarkm
188557416Smarkm    for (c = EncryptList; c->name; c++) {
188657416Smarkm	if (c->help) {
188757416Smarkm	    if (*c->help)
188857416Smarkm		printf("%-15s %s\r\n", c->name, c->help);
188957416Smarkm	    else
189057416Smarkm		printf("\r\n");
189157416Smarkm	}
189257416Smarkm    }
189357416Smarkm    return 0;
189457416Smarkm}
189557416Smarkm
189657416Smarkmstatic int
189757416Smarkmencrypt_cmd(int argc, char **argv)
189857416Smarkm{
189957416Smarkm    struct encryptlist *c;
190057416Smarkm
190157416Smarkm    c = (struct encryptlist *)
190257416Smarkm		genget(argv[1], (char **) EncryptList, sizeof(struct encryptlist));
190357416Smarkm    if (c == 0) {
190457416Smarkm        fprintf(stderr, "'%s': unknown argument ('encrypt ?' for help).\r\n",
190557416Smarkm    				argv[1]);
190657416Smarkm        return 0;
190757416Smarkm    }
190857416Smarkm    if (Ambiguous(c)) {
190957416Smarkm        fprintf(stderr, "'%s': ambiguous argument ('encrypt ?' for help).\r\n",
191057416Smarkm    				argv[1]);
191157416Smarkm        return 0;
191257416Smarkm    }
191357416Smarkm    argc -= 2;
191457416Smarkm    if (argc < c->minarg || argc > c->maxarg) {
191557416Smarkm	if (c->minarg == c->maxarg) {
191657416Smarkm	    fprintf(stderr, "Need %s%d argument%s ",
191757416Smarkm		c->minarg < argc ? "only " : "", c->minarg,
191857416Smarkm		c->minarg == 1 ? "" : "s");
191957416Smarkm	} else {
192057416Smarkm	    fprintf(stderr, "Need %s%d-%d arguments ",
192157416Smarkm		c->maxarg < argc ? "only " : "", c->minarg, c->maxarg);
192257416Smarkm	}
192357416Smarkm	fprintf(stderr, "to 'encrypt %s' command.  'encrypt ?' for help.\r\n",
192457416Smarkm		c->name);
192557416Smarkm	return 0;
192657416Smarkm    }
192757416Smarkm    if (c->needconnect && !connected) {
192857416Smarkm	if (!(argc && (isprefix(argv[2], "help") || isprefix(argv[2], "?")))) {
192957416Smarkm	    printf("?Need to be connected first.\r\n");
193057416Smarkm	    return 0;
193157416Smarkm	}
193257416Smarkm    }
193357416Smarkm    return ((*c->handler)(argc > 0 ? argv[2] : 0,
193457416Smarkm			argc > 1 ? argv[3] : 0,
193557416Smarkm			argc > 2 ? argv[4] : 0));
193657416Smarkm}
193757416Smarkm#endif
193857416Smarkm
193957416Smarkm
194057416Smarkm/*
194157416Smarkm * Print status about the connection.
194257416Smarkm */
194357416Smarkm
194457416Smarkmstatic int
194557416Smarkmstatus(int argc, char **argv)
194657416Smarkm{
194757416Smarkm    if (connected) {
194857416Smarkm	printf("Connected to %s.\r\n", hostname);
194957416Smarkm	if ((argc < 2) || strcmp(argv[1], "notmuch")) {
195057416Smarkm	    int mode = getconnmode();
195157416Smarkm
195257416Smarkm	    if (my_want_state_is_will(TELOPT_LINEMODE)) {
195357416Smarkm		printf("Operating with LINEMODE option\r\n");
195457416Smarkm		printf("%s line editing\r\n", (mode&MODE_EDIT) ? "Local" : "No");
195557416Smarkm		printf("%s catching of signals\r\n",
195657416Smarkm					(mode&MODE_TRAPSIG) ? "Local" : "No");
195757416Smarkm		slcstate();
195857416Smarkm#ifdef	KLUDGELINEMODE
195957416Smarkm	    } else if (kludgelinemode && my_want_state_is_dont(TELOPT_SGA)) {
196057416Smarkm		printf("Operating in obsolete linemode\r\n");
196157416Smarkm#endif
196257416Smarkm	    } else {
196357416Smarkm		printf("Operating in single character mode\r\n");
196457416Smarkm		if (localchars)
196557416Smarkm		    printf("Catching signals locally\r\n");
196657416Smarkm	    }
196757416Smarkm	    printf("%s character echo\r\n", (mode&MODE_ECHO) ? "Local" : "Remote");
196857416Smarkm	    if (my_want_state_is_will(TELOPT_LFLOW))
196957416Smarkm		printf("%s flow control\r\n", (mode&MODE_FLOW) ? "Local" : "No");
197057416Smarkm#if	defined(ENCRYPTION)
197157416Smarkm	    encrypt_display();
197257416Smarkm#endif
197357416Smarkm	}
197457416Smarkm    } else {
197557416Smarkm	printf("No connection.\r\n");
197657416Smarkm    }
197757416Smarkm    printf("Escape character is '%s'.\r\n", control(escape));
197857416Smarkm    fflush(stdout);
197957416Smarkm    return 1;
198057416Smarkm}
198157416Smarkm
198257416Smarkm#ifdef	SIGINFO
198357416Smarkm/*
198457416Smarkm * Function that gets called when SIGINFO is received.
198557416Smarkm */
198678527SassarRETSIGTYPE
198757416Smarkmayt_status(int ignore)
198857416Smarkm{
198957416Smarkm    call(status, "status", "notmuch", 0);
199057416Smarkm}
199157416Smarkm#endif
199257416Smarkm
199357416Smarkmstatic Command *getcmd(char *name);
199457416Smarkm
199557416Smarkmstatic void
199657416Smarkmcmdrc(char *m1, char *m2)
199757416Smarkm{
199857416Smarkm    static char rcname[128];
199957416Smarkm    Command *c;
200057416Smarkm    FILE *rcfile;
200157416Smarkm    int gotmachine = 0;
200257416Smarkm    int l1 = strlen(m1);
200357416Smarkm    int l2 = strlen(m2);
200457416Smarkm    char m1save[64];
200557416Smarkm
200657416Smarkm    if (skiprc)
200757416Smarkm	return;
200857416Smarkm
200957416Smarkm    strlcpy(m1save, m1, sizeof(m1save));
201057416Smarkm    m1 = m1save;
201157416Smarkm
201257416Smarkm    if (rcname[0] == 0) {
201357416Smarkm	char *home = getenv("HOME");
201457416Smarkm
201557416Smarkm	snprintf (rcname, sizeof(rcname), "%s/.telnetrc",
201657416Smarkm		  home ? home : "");
201757416Smarkm    }
201857416Smarkm
201957416Smarkm    if ((rcfile = fopen(rcname, "r")) == 0) {
202057416Smarkm	return;
202157416Smarkm    }
202257416Smarkm
202357416Smarkm    for (;;) {
202457416Smarkm	if (fgets(line, sizeof(line), rcfile) == NULL)
202557416Smarkm	    break;
202657416Smarkm	if (line[0] == 0)
202757416Smarkm	    break;
202857416Smarkm	if (line[0] == '#')
202957416Smarkm	    continue;
203057416Smarkm	if (gotmachine) {
2031178825Sdfr	    if (!isspace((unsigned char)line[0]))
203257416Smarkm		gotmachine = 0;
203357416Smarkm	}
203457416Smarkm	if (gotmachine == 0) {
2035178825Sdfr	    if (isspace((unsigned char)line[0]))
203657416Smarkm		continue;
203757416Smarkm	    if (strncasecmp(line, m1, l1) == 0)
203857416Smarkm		strncpy(line, &line[l1], sizeof(line) - l1);
203957416Smarkm	    else if (strncasecmp(line, m2, l2) == 0)
204057416Smarkm		strncpy(line, &line[l2], sizeof(line) - l2);
204157416Smarkm	    else if (strncasecmp(line, "DEFAULT", 7) == 0)
204257416Smarkm		strncpy(line, &line[7], sizeof(line) - 7);
204357416Smarkm	    else
204457416Smarkm		continue;
204557416Smarkm	    if (line[0] != ' ' && line[0] != '\t' && line[0] != '\n')
204657416Smarkm		continue;
204757416Smarkm	    gotmachine = 1;
204857416Smarkm	}
204957416Smarkm	makeargv();
205057416Smarkm	if (margv[0] == 0)
205157416Smarkm	    continue;
205257416Smarkm	c = getcmd(margv[0]);
205357416Smarkm	if (Ambiguous(c)) {
205457416Smarkm	    printf("?Ambiguous command: %s\r\n", margv[0]);
205557416Smarkm	    continue;
205657416Smarkm	}
205757416Smarkm	if (c == 0) {
205857416Smarkm	    printf("?Invalid command: %s\r\n", margv[0]);
205957416Smarkm	    continue;
206057416Smarkm	}
206157416Smarkm	/*
206257416Smarkm	 * This should never happen...
206357416Smarkm	 */
206457416Smarkm	if (c->needconnect && !connected) {
206557416Smarkm	    printf("?Need to be connected first for %s.\r\n", margv[0]);
206657416Smarkm	    continue;
206757416Smarkm	}
206857416Smarkm	(*c->handler)(margc, margv);
206957416Smarkm    }
207057416Smarkm    fclose(rcfile);
207157416Smarkm}
207257416Smarkm
207357416Smarkmint
207457416Smarkmtn(int argc, char **argv)
207557416Smarkm{
207657416Smarkm    struct servent *sp = 0;
207757416Smarkm    char *cmd, *hostp = 0, *portp = 0;
207857416Smarkm    char *user = 0;
207957416Smarkm    int port = 0;
208057416Smarkm
208157416Smarkm    /* clear the socket address prior to use */
208257416Smarkm
208357416Smarkm    if (connected) {
208457416Smarkm	printf("?Already connected to %s\r\n", hostname);
208557416Smarkm	return 0;
208657416Smarkm    }
208757416Smarkm    if (argc < 2) {
208857416Smarkm	strlcpy(line, "open ", sizeof(line));
208957416Smarkm	printf("(to) ");
209057416Smarkm	fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin);
209157416Smarkm	makeargv();
209257416Smarkm	argc = margc;
209357416Smarkm	argv = margv;
209457416Smarkm    }
209557416Smarkm    cmd = *argv;
209657416Smarkm    --argc; ++argv;
209757416Smarkm    while (argc) {
209857416Smarkm	if (strcmp(*argv, "help") == 0 || isprefix(*argv, "?"))
209957416Smarkm	    goto usage;
210057416Smarkm	if (strcmp(*argv, "-l") == 0) {
210157416Smarkm	    --argc; ++argv;
210257416Smarkm	    if (argc == 0)
210357416Smarkm		goto usage;
210457416Smarkm	    user = strdup(*argv++);
210557416Smarkm	    --argc;
210657416Smarkm	    continue;
210757416Smarkm	}
210857416Smarkm	if (strcmp(*argv, "-a") == 0) {
210957416Smarkm	    --argc; ++argv;
211057416Smarkm	    autologin = 1;
211157416Smarkm	    continue;
211257416Smarkm	}
211357416Smarkm	if (hostp == 0) {
211457416Smarkm	    hostp = *argv++;
211557416Smarkm	    --argc;
211657416Smarkm	    continue;
211757416Smarkm	}
211857416Smarkm	if (portp == 0) {
211957416Smarkm	    portp = *argv++;
212057416Smarkm	    --argc;
212157416Smarkm	    continue;
212257416Smarkm	}
212357416Smarkm    usage:
212457416Smarkm	printf("usage: %s [-l user] [-a] host-name [port]\r\n", cmd);
212557416Smarkm	return 0;
212657416Smarkm    }
212757416Smarkm    if (hostp == 0)
212857416Smarkm	goto usage;
212957416Smarkm
213072445Sassar    strlcpy (_hostname, hostp, sizeof(_hostname));
213178527Sassar    hostp = _hostname;
213272445Sassar    if (hostp[0] == '@' || hostp[0] == '!') {
213372445Sassar	char *p;
213472445Sassar	hostname = NULL;
213572445Sassar	for (p = hostp + 1; *p; p++) {
213672445Sassar	    if (*p == ',' || *p == '@')
213772445Sassar		hostname = p;
213872445Sassar	}
213972445Sassar	if (hostname == NULL) {
214072445Sassar	    fprintf(stderr, "%s: bad source route specification\n", hostp);
214172445Sassar	    return 0;
214272445Sassar	}
214372445Sassar	*hostname++ = '\0';
214472445Sassar    } else
214572445Sassar	hostname = hostp;
214672445Sassar
214757416Smarkm    if (portp) {
214857416Smarkm	if (*portp == '-') {
214957416Smarkm	    portp++;
215057416Smarkm	    telnetport = 1;
215157416Smarkm	} else
215257416Smarkm	    telnetport = 0;
215357416Smarkm	port = atoi(portp);
215457416Smarkm	if (port == 0) {
215557416Smarkm	    sp = roken_getservbyname(portp, "tcp");
215657416Smarkm	    if (sp)
215757416Smarkm		port = sp->s_port;
215857416Smarkm	    else {
215957416Smarkm		printf("%s: bad port number\r\n", portp);
216057416Smarkm		return 0;
216157416Smarkm	    }
216257416Smarkm	} else {
216357416Smarkm	    port = htons(port);
216457416Smarkm	}
216557416Smarkm    } else {
216657416Smarkm	if (sp == 0) {
216757416Smarkm	    sp = roken_getservbyname("telnet", "tcp");
216857416Smarkm	    if (sp == 0) {
216957416Smarkm		fprintf(stderr, "telnet: tcp/telnet: unknown service\r\n");
217057416Smarkm		return 0;
217157416Smarkm	    }
217257416Smarkm	    port = sp->s_port;
217357416Smarkm	}
217457416Smarkm	telnetport = 1;
217557416Smarkm    }
217657416Smarkm
217757416Smarkm    {
217857416Smarkm	struct addrinfo *ai, *a, hints;
217957416Smarkm	int error;
218057416Smarkm	char portstr[NI_MAXSERV];
218157416Smarkm
218257416Smarkm	memset (&hints, 0, sizeof(hints));
218357416Smarkm	hints.ai_socktype = SOCK_STREAM;
218457416Smarkm	hints.ai_protocol = IPPROTO_TCP;
218557416Smarkm	hints.ai_flags    = AI_CANONNAME;
218657416Smarkm
218757416Smarkm	snprintf (portstr, sizeof(portstr), "%u", ntohs(port));
218857416Smarkm
218972445Sassar	error = getaddrinfo (hostname, portstr, &hints, &ai);
219057416Smarkm	if (error) {
219172445Sassar	    fprintf (stderr, "%s: %s\r\n", hostname, gai_strerror (error));
219257416Smarkm	    return 0;
219357416Smarkm	}
219457416Smarkm
219557416Smarkm	for (a = ai; a != NULL && connected == 0; a = a->ai_next) {
219657416Smarkm	    char addrstr[256];
219757416Smarkm
219857416Smarkm	    if (a->ai_canonname != NULL)
219957416Smarkm		strlcpy (_hostname, a->ai_canonname, sizeof(_hostname));
220057416Smarkm
220157416Smarkm	    if (getnameinfo (a->ai_addr, a->ai_addrlen,
220257416Smarkm			     addrstr, sizeof(addrstr),
220357416Smarkm			     NULL, 0, NI_NUMERICHOST) != 0)
220457416Smarkm		strlcpy (addrstr, "unknown address", sizeof(addrstr));
220557416Smarkm
220657416Smarkm	    printf("Trying %s...\r\n", addrstr);
220757416Smarkm
220857416Smarkm	    net = socket (a->ai_family, a->ai_socktype, a->ai_protocol);
220957416Smarkm	    if (net < 0) {
221072445Sassar		warn ("socket");
221157416Smarkm		continue;
221257416Smarkm	    }
221372445Sassar
221457416Smarkm#if	defined(IP_OPTIONS) && defined(IPPROTO_IP) && defined(HAVE_SETSOCKOPT)
221572445Sassar	if (hostp[0] == '@' || hostp[0] == '!') {
221672445Sassar	    char *srp = 0;
221772445Sassar	    int srlen;
221872445Sassar	    int proto, opt;
221972445Sassar
222072445Sassar	    if ((srlen = sourceroute(a, hostp, &srp, &proto, &opt)) < 0) {
222172445Sassar		(void) NetClose(net);
222272445Sassar		net = -1;
222372445Sassar		continue;
222472445Sassar	    }
222572445Sassar	    if (srp && setsockopt(net, proto, opt, srp, srlen) < 0)
222672445Sassar		perror("setsockopt (source route)");
222772445Sassar	}
222857416Smarkm#endif
222972445Sassar
223057416Smarkm#if	defined(IPPROTO_IP) && defined(IP_TOS)
223157419Smarkm	    if (a->ai_family == AF_INET) {
223257416Smarkm# if	defined(HAVE_GETTOSBYNAME)
223357416Smarkm		struct tosent *tp;
223457416Smarkm		if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
223557416Smarkm		    tos = tp->t_tos;
223657416Smarkm# endif
223757416Smarkm		if (tos < 0)
223857416Smarkm		    tos = 020;	/* Low Delay bit */
223957416Smarkm		if (tos
224057416Smarkm		    && (setsockopt(net, IPPROTO_IP, IP_TOS,
224157416Smarkm				   (void *)&tos, sizeof(int)) < 0)
224257416Smarkm		    && (errno != ENOPROTOOPT))
224357416Smarkm		    perror("telnet: setsockopt (IP_TOS) (ignored)");
224457416Smarkm	    }
224557416Smarkm#endif	/* defined(IPPROTO_IP) && defined(IP_TOS) */
224657416Smarkm	    if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) {
224757416Smarkm		perror("setsockopt (SO_DEBUG)");
224857416Smarkm	    }
224957416Smarkm
225057416Smarkm	    if (connect (net, a->ai_addr, a->ai_addrlen) < 0) {
225157416Smarkm		fprintf (stderr, "telnet: connect to address %s: %s\n",
225257416Smarkm			 addrstr, strerror(errno));
225357416Smarkm		NetClose(net);
225457416Smarkm		if (a->ai_next != NULL) {
225557416Smarkm		    continue;
225657416Smarkm		} else {
225757416Smarkm		    freeaddrinfo (ai);
225857416Smarkm		    return 0;
225957416Smarkm		}
226057416Smarkm	    }
226157416Smarkm	    ++connected;
226257416Smarkm#if	defined(AUTHENTICATION) || defined(ENCRYPTION)
226357416Smarkm	    auth_encrypt_connect(connected);
226457416Smarkm#endif
226557416Smarkm	}
226672445Sassar	freeaddrinfo (ai);
226772445Sassar	if (connected == 0)
226872445Sassar	    return 0;
226957416Smarkm    }
227057416Smarkm    cmdrc(hostp, hostname);
2271102644Snectar    set_forward_options();
227257416Smarkm    if (autologin && user == NULL)
227357416Smarkm	user = (char *)get_default_username ();
227457416Smarkm    if (user) {
227557416Smarkm	env_define((unsigned char *)"USER", (unsigned char *)user);
227657416Smarkm	env_export((unsigned char *)"USER");
227757416Smarkm    }
227857416Smarkm    call(status, "status", "notmuch", 0);
227957416Smarkm    if (setjmp(peerdied) == 0)
228057416Smarkm	my_telnet((char *)user);
228157416Smarkm    NetClose(net);
228257416Smarkm    ExitString("Connection closed by foreign host.\r\n",1);
228357416Smarkm    /*NOTREACHED*/
228457416Smarkm    return 0;
228557416Smarkm}
228657416Smarkm
228757416Smarkm#define HELPINDENT ((int)sizeof ("connect"))
228857416Smarkm
228957416Smarkmstatic char
229057416Smarkm	openhelp[] =	"connect to a site",
229157416Smarkm	closehelp[] =	"close current connection",
229257416Smarkm	logouthelp[] =	"forcibly logout remote user and close the connection",
229357416Smarkm	quithelp[] =	"exit telnet",
229457416Smarkm	statushelp[] =	"print status information",
229557416Smarkm	helphelp[] =	"print help information",
229657416Smarkm	sendhelp[] =	"transmit special characters ('send ?' for more)",
229757416Smarkm	sethelp[] = 	"set operating parameters ('set ?' for more)",
229857416Smarkm	unsethelp[] = 	"unset operating parameters ('unset ?' for more)",
229957416Smarkm	togglestring[] ="toggle operating parameters ('toggle ?' for more)",
230057416Smarkm	slchelp[] =	"change state of special charaters ('slc ?' for more)",
230157416Smarkm	displayhelp[] =	"display operating parameters",
230257416Smarkm#if	defined(AUTHENTICATION)
230357416Smarkm	authhelp[] =	"turn on (off) authentication ('auth ?' for more)",
230457416Smarkm#endif
230557416Smarkm#if	defined(ENCRYPTION)
230657416Smarkm	encrypthelp[] =	"turn on (off) encryption ('encrypt ?' for more)",
230757416Smarkm#endif
230857416Smarkm	zhelp[] =	"suspend telnet",
230957416Smarkm	shellhelp[] =	"invoke a subshell",
231057416Smarkm	envhelp[] =	"change environment variables ('environ ?' for more)",
231157416Smarkm	modestring[] = "try to enter line or character mode ('mode ?' for more)";
231257416Smarkm
231357416Smarkmstatic int help(int argc, char **argv);
231457416Smarkm
231557416Smarkmstatic Command cmdtab[] = {
231657416Smarkm	{ "close",	closehelp,	bye,		1 },
231757416Smarkm	{ "logout",	logouthelp,	logout,		1 },
231857416Smarkm	{ "display",	displayhelp,	display,	0 },
231957416Smarkm	{ "mode",	modestring,	modecmd,	0 },
232057416Smarkm	{ "open",	openhelp,	tn,		0 },
232157416Smarkm	{ "quit",	quithelp,	quit,		0 },
232257416Smarkm	{ "send",	sendhelp,	sendcmd,	0 },
232357416Smarkm	{ "set",	sethelp,	setcmd,		0 },
232457416Smarkm	{ "unset",	unsethelp,	unsetcmd,	0 },
232557416Smarkm	{ "status",	statushelp,	status,		0 },
232657416Smarkm	{ "toggle",	togglestring,	toggle,		0 },
232757416Smarkm	{ "slc",	slchelp,	slccmd,		0 },
232857416Smarkm#if	defined(AUTHENTICATION)
232957416Smarkm	{ "auth",	authhelp,	auth_cmd,	0 },
233057416Smarkm#endif
233157416Smarkm#if	defined(ENCRYPTION)
233257416Smarkm	{ "encrypt",	encrypthelp,	encrypt_cmd,	0 },
233357416Smarkm#endif
233457416Smarkm	{ "z",		zhelp,		telnetsuspend,	0 },
233557416Smarkm	{ "!",		shellhelp,	shell,		0 },
233657416Smarkm	{ "environ",	envhelp,	env_cmd,	0 },
233757416Smarkm	{ "?",		helphelp,	help,		0 },
233857416Smarkm	{ 0,            0,              0,              0 }
233957416Smarkm};
234057416Smarkm
234157416Smarkmstatic char	crmodhelp[] =	"deprecated command -- use 'toggle crmod' instead";
234257416Smarkmstatic char	escapehelp[] =	"deprecated command -- use 'set escape' instead";
234357416Smarkm
234457416Smarkmstatic Command cmdtab2[] = {
234557416Smarkm	{ "help",	0,		help,		0 },
234657416Smarkm	{ "escape",	escapehelp,	setescape,	0 },
234757416Smarkm	{ "crmod",	crmodhelp,	togcrmod,	0 },
234857416Smarkm	{ 0,            0,		0, 		0 }
234957416Smarkm};
235057416Smarkm
235157416Smarkm
235257416Smarkm/*
235357416Smarkm * Call routine with argc, argv set from args (terminated by 0).
235457416Smarkm */
235557416Smarkm
235657416Smarkmstatic int
235757416Smarkmcall(intrtn_t routine, ...)
235857416Smarkm{
235957416Smarkm    va_list ap;
236057416Smarkm    char *args[100];
236157416Smarkm    int argno = 0;
236257416Smarkm
236357416Smarkm    va_start(ap, routine);
236457416Smarkm    while ((args[argno++] = va_arg(ap, char *)) != 0);
236557416Smarkm    va_end(ap);
236657416Smarkm    return (*routine)(argno-1, args);
236757416Smarkm}
236857416Smarkm
236957416Smarkm
237057416Smarkmstatic Command
237157416Smarkm*getcmd(char *name)
237257416Smarkm{
237357416Smarkm    Command *cm;
237457416Smarkm
237557416Smarkm    if ((cm = (Command *) genget(name, (char **) cmdtab, sizeof(Command))))
237657416Smarkm	return cm;
237757416Smarkm    return (Command *) genget(name, (char **) cmdtab2, sizeof(Command));
237857416Smarkm}
237957416Smarkm
238057416Smarkmvoid
238157416Smarkmcommand(int top, char *tbuf, int cnt)
238257416Smarkm{
238357416Smarkm    Command *c;
238457416Smarkm
238557416Smarkm    setcommandmode();
238657416Smarkm    if (!top) {
238757416Smarkm	putchar('\n');
238857416Smarkm    } else {
238957416Smarkm	signal(SIGINT, SIG_DFL);
239057416Smarkm	signal(SIGQUIT, SIG_DFL);
239157416Smarkm    }
239257416Smarkm    for (;;) {
239357416Smarkm	if (rlogin == _POSIX_VDISABLE)
239457416Smarkm		printf("%s> ", prompt);
239557416Smarkm	if (tbuf) {
239657416Smarkm	    char *cp;
239757416Smarkm	    cp = line;
239857416Smarkm	    while (cnt > 0 && (*cp++ = *tbuf++) != '\n')
239957416Smarkm		cnt--;
240057416Smarkm	    tbuf = 0;
240157416Smarkm	    if (cp == line || *--cp != '\n' || cp == line)
240257416Smarkm		goto getline;
240357416Smarkm	    *cp = '\0';
240457416Smarkm	    if (rlogin == _POSIX_VDISABLE)
240557416Smarkm		printf("%s\r\n", line);
240657416Smarkm	} else {
240757416Smarkm	getline:
240857416Smarkm	    if (rlogin != _POSIX_VDISABLE)
240957416Smarkm		printf("%s> ", prompt);
241057416Smarkm	    if (fgets(line, sizeof(line), stdin) == NULL) {
241157416Smarkm		if (feof(stdin) || ferror(stdin)) {
241257416Smarkm		    quit();
241357416Smarkm		    /*NOTREACHED*/
241457416Smarkm		}
241557416Smarkm		break;
241657416Smarkm	    }
241757416Smarkm	}
241857416Smarkm	if (line[0] == 0)
241957416Smarkm	    break;
242057416Smarkm	makeargv();
242157416Smarkm	if (margv[0] == 0) {
242257416Smarkm	    break;
242357416Smarkm	}
242457416Smarkm	c = getcmd(margv[0]);
242557416Smarkm	if (Ambiguous(c)) {
242657416Smarkm	    printf("?Ambiguous command\r\n");
242757416Smarkm	    continue;
242857416Smarkm	}
242957416Smarkm	if (c == 0) {
243057416Smarkm	    printf("?Invalid command\r\n");
243157416Smarkm	    continue;
243257416Smarkm	}
243357416Smarkm	if (c->needconnect && !connected) {
243457416Smarkm	    printf("?Need to be connected first.\r\n");
243557416Smarkm	    continue;
243657416Smarkm	}
243757416Smarkm	if ((*c->handler)(margc, margv)) {
243857416Smarkm	    break;
243957416Smarkm	}
244057416Smarkm    }
244157416Smarkm    if (!top) {
244257416Smarkm	if (!connected) {
244357416Smarkm	    longjmp(toplevel, 1);
244457416Smarkm	    /*NOTREACHED*/
244557416Smarkm	}
244657416Smarkm	setconnmode(0);
244757416Smarkm    }
244857416Smarkm}
244957416Smarkm
245057416Smarkm/*
245157416Smarkm * Help command.
245257416Smarkm */
245357416Smarkmstatic int
245457416Smarkmhelp(int argc, char **argv)
245557416Smarkm{
245657416Smarkm	Command *c;
245757416Smarkm
245857416Smarkm	if (argc == 1) {
245957416Smarkm		printf("Commands may be abbreviated.  Commands are:\r\n\r\n");
246057416Smarkm		for (c = cmdtab; c->name; c++)
246157416Smarkm			if (c->help) {
246257416Smarkm				printf("%-*s\t%s\r\n", HELPINDENT, c->name,
246357416Smarkm								    c->help);
246457416Smarkm			}
246557416Smarkm		return 0;
246657416Smarkm	}
246757416Smarkm	while (--argc > 0) {
246857416Smarkm		char *arg;
246957416Smarkm		arg = *++argv;
247057416Smarkm		c = getcmd(arg);
247157416Smarkm		if (Ambiguous(c))
247257416Smarkm			printf("?Ambiguous help command %s\r\n", arg);
247357416Smarkm		else if (c == (Command *)0)
247457416Smarkm			printf("?Invalid help command %s\r\n", arg);
247557416Smarkm		else
247657416Smarkm			printf("%s\r\n", c->help);
247757416Smarkm	}
247857416Smarkm	return 0;
247957416Smarkm}
248057416Smarkm
248157416Smarkm
248257416Smarkm#if	defined(IP_OPTIONS) && defined(IPPROTO_IP)
248357416Smarkm
248457416Smarkm/*
248557416Smarkm * Source route is handed in as
248672445Sassar *	[!]@hop1@hop2...@dst
248757416Smarkm *
248872445Sassar * If the leading ! is present, it is a strict source route, otherwise it is
248972445Sassar * assmed to be a loose source route.  Note that leading ! is effective
249072445Sassar * only for IPv4 case.
249172445Sassar *
249257416Smarkm * We fill in the source route option as
249357416Smarkm *	hop1,hop2,hop3...dest
249457416Smarkm * and return a pointer to hop1, which will
249557416Smarkm * be the address to connect() to.
249657416Smarkm *
249757416Smarkm * Arguments:
249872445Sassar *	ai:	The address (by struct addrinfo) for the final destination.
249957416Smarkm *
250072445Sassar *	arg:	Pointer to route list to decipher
250157416Smarkm *
250272445Sassar *	cpp: 	Pointer to a pointer, so that sourceroute() can return
250372445Sassar *		the address of result buffer (statically alloc'ed).
250472445Sassar *
250572445Sassar *	protop/optp:
250672445Sassar *		Pointer to an integer.  The pointed variable
250757416Smarkm *	lenp:	pointer to an integer that contains the
250857416Smarkm *		length of *cpp if *cpp != NULL.
250957416Smarkm *
251057416Smarkm * Return values:
251157416Smarkm *
251272445Sassar *	Returns the length of the option pointed to by *cpp.  If the
251357416Smarkm *	return value is -1, there was a syntax error in the
251472445Sassar *	option, either arg contained unknown characters or too many hosts,
251572445Sassar *	or hostname cannot be resolved.
251657416Smarkm *
251772445Sassar *	The caller needs to pass return value (len), *cpp, *protop and *optp
251872445Sassar *	to setsockopt(2).
251957416Smarkm *
252072445Sassar *	*cpp:	Points to the result buffer.  The region is statically
252172445Sassar *		allocated by the function.
252257416Smarkm *
252372445Sassar *	*protop:
252472445Sassar *		protocol # to be passed to setsockopt(2).
252572445Sassar *
252672445Sassar *	*optp:	option # to be passed to setsockopt(2).
252772445Sassar *
252857416Smarkm */
252972445Sassarint
253072445Sassarsourceroute(struct addrinfo *ai,
253172445Sassar	    char *arg,
253272445Sassar	    char **cpp,
253372445Sassar	    int *protop,
253472445Sassar	    int *optp)
253557416Smarkm{
2536102644Snectar	char *cp, *cp2, *lsrp = NULL, *lsrep = NULL;
253772445Sassar	struct addrinfo hints, *res;
253872445Sassar	int len, error;
253972445Sassar	struct sockaddr_in *sin;
254072445Sassar	register char c;
254157416Smarkm	static char lsr[44];
254272445Sassar#ifdef INET6
2543102644Snectar	struct cmsghdr *cmsg = NULL;
254472445Sassar	struct sockaddr_in6 *sin6;
254572445Sassar	static char rhbuf[1024];
254672445Sassar#endif
254757416Smarkm
254857416Smarkm	/*
254972445Sassar	 * Verify the arguments.
255057416Smarkm	 */
255172445Sassar	if (cpp == NULL)
255272445Sassar		return -1;
255357416Smarkm
255457416Smarkm	cp = arg;
255557416Smarkm
255672445Sassar	*cpp = NULL;
255772445Sassar	switch (ai->ai_family) {
255872445Sassar	case AF_INET:
255972445Sassar		lsrp = lsr;
256072445Sassar		lsrep = lsrp + sizeof(lsr);
256172445Sassar
256272445Sassar		/*
256372445Sassar		 * Next, decide whether we have a loose source
256472445Sassar		 * route or a strict source route, and fill in
256572445Sassar		 * the begining of the option.
256672445Sassar		 */
256772445Sassar		if (*cp == '!') {
256872445Sassar			cp++;
256972445Sassar			*lsrp++ = IPOPT_SSRR;
257072445Sassar		} else
257172445Sassar			*lsrp++ = IPOPT_LSRR;
257272445Sassar		if (*cp != '@')
257372445Sassar			return -1;
257472445Sassar		lsrp++;		/* skip over length, we'll fill it in later */
257572445Sassar		*lsrp++ = 4;
257657416Smarkm		cp++;
257772445Sassar		*protop = IPPROTO_IP;
257872445Sassar		*optp = IP_OPTIONS;
257972445Sassar		break;
258072445Sassar#ifdef INET6
258172445Sassar	case AF_INET6:
258272445Sassar/* this needs to be updated for rfc2292bis */
258372445Sassar#ifdef IPV6_PKTOPTIONS
258472445Sassar		cmsg = inet6_rthdr_init(rhbuf, IPV6_RTHDR_TYPE_0);
258572445Sassar		if (*cp != '@')
258672445Sassar			return -1;
258772445Sassar		cp++;
258872445Sassar		*protop = IPPROTO_IPV6;
258972445Sassar		*optp = IPV6_PKTOPTIONS;
259072445Sassar		break;
259172445Sassar#else
259272445Sassar		return -1;
259372445Sassar#endif
259472445Sassar#endif
259572445Sassar	default:
259672445Sassar		return -1;
259772445Sassar	}
259857416Smarkm
259972445Sassar	memset(&hints, 0, sizeof(hints));
260072445Sassar	hints.ai_family = ai->ai_family;
260172445Sassar	hints.ai_socktype = SOCK_STREAM;
260257416Smarkm
260357416Smarkm	for (c = 0;;) {
260457416Smarkm		if (c == ':')
260557416Smarkm			cp2 = 0;
260672445Sassar		else for (cp2 = cp; (c = *cp2) != '\0'; cp2++) {
260757416Smarkm			if (c == ',') {
260857416Smarkm				*cp2++ = '\0';
260957416Smarkm				if (*cp2 == '@')
261057416Smarkm					cp2++;
261157416Smarkm			} else if (c == '@') {
261257416Smarkm				*cp2++ = '\0';
261372445Sassar			}
261472445Sassar#if 0	/*colon conflicts with IPv6 address*/
261572445Sassar			else if (c == ':') {
261657416Smarkm				*cp2++ = '\0';
261772445Sassar			}
261872445Sassar#endif
261972445Sassar			else
262057416Smarkm				continue;
262157416Smarkm			break;
262257416Smarkm		}
262357416Smarkm		if (!c)
262457416Smarkm			cp2 = 0;
262557416Smarkm
262672445Sassar		error = getaddrinfo(cp, NULL, &hints, &res);
262772445Sassar		if (error) {
262872445Sassar			fprintf(stderr, "%s: %s\n", cp, gai_strerror(error));
262972445Sassar			return -1;
263057416Smarkm		}
263172445Sassar		if (ai->ai_family != res->ai_family) {
263272445Sassar			freeaddrinfo(res);
263372445Sassar			return -1;
263472445Sassar		}
263572445Sassar		if (ai->ai_family == AF_INET) {
263672445Sassar			/*
263772445Sassar			 * Check to make sure there is space for address
263872445Sassar			 */
263972445Sassar			if (lsrp + 4 > lsrep) {
264072445Sassar				freeaddrinfo(res);
264172445Sassar				return -1;
264272445Sassar			}
264372445Sassar			sin = (struct sockaddr_in *)res->ai_addr;
264472445Sassar			memcpy(lsrp, &sin->sin_addr, sizeof(struct in_addr));
264572445Sassar			lsrp += sizeof(struct in_addr);
264672445Sassar		}
264772445Sassar#ifdef INET6
264872445Sassar		else if (ai->ai_family == AF_INET6) {
264972445Sassar			sin6 = (struct sockaddr_in6 *)res->ai_addr;
265072445Sassar			inet6_rthdr_add(cmsg, &sin6->sin6_addr,
265172445Sassar				IPV6_RTHDR_LOOSE);
265272445Sassar		}
265372445Sassar#endif
265472445Sassar		else {
265572445Sassar			freeaddrinfo(res);
265672445Sassar			return -1;
265772445Sassar		}
265872445Sassar		freeaddrinfo(res);
265957416Smarkm		if (cp2)
266057416Smarkm			cp = cp2;
266157416Smarkm		else
266257416Smarkm			break;
266372445Sassar	}
266472445Sassar	if (ai->ai_family == AF_INET) {
266572445Sassar		/* record the last hop */
266657416Smarkm		if (lsrp + 4 > lsrep)
266772445Sassar			return -1;
266872445Sassar		sin = (struct sockaddr_in *)ai->ai_addr;
266972445Sassar		memcpy(lsrp, &sin->sin_addr, sizeof(struct in_addr));
267072445Sassar		lsrp += sizeof(struct in_addr);
267172445Sassar#ifndef	sysV88
267272445Sassar		lsr[IPOPT_OLEN] = lsrp - lsr;
267372445Sassar		if (lsr[IPOPT_OLEN] <= 7 || lsr[IPOPT_OLEN] > 40)
267472445Sassar			return -1;
267572445Sassar		*lsrp++ = IPOPT_NOP;	/*32bit word align*/
267672445Sassar		len = lsrp - lsr;
267772445Sassar		*cpp = lsr;
267872445Sassar#else
267972445Sassar		ipopt.io_len = lsrp - lsr;
268072445Sassar		if (ipopt.io_len <= 5)	/*is 3 better?*/
268172445Sassar			return -1;
268272445Sassar		*cpp = (char 8)&ipopt;
268372445Sassar#endif
268457416Smarkm	}
268572445Sassar#ifdef INET6
268672445Sassar	else if (ai->ai_family == AF_INET6) {
268772445Sassar		inet6_rthdr_lasthop(cmsg, IPV6_RTHDR_LOOSE);
268872445Sassar		len = cmsg->cmsg_len;
268972445Sassar		*cpp = rhbuf;
269057416Smarkm	}
269172445Sassar#endif
269272445Sassar	else
269372445Sassar		return -1;
269472445Sassar	return len;
269557416Smarkm}
269657416Smarkm#endif
2697