xref: /netbsd-src/usr.bin/telnet/commands.c (revision edf58efcdb97a27ac39e54a5ddc1b7ed070261c8)
1*edf58efcSmlelstv /*	$NetBSD: commands.c,v 1.80 2022/07/08 21:51:24 mlelstv Exp $	*/
29bee0214Sitojun 
39bee0214Sitojun /*
49bee0214Sitojun  * Copyright (C) 1997 and 1998 WIDE Project.
59bee0214Sitojun  * All rights reserved.
69bee0214Sitojun  *
79bee0214Sitojun  * Redistribution and use in source and binary forms, with or without
89bee0214Sitojun  * modification, are permitted provided that the following conditions
99bee0214Sitojun  * are met:
109bee0214Sitojun  * 1. Redistributions of source code must retain the above copyright
119bee0214Sitojun  *    notice, this list of conditions and the following disclaimer.
129bee0214Sitojun  * 2. Redistributions in binary form must reproduce the above copyright
139bee0214Sitojun  *    notice, this list of conditions and the following disclaimer in the
149bee0214Sitojun  *    documentation and/or other materials provided with the distribution.
159bee0214Sitojun  * 3. Neither the name of the project nor the names of its contributors
169bee0214Sitojun  *    may be used to endorse or promote products derived from this software
179bee0214Sitojun  *    without specific prior written permission.
189bee0214Sitojun  *
199bee0214Sitojun  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
209bee0214Sitojun  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
219bee0214Sitojun  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
229bee0214Sitojun  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
239bee0214Sitojun  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
249bee0214Sitojun  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
259bee0214Sitojun  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
269bee0214Sitojun  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
279bee0214Sitojun  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
289bee0214Sitojun  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
299bee0214Sitojun  * SUCH DAMAGE.
309bee0214Sitojun  */
31077a490aSthorpej 
3261f28255Scgd /*
330582c913Scgd  * Copyright (c) 1988, 1990, 1993
340582c913Scgd  *	The Regents of the University of California.  All rights reserved.
3561f28255Scgd  *
3661f28255Scgd  * Redistribution and use in source and binary forms, with or without
3761f28255Scgd  * modification, are permitted provided that the following conditions
3861f28255Scgd  * are met:
3961f28255Scgd  * 1. Redistributions of source code must retain the above copyright
4061f28255Scgd  *    notice, this list of conditions and the following disclaimer.
4161f28255Scgd  * 2. Redistributions in binary form must reproduce the above copyright
4261f28255Scgd  *    notice, this list of conditions and the following disclaimer in the
4361f28255Scgd  *    documentation and/or other materials provided with the distribution.
4489aaa1bbSagc  * 3. Neither the name of the University nor the names of its contributors
4561f28255Scgd  *    may be used to endorse or promote products derived from this software
4661f28255Scgd  *    without specific prior written permission.
4761f28255Scgd  *
4861f28255Scgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
4961f28255Scgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5061f28255Scgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5161f28255Scgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
5261f28255Scgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5361f28255Scgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5461f28255Scgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5561f28255Scgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5661f28255Scgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5761f28255Scgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5861f28255Scgd  * SUCH DAMAGE.
5961f28255Scgd  */
6061f28255Scgd 
61434ea11bSchristos #include <sys/cdefs.h>
6261f28255Scgd #ifndef lint
63077a490aSthorpej #if 0
64077a490aSthorpej static char sccsid[] = "@(#)commands.c	8.4 (Berkeley) 5/30/95";
65077a490aSthorpej #else
66*edf58efcSmlelstv __RCSID("$NetBSD: commands.c,v 1.80 2022/07/08 21:51:24 mlelstv Exp $");
67077a490aSthorpej #endif
6861f28255Scgd #endif /* not lint */
6961f28255Scgd 
7061f28255Scgd #include <sys/param.h>
7161f28255Scgd #include <sys/file.h>
72434ea11bSchristos #include <sys/wait.h>
7361f28255Scgd #include <sys/socket.h>
7461f28255Scgd #include <netinet/in.h>
75434ea11bSchristos #include <arpa/inet.h>
7661f28255Scgd 
7761f28255Scgd #include <ctype.h>
7861f28255Scgd #include <errno.h>
79797d779cSwiz #include <netdb.h>
80797d779cSwiz #include <pwd.h>
81797d779cSwiz #include <signal.h>
82797d779cSwiz #include <stdarg.h>
83434ea11bSchristos #include <unistd.h>
84dbe0036bSchristos #include <err.h>
8561f28255Scgd 
8661f28255Scgd #include <arpa/telnet.h>
8761f28255Scgd 
8861f28255Scgd #include "general.h"
8961f28255Scgd #include "ring.h"
9061f28255Scgd #include "externs.h"
9161f28255Scgd #include "defines.h"
9261f28255Scgd #include "types.h"
93434ea11bSchristos #include <libtelnet/misc.h>
945c099b14Sthorpej #ifdef AUTHENTICATION
955c099b14Sthorpej #include <libtelnet/auth.h>
965c099b14Sthorpej #endif
975c099b14Sthorpej #ifdef ENCRYPTION
985c099b14Sthorpej #include <libtelnet/encrypt.h>
995c099b14Sthorpej #endif
10061f28255Scgd 
10161f28255Scgd #include <netinet/in_systm.h>
10261f28255Scgd #include <netinet/ip.h>
10361f28255Scgd 
10461f28255Scgd 
10561f28255Scgd #if	defined(IPPROTO_IP) && defined(IP_TOS)
10661f28255Scgd int tos = -1;
10761f28255Scgd #endif	/* defined(IPPROTO_IP) && defined(IP_TOS) */
10861f28255Scgd 
10961f28255Scgd char	*hostname;
11061f28255Scgd static char _hostname[MAXHOSTNAMELEN];
11161f28255Scgd 
11261f28255Scgd typedef struct {
113fcdbba42Schristos 	const char	*name;	/* command name */
114fcdbba42Schristos 	const char	*help;	/* help string (NULL for no help) */
115434ea11bSchristos 	int	(*handler)	/* routine which executes command */
116797d779cSwiz 			(int, char *[]);
11761f28255Scgd 	int	needconnect;	/* Do we need to be connected to execute? */
11861f28255Scgd } Command;
11961f28255Scgd 
12061f28255Scgd static char line[256];
12161f28255Scgd static char saveline[256];
12261f28255Scgd static int margc;
12361f28255Scgd static char *margv[20];
12461f28255Scgd 
125797d779cSwiz static void makeargv(void);
126dbe0036bSchristos static int special(const char *);
127fcdbba42Schristos static const char *control(cc_t);
128797d779cSwiz static int sendcmd(int, char **);
129dbe0036bSchristos static int send_esc(const char *);
130dbe0036bSchristos static int send_docmd(const char *);
131dbe0036bSchristos static int send_dontcmd(const char *);
132dbe0036bSchristos static int send_willcmd(const char *);
133dbe0036bSchristos static int send_wontcmd(const char *);
134dbe0036bSchristos static int send_help(const char *);
135797d779cSwiz static int lclchars(int);
136797d779cSwiz static int togdebug(int);
137797d779cSwiz static int togcrlf(int);
138797d779cSwiz static int togbinary(int);
139797d779cSwiz static int togrbinary(int);
140797d779cSwiz static int togxbinary(int);
141797d779cSwiz static int togglehelp(int);
142797d779cSwiz static void settogglehelp(int);
143797d779cSwiz static int toggle(int, char *[]);
144dbe0036bSchristos static struct setlist *getset(const char *);
145797d779cSwiz static int setcmd(int, char *[]);
146797d779cSwiz static int unsetcmd(int, char *[]);
147797d779cSwiz static int dokludgemode(int);
148797d779cSwiz static int dolinemode(int);
149797d779cSwiz static int docharmode(int);
150797d779cSwiz static int dolmmode(int, int );
151797d779cSwiz static int modecmd(int, char *[]);
152797d779cSwiz static int display(int, char *[]);
153797d779cSwiz static int setescape(int, char *[]);
154797d779cSwiz static int togcrmod(int, char *[]);
155797d779cSwiz static int bye(int, char *[]);
156797d779cSwiz static void slc_help(int);
157dbe0036bSchristos static struct slclist *getslc(const char *);
158797d779cSwiz static int slccmd(int, char *[]);
159dbe0036bSchristos static struct env_lst *env_help(const char *, char *);
160dbe0036bSchristos static struct envlist *getenvcmd(const char *);
161434ea11bSchristos #ifdef AUTHENTICATION
162dbe0036bSchristos static int auth_help(const char *);
163434ea11bSchristos #endif
164797d779cSwiz static int status(int, char *[]);
165797d779cSwiz static const char *sockaddr_ntop (struct sockaddr *);
166797d779cSwiz typedef int (*intrtn_t)(int, char **);
167797d779cSwiz static int call(intrtn_t, ...);
168dbe0036bSchristos static Command *getcmd(const char *);
169797d779cSwiz static int help(int, char *[]);
170434ea11bSchristos 
171dbe0036bSchristos static int
addarg(char * str)172dbe0036bSchristos addarg(char *str)
173dbe0036bSchristos {
174dbe0036bSchristos 	if ((size_t)margc >= __arraycount(margv) - 1)
175dbe0036bSchristos 		return 0;
176dbe0036bSchristos 	margv[margc++] = str;
177dbe0036bSchristos 	margv[margc] = NULL;
178dbe0036bSchristos 	return 1;
179dbe0036bSchristos }
180dbe0036bSchristos 
181dbe0036bSchristos 
18261f28255Scgd static void
makeargv(void)18326583868Schristos makeargv(void)
18461f28255Scgd {
185797d779cSwiz     char *cp, *cp2, c;
186fcdbba42Schristos     static char bang[] = "!";
18761f28255Scgd 
18861f28255Scgd     margc = 0;
189dbe0036bSchristos     margv[0] = NULL;
19061f28255Scgd     cp = line;
19161f28255Scgd     if (*cp == '!') {		/* Special case shell escape */
192dbe0036bSchristos 	/* save for shell command */
193dbe0036bSchristos 	strlcpy(saveline, line, sizeof(saveline));
194dbe0036bSchristos 	if (!addarg(bang))
195dbe0036bSchristos 	    return;
19661f28255Scgd 	cp++;
19761f28255Scgd     }
198434ea11bSchristos     while ((c = *cp) != '\0') {
199797d779cSwiz 	int inquote = 0;
20081c93f4cSchristos 	while (isspace((unsigned char)c))
20161f28255Scgd 	    c = *++cp;
20261f28255Scgd 	if (c == '\0')
20361f28255Scgd 	    break;
204dbe0036bSchristos 	if (!addarg(cp))
205dbe0036bSchristos 	    return;
20661f28255Scgd 	for (cp2 = cp; c != '\0'; c = *++cp) {
20761f28255Scgd 	    if (inquote) {
20861f28255Scgd 		if (c == inquote) {
20961f28255Scgd 		    inquote = 0;
21061f28255Scgd 		    continue;
21161f28255Scgd 		}
21261f28255Scgd 	    } else {
21361f28255Scgd 		if (c == '\\') {
21461f28255Scgd 		    if ((c = *++cp) == '\0')
21561f28255Scgd 			break;
216dbe0036bSchristos 		} else if (c == '"' || c == '\'') {
217dbe0036bSchristos 		    inquote = c;
21861f28255Scgd 		    continue;
21981c93f4cSchristos 		} else if (isspace((unsigned char)c))
22061f28255Scgd 		    break;
22161f28255Scgd 	    }
22261f28255Scgd 	    *cp2++ = c;
22361f28255Scgd 	}
22461f28255Scgd 	*cp2 = '\0';
22561f28255Scgd 	if (c == '\0')
22661f28255Scgd 	    break;
22761f28255Scgd 	cp++;
22861f28255Scgd     }
22961f28255Scgd }
23061f28255Scgd 
23161f28255Scgd /*
23261f28255Scgd  * Make a character string into a number.
23361f28255Scgd  *
23461f28255Scgd  * Todo:  1.  Could take random integers (12, 0x12, 012, 0b1).
23561f28255Scgd  */
23661f28255Scgd 
237434ea11bSchristos static int
special(const char * s)238dbe0036bSchristos special(const char *s)
23961f28255Scgd {
240797d779cSwiz 	char c;
24161f28255Scgd 	char b;
24261f28255Scgd 
24361f28255Scgd 	switch (*s) {
24461f28255Scgd 	case '^':
24561f28255Scgd 		b = *++s;
24661f28255Scgd 		if (b == '?') {
24761f28255Scgd 		    c = b | 0x40;		/* DEL */
24861f28255Scgd 		} else {
24961f28255Scgd 		    c = b & 0x1f;
25061f28255Scgd 		}
25161f28255Scgd 		break;
25261f28255Scgd 	default:
25361f28255Scgd 		c = *s;
25461f28255Scgd 		break;
25561f28255Scgd 	}
25661f28255Scgd 	return c;
25761f28255Scgd }
25861f28255Scgd 
25961f28255Scgd /*
26061f28255Scgd  * Construct a control character sequence
26161f28255Scgd  * for a special character.
26261f28255Scgd  */
263fcdbba42Schristos static const char *
control(cc_t c)26426583868Schristos control(cc_t c)
26561f28255Scgd {
26661f28255Scgd 	static char buf[5];
26761f28255Scgd 	/*
26861f28255Scgd 	 * The only way I could get the Sun 3.5 compiler
26961f28255Scgd 	 * to shut up about
27061f28255Scgd 	 *	if ((unsigned int)c >= 0x80)
27161f28255Scgd 	 * was to assign "c" to an unsigned int variable...
27261f28255Scgd 	 * Arggg....
27361f28255Scgd 	 */
274797d779cSwiz 	unsigned int uic = (unsigned int)c;
27561f28255Scgd 
27661f28255Scgd 	if (uic == 0x7f)
27761f28255Scgd 		return ("^?");
27861f28255Scgd 	if (c == (cc_t)_POSIX_VDISABLE) {
27961f28255Scgd 		return "off";
28061f28255Scgd 	}
28161f28255Scgd 	if (uic >= 0x80) {
28261f28255Scgd 		buf[0] = '\\';
28328da9662Smaya 		buf[1] = ((c >> 6) & 07) + '0';
28428da9662Smaya 		buf[2] = ((c >> 3) & 07) + '0';
28528da9662Smaya 		buf[3] = (c & 07) + '0';
286dbe0036bSchristos 		buf[4] = '\0';
28761f28255Scgd 	} else if (uic >= 0x20) {
28828da9662Smaya 		buf[0] = c;
289dbe0036bSchristos 		buf[1] = '\0';
29061f28255Scgd 	} else {
29161f28255Scgd 		buf[0] = '^';
29228da9662Smaya 		buf[1] = '@' + c;
293dbe0036bSchristos 		buf[2] = '\0';
29461f28255Scgd 	}
29561f28255Scgd 	return (buf);
29661f28255Scgd }
29761f28255Scgd 
29861f28255Scgd 
29961f28255Scgd 
30061f28255Scgd /*
30161f28255Scgd  *	The following are data structures and routines for
30261f28255Scgd  *	the "send" command.
30361f28255Scgd  *
30461f28255Scgd  */
30561f28255Scgd 
30661f28255Scgd struct sendlist {
307fcdbba42Schristos     const char	*name;		/* How user refers to it (case independent) */
308fcdbba42Schristos     const char	*help;		/* Help information (0 ==> no help) */
30961f28255Scgd     int		needconnect;	/* Need to be connected */
31061f28255Scgd     int		narg;		/* Number of arguments */
311434ea11bSchristos     int		(*handler)	/* Routine to perform (for special ops) */
312dbe0036bSchristos 			(const char *);
31361f28255Scgd     int		nbyte;		/* Number of bytes to send this command */
31461f28255Scgd     int		what;		/* Character to be sent (<0 ==> special) */
31561f28255Scgd };
31661f28255Scgd 
31761f28255Scgd 
31861f28255Scgd static struct sendlist Sendlist[] = {
31961f28255Scgd     { "ao",	"Send Telnet Abort output",		1, 0, 0, 2, AO },
32061f28255Scgd     { "ayt",	"Send Telnet 'Are You There'",		1, 0, 0, 2, AYT },
32161f28255Scgd     { "brk",	"Send Telnet Break",			1, 0, 0, 2, BREAK },
32261f28255Scgd     { "break",	0,					1, 0, 0, 2, BREAK },
32361f28255Scgd     { "ec",	"Send Telnet Erase Character",		1, 0, 0, 2, EC },
32461f28255Scgd     { "el",	"Send Telnet Erase Line",		1, 0, 0, 2, EL },
32561f28255Scgd     { "escape",	"Send current escape character",	1, 0, send_esc, 1, 0 },
32661f28255Scgd     { "ga",	"Send Telnet 'Go Ahead' sequence",	1, 0, 0, 2, GA },
32761f28255Scgd     { "ip",	"Send Telnet Interrupt Process",	1, 0, 0, 2, IP },
32861f28255Scgd     { "intp",	0,					1, 0, 0, 2, IP },
32961f28255Scgd     { "interrupt", 0,					1, 0, 0, 2, IP },
33061f28255Scgd     { "intr",	0,					1, 0, 0, 2, IP },
33161f28255Scgd     { "nop",	"Send Telnet 'No operation'",		1, 0, 0, 2, NOP },
33261f28255Scgd     { "eor",	"Send Telnet 'End of Record'",		1, 0, 0, 2, EOR },
33361f28255Scgd     { "abort",	"Send Telnet 'Abort Process'",		1, 0, 0, 2, ABORT },
33461f28255Scgd     { "susp",	"Send Telnet 'Suspend Process'",	1, 0, 0, 2, SUSP },
33561f28255Scgd     { "eof",	"Send Telnet End of File Character",	1, 0, 0, 2, xEOF },
33661f28255Scgd     { "synch",	"Perform Telnet 'Synch operation'",	1, 0, dosynch, 2, 0 },
33761f28255Scgd     { "getstatus", "Send request for STATUS",		1, 0, get_status, 6, 0 },
33861f28255Scgd     { "?",	"Display send options",			0, 0, send_help, 0, 0 },
33961f28255Scgd     { "help",	0,					0, 0, send_help, 0, 0 },
34061f28255Scgd     { "do",	0,					0, 1, send_docmd, 3, 0 },
34161f28255Scgd     { "dont",	0,					0, 1, send_dontcmd, 3, 0 },
34261f28255Scgd     { "will",	0,					0, 1, send_willcmd, 3, 0 },
34361f28255Scgd     { "wont",	0,					0, 1, send_wontcmd, 3, 0 },
344fcdbba42Schristos     { .name = 0 }
34561f28255Scgd };
34661f28255Scgd 
34761f28255Scgd #define	GETSEND(name) ((struct sendlist *) genget(name, (char **) Sendlist, \
34861f28255Scgd 				sizeof(struct sendlist)))
34961f28255Scgd 
35061f28255Scgd static int
sendcmd(int argc,char ** argv)35126583868Schristos sendcmd(int  argc, char **argv)
35261f28255Scgd {
35361f28255Scgd     int count;		/* how many bytes we are going to need to send */
35461f28255Scgd     int i;
35561f28255Scgd     struct sendlist *s;	/* pointer to current command */
35661f28255Scgd     int success = 0;
35761f28255Scgd     int needconnect = 0;
35861f28255Scgd 
35961f28255Scgd     if (argc < 2) {
36061f28255Scgd 	printf("need at least one argument for 'send' command\n");
36161f28255Scgd 	printf("'send ?' for help\n");
36261f28255Scgd 	return 0;
36361f28255Scgd     }
36461f28255Scgd     /*
36561f28255Scgd      * First, validate all the send arguments.
36661f28255Scgd      * In addition, we see how much space we are going to need, and
36761f28255Scgd      * whether or not we will be doing a "SYNCH" operation (which
36861f28255Scgd      * flushes the network queue).
36961f28255Scgd      */
37061f28255Scgd     count = 0;
37161f28255Scgd     for (i = 1; i < argc; i++) {
37261f28255Scgd 	s = GETSEND(argv[i]);
37361f28255Scgd 	if (s == 0) {
37461f28255Scgd 	    printf("Unknown send argument '%s'\n'send ?' for help.\n",
37561f28255Scgd 			argv[i]);
37661f28255Scgd 	    return 0;
37761f28255Scgd 	} else if (Ambiguous(s)) {
37861f28255Scgd 	    printf("Ambiguous send argument '%s'\n'send ?' for help.\n",
37961f28255Scgd 			argv[i]);
38061f28255Scgd 	    return 0;
38161f28255Scgd 	}
38261f28255Scgd 	if (i + s->narg >= argc) {
38361f28255Scgd 	    fprintf(stderr,
38461f28255Scgd 	    "Need %d argument%s to 'send %s' command.  'send %s ?' for help.\n",
38561f28255Scgd 		s->narg, s->narg == 1 ? "" : "s", s->name, s->name);
38661f28255Scgd 	    return 0;
38761f28255Scgd 	}
38861f28255Scgd 	count += s->nbyte;
38961f28255Scgd 	if (s->handler == send_help) {
390434ea11bSchristos 	    send_help(NULL);
39161f28255Scgd 	    return 0;
39261f28255Scgd 	}
39361f28255Scgd 
39461f28255Scgd 	i += s->narg;
39561f28255Scgd 	needconnect += s->needconnect;
39661f28255Scgd     }
39761f28255Scgd     if (!connected && needconnect) {
39861f28255Scgd 	printf("?Need to be connected first.\n");
39961f28255Scgd 	printf("'send ?' for help\n");
40061f28255Scgd 	return 0;
40161f28255Scgd     }
40261f28255Scgd     /* Now, do we have enough room? */
40361f28255Scgd     if (NETROOM() < count) {
40461f28255Scgd 	printf("There is not enough room in the buffer TO the network\n");
40561f28255Scgd 	printf("to process your request.  Nothing will be done.\n");
40661f28255Scgd 	printf("('send synch' will throw away most data in the network\n");
40761f28255Scgd 	printf("buffer, if this might help.)\n");
40861f28255Scgd 	return 0;
40961f28255Scgd     }
41061f28255Scgd     /* OK, they are all OK, now go through again and actually send */
41161f28255Scgd     count = 0;
41261f28255Scgd     for (i = 1; i < argc; i++) {
41361f28255Scgd 	if ((s = GETSEND(argv[i])) == 0) {
41461f28255Scgd 	    fprintf(stderr, "Telnet 'send' error - argument disappeared!\n");
415434ea11bSchristos 	    (void) quit(0, NULL);
41661f28255Scgd 	    /*NOTREACHED*/
41761f28255Scgd 	}
41861f28255Scgd 	if (s->handler) {
41961f28255Scgd 	    count++;
420434ea11bSchristos 	    success += (*s->handler)(argv[i+1]);
42161f28255Scgd 	    i += s->narg;
42261f28255Scgd 	} else {
423dbe0036bSchristos 	    NET2ADD(IAC, (unsigned char)s->what);
4246bc41d30Scgd 	    printoption("SENT", IAC, s->what);
42561f28255Scgd 	}
42661f28255Scgd     }
42761f28255Scgd     return (count == success);
42861f28255Scgd }
42961f28255Scgd 
43061f28255Scgd static int
send_esc(const char * s)431dbe0036bSchristos send_esc(const char *s)
43261f28255Scgd {
43361f28255Scgd     NETADD(escape);
43461f28255Scgd     return 1;
43561f28255Scgd }
43661f28255Scgd 
43761f28255Scgd static int
send_docmd(const char * name)438dbe0036bSchristos send_docmd(const char *name)
43961f28255Scgd {
440dbe0036bSchristos     return send_tncmd(send_do, "do", name);
44161f28255Scgd }
44261f28255Scgd 
44361f28255Scgd static int
send_dontcmd(const char * name)444dbe0036bSchristos send_dontcmd(const char *name)
44561f28255Scgd {
446dbe0036bSchristos     return send_tncmd(send_dont, "dont", name);
44761f28255Scgd }
448dbe0036bSchristos 
44961f28255Scgd static int
send_willcmd(const char * name)450dbe0036bSchristos send_willcmd(const char *name)
45161f28255Scgd {
452dbe0036bSchristos     return send_tncmd(send_will, "will", name);
45361f28255Scgd }
454dbe0036bSchristos 
45561f28255Scgd static int
send_wontcmd(const char * name)456dbe0036bSchristos send_wontcmd(const char *name)
45761f28255Scgd {
458dbe0036bSchristos     return send_tncmd(send_wont, "wont", name);
45961f28255Scgd }
46061f28255Scgd 
46161f28255Scgd int
send_tncmd(void (* func)(int,int),const char * cmd,const char * name)462dbe0036bSchristos send_tncmd(void	(*func)(int, int), const char	*cmd, const char *name)
46361f28255Scgd {
4643ac7a404Schristos     const char **cpp;
465dbe0036bSchristos     ptrdiff_t val = 0;
46661f28255Scgd 
46707f5d8eaSjtk     if (isprefix(name, "?")) {
468dbe0036bSchristos 	size_t col, len;
46961f28255Scgd 
470b635f565Sjmmv 	printf("usage: send %s <value|option>\n", cmd);
4710582c913Scgd 	printf("\"value\" must be from 0 to 255\n");
47261f28255Scgd 	printf("Valid options are:\n\t");
47361f28255Scgd 
47461f28255Scgd 	col = 8;
47561f28255Scgd 	for (cpp = telopts; *cpp; cpp++) {
4760582c913Scgd 	    len = strlen(*cpp) + 3;
47761f28255Scgd 	    if (col + len > 65) {
47861f28255Scgd 		printf("\n\t");
47961f28255Scgd 		col = 8;
48061f28255Scgd 	    }
4810582c913Scgd 	    printf(" \"%s\"", *cpp);
48261f28255Scgd 	    col += len;
48361f28255Scgd 	}
48461f28255Scgd 	printf("\n");
48561f28255Scgd 	return 0;
48661f28255Scgd     }
487fcdbba42Schristos     cpp = (void *)genget(name, __UNCONST(telopts), sizeof(char *));
48861f28255Scgd     if (Ambiguous(cpp)) {
48961f28255Scgd 	fprintf(stderr,"'%s': ambiguous argument ('send %s ?' for help).\n",
49061f28255Scgd 					name, cmd);
49161f28255Scgd 	return 0;
49261f28255Scgd     }
4930582c913Scgd     if (cpp) {
4940582c913Scgd 	val = cpp - telopts;
4950582c913Scgd     } else {
496dbe0036bSchristos 	const char *cp = name;
4970582c913Scgd 
4980582c913Scgd 	while (*cp >= '0' && *cp <= '9') {
4990582c913Scgd 	    val *= 10;
5000582c913Scgd 	    val += *cp - '0';
5010582c913Scgd 	    cp++;
5020582c913Scgd 	}
5030582c913Scgd 	if (*cp != 0) {
50461f28255Scgd 	    fprintf(stderr, "'%s': unknown argument ('send %s ?' for help).\n",
50561f28255Scgd 					name, cmd);
50661f28255Scgd 	    return 0;
5070582c913Scgd 	} else if (val < 0 || val > 255) {
5080582c913Scgd 	    fprintf(stderr, "'%s': bad value ('send %s ?' for help).\n",
5090582c913Scgd 					name, cmd);
5100582c913Scgd 	    return 0;
5110582c913Scgd 	}
51261f28255Scgd     }
51361f28255Scgd     if (!connected) {
51461f28255Scgd 	printf("?Need to be connected first.\n");
51561f28255Scgd 	return 0;
51661f28255Scgd     }
517dbe0036bSchristos     (*func)((int)val, 1);
51861f28255Scgd     return 1;
51961f28255Scgd }
52061f28255Scgd 
52161f28255Scgd static int
send_help(const char * n)522dbe0036bSchristos send_help(const char *n)
52361f28255Scgd {
52461f28255Scgd     struct sendlist *s;	/* pointer to current command */
52561f28255Scgd     for (s = Sendlist; s->name; s++) {
52661f28255Scgd 	if (s->help)
52761f28255Scgd 	    printf("%-15s %s\n", s->name, s->help);
52861f28255Scgd     }
529dbe0036bSchristos     return 0;
53061f28255Scgd }
53161f28255Scgd 
53261f28255Scgd /*
53361f28255Scgd  * The following are the routines and data structures referred
53461f28255Scgd  * to by the arguments to the "toggle" command.
53561f28255Scgd  */
53661f28255Scgd 
53761f28255Scgd static int
lclchars(int n)53826583868Schristos lclchars(int n)
53961f28255Scgd {
54061f28255Scgd     donelclchars = 1;
54161f28255Scgd     return 1;
54261f28255Scgd }
54361f28255Scgd 
54461f28255Scgd static int
togdebug(int n)54526583868Schristos togdebug(int n)
54661f28255Scgd {
54761f28255Scgd     if (net > 0 &&
5489dfcf4d4She 	(SetSockOpt(net, SOL_SOCKET, SO_DEBUG, telnet_debug)) < 0) {
549dbe0036bSchristos 	    warn("setsockopt (SO_DEBUG)");
55061f28255Scgd     }
55161f28255Scgd     return 1;
55261f28255Scgd }
55361f28255Scgd 
55461f28255Scgd static int
togcrlf(int n)55526583868Schristos togcrlf(int n)
55661f28255Scgd {
55761f28255Scgd     if (crlf) {
55861f28255Scgd 	printf("Will send carriage returns as telnet <CR><LF>.\n");
55961f28255Scgd     } else {
56061f28255Scgd 	printf("Will send carriage returns as telnet <CR><NUL>.\n");
56161f28255Scgd     }
56261f28255Scgd     return 1;
56361f28255Scgd }
56461f28255Scgd 
56561f28255Scgd int binmode;
56661f28255Scgd 
56761f28255Scgd static int
togbinary(int val)56826583868Schristos togbinary(int val)
56961f28255Scgd {
57061f28255Scgd     donebinarytoggle = 1;
57161f28255Scgd 
57261f28255Scgd     if (val >= 0) {
57361f28255Scgd 	binmode = val;
57461f28255Scgd     } else {
57561f28255Scgd 	if (my_want_state_is_will(TELOPT_BINARY) &&
57661f28255Scgd 				my_want_state_is_do(TELOPT_BINARY)) {
57761f28255Scgd 	    binmode = 1;
57861f28255Scgd 	} else if (my_want_state_is_wont(TELOPT_BINARY) &&
57961f28255Scgd 				my_want_state_is_dont(TELOPT_BINARY)) {
58061f28255Scgd 	    binmode = 0;
58161f28255Scgd 	}
58261f28255Scgd 	val = binmode ? 0 : 1;
58361f28255Scgd     }
58461f28255Scgd 
58561f28255Scgd     if (val == 1) {
58661f28255Scgd 	if (my_want_state_is_will(TELOPT_BINARY) &&
58761f28255Scgd 					my_want_state_is_do(TELOPT_BINARY)) {
58861f28255Scgd 	    printf("Already operating in binary mode with remote host.\n");
58961f28255Scgd 	} else {
59061f28255Scgd 	    printf("Negotiating binary mode with remote host.\n");
59161f28255Scgd 	    tel_enter_binary(3);
59261f28255Scgd 	}
59361f28255Scgd     } else {
59461f28255Scgd 	if (my_want_state_is_wont(TELOPT_BINARY) &&
59561f28255Scgd 					my_want_state_is_dont(TELOPT_BINARY)) {
59661f28255Scgd 	    printf("Already in network ascii mode with remote host.\n");
59761f28255Scgd 	} else {
59861f28255Scgd 	    printf("Negotiating network ascii mode with remote host.\n");
59961f28255Scgd 	    tel_leave_binary(3);
60061f28255Scgd 	}
60161f28255Scgd     }
60261f28255Scgd     return 1;
60361f28255Scgd }
60461f28255Scgd 
60561f28255Scgd static int
togrbinary(int val)60626583868Schristos togrbinary(int val)
60761f28255Scgd {
60861f28255Scgd     donebinarytoggle = 1;
60961f28255Scgd 
61061f28255Scgd     if (val == -1)
61161f28255Scgd 	val = my_want_state_is_do(TELOPT_BINARY) ? 0 : 1;
61261f28255Scgd 
61361f28255Scgd     if (val == 1) {
61461f28255Scgd 	if (my_want_state_is_do(TELOPT_BINARY)) {
61561f28255Scgd 	    printf("Already receiving in binary mode.\n");
61661f28255Scgd 	} else {
61761f28255Scgd 	    printf("Negotiating binary mode on input.\n");
61861f28255Scgd 	    tel_enter_binary(1);
61961f28255Scgd 	}
62061f28255Scgd     } else {
62161f28255Scgd 	if (my_want_state_is_dont(TELOPT_BINARY)) {
62261f28255Scgd 	    printf("Already receiving in network ascii mode.\n");
62361f28255Scgd 	} else {
62461f28255Scgd 	    printf("Negotiating network ascii mode on input.\n");
62561f28255Scgd 	    tel_leave_binary(1);
62661f28255Scgd 	}
62761f28255Scgd     }
62861f28255Scgd     return 1;
62961f28255Scgd }
63061f28255Scgd 
63161f28255Scgd static int
togxbinary(int val)63226583868Schristos togxbinary(int val)
63361f28255Scgd {
63461f28255Scgd     donebinarytoggle = 1;
63561f28255Scgd 
63661f28255Scgd     if (val == -1)
63761f28255Scgd 	val = my_want_state_is_will(TELOPT_BINARY) ? 0 : 1;
63861f28255Scgd 
63961f28255Scgd     if (val == 1) {
64061f28255Scgd 	if (my_want_state_is_will(TELOPT_BINARY)) {
64161f28255Scgd 	    printf("Already transmitting in binary mode.\n");
64261f28255Scgd 	} else {
64361f28255Scgd 	    printf("Negotiating binary mode on output.\n");
64461f28255Scgd 	    tel_enter_binary(2);
64561f28255Scgd 	}
64661f28255Scgd     } else {
64761f28255Scgd 	if (my_want_state_is_wont(TELOPT_BINARY)) {
64861f28255Scgd 	    printf("Already transmitting in network ascii mode.\n");
64961f28255Scgd 	} else {
65061f28255Scgd 	    printf("Negotiating network ascii mode on output.\n");
65161f28255Scgd 	    tel_leave_binary(2);
65261f28255Scgd 	}
65361f28255Scgd     }
65461f28255Scgd     return 1;
65561f28255Scgd }
65661f28255Scgd 
6575c099b14Sthorpej #ifdef	ENCRYPTION
658797d779cSwiz extern int EncryptAutoEnc(int);
659797d779cSwiz extern int EncryptAutoDec(int);
660797d779cSwiz extern int EncryptDebug(int);
661797d779cSwiz extern int EncryptVerbose(int);
6625c099b14Sthorpej #endif	/* ENCRYPTION */
66361f28255Scgd 
66461f28255Scgd struct togglelist {
665fcdbba42Schristos     const char	*name;		/* name of toggle */
666fcdbba42Schristos     const char	*help;		/* help message */
667434ea11bSchristos     int		(*handler)	/* routine to do actual setting */
668797d779cSwiz 			(int);
66961f28255Scgd     int		*variable;
670fcdbba42Schristos     const char	*actionexplanation;
67161f28255Scgd };
67261f28255Scgd 
67361f28255Scgd static struct togglelist Togglelist[] = {
67461f28255Scgd     { "autoflush",
67561f28255Scgd 	"flushing of output when sending interrupt characters",
67661f28255Scgd 	    0,
67761f28255Scgd 		&autoflush,
67861f28255Scgd 		    "flush output when sending interrupt characters" },
67961f28255Scgd     { "autosynch",
68061f28255Scgd 	"automatic sending of interrupt characters in urgent mode",
68161f28255Scgd 	    0,
68261f28255Scgd 		&autosynch,
68361f28255Scgd 		    "send interrupt characters in urgent mode" },
68421f5307cSitojun #ifdef AUTHENTICATION
68561f28255Scgd     { "autologin",
68661f28255Scgd 	"automatic sending of login and/or authentication info",
68761f28255Scgd 	    0,
68861f28255Scgd 		&autologin,
68961f28255Scgd 		    "send login name and/or authentication information" },
69061f28255Scgd     { "authdebug",
69161f28255Scgd 	"Toggle authentication debugging",
69261f28255Scgd 	    auth_togdebug,
69361f28255Scgd 		0,
69461f28255Scgd 		     "print authentication debugging information" },
69561f28255Scgd #endif
6965c099b14Sthorpej #ifdef	ENCRYPTION
6975c099b14Sthorpej     { "autoencrypt",
6985c099b14Sthorpej       "automatic encryption of data stream",
6995c099b14Sthorpej 	    EncryptAutoEnc,
7005c099b14Sthorpej 		0,
7015c099b14Sthorpej 		     "automatically encrypt output" },
7025c099b14Sthorpej     { "autodecrypt",
7035c099b14Sthorpej       "automatic decryption of data stream",
7045c099b14Sthorpej 	    EncryptAutoDec,
7055c099b14Sthorpej 		0,
7065c099b14Sthorpej 		     "automatically decrypt input" },
7075c099b14Sthorpej     { "verbose_encrypt",
7085c099b14Sthorpej       "Toggle verbose encryption output",
7095c099b14Sthorpej 	    EncryptVerbose,
7105c099b14Sthorpej 		0,
7115c099b14Sthorpej 		     "print verbose encryption output" },
7125c099b14Sthorpej     { "encdebug",
7135c099b14Sthorpej       "Toggle encryption debugging",
7145c099b14Sthorpej 	    EncryptDebug,
7155c099b14Sthorpej 		0,
7165c099b14Sthorpej 		     "print encryption debugging information" },
7175c099b14Sthorpej #endif	/* ENCRYPTION */
71861f28255Scgd     { "skiprc",
71961f28255Scgd 	"don't read ~/.telnetrc file",
72061f28255Scgd 	    0,
72161f28255Scgd 		&skiprc,
7220582c913Scgd 		    "skip reading of ~/.telnetrc file" },
72361f28255Scgd     { "binary",
72461f28255Scgd 	"sending and receiving of binary data",
72561f28255Scgd 	    togbinary,
72661f28255Scgd 		0,
72761f28255Scgd 		    0 },
72861f28255Scgd     { "inbinary",
72961f28255Scgd 	"receiving of binary data",
73061f28255Scgd 	    togrbinary,
73161f28255Scgd 		0,
73261f28255Scgd 		    0 },
73361f28255Scgd     { "outbinary",
73461f28255Scgd 	"sending of binary data",
73561f28255Scgd 	    togxbinary,
73661f28255Scgd 		0,
73761f28255Scgd 		    0 },
73861f28255Scgd     { "crlf",
73961f28255Scgd 	"sending carriage returns as telnet <CR><LF>",
74061f28255Scgd 	   togcrlf,
74161f28255Scgd 		&crlf,
74261f28255Scgd 		    0 },
74361f28255Scgd     { "crmod",
74461f28255Scgd 	"mapping of received carriage returns",
74561f28255Scgd 	    0,
74661f28255Scgd 		&crmod,
74761f28255Scgd 		    "map carriage return on output" },
74861f28255Scgd     { "localchars",
74961f28255Scgd 	"local recognition of certain control characters",
75061f28255Scgd 	    lclchars,
75161f28255Scgd 		&localchars,
75261f28255Scgd 		    "recognize certain control characters" },
753fcdbba42Schristos     { " ", "", 0, NULL, NULL },		/* empty line */
75461f28255Scgd     { "debug",
75561f28255Scgd 	"debugging",
75661f28255Scgd 	    togdebug,
7579dfcf4d4She 		&telnet_debug,
75861f28255Scgd 		    "turn on socket level debugging" },
75961f28255Scgd     { "netdata",
76061f28255Scgd 	"printing of hexadecimal network data (debugging)",
76161f28255Scgd 	    0,
76261f28255Scgd 		&netdata,
76361f28255Scgd 		    "print hexadecimal representation of network traffic" },
76461f28255Scgd     { "prettydump",
76561f28255Scgd 	"output of \"netdata\" to user readable format (debugging)",
76661f28255Scgd 	    0,
76761f28255Scgd 		&prettydump,
76861f28255Scgd 		    "print user readable output for \"netdata\"" },
76961f28255Scgd     { "options",
77061f28255Scgd 	"viewing of options processing (debugging)",
77161f28255Scgd 	    0,
77261f28255Scgd 		&showoptions,
77361f28255Scgd 		    "show option processing" },
77461f28255Scgd     { "termdata",
77561f28255Scgd 	"(debugging) toggle printing of hexadecimal terminal data",
77661f28255Scgd 	    0,
77761f28255Scgd 		&termdata,
77861f28255Scgd 		    "print hexadecimal representation of terminal traffic" },
77961f28255Scgd     { "?",
78061f28255Scgd 	0,
781fcdbba42Schristos 	    togglehelp, NULL, NULL },
78261f28255Scgd     { "help",
78361f28255Scgd 	0,
784fcdbba42Schristos 	    togglehelp, NULL, NULL },
785fcdbba42Schristos     { .name = 0 }
78661f28255Scgd };
78761f28255Scgd 
78861f28255Scgd static int
togglehelp(int n)78926583868Schristos togglehelp(int n)
79061f28255Scgd {
79161f28255Scgd     struct togglelist *c;
79261f28255Scgd 
79361f28255Scgd     for (c = Togglelist; c->name; c++) {
79461f28255Scgd 	if (c->help) {
79561f28255Scgd 	    if (*c->help)
79661f28255Scgd 		printf("%-15s toggle %s\n", c->name, c->help);
79761f28255Scgd 	    else
79861f28255Scgd 		printf("\n");
79961f28255Scgd 	}
80061f28255Scgd     }
80161f28255Scgd     printf("\n");
80261f28255Scgd     printf("%-15s %s\n", "?", "display help information");
80361f28255Scgd     return 0;
80461f28255Scgd }
80561f28255Scgd 
80661f28255Scgd static void
settogglehelp(int set)80726583868Schristos settogglehelp(int set)
80861f28255Scgd {
80961f28255Scgd     struct togglelist *c;
81061f28255Scgd 
81161f28255Scgd     for (c = Togglelist; c->name; c++) {
81261f28255Scgd 	if (c->help) {
81361f28255Scgd 	    if (*c->help)
81461f28255Scgd 		printf("%-15s %s %s\n", c->name, set ? "enable" : "disable",
81561f28255Scgd 						c->help);
81661f28255Scgd 	    else
81761f28255Scgd 		printf("\n");
81861f28255Scgd 	}
81961f28255Scgd     }
82061f28255Scgd }
82161f28255Scgd 
82261f28255Scgd #define	GETTOGGLE(name) (struct togglelist *) \
82361f28255Scgd 		genget(name, (char **) Togglelist, sizeof(struct togglelist))
82461f28255Scgd 
82561f28255Scgd static int
toggle(int argc,char * argv[])82626583868Schristos toggle(int  argc, char *argv[])
82761f28255Scgd {
82861f28255Scgd     int retval = 1;
82961f28255Scgd     char *name;
83061f28255Scgd     struct togglelist *c;
83161f28255Scgd 
83261f28255Scgd     if (argc < 2) {
83361f28255Scgd 	fprintf(stderr,
83461f28255Scgd 	    "Need an argument to 'toggle' command.  'toggle ?' for help.\n");
83561f28255Scgd 	return 0;
83661f28255Scgd     }
83761f28255Scgd     argc--;
83861f28255Scgd     argv++;
83961f28255Scgd     while (argc--) {
84061f28255Scgd 	name = *argv++;
84161f28255Scgd 	c = GETTOGGLE(name);
84261f28255Scgd 	if (Ambiguous(c)) {
84361f28255Scgd 	    fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n",
84461f28255Scgd 					name);
84561f28255Scgd 	    return 0;
84661f28255Scgd 	} else if (c == 0) {
84761f28255Scgd 	    fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n",
84861f28255Scgd 					name);
84961f28255Scgd 	    return 0;
85061f28255Scgd 	} else {
85161f28255Scgd 	    if (c->variable) {
85261f28255Scgd 		*c->variable = !*c->variable;		/* invert it */
85361f28255Scgd 		if (c->actionexplanation) {
85461f28255Scgd 		    printf("%s %s.\n", *c->variable? "Will" : "Won't",
85561f28255Scgd 							c->actionexplanation);
85661f28255Scgd 		}
85761f28255Scgd 	    }
85861f28255Scgd 	    if (c->handler) {
85961f28255Scgd 		retval &= (*c->handler)(-1);
86061f28255Scgd 	    }
86161f28255Scgd 	}
86261f28255Scgd     }
86361f28255Scgd     return retval;
86461f28255Scgd }
86561f28255Scgd 
86661f28255Scgd /*
86761f28255Scgd  * The following perform the "set" command.
86861f28255Scgd  */
86961f28255Scgd 
870fcdbba42Schristos struct termios new_tc = { .c_iflag = 0 };
87161f28255Scgd 
87261f28255Scgd struct setlist {
873fcdbba42Schristos     const char *name;			/* name */
874fcdbba42Schristos     const char *help;			/* help information */
875dbe0036bSchristos     void (*handler)(const char *);
87661f28255Scgd     cc_t *charp;			/* where it is located at */
87761f28255Scgd };
87861f28255Scgd 
87961f28255Scgd static struct setlist Setlist[] = {
88061f28255Scgd #ifdef	KLUDGELINEMODE
88161f28255Scgd     { "echo", 	"character to toggle local echoing on/off", 0, &echoc },
88261f28255Scgd #endif
88361f28255Scgd     { "escape",	"character to escape back to telnet command mode", 0, &escape },
88461f28255Scgd     { "rlogin", "rlogin escape character", 0, &rlogin },
88561f28255Scgd     { "tracefile", "file to write trace information to", SetNetTrace, (cc_t *)NetTraceFile},
886fcdbba42Schristos     { " ", "", NULL, NULL },
88761f28255Scgd     { " ", "The following need 'localchars' to be toggled true", 0, 0 },
88861f28255Scgd     { "flushoutput", "character to cause an Abort Output", 0, termFlushCharp },
88961f28255Scgd     { "interrupt", "character to cause an Interrupt Process", 0, termIntCharp },
89061f28255Scgd     { "quit",	"character to cause an Abort process", 0, termQuitCharp },
89161f28255Scgd     { "eof",	"character to cause an EOF ", 0, termEofCharp },
892fcdbba42Schristos     { " ", "", NULL, NULL },
89361f28255Scgd     { " ", "The following are for local editing in linemode", 0, 0 },
89461f28255Scgd     { "erase",	"character to use to erase a character", 0, termEraseCharp },
89561f28255Scgd     { "kill",	"character to use to erase a line", 0, termKillCharp },
89661f28255Scgd     { "lnext",	"character to use for literal next", 0, termLiteralNextCharp },
89761f28255Scgd     { "susp",	"character to cause a Suspend Process", 0, termSuspCharp },
89861f28255Scgd     { "reprint", "character to use for line reprint", 0, termRprntCharp },
89961f28255Scgd     { "worderase", "character to use to erase a word", 0, termWerasCharp },
90061f28255Scgd     { "start",	"character to use for XON", 0, termStartCharp },
90161f28255Scgd     { "stop",	"character to use for XOFF", 0, termStopCharp },
90261f28255Scgd     { "forw1",	"alternate end of line character", 0, termForw1Charp },
90361f28255Scgd     { "forw2",	"alternate end of line character", 0, termForw2Charp },
90461f28255Scgd     { "ayt",	"alternate AYT character", 0, termAytCharp },
905fcdbba42Schristos     { .name = 0 }
90661f28255Scgd };
90761f28255Scgd 
90861f28255Scgd static struct setlist *
getset(const char * name)909dbe0036bSchristos getset(const char *name)
91061f28255Scgd {
91161f28255Scgd     return (struct setlist *)
91261f28255Scgd 		genget(name, (char **) Setlist, sizeof(struct setlist));
91361f28255Scgd }
91461f28255Scgd 
915dbe0036bSchristos static cc_t
getcc(const char * s)916dbe0036bSchristos getcc(const char *s)
917dbe0036bSchristos {
918dbe0036bSchristos 	return (cc_t)((s && *s) ? special(s) : _POSIX_VDISABLE);
919dbe0036bSchristos }
920dbe0036bSchristos 
92161f28255Scgd void
set_escape_char(char * s)92226583868Schristos set_escape_char(char *s)
92361f28255Scgd {
92461f28255Scgd 	if (rlogin != _POSIX_VDISABLE) {
925dbe0036bSchristos 		rlogin = getcc(s);
92661f28255Scgd 		printf("Telnet rlogin escape character is '%s'.\n",
92761f28255Scgd 					control(rlogin));
92861f28255Scgd 	} else {
929dbe0036bSchristos 		escape = getcc(s);
93061f28255Scgd 		printf("Telnet escape character is '%s'.\n", control(escape));
93161f28255Scgd 	}
93261f28255Scgd }
93361f28255Scgd 
93461f28255Scgd static int
setcmd(int argc,char * argv[])93526583868Schristos setcmd(int  argc, char *argv[])
93661f28255Scgd {
93761f28255Scgd     int value;
93861f28255Scgd     struct setlist *ct;
93961f28255Scgd     struct togglelist *c;
94061f28255Scgd 
94161f28255Scgd     if (argc < 2 || argc > 3) {
94261f28255Scgd 	printf("Format is 'set Name Value'\n'set ?' for help.\n");
94361f28255Scgd 	return 0;
94461f28255Scgd     }
94561f28255Scgd     if ((argc == 2) && (isprefix(argv[1], "?") || isprefix(argv[1], "help"))) {
94661f28255Scgd 	for (ct = Setlist; ct->name; ct++)
94761f28255Scgd 	    printf("%-15s %s\n", ct->name, ct->help);
94861f28255Scgd 	printf("\n");
94961f28255Scgd 	settogglehelp(1);
95061f28255Scgd 	printf("%-15s %s\n", "?", "display help information");
95161f28255Scgd 	return 0;
95261f28255Scgd     }
95361f28255Scgd 
95461f28255Scgd     ct = getset(argv[1]);
955*edf58efcSmlelstv     if (ct == 0 || !(ct->name && ct->name[0] != ' ')) {
95661f28255Scgd 	c = GETTOGGLE(argv[1]);
95761f28255Scgd 	if (c == 0) {
95861f28255Scgd 	    fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n",
95961f28255Scgd 			argv[1]);
96061f28255Scgd 	    return 0;
96161f28255Scgd 	} else if (Ambiguous(c)) {
96261f28255Scgd 	    fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
96361f28255Scgd 			argv[1]);
96461f28255Scgd 	    return 0;
96561f28255Scgd 	}
96661f28255Scgd 	if (c->variable) {
96761f28255Scgd 	    if ((argc == 2) || (strcmp("on", argv[2]) == 0))
96861f28255Scgd 		*c->variable = 1;
96961f28255Scgd 	    else if (strcmp("off", argv[2]) == 0)
97061f28255Scgd 		*c->variable = 0;
97161f28255Scgd 	    else {
97261f28255Scgd 		printf("Format is 'set togglename [on|off]'\n'set ?' for help.\n");
97361f28255Scgd 		return 0;
97461f28255Scgd 	    }
97561f28255Scgd 	    if (c->actionexplanation) {
97661f28255Scgd 		printf("%s %s.\n", *c->variable? "Will" : "Won't",
97761f28255Scgd 							c->actionexplanation);
97861f28255Scgd 	    }
97961f28255Scgd 	}
98061f28255Scgd 	if (c->handler)
98161f28255Scgd 	    (*c->handler)(1);
98261f28255Scgd     } else if (argc != 3) {
98361f28255Scgd 	printf("Format is 'set Name Value'\n'set ?' for help.\n");
98461f28255Scgd 	return 0;
98561f28255Scgd     } else if (Ambiguous(ct)) {
98661f28255Scgd 	fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
98761f28255Scgd 			argv[1]);
98861f28255Scgd 	return 0;
98961f28255Scgd     } else if (ct->handler) {
99061f28255Scgd 	(*ct->handler)(argv[2]);
991dbe0036bSchristos 	printf("%s set to \"%s\".\n", ct->name, ct->charp);
99261f28255Scgd     } else {
99361f28255Scgd 	if (strcmp("off", argv[2])) {
99461f28255Scgd 	    value = special(argv[2]);
99561f28255Scgd 	} else {
99661f28255Scgd 	    value = _POSIX_VDISABLE;
99761f28255Scgd 	}
99861f28255Scgd 	*(ct->charp) = (cc_t)value;
99961f28255Scgd 	printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
100061f28255Scgd     }
100161f28255Scgd     slc_check();
100261f28255Scgd     return 1;
100361f28255Scgd }
100461f28255Scgd 
100561f28255Scgd static int
unsetcmd(int argc,char * argv[])100626583868Schristos unsetcmd(int  argc, char *argv[])
100761f28255Scgd {
100861f28255Scgd     struct setlist *ct;
100961f28255Scgd     struct togglelist *c;
1010797d779cSwiz     char *name;
101161f28255Scgd 
101261f28255Scgd     if (argc < 2) {
101361f28255Scgd 	fprintf(stderr,
101461f28255Scgd 	    "Need an argument to 'unset' command.  'unset ?' for help.\n");
101561f28255Scgd 	return 0;
101661f28255Scgd     }
101761f28255Scgd     if (isprefix(argv[1], "?") || isprefix(argv[1], "help")) {
101861f28255Scgd 	for (ct = Setlist; ct->name; ct++)
101961f28255Scgd 	    printf("%-15s %s\n", ct->name, ct->help);
102061f28255Scgd 	printf("\n");
102161f28255Scgd 	settogglehelp(0);
102261f28255Scgd 	printf("%-15s %s\n", "?", "display help information");
102361f28255Scgd 	return 0;
102461f28255Scgd     }
102561f28255Scgd 
102661f28255Scgd     argc--;
102761f28255Scgd     argv++;
102861f28255Scgd     while (argc--) {
102961f28255Scgd 	name = *argv++;
103061f28255Scgd 	ct = getset(name);
1031*edf58efcSmlelstv 	if (ct == 0 || !(ct->name && ct->name[0] != ' ')) {
103261f28255Scgd 	    c = GETTOGGLE(name);
103361f28255Scgd 	    if (c == 0) {
103461f28255Scgd 		fprintf(stderr, "'%s': unknown argument ('unset ?' for help).\n",
103561f28255Scgd 			name);
103661f28255Scgd 		return 0;
103761f28255Scgd 	    } else if (Ambiguous(c)) {
103861f28255Scgd 		fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n",
103961f28255Scgd 			name);
104061f28255Scgd 		return 0;
104161f28255Scgd 	    }
104261f28255Scgd 	    if (c->variable) {
104361f28255Scgd 		*c->variable = 0;
104461f28255Scgd 		if (c->actionexplanation) {
104561f28255Scgd 		    printf("%s %s.\n", *c->variable? "Will" : "Won't",
104661f28255Scgd 							c->actionexplanation);
104761f28255Scgd 		}
104861f28255Scgd 	    }
104961f28255Scgd 	    if (c->handler)
105061f28255Scgd 		(*c->handler)(0);
105161f28255Scgd 	} else if (Ambiguous(ct)) {
105261f28255Scgd 	    fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n",
105361f28255Scgd 			name);
105461f28255Scgd 	    return 0;
105561f28255Scgd 	} else if (ct->handler) {
105661f28255Scgd 	    (*ct->handler)(0);
1057dbe0036bSchristos 	    printf("%s reset to \"%s\".\n", ct->name, ct->charp);
105861f28255Scgd 	} else {
105961f28255Scgd 	    *(ct->charp) = _POSIX_VDISABLE;
106061f28255Scgd 	    printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
106161f28255Scgd 	}
106261f28255Scgd     }
106361f28255Scgd     return 1;
106461f28255Scgd }
106561f28255Scgd 
106661f28255Scgd /*
106761f28255Scgd  * The following are the data structures and routines for the
106861f28255Scgd  * 'mode' command.
106961f28255Scgd  */
107061f28255Scgd #ifdef	KLUDGELINEMODE
107161f28255Scgd extern int kludgelinemode;
107261f28255Scgd 
107361f28255Scgd static int
dokludgemode(int n)107426583868Schristos dokludgemode(int n)
107561f28255Scgd {
107661f28255Scgd     kludgelinemode = 1;
107761f28255Scgd     send_wont(TELOPT_LINEMODE, 1);
107861f28255Scgd     send_dont(TELOPT_SGA, 1);
107961f28255Scgd     send_dont(TELOPT_ECHO, 1);
1080434ea11bSchristos     return 1;
108161f28255Scgd }
108261f28255Scgd #endif
108361f28255Scgd 
108461f28255Scgd static int
dolinemode(int n)108526583868Schristos dolinemode(int n)
108661f28255Scgd {
108761f28255Scgd #ifdef	KLUDGELINEMODE
108861f28255Scgd     if (kludgelinemode)
108961f28255Scgd 	send_dont(TELOPT_SGA, 1);
109061f28255Scgd #endif
109161f28255Scgd     send_will(TELOPT_LINEMODE, 1);
109261f28255Scgd     send_dont(TELOPT_ECHO, 1);
109361f28255Scgd     return 1;
109461f28255Scgd }
109561f28255Scgd 
109661f28255Scgd static int
docharmode(int n)109726583868Schristos docharmode(int n)
109861f28255Scgd {
109961f28255Scgd #ifdef	KLUDGELINEMODE
110061f28255Scgd     if (kludgelinemode)
110161f28255Scgd 	send_do(TELOPT_SGA, 1);
110261f28255Scgd     else
110361f28255Scgd #endif
110461f28255Scgd     send_wont(TELOPT_LINEMODE, 1);
110561f28255Scgd     send_do(TELOPT_ECHO, 1);
110661f28255Scgd     return 1;
110761f28255Scgd }
110861f28255Scgd 
110961f28255Scgd static int
dolmmode(int bit,int on)111026583868Schristos dolmmode(int bit, int on)
111161f28255Scgd {
111261f28255Scgd     unsigned char c;
111361f28255Scgd     extern int linemode;
111461f28255Scgd 
111561f28255Scgd     if (my_want_state_is_wont(TELOPT_LINEMODE)) {
111661f28255Scgd 	printf("?Need to have LINEMODE option enabled first.\n");
111761f28255Scgd 	printf("'mode ?' for help.\n");
111861f28255Scgd 	return 0;
111961f28255Scgd     }
112061f28255Scgd 
112161f28255Scgd     if (on)
1122dbe0036bSchristos 	c = (unsigned char)(linemode | bit);
112361f28255Scgd     else
1124dbe0036bSchristos 	c = (unsigned char)(linemode & ~bit);
112561f28255Scgd     lm_mode(&c, 1, 1);
112661f28255Scgd     return 1;
112761f28255Scgd }
112861f28255Scgd 
112961f28255Scgd int
set_mode(int bit)113026583868Schristos set_mode(int bit)
113161f28255Scgd {
113261f28255Scgd     return dolmmode(bit, 1);
113361f28255Scgd }
113461f28255Scgd 
113561f28255Scgd int
clear_mode(int bit)113626583868Schristos clear_mode(int bit)
113761f28255Scgd {
113861f28255Scgd     return dolmmode(bit, 0);
113961f28255Scgd }
114061f28255Scgd 
114161f28255Scgd struct modelist {
1142fcdbba42Schristos 	const char	*name;	/* command name */
1143fcdbba42Schristos 	const char	*help;	/* help string */
1144434ea11bSchristos 	int	(*handler)	/* routine which executes command */
1145797d779cSwiz 			(int);
114661f28255Scgd 	int	needconnect;	/* Do we need to be connected to execute? */
114761f28255Scgd 	int	arg1;
114861f28255Scgd };
114961f28255Scgd 
115061f28255Scgd static struct modelist ModeList[] = {
1151fcdbba42Schristos     { "character", "Disable LINEMODE option",	docharmode, 1, 0 },
115261f28255Scgd #ifdef	KLUDGELINEMODE
1153fcdbba42Schristos     { "",	"(or disable obsolete line-by-line mode)", 0, 0, 0 },
115461f28255Scgd #endif
1155fcdbba42Schristos     { "line",	"Enable LINEMODE option",	dolinemode, 1, 0 },
115661f28255Scgd #ifdef	KLUDGELINEMODE
1157fcdbba42Schristos     { "",	"(or enable obsolete line-by-line mode)", 0, 0, 0 },
115861f28255Scgd #endif
1159fcdbba42Schristos     { "", "", 0, 0, 0 },
1160fcdbba42Schristos     { "",	"These require the LINEMODE option to be enabled", 0, 0, 0 },
1161434ea11bSchristos     { "isig",	"Enable signal trapping",	set_mode, 1, MODE_TRAPSIG },
1162434ea11bSchristos     { "+isig",	0,				set_mode, 1, MODE_TRAPSIG },
1163434ea11bSchristos     { "-isig",	"Disable signal trapping",	clear_mode, 1, MODE_TRAPSIG },
1164434ea11bSchristos     { "edit",	"Enable character editing",	set_mode, 1, MODE_EDIT },
1165434ea11bSchristos     { "+edit",	0,				set_mode, 1, MODE_EDIT },
1166434ea11bSchristos     { "-edit",	"Disable character editing",	clear_mode, 1, MODE_EDIT },
1167434ea11bSchristos     { "softtabs", "Enable tab expansion",	set_mode, 1, MODE_SOFT_TAB },
1168434ea11bSchristos     { "+softtabs", 0,				set_mode, 1, MODE_SOFT_TAB },
1169434ea11bSchristos     { "-softtabs", "Disable character editing",	clear_mode, 1, MODE_SOFT_TAB },
1170434ea11bSchristos     { "litecho", "Enable literal character echo", set_mode, 1, MODE_LIT_ECHO },
1171434ea11bSchristos     { "+litecho", 0,				set_mode, 1, MODE_LIT_ECHO },
1172434ea11bSchristos     { "-litecho", "Disable literal character echo", clear_mode, 1, MODE_LIT_ECHO },
1173fcdbba42Schristos     { "help",	0,				modehelp, 0, 0 },
117461f28255Scgd #ifdef	KLUDGELINEMODE
1175fcdbba42Schristos     { "kludgeline", 0,				dokludgemode, 1, 0 },
117661f28255Scgd #endif
1177fcdbba42Schristos     { "", "", 0, 0, 0 },
1178fcdbba42Schristos     { "?",	"Print help information",	modehelp, 0, 0 },
1179fcdbba42Schristos     { .name = 0 },
118061f28255Scgd };
118161f28255Scgd 
118261f28255Scgd 
118361f28255Scgd int
modehelp(int n)118426583868Schristos modehelp(int n)
118561f28255Scgd {
118661f28255Scgd     struct modelist *mt;
118761f28255Scgd 
118861f28255Scgd     printf("format is:  'mode Mode', where 'Mode' is one of:\n\n");
118961f28255Scgd     for (mt = ModeList; mt->name; mt++) {
119061f28255Scgd 	if (mt->help) {
119161f28255Scgd 	    if (*mt->help)
119261f28255Scgd 		printf("%-15s %s\n", mt->name, mt->help);
119361f28255Scgd 	    else
119461f28255Scgd 		printf("\n");
119561f28255Scgd 	}
119661f28255Scgd     }
119761f28255Scgd     return 0;
119861f28255Scgd }
119961f28255Scgd 
120061f28255Scgd #define	GETMODECMD(name) (struct modelist *) \
120161f28255Scgd 		genget(name, (char **) ModeList, sizeof(struct modelist))
120261f28255Scgd 
120361f28255Scgd static int
modecmd(int argc,char * argv[])120426583868Schristos modecmd(int  argc, char *argv[])
120561f28255Scgd {
120661f28255Scgd     struct modelist *mt;
120761f28255Scgd 
120861f28255Scgd     if (argc != 2) {
120961f28255Scgd 	printf("'mode' command requires an argument\n");
121061f28255Scgd 	printf("'mode ?' for help.\n");
121161f28255Scgd     } else if ((mt = GETMODECMD(argv[1])) == 0) {
121261f28255Scgd 	fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]);
121361f28255Scgd     } else if (Ambiguous(mt)) {
121461f28255Scgd 	fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]);
121561f28255Scgd     } else if (mt->needconnect && !connected) {
121661f28255Scgd 	printf("?Need to be connected first.\n");
121761f28255Scgd 	printf("'mode ?' for help.\n");
121861f28255Scgd     } else if (mt->handler) {
121961f28255Scgd 	return (*mt->handler)(mt->arg1);
122061f28255Scgd     }
122161f28255Scgd     return 0;
122261f28255Scgd }
122361f28255Scgd 
122461f28255Scgd /*
122561f28255Scgd  * The following data structures and routines implement the
122661f28255Scgd  * "display" command.
122761f28255Scgd  */
122861f28255Scgd 
122961f28255Scgd static int
display(int argc,char * argv[])123026583868Schristos display(int  argc, char *argv[])
123161f28255Scgd {
123261f28255Scgd     struct togglelist *tl;
123361f28255Scgd     struct setlist *sl;
123461f28255Scgd 
123561f28255Scgd #define	dotog(tl)	if (tl->variable && tl->actionexplanation) { \
123661f28255Scgd 			    if (*tl->variable) { \
123761f28255Scgd 				printf("will"); \
123861f28255Scgd 			    } else { \
123961f28255Scgd 				printf("won't"); \
124061f28255Scgd 			    } \
124161f28255Scgd 			    printf(" %s.\n", tl->actionexplanation); \
124261f28255Scgd 			}
124361f28255Scgd 
124461f28255Scgd #define	doset(sl)   if (sl->name && *sl->name != ' ') { \
124561f28255Scgd 			if (sl->handler == 0) \
124661f28255Scgd 			    printf("%-15s [%s]\n", sl->name, control(*sl->charp)); \
124761f28255Scgd 			else \
1248dbe0036bSchristos 			    printf("%-15s \"%s\"\n", sl->name, sl->charp); \
124961f28255Scgd 		    }
125061f28255Scgd 
125161f28255Scgd     if (argc == 1) {
125261f28255Scgd 	for (tl = Togglelist; tl->name; tl++) {
125361f28255Scgd 	    dotog(tl);
125461f28255Scgd 	}
125561f28255Scgd 	printf("\n");
125661f28255Scgd 	for (sl = Setlist; sl->name; sl++) {
125761f28255Scgd 	    doset(sl);
125861f28255Scgd 	}
125961f28255Scgd     } else {
126061f28255Scgd 	int i;
126161f28255Scgd 
126261f28255Scgd 	for (i = 1; i < argc; i++) {
126361f28255Scgd 	    sl = getset(argv[i]);
126461f28255Scgd 	    tl = GETTOGGLE(argv[i]);
126561f28255Scgd 	    if (Ambiguous(sl) || Ambiguous(tl)) {
126661f28255Scgd 		printf("?Ambiguous argument '%s'.\n", argv[i]);
126761f28255Scgd 		return 0;
126861f28255Scgd 	    } else if (!sl && !tl) {
126961f28255Scgd 		printf("?Unknown argument '%s'.\n", argv[i]);
127061f28255Scgd 		return 0;
127161f28255Scgd 	    } else {
127261f28255Scgd 		if (tl) {
127361f28255Scgd 		    dotog(tl);
127461f28255Scgd 		}
127561f28255Scgd 		if (sl) {
127661f28255Scgd 		    doset(sl);
127761f28255Scgd 		}
127861f28255Scgd 	    }
127961f28255Scgd 	}
128061f28255Scgd     }
128161f28255Scgd /*@*/optionstatus();
12825c099b14Sthorpej #ifdef	ENCRYPTION
12838a135c6aSmaya     EncryptStatus(NULL, NULL);
12845c099b14Sthorpej #endif	/* ENCRYPTION */
128561f28255Scgd     return 1;
128661f28255Scgd #undef	doset
128761f28255Scgd #undef	dotog
128861f28255Scgd }
128961f28255Scgd 
129061f28255Scgd /*
129161f28255Scgd  * The following are the data structures, and many of the routines,
129261f28255Scgd  * relating to command processing.
129361f28255Scgd  */
129461f28255Scgd 
129561f28255Scgd /*
129661f28255Scgd  * Set the escape character.
129761f28255Scgd  */
129861f28255Scgd static int
setescape(int argc,char * argv[])129926583868Schristos setescape(int argc, char *argv[])
130061f28255Scgd {
1301797d779cSwiz 	char *arg;
130261f28255Scgd 	char buf[50];
130361f28255Scgd 
130461f28255Scgd 	printf(
130561f28255Scgd 	    "Deprecated usage - please use 'set escape%s%s' in the future.\n",
130661f28255Scgd 				(argc > 2)? " ":"", (argc > 2)? argv[1]: "");
130761f28255Scgd 	if (argc > 2)
130861f28255Scgd 		arg = argv[1];
130961f28255Scgd 	else {
131061f28255Scgd 		printf("new escape character: ");
131161f28255Scgd 		(void) fgets(buf, sizeof(buf), stdin);
131261f28255Scgd 		arg = buf;
131361f28255Scgd 	}
131461f28255Scgd 	if (arg[0] != '\0')
1315dbe0036bSchristos 		escape = (cc_t)arg[0];
13164e424770Smaya 
131761f28255Scgd 	printf("Escape character is '%s'.\n", control(escape));
131861f28255Scgd 	(void) fflush(stdout);
131961f28255Scgd 	return 1;
132061f28255Scgd }
132161f28255Scgd 
132261f28255Scgd /*VARARGS*/
132361f28255Scgd static int
togcrmod(int argc,char * argv[])132426583868Schristos togcrmod(int argc, char *argv[])
132561f28255Scgd {
132661f28255Scgd     crmod = !crmod;
132761f28255Scgd     printf("Deprecated usage - please use 'toggle crmod' in the future.\n");
132861f28255Scgd     printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't");
132961f28255Scgd     (void) fflush(stdout);
133061f28255Scgd     return 1;
133161f28255Scgd }
133261f28255Scgd 
133361f28255Scgd /*VARARGS*/
133461f28255Scgd int
suspend(int argc,char * argv[])133526583868Schristos suspend(int argc, char *argv[])
133661f28255Scgd {
133761f28255Scgd     setcommandmode();
133861f28255Scgd     {
133961f28255Scgd 	long oldrows, oldcols, newrows, newcols, err;
134061f28255Scgd 
13410582c913Scgd 	err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0;
134261f28255Scgd 	(void) kill(0, SIGTSTP);
13430582c913Scgd 	/*
13440582c913Scgd 	 * If we didn't get the window size before the SUSPEND, but we
1345583a8146Sjtk 	 * can get them now (?), then send the NAWS to make sure that
13460582c913Scgd 	 * we are set up for the right window size.
13470582c913Scgd 	 */
13480582c913Scgd 	if (TerminalWindowSize(&newrows, &newcols) && connected &&
13490582c913Scgd 	    (err || ((oldrows != newrows) || (oldcols != newcols)))) {
135061f28255Scgd 		sendnaws();
135161f28255Scgd 	}
135261f28255Scgd     }
135361f28255Scgd     /* reget parameters in case they were changed */
135461f28255Scgd     TerminalSaveState();
135561f28255Scgd     setconnmode(0);
135661f28255Scgd     return 1;
135761f28255Scgd }
135861f28255Scgd 
135961f28255Scgd /*ARGSUSED*/
136061f28255Scgd int
shell(int argc,char * argv[])136126583868Schristos shell(int argc, char *argv[])
136261f28255Scgd {
1363019209fdSchristos     long oldrows, oldcols, newrows, newcols;
1364019209fdSchristos     long volatile err;	/* Avoid vfork clobbering */
1365e0008f3aSthorpej 
136661f28255Scgd     setcommandmode();
13670582c913Scgd 
13680582c913Scgd     err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0;
136961f28255Scgd     switch(vfork()) {
137061f28255Scgd     case -1:
1371dbe0036bSchristos 	warn("Fork failed");
137261f28255Scgd 	break;
137361f28255Scgd 
137461f28255Scgd     case 0:
137561f28255Scgd 	{
137661f28255Scgd 	    /*
137761f28255Scgd 	     * Fire up the shell in the child.
137861f28255Scgd 	     */
1379fcdbba42Schristos 	    const char *shellp, *shellname;
138061f28255Scgd 
138161f28255Scgd 	    shellp = getenv("SHELL");
138261f28255Scgd 	    if (shellp == NULL)
138361f28255Scgd 		shellp = "/bin/sh";
1384583a8146Sjtk 	    if ((shellname = strrchr(shellp, '/')) == 0)
138561f28255Scgd 		shellname = shellp;
138661f28255Scgd 	    else
138761f28255Scgd 		shellname++;
138861f28255Scgd 	    if (argc > 1)
13894bc6feceSmrg 		execl(shellp, shellname, "-c", &saveline[1], NULL);
139061f28255Scgd 	    else
13914bc6feceSmrg 		execl(shellp, shellname, NULL);
1392dbe0036bSchristos 	    warn("execl");
139361f28255Scgd 	    _exit(1);
139461f28255Scgd 	}
139561f28255Scgd     default:
139661f28255Scgd 	    (void)wait((int *)0);	/* Wait for the shell to complete */
13970582c913Scgd 
13980582c913Scgd 	    if (TerminalWindowSize(&newrows, &newcols) && connected &&
13990582c913Scgd 		(err || ((oldrows != newrows) || (oldcols != newcols)))) {
14000582c913Scgd 		    sendnaws();
14010582c913Scgd 	    }
14020582c913Scgd 	    break;
140361f28255Scgd     }
140461f28255Scgd     return 1;
140561f28255Scgd }
140661f28255Scgd 
140761f28255Scgd /*VARARGS*/
1408434ea11bSchristos static int
bye(int argc,char * argv[])140926583868Schristos bye(int  argc, char *argv[])
141061f28255Scgd {
141161f28255Scgd     extern int resettermname;
141261f28255Scgd 
141361f28255Scgd     if (connected) {
141461f28255Scgd 	(void) shutdown(net, 2);
141561f28255Scgd 	printf("Connection closed.\n");
141661f28255Scgd 	(void) NetClose(net);
141761f28255Scgd 	connected = 0;
141861f28255Scgd 	resettermname = 1;
14195c099b14Sthorpej #if	defined(AUTHENTICATION) || defined(ENCRYPTION)
142061f28255Scgd 	auth_encrypt_connect(connected);
14210582c913Scgd #endif	/* defined(AUTHENTICATION) */
142261f28255Scgd 	/* reset options */
142361f28255Scgd 	tninit();
142461f28255Scgd     }
142561f28255Scgd     if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) {
142661f28255Scgd 	longjmp(toplevel, 1);
142761f28255Scgd 	/* NOTREACHED */
142861f28255Scgd     }
142961f28255Scgd     return 1;			/* Keep lint, etc., happy */
143061f28255Scgd }
143161f28255Scgd 
143261f28255Scgd /*VARARGS*/
1433434ea11bSchristos int
quit(int argc,char * argv[])143426583868Schristos quit(int argc, char *argv[])
143561f28255Scgd {
143661f28255Scgd 	(void) call(bye, "bye", "fromquit", 0);
143761f28255Scgd 	Exit(0);
143861f28255Scgd 	/*NOTREACHED*/
143961f28255Scgd }
144061f28255Scgd 
144161f28255Scgd /*VARARGS*/
144261f28255Scgd int
logout(int argc,char * argv[])144326583868Schristos logout(int argc, char *argv[])
144461f28255Scgd {
144561f28255Scgd 	send_do(TELOPT_LOGOUT, 1);
144661f28255Scgd 	(void) netflush();
144761f28255Scgd 	return 1;
144861f28255Scgd }
144961f28255Scgd 
145061f28255Scgd 
145161f28255Scgd /*
145261f28255Scgd  * The SLC command.
145361f28255Scgd  */
145461f28255Scgd 
145561f28255Scgd struct slclist {
1456fcdbba42Schristos 	const char	*name;
1457fcdbba42Schristos 	const char	*help;
1458797d779cSwiz 	void	(*handler)(int);
145961f28255Scgd 	int	arg;
146061f28255Scgd };
146161f28255Scgd 
146261f28255Scgd struct slclist SlcList[] = {
146361f28255Scgd     { "export",	"Use local special character definitions",
146461f28255Scgd 						slc_mode_export,	0 },
146561f28255Scgd     { "import",	"Use remote special character definitions",
146661f28255Scgd 						slc_mode_import,	1 },
146761f28255Scgd     { "check",	"Verify remote special character definitions",
146861f28255Scgd 						slc_mode_import,	0 },
146961f28255Scgd     { "help",	0,				slc_help,		0 },
147061f28255Scgd     { "?",	"Print help information",	slc_help,		0 },
1471fcdbba42Schristos     { .name = 0 },
147261f28255Scgd };
147361f28255Scgd 
147461f28255Scgd static void
slc_help(int n)147526583868Schristos slc_help(int n)
147661f28255Scgd {
147761f28255Scgd     struct slclist *c;
147861f28255Scgd 
147961f28255Scgd     for (c = SlcList; c->name; c++) {
148061f28255Scgd 	if (c->help) {
148161f28255Scgd 	    if (*c->help)
148261f28255Scgd 		printf("%-15s %s\n", c->name, c->help);
148361f28255Scgd 	    else
148461f28255Scgd 		printf("\n");
148561f28255Scgd 	}
148661f28255Scgd     }
148761f28255Scgd }
148861f28255Scgd 
148961f28255Scgd static struct slclist *
getslc(const char * name)1490dbe0036bSchristos getslc(const char *name)
149161f28255Scgd {
149261f28255Scgd     return (struct slclist *)
149361f28255Scgd 		genget(name, (char **) SlcList, sizeof(struct slclist));
149461f28255Scgd }
149561f28255Scgd 
1496434ea11bSchristos static int
slccmd(int argc,char * argv[])149726583868Schristos slccmd(int  argc, char *argv[])
149861f28255Scgd {
149961f28255Scgd     struct slclist *c;
150061f28255Scgd 
150161f28255Scgd     if (argc != 2) {
150261f28255Scgd 	fprintf(stderr,
150361f28255Scgd 	    "Need an argument to 'slc' command.  'slc ?' for help.\n");
150461f28255Scgd 	return 0;
150561f28255Scgd     }
150661f28255Scgd     c = getslc(argv[1]);
150761f28255Scgd     if (c == 0) {
150861f28255Scgd 	fprintf(stderr, "'%s': unknown argument ('slc ?' for help).\n",
150961f28255Scgd     				argv[1]);
151061f28255Scgd 	return 0;
151161f28255Scgd     }
151261f28255Scgd     if (Ambiguous(c)) {
151361f28255Scgd 	fprintf(stderr, "'%s': ambiguous argument ('slc ?' for help).\n",
151461f28255Scgd     				argv[1]);
151561f28255Scgd 	return 0;
151661f28255Scgd     }
151761f28255Scgd     (*c->handler)(c->arg);
151861f28255Scgd     slcstate();
151961f28255Scgd     return 1;
152061f28255Scgd }
152161f28255Scgd 
152261f28255Scgd /*
152361f28255Scgd  * The ENVIRON command.
152461f28255Scgd  */
152561f28255Scgd 
152661f28255Scgd struct envlist {
1527fcdbba42Schristos 	const char	*name;
1528fcdbba42Schristos 	const char	*help;
1529dbe0036bSchristos 	struct env_lst *(*handler)(const char *, char *);
153061f28255Scgd 	int	narg;
153161f28255Scgd };
153261f28255Scgd 
153361f28255Scgd struct envlist EnvList[] = {
153461f28255Scgd     { "define",	"Define an environment variable",
1535434ea11bSchristos 						env_define,	2 },
153661f28255Scgd     { "undefine", "Undefine an environment variable",
153761f28255Scgd 						env_undefine,	1 },
153861f28255Scgd     { "export",	"Mark an environment variable for automatic export",
153961f28255Scgd 						env_export,	1 },
154061f28255Scgd     { "unexport", "Don't mark an environment variable for automatic export",
154161f28255Scgd 						env_unexport,	1 },
154261f28255Scgd     { "send",	"Send an environment variable", env_send,	1 },
154361f28255Scgd     { "list",	"List the current environment variables",
154461f28255Scgd 						env_list,	0 },
154561f28255Scgd     { "help",	0,				env_help,		0 },
154661f28255Scgd     { "?",	"Print help information",	env_help,		0 },
1547fcdbba42Schristos     { .name = 0 },
154861f28255Scgd };
154961f28255Scgd 
1550434ea11bSchristos static struct env_lst *
env_help(const char * us1,char * us2)1551dbe0036bSchristos env_help(const char *us1, char *us2)
155261f28255Scgd {
155361f28255Scgd     struct envlist *c;
155461f28255Scgd 
155561f28255Scgd     for (c = EnvList; c->name; c++) {
155661f28255Scgd 	if (c->help) {
155761f28255Scgd 	    if (*c->help)
155861f28255Scgd 		printf("%-15s %s\n", c->name, c->help);
155961f28255Scgd 	    else
156061f28255Scgd 		printf("\n");
156161f28255Scgd 	}
156261f28255Scgd     }
1563434ea11bSchristos     return NULL;
156461f28255Scgd }
156561f28255Scgd 
156661f28255Scgd static struct envlist *
getenvcmd(const char * name)1567dbe0036bSchristos getenvcmd(const char *name)
156861f28255Scgd {
156961f28255Scgd     return (struct envlist *)
157061f28255Scgd 		genget(name, (char **) EnvList, sizeof(struct envlist));
157161f28255Scgd }
157261f28255Scgd 
1573434ea11bSchristos int
env_cmd(int argc,char * argv[])157426583868Schristos env_cmd(int  argc, char *argv[])
157561f28255Scgd {
157661f28255Scgd     struct envlist *c;
157761f28255Scgd 
157861f28255Scgd     if (argc < 2) {
157961f28255Scgd 	fprintf(stderr,
158061f28255Scgd 	    "Need an argument to 'environ' command.  'environ ?' for help.\n");
158161f28255Scgd 	return 0;
158261f28255Scgd     }
158361f28255Scgd     c = getenvcmd(argv[1]);
158461f28255Scgd     if (c == 0) {
158561f28255Scgd 	fprintf(stderr, "'%s': unknown argument ('environ ?' for help).\n",
158661f28255Scgd     				argv[1]);
158761f28255Scgd 	return 0;
158861f28255Scgd     }
158961f28255Scgd     if (Ambiguous(c)) {
159061f28255Scgd 	fprintf(stderr, "'%s': ambiguous argument ('environ ?' for help).\n",
159161f28255Scgd     				argv[1]);
159261f28255Scgd 	return 0;
159361f28255Scgd     }
159461f28255Scgd     if (c->narg + 2 != argc) {
159561f28255Scgd 	fprintf(stderr,
159661f28255Scgd 	    "Need %s%d argument%s to 'environ %s' command.  'environ ?' for help.\n",
159761f28255Scgd 		c->narg < argc + 2 ? "only " : "",
159861f28255Scgd 		c->narg, c->narg == 1 ? "" : "s", c->name);
159961f28255Scgd 	return 0;
160061f28255Scgd     }
160161f28255Scgd     (*c->handler)(argv[2], argv[3]);
160261f28255Scgd     return 1;
160361f28255Scgd }
160461f28255Scgd 
160561f28255Scgd struct env_lst {
160661f28255Scgd 	struct env_lst *next;	/* pointer to next structure */
16070582c913Scgd 	struct env_lst *prev;	/* pointer to previous structure */
160861f28255Scgd 	unsigned char *var;	/* pointer to variable name */
16090582c913Scgd 	unsigned char *value;	/* pointer to variable value */
161061f28255Scgd 	int export;		/* 1 -> export with default list of variables */
16110582c913Scgd 	int welldefined;	/* A well defined variable */
161261f28255Scgd };
161361f28255Scgd 
161461f28255Scgd struct env_lst envlisthead;
161561f28255Scgd 
161661f28255Scgd struct env_lst *
env_find(const char * var)1617dbe0036bSchristos env_find(const char *var)
161861f28255Scgd {
1619797d779cSwiz 	struct env_lst *ep;
162061f28255Scgd 
162161f28255Scgd 	for (ep = envlisthead.next; ep; ep = ep->next) {
1622dbe0036bSchristos 		if (strcmp(ep->var, var) == 0)
1623dbe0036bSchristos 			return ep;
162461f28255Scgd 	}
1625dbe0036bSchristos 	return NULL;
162661f28255Scgd }
162761f28255Scgd 
162861f28255Scgd void
env_init(void)162926583868Schristos env_init(void)
163061f28255Scgd {
163161f28255Scgd 	extern char **environ;
1632797d779cSwiz 	char **epp, *cp;
1633797d779cSwiz 	struct env_lst *ep;
163461f28255Scgd 
163561f28255Scgd 	for (epp = environ; *epp; epp++) {
1636434ea11bSchristos 		if ((cp = strchr(*epp, '=')) != NULL) {
163761f28255Scgd 			*cp = '\0';
163861f28255Scgd 			ep = env_define((unsigned char *)*epp,
163961f28255Scgd 					(unsigned char *)cp+1);
164061f28255Scgd 			ep->export = 0;
164161f28255Scgd 			*cp = '=';
164261f28255Scgd 		}
164361f28255Scgd 	}
164461f28255Scgd 	/*
164561f28255Scgd 	 * Special case for DISPLAY variable.  If it is ":0.0" or
164661f28255Scgd 	 * "unix:0.0", we have to get rid of "unix" and insert our
164761f28255Scgd 	 * hostname.
164861f28255Scgd 	 */
164961f28255Scgd 	if ((ep = env_find("DISPLAY"))
165061f28255Scgd 	    && ((*ep->value == ':')
1651dbe0036bSchristos 		|| (strncmp(ep->value, "unix:", 5) == 0))) {
165232f51971Smrg 		char hbuf[MAXHOSTNAMELEN + 1];
1653dbe0036bSchristos 		char *cp2 = strchr(ep->value, ':');
165461f28255Scgd 
165532f51971Smrg 		gethostname(hbuf, sizeof hbuf);
1656d310ce0dSfvdl 		hbuf[sizeof(hbuf) - 1] = '\0';
1657dbe0036bSchristos 		if (asprintf(&cp, "%s%s", hbuf, cp2) < 0)
1658dbe0036bSchristos 			err(1, "Out of memory");
165961f28255Scgd 		free(ep->value);
1660dbe0036bSchristos 		ep->value = cp;
166161f28255Scgd 	}
166261f28255Scgd 	/*
166361f28255Scgd 	 * If USER is not defined, but LOGNAME is, then add
166461f28255Scgd 	 * USER with the value from LOGNAME.  By default, we
166561f28255Scgd 	 * don't export the USER variable.
166661f28255Scgd 	 */
166761f28255Scgd 	if ((env_find("USER") == NULL) && (ep = env_find("LOGNAME"))) {
1668dbe0036bSchristos 		env_define("USER", ep->value);
1669dbe0036bSchristos 		env_unexport("USER", NULL);
167061f28255Scgd 	}
1671dbe0036bSchristos 	env_export("DISPLAY", NULL);
1672dbe0036bSchristos 	env_export("PRINTER", NULL);
167361f28255Scgd }
167461f28255Scgd 
167561f28255Scgd struct env_lst *
env_define(const char * var,char * value)1676dbe0036bSchristos env_define(const char *var, char *value)
167761f28255Scgd {
1678797d779cSwiz 	struct env_lst *ep;
167961f28255Scgd 
1680434ea11bSchristos 	if ((ep = env_find(var)) != NULL) {
168161f28255Scgd 		if (ep->var)
168261f28255Scgd 			free(ep->var);
168361f28255Scgd 		if (ep->value)
168461f28255Scgd 			free(ep->value);
168561f28255Scgd 	} else {
168661f28255Scgd 		ep = (struct env_lst *)malloc(sizeof(struct env_lst));
168761f28255Scgd 		ep->next = envlisthead.next;
168861f28255Scgd 		envlisthead.next = ep;
168961f28255Scgd 		ep->prev = &envlisthead;
169061f28255Scgd 		if (ep->next)
169161f28255Scgd 			ep->next->prev = ep;
169261f28255Scgd 	}
16930582c913Scgd 	ep->welldefined = opt_welldefined(var);
169461f28255Scgd 	ep->export = 1;
1695dbe0036bSchristos 	ep->var = strdup(var);
1696dbe0036bSchristos 	ep->value = strdup(value);
1697dbe0036bSchristos 	return ep;
169861f28255Scgd }
169961f28255Scgd 
1700434ea11bSchristos struct env_lst *
env_undefine(const char * var,char * d)1701dbe0036bSchristos env_undefine(const char *var, char *d)
170261f28255Scgd {
1703797d779cSwiz 	struct env_lst *ep;
170461f28255Scgd 
1705434ea11bSchristos 	if ((ep = env_find(var)) != NULL) {
170661f28255Scgd 		ep->prev->next = ep->next;
170761f28255Scgd 		if (ep->next)
170861f28255Scgd 			ep->next->prev = ep->prev;
170961f28255Scgd 		if (ep->var)
171061f28255Scgd 			free(ep->var);
171161f28255Scgd 		if (ep->value)
171261f28255Scgd 			free(ep->value);
171361f28255Scgd 		free(ep);
171461f28255Scgd 	}
1715434ea11bSchristos 	return NULL;
171661f28255Scgd }
171761f28255Scgd 
1718434ea11bSchristos struct env_lst *
env_export(const char * var,char * d)1719dbe0036bSchristos env_export(const char *var, char *d)
172061f28255Scgd {
1721797d779cSwiz 	struct env_lst *ep;
172261f28255Scgd 
1723434ea11bSchristos 	if ((ep = env_find(var)) != NULL)
172461f28255Scgd 		ep->export = 1;
1725434ea11bSchristos 	return NULL;
172661f28255Scgd }
172761f28255Scgd 
1728434ea11bSchristos struct env_lst *
env_unexport(const char * var,char * d)1729dbe0036bSchristos env_unexport(const char *var, char *d)
173061f28255Scgd {
1731797d779cSwiz 	struct env_lst *ep;
173261f28255Scgd 
1733434ea11bSchristos 	if ((ep = env_find(var)) != NULL)
173461f28255Scgd 		ep->export = 0;
1735434ea11bSchristos 	return NULL;
173661f28255Scgd }
173761f28255Scgd 
1738434ea11bSchristos struct env_lst *
env_send(const char * var,char * d)1739dbe0036bSchristos env_send(const char *var, char *d)
174061f28255Scgd {
1741797d779cSwiz 	struct env_lst *ep;
174261f28255Scgd 
17430582c913Scgd 	if (my_state_is_wont(TELOPT_NEW_ENVIRON)
17440582c913Scgd 		) {
174561f28255Scgd 		fprintf(stderr,
174661f28255Scgd 		    "Cannot send '%s': Telnet ENVIRON option not enabled\n",
174761f28255Scgd 									var);
1748434ea11bSchristos 		return NULL;
174961f28255Scgd 	}
175061f28255Scgd 	ep = env_find(var);
175161f28255Scgd 	if (ep == 0) {
175261f28255Scgd 		fprintf(stderr, "Cannot send '%s': variable not defined\n",
175361f28255Scgd 									var);
1754434ea11bSchristos 		return NULL;
175561f28255Scgd 	}
175661f28255Scgd 	env_opt_start_info();
175761f28255Scgd 	env_opt_add(ep->var);
175861f28255Scgd 	env_opt_end(0);
1759434ea11bSchristos 	return NULL;
176061f28255Scgd }
176161f28255Scgd 
1762434ea11bSchristos struct env_lst *
env_list(const char * d1,char * d2)1763dbe0036bSchristos env_list(const char *d1, char *d2)
176461f28255Scgd {
1765797d779cSwiz 	struct env_lst *ep;
176661f28255Scgd 
176761f28255Scgd 	for (ep = envlisthead.next; ep; ep = ep->next) {
176861f28255Scgd 		printf("%c %-20s %s\n", ep->export ? '*' : ' ',
176961f28255Scgd 					ep->var, ep->value);
177061f28255Scgd 	}
1771434ea11bSchristos 	return NULL;
177261f28255Scgd }
177361f28255Scgd 
1774dbe0036bSchristos char *
env_default(int init,int welldefined)177526583868Schristos env_default(int init, int welldefined)
177661f28255Scgd {
177761f28255Scgd 	static struct env_lst *nep = NULL;
177861f28255Scgd 
177961f28255Scgd 	if (init) {
178061f28255Scgd 		nep = &envlisthead;
1781434ea11bSchristos 		return NULL;
178261f28255Scgd 	}
1783dbe0036bSchristos 	if (!nep) {
1784dbe0036bSchristos 		return NULL;
1785dbe0036bSchristos 	}
1786434ea11bSchristos 	while ((nep = nep->next) != NULL) {
17870582c913Scgd 		if (nep->export && (nep->welldefined == welldefined))
1788dbe0036bSchristos 			return nep->var;
178961f28255Scgd 	}
1790dbe0036bSchristos 	return NULL;
179161f28255Scgd }
179261f28255Scgd 
1793dbe0036bSchristos char *
env_getvalue(const char * var)1794dbe0036bSchristos env_getvalue(const char *var)
179561f28255Scgd {
1796797d779cSwiz 	struct env_lst *ep;
179761f28255Scgd 
1798434ea11bSchristos 	if ((ep = env_find(var)) != NULL)
1799dbe0036bSchristos 		return ep->value;
1800dbe0036bSchristos 	return NULL;
180161f28255Scgd }
180261f28255Scgd 
180321f5307cSitojun #ifdef AUTHENTICATION
180461f28255Scgd /*
180561f28255Scgd  * The AUTHENTICATE command.
180661f28255Scgd  */
180761f28255Scgd 
180861f28255Scgd struct authlist {
1809fcdbba42Schristos 	const char	*name;
1810fcdbba42Schristos 	const char	*help;
1811dbe0036bSchristos 	int	(*handler)(const char *);
181261f28255Scgd 	int	narg;
181361f28255Scgd };
181461f28255Scgd 
181561f28255Scgd struct authlist AuthList[] = {
181661f28255Scgd     { "status",	"Display current status of authentication information",
181761f28255Scgd 						auth_status,	0 },
181861f28255Scgd     { "disable", "Disable an authentication type ('auth disable ?' for more)",
181961f28255Scgd 						auth_disable,	1 },
182061f28255Scgd     { "enable", "Enable an authentication type ('auth enable ?' for more)",
182161f28255Scgd 						auth_enable,	1 },
182261f28255Scgd     { "help",	0,				auth_help,		0 },
182361f28255Scgd     { "?",	"Print help information",	auth_help,		0 },
1824fcdbba42Schristos     { .name = 0 },
182561f28255Scgd };
182661f28255Scgd 
182761f28255Scgd static int
auth_help(const char * s)1828dbe0036bSchristos auth_help(const char *s)
182961f28255Scgd {
183061f28255Scgd     struct authlist *c;
183161f28255Scgd 
183261f28255Scgd     for (c = AuthList; c->name; c++) {
183361f28255Scgd 	if (c->help) {
183461f28255Scgd 	    if (*c->help)
183561f28255Scgd 		printf("%-15s %s\n", c->name, c->help);
183661f28255Scgd 	    else
183761f28255Scgd 		printf("\n");
183861f28255Scgd 	}
183961f28255Scgd     }
184061f28255Scgd     return 0;
184161f28255Scgd }
184261f28255Scgd 
184381c93f4cSchristos int
auth_cmd(int argc,char * argv[])184426583868Schristos auth_cmd(int  argc, char *argv[])
184561f28255Scgd {
184661f28255Scgd     struct authlist *c;
184761f28255Scgd 
1848583a8146Sjtk     if (argc < 2) {
1849583a8146Sjtk 	fprintf(stderr,
1850583a8146Sjtk 	    "Need an argument to 'auth' command.  'auth ?' for help.\n");
1851583a8146Sjtk 	return 0;
1852583a8146Sjtk     }
1853583a8146Sjtk 
185461f28255Scgd     c = (struct authlist *)
185561f28255Scgd 		genget(argv[1], (char **) AuthList, sizeof(struct authlist));
185661f28255Scgd     if (c == 0) {
185761f28255Scgd 	fprintf(stderr, "'%s': unknown argument ('auth ?' for help).\n",
185861f28255Scgd     				argv[1]);
185961f28255Scgd 	return 0;
186061f28255Scgd     }
186161f28255Scgd     if (Ambiguous(c)) {
186261f28255Scgd 	fprintf(stderr, "'%s': ambiguous argument ('auth ?' for help).\n",
186361f28255Scgd     				argv[1]);
186461f28255Scgd 	return 0;
186561f28255Scgd     }
186661f28255Scgd     if (c->narg + 2 != argc) {
186761f28255Scgd 	fprintf(stderr,
186861f28255Scgd 	    "Need %s%d argument%s to 'auth %s' command.  'auth ?' for help.\n",
186961f28255Scgd 		c->narg < argc + 2 ? "only " : "",
187061f28255Scgd 		c->narg, c->narg == 1 ? "" : "s", c->name);
187161f28255Scgd 	return 0;
187261f28255Scgd     }
1873dbe0036bSchristos     return (*c->handler)(argv[2]);
187461f28255Scgd }
187561f28255Scgd #endif
187661f28255Scgd 
18775c099b14Sthorpej #ifdef	ENCRYPTION
18785c099b14Sthorpej /*
18795c099b14Sthorpej  * The ENCRYPT command.
18805c099b14Sthorpej  */
18815c099b14Sthorpej 
18825c099b14Sthorpej struct encryptlist {
1883fcdbba42Schristos 	const char	*name;
1884fcdbba42Schristos 	const char	*help;
1885797d779cSwiz 	int	(*handler)(char *, char *);
18865c099b14Sthorpej 	int	needconnect;
18875c099b14Sthorpej 	int	minarg;
18885c099b14Sthorpej 	int	maxarg;
18895c099b14Sthorpej };
18905c099b14Sthorpej 
18918a135c6aSmaya static int EncryptHelp(char *, char *);
18925c099b14Sthorpej 
18935c099b14Sthorpej struct encryptlist EncryptList[] = {
18945c099b14Sthorpej     { "enable", "Enable encryption. ('encrypt enable ?' for more)",
18955c099b14Sthorpej 						EncryptEnable, 1, 1, 2 },
18965c099b14Sthorpej     { "disable", "Disable encryption. ('encrypt enable ?' for more)",
18975c099b14Sthorpej 						EncryptDisable, 0, 1, 2 },
18985c099b14Sthorpej     { "type", "Set encryption type. ('encrypt type ?' for more)",
18995c099b14Sthorpej 						EncryptType, 0, 1, 1 },
19005c099b14Sthorpej     { "start", "Start encryption. ('encrypt start ?' for more)",
19018a135c6aSmaya 						EncryptStart, 1, 0, 1 },
19025c099b14Sthorpej     { "stop", "Stop encryption. ('encrypt stop ?' for more)",
19038a135c6aSmaya 						EncryptStop, 1, 0, 1 },
19045c099b14Sthorpej     { "input", "Start encrypting the input stream",
19058a135c6aSmaya 						EncryptStartInput, 1, 0, 0 },
19065c099b14Sthorpej     { "-input", "Stop encrypting the input stream",
19078a135c6aSmaya 						EncryptStopInput, 1, 0, 0 },
19085c099b14Sthorpej     { "output", "Start encrypting the output stream",
19098a135c6aSmaya 						EncryptStartOutput, 1, 0, 0 },
19105c099b14Sthorpej     { "-output", "Stop encrypting the output stream",
19118a135c6aSmaya 						EncryptStopOutput, 1, 0, 0 },
19125c099b14Sthorpej 
19135c099b14Sthorpej     { "status",       "Display current status of authentication information",
19148a135c6aSmaya 						EncryptStatus,	0, 0, 0 },
19155c099b14Sthorpej     { "help", 0,				EncryptHelp,	0, 0, 0 },
19165c099b14Sthorpej     { "?",    "Print help information",		EncryptHelp,	0, 0, 0 },
1917fcdbba42Schristos     { .name = 0 },
19185c099b14Sthorpej };
19195c099b14Sthorpej 
19205c099b14Sthorpej static int
EncryptHelp(char * s1,char * s2)192126583868Schristos EncryptHelp(char *s1, char *s2)
19225c099b14Sthorpej {
19235c099b14Sthorpej 	struct encryptlist *c;
19245c099b14Sthorpej 
19255c099b14Sthorpej 	for (c = EncryptList; c->name; c++) {
19265c099b14Sthorpej 		if (c->help) {
19275c099b14Sthorpej 			if (*c->help)
19285c099b14Sthorpej 				printf("%-15s %s\n", c->name, c->help);
19295c099b14Sthorpej 			else
19305c099b14Sthorpej 				printf("\n");
19315c099b14Sthorpej 		}
19325c099b14Sthorpej 	}
19335c099b14Sthorpej 	return (0);
19345c099b14Sthorpej }
19355c099b14Sthorpej 
19365c099b14Sthorpej int
encrypt_cmd(int argc,char * argv[])193726583868Schristos encrypt_cmd(int argc, char *argv[])
19385c099b14Sthorpej {
19395c099b14Sthorpej 	struct encryptlist *c;
19405c099b14Sthorpej 
19415c099b14Sthorpej 	if (argc < 2) {
19425c099b14Sthorpej 		fprintf(stderr,
19435c099b14Sthorpej 		    "Need an argument to 'encrypt' command.  "
19445c099b14Sthorpej 		    "'encrypt ?' for help.\n");
19455c099b14Sthorpej 		return (0);
19465c099b14Sthorpej 	}
19475c099b14Sthorpej 
19485c099b14Sthorpej 	c = (struct encryptlist *)
19495c099b14Sthorpej 	    genget(argv[1], (char **) EncryptList, sizeof(struct encryptlist));
19505c099b14Sthorpej 	if (c == NULL) {
19515c099b14Sthorpej 		fprintf(stderr,
19525c099b14Sthorpej 		    "'%s': unknown argument ('encrypt ?' for help).\n",
19535c099b14Sthorpej 		    argv[1]);
19545c099b14Sthorpej 		return (0);
19555c099b14Sthorpej 	}
19565c099b14Sthorpej 	if (Ambiguous(c)) {
19575c099b14Sthorpej 		fprintf(stderr,
19585c099b14Sthorpej 		    "'%s': ambiguous argument ('encrypt ?' for help).\n",
19595c099b14Sthorpej 		    argv[1]);
19605c099b14Sthorpej 		return (0);
19615c099b14Sthorpej 	}
19625c099b14Sthorpej 	argc -= 2;
19635c099b14Sthorpej 	if (argc < c->minarg || argc > c->maxarg) {
19645c099b14Sthorpej 		if (c->minarg == c->maxarg) {
19655c099b14Sthorpej 			fprintf(stderr, "Need %s%d argument%s ",
19665c099b14Sthorpej 			    c->minarg < argc ? "only " : "", c->minarg,
19675c099b14Sthorpej 			    c->minarg == 1 ? "" : "s");
19685c099b14Sthorpej 		} else {
19695c099b14Sthorpej 			fprintf(stderr, "Need %s%d-%d arguments ",
19705c099b14Sthorpej 			    c->maxarg < argc ? "only " : "", c->minarg,
19715c099b14Sthorpej 			    c->maxarg);
19725c099b14Sthorpej 		}
19735c099b14Sthorpej 		fprintf(stderr,
19745c099b14Sthorpej 		    "to 'encrypt %s' command.  'encrypt ?' for help.\n",
19755c099b14Sthorpej 		    c->name);
19765c099b14Sthorpej 		return (0);
19775c099b14Sthorpej 	}
19785c099b14Sthorpej 	if (c->needconnect && !connected) {
19795c099b14Sthorpej 		if (!(argc && (isprefix(argv[2], "help") ||
19805c099b14Sthorpej 		    isprefix(argv[2], "?")))) {
19815c099b14Sthorpej 			printf("?Need to be connected first.\n");
19825c099b14Sthorpej 			return (0);
19835c099b14Sthorpej 		}
19845c099b14Sthorpej 	}
19855c099b14Sthorpej 	return ((*c->handler)(argv[2], argv[3]));
19865c099b14Sthorpej }
19875c099b14Sthorpej #endif	/* ENCRYPTION */
198861f28255Scgd 
198961f28255Scgd 
199061f28255Scgd /*
199161f28255Scgd  * Print status about the connection.
199261f28255Scgd  */
199361f28255Scgd /*ARGSUSED*/
1994434ea11bSchristos static int
status(int argc,char * argv[])199526583868Schristos status(int argc, char *argv[])
199661f28255Scgd {
199761f28255Scgd     if (connected) {
199861f28255Scgd 	printf("Connected to %s.\n", hostname);
199961f28255Scgd 	if ((argc < 2) || strcmp(argv[1], "notmuch")) {
200061f28255Scgd 	    int mode = getconnmode();
200161f28255Scgd 
200261f28255Scgd 	    if (my_want_state_is_will(TELOPT_LINEMODE)) {
200361f28255Scgd 		printf("Operating with LINEMODE option\n");
200461f28255Scgd 		printf("%s line editing\n", (mode&MODE_EDIT) ? "Local" : "No");
200561f28255Scgd 		printf("%s catching of signals\n",
200661f28255Scgd 					(mode&MODE_TRAPSIG) ? "Local" : "No");
200761f28255Scgd 		slcstate();
200861f28255Scgd #ifdef	KLUDGELINEMODE
200961f28255Scgd 	    } else if (kludgelinemode && my_want_state_is_dont(TELOPT_SGA)) {
201061f28255Scgd 		printf("Operating in obsolete linemode\n");
201161f28255Scgd #endif
201261f28255Scgd 	    } else {
201361f28255Scgd 		printf("Operating in single character mode\n");
201461f28255Scgd 		if (localchars)
201561f28255Scgd 		    printf("Catching signals locally\n");
201661f28255Scgd 	    }
201761f28255Scgd 	    printf("%s character echo\n", (mode&MODE_ECHO) ? "Local" : "Remote");
201861f28255Scgd 	    if (my_want_state_is_will(TELOPT_LFLOW))
201961f28255Scgd 		printf("%s flow control\n", (mode&MODE_FLOW) ? "Local" : "No");
20205c099b14Sthorpej #ifdef	ENCRYPTION
20215c099b14Sthorpej 	    encrypt_display();
20225c099b14Sthorpej #endif	/* ENCRYPTION */
202361f28255Scgd 	}
202461f28255Scgd     } else {
202561f28255Scgd 	printf("No connection.\n");
202661f28255Scgd     }
202761f28255Scgd     printf("Escape character is '%s'.\n", control(escape));
202861f28255Scgd     (void) fflush(stdout);
202961f28255Scgd     return 1;
203061f28255Scgd }
203161f28255Scgd 
203261f28255Scgd /*
203361f28255Scgd  * Function that gets called when SIGINFO is received.
203461f28255Scgd  */
2035434ea11bSchristos int
ayt_status(void)203626583868Schristos ayt_status(void)
203761f28255Scgd {
2038434ea11bSchristos     return call(status, "status", "notmuch", 0);
203961f28255Scgd }
204061f28255Scgd 
20419bee0214Sitojun static const char *
sockaddr_ntop(struct sockaddr * sa)204226583868Schristos sockaddr_ntop(struct sockaddr *sa)
20439bee0214Sitojun {
2044e07bdd02Sitojun     static char addrbuf[NI_MAXHOST];
2045e07bdd02Sitojun     const int niflags = NI_NUMERICHOST;
20469bee0214Sitojun 
2047e07bdd02Sitojun     if (getnameinfo(sa, sa->sa_len, addrbuf, sizeof(addrbuf),
2048e07bdd02Sitojun 	    NULL, 0, niflags) == 0)
2049e07bdd02Sitojun 	return addrbuf;
2050e07bdd02Sitojun     else
20519bee0214Sitojun 	return NULL;
20529bee0214Sitojun }
20539bee0214Sitojun 
2054a58fc4d3Sitojun #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
2055797d779cSwiz static int setpolicy (int, struct addrinfo *, char *);
2056a58fc4d3Sitojun 
2057a58fc4d3Sitojun static int
setpolicy(int netw,struct addrinfo * res,char * policy)2058fcdbba42Schristos setpolicy(int netw, struct addrinfo *res, char *policy)
2059a58fc4d3Sitojun {
2060a58fc4d3Sitojun 	char *buf;
2061a58fc4d3Sitojun 	int level;
2062a58fc4d3Sitojun 	int optname;
2063a58fc4d3Sitojun 
2064a58fc4d3Sitojun 	if (policy == NULL)
2065a58fc4d3Sitojun 		return 0;
2066a58fc4d3Sitojun 
2067dbe0036bSchristos 	buf = ipsec_set_policy(policy, (int)strlen(policy));
2068a58fc4d3Sitojun 	if (buf == NULL) {
2069a58fc4d3Sitojun 		printf("%s\n", ipsec_strerror());
2070a58fc4d3Sitojun 		return -1;
2071a58fc4d3Sitojun 	}
2072a58fc4d3Sitojun 	level = res->ai_family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6;
2073a58fc4d3Sitojun 	optname = res->ai_family == AF_INET ? IP_IPSEC_POLICY : IPV6_IPSEC_POLICY;
2074dbe0036bSchristos 	if (setsockopt(netw, level, optname, buf, (socklen_t)ipsec_get_policylen(buf)) < 0){
2075dbe0036bSchristos 		warn("setsockopt");
2076a58fc4d3Sitojun 		return -1;
2077a58fc4d3Sitojun 	}
2078a58fc4d3Sitojun 
2079a58fc4d3Sitojun 	free(buf);
2080a58fc4d3Sitojun 	return 0;
2081a58fc4d3Sitojun }
2082a58fc4d3Sitojun #endif
2083a58fc4d3Sitojun 
208461f28255Scgd int
tn(int argc,char * argv[])208526583868Schristos tn(int argc, char *argv[])
208661f28255Scgd {
20876ae77d03Sitojun     struct addrinfo hints, *res, *res0;
2088fcdbba42Schristos     const char *cause = "telnet: unknown";
2089ca969aaeSchristos     int error, serrno = 0;
2090fcdbba42Schristos     char *cmd, *hostp = 0;
2091fcdbba42Schristos     const char *portp = 0;
2092a405bce5Smycroft     const char *user = 0;
209361f28255Scgd 
209461f28255Scgd     if (connected) {
209561f28255Scgd 	printf("?Already connected to %s\n", hostname);
209661f28255Scgd 	return 0;
209761f28255Scgd     }
209861f28255Scgd     if (argc < 2) {
20997173f166Sitojun 	(void) strlcpy(line, "open ", sizeof(line));
210061f28255Scgd 	printf("(to) ");
2101dbe0036bSchristos 	(void) fgets(&line[strlen(line)], (int)(sizeof(line) - strlen(line)),
2102dbe0036bSchristos 	    stdin);
210361f28255Scgd 	makeargv();
210461f28255Scgd 	argc = margc;
210561f28255Scgd 	argv = margv;
210661f28255Scgd     }
210761f28255Scgd     cmd = *argv;
210861f28255Scgd     --argc; ++argv;
210961f28255Scgd     while (argc) {
2110583a8146Sjtk 	if (strcmp(*argv, "help") == 0 || isprefix(*argv, "?"))
211161f28255Scgd 	    goto usage;
211261f28255Scgd 	if (strcmp(*argv, "-l") == 0) {
211361f28255Scgd 	    --argc; ++argv;
211461f28255Scgd 	    if (argc == 0)
211561f28255Scgd 		goto usage;
211661f28255Scgd 	    user = *argv++;
211761f28255Scgd 	    --argc;
211861f28255Scgd 	    continue;
211961f28255Scgd 	}
212061f28255Scgd 	if (strcmp(*argv, "-a") == 0) {
212161f28255Scgd 	    --argc; ++argv;
212261f28255Scgd 	    autologin = 1;
212361f28255Scgd 	    continue;
212461f28255Scgd 	}
212561f28255Scgd 	if (hostp == 0) {
212661f28255Scgd 	    hostp = *argv++;
212761f28255Scgd 	    --argc;
212861f28255Scgd 	    continue;
212961f28255Scgd 	}
213061f28255Scgd 	if (portp == 0) {
213161f28255Scgd 	    portp = *argv++;
213261f28255Scgd 	    --argc;
213361f28255Scgd 	    continue;
213461f28255Scgd 	}
213561f28255Scgd     usage:
213661f28255Scgd 	printf("usage: %s [-l user] [-a] host-name [port]\n", cmd);
213761f28255Scgd 	return 0;
213861f28255Scgd     }
213961f28255Scgd     if (hostp == 0)
214061f28255Scgd 	goto usage;
214161f28255Scgd 
21427173f166Sitojun     (void) strlcpy(_hostname, hostp, sizeof(_hostname));
21439bee0214Sitojun     hostname = hostp;
21449bee0214Sitojun 
21459bee0214Sitojun     if (!portp) {
214661f28255Scgd 	telnetport = 1;
21479bee0214Sitojun 	portp = "telnet";
2148be9d0297Sjtk     } else if (portp[0] == '-') {
2149be9d0297Sjtk 	/* use telnet negotiation if port number/name preceded by minus sign */
2150be9d0297Sjtk 	telnetport = 1;
2151be9d0297Sjtk 	portp++;
2152955ffe2dSitojun     } else
2153955ffe2dSitojun 	telnetport = 0;
21549bee0214Sitojun 
21559bee0214Sitojun     memset(&hints, 0, sizeof(hints));
2156d4a4b29eSkanaoka     hints.ai_family = family;
21579bee0214Sitojun     hints.ai_socktype = SOCK_STREAM;
21589bee0214Sitojun     hints.ai_protocol = 0;
2159741f9b63Sitojun     hints.ai_flags = AI_NUMERICHOST;	/* avoid forward lookup */
21606ae77d03Sitojun     error = getaddrinfo(hostname, portp, &hints, &res0);
21619bee0214Sitojun     if (!error) {
21629bee0214Sitojun 	/* numeric */
2163741f9b63Sitojun 	if (doaddrlookup &&
2164741f9b63Sitojun 	    getnameinfo(res0->ai_addr, res0->ai_addrlen,
2165741f9b63Sitojun 		_hostname, sizeof(_hostname), NULL, 0, NI_NAMEREQD) == 0)
2166741f9b63Sitojun 	    ; /* okay */
2167032ed69fSitojun 	else
2168032ed69fSitojun 	    strlcpy(_hostname, hostname, sizeof(_hostname));
2169741f9b63Sitojun     } else {
2170741f9b63Sitojun 	/* FQDN - try again with forward DNS lookup */
2171741f9b63Sitojun 	memset(&hints, 0, sizeof(hints));
2172d4a4b29eSkanaoka 	hints.ai_family = family;
2173741f9b63Sitojun 	hints.ai_socktype = SOCK_STREAM;
2174741f9b63Sitojun 	hints.ai_protocol = 0;
2175741f9b63Sitojun 	hints.ai_flags = AI_CANONNAME;
2176741f9b63Sitojun 	error = getaddrinfo(hostname, portp, &hints, &res0);
2177643a3cfaSitojun 	if (error == EAI_SERVICE) {
2178643a3cfaSitojun 	    fprintf(stderr, "tcp/%s: unknown service\n", portp);
2179643a3cfaSitojun 	    return 0;
2180643a3cfaSitojun 	} else if (error) {
21819bee0214Sitojun 	    fprintf(stderr, "%s: %s\n", hostname, gai_strerror(error));
21829bee0214Sitojun 	    return 0;
21839bee0214Sitojun 	}
2184032ed69fSitojun 	if (res0->ai_canonname)
2185032ed69fSitojun 	    (void)strlcpy(_hostname, res0->ai_canonname, sizeof(_hostname));
2186032ed69fSitojun 	else
2187032ed69fSitojun 	    (void)strlcpy(_hostname, hostname, sizeof(_hostname));
2188741f9b63Sitojun     }
21899bee0214Sitojun     hostname = _hostname;
21909bee0214Sitojun 
21916ae77d03Sitojun     net = -1;
21926ae77d03Sitojun     for (res = res0; res; res = res->ai_next) {
21939bee0214Sitojun 	printf("Trying %s...\n", sockaddr_ntop(res->ai_addr));
21949bee0214Sitojun 	net = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
219561f28255Scgd 	if (net < 0) {
2196ca969aaeSchristos 	    serrno = errno;
21976ae77d03Sitojun 	    cause = "telnet: socket";
21986ae77d03Sitojun 	    continue;
219961f28255Scgd 	}
220061f28255Scgd 
22019dfcf4d4She 	if (telnet_debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) {
2202dbe0036bSchristos 	    warn("setsockopt (SO_DEBUG)");
220361f28255Scgd 	}
220461f28255Scgd 
2205a58fc4d3Sitojun #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
2206a58fc4d3Sitojun 	if (setpolicy(net, res, ipsec_policy_in) < 0) {
2207ca969aaeSchristos 	    serrno = errno;
22086ceceb26Sitojun 	    (void) NetClose(net);
22096ceceb26Sitojun 	    net = -1;
22106ceceb26Sitojun 	    continue;
22119bee0214Sitojun 	}
2212a58fc4d3Sitojun 	if (setpolicy(net, res, ipsec_policy_out) < 0) {
2213ca969aaeSchristos 	    serrno = errno;
22146ceceb26Sitojun 	    (void) NetClose(net);
22156ceceb26Sitojun 	    net = -1;
22166ceceb26Sitojun 	    continue;
22179bee0214Sitojun 	}
22189bee0214Sitojun #endif
22199bee0214Sitojun 
22209bee0214Sitojun 	if (connect(net, res->ai_addr, res->ai_addrlen) < 0) {
22219bee0214Sitojun 	    if (res->ai_next) {
2222dbe0036bSchristos 		warn("Connect to address %s: ", sockaddr_ntop(res->ai_addr));
22236ae77d03Sitojun 	    }
2224ca969aaeSchristos 	    serrno = errno;
2225dbe0036bSchristos 	    cause = "Unable to connect to remote host";
222661f28255Scgd 	    (void) NetClose(net);
22276ae77d03Sitojun 	    net = -1;
222861f28255Scgd 	    continue;
222961f28255Scgd 	}
22306ae77d03Sitojun 
223161f28255Scgd 	connected++;
22325c099b14Sthorpej #if	defined(AUTHENTICATION) || defined(ENCRYPTION)
223361f28255Scgd 	auth_encrypt_connect(connected);
22345c099b14Sthorpej #endif	/* defined(AUTHENTICATION) || defined(ENCRYPTION) */
22356ae77d03Sitojun 	break;
22366ae77d03Sitojun     }
22376ae77d03Sitojun     freeaddrinfo(res0);
22386ae77d03Sitojun     if (net < 0 || connected == 0) {
2239ca969aaeSchristos 	warnc(serrno, "%s", cause);
22406ae77d03Sitojun 	return 0;
22416ae77d03Sitojun     }
22426ae77d03Sitojun 
224361f28255Scgd     cmdrc(hostp, hostname);
224461f28255Scgd     if (autologin && user == NULL) {
224561f28255Scgd 	struct passwd *pw;
224661f28255Scgd 
224761f28255Scgd 	user = getenv("USER");
224861f28255Scgd 	if (user == NULL ||
2249434ea11bSchristos 	    ((pw = getpwnam(user)) && pw->pw_uid != getuid())) {
2250434ea11bSchristos 		if ((pw = getpwuid(getuid())) != NULL)
225161f28255Scgd 			user = pw->pw_name;
225261f28255Scgd 		else
225361f28255Scgd 			user = NULL;
225461f28255Scgd 	}
225561f28255Scgd     }
225661f28255Scgd     if (user) {
2257dbe0036bSchristos 	env_define("USER", __UNCONST(user));
2258dbe0036bSchristos 	env_export("USER", NULL);
225961f28255Scgd     }
226061f28255Scgd     (void) call(status, "status", "notmuch", 0);
226161f28255Scgd     telnet(user);
226261f28255Scgd     (void) NetClose(net);
226361f28255Scgd     ExitString("Connection closed by foreign host.\n",1);
226461f28255Scgd     /*NOTREACHED*/
226561f28255Scgd }
226661f28255Scgd 
2267292d795fSthorpej #define HELPINDENT ((int)sizeof ("connect"))
226861f28255Scgd 
226961f28255Scgd static char
227061f28255Scgd 	openhelp[] =	"connect to a site",
227161f28255Scgd 	closehelp[] =	"close current connection",
227261f28255Scgd 	logouthelp[] =	"forcibly logout remote user and close the connection",
227361f28255Scgd 	quithelp[] =	"exit telnet",
227461f28255Scgd 	statushelp[] =	"print status information",
227561f28255Scgd 	helphelp[] =	"print help information",
227661f28255Scgd 	sendhelp[] =	"transmit special characters ('send ?' for more)",
227761f28255Scgd 	sethelp[] = 	"set operating parameters ('set ?' for more)",
227861f28255Scgd 	unsethelp[] = 	"unset operating parameters ('unset ?' for more)",
227961f28255Scgd 	togglestring[] ="toggle operating parameters ('toggle ?' for more)",
2280bfff2fd6Satatat 	slchelp[] =	"change state of special characters ('slc ?' for more)",
228161f28255Scgd 	displayhelp[] =	"display operating parameters",
228221f5307cSitojun #ifdef AUTHENTICATION
228361f28255Scgd 	authhelp[] =	"turn on (off) authentication ('auth ?' for more)",
228461f28255Scgd #endif
22855c099b14Sthorpej #ifdef	ENCRYPTION
22865c099b14Sthorpej 	encrypthelp[] = "turn on (off) encryption ('encrypt ?' for more)",
22875c099b14Sthorpej #endif	/* ENCRYPTION */
228861f28255Scgd 	zhelp[] =	"suspend telnet",
228961f28255Scgd 	shellhelp[] =	"invoke a subshell",
229061f28255Scgd 	envhelp[] =	"change environment variables ('environ ?' for more)",
229161f28255Scgd 	modestring[] = "try to enter line or character mode ('mode ?' for more)";
229261f28255Scgd 
229361f28255Scgd static Command cmdtab[] = {
229461f28255Scgd 	{ "close",	closehelp,	bye,		1 },
229561f28255Scgd 	{ "logout",	logouthelp,	logout,		1 },
229661f28255Scgd 	{ "display",	displayhelp,	display,	0 },
229761f28255Scgd 	{ "mode",	modestring,	modecmd,	0 },
229861f28255Scgd 	{ "open",	openhelp,	tn,		0 },
229961f28255Scgd 	{ "quit",	quithelp,	quit,		0 },
230061f28255Scgd 	{ "send",	sendhelp,	sendcmd,	0 },
230161f28255Scgd 	{ "set",	sethelp,	setcmd,		0 },
230261f28255Scgd 	{ "unset",	unsethelp,	unsetcmd,	0 },
230361f28255Scgd 	{ "status",	statushelp,	status,		0 },
230461f28255Scgd 	{ "toggle",	togglestring,	toggle,		0 },
230561f28255Scgd 	{ "slc",	slchelp,	slccmd,		0 },
23061f245ffbSitojun #ifdef AUTHENTICATION
230761f28255Scgd 	{ "auth",	authhelp,	auth_cmd,	0 },
230861f28255Scgd #endif
23095c099b14Sthorpej #ifdef	ENCRYPTION
23105c099b14Sthorpej 	{ "encrypt",	encrypthelp,	encrypt_cmd,	0 },
23115c099b14Sthorpej #endif
231261f28255Scgd 	{ "z",		zhelp,		suspend,	0 },
231361f28255Scgd 	{ "!",		shellhelp,	shell,		0 },
231461f28255Scgd 	{ "environ",	envhelp,	env_cmd,	0 },
231561f28255Scgd 	{ "?",		helphelp,	help,		0 },
2316434ea11bSchristos 	{ NULL,		NULL,		NULL,		0 }
231761f28255Scgd };
231861f28255Scgd 
231961f28255Scgd static char	crmodhelp[] =	"deprecated command -- use 'toggle crmod' instead";
232061f28255Scgd static char	escapehelp[] =	"deprecated command -- use 'set escape' instead";
232161f28255Scgd 
232261f28255Scgd static Command cmdtab2[] = {
232361f28255Scgd 	{ "help",	0,		help,		0 },
232461f28255Scgd 	{ "escape",	escapehelp,	setescape,	0 },
232561f28255Scgd 	{ "crmod",	crmodhelp,	togcrmod,	0 },
2326434ea11bSchristos 	{ NULL,		NULL,		NULL,		0 }
232761f28255Scgd };
232861f28255Scgd 
232961f28255Scgd 
233061f28255Scgd /*
233161f28255Scgd  * Call routine with argc, argv set from args (terminated by 0).
233261f28255Scgd  */
233361f28255Scgd 
233461f28255Scgd /*VARARGS1*/
2335434ea11bSchristos static int
call(intrtn_t routine,...)2336434ea11bSchristos call(intrtn_t routine, ...)
233761f28255Scgd {
233861f28255Scgd     va_list ap;
233961f28255Scgd     char *args[100];
234061f28255Scgd     int argno = 0;
234161f28255Scgd 
2342434ea11bSchristos     va_start(ap, routine);
234361f28255Scgd     while ((args[argno++] = va_arg(ap, char *)) != 0) {
234461f28255Scgd 	;
234561f28255Scgd     }
234661f28255Scgd     va_end(ap);
234761f28255Scgd     return (*routine)(argno-1, args);
234861f28255Scgd }
234961f28255Scgd 
235061f28255Scgd 
235161f28255Scgd static Command *
getcmd(const char * name)2352dbe0036bSchristos getcmd(const char *name)
235361f28255Scgd {
235461f28255Scgd     Command *cm;
235561f28255Scgd 
2356434ea11bSchristos     if ((cm = (Command *) genget(name, (char **) cmdtab, sizeof(Command))) != NULL)
235761f28255Scgd 	return cm;
235861f28255Scgd     return (Command *) genget(name, (char **) cmdtab2, sizeof(Command));
235961f28255Scgd }
236061f28255Scgd 
236161f28255Scgd void
command(int top,const char * tbuf,int cnt)2362fcdbba42Schristos command(int top, const char *tbuf, int cnt)
236361f28255Scgd {
2364797d779cSwiz     Command *c;
236561f28255Scgd 
236661f28255Scgd     setcommandmode();
236761f28255Scgd     if (!top) {
236861f28255Scgd 	putchar('\n');
236961f28255Scgd     } else {
237061f28255Scgd 	(void) signal(SIGINT, SIG_DFL);
237161f28255Scgd 	(void) signal(SIGQUIT, SIG_DFL);
237261f28255Scgd     }
237361f28255Scgd     for (;;) {
237461f28255Scgd 	if (rlogin == _POSIX_VDISABLE)
237561f28255Scgd 		printf("%s> ", prompt);
237661f28255Scgd 	if (tbuf) {
2377797d779cSwiz 	    char *cp;
237861f28255Scgd 	    cp = line;
237961f28255Scgd 	    while (cnt > 0 && (*cp++ = *tbuf++) != '\n')
238061f28255Scgd 		cnt--;
238161f28255Scgd 	    tbuf = 0;
238261f28255Scgd 	    if (cp == line || *--cp != '\n' || cp == line)
238361f28255Scgd 		goto getline;
238461f28255Scgd 	    *cp = '\0';
238561f28255Scgd 	    if (rlogin == _POSIX_VDISABLE)
238661f28255Scgd 		printf("%s\n", line);
238761f28255Scgd 	} else {
238861f28255Scgd 	getline:
238961f28255Scgd 	    if (rlogin != _POSIX_VDISABLE)
239061f28255Scgd 		printf("%s> ", prompt);
239161f28255Scgd 	    if (fgets(line, sizeof(line), stdin) == NULL) {
239261f28255Scgd 		if (feof(stdin) || ferror(stdin)) {
2393434ea11bSchristos 		    (void) quit(0, NULL);
239461f28255Scgd 		    /*NOTREACHED*/
239561f28255Scgd 		}
239661f28255Scgd 		break;
239761f28255Scgd 	    }
239861f28255Scgd 	}
239961f28255Scgd 	if (line[0] == 0)
240061f28255Scgd 	    break;
240161f28255Scgd 	makeargv();
240261f28255Scgd 	if (margv[0] == 0) {
240361f28255Scgd 	    break;
240461f28255Scgd 	}
240561f28255Scgd 	c = getcmd(margv[0]);
240661f28255Scgd 	if (Ambiguous(c)) {
240761f28255Scgd 	    printf("?Ambiguous command\n");
240861f28255Scgd 	    continue;
240961f28255Scgd 	}
241061f28255Scgd 	if (c == 0) {
241161f28255Scgd 	    printf("?Invalid command\n");
241261f28255Scgd 	    continue;
241361f28255Scgd 	}
241461f28255Scgd 	if (c->needconnect && !connected) {
241561f28255Scgd 	    printf("?Need to be connected first.\n");
241661f28255Scgd 	    continue;
241761f28255Scgd 	}
241861f28255Scgd 	if ((*c->handler)(margc, margv)) {
241961f28255Scgd 	    break;
242061f28255Scgd 	}
242161f28255Scgd     }
242261f28255Scgd     if (!top) {
242361f28255Scgd 	if (!connected) {
242461f28255Scgd 	    longjmp(toplevel, 1);
242561f28255Scgd 	    /*NOTREACHED*/
242661f28255Scgd 	}
242761f28255Scgd 	setconnmode(0);
242861f28255Scgd     }
242961f28255Scgd }
243061f28255Scgd 
243161f28255Scgd /*
243261f28255Scgd  * Help command.
243361f28255Scgd  */
2434434ea11bSchristos static int
help(int argc,char * argv[])243526583868Schristos help(int argc, char *argv[])
243661f28255Scgd {
2437797d779cSwiz 	Command *c;
243861f28255Scgd 
243961f28255Scgd 	if (argc == 1) {
244061f28255Scgd 		printf("Commands may be abbreviated.  Commands are:\n\n");
244161f28255Scgd 		for (c = cmdtab; c->name; c++)
244261f28255Scgd 			if (c->help) {
244361f28255Scgd 				printf("%-*s\t%s\n", HELPINDENT, c->name,
244461f28255Scgd 								    c->help);
244561f28255Scgd 			}
244661f28255Scgd 		return 0;
244761f28255Scgd 	}
244861f28255Scgd 	while (--argc > 0) {
2449797d779cSwiz 		char *arg;
245061f28255Scgd 		arg = *++argv;
245161f28255Scgd 		c = getcmd(arg);
245261f28255Scgd 		if (Ambiguous(c))
245361f28255Scgd 			printf("?Ambiguous help command %s\n", arg);
245461f28255Scgd 		else if (c == (Command *)0)
245561f28255Scgd 			printf("?Invalid help command %s\n", arg);
2456*edf58efcSmlelstv 		else if (c->help)
245761f28255Scgd 			printf("%s\n", c->help);
245861f28255Scgd 	}
245961f28255Scgd 	return 0;
246061f28255Scgd }
246161f28255Scgd 
246261f28255Scgd static char *rcname = 0;
246361f28255Scgd static char rcbuf[128];
246461f28255Scgd 
2465434ea11bSchristos void
cmdrc(const char * m1,const char * m2)246626583868Schristos cmdrc(const char *m1, const char *m2)
246761f28255Scgd {
2468797d779cSwiz     Command *c;
246961f28255Scgd     FILE *rcfile;
247061f28255Scgd     int gotmachine = 0;
2471dbe0036bSchristos     size_t l1 = strlen(m1);
2472dbe0036bSchristos     size_t l2 = strlen(m2);
24736c2663f7Smjl     char m1save[MAXHOSTNAMELEN + 1];
247461f28255Scgd 
247561f28255Scgd     if (skiprc)
247661f28255Scgd 	return;
247761f28255Scgd 
24786c2663f7Smjl     strlcpy(m1save, m1, sizeof(m1save));
247961f28255Scgd     m1 = m1save;
248061f28255Scgd 
248161f28255Scgd     if (rcname == 0) {
248261f28255Scgd 	rcname = getenv("HOME");
248361f28255Scgd 	if (rcname)
24847173f166Sitojun 	    strlcpy(rcbuf, rcname, sizeof(rcbuf));
248561f28255Scgd 	else
248661f28255Scgd 	    rcbuf[0] = '\0';
24877173f166Sitojun 	strlcat(rcbuf, "/.telnetrc", sizeof(rcbuf));
248861f28255Scgd 	rcname = rcbuf;
248961f28255Scgd     }
249061f28255Scgd 
249161f28255Scgd     if ((rcfile = fopen(rcname, "r")) == 0) {
249261f28255Scgd 	return;
249361f28255Scgd     }
249461f28255Scgd 
249561f28255Scgd     for (;;) {
249661f28255Scgd 	if (fgets(line, sizeof(line), rcfile) == NULL)
249761f28255Scgd 	    break;
249861f28255Scgd 	if (line[0] == 0)
249961f28255Scgd 	    break;
250061f28255Scgd 	if (line[0] == '#')
250161f28255Scgd 	    continue;
250261f28255Scgd 	if (gotmachine) {
250381c93f4cSchristos 	    if (!isspace((unsigned char)line[0]))
250461f28255Scgd 		gotmachine = 0;
250561f28255Scgd 	}
250661f28255Scgd 	if (gotmachine == 0) {
250781c93f4cSchristos 	    if (isspace((unsigned char)line[0]))
250861f28255Scgd 		continue;
250961f28255Scgd 	    if (strncasecmp(line, m1, l1) == 0)
25100af6a529Smrg 		memmove(line, &line[l1], sizeof(line) - l1 - 1);
251161f28255Scgd 	    else if (strncasecmp(line, m2, l2) == 0)
25120af6a529Smrg 		memmove(line, &line[l2], sizeof(line) - l2 - 1);
251361f28255Scgd 	    else if (strncasecmp(line, "DEFAULT", 7) == 0)
25140af6a529Smrg 		memmove(line, &line[7], sizeof(line) - 7 - 1);
251561f28255Scgd 	    else
251661f28255Scgd 		continue;
25170af6a529Smrg 	    line[sizeof(line) - 1] = '\0';
251861f28255Scgd 	    if (line[0] != ' ' && line[0] != '\t' && line[0] != '\n')
251961f28255Scgd 		continue;
252061f28255Scgd 	    gotmachine = 1;
252161f28255Scgd 	}
252261f28255Scgd 	makeargv();
252361f28255Scgd 	if (margv[0] == 0)
252461f28255Scgd 	    continue;
252561f28255Scgd 	c = getcmd(margv[0]);
252661f28255Scgd 	if (Ambiguous(c)) {
252761f28255Scgd 	    printf("?Ambiguous command: %s\n", margv[0]);
252861f28255Scgd 	    continue;
252961f28255Scgd 	}
253061f28255Scgd 	if (c == 0) {
253161f28255Scgd 	    printf("?Invalid command: %s\n", margv[0]);
253261f28255Scgd 	    continue;
253361f28255Scgd 	}
253461f28255Scgd 	/*
253561f28255Scgd 	 * This should never happen...
253661f28255Scgd 	 */
253761f28255Scgd 	if (c->needconnect && !connected) {
253861f28255Scgd 	    printf("?Need to be connected first for %s.\n", margv[0]);
253961f28255Scgd 	    continue;
254061f28255Scgd 	}
254161f28255Scgd 	(*c->handler)(margc, margv);
254261f28255Scgd     }
254361f28255Scgd     fclose(rcfile);
254461f28255Scgd }
2545