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