xref: /minix3/usr.bin/telnet/commands.c (revision 7348b5c52b47a1c199a1754a40bbfa360b536de2)
1*7348b5c5SDavid van Moolenbroek /*	$NetBSD: commands.c,v 1.68 2012/01/09 16:08:55 christos Exp $	*/
2*7348b5c5SDavid van Moolenbroek 
3*7348b5c5SDavid van Moolenbroek /*
4*7348b5c5SDavid van Moolenbroek  * Copyright (C) 1997 and 1998 WIDE Project.
5*7348b5c5SDavid van Moolenbroek  * All rights reserved.
6*7348b5c5SDavid van Moolenbroek  *
7*7348b5c5SDavid van Moolenbroek  * Redistribution and use in source and binary forms, with or without
8*7348b5c5SDavid van Moolenbroek  * modification, are permitted provided that the following conditions
9*7348b5c5SDavid van Moolenbroek  * are met:
10*7348b5c5SDavid van Moolenbroek  * 1. Redistributions of source code must retain the above copyright
11*7348b5c5SDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer.
12*7348b5c5SDavid van Moolenbroek  * 2. Redistributions in binary form must reproduce the above copyright
13*7348b5c5SDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer in the
14*7348b5c5SDavid van Moolenbroek  *    documentation and/or other materials provided with the distribution.
15*7348b5c5SDavid van Moolenbroek  * 3. Neither the name of the project nor the names of its contributors
16*7348b5c5SDavid van Moolenbroek  *    may be used to endorse or promote products derived from this software
17*7348b5c5SDavid van Moolenbroek  *    without specific prior written permission.
18*7348b5c5SDavid van Moolenbroek  *
19*7348b5c5SDavid van Moolenbroek  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20*7348b5c5SDavid van Moolenbroek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21*7348b5c5SDavid van Moolenbroek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22*7348b5c5SDavid van Moolenbroek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23*7348b5c5SDavid van Moolenbroek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24*7348b5c5SDavid van Moolenbroek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25*7348b5c5SDavid van Moolenbroek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26*7348b5c5SDavid van Moolenbroek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27*7348b5c5SDavid van Moolenbroek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28*7348b5c5SDavid van Moolenbroek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29*7348b5c5SDavid van Moolenbroek  * SUCH DAMAGE.
30*7348b5c5SDavid van Moolenbroek  */
31*7348b5c5SDavid van Moolenbroek 
32*7348b5c5SDavid van Moolenbroek /*
33*7348b5c5SDavid van Moolenbroek  * Copyright (c) 1988, 1990, 1993
34*7348b5c5SDavid van Moolenbroek  *	The Regents of the University of California.  All rights reserved.
35*7348b5c5SDavid van Moolenbroek  *
36*7348b5c5SDavid van Moolenbroek  * Redistribution and use in source and binary forms, with or without
37*7348b5c5SDavid van Moolenbroek  * modification, are permitted provided that the following conditions
38*7348b5c5SDavid van Moolenbroek  * are met:
39*7348b5c5SDavid van Moolenbroek  * 1. Redistributions of source code must retain the above copyright
40*7348b5c5SDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer.
41*7348b5c5SDavid van Moolenbroek  * 2. Redistributions in binary form must reproduce the above copyright
42*7348b5c5SDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer in the
43*7348b5c5SDavid van Moolenbroek  *    documentation and/or other materials provided with the distribution.
44*7348b5c5SDavid van Moolenbroek  * 3. Neither the name of the University nor the names of its contributors
45*7348b5c5SDavid van Moolenbroek  *    may be used to endorse or promote products derived from this software
46*7348b5c5SDavid van Moolenbroek  *    without specific prior written permission.
47*7348b5c5SDavid van Moolenbroek  *
48*7348b5c5SDavid van Moolenbroek  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49*7348b5c5SDavid van Moolenbroek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50*7348b5c5SDavid van Moolenbroek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51*7348b5c5SDavid van Moolenbroek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52*7348b5c5SDavid van Moolenbroek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53*7348b5c5SDavid van Moolenbroek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54*7348b5c5SDavid van Moolenbroek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55*7348b5c5SDavid van Moolenbroek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56*7348b5c5SDavid van Moolenbroek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57*7348b5c5SDavid van Moolenbroek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58*7348b5c5SDavid van Moolenbroek  * SUCH DAMAGE.
59*7348b5c5SDavid van Moolenbroek  */
60*7348b5c5SDavid van Moolenbroek 
61*7348b5c5SDavid van Moolenbroek #include <sys/cdefs.h>
62*7348b5c5SDavid van Moolenbroek #ifndef lint
63*7348b5c5SDavid van Moolenbroek #if 0
64*7348b5c5SDavid van Moolenbroek static char sccsid[] = "@(#)commands.c	8.4 (Berkeley) 5/30/95";
65*7348b5c5SDavid van Moolenbroek #else
66*7348b5c5SDavid van Moolenbroek __RCSID("$NetBSD: commands.c,v 1.68 2012/01/09 16:08:55 christos Exp $");
67*7348b5c5SDavid van Moolenbroek #endif
68*7348b5c5SDavid van Moolenbroek #endif /* not lint */
69*7348b5c5SDavid van Moolenbroek 
70*7348b5c5SDavid van Moolenbroek #include <sys/param.h>
71*7348b5c5SDavid van Moolenbroek #include <sys/file.h>
72*7348b5c5SDavid van Moolenbroek #include <sys/wait.h>
73*7348b5c5SDavid van Moolenbroek #include <sys/socket.h>
74*7348b5c5SDavid van Moolenbroek #include <netinet/in.h>
75*7348b5c5SDavid van Moolenbroek #include <arpa/inet.h>
76*7348b5c5SDavid van Moolenbroek 
77*7348b5c5SDavid van Moolenbroek #include <ctype.h>
78*7348b5c5SDavid van Moolenbroek #include <errno.h>
79*7348b5c5SDavid van Moolenbroek #include <netdb.h>
80*7348b5c5SDavid van Moolenbroek #include <pwd.h>
81*7348b5c5SDavid van Moolenbroek #include <signal.h>
82*7348b5c5SDavid van Moolenbroek #include <stdarg.h>
83*7348b5c5SDavid van Moolenbroek #include <unistd.h>
84*7348b5c5SDavid van Moolenbroek 
85*7348b5c5SDavid van Moolenbroek #include <arpa/telnet.h>
86*7348b5c5SDavid van Moolenbroek 
87*7348b5c5SDavid van Moolenbroek #include "general.h"
88*7348b5c5SDavid van Moolenbroek #include "ring.h"
89*7348b5c5SDavid van Moolenbroek #include "externs.h"
90*7348b5c5SDavid van Moolenbroek #include "defines.h"
91*7348b5c5SDavid van Moolenbroek #include "types.h"
92*7348b5c5SDavid van Moolenbroek #include <libtelnet/misc.h>
93*7348b5c5SDavid van Moolenbroek #ifdef AUTHENTICATION
94*7348b5c5SDavid van Moolenbroek #include <libtelnet/auth.h>
95*7348b5c5SDavid van Moolenbroek #endif
96*7348b5c5SDavid van Moolenbroek #ifdef ENCRYPTION
97*7348b5c5SDavid van Moolenbroek #include <libtelnet/encrypt.h>
98*7348b5c5SDavid van Moolenbroek #endif
99*7348b5c5SDavid van Moolenbroek 
100*7348b5c5SDavid van Moolenbroek #include <netinet/in_systm.h>
101*7348b5c5SDavid van Moolenbroek #include <netinet/ip.h>
102*7348b5c5SDavid van Moolenbroek 
103*7348b5c5SDavid van Moolenbroek 
104*7348b5c5SDavid van Moolenbroek #if	defined(IPPROTO_IP) && defined(IP_TOS)
105*7348b5c5SDavid van Moolenbroek int tos = -1;
106*7348b5c5SDavid van Moolenbroek #endif	/* defined(IPPROTO_IP) && defined(IP_TOS) */
107*7348b5c5SDavid van Moolenbroek 
108*7348b5c5SDavid van Moolenbroek char	*hostname;
109*7348b5c5SDavid van Moolenbroek static char _hostname[MAXHOSTNAMELEN];
110*7348b5c5SDavid van Moolenbroek 
111*7348b5c5SDavid van Moolenbroek typedef struct {
112*7348b5c5SDavid van Moolenbroek 	const char	*name;	/* command name */
113*7348b5c5SDavid van Moolenbroek 	const char	*help;	/* help string (NULL for no help) */
114*7348b5c5SDavid van Moolenbroek 	int	(*handler)	/* routine which executes command */
115*7348b5c5SDavid van Moolenbroek 			(int, char *[]);
116*7348b5c5SDavid van Moolenbroek 	int	needconnect;	/* Do we need to be connected to execute? */
117*7348b5c5SDavid van Moolenbroek } Command;
118*7348b5c5SDavid van Moolenbroek 
119*7348b5c5SDavid van Moolenbroek static char line[256];
120*7348b5c5SDavid van Moolenbroek static char saveline[256];
121*7348b5c5SDavid van Moolenbroek static int margc;
122*7348b5c5SDavid van Moolenbroek static char *margv[20];
123*7348b5c5SDavid van Moolenbroek 
124*7348b5c5SDavid van Moolenbroek static void makeargv(void);
125*7348b5c5SDavid van Moolenbroek static int special(char *);
126*7348b5c5SDavid van Moolenbroek static const char *control(cc_t);
127*7348b5c5SDavid van Moolenbroek static int sendcmd(int, char **);
128*7348b5c5SDavid van Moolenbroek static int send_esc(char *);
129*7348b5c5SDavid van Moolenbroek static int send_docmd(char *);
130*7348b5c5SDavid van Moolenbroek static int send_dontcmd(char *);
131*7348b5c5SDavid van Moolenbroek static int send_willcmd(char *);
132*7348b5c5SDavid van Moolenbroek static int send_wontcmd(char *);
133*7348b5c5SDavid van Moolenbroek static int send_help(char *);
134*7348b5c5SDavid van Moolenbroek static int lclchars(int);
135*7348b5c5SDavid van Moolenbroek static int togdebug(int);
136*7348b5c5SDavid van Moolenbroek static int togcrlf(int);
137*7348b5c5SDavid van Moolenbroek static int togbinary(int);
138*7348b5c5SDavid van Moolenbroek static int togrbinary(int);
139*7348b5c5SDavid van Moolenbroek static int togxbinary(int);
140*7348b5c5SDavid van Moolenbroek static int togglehelp(int);
141*7348b5c5SDavid van Moolenbroek static void settogglehelp(int);
142*7348b5c5SDavid van Moolenbroek static int toggle(int, char *[]);
143*7348b5c5SDavid van Moolenbroek static struct setlist *getset(char *);
144*7348b5c5SDavid van Moolenbroek static int setcmd(int, char *[]);
145*7348b5c5SDavid van Moolenbroek static int unsetcmd(int, char *[]);
146*7348b5c5SDavid van Moolenbroek static int dokludgemode(int);
147*7348b5c5SDavid van Moolenbroek static int dolinemode(int);
148*7348b5c5SDavid van Moolenbroek static int docharmode(int);
149*7348b5c5SDavid van Moolenbroek static int dolmmode(int, int );
150*7348b5c5SDavid van Moolenbroek static int modecmd(int, char *[]);
151*7348b5c5SDavid van Moolenbroek static int display(int, char *[]);
152*7348b5c5SDavid van Moolenbroek static int setescape(int, char *[]);
153*7348b5c5SDavid van Moolenbroek static int togcrmod(int, char *[]);
154*7348b5c5SDavid van Moolenbroek static int bye(int, char *[]);
155*7348b5c5SDavid van Moolenbroek static void slc_help(int);
156*7348b5c5SDavid van Moolenbroek static struct slclist *getslc(char *);
157*7348b5c5SDavid van Moolenbroek static int slccmd(int, char *[]);
158*7348b5c5SDavid van Moolenbroek static struct env_lst *env_help(const unsigned char *, unsigned char *);
159*7348b5c5SDavid van Moolenbroek static struct envlist *getenvcmd(char *);
160*7348b5c5SDavid van Moolenbroek #ifdef AUTHENTICATION
161*7348b5c5SDavid van Moolenbroek static int auth_help(char *);
162*7348b5c5SDavid van Moolenbroek #endif
163*7348b5c5SDavid van Moolenbroek #ifdef TN3270
164*7348b5c5SDavid van Moolenbroek static void filestuff(int);
165*7348b5c5SDavid van Moolenbroek #endif
166*7348b5c5SDavid van Moolenbroek static int status(int, char *[]);
167*7348b5c5SDavid van Moolenbroek static const char *sockaddr_ntop (struct sockaddr *);
168*7348b5c5SDavid van Moolenbroek typedef int (*intrtn_t)(int, char **);
169*7348b5c5SDavid van Moolenbroek static int call(intrtn_t, ...);
170*7348b5c5SDavid van Moolenbroek static Command *getcmd(char *);
171*7348b5c5SDavid van Moolenbroek static int help(int, char *[]);
172*7348b5c5SDavid van Moolenbroek 
173*7348b5c5SDavid van Moolenbroek static void
makeargv(void)174*7348b5c5SDavid van Moolenbroek makeargv(void)
175*7348b5c5SDavid van Moolenbroek {
176*7348b5c5SDavid van Moolenbroek     char *cp, *cp2, c;
177*7348b5c5SDavid van Moolenbroek     char **argp = margv;
178*7348b5c5SDavid van Moolenbroek     static char bang[] = "!";
179*7348b5c5SDavid van Moolenbroek 
180*7348b5c5SDavid van Moolenbroek     margc = 0;
181*7348b5c5SDavid van Moolenbroek     cp = line;
182*7348b5c5SDavid van Moolenbroek     if (*cp == '!') {		/* Special case shell escape */
183*7348b5c5SDavid van Moolenbroek 	strlcpy(saveline, line, sizeof(saveline)); /* save for shell command */
184*7348b5c5SDavid van Moolenbroek 	*argp++ = bang;		/* No room in string to get this */
185*7348b5c5SDavid van Moolenbroek 	margc++;
186*7348b5c5SDavid van Moolenbroek 	cp++;
187*7348b5c5SDavid van Moolenbroek     }
188*7348b5c5SDavid van Moolenbroek     while ((c = *cp) != '\0') {
189*7348b5c5SDavid van Moolenbroek 	int inquote = 0;
190*7348b5c5SDavid van Moolenbroek 	while (isspace((unsigned char)c))
191*7348b5c5SDavid van Moolenbroek 	    c = *++cp;
192*7348b5c5SDavid van Moolenbroek 	if (c == '\0')
193*7348b5c5SDavid van Moolenbroek 	    break;
194*7348b5c5SDavid van Moolenbroek 	*argp++ = cp;
195*7348b5c5SDavid van Moolenbroek 	margc += 1;
196*7348b5c5SDavid van Moolenbroek 	for (cp2 = cp; c != '\0'; c = *++cp) {
197*7348b5c5SDavid van Moolenbroek 	    if (inquote) {
198*7348b5c5SDavid van Moolenbroek 		if (c == inquote) {
199*7348b5c5SDavid van Moolenbroek 		    inquote = 0;
200*7348b5c5SDavid van Moolenbroek 		    continue;
201*7348b5c5SDavid van Moolenbroek 		}
202*7348b5c5SDavid van Moolenbroek 	    } else {
203*7348b5c5SDavid van Moolenbroek 		if (c == '\\') {
204*7348b5c5SDavid van Moolenbroek 		    if ((c = *++cp) == '\0')
205*7348b5c5SDavid van Moolenbroek 			break;
206*7348b5c5SDavid van Moolenbroek 		} else if (c == '"') {
207*7348b5c5SDavid van Moolenbroek 		    inquote = '"';
208*7348b5c5SDavid van Moolenbroek 		    continue;
209*7348b5c5SDavid van Moolenbroek 		} else if (c == '\'') {
210*7348b5c5SDavid van Moolenbroek 		    inquote = '\'';
211*7348b5c5SDavid van Moolenbroek 		    continue;
212*7348b5c5SDavid van Moolenbroek 		} else if (isspace((unsigned char)c))
213*7348b5c5SDavid van Moolenbroek 		    break;
214*7348b5c5SDavid van Moolenbroek 	    }
215*7348b5c5SDavid van Moolenbroek 	    *cp2++ = c;
216*7348b5c5SDavid van Moolenbroek 	}
217*7348b5c5SDavid van Moolenbroek 	*cp2 = '\0';
218*7348b5c5SDavid van Moolenbroek 	if (c == '\0')
219*7348b5c5SDavid van Moolenbroek 	    break;
220*7348b5c5SDavid van Moolenbroek 	cp++;
221*7348b5c5SDavid van Moolenbroek     }
222*7348b5c5SDavid van Moolenbroek     *argp++ = 0;
223*7348b5c5SDavid van Moolenbroek }
224*7348b5c5SDavid van Moolenbroek 
225*7348b5c5SDavid van Moolenbroek /*
226*7348b5c5SDavid van Moolenbroek  * Make a character string into a number.
227*7348b5c5SDavid van Moolenbroek  *
228*7348b5c5SDavid van Moolenbroek  * Todo:  1.  Could take random integers (12, 0x12, 012, 0b1).
229*7348b5c5SDavid van Moolenbroek  */
230*7348b5c5SDavid van Moolenbroek 
231*7348b5c5SDavid van Moolenbroek static int
special(char * s)232*7348b5c5SDavid van Moolenbroek special(char *s)
233*7348b5c5SDavid van Moolenbroek {
234*7348b5c5SDavid van Moolenbroek 	char c;
235*7348b5c5SDavid van Moolenbroek 	char b;
236*7348b5c5SDavid van Moolenbroek 
237*7348b5c5SDavid van Moolenbroek 	switch (*s) {
238*7348b5c5SDavid van Moolenbroek 	case '^':
239*7348b5c5SDavid van Moolenbroek 		b = *++s;
240*7348b5c5SDavid van Moolenbroek 		if (b == '?') {
241*7348b5c5SDavid van Moolenbroek 		    c = b | 0x40;		/* DEL */
242*7348b5c5SDavid van Moolenbroek 		} else {
243*7348b5c5SDavid van Moolenbroek 		    c = b & 0x1f;
244*7348b5c5SDavid van Moolenbroek 		}
245*7348b5c5SDavid van Moolenbroek 		break;
246*7348b5c5SDavid van Moolenbroek 	default:
247*7348b5c5SDavid van Moolenbroek 		c = *s;
248*7348b5c5SDavid van Moolenbroek 		break;
249*7348b5c5SDavid van Moolenbroek 	}
250*7348b5c5SDavid van Moolenbroek 	return c;
251*7348b5c5SDavid van Moolenbroek }
252*7348b5c5SDavid van Moolenbroek 
253*7348b5c5SDavid van Moolenbroek /*
254*7348b5c5SDavid van Moolenbroek  * Construct a control character sequence
255*7348b5c5SDavid van Moolenbroek  * for a special character.
256*7348b5c5SDavid van Moolenbroek  */
257*7348b5c5SDavid van Moolenbroek static const char *
control(cc_t c)258*7348b5c5SDavid van Moolenbroek control(cc_t c)
259*7348b5c5SDavid van Moolenbroek {
260*7348b5c5SDavid van Moolenbroek 	static char buf[5];
261*7348b5c5SDavid van Moolenbroek 	/*
262*7348b5c5SDavid van Moolenbroek 	 * The only way I could get the Sun 3.5 compiler
263*7348b5c5SDavid van Moolenbroek 	 * to shut up about
264*7348b5c5SDavid van Moolenbroek 	 *	if ((unsigned int)c >= 0x80)
265*7348b5c5SDavid van Moolenbroek 	 * was to assign "c" to an unsigned int variable...
266*7348b5c5SDavid van Moolenbroek 	 * Arggg....
267*7348b5c5SDavid van Moolenbroek 	 */
268*7348b5c5SDavid van Moolenbroek 	unsigned int uic = (unsigned int)c;
269*7348b5c5SDavid van Moolenbroek 
270*7348b5c5SDavid van Moolenbroek 	if (uic == 0x7f)
271*7348b5c5SDavid van Moolenbroek 		return ("^?");
272*7348b5c5SDavid van Moolenbroek 	if (c == (cc_t)_POSIX_VDISABLE) {
273*7348b5c5SDavid van Moolenbroek 		return "off";
274*7348b5c5SDavid van Moolenbroek 	}
275*7348b5c5SDavid van Moolenbroek 	if (uic >= 0x80) {
276*7348b5c5SDavid van Moolenbroek 		buf[0] = '\\';
277*7348b5c5SDavid van Moolenbroek 		buf[1] = ((c>>6)&07) + '0';
278*7348b5c5SDavid van Moolenbroek 		buf[2] = ((c>>3)&07) + '0';
279*7348b5c5SDavid van Moolenbroek 		buf[3] = (c&07) + '0';
280*7348b5c5SDavid van Moolenbroek 		buf[4] = 0;
281*7348b5c5SDavid van Moolenbroek 	} else if (uic >= 0x20) {
282*7348b5c5SDavid van Moolenbroek 		buf[0] = c;
283*7348b5c5SDavid van Moolenbroek 		buf[1] = 0;
284*7348b5c5SDavid van Moolenbroek 	} else {
285*7348b5c5SDavid van Moolenbroek 		buf[0] = '^';
286*7348b5c5SDavid van Moolenbroek 		buf[1] = '@'+c;
287*7348b5c5SDavid van Moolenbroek 		buf[2] = 0;
288*7348b5c5SDavid van Moolenbroek 	}
289*7348b5c5SDavid van Moolenbroek 	return (buf);
290*7348b5c5SDavid van Moolenbroek }
291*7348b5c5SDavid van Moolenbroek 
292*7348b5c5SDavid van Moolenbroek 
293*7348b5c5SDavid van Moolenbroek 
294*7348b5c5SDavid van Moolenbroek /*
295*7348b5c5SDavid van Moolenbroek  *	The following are data structures and routines for
296*7348b5c5SDavid van Moolenbroek  *	the "send" command.
297*7348b5c5SDavid van Moolenbroek  *
298*7348b5c5SDavid van Moolenbroek  */
299*7348b5c5SDavid van Moolenbroek 
300*7348b5c5SDavid van Moolenbroek struct sendlist {
301*7348b5c5SDavid van Moolenbroek     const char	*name;		/* How user refers to it (case independent) */
302*7348b5c5SDavid van Moolenbroek     const char	*help;		/* Help information (0 ==> no help) */
303*7348b5c5SDavid van Moolenbroek     int		needconnect;	/* Need to be connected */
304*7348b5c5SDavid van Moolenbroek     int		narg;		/* Number of arguments */
305*7348b5c5SDavid van Moolenbroek     int		(*handler)	/* Routine to perform (for special ops) */
306*7348b5c5SDavid van Moolenbroek 			(char *);
307*7348b5c5SDavid van Moolenbroek     int		nbyte;		/* Number of bytes to send this command */
308*7348b5c5SDavid van Moolenbroek     int		what;		/* Character to be sent (<0 ==> special) */
309*7348b5c5SDavid van Moolenbroek };
310*7348b5c5SDavid van Moolenbroek 
311*7348b5c5SDavid van Moolenbroek 
312*7348b5c5SDavid van Moolenbroek static struct sendlist Sendlist[] = {
313*7348b5c5SDavid van Moolenbroek     { "ao",	"Send Telnet Abort output",		1, 0, 0, 2, AO },
314*7348b5c5SDavid van Moolenbroek     { "ayt",	"Send Telnet 'Are You There'",		1, 0, 0, 2, AYT },
315*7348b5c5SDavid van Moolenbroek     { "brk",	"Send Telnet Break",			1, 0, 0, 2, BREAK },
316*7348b5c5SDavid van Moolenbroek     { "break",	0,					1, 0, 0, 2, BREAK },
317*7348b5c5SDavid van Moolenbroek     { "ec",	"Send Telnet Erase Character",		1, 0, 0, 2, EC },
318*7348b5c5SDavid van Moolenbroek     { "el",	"Send Telnet Erase Line",		1, 0, 0, 2, EL },
319*7348b5c5SDavid van Moolenbroek     { "escape",	"Send current escape character",	1, 0, send_esc, 1, 0 },
320*7348b5c5SDavid van Moolenbroek     { "ga",	"Send Telnet 'Go Ahead' sequence",	1, 0, 0, 2, GA },
321*7348b5c5SDavid van Moolenbroek     { "ip",	"Send Telnet Interrupt Process",	1, 0, 0, 2, IP },
322*7348b5c5SDavid van Moolenbroek     { "intp",	0,					1, 0, 0, 2, IP },
323*7348b5c5SDavid van Moolenbroek     { "interrupt", 0,					1, 0, 0, 2, IP },
324*7348b5c5SDavid van Moolenbroek     { "intr",	0,					1, 0, 0, 2, IP },
325*7348b5c5SDavid van Moolenbroek     { "nop",	"Send Telnet 'No operation'",		1, 0, 0, 2, NOP },
326*7348b5c5SDavid van Moolenbroek     { "eor",	"Send Telnet 'End of Record'",		1, 0, 0, 2, EOR },
327*7348b5c5SDavid van Moolenbroek     { "abort",	"Send Telnet 'Abort Process'",		1, 0, 0, 2, ABORT },
328*7348b5c5SDavid van Moolenbroek     { "susp",	"Send Telnet 'Suspend Process'",	1, 0, 0, 2, SUSP },
329*7348b5c5SDavid van Moolenbroek     { "eof",	"Send Telnet End of File Character",	1, 0, 0, 2, xEOF },
330*7348b5c5SDavid van Moolenbroek     { "synch",	"Perform Telnet 'Synch operation'",	1, 0, dosynch, 2, 0 },
331*7348b5c5SDavid van Moolenbroek     { "getstatus", "Send request for STATUS",		1, 0, get_status, 6, 0 },
332*7348b5c5SDavid van Moolenbroek     { "?",	"Display send options",			0, 0, send_help, 0, 0 },
333*7348b5c5SDavid van Moolenbroek     { "help",	0,					0, 0, send_help, 0, 0 },
334*7348b5c5SDavid van Moolenbroek     { "do",	0,					0, 1, send_docmd, 3, 0 },
335*7348b5c5SDavid van Moolenbroek     { "dont",	0,					0, 1, send_dontcmd, 3, 0 },
336*7348b5c5SDavid van Moolenbroek     { "will",	0,					0, 1, send_willcmd, 3, 0 },
337*7348b5c5SDavid van Moolenbroek     { "wont",	0,					0, 1, send_wontcmd, 3, 0 },
338*7348b5c5SDavid van Moolenbroek     { .name = 0 }
339*7348b5c5SDavid van Moolenbroek };
340*7348b5c5SDavid van Moolenbroek 
341*7348b5c5SDavid van Moolenbroek #define	GETSEND(name) ((struct sendlist *) genget(name, (char **) Sendlist, \
342*7348b5c5SDavid van Moolenbroek 				sizeof(struct sendlist)))
343*7348b5c5SDavid van Moolenbroek 
344*7348b5c5SDavid van Moolenbroek static int
sendcmd(int argc,char ** argv)345*7348b5c5SDavid van Moolenbroek sendcmd(int  argc, char **argv)
346*7348b5c5SDavid van Moolenbroek {
347*7348b5c5SDavid van Moolenbroek     int count;		/* how many bytes we are going to need to send */
348*7348b5c5SDavid van Moolenbroek     int i;
349*7348b5c5SDavid van Moolenbroek     struct sendlist *s;	/* pointer to current command */
350*7348b5c5SDavid van Moolenbroek     int success = 0;
351*7348b5c5SDavid van Moolenbroek     int needconnect = 0;
352*7348b5c5SDavid van Moolenbroek 
353*7348b5c5SDavid van Moolenbroek     if (argc < 2) {
354*7348b5c5SDavid van Moolenbroek 	printf("need at least one argument for 'send' command\n");
355*7348b5c5SDavid van Moolenbroek 	printf("'send ?' for help\n");
356*7348b5c5SDavid van Moolenbroek 	return 0;
357*7348b5c5SDavid van Moolenbroek     }
358*7348b5c5SDavid van Moolenbroek     /*
359*7348b5c5SDavid van Moolenbroek      * First, validate all the send arguments.
360*7348b5c5SDavid van Moolenbroek      * In addition, we see how much space we are going to need, and
361*7348b5c5SDavid van Moolenbroek      * whether or not we will be doing a "SYNCH" operation (which
362*7348b5c5SDavid van Moolenbroek      * flushes the network queue).
363*7348b5c5SDavid van Moolenbroek      */
364*7348b5c5SDavid van Moolenbroek     count = 0;
365*7348b5c5SDavid van Moolenbroek     for (i = 1; i < argc; i++) {
366*7348b5c5SDavid van Moolenbroek 	s = GETSEND(argv[i]);
367*7348b5c5SDavid van Moolenbroek 	if (s == 0) {
368*7348b5c5SDavid van Moolenbroek 	    printf("Unknown send argument '%s'\n'send ?' for help.\n",
369*7348b5c5SDavid van Moolenbroek 			argv[i]);
370*7348b5c5SDavid van Moolenbroek 	    return 0;
371*7348b5c5SDavid van Moolenbroek 	} else if (Ambiguous(s)) {
372*7348b5c5SDavid van Moolenbroek 	    printf("Ambiguous send argument '%s'\n'send ?' for help.\n",
373*7348b5c5SDavid van Moolenbroek 			argv[i]);
374*7348b5c5SDavid van Moolenbroek 	    return 0;
375*7348b5c5SDavid van Moolenbroek 	}
376*7348b5c5SDavid van Moolenbroek 	if (i + s->narg >= argc) {
377*7348b5c5SDavid van Moolenbroek 	    fprintf(stderr,
378*7348b5c5SDavid van Moolenbroek 	    "Need %d argument%s to 'send %s' command.  'send %s ?' for help.\n",
379*7348b5c5SDavid van Moolenbroek 		s->narg, s->narg == 1 ? "" : "s", s->name, s->name);
380*7348b5c5SDavid van Moolenbroek 	    return 0;
381*7348b5c5SDavid van Moolenbroek 	}
382*7348b5c5SDavid van Moolenbroek 	count += s->nbyte;
383*7348b5c5SDavid van Moolenbroek 	if (s->handler == send_help) {
384*7348b5c5SDavid van Moolenbroek 	    send_help(NULL);
385*7348b5c5SDavid van Moolenbroek 	    return 0;
386*7348b5c5SDavid van Moolenbroek 	}
387*7348b5c5SDavid van Moolenbroek 
388*7348b5c5SDavid van Moolenbroek 	i += s->narg;
389*7348b5c5SDavid van Moolenbroek 	needconnect += s->needconnect;
390*7348b5c5SDavid van Moolenbroek     }
391*7348b5c5SDavid van Moolenbroek     if (!connected && needconnect) {
392*7348b5c5SDavid van Moolenbroek 	printf("?Need to be connected first.\n");
393*7348b5c5SDavid van Moolenbroek 	printf("'send ?' for help\n");
394*7348b5c5SDavid van Moolenbroek 	return 0;
395*7348b5c5SDavid van Moolenbroek     }
396*7348b5c5SDavid van Moolenbroek     /* Now, do we have enough room? */
397*7348b5c5SDavid van Moolenbroek     if (NETROOM() < count) {
398*7348b5c5SDavid van Moolenbroek 	printf("There is not enough room in the buffer TO the network\n");
399*7348b5c5SDavid van Moolenbroek 	printf("to process your request.  Nothing will be done.\n");
400*7348b5c5SDavid van Moolenbroek 	printf("('send synch' will throw away most data in the network\n");
401*7348b5c5SDavid van Moolenbroek 	printf("buffer, if this might help.)\n");
402*7348b5c5SDavid van Moolenbroek 	return 0;
403*7348b5c5SDavid van Moolenbroek     }
404*7348b5c5SDavid van Moolenbroek     /* OK, they are all OK, now go through again and actually send */
405*7348b5c5SDavid van Moolenbroek     count = 0;
406*7348b5c5SDavid van Moolenbroek     for (i = 1; i < argc; i++) {
407*7348b5c5SDavid van Moolenbroek 	if ((s = GETSEND(argv[i])) == 0) {
408*7348b5c5SDavid van Moolenbroek 	    fprintf(stderr, "Telnet 'send' error - argument disappeared!\n");
409*7348b5c5SDavid van Moolenbroek 	    (void) quit(0, NULL);
410*7348b5c5SDavid van Moolenbroek 	    /*NOTREACHED*/
411*7348b5c5SDavid van Moolenbroek 	}
412*7348b5c5SDavid van Moolenbroek 	if (s->handler) {
413*7348b5c5SDavid van Moolenbroek 	    count++;
414*7348b5c5SDavid van Moolenbroek 	    success += (*s->handler)(argv[i+1]);
415*7348b5c5SDavid van Moolenbroek 	    i += s->narg;
416*7348b5c5SDavid van Moolenbroek 	} else {
417*7348b5c5SDavid van Moolenbroek 	    NET2ADD(IAC, s->what);
418*7348b5c5SDavid van Moolenbroek 	    printoption("SENT", IAC, s->what);
419*7348b5c5SDavid van Moolenbroek 	}
420*7348b5c5SDavid van Moolenbroek     }
421*7348b5c5SDavid van Moolenbroek     return (count == success);
422*7348b5c5SDavid van Moolenbroek }
423*7348b5c5SDavid van Moolenbroek 
424*7348b5c5SDavid van Moolenbroek static int
send_esc(char * s)425*7348b5c5SDavid van Moolenbroek send_esc(char *s)
426*7348b5c5SDavid van Moolenbroek {
427*7348b5c5SDavid van Moolenbroek     NETADD(escape);
428*7348b5c5SDavid van Moolenbroek     return 1;
429*7348b5c5SDavid van Moolenbroek }
430*7348b5c5SDavid van Moolenbroek 
431*7348b5c5SDavid van Moolenbroek static int
send_docmd(char * name)432*7348b5c5SDavid van Moolenbroek send_docmd(char *name)
433*7348b5c5SDavid van Moolenbroek {
434*7348b5c5SDavid van Moolenbroek     return(send_tncmd(send_do, "do", name));
435*7348b5c5SDavid van Moolenbroek }
436*7348b5c5SDavid van Moolenbroek 
437*7348b5c5SDavid van Moolenbroek static int
send_dontcmd(char * name)438*7348b5c5SDavid van Moolenbroek send_dontcmd(char *name)
439*7348b5c5SDavid van Moolenbroek {
440*7348b5c5SDavid van Moolenbroek     return(send_tncmd(send_dont, "dont", name));
441*7348b5c5SDavid van Moolenbroek }
442*7348b5c5SDavid van Moolenbroek static int
send_willcmd(char * name)443*7348b5c5SDavid van Moolenbroek send_willcmd(char *name)
444*7348b5c5SDavid van Moolenbroek {
445*7348b5c5SDavid van Moolenbroek     return(send_tncmd(send_will, "will", name));
446*7348b5c5SDavid van Moolenbroek }
447*7348b5c5SDavid van Moolenbroek static int
send_wontcmd(char * name)448*7348b5c5SDavid van Moolenbroek send_wontcmd(char *name)
449*7348b5c5SDavid van Moolenbroek {
450*7348b5c5SDavid van Moolenbroek     return(send_tncmd(send_wont, "wont", name));
451*7348b5c5SDavid van Moolenbroek }
452*7348b5c5SDavid van Moolenbroek 
453*7348b5c5SDavid van Moolenbroek int
send_tncmd(void (* func)(int,int),const char * cmd,char * name)454*7348b5c5SDavid van Moolenbroek send_tncmd(void	(*func)(int, int), const char	*cmd, char *name)
455*7348b5c5SDavid van Moolenbroek {
456*7348b5c5SDavid van Moolenbroek     const char **cpp;
457*7348b5c5SDavid van Moolenbroek     int val = 0;
458*7348b5c5SDavid van Moolenbroek 
459*7348b5c5SDavid van Moolenbroek     if (isprefix(name, "?")) {
460*7348b5c5SDavid van Moolenbroek 	int col, len;
461*7348b5c5SDavid van Moolenbroek 
462*7348b5c5SDavid van Moolenbroek 	printf("usage: send %s <value|option>\n", cmd);
463*7348b5c5SDavid van Moolenbroek 	printf("\"value\" must be from 0 to 255\n");
464*7348b5c5SDavid van Moolenbroek 	printf("Valid options are:\n\t");
465*7348b5c5SDavid van Moolenbroek 
466*7348b5c5SDavid van Moolenbroek 	col = 8;
467*7348b5c5SDavid van Moolenbroek 	for (cpp = telopts; *cpp; cpp++) {
468*7348b5c5SDavid van Moolenbroek 	    len = strlen(*cpp) + 3;
469*7348b5c5SDavid van Moolenbroek 	    if (col + len > 65) {
470*7348b5c5SDavid van Moolenbroek 		printf("\n\t");
471*7348b5c5SDavid van Moolenbroek 		col = 8;
472*7348b5c5SDavid van Moolenbroek 	    }
473*7348b5c5SDavid van Moolenbroek 	    printf(" \"%s\"", *cpp);
474*7348b5c5SDavid van Moolenbroek 	    col += len;
475*7348b5c5SDavid van Moolenbroek 	}
476*7348b5c5SDavid van Moolenbroek 	printf("\n");
477*7348b5c5SDavid van Moolenbroek 	return 0;
478*7348b5c5SDavid van Moolenbroek     }
479*7348b5c5SDavid van Moolenbroek     cpp = (void *)genget(name, __UNCONST(telopts), sizeof(char *));
480*7348b5c5SDavid van Moolenbroek     if (Ambiguous(cpp)) {
481*7348b5c5SDavid van Moolenbroek 	fprintf(stderr,"'%s': ambiguous argument ('send %s ?' for help).\n",
482*7348b5c5SDavid van Moolenbroek 					name, cmd);
483*7348b5c5SDavid van Moolenbroek 	return 0;
484*7348b5c5SDavid van Moolenbroek     }
485*7348b5c5SDavid van Moolenbroek     if (cpp) {
486*7348b5c5SDavid van Moolenbroek 	val = cpp - telopts;
487*7348b5c5SDavid van Moolenbroek     } else {
488*7348b5c5SDavid van Moolenbroek 	char *cp = name;
489*7348b5c5SDavid van Moolenbroek 
490*7348b5c5SDavid van Moolenbroek 	while (*cp >= '0' && *cp <= '9') {
491*7348b5c5SDavid van Moolenbroek 	    val *= 10;
492*7348b5c5SDavid van Moolenbroek 	    val += *cp - '0';
493*7348b5c5SDavid van Moolenbroek 	    cp++;
494*7348b5c5SDavid van Moolenbroek 	}
495*7348b5c5SDavid van Moolenbroek 	if (*cp != 0) {
496*7348b5c5SDavid van Moolenbroek 	    fprintf(stderr, "'%s': unknown argument ('send %s ?' for help).\n",
497*7348b5c5SDavid van Moolenbroek 					name, cmd);
498*7348b5c5SDavid van Moolenbroek 	    return 0;
499*7348b5c5SDavid van Moolenbroek 	} else if (val < 0 || val > 255) {
500*7348b5c5SDavid van Moolenbroek 	    fprintf(stderr, "'%s': bad value ('send %s ?' for help).\n",
501*7348b5c5SDavid van Moolenbroek 					name, cmd);
502*7348b5c5SDavid van Moolenbroek 	    return 0;
503*7348b5c5SDavid van Moolenbroek 	}
504*7348b5c5SDavid van Moolenbroek     }
505*7348b5c5SDavid van Moolenbroek     if (!connected) {
506*7348b5c5SDavid van Moolenbroek 	printf("?Need to be connected first.\n");
507*7348b5c5SDavid van Moolenbroek 	return 0;
508*7348b5c5SDavid van Moolenbroek     }
509*7348b5c5SDavid van Moolenbroek     (*func)(val, 1);
510*7348b5c5SDavid van Moolenbroek     return 1;
511*7348b5c5SDavid van Moolenbroek }
512*7348b5c5SDavid van Moolenbroek 
513*7348b5c5SDavid van Moolenbroek static int
send_help(char * n)514*7348b5c5SDavid van Moolenbroek send_help(char *n)
515*7348b5c5SDavid van Moolenbroek {
516*7348b5c5SDavid van Moolenbroek     struct sendlist *s;	/* pointer to current command */
517*7348b5c5SDavid van Moolenbroek     for (s = Sendlist; s->name; s++) {
518*7348b5c5SDavid van Moolenbroek 	if (s->help)
519*7348b5c5SDavid van Moolenbroek 	    printf("%-15s %s\n", s->name, s->help);
520*7348b5c5SDavid van Moolenbroek     }
521*7348b5c5SDavid van Moolenbroek     return(0);
522*7348b5c5SDavid van Moolenbroek }
523*7348b5c5SDavid van Moolenbroek 
524*7348b5c5SDavid van Moolenbroek /*
525*7348b5c5SDavid van Moolenbroek  * The following are the routines and data structures referred
526*7348b5c5SDavid van Moolenbroek  * to by the arguments to the "toggle" command.
527*7348b5c5SDavid van Moolenbroek  */
528*7348b5c5SDavid van Moolenbroek 
529*7348b5c5SDavid van Moolenbroek static int
lclchars(int n)530*7348b5c5SDavid van Moolenbroek lclchars(int n)
531*7348b5c5SDavid van Moolenbroek {
532*7348b5c5SDavid van Moolenbroek     donelclchars = 1;
533*7348b5c5SDavid van Moolenbroek     return 1;
534*7348b5c5SDavid van Moolenbroek }
535*7348b5c5SDavid van Moolenbroek 
536*7348b5c5SDavid van Moolenbroek static int
togdebug(int n)537*7348b5c5SDavid van Moolenbroek togdebug(int n)
538*7348b5c5SDavid van Moolenbroek {
539*7348b5c5SDavid van Moolenbroek     if (net > 0 &&
540*7348b5c5SDavid van Moolenbroek 	(SetSockOpt(net, SOL_SOCKET, SO_DEBUG, telnet_debug)) < 0) {
541*7348b5c5SDavid van Moolenbroek 	    perror("setsockopt (SO_DEBUG)");
542*7348b5c5SDavid van Moolenbroek     }
543*7348b5c5SDavid van Moolenbroek     return 1;
544*7348b5c5SDavid van Moolenbroek }
545*7348b5c5SDavid van Moolenbroek 
546*7348b5c5SDavid van Moolenbroek static int
togcrlf(int n)547*7348b5c5SDavid van Moolenbroek togcrlf(int n)
548*7348b5c5SDavid van Moolenbroek {
549*7348b5c5SDavid van Moolenbroek     if (crlf) {
550*7348b5c5SDavid van Moolenbroek 	printf("Will send carriage returns as telnet <CR><LF>.\n");
551*7348b5c5SDavid van Moolenbroek     } else {
552*7348b5c5SDavid van Moolenbroek 	printf("Will send carriage returns as telnet <CR><NUL>.\n");
553*7348b5c5SDavid van Moolenbroek     }
554*7348b5c5SDavid van Moolenbroek     return 1;
555*7348b5c5SDavid van Moolenbroek }
556*7348b5c5SDavid van Moolenbroek 
557*7348b5c5SDavid van Moolenbroek int binmode;
558*7348b5c5SDavid van Moolenbroek 
559*7348b5c5SDavid van Moolenbroek static int
togbinary(int val)560*7348b5c5SDavid van Moolenbroek togbinary(int val)
561*7348b5c5SDavid van Moolenbroek {
562*7348b5c5SDavid van Moolenbroek     donebinarytoggle = 1;
563*7348b5c5SDavid van Moolenbroek 
564*7348b5c5SDavid van Moolenbroek     if (val >= 0) {
565*7348b5c5SDavid van Moolenbroek 	binmode = val;
566*7348b5c5SDavid van Moolenbroek     } else {
567*7348b5c5SDavid van Moolenbroek 	if (my_want_state_is_will(TELOPT_BINARY) &&
568*7348b5c5SDavid van Moolenbroek 				my_want_state_is_do(TELOPT_BINARY)) {
569*7348b5c5SDavid van Moolenbroek 	    binmode = 1;
570*7348b5c5SDavid van Moolenbroek 	} else if (my_want_state_is_wont(TELOPT_BINARY) &&
571*7348b5c5SDavid van Moolenbroek 				my_want_state_is_dont(TELOPT_BINARY)) {
572*7348b5c5SDavid van Moolenbroek 	    binmode = 0;
573*7348b5c5SDavid van Moolenbroek 	}
574*7348b5c5SDavid van Moolenbroek 	val = binmode ? 0 : 1;
575*7348b5c5SDavid van Moolenbroek     }
576*7348b5c5SDavid van Moolenbroek 
577*7348b5c5SDavid van Moolenbroek     if (val == 1) {
578*7348b5c5SDavid van Moolenbroek 	if (my_want_state_is_will(TELOPT_BINARY) &&
579*7348b5c5SDavid van Moolenbroek 					my_want_state_is_do(TELOPT_BINARY)) {
580*7348b5c5SDavid van Moolenbroek 	    printf("Already operating in binary mode with remote host.\n");
581*7348b5c5SDavid van Moolenbroek 	} else {
582*7348b5c5SDavid van Moolenbroek 	    printf("Negotiating binary mode with remote host.\n");
583*7348b5c5SDavid van Moolenbroek 	    tel_enter_binary(3);
584*7348b5c5SDavid van Moolenbroek 	}
585*7348b5c5SDavid van Moolenbroek     } else {
586*7348b5c5SDavid van Moolenbroek 	if (my_want_state_is_wont(TELOPT_BINARY) &&
587*7348b5c5SDavid van Moolenbroek 					my_want_state_is_dont(TELOPT_BINARY)) {
588*7348b5c5SDavid van Moolenbroek 	    printf("Already in network ascii mode with remote host.\n");
589*7348b5c5SDavid van Moolenbroek 	} else {
590*7348b5c5SDavid van Moolenbroek 	    printf("Negotiating network ascii mode with remote host.\n");
591*7348b5c5SDavid van Moolenbroek 	    tel_leave_binary(3);
592*7348b5c5SDavid van Moolenbroek 	}
593*7348b5c5SDavid van Moolenbroek     }
594*7348b5c5SDavid van Moolenbroek     return 1;
595*7348b5c5SDavid van Moolenbroek }
596*7348b5c5SDavid van Moolenbroek 
597*7348b5c5SDavid van Moolenbroek static int
togrbinary(int val)598*7348b5c5SDavid van Moolenbroek togrbinary(int val)
599*7348b5c5SDavid van Moolenbroek {
600*7348b5c5SDavid van Moolenbroek     donebinarytoggle = 1;
601*7348b5c5SDavid van Moolenbroek 
602*7348b5c5SDavid van Moolenbroek     if (val == -1)
603*7348b5c5SDavid van Moolenbroek 	val = my_want_state_is_do(TELOPT_BINARY) ? 0 : 1;
604*7348b5c5SDavid van Moolenbroek 
605*7348b5c5SDavid van Moolenbroek     if (val == 1) {
606*7348b5c5SDavid van Moolenbroek 	if (my_want_state_is_do(TELOPT_BINARY)) {
607*7348b5c5SDavid van Moolenbroek 	    printf("Already receiving in binary mode.\n");
608*7348b5c5SDavid van Moolenbroek 	} else {
609*7348b5c5SDavid van Moolenbroek 	    printf("Negotiating binary mode on input.\n");
610*7348b5c5SDavid van Moolenbroek 	    tel_enter_binary(1);
611*7348b5c5SDavid van Moolenbroek 	}
612*7348b5c5SDavid van Moolenbroek     } else {
613*7348b5c5SDavid van Moolenbroek 	if (my_want_state_is_dont(TELOPT_BINARY)) {
614*7348b5c5SDavid van Moolenbroek 	    printf("Already receiving in network ascii mode.\n");
615*7348b5c5SDavid van Moolenbroek 	} else {
616*7348b5c5SDavid van Moolenbroek 	    printf("Negotiating network ascii mode on input.\n");
617*7348b5c5SDavid van Moolenbroek 	    tel_leave_binary(1);
618*7348b5c5SDavid van Moolenbroek 	}
619*7348b5c5SDavid van Moolenbroek     }
620*7348b5c5SDavid van Moolenbroek     return 1;
621*7348b5c5SDavid van Moolenbroek }
622*7348b5c5SDavid van Moolenbroek 
623*7348b5c5SDavid van Moolenbroek static int
togxbinary(int val)624*7348b5c5SDavid van Moolenbroek togxbinary(int val)
625*7348b5c5SDavid van Moolenbroek {
626*7348b5c5SDavid van Moolenbroek     donebinarytoggle = 1;
627*7348b5c5SDavid van Moolenbroek 
628*7348b5c5SDavid van Moolenbroek     if (val == -1)
629*7348b5c5SDavid van Moolenbroek 	val = my_want_state_is_will(TELOPT_BINARY) ? 0 : 1;
630*7348b5c5SDavid van Moolenbroek 
631*7348b5c5SDavid van Moolenbroek     if (val == 1) {
632*7348b5c5SDavid van Moolenbroek 	if (my_want_state_is_will(TELOPT_BINARY)) {
633*7348b5c5SDavid van Moolenbroek 	    printf("Already transmitting in binary mode.\n");
634*7348b5c5SDavid van Moolenbroek 	} else {
635*7348b5c5SDavid van Moolenbroek 	    printf("Negotiating binary mode on output.\n");
636*7348b5c5SDavid van Moolenbroek 	    tel_enter_binary(2);
637*7348b5c5SDavid van Moolenbroek 	}
638*7348b5c5SDavid van Moolenbroek     } else {
639*7348b5c5SDavid van Moolenbroek 	if (my_want_state_is_wont(TELOPT_BINARY)) {
640*7348b5c5SDavid van Moolenbroek 	    printf("Already transmitting in network ascii mode.\n");
641*7348b5c5SDavid van Moolenbroek 	} else {
642*7348b5c5SDavid van Moolenbroek 	    printf("Negotiating network ascii mode on output.\n");
643*7348b5c5SDavid van Moolenbroek 	    tel_leave_binary(2);
644*7348b5c5SDavid van Moolenbroek 	}
645*7348b5c5SDavid van Moolenbroek     }
646*7348b5c5SDavid van Moolenbroek     return 1;
647*7348b5c5SDavid van Moolenbroek }
648*7348b5c5SDavid van Moolenbroek 
649*7348b5c5SDavid van Moolenbroek #ifdef	ENCRYPTION
650*7348b5c5SDavid van Moolenbroek extern int EncryptAutoEnc(int);
651*7348b5c5SDavid van Moolenbroek extern int EncryptAutoDec(int);
652*7348b5c5SDavid van Moolenbroek extern int EncryptDebug(int);
653*7348b5c5SDavid van Moolenbroek extern int EncryptVerbose(int);
654*7348b5c5SDavid van Moolenbroek #endif	/* ENCRYPTION */
655*7348b5c5SDavid van Moolenbroek 
656*7348b5c5SDavid van Moolenbroek struct togglelist {
657*7348b5c5SDavid van Moolenbroek     const char	*name;		/* name of toggle */
658*7348b5c5SDavid van Moolenbroek     const char	*help;		/* help message */
659*7348b5c5SDavid van Moolenbroek     int		(*handler)	/* routine to do actual setting */
660*7348b5c5SDavid van Moolenbroek 			(int);
661*7348b5c5SDavid van Moolenbroek     int		*variable;
662*7348b5c5SDavid van Moolenbroek     const char	*actionexplanation;
663*7348b5c5SDavid van Moolenbroek };
664*7348b5c5SDavid van Moolenbroek 
665*7348b5c5SDavid van Moolenbroek static struct togglelist Togglelist[] = {
666*7348b5c5SDavid van Moolenbroek     { "autoflush",
667*7348b5c5SDavid van Moolenbroek 	"flushing of output when sending interrupt characters",
668*7348b5c5SDavid van Moolenbroek 	    0,
669*7348b5c5SDavid van Moolenbroek 		&autoflush,
670*7348b5c5SDavid van Moolenbroek 		    "flush output when sending interrupt characters" },
671*7348b5c5SDavid van Moolenbroek     { "autosynch",
672*7348b5c5SDavid van Moolenbroek 	"automatic sending of interrupt characters in urgent mode",
673*7348b5c5SDavid van Moolenbroek 	    0,
674*7348b5c5SDavid van Moolenbroek 		&autosynch,
675*7348b5c5SDavid van Moolenbroek 		    "send interrupt characters in urgent mode" },
676*7348b5c5SDavid van Moolenbroek #ifdef AUTHENTICATION
677*7348b5c5SDavid van Moolenbroek     { "autologin",
678*7348b5c5SDavid van Moolenbroek 	"automatic sending of login and/or authentication info",
679*7348b5c5SDavid van Moolenbroek 	    0,
680*7348b5c5SDavid van Moolenbroek 		&autologin,
681*7348b5c5SDavid van Moolenbroek 		    "send login name and/or authentication information" },
682*7348b5c5SDavid van Moolenbroek     { "authdebug",
683*7348b5c5SDavid van Moolenbroek 	"Toggle authentication debugging",
684*7348b5c5SDavid van Moolenbroek 	    auth_togdebug,
685*7348b5c5SDavid van Moolenbroek 		0,
686*7348b5c5SDavid van Moolenbroek 		     "print authentication debugging information" },
687*7348b5c5SDavid van Moolenbroek #endif
688*7348b5c5SDavid van Moolenbroek #ifdef	ENCRYPTION
689*7348b5c5SDavid van Moolenbroek     { "autoencrypt",
690*7348b5c5SDavid van Moolenbroek       "automatic encryption of data stream",
691*7348b5c5SDavid van Moolenbroek 	    EncryptAutoEnc,
692*7348b5c5SDavid van Moolenbroek 		0,
693*7348b5c5SDavid van Moolenbroek 		     "automatically encrypt output" },
694*7348b5c5SDavid van Moolenbroek     { "autodecrypt",
695*7348b5c5SDavid van Moolenbroek       "automatic decryption of data stream",
696*7348b5c5SDavid van Moolenbroek 	    EncryptAutoDec,
697*7348b5c5SDavid van Moolenbroek 		0,
698*7348b5c5SDavid van Moolenbroek 		     "automatically decrypt input" },
699*7348b5c5SDavid van Moolenbroek     { "verbose_encrypt",
700*7348b5c5SDavid van Moolenbroek       "Toggle verbose encryption output",
701*7348b5c5SDavid van Moolenbroek 	    EncryptVerbose,
702*7348b5c5SDavid van Moolenbroek 		0,
703*7348b5c5SDavid van Moolenbroek 		     "print verbose encryption output" },
704*7348b5c5SDavid van Moolenbroek     { "encdebug",
705*7348b5c5SDavid van Moolenbroek       "Toggle encryption debugging",
706*7348b5c5SDavid van Moolenbroek 	    EncryptDebug,
707*7348b5c5SDavid van Moolenbroek 		0,
708*7348b5c5SDavid van Moolenbroek 		     "print encryption debugging information" },
709*7348b5c5SDavid van Moolenbroek #endif	/* ENCRYPTION */
710*7348b5c5SDavid van Moolenbroek     { "skiprc",
711*7348b5c5SDavid van Moolenbroek 	"don't read ~/.telnetrc file",
712*7348b5c5SDavid van Moolenbroek 	    0,
713*7348b5c5SDavid van Moolenbroek 		&skiprc,
714*7348b5c5SDavid van Moolenbroek 		    "skip reading of ~/.telnetrc file" },
715*7348b5c5SDavid van Moolenbroek     { "binary",
716*7348b5c5SDavid van Moolenbroek 	"sending and receiving of binary data",
717*7348b5c5SDavid van Moolenbroek 	    togbinary,
718*7348b5c5SDavid van Moolenbroek 		0,
719*7348b5c5SDavid van Moolenbroek 		    0 },
720*7348b5c5SDavid van Moolenbroek     { "inbinary",
721*7348b5c5SDavid van Moolenbroek 	"receiving of binary data",
722*7348b5c5SDavid van Moolenbroek 	    togrbinary,
723*7348b5c5SDavid van Moolenbroek 		0,
724*7348b5c5SDavid van Moolenbroek 		    0 },
725*7348b5c5SDavid van Moolenbroek     { "outbinary",
726*7348b5c5SDavid van Moolenbroek 	"sending of binary data",
727*7348b5c5SDavid van Moolenbroek 	    togxbinary,
728*7348b5c5SDavid van Moolenbroek 		0,
729*7348b5c5SDavid van Moolenbroek 		    0 },
730*7348b5c5SDavid van Moolenbroek     { "crlf",
731*7348b5c5SDavid van Moolenbroek 	"sending carriage returns as telnet <CR><LF>",
732*7348b5c5SDavid van Moolenbroek 	   togcrlf,
733*7348b5c5SDavid van Moolenbroek 		&crlf,
734*7348b5c5SDavid van Moolenbroek 		    0 },
735*7348b5c5SDavid van Moolenbroek     { "crmod",
736*7348b5c5SDavid van Moolenbroek 	"mapping of received carriage returns",
737*7348b5c5SDavid van Moolenbroek 	    0,
738*7348b5c5SDavid van Moolenbroek 		&crmod,
739*7348b5c5SDavid van Moolenbroek 		    "map carriage return on output" },
740*7348b5c5SDavid van Moolenbroek     { "localchars",
741*7348b5c5SDavid van Moolenbroek 	"local recognition of certain control characters",
742*7348b5c5SDavid van Moolenbroek 	    lclchars,
743*7348b5c5SDavid van Moolenbroek 		&localchars,
744*7348b5c5SDavid van Moolenbroek 		    "recognize certain control characters" },
745*7348b5c5SDavid van Moolenbroek     { " ", "", 0, NULL, NULL },		/* empty line */
746*7348b5c5SDavid van Moolenbroek #ifdef TN3270
747*7348b5c5SDavid van Moolenbroek     { "apitrace",
748*7348b5c5SDavid van Moolenbroek 	"(debugging) toggle tracing of API transactions",
749*7348b5c5SDavid van Moolenbroek 	    0,
750*7348b5c5SDavid van Moolenbroek 		&apitrace,
751*7348b5c5SDavid van Moolenbroek 		    "trace API transactions" },
752*7348b5c5SDavid van Moolenbroek     { "cursesdata",
753*7348b5c5SDavid van Moolenbroek 	"(debugging) toggle printing of hexadecimal curses data",
754*7348b5c5SDavid van Moolenbroek 	    0,
755*7348b5c5SDavid van Moolenbroek 		&cursesdata,
756*7348b5c5SDavid van Moolenbroek 		    "print hexadecimal representation of curses data" },
757*7348b5c5SDavid van Moolenbroek #endif	/* defined(TN3270) */
758*7348b5c5SDavid van Moolenbroek     { "debug",
759*7348b5c5SDavid van Moolenbroek 	"debugging",
760*7348b5c5SDavid van Moolenbroek 	    togdebug,
761*7348b5c5SDavid van Moolenbroek 		&telnet_debug,
762*7348b5c5SDavid van Moolenbroek 		    "turn on socket level debugging" },
763*7348b5c5SDavid van Moolenbroek     { "netdata",
764*7348b5c5SDavid van Moolenbroek 	"printing of hexadecimal network data (debugging)",
765*7348b5c5SDavid van Moolenbroek 	    0,
766*7348b5c5SDavid van Moolenbroek 		&netdata,
767*7348b5c5SDavid van Moolenbroek 		    "print hexadecimal representation of network traffic" },
768*7348b5c5SDavid van Moolenbroek     { "prettydump",
769*7348b5c5SDavid van Moolenbroek 	"output of \"netdata\" to user readable format (debugging)",
770*7348b5c5SDavid van Moolenbroek 	    0,
771*7348b5c5SDavid van Moolenbroek 		&prettydump,
772*7348b5c5SDavid van Moolenbroek 		    "print user readable output for \"netdata\"" },
773*7348b5c5SDavid van Moolenbroek     { "options",
774*7348b5c5SDavid van Moolenbroek 	"viewing of options processing (debugging)",
775*7348b5c5SDavid van Moolenbroek 	    0,
776*7348b5c5SDavid van Moolenbroek 		&showoptions,
777*7348b5c5SDavid van Moolenbroek 		    "show option processing" },
778*7348b5c5SDavid van Moolenbroek     { "termdata",
779*7348b5c5SDavid van Moolenbroek 	"(debugging) toggle printing of hexadecimal terminal data",
780*7348b5c5SDavid van Moolenbroek 	    0,
781*7348b5c5SDavid van Moolenbroek 		&termdata,
782*7348b5c5SDavid van Moolenbroek 		    "print hexadecimal representation of terminal traffic" },
783*7348b5c5SDavid van Moolenbroek     { "?",
784*7348b5c5SDavid van Moolenbroek 	0,
785*7348b5c5SDavid van Moolenbroek 	    togglehelp, NULL, NULL },
786*7348b5c5SDavid van Moolenbroek     { "help",
787*7348b5c5SDavid van Moolenbroek 	0,
788*7348b5c5SDavid van Moolenbroek 	    togglehelp, NULL, NULL },
789*7348b5c5SDavid van Moolenbroek     { .name = 0 }
790*7348b5c5SDavid van Moolenbroek };
791*7348b5c5SDavid van Moolenbroek 
792*7348b5c5SDavid van Moolenbroek static int
togglehelp(int n)793*7348b5c5SDavid van Moolenbroek togglehelp(int n)
794*7348b5c5SDavid van Moolenbroek {
795*7348b5c5SDavid van Moolenbroek     struct togglelist *c;
796*7348b5c5SDavid van Moolenbroek 
797*7348b5c5SDavid van Moolenbroek     for (c = Togglelist; c->name; c++) {
798*7348b5c5SDavid van Moolenbroek 	if (c->help) {
799*7348b5c5SDavid van Moolenbroek 	    if (*c->help)
800*7348b5c5SDavid van Moolenbroek 		printf("%-15s toggle %s\n", c->name, c->help);
801*7348b5c5SDavid van Moolenbroek 	    else
802*7348b5c5SDavid van Moolenbroek 		printf("\n");
803*7348b5c5SDavid van Moolenbroek 	}
804*7348b5c5SDavid van Moolenbroek     }
805*7348b5c5SDavid van Moolenbroek     printf("\n");
806*7348b5c5SDavid van Moolenbroek     printf("%-15s %s\n", "?", "display help information");
807*7348b5c5SDavid van Moolenbroek     return 0;
808*7348b5c5SDavid van Moolenbroek }
809*7348b5c5SDavid van Moolenbroek 
810*7348b5c5SDavid van Moolenbroek static void
settogglehelp(int set)811*7348b5c5SDavid van Moolenbroek settogglehelp(int set)
812*7348b5c5SDavid van Moolenbroek {
813*7348b5c5SDavid van Moolenbroek     struct togglelist *c;
814*7348b5c5SDavid van Moolenbroek 
815*7348b5c5SDavid van Moolenbroek     for (c = Togglelist; c->name; c++) {
816*7348b5c5SDavid van Moolenbroek 	if (c->help) {
817*7348b5c5SDavid van Moolenbroek 	    if (*c->help)
818*7348b5c5SDavid van Moolenbroek 		printf("%-15s %s %s\n", c->name, set ? "enable" : "disable",
819*7348b5c5SDavid van Moolenbroek 						c->help);
820*7348b5c5SDavid van Moolenbroek 	    else
821*7348b5c5SDavid van Moolenbroek 		printf("\n");
822*7348b5c5SDavid van Moolenbroek 	}
823*7348b5c5SDavid van Moolenbroek     }
824*7348b5c5SDavid van Moolenbroek }
825*7348b5c5SDavid van Moolenbroek 
826*7348b5c5SDavid van Moolenbroek #define	GETTOGGLE(name) (struct togglelist *) \
827*7348b5c5SDavid van Moolenbroek 		genget(name, (char **) Togglelist, sizeof(struct togglelist))
828*7348b5c5SDavid van Moolenbroek 
829*7348b5c5SDavid van Moolenbroek static int
toggle(int argc,char * argv[])830*7348b5c5SDavid van Moolenbroek toggle(int  argc, char *argv[])
831*7348b5c5SDavid van Moolenbroek {
832*7348b5c5SDavid van Moolenbroek     int retval = 1;
833*7348b5c5SDavid van Moolenbroek     char *name;
834*7348b5c5SDavid van Moolenbroek     struct togglelist *c;
835*7348b5c5SDavid van Moolenbroek 
836*7348b5c5SDavid van Moolenbroek     if (argc < 2) {
837*7348b5c5SDavid van Moolenbroek 	fprintf(stderr,
838*7348b5c5SDavid van Moolenbroek 	    "Need an argument to 'toggle' command.  'toggle ?' for help.\n");
839*7348b5c5SDavid van Moolenbroek 	return 0;
840*7348b5c5SDavid van Moolenbroek     }
841*7348b5c5SDavid van Moolenbroek     argc--;
842*7348b5c5SDavid van Moolenbroek     argv++;
843*7348b5c5SDavid van Moolenbroek     while (argc--) {
844*7348b5c5SDavid van Moolenbroek 	name = *argv++;
845*7348b5c5SDavid van Moolenbroek 	c = GETTOGGLE(name);
846*7348b5c5SDavid van Moolenbroek 	if (Ambiguous(c)) {
847*7348b5c5SDavid van Moolenbroek 	    fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n",
848*7348b5c5SDavid van Moolenbroek 					name);
849*7348b5c5SDavid van Moolenbroek 	    return 0;
850*7348b5c5SDavid van Moolenbroek 	} else if (c == 0) {
851*7348b5c5SDavid van Moolenbroek 	    fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n",
852*7348b5c5SDavid van Moolenbroek 					name);
853*7348b5c5SDavid van Moolenbroek 	    return 0;
854*7348b5c5SDavid van Moolenbroek 	} else {
855*7348b5c5SDavid van Moolenbroek 	    if (c->variable) {
856*7348b5c5SDavid van Moolenbroek 		*c->variable = !*c->variable;		/* invert it */
857*7348b5c5SDavid van Moolenbroek 		if (c->actionexplanation) {
858*7348b5c5SDavid van Moolenbroek 		    printf("%s %s.\n", *c->variable? "Will" : "Won't",
859*7348b5c5SDavid van Moolenbroek 							c->actionexplanation);
860*7348b5c5SDavid van Moolenbroek 		}
861*7348b5c5SDavid van Moolenbroek 	    }
862*7348b5c5SDavid van Moolenbroek 	    if (c->handler) {
863*7348b5c5SDavid van Moolenbroek 		retval &= (*c->handler)(-1);
864*7348b5c5SDavid van Moolenbroek 	    }
865*7348b5c5SDavid van Moolenbroek 	}
866*7348b5c5SDavid van Moolenbroek     }
867*7348b5c5SDavid van Moolenbroek     return retval;
868*7348b5c5SDavid van Moolenbroek }
869*7348b5c5SDavid van Moolenbroek 
870*7348b5c5SDavid van Moolenbroek /*
871*7348b5c5SDavid van Moolenbroek  * The following perform the "set" command.
872*7348b5c5SDavid van Moolenbroek  */
873*7348b5c5SDavid van Moolenbroek 
874*7348b5c5SDavid van Moolenbroek struct termios new_tc = { .c_iflag = 0 };
875*7348b5c5SDavid van Moolenbroek 
876*7348b5c5SDavid van Moolenbroek struct setlist {
877*7348b5c5SDavid van Moolenbroek     const char *name;			/* name */
878*7348b5c5SDavid van Moolenbroek     const char *help;			/* help information */
879*7348b5c5SDavid van Moolenbroek     void (*handler)(char *);
880*7348b5c5SDavid van Moolenbroek     cc_t *charp;			/* where it is located at */
881*7348b5c5SDavid van Moolenbroek };
882*7348b5c5SDavid van Moolenbroek 
883*7348b5c5SDavid van Moolenbroek static struct setlist Setlist[] = {
884*7348b5c5SDavid van Moolenbroek #ifdef	KLUDGELINEMODE
885*7348b5c5SDavid van Moolenbroek     { "echo", 	"character to toggle local echoing on/off", 0, &echoc },
886*7348b5c5SDavid van Moolenbroek #endif
887*7348b5c5SDavid van Moolenbroek     { "escape",	"character to escape back to telnet command mode", 0, &escape },
888*7348b5c5SDavid van Moolenbroek     { "rlogin", "rlogin escape character", 0, &rlogin },
889*7348b5c5SDavid van Moolenbroek     { "tracefile", "file to write trace information to", SetNetTrace, (cc_t *)NetTraceFile},
890*7348b5c5SDavid van Moolenbroek     { " ", "", NULL, NULL },
891*7348b5c5SDavid van Moolenbroek     { " ", "The following need 'localchars' to be toggled true", 0, 0 },
892*7348b5c5SDavid van Moolenbroek     { "flushoutput", "character to cause an Abort Output", 0, termFlushCharp },
893*7348b5c5SDavid van Moolenbroek     { "interrupt", "character to cause an Interrupt Process", 0, termIntCharp },
894*7348b5c5SDavid van Moolenbroek     { "quit",	"character to cause an Abort process", 0, termQuitCharp },
895*7348b5c5SDavid van Moolenbroek     { "eof",	"character to cause an EOF ", 0, termEofCharp },
896*7348b5c5SDavid van Moolenbroek     { " ", "", NULL, NULL },
897*7348b5c5SDavid van Moolenbroek     { " ", "The following are for local editing in linemode", 0, 0 },
898*7348b5c5SDavid van Moolenbroek     { "erase",	"character to use to erase a character", 0, termEraseCharp },
899*7348b5c5SDavid van Moolenbroek     { "kill",	"character to use to erase a line", 0, termKillCharp },
900*7348b5c5SDavid van Moolenbroek     { "lnext",	"character to use for literal next", 0, termLiteralNextCharp },
901*7348b5c5SDavid van Moolenbroek     { "susp",	"character to cause a Suspend Process", 0, termSuspCharp },
902*7348b5c5SDavid van Moolenbroek     { "reprint", "character to use for line reprint", 0, termRprntCharp },
903*7348b5c5SDavid van Moolenbroek     { "worderase", "character to use to erase a word", 0, termWerasCharp },
904*7348b5c5SDavid van Moolenbroek     { "start",	"character to use for XON", 0, termStartCharp },
905*7348b5c5SDavid van Moolenbroek     { "stop",	"character to use for XOFF", 0, termStopCharp },
906*7348b5c5SDavid van Moolenbroek     { "forw1",	"alternate end of line character", 0, termForw1Charp },
907*7348b5c5SDavid van Moolenbroek     { "forw2",	"alternate end of line character", 0, termForw2Charp },
908*7348b5c5SDavid van Moolenbroek     { "ayt",	"alternate AYT character", 0, termAytCharp },
909*7348b5c5SDavid van Moolenbroek     { .name = 0 }
910*7348b5c5SDavid van Moolenbroek };
911*7348b5c5SDavid van Moolenbroek 
912*7348b5c5SDavid van Moolenbroek static struct setlist *
getset(char * name)913*7348b5c5SDavid van Moolenbroek getset(char *name)
914*7348b5c5SDavid van Moolenbroek {
915*7348b5c5SDavid van Moolenbroek     return (struct setlist *)
916*7348b5c5SDavid van Moolenbroek 		genget(name, (char **) Setlist, sizeof(struct setlist));
917*7348b5c5SDavid van Moolenbroek }
918*7348b5c5SDavid van Moolenbroek 
919*7348b5c5SDavid van Moolenbroek void
set_escape_char(char * s)920*7348b5c5SDavid van Moolenbroek set_escape_char(char *s)
921*7348b5c5SDavid van Moolenbroek {
922*7348b5c5SDavid van Moolenbroek 	if (rlogin != _POSIX_VDISABLE) {
923*7348b5c5SDavid van Moolenbroek 		rlogin = (s && *s) ? special(s) : _POSIX_VDISABLE;
924*7348b5c5SDavid van Moolenbroek 		printf("Telnet rlogin escape character is '%s'.\n",
925*7348b5c5SDavid van Moolenbroek 					control(rlogin));
926*7348b5c5SDavid van Moolenbroek 	} else {
927*7348b5c5SDavid van Moolenbroek 		escape = (s && *s) ? special(s) : _POSIX_VDISABLE;
928*7348b5c5SDavid van Moolenbroek 		printf("Telnet escape character is '%s'.\n", control(escape));
929*7348b5c5SDavid van Moolenbroek 	}
930*7348b5c5SDavid van Moolenbroek }
931*7348b5c5SDavid van Moolenbroek 
932*7348b5c5SDavid van Moolenbroek static int
setcmd(int argc,char * argv[])933*7348b5c5SDavid van Moolenbroek setcmd(int  argc, char *argv[])
934*7348b5c5SDavid van Moolenbroek {
935*7348b5c5SDavid van Moolenbroek     int value;
936*7348b5c5SDavid van Moolenbroek     struct setlist *ct;
937*7348b5c5SDavid van Moolenbroek     struct togglelist *c;
938*7348b5c5SDavid van Moolenbroek 
939*7348b5c5SDavid van Moolenbroek     if (argc < 2 || argc > 3) {
940*7348b5c5SDavid van Moolenbroek 	printf("Format is 'set Name Value'\n'set ?' for help.\n");
941*7348b5c5SDavid van Moolenbroek 	return 0;
942*7348b5c5SDavid van Moolenbroek     }
943*7348b5c5SDavid van Moolenbroek     if ((argc == 2) && (isprefix(argv[1], "?") || isprefix(argv[1], "help"))) {
944*7348b5c5SDavid van Moolenbroek 	for (ct = Setlist; ct->name; ct++)
945*7348b5c5SDavid van Moolenbroek 	    printf("%-15s %s\n", ct->name, ct->help);
946*7348b5c5SDavid van Moolenbroek 	printf("\n");
947*7348b5c5SDavid van Moolenbroek 	settogglehelp(1);
948*7348b5c5SDavid van Moolenbroek 	printf("%-15s %s\n", "?", "display help information");
949*7348b5c5SDavid van Moolenbroek 	return 0;
950*7348b5c5SDavid van Moolenbroek     }
951*7348b5c5SDavid van Moolenbroek 
952*7348b5c5SDavid van Moolenbroek     ct = getset(argv[1]);
953*7348b5c5SDavid van Moolenbroek     if (ct == 0) {
954*7348b5c5SDavid van Moolenbroek 	c = GETTOGGLE(argv[1]);
955*7348b5c5SDavid van Moolenbroek 	if (c == 0) {
956*7348b5c5SDavid van Moolenbroek 	    fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n",
957*7348b5c5SDavid van Moolenbroek 			argv[1]);
958*7348b5c5SDavid van Moolenbroek 	    return 0;
959*7348b5c5SDavid van Moolenbroek 	} else if (Ambiguous(c)) {
960*7348b5c5SDavid van Moolenbroek 	    fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
961*7348b5c5SDavid van Moolenbroek 			argv[1]);
962*7348b5c5SDavid van Moolenbroek 	    return 0;
963*7348b5c5SDavid van Moolenbroek 	}
964*7348b5c5SDavid van Moolenbroek 	if (c->variable) {
965*7348b5c5SDavid van Moolenbroek 	    if ((argc == 2) || (strcmp("on", argv[2]) == 0))
966*7348b5c5SDavid van Moolenbroek 		*c->variable = 1;
967*7348b5c5SDavid van Moolenbroek 	    else if (strcmp("off", argv[2]) == 0)
968*7348b5c5SDavid van Moolenbroek 		*c->variable = 0;
969*7348b5c5SDavid van Moolenbroek 	    else {
970*7348b5c5SDavid van Moolenbroek 		printf("Format is 'set togglename [on|off]'\n'set ?' for help.\n");
971*7348b5c5SDavid van Moolenbroek 		return 0;
972*7348b5c5SDavid van Moolenbroek 	    }
973*7348b5c5SDavid van Moolenbroek 	    if (c->actionexplanation) {
974*7348b5c5SDavid van Moolenbroek 		printf("%s %s.\n", *c->variable? "Will" : "Won't",
975*7348b5c5SDavid van Moolenbroek 							c->actionexplanation);
976*7348b5c5SDavid van Moolenbroek 	    }
977*7348b5c5SDavid van Moolenbroek 	}
978*7348b5c5SDavid van Moolenbroek 	if (c->handler)
979*7348b5c5SDavid van Moolenbroek 	    (*c->handler)(1);
980*7348b5c5SDavid van Moolenbroek     } else if (argc != 3) {
981*7348b5c5SDavid van Moolenbroek 	printf("Format is 'set Name Value'\n'set ?' for help.\n");
982*7348b5c5SDavid van Moolenbroek 	return 0;
983*7348b5c5SDavid van Moolenbroek     } else if (Ambiguous(ct)) {
984*7348b5c5SDavid van Moolenbroek 	fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
985*7348b5c5SDavid van Moolenbroek 			argv[1]);
986*7348b5c5SDavid van Moolenbroek 	return 0;
987*7348b5c5SDavid van Moolenbroek     } else if (ct->handler) {
988*7348b5c5SDavid van Moolenbroek 	(*ct->handler)(argv[2]);
989*7348b5c5SDavid van Moolenbroek 	printf("%s set to \"%s\".\n", ct->name, (char *)ct->charp);
990*7348b5c5SDavid van Moolenbroek     } else {
991*7348b5c5SDavid van Moolenbroek 	if (strcmp("off", argv[2])) {
992*7348b5c5SDavid van Moolenbroek 	    value = special(argv[2]);
993*7348b5c5SDavid van Moolenbroek 	} else {
994*7348b5c5SDavid van Moolenbroek 	    value = _POSIX_VDISABLE;
995*7348b5c5SDavid van Moolenbroek 	}
996*7348b5c5SDavid van Moolenbroek 	*(ct->charp) = (cc_t)value;
997*7348b5c5SDavid van Moolenbroek 	printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
998*7348b5c5SDavid van Moolenbroek     }
999*7348b5c5SDavid van Moolenbroek     slc_check();
1000*7348b5c5SDavid van Moolenbroek     return 1;
1001*7348b5c5SDavid van Moolenbroek }
1002*7348b5c5SDavid van Moolenbroek 
1003*7348b5c5SDavid van Moolenbroek static int
unsetcmd(int argc,char * argv[])1004*7348b5c5SDavid van Moolenbroek unsetcmd(int  argc, char *argv[])
1005*7348b5c5SDavid van Moolenbroek {
1006*7348b5c5SDavid van Moolenbroek     struct setlist *ct;
1007*7348b5c5SDavid van Moolenbroek     struct togglelist *c;
1008*7348b5c5SDavid van Moolenbroek     char *name;
1009*7348b5c5SDavid van Moolenbroek 
1010*7348b5c5SDavid van Moolenbroek     if (argc < 2) {
1011*7348b5c5SDavid van Moolenbroek 	fprintf(stderr,
1012*7348b5c5SDavid van Moolenbroek 	    "Need an argument to 'unset' command.  'unset ?' for help.\n");
1013*7348b5c5SDavid van Moolenbroek 	return 0;
1014*7348b5c5SDavid van Moolenbroek     }
1015*7348b5c5SDavid van Moolenbroek     if (isprefix(argv[1], "?") || isprefix(argv[1], "help")) {
1016*7348b5c5SDavid van Moolenbroek 	for (ct = Setlist; ct->name; ct++)
1017*7348b5c5SDavid van Moolenbroek 	    printf("%-15s %s\n", ct->name, ct->help);
1018*7348b5c5SDavid van Moolenbroek 	printf("\n");
1019*7348b5c5SDavid van Moolenbroek 	settogglehelp(0);
1020*7348b5c5SDavid van Moolenbroek 	printf("%-15s %s\n", "?", "display help information");
1021*7348b5c5SDavid van Moolenbroek 	return 0;
1022*7348b5c5SDavid van Moolenbroek     }
1023*7348b5c5SDavid van Moolenbroek 
1024*7348b5c5SDavid van Moolenbroek     argc--;
1025*7348b5c5SDavid van Moolenbroek     argv++;
1026*7348b5c5SDavid van Moolenbroek     while (argc--) {
1027*7348b5c5SDavid van Moolenbroek 	name = *argv++;
1028*7348b5c5SDavid van Moolenbroek 	ct = getset(name);
1029*7348b5c5SDavid van Moolenbroek 	if (ct == 0) {
1030*7348b5c5SDavid van Moolenbroek 	    c = GETTOGGLE(name);
1031*7348b5c5SDavid van Moolenbroek 	    if (c == 0) {
1032*7348b5c5SDavid van Moolenbroek 		fprintf(stderr, "'%s': unknown argument ('unset ?' for help).\n",
1033*7348b5c5SDavid van Moolenbroek 			name);
1034*7348b5c5SDavid van Moolenbroek 		return 0;
1035*7348b5c5SDavid van Moolenbroek 	    } else if (Ambiguous(c)) {
1036*7348b5c5SDavid van Moolenbroek 		fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n",
1037*7348b5c5SDavid van Moolenbroek 			name);
1038*7348b5c5SDavid van Moolenbroek 		return 0;
1039*7348b5c5SDavid van Moolenbroek 	    }
1040*7348b5c5SDavid van Moolenbroek 	    if (c->variable) {
1041*7348b5c5SDavid van Moolenbroek 		*c->variable = 0;
1042*7348b5c5SDavid van Moolenbroek 		if (c->actionexplanation) {
1043*7348b5c5SDavid van Moolenbroek 		    printf("%s %s.\n", *c->variable? "Will" : "Won't",
1044*7348b5c5SDavid van Moolenbroek 							c->actionexplanation);
1045*7348b5c5SDavid van Moolenbroek 		}
1046*7348b5c5SDavid van Moolenbroek 	    }
1047*7348b5c5SDavid van Moolenbroek 	    if (c->handler)
1048*7348b5c5SDavid van Moolenbroek 		(*c->handler)(0);
1049*7348b5c5SDavid van Moolenbroek 	} else if (Ambiguous(ct)) {
1050*7348b5c5SDavid van Moolenbroek 	    fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n",
1051*7348b5c5SDavid van Moolenbroek 			name);
1052*7348b5c5SDavid van Moolenbroek 	    return 0;
1053*7348b5c5SDavid van Moolenbroek 	} else if (ct->handler) {
1054*7348b5c5SDavid van Moolenbroek 	    (*ct->handler)(0);
1055*7348b5c5SDavid van Moolenbroek 	    printf("%s reset to \"%s\".\n", ct->name, (char *)ct->charp);
1056*7348b5c5SDavid van Moolenbroek 	} else {
1057*7348b5c5SDavid van Moolenbroek 	    *(ct->charp) = _POSIX_VDISABLE;
1058*7348b5c5SDavid van Moolenbroek 	    printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
1059*7348b5c5SDavid van Moolenbroek 	}
1060*7348b5c5SDavid van Moolenbroek     }
1061*7348b5c5SDavid van Moolenbroek     return 1;
1062*7348b5c5SDavid van Moolenbroek }
1063*7348b5c5SDavid van Moolenbroek 
1064*7348b5c5SDavid van Moolenbroek /*
1065*7348b5c5SDavid van Moolenbroek  * The following are the data structures and routines for the
1066*7348b5c5SDavid van Moolenbroek  * 'mode' command.
1067*7348b5c5SDavid van Moolenbroek  */
1068*7348b5c5SDavid van Moolenbroek #ifdef	KLUDGELINEMODE
1069*7348b5c5SDavid van Moolenbroek extern int kludgelinemode;
1070*7348b5c5SDavid van Moolenbroek 
1071*7348b5c5SDavid van Moolenbroek static int
dokludgemode(int n)1072*7348b5c5SDavid van Moolenbroek dokludgemode(int n)
1073*7348b5c5SDavid van Moolenbroek {
1074*7348b5c5SDavid van Moolenbroek     kludgelinemode = 1;
1075*7348b5c5SDavid van Moolenbroek     send_wont(TELOPT_LINEMODE, 1);
1076*7348b5c5SDavid van Moolenbroek     send_dont(TELOPT_SGA, 1);
1077*7348b5c5SDavid van Moolenbroek     send_dont(TELOPT_ECHO, 1);
1078*7348b5c5SDavid van Moolenbroek     return 1;
1079*7348b5c5SDavid van Moolenbroek }
1080*7348b5c5SDavid van Moolenbroek #endif
1081*7348b5c5SDavid van Moolenbroek 
1082*7348b5c5SDavid van Moolenbroek static int
dolinemode(int n)1083*7348b5c5SDavid van Moolenbroek dolinemode(int n)
1084*7348b5c5SDavid van Moolenbroek {
1085*7348b5c5SDavid van Moolenbroek #ifdef	KLUDGELINEMODE
1086*7348b5c5SDavid van Moolenbroek     if (kludgelinemode)
1087*7348b5c5SDavid van Moolenbroek 	send_dont(TELOPT_SGA, 1);
1088*7348b5c5SDavid van Moolenbroek #endif
1089*7348b5c5SDavid van Moolenbroek     send_will(TELOPT_LINEMODE, 1);
1090*7348b5c5SDavid van Moolenbroek     send_dont(TELOPT_ECHO, 1);
1091*7348b5c5SDavid van Moolenbroek     return 1;
1092*7348b5c5SDavid van Moolenbroek }
1093*7348b5c5SDavid van Moolenbroek 
1094*7348b5c5SDavid van Moolenbroek static int
docharmode(int n)1095*7348b5c5SDavid van Moolenbroek docharmode(int n)
1096*7348b5c5SDavid van Moolenbroek {
1097*7348b5c5SDavid van Moolenbroek #ifdef	KLUDGELINEMODE
1098*7348b5c5SDavid van Moolenbroek     if (kludgelinemode)
1099*7348b5c5SDavid van Moolenbroek 	send_do(TELOPT_SGA, 1);
1100*7348b5c5SDavid van Moolenbroek     else
1101*7348b5c5SDavid van Moolenbroek #endif
1102*7348b5c5SDavid van Moolenbroek     send_wont(TELOPT_LINEMODE, 1);
1103*7348b5c5SDavid van Moolenbroek     send_do(TELOPT_ECHO, 1);
1104*7348b5c5SDavid van Moolenbroek     return 1;
1105*7348b5c5SDavid van Moolenbroek }
1106*7348b5c5SDavid van Moolenbroek 
1107*7348b5c5SDavid van Moolenbroek static int
dolmmode(int bit,int on)1108*7348b5c5SDavid van Moolenbroek dolmmode(int bit, int on)
1109*7348b5c5SDavid van Moolenbroek {
1110*7348b5c5SDavid van Moolenbroek     unsigned char c;
1111*7348b5c5SDavid van Moolenbroek     extern int linemode;
1112*7348b5c5SDavid van Moolenbroek 
1113*7348b5c5SDavid van Moolenbroek     if (my_want_state_is_wont(TELOPT_LINEMODE)) {
1114*7348b5c5SDavid van Moolenbroek 	printf("?Need to have LINEMODE option enabled first.\n");
1115*7348b5c5SDavid van Moolenbroek 	printf("'mode ?' for help.\n");
1116*7348b5c5SDavid van Moolenbroek 	return 0;
1117*7348b5c5SDavid van Moolenbroek     }
1118*7348b5c5SDavid van Moolenbroek 
1119*7348b5c5SDavid van Moolenbroek     if (on)
1120*7348b5c5SDavid van Moolenbroek 	c = (linemode | bit);
1121*7348b5c5SDavid van Moolenbroek     else
1122*7348b5c5SDavid van Moolenbroek 	c = (linemode & ~bit);
1123*7348b5c5SDavid van Moolenbroek     lm_mode(&c, 1, 1);
1124*7348b5c5SDavid van Moolenbroek     return 1;
1125*7348b5c5SDavid van Moolenbroek }
1126*7348b5c5SDavid van Moolenbroek 
1127*7348b5c5SDavid van Moolenbroek int
set_mode(int bit)1128*7348b5c5SDavid van Moolenbroek set_mode(int bit)
1129*7348b5c5SDavid van Moolenbroek {
1130*7348b5c5SDavid van Moolenbroek     return dolmmode(bit, 1);
1131*7348b5c5SDavid van Moolenbroek }
1132*7348b5c5SDavid van Moolenbroek 
1133*7348b5c5SDavid van Moolenbroek int
clear_mode(int bit)1134*7348b5c5SDavid van Moolenbroek clear_mode(int bit)
1135*7348b5c5SDavid van Moolenbroek {
1136*7348b5c5SDavid van Moolenbroek     return dolmmode(bit, 0);
1137*7348b5c5SDavid van Moolenbroek }
1138*7348b5c5SDavid van Moolenbroek 
1139*7348b5c5SDavid van Moolenbroek struct modelist {
1140*7348b5c5SDavid van Moolenbroek 	const char	*name;	/* command name */
1141*7348b5c5SDavid van Moolenbroek 	const char	*help;	/* help string */
1142*7348b5c5SDavid van Moolenbroek 	int	(*handler)	/* routine which executes command */
1143*7348b5c5SDavid van Moolenbroek 			(int);
1144*7348b5c5SDavid van Moolenbroek 	int	needconnect;	/* Do we need to be connected to execute? */
1145*7348b5c5SDavid van Moolenbroek 	int	arg1;
1146*7348b5c5SDavid van Moolenbroek };
1147*7348b5c5SDavid van Moolenbroek 
1148*7348b5c5SDavid van Moolenbroek static struct modelist ModeList[] = {
1149*7348b5c5SDavid van Moolenbroek     { "character", "Disable LINEMODE option",	docharmode, 1, 0 },
1150*7348b5c5SDavid van Moolenbroek #ifdef	KLUDGELINEMODE
1151*7348b5c5SDavid van Moolenbroek     { "",	"(or disable obsolete line-by-line mode)", 0, 0, 0 },
1152*7348b5c5SDavid van Moolenbroek #endif
1153*7348b5c5SDavid van Moolenbroek     { "line",	"Enable LINEMODE option",	dolinemode, 1, 0 },
1154*7348b5c5SDavid van Moolenbroek #ifdef	KLUDGELINEMODE
1155*7348b5c5SDavid van Moolenbroek     { "",	"(or enable obsolete line-by-line mode)", 0, 0, 0 },
1156*7348b5c5SDavid van Moolenbroek #endif
1157*7348b5c5SDavid van Moolenbroek     { "", "", 0, 0, 0 },
1158*7348b5c5SDavid van Moolenbroek     { "",	"These require the LINEMODE option to be enabled", 0, 0, 0 },
1159*7348b5c5SDavid van Moolenbroek     { "isig",	"Enable signal trapping",	set_mode, 1, MODE_TRAPSIG },
1160*7348b5c5SDavid van Moolenbroek     { "+isig",	0,				set_mode, 1, MODE_TRAPSIG },
1161*7348b5c5SDavid van Moolenbroek     { "-isig",	"Disable signal trapping",	clear_mode, 1, MODE_TRAPSIG },
1162*7348b5c5SDavid van Moolenbroek     { "edit",	"Enable character editing",	set_mode, 1, MODE_EDIT },
1163*7348b5c5SDavid van Moolenbroek     { "+edit",	0,				set_mode, 1, MODE_EDIT },
1164*7348b5c5SDavid van Moolenbroek     { "-edit",	"Disable character editing",	clear_mode, 1, MODE_EDIT },
1165*7348b5c5SDavid van Moolenbroek     { "softtabs", "Enable tab expansion",	set_mode, 1, MODE_SOFT_TAB },
1166*7348b5c5SDavid van Moolenbroek     { "+softtabs", 0,				set_mode, 1, MODE_SOFT_TAB },
1167*7348b5c5SDavid van Moolenbroek     { "-softtabs", "Disable character editing",	clear_mode, 1, MODE_SOFT_TAB },
1168*7348b5c5SDavid van Moolenbroek     { "litecho", "Enable literal character echo", set_mode, 1, MODE_LIT_ECHO },
1169*7348b5c5SDavid van Moolenbroek     { "+litecho", 0,				set_mode, 1, MODE_LIT_ECHO },
1170*7348b5c5SDavid van Moolenbroek     { "-litecho", "Disable literal character echo", clear_mode, 1, MODE_LIT_ECHO },
1171*7348b5c5SDavid van Moolenbroek     { "help",	0,				modehelp, 0, 0 },
1172*7348b5c5SDavid van Moolenbroek #ifdef	KLUDGELINEMODE
1173*7348b5c5SDavid van Moolenbroek     { "kludgeline", 0,				dokludgemode, 1, 0 },
1174*7348b5c5SDavid van Moolenbroek #endif
1175*7348b5c5SDavid van Moolenbroek     { "", "", 0, 0, 0 },
1176*7348b5c5SDavid van Moolenbroek     { "?",	"Print help information",	modehelp, 0, 0 },
1177*7348b5c5SDavid van Moolenbroek     { .name = 0 },
1178*7348b5c5SDavid van Moolenbroek };
1179*7348b5c5SDavid van Moolenbroek 
1180*7348b5c5SDavid van Moolenbroek 
1181*7348b5c5SDavid van Moolenbroek int
modehelp(int n)1182*7348b5c5SDavid van Moolenbroek modehelp(int n)
1183*7348b5c5SDavid van Moolenbroek {
1184*7348b5c5SDavid van Moolenbroek     struct modelist *mt;
1185*7348b5c5SDavid van Moolenbroek 
1186*7348b5c5SDavid van Moolenbroek     printf("format is:  'mode Mode', where 'Mode' is one of:\n\n");
1187*7348b5c5SDavid van Moolenbroek     for (mt = ModeList; mt->name; mt++) {
1188*7348b5c5SDavid van Moolenbroek 	if (mt->help) {
1189*7348b5c5SDavid van Moolenbroek 	    if (*mt->help)
1190*7348b5c5SDavid van Moolenbroek 		printf("%-15s %s\n", mt->name, mt->help);
1191*7348b5c5SDavid van Moolenbroek 	    else
1192*7348b5c5SDavid van Moolenbroek 		printf("\n");
1193*7348b5c5SDavid van Moolenbroek 	}
1194*7348b5c5SDavid van Moolenbroek     }
1195*7348b5c5SDavid van Moolenbroek     return 0;
1196*7348b5c5SDavid van Moolenbroek }
1197*7348b5c5SDavid van Moolenbroek 
1198*7348b5c5SDavid van Moolenbroek #define	GETMODECMD(name) (struct modelist *) \
1199*7348b5c5SDavid van Moolenbroek 		genget(name, (char **) ModeList, sizeof(struct modelist))
1200*7348b5c5SDavid van Moolenbroek 
1201*7348b5c5SDavid van Moolenbroek static int
modecmd(int argc,char * argv[])1202*7348b5c5SDavid van Moolenbroek modecmd(int  argc, char *argv[])
1203*7348b5c5SDavid van Moolenbroek {
1204*7348b5c5SDavid van Moolenbroek     struct modelist *mt;
1205*7348b5c5SDavid van Moolenbroek 
1206*7348b5c5SDavid van Moolenbroek     if (argc != 2) {
1207*7348b5c5SDavid van Moolenbroek 	printf("'mode' command requires an argument\n");
1208*7348b5c5SDavid van Moolenbroek 	printf("'mode ?' for help.\n");
1209*7348b5c5SDavid van Moolenbroek     } else if ((mt = GETMODECMD(argv[1])) == 0) {
1210*7348b5c5SDavid van Moolenbroek 	fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]);
1211*7348b5c5SDavid van Moolenbroek     } else if (Ambiguous(mt)) {
1212*7348b5c5SDavid van Moolenbroek 	fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]);
1213*7348b5c5SDavid van Moolenbroek     } else if (mt->needconnect && !connected) {
1214*7348b5c5SDavid van Moolenbroek 	printf("?Need to be connected first.\n");
1215*7348b5c5SDavid van Moolenbroek 	printf("'mode ?' for help.\n");
1216*7348b5c5SDavid van Moolenbroek     } else if (mt->handler) {
1217*7348b5c5SDavid van Moolenbroek 	return (*mt->handler)(mt->arg1);
1218*7348b5c5SDavid van Moolenbroek     }
1219*7348b5c5SDavid van Moolenbroek     return 0;
1220*7348b5c5SDavid van Moolenbroek }
1221*7348b5c5SDavid van Moolenbroek 
1222*7348b5c5SDavid van Moolenbroek /*
1223*7348b5c5SDavid van Moolenbroek  * The following data structures and routines implement the
1224*7348b5c5SDavid van Moolenbroek  * "display" command.
1225*7348b5c5SDavid van Moolenbroek  */
1226*7348b5c5SDavid van Moolenbroek 
1227*7348b5c5SDavid van Moolenbroek static int
display(int argc,char * argv[])1228*7348b5c5SDavid van Moolenbroek display(int  argc, char *argv[])
1229*7348b5c5SDavid van Moolenbroek {
1230*7348b5c5SDavid van Moolenbroek     struct togglelist *tl;
1231*7348b5c5SDavid van Moolenbroek     struct setlist *sl;
1232*7348b5c5SDavid van Moolenbroek 
1233*7348b5c5SDavid van Moolenbroek #define	dotog(tl)	if (tl->variable && tl->actionexplanation) { \
1234*7348b5c5SDavid van Moolenbroek 			    if (*tl->variable) { \
1235*7348b5c5SDavid van Moolenbroek 				printf("will"); \
1236*7348b5c5SDavid van Moolenbroek 			    } else { \
1237*7348b5c5SDavid van Moolenbroek 				printf("won't"); \
1238*7348b5c5SDavid van Moolenbroek 			    } \
1239*7348b5c5SDavid van Moolenbroek 			    printf(" %s.\n", tl->actionexplanation); \
1240*7348b5c5SDavid van Moolenbroek 			}
1241*7348b5c5SDavid van Moolenbroek 
1242*7348b5c5SDavid van Moolenbroek #define	doset(sl)   if (sl->name && *sl->name != ' ') { \
1243*7348b5c5SDavid van Moolenbroek 			if (sl->handler == 0) \
1244*7348b5c5SDavid van Moolenbroek 			    printf("%-15s [%s]\n", sl->name, control(*sl->charp)); \
1245*7348b5c5SDavid van Moolenbroek 			else \
1246*7348b5c5SDavid van Moolenbroek 			    printf("%-15s \"%s\"\n", sl->name, (char *)sl->charp); \
1247*7348b5c5SDavid van Moolenbroek 		    }
1248*7348b5c5SDavid van Moolenbroek 
1249*7348b5c5SDavid van Moolenbroek     if (argc == 1) {
1250*7348b5c5SDavid van Moolenbroek 	for (tl = Togglelist; tl->name; tl++) {
1251*7348b5c5SDavid van Moolenbroek 	    dotog(tl);
1252*7348b5c5SDavid van Moolenbroek 	}
1253*7348b5c5SDavid van Moolenbroek 	printf("\n");
1254*7348b5c5SDavid van Moolenbroek 	for (sl = Setlist; sl->name; sl++) {
1255*7348b5c5SDavid van Moolenbroek 	    doset(sl);
1256*7348b5c5SDavid van Moolenbroek 	}
1257*7348b5c5SDavid van Moolenbroek     } else {
1258*7348b5c5SDavid van Moolenbroek 	int i;
1259*7348b5c5SDavid van Moolenbroek 
1260*7348b5c5SDavid van Moolenbroek 	for (i = 1; i < argc; i++) {
1261*7348b5c5SDavid van Moolenbroek 	    sl = getset(argv[i]);
1262*7348b5c5SDavid van Moolenbroek 	    tl = GETTOGGLE(argv[i]);
1263*7348b5c5SDavid van Moolenbroek 	    if (Ambiguous(sl) || Ambiguous(tl)) {
1264*7348b5c5SDavid van Moolenbroek 		printf("?Ambiguous argument '%s'.\n", argv[i]);
1265*7348b5c5SDavid van Moolenbroek 		return 0;
1266*7348b5c5SDavid van Moolenbroek 	    } else if (!sl && !tl) {
1267*7348b5c5SDavid van Moolenbroek 		printf("?Unknown argument '%s'.\n", argv[i]);
1268*7348b5c5SDavid van Moolenbroek 		return 0;
1269*7348b5c5SDavid van Moolenbroek 	    } else {
1270*7348b5c5SDavid van Moolenbroek 		if (tl) {
1271*7348b5c5SDavid van Moolenbroek 		    dotog(tl);
1272*7348b5c5SDavid van Moolenbroek 		}
1273*7348b5c5SDavid van Moolenbroek 		if (sl) {
1274*7348b5c5SDavid van Moolenbroek 		    doset(sl);
1275*7348b5c5SDavid van Moolenbroek 		}
1276*7348b5c5SDavid van Moolenbroek 	    }
1277*7348b5c5SDavid van Moolenbroek 	}
1278*7348b5c5SDavid van Moolenbroek     }
1279*7348b5c5SDavid van Moolenbroek /*@*/optionstatus();
1280*7348b5c5SDavid van Moolenbroek #ifdef	ENCRYPTION
1281*7348b5c5SDavid van Moolenbroek     EncryptStatus();
1282*7348b5c5SDavid van Moolenbroek #endif	/* ENCRYPTION */
1283*7348b5c5SDavid van Moolenbroek     return 1;
1284*7348b5c5SDavid van Moolenbroek #undef	doset
1285*7348b5c5SDavid van Moolenbroek #undef	dotog
1286*7348b5c5SDavid van Moolenbroek }
1287*7348b5c5SDavid van Moolenbroek 
1288*7348b5c5SDavid van Moolenbroek /*
1289*7348b5c5SDavid van Moolenbroek  * The following are the data structures, and many of the routines,
1290*7348b5c5SDavid van Moolenbroek  * relating to command processing.
1291*7348b5c5SDavid van Moolenbroek  */
1292*7348b5c5SDavid van Moolenbroek 
1293*7348b5c5SDavid van Moolenbroek /*
1294*7348b5c5SDavid van Moolenbroek  * Set the escape character.
1295*7348b5c5SDavid van Moolenbroek  */
1296*7348b5c5SDavid van Moolenbroek static int
setescape(int argc,char * argv[])1297*7348b5c5SDavid van Moolenbroek setescape(int argc, char *argv[])
1298*7348b5c5SDavid van Moolenbroek {
1299*7348b5c5SDavid van Moolenbroek 	char *arg;
1300*7348b5c5SDavid van Moolenbroek 	char buf[50];
1301*7348b5c5SDavid van Moolenbroek 
1302*7348b5c5SDavid van Moolenbroek 	printf(
1303*7348b5c5SDavid van Moolenbroek 	    "Deprecated usage - please use 'set escape%s%s' in the future.\n",
1304*7348b5c5SDavid van Moolenbroek 				(argc > 2)? " ":"", (argc > 2)? argv[1]: "");
1305*7348b5c5SDavid van Moolenbroek 	if (argc > 2)
1306*7348b5c5SDavid van Moolenbroek 		arg = argv[1];
1307*7348b5c5SDavid van Moolenbroek 	else {
1308*7348b5c5SDavid van Moolenbroek 		printf("new escape character: ");
1309*7348b5c5SDavid van Moolenbroek 		(void) fgets(buf, sizeof(buf), stdin);
1310*7348b5c5SDavid van Moolenbroek 		arg = buf;
1311*7348b5c5SDavid van Moolenbroek 	}
1312*7348b5c5SDavid van Moolenbroek 	if (arg[0] != '\0')
1313*7348b5c5SDavid van Moolenbroek 		escape = arg[0];
1314*7348b5c5SDavid van Moolenbroek 	if (!In3270) {
1315*7348b5c5SDavid van Moolenbroek 		printf("Escape character is '%s'.\n", control(escape));
1316*7348b5c5SDavid van Moolenbroek 	}
1317*7348b5c5SDavid van Moolenbroek 	(void) fflush(stdout);
1318*7348b5c5SDavid van Moolenbroek 	return 1;
1319*7348b5c5SDavid van Moolenbroek }
1320*7348b5c5SDavid van Moolenbroek 
1321*7348b5c5SDavid van Moolenbroek /*VARARGS*/
1322*7348b5c5SDavid van Moolenbroek static int
togcrmod(int argc,char * argv[])1323*7348b5c5SDavid van Moolenbroek togcrmod(int argc, char *argv[])
1324*7348b5c5SDavid van Moolenbroek {
1325*7348b5c5SDavid van Moolenbroek     crmod = !crmod;
1326*7348b5c5SDavid van Moolenbroek     printf("Deprecated usage - please use 'toggle crmod' in the future.\n");
1327*7348b5c5SDavid van Moolenbroek     printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't");
1328*7348b5c5SDavid van Moolenbroek     (void) fflush(stdout);
1329*7348b5c5SDavid van Moolenbroek     return 1;
1330*7348b5c5SDavid van Moolenbroek }
1331*7348b5c5SDavid van Moolenbroek 
1332*7348b5c5SDavid van Moolenbroek /*VARARGS*/
1333*7348b5c5SDavid van Moolenbroek int
suspend(int argc,char * argv[])1334*7348b5c5SDavid van Moolenbroek suspend(int argc, char *argv[])
1335*7348b5c5SDavid van Moolenbroek {
1336*7348b5c5SDavid van Moolenbroek     setcommandmode();
1337*7348b5c5SDavid van Moolenbroek     {
1338*7348b5c5SDavid van Moolenbroek 	long oldrows, oldcols, newrows, newcols, err;
1339*7348b5c5SDavid van Moolenbroek 
1340*7348b5c5SDavid van Moolenbroek 	err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0;
1341*7348b5c5SDavid van Moolenbroek 	(void) kill(0, SIGTSTP);
1342*7348b5c5SDavid van Moolenbroek 	/*
1343*7348b5c5SDavid van Moolenbroek 	 * If we didn't get the window size before the SUSPEND, but we
1344*7348b5c5SDavid van Moolenbroek 	 * can get them now (?), then send the NAWS to make sure that
1345*7348b5c5SDavid van Moolenbroek 	 * we are set up for the right window size.
1346*7348b5c5SDavid van Moolenbroek 	 */
1347*7348b5c5SDavid van Moolenbroek 	if (TerminalWindowSize(&newrows, &newcols) && connected &&
1348*7348b5c5SDavid van Moolenbroek 	    (err || ((oldrows != newrows) || (oldcols != newcols)))) {
1349*7348b5c5SDavid van Moolenbroek 		sendnaws();
1350*7348b5c5SDavid van Moolenbroek 	}
1351*7348b5c5SDavid van Moolenbroek     }
1352*7348b5c5SDavid van Moolenbroek     /* reget parameters in case they were changed */
1353*7348b5c5SDavid van Moolenbroek     TerminalSaveState();
1354*7348b5c5SDavid van Moolenbroek     setconnmode(0);
1355*7348b5c5SDavid van Moolenbroek     return 1;
1356*7348b5c5SDavid van Moolenbroek }
1357*7348b5c5SDavid van Moolenbroek 
1358*7348b5c5SDavid van Moolenbroek #ifndef TN3270
1359*7348b5c5SDavid van Moolenbroek /*ARGSUSED*/
1360*7348b5c5SDavid van Moolenbroek int
shell(int argc,char * argv[])1361*7348b5c5SDavid van Moolenbroek shell(int argc, char *argv[])
1362*7348b5c5SDavid van Moolenbroek {
1363*7348b5c5SDavid van Moolenbroek     long oldrows, oldcols, newrows, newcols;
1364*7348b5c5SDavid van Moolenbroek     long volatile err;	/* Avoid vfork clobbering */
1365*7348b5c5SDavid van Moolenbroek 
1366*7348b5c5SDavid van Moolenbroek     setcommandmode();
1367*7348b5c5SDavid van Moolenbroek 
1368*7348b5c5SDavid van Moolenbroek     err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0;
1369*7348b5c5SDavid van Moolenbroek     switch(vfork()) {
1370*7348b5c5SDavid van Moolenbroek     case -1:
1371*7348b5c5SDavid van Moolenbroek 	perror("Fork failed");
1372*7348b5c5SDavid van Moolenbroek 	break;
1373*7348b5c5SDavid van Moolenbroek 
1374*7348b5c5SDavid van Moolenbroek     case 0:
1375*7348b5c5SDavid van Moolenbroek 	{
1376*7348b5c5SDavid van Moolenbroek 	    /*
1377*7348b5c5SDavid van Moolenbroek 	     * Fire up the shell in the child.
1378*7348b5c5SDavid van Moolenbroek 	     */
1379*7348b5c5SDavid van Moolenbroek 	    const char *shellp, *shellname;
1380*7348b5c5SDavid van Moolenbroek 
1381*7348b5c5SDavid van Moolenbroek 	    shellp = getenv("SHELL");
1382*7348b5c5SDavid van Moolenbroek 	    if (shellp == NULL)
1383*7348b5c5SDavid van Moolenbroek 		shellp = "/bin/sh";
1384*7348b5c5SDavid van Moolenbroek 	    if ((shellname = strrchr(shellp, '/')) == 0)
1385*7348b5c5SDavid van Moolenbroek 		shellname = shellp;
1386*7348b5c5SDavid van Moolenbroek 	    else
1387*7348b5c5SDavid van Moolenbroek 		shellname++;
1388*7348b5c5SDavid van Moolenbroek 	    if (argc > 1)
1389*7348b5c5SDavid van Moolenbroek 		execl(shellp, shellname, "-c", &saveline[1], NULL);
1390*7348b5c5SDavid van Moolenbroek 	    else
1391*7348b5c5SDavid van Moolenbroek 		execl(shellp, shellname, NULL);
1392*7348b5c5SDavid van Moolenbroek 	    perror("execl");
1393*7348b5c5SDavid van Moolenbroek 	    _exit(1);
1394*7348b5c5SDavid van Moolenbroek 	}
1395*7348b5c5SDavid van Moolenbroek     default:
1396*7348b5c5SDavid van Moolenbroek 	    (void)wait((int *)0);	/* Wait for the shell to complete */
1397*7348b5c5SDavid van Moolenbroek 
1398*7348b5c5SDavid van Moolenbroek 	    if (TerminalWindowSize(&newrows, &newcols) && connected &&
1399*7348b5c5SDavid van Moolenbroek 		(err || ((oldrows != newrows) || (oldcols != newcols)))) {
1400*7348b5c5SDavid van Moolenbroek 		    sendnaws();
1401*7348b5c5SDavid van Moolenbroek 	    }
1402*7348b5c5SDavid van Moolenbroek 	    break;
1403*7348b5c5SDavid van Moolenbroek     }
1404*7348b5c5SDavid van Moolenbroek     return 1;
1405*7348b5c5SDavid van Moolenbroek }
1406*7348b5c5SDavid van Moolenbroek #endif	/* !defined(TN3270) */
1407*7348b5c5SDavid van Moolenbroek 
1408*7348b5c5SDavid van Moolenbroek /*VARARGS*/
1409*7348b5c5SDavid van Moolenbroek static int
bye(int argc,char * argv[])1410*7348b5c5SDavid van Moolenbroek bye(int  argc, char *argv[])
1411*7348b5c5SDavid van Moolenbroek {
1412*7348b5c5SDavid van Moolenbroek     extern int resettermname;
1413*7348b5c5SDavid van Moolenbroek 
1414*7348b5c5SDavid van Moolenbroek     if (connected) {
1415*7348b5c5SDavid van Moolenbroek 	(void) shutdown(net, 2);
1416*7348b5c5SDavid van Moolenbroek 	printf("Connection closed.\n");
1417*7348b5c5SDavid van Moolenbroek 	(void) NetClose(net);
1418*7348b5c5SDavid van Moolenbroek 	connected = 0;
1419*7348b5c5SDavid van Moolenbroek 	resettermname = 1;
1420*7348b5c5SDavid van Moolenbroek #if	defined(AUTHENTICATION) || defined(ENCRYPTION)
1421*7348b5c5SDavid van Moolenbroek 	auth_encrypt_connect(connected);
1422*7348b5c5SDavid van Moolenbroek #endif	/* defined(AUTHENTICATION) */
1423*7348b5c5SDavid van Moolenbroek 	/* reset options */
1424*7348b5c5SDavid van Moolenbroek 	tninit();
1425*7348b5c5SDavid van Moolenbroek #ifdef TN3270
1426*7348b5c5SDavid van Moolenbroek 	SetIn3270();		/* Get out of 3270 mode */
1427*7348b5c5SDavid van Moolenbroek #endif	/* defined(TN3270) */
1428*7348b5c5SDavid van Moolenbroek     }
1429*7348b5c5SDavid van Moolenbroek     if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) {
1430*7348b5c5SDavid van Moolenbroek 	longjmp(toplevel, 1);
1431*7348b5c5SDavid van Moolenbroek 	/* NOTREACHED */
1432*7348b5c5SDavid van Moolenbroek     }
1433*7348b5c5SDavid van Moolenbroek     return 1;			/* Keep lint, etc., happy */
1434*7348b5c5SDavid van Moolenbroek }
1435*7348b5c5SDavid van Moolenbroek 
1436*7348b5c5SDavid van Moolenbroek /*VARARGS*/
1437*7348b5c5SDavid van Moolenbroek int
quit(int argc,char * argv[])1438*7348b5c5SDavid van Moolenbroek quit(int argc, char *argv[])
1439*7348b5c5SDavid van Moolenbroek {
1440*7348b5c5SDavid van Moolenbroek 	(void) call(bye, "bye", "fromquit", 0);
1441*7348b5c5SDavid van Moolenbroek 	Exit(0);
1442*7348b5c5SDavid van Moolenbroek 	/*NOTREACHED*/
1443*7348b5c5SDavid van Moolenbroek }
1444*7348b5c5SDavid van Moolenbroek 
1445*7348b5c5SDavid van Moolenbroek /*VARARGS*/
1446*7348b5c5SDavid van Moolenbroek int
logout(int argc,char * argv[])1447*7348b5c5SDavid van Moolenbroek logout(int argc, char *argv[])
1448*7348b5c5SDavid van Moolenbroek {
1449*7348b5c5SDavid van Moolenbroek 	send_do(TELOPT_LOGOUT, 1);
1450*7348b5c5SDavid van Moolenbroek 	(void) netflush();
1451*7348b5c5SDavid van Moolenbroek 	return 1;
1452*7348b5c5SDavid van Moolenbroek }
1453*7348b5c5SDavid van Moolenbroek 
1454*7348b5c5SDavid van Moolenbroek 
1455*7348b5c5SDavid van Moolenbroek /*
1456*7348b5c5SDavid van Moolenbroek  * The SLC command.
1457*7348b5c5SDavid van Moolenbroek  */
1458*7348b5c5SDavid van Moolenbroek 
1459*7348b5c5SDavid van Moolenbroek struct slclist {
1460*7348b5c5SDavid van Moolenbroek 	const char	*name;
1461*7348b5c5SDavid van Moolenbroek 	const char	*help;
1462*7348b5c5SDavid van Moolenbroek 	void	(*handler)(int);
1463*7348b5c5SDavid van Moolenbroek 	int	arg;
1464*7348b5c5SDavid van Moolenbroek };
1465*7348b5c5SDavid van Moolenbroek 
1466*7348b5c5SDavid van Moolenbroek struct slclist SlcList[] = {
1467*7348b5c5SDavid van Moolenbroek     { "export",	"Use local special character definitions",
1468*7348b5c5SDavid van Moolenbroek 						slc_mode_export,	0 },
1469*7348b5c5SDavid van Moolenbroek     { "import",	"Use remote special character definitions",
1470*7348b5c5SDavid van Moolenbroek 						slc_mode_import,	1 },
1471*7348b5c5SDavid van Moolenbroek     { "check",	"Verify remote special character definitions",
1472*7348b5c5SDavid van Moolenbroek 						slc_mode_import,	0 },
1473*7348b5c5SDavid van Moolenbroek     { "help",	0,				slc_help,		0 },
1474*7348b5c5SDavid van Moolenbroek     { "?",	"Print help information",	slc_help,		0 },
1475*7348b5c5SDavid van Moolenbroek     { .name = 0 },
1476*7348b5c5SDavid van Moolenbroek };
1477*7348b5c5SDavid van Moolenbroek 
1478*7348b5c5SDavid van Moolenbroek static void
slc_help(int n)1479*7348b5c5SDavid van Moolenbroek slc_help(int n)
1480*7348b5c5SDavid van Moolenbroek {
1481*7348b5c5SDavid van Moolenbroek     struct slclist *c;
1482*7348b5c5SDavid van Moolenbroek 
1483*7348b5c5SDavid van Moolenbroek     for (c = SlcList; c->name; c++) {
1484*7348b5c5SDavid van Moolenbroek 	if (c->help) {
1485*7348b5c5SDavid van Moolenbroek 	    if (*c->help)
1486*7348b5c5SDavid van Moolenbroek 		printf("%-15s %s\n", c->name, c->help);
1487*7348b5c5SDavid van Moolenbroek 	    else
1488*7348b5c5SDavid van Moolenbroek 		printf("\n");
1489*7348b5c5SDavid van Moolenbroek 	}
1490*7348b5c5SDavid van Moolenbroek     }
1491*7348b5c5SDavid van Moolenbroek }
1492*7348b5c5SDavid van Moolenbroek 
1493*7348b5c5SDavid van Moolenbroek static struct slclist *
getslc(char * name)1494*7348b5c5SDavid van Moolenbroek getslc(char *name)
1495*7348b5c5SDavid van Moolenbroek {
1496*7348b5c5SDavid van Moolenbroek     return (struct slclist *)
1497*7348b5c5SDavid van Moolenbroek 		genget(name, (char **) SlcList, sizeof(struct slclist));
1498*7348b5c5SDavid van Moolenbroek }
1499*7348b5c5SDavid van Moolenbroek 
1500*7348b5c5SDavid van Moolenbroek static int
slccmd(int argc,char * argv[])1501*7348b5c5SDavid van Moolenbroek slccmd(int  argc, char *argv[])
1502*7348b5c5SDavid van Moolenbroek {
1503*7348b5c5SDavid van Moolenbroek     struct slclist *c;
1504*7348b5c5SDavid van Moolenbroek 
1505*7348b5c5SDavid van Moolenbroek     if (argc != 2) {
1506*7348b5c5SDavid van Moolenbroek 	fprintf(stderr,
1507*7348b5c5SDavid van Moolenbroek 	    "Need an argument to 'slc' command.  'slc ?' for help.\n");
1508*7348b5c5SDavid van Moolenbroek 	return 0;
1509*7348b5c5SDavid van Moolenbroek     }
1510*7348b5c5SDavid van Moolenbroek     c = getslc(argv[1]);
1511*7348b5c5SDavid van Moolenbroek     if (c == 0) {
1512*7348b5c5SDavid van Moolenbroek 	fprintf(stderr, "'%s': unknown argument ('slc ?' for help).\n",
1513*7348b5c5SDavid van Moolenbroek     				argv[1]);
1514*7348b5c5SDavid van Moolenbroek 	return 0;
1515*7348b5c5SDavid van Moolenbroek     }
1516*7348b5c5SDavid van Moolenbroek     if (Ambiguous(c)) {
1517*7348b5c5SDavid van Moolenbroek 	fprintf(stderr, "'%s': ambiguous argument ('slc ?' for help).\n",
1518*7348b5c5SDavid van Moolenbroek     				argv[1]);
1519*7348b5c5SDavid van Moolenbroek 	return 0;
1520*7348b5c5SDavid van Moolenbroek     }
1521*7348b5c5SDavid van Moolenbroek     (*c->handler)(c->arg);
1522*7348b5c5SDavid van Moolenbroek     slcstate();
1523*7348b5c5SDavid van Moolenbroek     return 1;
1524*7348b5c5SDavid van Moolenbroek }
1525*7348b5c5SDavid van Moolenbroek 
1526*7348b5c5SDavid van Moolenbroek /*
1527*7348b5c5SDavid van Moolenbroek  * The ENVIRON command.
1528*7348b5c5SDavid van Moolenbroek  */
1529*7348b5c5SDavid van Moolenbroek 
1530*7348b5c5SDavid van Moolenbroek struct envlist {
1531*7348b5c5SDavid van Moolenbroek 	const char	*name;
1532*7348b5c5SDavid van Moolenbroek 	const char	*help;
1533*7348b5c5SDavid van Moolenbroek 	struct env_lst *(*handler)(const unsigned char *, unsigned char *);
1534*7348b5c5SDavid van Moolenbroek 	int	narg;
1535*7348b5c5SDavid van Moolenbroek };
1536*7348b5c5SDavid van Moolenbroek 
1537*7348b5c5SDavid van Moolenbroek struct envlist EnvList[] = {
1538*7348b5c5SDavid van Moolenbroek     { "define",	"Define an environment variable",
1539*7348b5c5SDavid van Moolenbroek 						env_define,	2 },
1540*7348b5c5SDavid van Moolenbroek     { "undefine", "Undefine an environment variable",
1541*7348b5c5SDavid van Moolenbroek 						env_undefine,	1 },
1542*7348b5c5SDavid van Moolenbroek     { "export",	"Mark an environment variable for automatic export",
1543*7348b5c5SDavid van Moolenbroek 						env_export,	1 },
1544*7348b5c5SDavid van Moolenbroek     { "unexport", "Don't mark an environment variable for automatic export",
1545*7348b5c5SDavid van Moolenbroek 						env_unexport,	1 },
1546*7348b5c5SDavid van Moolenbroek     { "send",	"Send an environment variable", env_send,	1 },
1547*7348b5c5SDavid van Moolenbroek     { "list",	"List the current environment variables",
1548*7348b5c5SDavid van Moolenbroek 						env_list,	0 },
1549*7348b5c5SDavid van Moolenbroek #if defined(OLD_ENVIRON) && defined(ENV_HACK)
1550*7348b5c5SDavid van Moolenbroek     { "varval", "Reverse VAR and VALUE (auto, right, wrong, status)",
1551*7348b5c5SDavid van Moolenbroek 						env_varval,    1 },
1552*7348b5c5SDavid van Moolenbroek #endif
1553*7348b5c5SDavid van Moolenbroek     { "help",	0,				env_help,		0 },
1554*7348b5c5SDavid van Moolenbroek     { "?",	"Print help information",	env_help,		0 },
1555*7348b5c5SDavid van Moolenbroek     { .name = 0 },
1556*7348b5c5SDavid van Moolenbroek };
1557*7348b5c5SDavid van Moolenbroek 
1558*7348b5c5SDavid van Moolenbroek static struct env_lst *
env_help(const unsigned char * us1,unsigned char * us2)1559*7348b5c5SDavid van Moolenbroek env_help(const unsigned char *us1, unsigned char *us2)
1560*7348b5c5SDavid van Moolenbroek {
1561*7348b5c5SDavid van Moolenbroek     struct envlist *c;
1562*7348b5c5SDavid van Moolenbroek 
1563*7348b5c5SDavid van Moolenbroek     for (c = EnvList; c->name; c++) {
1564*7348b5c5SDavid van Moolenbroek 	if (c->help) {
1565*7348b5c5SDavid van Moolenbroek 	    if (*c->help)
1566*7348b5c5SDavid van Moolenbroek 		printf("%-15s %s\n", c->name, c->help);
1567*7348b5c5SDavid van Moolenbroek 	    else
1568*7348b5c5SDavid van Moolenbroek 		printf("\n");
1569*7348b5c5SDavid van Moolenbroek 	}
1570*7348b5c5SDavid van Moolenbroek     }
1571*7348b5c5SDavid van Moolenbroek     return NULL;
1572*7348b5c5SDavid van Moolenbroek }
1573*7348b5c5SDavid van Moolenbroek 
1574*7348b5c5SDavid van Moolenbroek static struct envlist *
getenvcmd(char * name)1575*7348b5c5SDavid van Moolenbroek getenvcmd(char *name)
1576*7348b5c5SDavid van Moolenbroek {
1577*7348b5c5SDavid van Moolenbroek     return (struct envlist *)
1578*7348b5c5SDavid van Moolenbroek 		genget(name, (char **) EnvList, sizeof(struct envlist));
1579*7348b5c5SDavid van Moolenbroek }
1580*7348b5c5SDavid van Moolenbroek 
1581*7348b5c5SDavid van Moolenbroek int
env_cmd(int argc,char * argv[])1582*7348b5c5SDavid van Moolenbroek env_cmd(int  argc, char *argv[])
1583*7348b5c5SDavid van Moolenbroek {
1584*7348b5c5SDavid van Moolenbroek     struct envlist *c;
1585*7348b5c5SDavid van Moolenbroek 
1586*7348b5c5SDavid van Moolenbroek     if (argc < 2) {
1587*7348b5c5SDavid van Moolenbroek 	fprintf(stderr,
1588*7348b5c5SDavid van Moolenbroek 	    "Need an argument to 'environ' command.  'environ ?' for help.\n");
1589*7348b5c5SDavid van Moolenbroek 	return 0;
1590*7348b5c5SDavid van Moolenbroek     }
1591*7348b5c5SDavid van Moolenbroek     c = getenvcmd(argv[1]);
1592*7348b5c5SDavid van Moolenbroek     if (c == 0) {
1593*7348b5c5SDavid van Moolenbroek 	fprintf(stderr, "'%s': unknown argument ('environ ?' for help).\n",
1594*7348b5c5SDavid van Moolenbroek     				argv[1]);
1595*7348b5c5SDavid van Moolenbroek 	return 0;
1596*7348b5c5SDavid van Moolenbroek     }
1597*7348b5c5SDavid van Moolenbroek     if (Ambiguous(c)) {
1598*7348b5c5SDavid van Moolenbroek 	fprintf(stderr, "'%s': ambiguous argument ('environ ?' for help).\n",
1599*7348b5c5SDavid van Moolenbroek     				argv[1]);
1600*7348b5c5SDavid van Moolenbroek 	return 0;
1601*7348b5c5SDavid van Moolenbroek     }
1602*7348b5c5SDavid van Moolenbroek     if (c->narg + 2 != argc) {
1603*7348b5c5SDavid van Moolenbroek 	fprintf(stderr,
1604*7348b5c5SDavid van Moolenbroek 	    "Need %s%d argument%s to 'environ %s' command.  'environ ?' for help.\n",
1605*7348b5c5SDavid van Moolenbroek 		c->narg < argc + 2 ? "only " : "",
1606*7348b5c5SDavid van Moolenbroek 		c->narg, c->narg == 1 ? "" : "s", c->name);
1607*7348b5c5SDavid van Moolenbroek 	return 0;
1608*7348b5c5SDavid van Moolenbroek     }
1609*7348b5c5SDavid van Moolenbroek     (*c->handler)(argv[2], argv[3]);
1610*7348b5c5SDavid van Moolenbroek     return 1;
1611*7348b5c5SDavid van Moolenbroek }
1612*7348b5c5SDavid van Moolenbroek 
1613*7348b5c5SDavid van Moolenbroek struct env_lst {
1614*7348b5c5SDavid van Moolenbroek 	struct env_lst *next;	/* pointer to next structure */
1615*7348b5c5SDavid van Moolenbroek 	struct env_lst *prev;	/* pointer to previous structure */
1616*7348b5c5SDavid van Moolenbroek 	unsigned char *var;	/* pointer to variable name */
1617*7348b5c5SDavid van Moolenbroek 	unsigned char *value;	/* pointer to variable value */
1618*7348b5c5SDavid van Moolenbroek 	int export;		/* 1 -> export with default list of variables */
1619*7348b5c5SDavid van Moolenbroek 	int welldefined;	/* A well defined variable */
1620*7348b5c5SDavid van Moolenbroek };
1621*7348b5c5SDavid van Moolenbroek 
1622*7348b5c5SDavid van Moolenbroek struct env_lst envlisthead;
1623*7348b5c5SDavid van Moolenbroek 
1624*7348b5c5SDavid van Moolenbroek struct env_lst *
env_find(const unsigned char * var)1625*7348b5c5SDavid van Moolenbroek env_find(const unsigned char *var)
1626*7348b5c5SDavid van Moolenbroek {
1627*7348b5c5SDavid van Moolenbroek 	struct env_lst *ep;
1628*7348b5c5SDavid van Moolenbroek 
1629*7348b5c5SDavid van Moolenbroek 	for (ep = envlisthead.next; ep; ep = ep->next) {
1630*7348b5c5SDavid van Moolenbroek 		if (strcmp((const char *)ep->var, (const char *)var) == 0)
1631*7348b5c5SDavid van Moolenbroek 			return(ep);
1632*7348b5c5SDavid van Moolenbroek 	}
1633*7348b5c5SDavid van Moolenbroek 	return(NULL);
1634*7348b5c5SDavid van Moolenbroek }
1635*7348b5c5SDavid van Moolenbroek 
1636*7348b5c5SDavid van Moolenbroek void
env_init(void)1637*7348b5c5SDavid van Moolenbroek env_init(void)
1638*7348b5c5SDavid van Moolenbroek {
1639*7348b5c5SDavid van Moolenbroek 	extern char **environ;
1640*7348b5c5SDavid van Moolenbroek 	char **epp, *cp;
1641*7348b5c5SDavid van Moolenbroek 	struct env_lst *ep;
1642*7348b5c5SDavid van Moolenbroek 
1643*7348b5c5SDavid van Moolenbroek 	for (epp = environ; *epp; epp++) {
1644*7348b5c5SDavid van Moolenbroek 		if ((cp = strchr(*epp, '=')) != NULL) {
1645*7348b5c5SDavid van Moolenbroek 			*cp = '\0';
1646*7348b5c5SDavid van Moolenbroek 			ep = env_define((unsigned char *)*epp,
1647*7348b5c5SDavid van Moolenbroek 					(unsigned char *)cp+1);
1648*7348b5c5SDavid van Moolenbroek 			ep->export = 0;
1649*7348b5c5SDavid van Moolenbroek 			*cp = '=';
1650*7348b5c5SDavid van Moolenbroek 		}
1651*7348b5c5SDavid van Moolenbroek 	}
1652*7348b5c5SDavid van Moolenbroek 	/*
1653*7348b5c5SDavid van Moolenbroek 	 * Special case for DISPLAY variable.  If it is ":0.0" or
1654*7348b5c5SDavid van Moolenbroek 	 * "unix:0.0", we have to get rid of "unix" and insert our
1655*7348b5c5SDavid van Moolenbroek 	 * hostname.
1656*7348b5c5SDavid van Moolenbroek 	 */
1657*7348b5c5SDavid van Moolenbroek 	if ((ep = env_find("DISPLAY"))
1658*7348b5c5SDavid van Moolenbroek 	    && ((*ep->value == ':')
1659*7348b5c5SDavid van Moolenbroek 		|| (strncmp((char *)ep->value, "unix:", 5) == 0))) {
1660*7348b5c5SDavid van Moolenbroek 		char hbuf[MAXHOSTNAMELEN + 1];
1661*7348b5c5SDavid van Moolenbroek 		char *cp2 = strchr((char *)ep->value, ':');
1662*7348b5c5SDavid van Moolenbroek 
1663*7348b5c5SDavid van Moolenbroek 		gethostname(hbuf, sizeof hbuf);
1664*7348b5c5SDavid van Moolenbroek 		hbuf[sizeof(hbuf) - 1] = '\0';
1665*7348b5c5SDavid van Moolenbroek 		cp = (char *)malloc(strlen(hbuf) + strlen(cp2) + 1);
1666*7348b5c5SDavid van Moolenbroek 		sprintf((char *)cp, "%s%s", hbuf, cp2);
1667*7348b5c5SDavid van Moolenbroek 		free(ep->value);
1668*7348b5c5SDavid van Moolenbroek 		ep->value = (unsigned char *)cp;
1669*7348b5c5SDavid van Moolenbroek 	}
1670*7348b5c5SDavid van Moolenbroek 	/*
1671*7348b5c5SDavid van Moolenbroek 	 * If USER is not defined, but LOGNAME is, then add
1672*7348b5c5SDavid van Moolenbroek 	 * USER with the value from LOGNAME.  By default, we
1673*7348b5c5SDavid van Moolenbroek 	 * don't export the USER variable.
1674*7348b5c5SDavid van Moolenbroek 	 */
1675*7348b5c5SDavid van Moolenbroek 	if ((env_find("USER") == NULL) && (ep = env_find("LOGNAME"))) {
1676*7348b5c5SDavid van Moolenbroek 		env_define((const unsigned char *)"USER", ep->value);
1677*7348b5c5SDavid van Moolenbroek 		env_unexport((const unsigned char *)"USER", NULL);
1678*7348b5c5SDavid van Moolenbroek 	}
1679*7348b5c5SDavid van Moolenbroek 	env_export((const unsigned char *)"DISPLAY", NULL);
1680*7348b5c5SDavid van Moolenbroek 	env_export((const unsigned char *)"PRINTER", NULL);
1681*7348b5c5SDavid van Moolenbroek }
1682*7348b5c5SDavid van Moolenbroek 
1683*7348b5c5SDavid van Moolenbroek struct env_lst *
env_define(const unsigned char * var,unsigned char * value)1684*7348b5c5SDavid van Moolenbroek env_define(const unsigned char *var, unsigned char *value)
1685*7348b5c5SDavid van Moolenbroek {
1686*7348b5c5SDavid van Moolenbroek 	struct env_lst *ep;
1687*7348b5c5SDavid van Moolenbroek 
1688*7348b5c5SDavid van Moolenbroek 	if ((ep = env_find(var)) != NULL) {
1689*7348b5c5SDavid van Moolenbroek 		if (ep->var)
1690*7348b5c5SDavid van Moolenbroek 			free(ep->var);
1691*7348b5c5SDavid van Moolenbroek 		if (ep->value)
1692*7348b5c5SDavid van Moolenbroek 			free(ep->value);
1693*7348b5c5SDavid van Moolenbroek 	} else {
1694*7348b5c5SDavid van Moolenbroek 		ep = (struct env_lst *)malloc(sizeof(struct env_lst));
1695*7348b5c5SDavid van Moolenbroek 		ep->next = envlisthead.next;
1696*7348b5c5SDavid van Moolenbroek 		envlisthead.next = ep;
1697*7348b5c5SDavid van Moolenbroek 		ep->prev = &envlisthead;
1698*7348b5c5SDavid van Moolenbroek 		if (ep->next)
1699*7348b5c5SDavid van Moolenbroek 			ep->next->prev = ep;
1700*7348b5c5SDavid van Moolenbroek 	}
1701*7348b5c5SDavid van Moolenbroek 	ep->welldefined = opt_welldefined(var);
1702*7348b5c5SDavid van Moolenbroek 	ep->export = 1;
1703*7348b5c5SDavid van Moolenbroek 	ep->var = (unsigned char *)strdup((const char *)var);
1704*7348b5c5SDavid van Moolenbroek 	ep->value = (unsigned char *)strdup((const char *)value);
1705*7348b5c5SDavid van Moolenbroek 	return(ep);
1706*7348b5c5SDavid van Moolenbroek }
1707*7348b5c5SDavid van Moolenbroek 
1708*7348b5c5SDavid van Moolenbroek struct env_lst *
env_undefine(const unsigned char * var,unsigned char * d)1709*7348b5c5SDavid van Moolenbroek env_undefine(const unsigned char *var, unsigned char *d)
1710*7348b5c5SDavid van Moolenbroek {
1711*7348b5c5SDavid van Moolenbroek 	struct env_lst *ep;
1712*7348b5c5SDavid van Moolenbroek 
1713*7348b5c5SDavid van Moolenbroek 	if ((ep = env_find(var)) != NULL) {
1714*7348b5c5SDavid van Moolenbroek 		ep->prev->next = ep->next;
1715*7348b5c5SDavid van Moolenbroek 		if (ep->next)
1716*7348b5c5SDavid van Moolenbroek 			ep->next->prev = ep->prev;
1717*7348b5c5SDavid van Moolenbroek 		if (ep->var)
1718*7348b5c5SDavid van Moolenbroek 			free(ep->var);
1719*7348b5c5SDavid van Moolenbroek 		if (ep->value)
1720*7348b5c5SDavid van Moolenbroek 			free(ep->value);
1721*7348b5c5SDavid van Moolenbroek 		free(ep);
1722*7348b5c5SDavid van Moolenbroek 	}
1723*7348b5c5SDavid van Moolenbroek 	return NULL;
1724*7348b5c5SDavid van Moolenbroek }
1725*7348b5c5SDavid van Moolenbroek 
1726*7348b5c5SDavid van Moolenbroek struct env_lst *
env_export(const unsigned char * var,unsigned char * d)1727*7348b5c5SDavid van Moolenbroek env_export(const unsigned char *var, unsigned char *d)
1728*7348b5c5SDavid van Moolenbroek {
1729*7348b5c5SDavid van Moolenbroek 	struct env_lst *ep;
1730*7348b5c5SDavid van Moolenbroek 
1731*7348b5c5SDavid van Moolenbroek 	if ((ep = env_find(var)) != NULL)
1732*7348b5c5SDavid van Moolenbroek 		ep->export = 1;
1733*7348b5c5SDavid van Moolenbroek 	return NULL;
1734*7348b5c5SDavid van Moolenbroek }
1735*7348b5c5SDavid van Moolenbroek 
1736*7348b5c5SDavid van Moolenbroek struct env_lst *
env_unexport(const unsigned char * var,unsigned char * d)1737*7348b5c5SDavid van Moolenbroek env_unexport(const unsigned char *var, unsigned char *d)
1738*7348b5c5SDavid van Moolenbroek {
1739*7348b5c5SDavid van Moolenbroek 	struct env_lst *ep;
1740*7348b5c5SDavid van Moolenbroek 
1741*7348b5c5SDavid van Moolenbroek 	if ((ep = env_find(var)) != NULL)
1742*7348b5c5SDavid van Moolenbroek 		ep->export = 0;
1743*7348b5c5SDavid van Moolenbroek 	return NULL;
1744*7348b5c5SDavid van Moolenbroek }
1745*7348b5c5SDavid van Moolenbroek 
1746*7348b5c5SDavid van Moolenbroek struct env_lst *
env_send(const unsigned char * var,unsigned char * d)1747*7348b5c5SDavid van Moolenbroek env_send(const unsigned char *var, unsigned char *d)
1748*7348b5c5SDavid van Moolenbroek {
1749*7348b5c5SDavid van Moolenbroek 	struct env_lst *ep;
1750*7348b5c5SDavid van Moolenbroek 
1751*7348b5c5SDavid van Moolenbroek 	if (my_state_is_wont(TELOPT_NEW_ENVIRON)
1752*7348b5c5SDavid van Moolenbroek #ifdef	OLD_ENVIRON
1753*7348b5c5SDavid van Moolenbroek 	    && my_state_is_wont(TELOPT_OLD_ENVIRON)
1754*7348b5c5SDavid van Moolenbroek #endif
1755*7348b5c5SDavid van Moolenbroek 		) {
1756*7348b5c5SDavid van Moolenbroek 		fprintf(stderr,
1757*7348b5c5SDavid van Moolenbroek 		    "Cannot send '%s': Telnet ENVIRON option not enabled\n",
1758*7348b5c5SDavid van Moolenbroek 									var);
1759*7348b5c5SDavid van Moolenbroek 		return NULL;
1760*7348b5c5SDavid van Moolenbroek 	}
1761*7348b5c5SDavid van Moolenbroek 	ep = env_find(var);
1762*7348b5c5SDavid van Moolenbroek 	if (ep == 0) {
1763*7348b5c5SDavid van Moolenbroek 		fprintf(stderr, "Cannot send '%s': variable not defined\n",
1764*7348b5c5SDavid van Moolenbroek 									var);
1765*7348b5c5SDavid van Moolenbroek 		return NULL;
1766*7348b5c5SDavid van Moolenbroek 	}
1767*7348b5c5SDavid van Moolenbroek 	env_opt_start_info();
1768*7348b5c5SDavid van Moolenbroek 	env_opt_add(ep->var);
1769*7348b5c5SDavid van Moolenbroek 	env_opt_end(0);
1770*7348b5c5SDavid van Moolenbroek 	return NULL;
1771*7348b5c5SDavid van Moolenbroek }
1772*7348b5c5SDavid van Moolenbroek 
1773*7348b5c5SDavid van Moolenbroek struct env_lst *
env_list(const unsigned char * d1,unsigned char * d2)1774*7348b5c5SDavid van Moolenbroek env_list(const unsigned char *d1, unsigned char *d2)
1775*7348b5c5SDavid van Moolenbroek {
1776*7348b5c5SDavid van Moolenbroek 	struct env_lst *ep;
1777*7348b5c5SDavid van Moolenbroek 
1778*7348b5c5SDavid van Moolenbroek 	for (ep = envlisthead.next; ep; ep = ep->next) {
1779*7348b5c5SDavid van Moolenbroek 		printf("%c %-20s %s\n", ep->export ? '*' : ' ',
1780*7348b5c5SDavid van Moolenbroek 					ep->var, ep->value);
1781*7348b5c5SDavid van Moolenbroek 	}
1782*7348b5c5SDavid van Moolenbroek 	return NULL;
1783*7348b5c5SDavid van Moolenbroek }
1784*7348b5c5SDavid van Moolenbroek 
1785*7348b5c5SDavid van Moolenbroek unsigned char *
env_default(int init,int welldefined)1786*7348b5c5SDavid van Moolenbroek env_default(int init, int welldefined)
1787*7348b5c5SDavid van Moolenbroek {
1788*7348b5c5SDavid van Moolenbroek 	static struct env_lst *nep = NULL;
1789*7348b5c5SDavid van Moolenbroek 
1790*7348b5c5SDavid van Moolenbroek 	if (init) {
1791*7348b5c5SDavid van Moolenbroek 		nep = &envlisthead;
1792*7348b5c5SDavid van Moolenbroek 		return NULL;
1793*7348b5c5SDavid van Moolenbroek 	}
1794*7348b5c5SDavid van Moolenbroek 	if (nep) {
1795*7348b5c5SDavid van Moolenbroek 		while ((nep = nep->next) != NULL) {
1796*7348b5c5SDavid van Moolenbroek 			if (nep->export && (nep->welldefined == welldefined))
1797*7348b5c5SDavid van Moolenbroek 				return(nep->var);
1798*7348b5c5SDavid van Moolenbroek 		}
1799*7348b5c5SDavid van Moolenbroek 	}
1800*7348b5c5SDavid van Moolenbroek 	return(NULL);
1801*7348b5c5SDavid van Moolenbroek }
1802*7348b5c5SDavid van Moolenbroek 
1803*7348b5c5SDavid van Moolenbroek unsigned char *
env_getvalue(const unsigned char * var)1804*7348b5c5SDavid van Moolenbroek env_getvalue(const unsigned char *var)
1805*7348b5c5SDavid van Moolenbroek {
1806*7348b5c5SDavid van Moolenbroek 	struct env_lst *ep;
1807*7348b5c5SDavid van Moolenbroek 
1808*7348b5c5SDavid van Moolenbroek 	if ((ep = env_find(var)) != NULL)
1809*7348b5c5SDavid van Moolenbroek 		return(ep->value);
1810*7348b5c5SDavid van Moolenbroek 	return(NULL);
1811*7348b5c5SDavid van Moolenbroek }
1812*7348b5c5SDavid van Moolenbroek 
1813*7348b5c5SDavid van Moolenbroek #if defined(OLD_ENVIRON) && defined(ENV_HACK)
1814*7348b5c5SDavid van Moolenbroek void
env_varval(const unsigned char * what)1815*7348b5c5SDavid van Moolenbroek env_varval(const unsigned char *what)
1816*7348b5c5SDavid van Moolenbroek {
1817*7348b5c5SDavid van Moolenbroek 	extern int old_env_var, old_env_value, env_auto;
1818*7348b5c5SDavid van Moolenbroek 	int len = strlen((char *)what);
1819*7348b5c5SDavid van Moolenbroek 
1820*7348b5c5SDavid van Moolenbroek 	if (len == 0)
1821*7348b5c5SDavid van Moolenbroek 		goto unknown;
1822*7348b5c5SDavid van Moolenbroek 
1823*7348b5c5SDavid van Moolenbroek 	if (strncasecmp((char *)what, "status", len) == 0) {
1824*7348b5c5SDavid van Moolenbroek 		if (env_auto)
1825*7348b5c5SDavid van Moolenbroek 			printf("%s%s", "VAR and VALUE are/will be ",
1826*7348b5c5SDavid van Moolenbroek 					"determined automatically\n");
1827*7348b5c5SDavid van Moolenbroek 		if (old_env_var == OLD_ENV_VAR)
1828*7348b5c5SDavid van Moolenbroek 			printf("VAR and VALUE set to correct definitions\n");
1829*7348b5c5SDavid van Moolenbroek 		else
1830*7348b5c5SDavid van Moolenbroek 			printf("VAR and VALUE definitions are reversed\n");
1831*7348b5c5SDavid van Moolenbroek 	} else if (strncasecmp((char *)what, "auto", len) == 0) {
1832*7348b5c5SDavid van Moolenbroek 		env_auto = 1;
1833*7348b5c5SDavid van Moolenbroek 		old_env_var = OLD_ENV_VALUE;
1834*7348b5c5SDavid van Moolenbroek 		old_env_value = OLD_ENV_VAR;
1835*7348b5c5SDavid van Moolenbroek 	} else if (strncasecmp((char *)what, "right", len) == 0) {
1836*7348b5c5SDavid van Moolenbroek 		env_auto = 0;
1837*7348b5c5SDavid van Moolenbroek 		old_env_var = OLD_ENV_VAR;
1838*7348b5c5SDavid van Moolenbroek 		old_env_value = OLD_ENV_VALUE;
1839*7348b5c5SDavid van Moolenbroek 	} else if (strncasecmp((char *)what, "wrong", len) == 0) {
1840*7348b5c5SDavid van Moolenbroek 		env_auto = 0;
1841*7348b5c5SDavid van Moolenbroek 		old_env_var = OLD_ENV_VALUE;
1842*7348b5c5SDavid van Moolenbroek 		old_env_value = OLD_ENV_VAR;
1843*7348b5c5SDavid van Moolenbroek 	} else {
1844*7348b5c5SDavid van Moolenbroek unknown:
1845*7348b5c5SDavid van Moolenbroek 		printf("Unknown \"varval\" command. (\"auto\", \"right\", \"wrong\", \"status\")\n");
1846*7348b5c5SDavid van Moolenbroek 	}
1847*7348b5c5SDavid van Moolenbroek }
1848*7348b5c5SDavid van Moolenbroek #endif
1849*7348b5c5SDavid van Moolenbroek 
1850*7348b5c5SDavid van Moolenbroek #ifdef AUTHENTICATION
1851*7348b5c5SDavid van Moolenbroek /*
1852*7348b5c5SDavid van Moolenbroek  * The AUTHENTICATE command.
1853*7348b5c5SDavid van Moolenbroek  */
1854*7348b5c5SDavid van Moolenbroek 
1855*7348b5c5SDavid van Moolenbroek struct authlist {
1856*7348b5c5SDavid van Moolenbroek 	const char	*name;
1857*7348b5c5SDavid van Moolenbroek 	const char	*help;
1858*7348b5c5SDavid van Moolenbroek 	int	(*handler)(char *);
1859*7348b5c5SDavid van Moolenbroek 	int	narg;
1860*7348b5c5SDavid van Moolenbroek };
1861*7348b5c5SDavid van Moolenbroek 
1862*7348b5c5SDavid van Moolenbroek struct authlist AuthList[] = {
1863*7348b5c5SDavid van Moolenbroek     { "status",	"Display current status of authentication information",
1864*7348b5c5SDavid van Moolenbroek 						auth_status,	0 },
1865*7348b5c5SDavid van Moolenbroek     { "disable", "Disable an authentication type ('auth disable ?' for more)",
1866*7348b5c5SDavid van Moolenbroek 						auth_disable,	1 },
1867*7348b5c5SDavid van Moolenbroek     { "enable", "Enable an authentication type ('auth enable ?' for more)",
1868*7348b5c5SDavid van Moolenbroek 						auth_enable,	1 },
1869*7348b5c5SDavid van Moolenbroek     { "help",	0,				auth_help,		0 },
1870*7348b5c5SDavid van Moolenbroek     { "?",	"Print help information",	auth_help,		0 },
1871*7348b5c5SDavid van Moolenbroek     { .name = 0 },
1872*7348b5c5SDavid van Moolenbroek };
1873*7348b5c5SDavid van Moolenbroek 
1874*7348b5c5SDavid van Moolenbroek static int
auth_help(char * s)1875*7348b5c5SDavid van Moolenbroek auth_help(char *s)
1876*7348b5c5SDavid van Moolenbroek {
1877*7348b5c5SDavid van Moolenbroek     struct authlist *c;
1878*7348b5c5SDavid van Moolenbroek 
1879*7348b5c5SDavid van Moolenbroek     for (c = AuthList; c->name; c++) {
1880*7348b5c5SDavid van Moolenbroek 	if (c->help) {
1881*7348b5c5SDavid van Moolenbroek 	    if (*c->help)
1882*7348b5c5SDavid van Moolenbroek 		printf("%-15s %s\n", c->name, c->help);
1883*7348b5c5SDavid van Moolenbroek 	    else
1884*7348b5c5SDavid van Moolenbroek 		printf("\n");
1885*7348b5c5SDavid van Moolenbroek 	}
1886*7348b5c5SDavid van Moolenbroek     }
1887*7348b5c5SDavid van Moolenbroek     return 0;
1888*7348b5c5SDavid van Moolenbroek }
1889*7348b5c5SDavid van Moolenbroek 
1890*7348b5c5SDavid van Moolenbroek int
auth_cmd(int argc,char * argv[])1891*7348b5c5SDavid van Moolenbroek auth_cmd(int  argc, char *argv[])
1892*7348b5c5SDavid van Moolenbroek {
1893*7348b5c5SDavid van Moolenbroek     struct authlist *c;
1894*7348b5c5SDavid van Moolenbroek 
1895*7348b5c5SDavid van Moolenbroek     if (argc < 2) {
1896*7348b5c5SDavid van Moolenbroek 	fprintf(stderr,
1897*7348b5c5SDavid van Moolenbroek 	    "Need an argument to 'auth' command.  'auth ?' for help.\n");
1898*7348b5c5SDavid van Moolenbroek 	return 0;
1899*7348b5c5SDavid van Moolenbroek     }
1900*7348b5c5SDavid van Moolenbroek 
1901*7348b5c5SDavid van Moolenbroek     c = (struct authlist *)
1902*7348b5c5SDavid van Moolenbroek 		genget(argv[1], (char **) AuthList, sizeof(struct authlist));
1903*7348b5c5SDavid van Moolenbroek     if (c == 0) {
1904*7348b5c5SDavid van Moolenbroek 	fprintf(stderr, "'%s': unknown argument ('auth ?' for help).\n",
1905*7348b5c5SDavid van Moolenbroek     				argv[1]);
1906*7348b5c5SDavid van Moolenbroek 	return 0;
1907*7348b5c5SDavid van Moolenbroek     }
1908*7348b5c5SDavid van Moolenbroek     if (Ambiguous(c)) {
1909*7348b5c5SDavid van Moolenbroek 	fprintf(stderr, "'%s': ambiguous argument ('auth ?' for help).\n",
1910*7348b5c5SDavid van Moolenbroek     				argv[1]);
1911*7348b5c5SDavid van Moolenbroek 	return 0;
1912*7348b5c5SDavid van Moolenbroek     }
1913*7348b5c5SDavid van Moolenbroek     if (c->narg + 2 != argc) {
1914*7348b5c5SDavid van Moolenbroek 	fprintf(stderr,
1915*7348b5c5SDavid van Moolenbroek 	    "Need %s%d argument%s to 'auth %s' command.  'auth ?' for help.\n",
1916*7348b5c5SDavid van Moolenbroek 		c->narg < argc + 2 ? "only " : "",
1917*7348b5c5SDavid van Moolenbroek 		c->narg, c->narg == 1 ? "" : "s", c->name);
1918*7348b5c5SDavid van Moolenbroek 	return 0;
1919*7348b5c5SDavid van Moolenbroek     }
1920*7348b5c5SDavid van Moolenbroek     return((*c->handler)(argv[2]));
1921*7348b5c5SDavid van Moolenbroek }
1922*7348b5c5SDavid van Moolenbroek #endif
1923*7348b5c5SDavid van Moolenbroek 
1924*7348b5c5SDavid van Moolenbroek #ifdef	ENCRYPTION
1925*7348b5c5SDavid van Moolenbroek /*
1926*7348b5c5SDavid van Moolenbroek  * The ENCRYPT command.
1927*7348b5c5SDavid van Moolenbroek  */
1928*7348b5c5SDavid van Moolenbroek 
1929*7348b5c5SDavid van Moolenbroek struct encryptlist {
1930*7348b5c5SDavid van Moolenbroek 	const char	*name;
1931*7348b5c5SDavid van Moolenbroek 	const char	*help;
1932*7348b5c5SDavid van Moolenbroek 	int	(*handler)(char *, char *);
1933*7348b5c5SDavid van Moolenbroek 	int	needconnect;
1934*7348b5c5SDavid van Moolenbroek 	int	minarg;
1935*7348b5c5SDavid van Moolenbroek 	int	maxarg;
1936*7348b5c5SDavid van Moolenbroek };
1937*7348b5c5SDavid van Moolenbroek 
1938*7348b5c5SDavid van Moolenbroek static int
1939*7348b5c5SDavid van Moolenbroek 	EncryptHelp(char *, char *);
1940*7348b5c5SDavid van Moolenbroek typedef int (*encrypthandler)(char *, char *);
1941*7348b5c5SDavid van Moolenbroek 
1942*7348b5c5SDavid van Moolenbroek struct encryptlist EncryptList[] = {
1943*7348b5c5SDavid van Moolenbroek     { "enable", "Enable encryption. ('encrypt enable ?' for more)",
1944*7348b5c5SDavid van Moolenbroek 						EncryptEnable, 1, 1, 2 },
1945*7348b5c5SDavid van Moolenbroek     { "disable", "Disable encryption. ('encrypt enable ?' for more)",
1946*7348b5c5SDavid van Moolenbroek 						EncryptDisable, 0, 1, 2 },
1947*7348b5c5SDavid van Moolenbroek     { "type", "Set encryption type. ('encrypt type ?' for more)",
1948*7348b5c5SDavid van Moolenbroek 						EncryptType, 0, 1, 1 },
1949*7348b5c5SDavid van Moolenbroek     { "start", "Start encryption. ('encrypt start ?' for more)",
1950*7348b5c5SDavid van Moolenbroek 				(encrypthandler) EncryptStart, 1, 0, 1 },
1951*7348b5c5SDavid van Moolenbroek     { "stop", "Stop encryption. ('encrypt stop ?' for more)",
1952*7348b5c5SDavid van Moolenbroek 				(encrypthandler) EncryptStop, 1, 0, 1 },
1953*7348b5c5SDavid van Moolenbroek     { "input", "Start encrypting the input stream",
1954*7348b5c5SDavid van Moolenbroek 				(encrypthandler) EncryptStartInput, 1, 0, 0 },
1955*7348b5c5SDavid van Moolenbroek     { "-input", "Stop encrypting the input stream",
1956*7348b5c5SDavid van Moolenbroek 				(encrypthandler) EncryptStopInput, 1, 0, 0 },
1957*7348b5c5SDavid van Moolenbroek     { "output", "Start encrypting the output stream",
1958*7348b5c5SDavid van Moolenbroek 				(encrypthandler) EncryptStartOutput, 1, 0, 0 },
1959*7348b5c5SDavid van Moolenbroek     { "-output", "Stop encrypting the output stream",
1960*7348b5c5SDavid van Moolenbroek 				(encrypthandler) EncryptStopOutput, 1, 0, 0 },
1961*7348b5c5SDavid van Moolenbroek 
1962*7348b5c5SDavid van Moolenbroek     { "status",       "Display current status of authentication information",
1963*7348b5c5SDavid van Moolenbroek 				(encrypthandler) EncryptStatus,	0, 0, 0 },
1964*7348b5c5SDavid van Moolenbroek     { "help", 0,				 EncryptHelp,	0, 0, 0 },
1965*7348b5c5SDavid van Moolenbroek     { "?",    "Print help information",		 EncryptHelp,	0, 0, 0 },
1966*7348b5c5SDavid van Moolenbroek     { .name = 0 },
1967*7348b5c5SDavid van Moolenbroek };
1968*7348b5c5SDavid van Moolenbroek 
1969*7348b5c5SDavid van Moolenbroek static int
EncryptHelp(char * s1,char * s2)1970*7348b5c5SDavid van Moolenbroek EncryptHelp(char *s1, char *s2)
1971*7348b5c5SDavid van Moolenbroek {
1972*7348b5c5SDavid van Moolenbroek 	struct encryptlist *c;
1973*7348b5c5SDavid van Moolenbroek 
1974*7348b5c5SDavid van Moolenbroek 	for (c = EncryptList; c->name; c++) {
1975*7348b5c5SDavid van Moolenbroek 		if (c->help) {
1976*7348b5c5SDavid van Moolenbroek 			if (*c->help)
1977*7348b5c5SDavid van Moolenbroek 				printf("%-15s %s\n", c->name, c->help);
1978*7348b5c5SDavid van Moolenbroek 			else
1979*7348b5c5SDavid van Moolenbroek 				printf("\n");
1980*7348b5c5SDavid van Moolenbroek 		}
1981*7348b5c5SDavid van Moolenbroek 	}
1982*7348b5c5SDavid van Moolenbroek 	return (0);
1983*7348b5c5SDavid van Moolenbroek }
1984*7348b5c5SDavid van Moolenbroek 
1985*7348b5c5SDavid van Moolenbroek int
encrypt_cmd(int argc,char * argv[])1986*7348b5c5SDavid van Moolenbroek encrypt_cmd(int argc, char *argv[])
1987*7348b5c5SDavid van Moolenbroek {
1988*7348b5c5SDavid van Moolenbroek 	struct encryptlist *c;
1989*7348b5c5SDavid van Moolenbroek 
1990*7348b5c5SDavid van Moolenbroek 	if (argc < 2) {
1991*7348b5c5SDavid van Moolenbroek 		fprintf(stderr,
1992*7348b5c5SDavid van Moolenbroek 		    "Need an argument to 'encrypt' command.  "
1993*7348b5c5SDavid van Moolenbroek 		    "'encrypt ?' for help.\n");
1994*7348b5c5SDavid van Moolenbroek 		return (0);
1995*7348b5c5SDavid van Moolenbroek 	}
1996*7348b5c5SDavid van Moolenbroek 
1997*7348b5c5SDavid van Moolenbroek 	c = (struct encryptlist *)
1998*7348b5c5SDavid van Moolenbroek 	    genget(argv[1], (char **) EncryptList, sizeof(struct encryptlist));
1999*7348b5c5SDavid van Moolenbroek 	if (c == NULL) {
2000*7348b5c5SDavid van Moolenbroek 		fprintf(stderr,
2001*7348b5c5SDavid van Moolenbroek 		    "'%s': unknown argument ('encrypt ?' for help).\n",
2002*7348b5c5SDavid van Moolenbroek 		    argv[1]);
2003*7348b5c5SDavid van Moolenbroek 		return (0);
2004*7348b5c5SDavid van Moolenbroek 	}
2005*7348b5c5SDavid van Moolenbroek 	if (Ambiguous(c)) {
2006*7348b5c5SDavid van Moolenbroek 		fprintf(stderr,
2007*7348b5c5SDavid van Moolenbroek 		    "'%s': ambiguous argument ('encrypt ?' for help).\n",
2008*7348b5c5SDavid van Moolenbroek 		    argv[1]);
2009*7348b5c5SDavid van Moolenbroek 		return (0);
2010*7348b5c5SDavid van Moolenbroek 	}
2011*7348b5c5SDavid van Moolenbroek 	argc -= 2;
2012*7348b5c5SDavid van Moolenbroek 	if (argc < c->minarg || argc > c->maxarg) {
2013*7348b5c5SDavid van Moolenbroek 		if (c->minarg == c->maxarg) {
2014*7348b5c5SDavid van Moolenbroek 			fprintf(stderr, "Need %s%d argument%s ",
2015*7348b5c5SDavid van Moolenbroek 			    c->minarg < argc ? "only " : "", c->minarg,
2016*7348b5c5SDavid van Moolenbroek 			    c->minarg == 1 ? "" : "s");
2017*7348b5c5SDavid van Moolenbroek 		} else {
2018*7348b5c5SDavid van Moolenbroek 			fprintf(stderr, "Need %s%d-%d arguments ",
2019*7348b5c5SDavid van Moolenbroek 			    c->maxarg < argc ? "only " : "", c->minarg,
2020*7348b5c5SDavid van Moolenbroek 			    c->maxarg);
2021*7348b5c5SDavid van Moolenbroek 		}
2022*7348b5c5SDavid van Moolenbroek 		fprintf(stderr,
2023*7348b5c5SDavid van Moolenbroek 		    "to 'encrypt %s' command.  'encrypt ?' for help.\n",
2024*7348b5c5SDavid van Moolenbroek 		    c->name);
2025*7348b5c5SDavid van Moolenbroek 		return (0);
2026*7348b5c5SDavid van Moolenbroek 	}
2027*7348b5c5SDavid van Moolenbroek 	if (c->needconnect && !connected) {
2028*7348b5c5SDavid van Moolenbroek 		if (!(argc && (isprefix(argv[2], "help") ||
2029*7348b5c5SDavid van Moolenbroek 		    isprefix(argv[2], "?")))) {
2030*7348b5c5SDavid van Moolenbroek 			printf("?Need to be connected first.\n");
2031*7348b5c5SDavid van Moolenbroek 			return (0);
2032*7348b5c5SDavid van Moolenbroek 		}
2033*7348b5c5SDavid van Moolenbroek 	}
2034*7348b5c5SDavid van Moolenbroek 	return ((*c->handler)(argv[2], argv[3]));
2035*7348b5c5SDavid van Moolenbroek }
2036*7348b5c5SDavid van Moolenbroek #endif	/* ENCRYPTION */
2037*7348b5c5SDavid van Moolenbroek 
2038*7348b5c5SDavid van Moolenbroek #ifdef TN3270
2039*7348b5c5SDavid van Moolenbroek static void
filestuff(int fd)2040*7348b5c5SDavid van Moolenbroek filestuff(int fd)
2041*7348b5c5SDavid van Moolenbroek {
2042*7348b5c5SDavid van Moolenbroek     int res;
2043*7348b5c5SDavid van Moolenbroek 
2044*7348b5c5SDavid van Moolenbroek     setconnmode(0);
2045*7348b5c5SDavid van Moolenbroek     res = fcntl(fd, F_GETOWN, 0);
2046*7348b5c5SDavid van Moolenbroek     setcommandmode();
2047*7348b5c5SDavid van Moolenbroek 
2048*7348b5c5SDavid van Moolenbroek     if (res == -1) {
2049*7348b5c5SDavid van Moolenbroek 	perror("fcntl");
2050*7348b5c5SDavid van Moolenbroek 	return;
2051*7348b5c5SDavid van Moolenbroek     }
2052*7348b5c5SDavid van Moolenbroek     printf("\tOwner is %d.\n", res);
2053*7348b5c5SDavid van Moolenbroek 
2054*7348b5c5SDavid van Moolenbroek     setconnmode(0);
2055*7348b5c5SDavid van Moolenbroek     res = fcntl(fd, F_GETFL, 0);
2056*7348b5c5SDavid van Moolenbroek     setcommandmode();
2057*7348b5c5SDavid van Moolenbroek 
2058*7348b5c5SDavid van Moolenbroek     if (res == -1) {
2059*7348b5c5SDavid van Moolenbroek 	perror("fcntl");
2060*7348b5c5SDavid van Moolenbroek 	return;
2061*7348b5c5SDavid van Moolenbroek     }
2062*7348b5c5SDavid van Moolenbroek #ifdef notdef
2063*7348b5c5SDavid van Moolenbroek     printf("\tFlags are 0x%x: %s\n", res, decodeflags(res));
2064*7348b5c5SDavid van Moolenbroek #endif
2065*7348b5c5SDavid van Moolenbroek }
2066*7348b5c5SDavid van Moolenbroek #endif /* defined(TN3270) */
2067*7348b5c5SDavid van Moolenbroek 
2068*7348b5c5SDavid van Moolenbroek /*
2069*7348b5c5SDavid van Moolenbroek  * Print status about the connection.
2070*7348b5c5SDavid van Moolenbroek  */
2071*7348b5c5SDavid van Moolenbroek /*ARGSUSED*/
2072*7348b5c5SDavid van Moolenbroek static int
status(int argc,char * argv[])2073*7348b5c5SDavid van Moolenbroek status(int argc, char *argv[])
2074*7348b5c5SDavid van Moolenbroek {
2075*7348b5c5SDavid van Moolenbroek     if (connected) {
2076*7348b5c5SDavid van Moolenbroek 	printf("Connected to %s.\n", hostname);
2077*7348b5c5SDavid van Moolenbroek 	if ((argc < 2) || strcmp(argv[1], "notmuch")) {
2078*7348b5c5SDavid van Moolenbroek 	    int mode = getconnmode();
2079*7348b5c5SDavid van Moolenbroek 
2080*7348b5c5SDavid van Moolenbroek 	    if (my_want_state_is_will(TELOPT_LINEMODE)) {
2081*7348b5c5SDavid van Moolenbroek 		printf("Operating with LINEMODE option\n");
2082*7348b5c5SDavid van Moolenbroek 		printf("%s line editing\n", (mode&MODE_EDIT) ? "Local" : "No");
2083*7348b5c5SDavid van Moolenbroek 		printf("%s catching of signals\n",
2084*7348b5c5SDavid van Moolenbroek 					(mode&MODE_TRAPSIG) ? "Local" : "No");
2085*7348b5c5SDavid van Moolenbroek 		slcstate();
2086*7348b5c5SDavid van Moolenbroek #ifdef	KLUDGELINEMODE
2087*7348b5c5SDavid van Moolenbroek 	    } else if (kludgelinemode && my_want_state_is_dont(TELOPT_SGA)) {
2088*7348b5c5SDavid van Moolenbroek 		printf("Operating in obsolete linemode\n");
2089*7348b5c5SDavid van Moolenbroek #endif
2090*7348b5c5SDavid van Moolenbroek 	    } else {
2091*7348b5c5SDavid van Moolenbroek 		printf("Operating in single character mode\n");
2092*7348b5c5SDavid van Moolenbroek 		if (localchars)
2093*7348b5c5SDavid van Moolenbroek 		    printf("Catching signals locally\n");
2094*7348b5c5SDavid van Moolenbroek 	    }
2095*7348b5c5SDavid van Moolenbroek 	    printf("%s character echo\n", (mode&MODE_ECHO) ? "Local" : "Remote");
2096*7348b5c5SDavid van Moolenbroek 	    if (my_want_state_is_will(TELOPT_LFLOW))
2097*7348b5c5SDavid van Moolenbroek 		printf("%s flow control\n", (mode&MODE_FLOW) ? "Local" : "No");
2098*7348b5c5SDavid van Moolenbroek #ifdef	ENCRYPTION
2099*7348b5c5SDavid van Moolenbroek 	    encrypt_display();
2100*7348b5c5SDavid van Moolenbroek #endif	/* ENCRYPTION */
2101*7348b5c5SDavid van Moolenbroek 	}
2102*7348b5c5SDavid van Moolenbroek     } else {
2103*7348b5c5SDavid van Moolenbroek 	printf("No connection.\n");
2104*7348b5c5SDavid van Moolenbroek     }
2105*7348b5c5SDavid van Moolenbroek #   ifndef TN3270
2106*7348b5c5SDavid van Moolenbroek     printf("Escape character is '%s'.\n", control(escape));
2107*7348b5c5SDavid van Moolenbroek     (void) fflush(stdout);
2108*7348b5c5SDavid van Moolenbroek #   else /* !defined(TN3270) */
2109*7348b5c5SDavid van Moolenbroek     if ((!In3270) && ((argc < 2) || strcmp(argv[1], "notmuch"))) {
2110*7348b5c5SDavid van Moolenbroek 	printf("Escape character is '%s'.\n", control(escape));
2111*7348b5c5SDavid van Moolenbroek     }
2112*7348b5c5SDavid van Moolenbroek     if ((argc >= 2) && !strcmp(argv[1], "everything")) {
2113*7348b5c5SDavid van Moolenbroek 	printf("SIGIO received %d time%s.\n",
2114*7348b5c5SDavid van Moolenbroek 				sigiocount, (sigiocount == 1)? "":"s");
2115*7348b5c5SDavid van Moolenbroek 	if (In3270) {
2116*7348b5c5SDavid van Moolenbroek 	    printf("Process ID %d, process group %d.\n",
2117*7348b5c5SDavid van Moolenbroek 					    getpid(), getpgrp());
2118*7348b5c5SDavid van Moolenbroek 	    printf("Terminal input:\n");
2119*7348b5c5SDavid van Moolenbroek 	    filestuff(tin);
2120*7348b5c5SDavid van Moolenbroek 	    printf("Terminal output:\n");
2121*7348b5c5SDavid van Moolenbroek 	    filestuff(tout);
2122*7348b5c5SDavid van Moolenbroek 	    printf("Network socket:\n");
2123*7348b5c5SDavid van Moolenbroek 	    filestuff(net);
2124*7348b5c5SDavid van Moolenbroek 	}
2125*7348b5c5SDavid van Moolenbroek     }
2126*7348b5c5SDavid van Moolenbroek     if (In3270 && transcom) {
2127*7348b5c5SDavid van Moolenbroek 	printf("Transparent mode command is '%s'.\n", transcom);
2128*7348b5c5SDavid van Moolenbroek     }
2129*7348b5c5SDavid van Moolenbroek     (void) fflush(stdout);
2130*7348b5c5SDavid van Moolenbroek     if (In3270) {
2131*7348b5c5SDavid van Moolenbroek 	return 0;
2132*7348b5c5SDavid van Moolenbroek     }
2133*7348b5c5SDavid van Moolenbroek #   endif /* defined(TN3270) */
2134*7348b5c5SDavid van Moolenbroek     return 1;
2135*7348b5c5SDavid van Moolenbroek }
2136*7348b5c5SDavid van Moolenbroek 
2137*7348b5c5SDavid van Moolenbroek /*
2138*7348b5c5SDavid van Moolenbroek  * Function that gets called when SIGINFO is received.
2139*7348b5c5SDavid van Moolenbroek  */
2140*7348b5c5SDavid van Moolenbroek int
ayt_status(void)2141*7348b5c5SDavid van Moolenbroek ayt_status(void)
2142*7348b5c5SDavid van Moolenbroek {
2143*7348b5c5SDavid van Moolenbroek     return call(status, "status", "notmuch", 0);
2144*7348b5c5SDavid van Moolenbroek }
2145*7348b5c5SDavid van Moolenbroek 
2146*7348b5c5SDavid van Moolenbroek static const char *
sockaddr_ntop(struct sockaddr * sa)2147*7348b5c5SDavid van Moolenbroek sockaddr_ntop(struct sockaddr *sa)
2148*7348b5c5SDavid van Moolenbroek {
2149*7348b5c5SDavid van Moolenbroek     static char addrbuf[NI_MAXHOST];
2150*7348b5c5SDavid van Moolenbroek     const int niflags = NI_NUMERICHOST;
2151*7348b5c5SDavid van Moolenbroek 
2152*7348b5c5SDavid van Moolenbroek     if (getnameinfo(sa, sa->sa_len, addrbuf, sizeof(addrbuf),
2153*7348b5c5SDavid van Moolenbroek 	    NULL, 0, niflags) == 0)
2154*7348b5c5SDavid van Moolenbroek 	return addrbuf;
2155*7348b5c5SDavid van Moolenbroek     else
2156*7348b5c5SDavid van Moolenbroek 	return NULL;
2157*7348b5c5SDavid van Moolenbroek }
2158*7348b5c5SDavid van Moolenbroek 
2159*7348b5c5SDavid van Moolenbroek #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
2160*7348b5c5SDavid van Moolenbroek static int setpolicy (int, struct addrinfo *, char *);
2161*7348b5c5SDavid van Moolenbroek 
2162*7348b5c5SDavid van Moolenbroek static int
setpolicy(int netw,struct addrinfo * res,char * policy)2163*7348b5c5SDavid van Moolenbroek setpolicy(int netw, struct addrinfo *res, char *policy)
2164*7348b5c5SDavid van Moolenbroek {
2165*7348b5c5SDavid van Moolenbroek 	char *buf;
2166*7348b5c5SDavid van Moolenbroek 	int level;
2167*7348b5c5SDavid van Moolenbroek 	int optname;
2168*7348b5c5SDavid van Moolenbroek 
2169*7348b5c5SDavid van Moolenbroek 	if (policy == NULL)
2170*7348b5c5SDavid van Moolenbroek 		return 0;
2171*7348b5c5SDavid van Moolenbroek 
2172*7348b5c5SDavid van Moolenbroek 	buf = ipsec_set_policy(policy, strlen(policy));
2173*7348b5c5SDavid van Moolenbroek 	if (buf == NULL) {
2174*7348b5c5SDavid van Moolenbroek 		printf("%s\n", ipsec_strerror());
2175*7348b5c5SDavid van Moolenbroek 		return -1;
2176*7348b5c5SDavid van Moolenbroek 	}
2177*7348b5c5SDavid van Moolenbroek 	level = res->ai_family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6;
2178*7348b5c5SDavid van Moolenbroek 	optname = res->ai_family == AF_INET ? IP_IPSEC_POLICY : IPV6_IPSEC_POLICY;
2179*7348b5c5SDavid van Moolenbroek 	if (setsockopt(netw, level, optname, buf, ipsec_get_policylen(buf)) < 0){
2180*7348b5c5SDavid van Moolenbroek 		perror("setsockopt");
2181*7348b5c5SDavid van Moolenbroek 		return -1;
2182*7348b5c5SDavid van Moolenbroek 	}
2183*7348b5c5SDavid van Moolenbroek 
2184*7348b5c5SDavid van Moolenbroek 	free(buf);
2185*7348b5c5SDavid van Moolenbroek 	return 0;
2186*7348b5c5SDavid van Moolenbroek }
2187*7348b5c5SDavid van Moolenbroek #endif
2188*7348b5c5SDavid van Moolenbroek 
2189*7348b5c5SDavid van Moolenbroek int
tn(int argc,char * argv[])2190*7348b5c5SDavid van Moolenbroek tn(int argc, char *argv[])
2191*7348b5c5SDavid van Moolenbroek {
2192*7348b5c5SDavid van Moolenbroek     struct addrinfo hints, *res, *res0;
2193*7348b5c5SDavid van Moolenbroek     const char *cause = "telnet: unknown";
2194*7348b5c5SDavid van Moolenbroek     int error;
2195*7348b5c5SDavid van Moolenbroek #if	defined(IP_OPTIONS) && defined(IPPROTO_IP)
2196*7348b5c5SDavid van Moolenbroek     char *srp = 0;
2197*7348b5c5SDavid van Moolenbroek     long srlen;
2198*7348b5c5SDavid van Moolenbroek     int proto, opt;
2199*7348b5c5SDavid van Moolenbroek #endif
2200*7348b5c5SDavid van Moolenbroek     char *cmd, *hostp = 0;
2201*7348b5c5SDavid van Moolenbroek     const char *portp = 0;
2202*7348b5c5SDavid van Moolenbroek     const char *user = 0;
2203*7348b5c5SDavid van Moolenbroek 
2204*7348b5c5SDavid van Moolenbroek     if (connected) {
2205*7348b5c5SDavid van Moolenbroek 	printf("?Already connected to %s\n", hostname);
2206*7348b5c5SDavid van Moolenbroek 	return 0;
2207*7348b5c5SDavid van Moolenbroek     }
2208*7348b5c5SDavid van Moolenbroek     if (argc < 2) {
2209*7348b5c5SDavid van Moolenbroek 	(void) strlcpy(line, "open ", sizeof(line));
2210*7348b5c5SDavid van Moolenbroek 	printf("(to) ");
2211*7348b5c5SDavid van Moolenbroek 	(void) fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin);
2212*7348b5c5SDavid van Moolenbroek 	makeargv();
2213*7348b5c5SDavid van Moolenbroek 	argc = margc;
2214*7348b5c5SDavid van Moolenbroek 	argv = margv;
2215*7348b5c5SDavid van Moolenbroek     }
2216*7348b5c5SDavid van Moolenbroek     cmd = *argv;
2217*7348b5c5SDavid van Moolenbroek     --argc; ++argv;
2218*7348b5c5SDavid van Moolenbroek     while (argc) {
2219*7348b5c5SDavid van Moolenbroek 	if (strcmp(*argv, "help") == 0 || isprefix(*argv, "?"))
2220*7348b5c5SDavid van Moolenbroek 	    goto usage;
2221*7348b5c5SDavid van Moolenbroek 	if (strcmp(*argv, "-l") == 0) {
2222*7348b5c5SDavid van Moolenbroek 	    --argc; ++argv;
2223*7348b5c5SDavid van Moolenbroek 	    if (argc == 0)
2224*7348b5c5SDavid van Moolenbroek 		goto usage;
2225*7348b5c5SDavid van Moolenbroek 	    user = *argv++;
2226*7348b5c5SDavid van Moolenbroek 	    --argc;
2227*7348b5c5SDavid van Moolenbroek 	    continue;
2228*7348b5c5SDavid van Moolenbroek 	}
2229*7348b5c5SDavid van Moolenbroek 	if (strcmp(*argv, "-a") == 0) {
2230*7348b5c5SDavid van Moolenbroek 	    --argc; ++argv;
2231*7348b5c5SDavid van Moolenbroek 	    autologin = 1;
2232*7348b5c5SDavid van Moolenbroek 	    continue;
2233*7348b5c5SDavid van Moolenbroek 	}
2234*7348b5c5SDavid van Moolenbroek 	if (hostp == 0) {
2235*7348b5c5SDavid van Moolenbroek 	    hostp = *argv++;
2236*7348b5c5SDavid van Moolenbroek 	    --argc;
2237*7348b5c5SDavid van Moolenbroek 	    continue;
2238*7348b5c5SDavid van Moolenbroek 	}
2239*7348b5c5SDavid van Moolenbroek 	if (portp == 0) {
2240*7348b5c5SDavid van Moolenbroek 	    portp = *argv++;
2241*7348b5c5SDavid van Moolenbroek 	    --argc;
2242*7348b5c5SDavid van Moolenbroek 	    continue;
2243*7348b5c5SDavid van Moolenbroek 	}
2244*7348b5c5SDavid van Moolenbroek     usage:
2245*7348b5c5SDavid van Moolenbroek 	printf("usage: %s [-l user] [-a] host-name [port]\n", cmd);
2246*7348b5c5SDavid van Moolenbroek 	return 0;
2247*7348b5c5SDavid van Moolenbroek     }
2248*7348b5c5SDavid van Moolenbroek     if (hostp == 0)
2249*7348b5c5SDavid van Moolenbroek 	goto usage;
2250*7348b5c5SDavid van Moolenbroek 
2251*7348b5c5SDavid van Moolenbroek     (void) strlcpy(_hostname, hostp, sizeof(_hostname));
2252*7348b5c5SDavid van Moolenbroek     if (hostp[0] == '@' || hostp[0] == '!') {
2253*7348b5c5SDavid van Moolenbroek 	char *p;
2254*7348b5c5SDavid van Moolenbroek 	hostname = NULL;
2255*7348b5c5SDavid van Moolenbroek 	for (p = hostp + 1; *p; p++) {
2256*7348b5c5SDavid van Moolenbroek 	    if (*p == ',' || *p == '@')
2257*7348b5c5SDavid van Moolenbroek 		hostname = p;
2258*7348b5c5SDavid van Moolenbroek 	}
2259*7348b5c5SDavid van Moolenbroek 	if (hostname == NULL) {
2260*7348b5c5SDavid van Moolenbroek 	    fprintf(stderr, "%s: bad source route specification\n", hostp);
2261*7348b5c5SDavid van Moolenbroek 	    return 0;
2262*7348b5c5SDavid van Moolenbroek 	}
2263*7348b5c5SDavid van Moolenbroek 	*hostname++ = '\0';
2264*7348b5c5SDavid van Moolenbroek     } else
2265*7348b5c5SDavid van Moolenbroek 	hostname = hostp;
2266*7348b5c5SDavid van Moolenbroek 
2267*7348b5c5SDavid van Moolenbroek     if (!portp) {
2268*7348b5c5SDavid van Moolenbroek 	telnetport = 1;
2269*7348b5c5SDavid van Moolenbroek 	portp = "telnet";
2270*7348b5c5SDavid van Moolenbroek     } else if (portp[0] == '-') {
2271*7348b5c5SDavid van Moolenbroek 	/* use telnet negotiation if port number/name preceded by minus sign */
2272*7348b5c5SDavid van Moolenbroek 	telnetport = 1;
2273*7348b5c5SDavid van Moolenbroek 	portp++;
2274*7348b5c5SDavid van Moolenbroek     } else
2275*7348b5c5SDavid van Moolenbroek 	telnetport = 0;
2276*7348b5c5SDavid van Moolenbroek 
2277*7348b5c5SDavid van Moolenbroek     memset(&hints, 0, sizeof(hints));
2278*7348b5c5SDavid van Moolenbroek     hints.ai_family = family;
2279*7348b5c5SDavid van Moolenbroek     hints.ai_socktype = SOCK_STREAM;
2280*7348b5c5SDavid van Moolenbroek     hints.ai_protocol = 0;
2281*7348b5c5SDavid van Moolenbroek     hints.ai_flags = AI_NUMERICHOST;	/* avoid forward lookup */
2282*7348b5c5SDavid van Moolenbroek     error = getaddrinfo(hostname, portp, &hints, &res0);
2283*7348b5c5SDavid van Moolenbroek     if (!error) {
2284*7348b5c5SDavid van Moolenbroek 	/* numeric */
2285*7348b5c5SDavid van Moolenbroek 	if (doaddrlookup &&
2286*7348b5c5SDavid van Moolenbroek 	    getnameinfo(res0->ai_addr, res0->ai_addrlen,
2287*7348b5c5SDavid van Moolenbroek 		_hostname, sizeof(_hostname), NULL, 0, NI_NAMEREQD) == 0)
2288*7348b5c5SDavid van Moolenbroek 	    ; /* okay */
2289*7348b5c5SDavid van Moolenbroek 	else
2290*7348b5c5SDavid van Moolenbroek 	    strlcpy(_hostname, hostname, sizeof(_hostname));
2291*7348b5c5SDavid van Moolenbroek     } else {
2292*7348b5c5SDavid van Moolenbroek 	/* FQDN - try again with forward DNS lookup */
2293*7348b5c5SDavid van Moolenbroek 	memset(&hints, 0, sizeof(hints));
2294*7348b5c5SDavid van Moolenbroek 	hints.ai_family = family;
2295*7348b5c5SDavid van Moolenbroek 	hints.ai_socktype = SOCK_STREAM;
2296*7348b5c5SDavid van Moolenbroek 	hints.ai_protocol = 0;
2297*7348b5c5SDavid van Moolenbroek 	hints.ai_flags = AI_CANONNAME;
2298*7348b5c5SDavid van Moolenbroek 	error = getaddrinfo(hostname, portp, &hints, &res0);
2299*7348b5c5SDavid van Moolenbroek 	if (error == EAI_SERVICE) {
2300*7348b5c5SDavid van Moolenbroek 	    fprintf(stderr, "tcp/%s: unknown service\n", portp);
2301*7348b5c5SDavid van Moolenbroek 	    return 0;
2302*7348b5c5SDavid van Moolenbroek 	} else if (error) {
2303*7348b5c5SDavid van Moolenbroek 	    fprintf(stderr, "%s: %s\n", hostname, gai_strerror(error));
2304*7348b5c5SDavid van Moolenbroek 	    return 0;
2305*7348b5c5SDavid van Moolenbroek 	}
2306*7348b5c5SDavid van Moolenbroek 	if (res0->ai_canonname)
2307*7348b5c5SDavid van Moolenbroek 	    (void)strlcpy(_hostname, res0->ai_canonname, sizeof(_hostname));
2308*7348b5c5SDavid van Moolenbroek 	else
2309*7348b5c5SDavid van Moolenbroek 	    (void)strlcpy(_hostname, hostname, sizeof(_hostname));
2310*7348b5c5SDavid van Moolenbroek     }
2311*7348b5c5SDavid van Moolenbroek     hostname = _hostname;
2312*7348b5c5SDavid van Moolenbroek 
2313*7348b5c5SDavid van Moolenbroek     net = -1;
2314*7348b5c5SDavid van Moolenbroek     for (res = res0; res; res = res->ai_next) {
2315*7348b5c5SDavid van Moolenbroek 	printf("Trying %s...\n", sockaddr_ntop(res->ai_addr));
2316*7348b5c5SDavid van Moolenbroek 	net = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
2317*7348b5c5SDavid van Moolenbroek 	if (net < 0) {
2318*7348b5c5SDavid van Moolenbroek 	    cause = "telnet: socket";
2319*7348b5c5SDavid van Moolenbroek 	    continue;
2320*7348b5c5SDavid van Moolenbroek 	}
2321*7348b5c5SDavid van Moolenbroek 
2322*7348b5c5SDavid van Moolenbroek 	if (telnet_debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) {
2323*7348b5c5SDavid van Moolenbroek 	    perror("setsockopt (SO_DEBUG)");
2324*7348b5c5SDavid van Moolenbroek 	}
2325*7348b5c5SDavid van Moolenbroek 	if (hostp[0] == '@' || hostp[0] == '!') {
2326*7348b5c5SDavid van Moolenbroek 	    if ((srlen = sourceroute(res, hostp, &srp, &proto, &opt)) < 0) {
2327*7348b5c5SDavid van Moolenbroek 		(void) NetClose(net);
2328*7348b5c5SDavid van Moolenbroek 		net = -1;
2329*7348b5c5SDavid van Moolenbroek 		continue;
2330*7348b5c5SDavid van Moolenbroek 	    }
2331*7348b5c5SDavid van Moolenbroek 	    if (srp && setsockopt(net, proto, opt, srp, srlen) < 0)
2332*7348b5c5SDavid van Moolenbroek 		perror("setsockopt (source route)");
2333*7348b5c5SDavid van Moolenbroek 	}
2334*7348b5c5SDavid van Moolenbroek 
2335*7348b5c5SDavid van Moolenbroek #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
2336*7348b5c5SDavid van Moolenbroek 	if (setpolicy(net, res, ipsec_policy_in) < 0) {
2337*7348b5c5SDavid van Moolenbroek 	    (void) NetClose(net);
2338*7348b5c5SDavid van Moolenbroek 	    net = -1;
2339*7348b5c5SDavid van Moolenbroek 	    continue;
2340*7348b5c5SDavid van Moolenbroek 	}
2341*7348b5c5SDavid van Moolenbroek 	if (setpolicy(net, res, ipsec_policy_out) < 0) {
2342*7348b5c5SDavid van Moolenbroek 	    (void) NetClose(net);
2343*7348b5c5SDavid van Moolenbroek 	    net = -1;
2344*7348b5c5SDavid van Moolenbroek 	    continue;
2345*7348b5c5SDavid van Moolenbroek 	}
2346*7348b5c5SDavid van Moolenbroek #endif
2347*7348b5c5SDavid van Moolenbroek 
2348*7348b5c5SDavid van Moolenbroek 	if (connect(net, res->ai_addr, res->ai_addrlen) < 0) {
2349*7348b5c5SDavid van Moolenbroek 	    if (res->ai_next) {
2350*7348b5c5SDavid van Moolenbroek 		int oerrno = errno;
2351*7348b5c5SDavid van Moolenbroek 
2352*7348b5c5SDavid van Moolenbroek 		fprintf(stderr, "telnet: connect to address %s: ",
2353*7348b5c5SDavid van Moolenbroek 						sockaddr_ntop(res->ai_addr));
2354*7348b5c5SDavid van Moolenbroek 		errno = oerrno;
2355*7348b5c5SDavid van Moolenbroek 		perror((char *)0);
2356*7348b5c5SDavid van Moolenbroek 	    }
2357*7348b5c5SDavid van Moolenbroek 	    cause = "telnet: Unable to connect to remote host";
2358*7348b5c5SDavid van Moolenbroek 	    (void) NetClose(net);
2359*7348b5c5SDavid van Moolenbroek 	    net = -1;
2360*7348b5c5SDavid van Moolenbroek 	    continue;
2361*7348b5c5SDavid van Moolenbroek 	}
2362*7348b5c5SDavid van Moolenbroek 
2363*7348b5c5SDavid van Moolenbroek 	connected++;
2364*7348b5c5SDavid van Moolenbroek #if	defined(AUTHENTICATION) || defined(ENCRYPTION)
2365*7348b5c5SDavid van Moolenbroek 	auth_encrypt_connect(connected);
2366*7348b5c5SDavid van Moolenbroek #endif	/* defined(AUTHENTICATION) || defined(ENCRYPTION) */
2367*7348b5c5SDavid van Moolenbroek 	break;
2368*7348b5c5SDavid van Moolenbroek     }
2369*7348b5c5SDavid van Moolenbroek     freeaddrinfo(res0);
2370*7348b5c5SDavid van Moolenbroek     if (net < 0 || connected == 0) {
2371*7348b5c5SDavid van Moolenbroek 	perror(cause);
2372*7348b5c5SDavid van Moolenbroek 	return 0;
2373*7348b5c5SDavid van Moolenbroek     }
2374*7348b5c5SDavid van Moolenbroek 
2375*7348b5c5SDavid van Moolenbroek     cmdrc(hostp, hostname);
2376*7348b5c5SDavid van Moolenbroek     if (autologin && user == NULL) {
2377*7348b5c5SDavid van Moolenbroek 	struct passwd *pw;
2378*7348b5c5SDavid van Moolenbroek 
2379*7348b5c5SDavid van Moolenbroek 	user = getenv("USER");
2380*7348b5c5SDavid van Moolenbroek 	if (user == NULL ||
2381*7348b5c5SDavid van Moolenbroek 	    ((pw = getpwnam(user)) && pw->pw_uid != getuid())) {
2382*7348b5c5SDavid van Moolenbroek 		if ((pw = getpwuid(getuid())) != NULL)
2383*7348b5c5SDavid van Moolenbroek 			user = pw->pw_name;
2384*7348b5c5SDavid van Moolenbroek 		else
2385*7348b5c5SDavid van Moolenbroek 			user = NULL;
2386*7348b5c5SDavid van Moolenbroek 	}
2387*7348b5c5SDavid van Moolenbroek     }
2388*7348b5c5SDavid van Moolenbroek     if (user) {
2389*7348b5c5SDavid van Moolenbroek 	env_define((const unsigned char *)"USER", __UNCONST(user));
2390*7348b5c5SDavid van Moolenbroek 	env_export((const unsigned char *)"USER", NULL);
2391*7348b5c5SDavid van Moolenbroek     }
2392*7348b5c5SDavid van Moolenbroek     (void) call(status, "status", "notmuch", 0);
2393*7348b5c5SDavid van Moolenbroek     telnet(user);
2394*7348b5c5SDavid van Moolenbroek     (void) NetClose(net);
2395*7348b5c5SDavid van Moolenbroek     ExitString("Connection closed by foreign host.\n",1);
2396*7348b5c5SDavid van Moolenbroek     /*NOTREACHED*/
2397*7348b5c5SDavid van Moolenbroek }
2398*7348b5c5SDavid van Moolenbroek 
2399*7348b5c5SDavid van Moolenbroek #define HELPINDENT ((int)sizeof ("connect"))
2400*7348b5c5SDavid van Moolenbroek 
2401*7348b5c5SDavid van Moolenbroek static char
2402*7348b5c5SDavid van Moolenbroek 	openhelp[] =	"connect to a site",
2403*7348b5c5SDavid van Moolenbroek 	closehelp[] =	"close current connection",
2404*7348b5c5SDavid van Moolenbroek 	logouthelp[] =	"forcibly logout remote user and close the connection",
2405*7348b5c5SDavid van Moolenbroek 	quithelp[] =	"exit telnet",
2406*7348b5c5SDavid van Moolenbroek 	statushelp[] =	"print status information",
2407*7348b5c5SDavid van Moolenbroek 	helphelp[] =	"print help information",
2408*7348b5c5SDavid van Moolenbroek 	sendhelp[] =	"transmit special characters ('send ?' for more)",
2409*7348b5c5SDavid van Moolenbroek 	sethelp[] = 	"set operating parameters ('set ?' for more)",
2410*7348b5c5SDavid van Moolenbroek 	unsethelp[] = 	"unset operating parameters ('unset ?' for more)",
2411*7348b5c5SDavid van Moolenbroek 	togglestring[] ="toggle operating parameters ('toggle ?' for more)",
2412*7348b5c5SDavid van Moolenbroek 	slchelp[] =	"change state of special characters ('slc ?' for more)",
2413*7348b5c5SDavid van Moolenbroek 	displayhelp[] =	"display operating parameters",
2414*7348b5c5SDavid van Moolenbroek #ifdef TN3270
2415*7348b5c5SDavid van Moolenbroek 	transcomhelp[] = "specify Unix command for transparent mode pipe",
2416*7348b5c5SDavid van Moolenbroek #endif	/* defined(TN3270) */
2417*7348b5c5SDavid van Moolenbroek #ifdef AUTHENTICATION
2418*7348b5c5SDavid van Moolenbroek 	authhelp[] =	"turn on (off) authentication ('auth ?' for more)",
2419*7348b5c5SDavid van Moolenbroek #endif
2420*7348b5c5SDavid van Moolenbroek #ifdef	ENCRYPTION
2421*7348b5c5SDavid van Moolenbroek 	encrypthelp[] = "turn on (off) encryption ('encrypt ?' for more)",
2422*7348b5c5SDavid van Moolenbroek #endif	/* ENCRYPTION */
2423*7348b5c5SDavid van Moolenbroek 	zhelp[] =	"suspend telnet",
2424*7348b5c5SDavid van Moolenbroek 	shellhelp[] =	"invoke a subshell",
2425*7348b5c5SDavid van Moolenbroek 	envhelp[] =	"change environment variables ('environ ?' for more)",
2426*7348b5c5SDavid van Moolenbroek 	modestring[] = "try to enter line or character mode ('mode ?' for more)";
2427*7348b5c5SDavid van Moolenbroek 
2428*7348b5c5SDavid van Moolenbroek static Command cmdtab[] = {
2429*7348b5c5SDavid van Moolenbroek 	{ "close",	closehelp,	bye,		1 },
2430*7348b5c5SDavid van Moolenbroek 	{ "logout",	logouthelp,	logout,		1 },
2431*7348b5c5SDavid van Moolenbroek 	{ "display",	displayhelp,	display,	0 },
2432*7348b5c5SDavid van Moolenbroek 	{ "mode",	modestring,	modecmd,	0 },
2433*7348b5c5SDavid van Moolenbroek 	{ "open",	openhelp,	tn,		0 },
2434*7348b5c5SDavid van Moolenbroek 	{ "quit",	quithelp,	quit,		0 },
2435*7348b5c5SDavid van Moolenbroek 	{ "send",	sendhelp,	sendcmd,	0 },
2436*7348b5c5SDavid van Moolenbroek 	{ "set",	sethelp,	setcmd,		0 },
2437*7348b5c5SDavid van Moolenbroek 	{ "unset",	unsethelp,	unsetcmd,	0 },
2438*7348b5c5SDavid van Moolenbroek 	{ "status",	statushelp,	status,		0 },
2439*7348b5c5SDavid van Moolenbroek 	{ "toggle",	togglestring,	toggle,		0 },
2440*7348b5c5SDavid van Moolenbroek 	{ "slc",	slchelp,	slccmd,		0 },
2441*7348b5c5SDavid van Moolenbroek #ifdef TN3270
2442*7348b5c5SDavid van Moolenbroek 	{ "transcom",	transcomhelp,	settranscom,	0 },
2443*7348b5c5SDavid van Moolenbroek #endif	/* defined(TN3270) */
2444*7348b5c5SDavid van Moolenbroek #ifdef AUTHENTICATION
2445*7348b5c5SDavid van Moolenbroek 	{ "auth",	authhelp,	auth_cmd,	0 },
2446*7348b5c5SDavid van Moolenbroek #endif
2447*7348b5c5SDavid van Moolenbroek #ifdef	ENCRYPTION
2448*7348b5c5SDavid van Moolenbroek 	{ "encrypt",	encrypthelp,	encrypt_cmd,	0 },
2449*7348b5c5SDavid van Moolenbroek #endif
2450*7348b5c5SDavid van Moolenbroek 	{ "z",		zhelp,		suspend,	0 },
2451*7348b5c5SDavid van Moolenbroek #ifdef TN3270
2452*7348b5c5SDavid van Moolenbroek 	{ "!",		shellhelp,	shell,		1 },
2453*7348b5c5SDavid van Moolenbroek #else
2454*7348b5c5SDavid van Moolenbroek 	{ "!",		shellhelp,	shell,		0 },
2455*7348b5c5SDavid van Moolenbroek #endif
2456*7348b5c5SDavid van Moolenbroek 	{ "environ",	envhelp,	env_cmd,	0 },
2457*7348b5c5SDavid van Moolenbroek 	{ "?",		helphelp,	help,		0 },
2458*7348b5c5SDavid van Moolenbroek 	{ NULL,		NULL,		NULL,		0 }
2459*7348b5c5SDavid van Moolenbroek };
2460*7348b5c5SDavid van Moolenbroek 
2461*7348b5c5SDavid van Moolenbroek static char	crmodhelp[] =	"deprecated command -- use 'toggle crmod' instead";
2462*7348b5c5SDavid van Moolenbroek static char	escapehelp[] =	"deprecated command -- use 'set escape' instead";
2463*7348b5c5SDavid van Moolenbroek 
2464*7348b5c5SDavid van Moolenbroek static Command cmdtab2[] = {
2465*7348b5c5SDavid van Moolenbroek 	{ "help",	0,		help,		0 },
2466*7348b5c5SDavid van Moolenbroek 	{ "escape",	escapehelp,	setescape,	0 },
2467*7348b5c5SDavid van Moolenbroek 	{ "crmod",	crmodhelp,	togcrmod,	0 },
2468*7348b5c5SDavid van Moolenbroek 	{ NULL,		NULL,		NULL,		0 }
2469*7348b5c5SDavid van Moolenbroek };
2470*7348b5c5SDavid van Moolenbroek 
2471*7348b5c5SDavid van Moolenbroek 
2472*7348b5c5SDavid van Moolenbroek /*
2473*7348b5c5SDavid van Moolenbroek  * Call routine with argc, argv set from args (terminated by 0).
2474*7348b5c5SDavid van Moolenbroek  */
2475*7348b5c5SDavid van Moolenbroek 
2476*7348b5c5SDavid van Moolenbroek /*VARARGS1*/
2477*7348b5c5SDavid van Moolenbroek static int
call(intrtn_t routine,...)2478*7348b5c5SDavid van Moolenbroek call(intrtn_t routine, ...)
2479*7348b5c5SDavid van Moolenbroek {
2480*7348b5c5SDavid van Moolenbroek     va_list ap;
2481*7348b5c5SDavid van Moolenbroek     char *args[100];
2482*7348b5c5SDavid van Moolenbroek     int argno = 0;
2483*7348b5c5SDavid van Moolenbroek 
2484*7348b5c5SDavid van Moolenbroek     va_start(ap, routine);
2485*7348b5c5SDavid van Moolenbroek     while ((args[argno++] = va_arg(ap, char *)) != 0) {
2486*7348b5c5SDavid van Moolenbroek 	;
2487*7348b5c5SDavid van Moolenbroek     }
2488*7348b5c5SDavid van Moolenbroek     va_end(ap);
2489*7348b5c5SDavid van Moolenbroek     return (*routine)(argno-1, args);
2490*7348b5c5SDavid van Moolenbroek }
2491*7348b5c5SDavid van Moolenbroek 
2492*7348b5c5SDavid van Moolenbroek 
2493*7348b5c5SDavid van Moolenbroek static Command *
getcmd(char * name)2494*7348b5c5SDavid van Moolenbroek getcmd(char *name)
2495*7348b5c5SDavid van Moolenbroek {
2496*7348b5c5SDavid van Moolenbroek     Command *cm;
2497*7348b5c5SDavid van Moolenbroek 
2498*7348b5c5SDavid van Moolenbroek     if ((cm = (Command *) genget(name, (char **) cmdtab, sizeof(Command))) != NULL)
2499*7348b5c5SDavid van Moolenbroek 	return cm;
2500*7348b5c5SDavid van Moolenbroek     return (Command *) genget(name, (char **) cmdtab2, sizeof(Command));
2501*7348b5c5SDavid van Moolenbroek }
2502*7348b5c5SDavid van Moolenbroek 
2503*7348b5c5SDavid van Moolenbroek void
command(int top,const char * tbuf,int cnt)2504*7348b5c5SDavid van Moolenbroek command(int top, const char *tbuf, int cnt)
2505*7348b5c5SDavid van Moolenbroek {
2506*7348b5c5SDavid van Moolenbroek     Command *c;
2507*7348b5c5SDavid van Moolenbroek 
2508*7348b5c5SDavid van Moolenbroek     setcommandmode();
2509*7348b5c5SDavid van Moolenbroek     if (!top) {
2510*7348b5c5SDavid van Moolenbroek 	putchar('\n');
2511*7348b5c5SDavid van Moolenbroek     } else {
2512*7348b5c5SDavid van Moolenbroek 	(void) signal(SIGINT, SIG_DFL);
2513*7348b5c5SDavid van Moolenbroek 	(void) signal(SIGQUIT, SIG_DFL);
2514*7348b5c5SDavid van Moolenbroek     }
2515*7348b5c5SDavid van Moolenbroek     for (;;) {
2516*7348b5c5SDavid van Moolenbroek 	if (rlogin == _POSIX_VDISABLE)
2517*7348b5c5SDavid van Moolenbroek 		printf("%s> ", prompt);
2518*7348b5c5SDavid van Moolenbroek 	if (tbuf) {
2519*7348b5c5SDavid van Moolenbroek 	    char *cp;
2520*7348b5c5SDavid van Moolenbroek 	    cp = line;
2521*7348b5c5SDavid van Moolenbroek 	    while (cnt > 0 && (*cp++ = *tbuf++) != '\n')
2522*7348b5c5SDavid van Moolenbroek 		cnt--;
2523*7348b5c5SDavid van Moolenbroek 	    tbuf = 0;
2524*7348b5c5SDavid van Moolenbroek 	    if (cp == line || *--cp != '\n' || cp == line)
2525*7348b5c5SDavid van Moolenbroek 		goto getline;
2526*7348b5c5SDavid van Moolenbroek 	    *cp = '\0';
2527*7348b5c5SDavid van Moolenbroek 	    if (rlogin == _POSIX_VDISABLE)
2528*7348b5c5SDavid van Moolenbroek 		printf("%s\n", line);
2529*7348b5c5SDavid van Moolenbroek 	} else {
2530*7348b5c5SDavid van Moolenbroek 	getline:
2531*7348b5c5SDavid van Moolenbroek 	    if (rlogin != _POSIX_VDISABLE)
2532*7348b5c5SDavid van Moolenbroek 		printf("%s> ", prompt);
2533*7348b5c5SDavid van Moolenbroek #ifdef TN3270
2534*7348b5c5SDavid van Moolenbroek 	    fflush(stdout);
2535*7348b5c5SDavid van Moolenbroek #endif
2536*7348b5c5SDavid van Moolenbroek 	    if (fgets(line, sizeof(line), stdin) == NULL) {
2537*7348b5c5SDavid van Moolenbroek 		if (feof(stdin) || ferror(stdin)) {
2538*7348b5c5SDavid van Moolenbroek 		    (void) quit(0, NULL);
2539*7348b5c5SDavid van Moolenbroek 		    /*NOTREACHED*/
2540*7348b5c5SDavid van Moolenbroek 		}
2541*7348b5c5SDavid van Moolenbroek 		break;
2542*7348b5c5SDavid van Moolenbroek 	    }
2543*7348b5c5SDavid van Moolenbroek 	}
2544*7348b5c5SDavid van Moolenbroek 	if (line[0] == 0)
2545*7348b5c5SDavid van Moolenbroek 	    break;
2546*7348b5c5SDavid van Moolenbroek 	makeargv();
2547*7348b5c5SDavid van Moolenbroek 	if (margv[0] == 0) {
2548*7348b5c5SDavid van Moolenbroek 	    break;
2549*7348b5c5SDavid van Moolenbroek 	}
2550*7348b5c5SDavid van Moolenbroek 	c = getcmd(margv[0]);
2551*7348b5c5SDavid van Moolenbroek 	if (Ambiguous(c)) {
2552*7348b5c5SDavid van Moolenbroek 	    printf("?Ambiguous command\n");
2553*7348b5c5SDavid van Moolenbroek 	    continue;
2554*7348b5c5SDavid van Moolenbroek 	}
2555*7348b5c5SDavid van Moolenbroek 	if (c == 0) {
2556*7348b5c5SDavid van Moolenbroek 	    printf("?Invalid command\n");
2557*7348b5c5SDavid van Moolenbroek 	    continue;
2558*7348b5c5SDavid van Moolenbroek 	}
2559*7348b5c5SDavid van Moolenbroek 	if (c->needconnect && !connected) {
2560*7348b5c5SDavid van Moolenbroek 	    printf("?Need to be connected first.\n");
2561*7348b5c5SDavid van Moolenbroek 	    continue;
2562*7348b5c5SDavid van Moolenbroek 	}
2563*7348b5c5SDavid van Moolenbroek 	if ((*c->handler)(margc, margv)) {
2564*7348b5c5SDavid van Moolenbroek 	    break;
2565*7348b5c5SDavid van Moolenbroek 	}
2566*7348b5c5SDavid van Moolenbroek     }
2567*7348b5c5SDavid van Moolenbroek     if (!top) {
2568*7348b5c5SDavid van Moolenbroek 	if (!connected) {
2569*7348b5c5SDavid van Moolenbroek 	    longjmp(toplevel, 1);
2570*7348b5c5SDavid van Moolenbroek 	    /*NOTREACHED*/
2571*7348b5c5SDavid van Moolenbroek 	}
2572*7348b5c5SDavid van Moolenbroek #ifdef TN3270
2573*7348b5c5SDavid van Moolenbroek 	if (shell_active == 0) {
2574*7348b5c5SDavid van Moolenbroek 	    setconnmode(0);
2575*7348b5c5SDavid van Moolenbroek 	}
2576*7348b5c5SDavid van Moolenbroek #else	/* defined(TN3270) */
2577*7348b5c5SDavid van Moolenbroek 	setconnmode(0);
2578*7348b5c5SDavid van Moolenbroek #endif	/* defined(TN3270) */
2579*7348b5c5SDavid van Moolenbroek     }
2580*7348b5c5SDavid van Moolenbroek }
2581*7348b5c5SDavid van Moolenbroek 
2582*7348b5c5SDavid van Moolenbroek /*
2583*7348b5c5SDavid van Moolenbroek  * Help command.
2584*7348b5c5SDavid van Moolenbroek  */
2585*7348b5c5SDavid van Moolenbroek static int
help(int argc,char * argv[])2586*7348b5c5SDavid van Moolenbroek help(int argc, char *argv[])
2587*7348b5c5SDavid van Moolenbroek {
2588*7348b5c5SDavid van Moolenbroek 	Command *c;
2589*7348b5c5SDavid van Moolenbroek 
2590*7348b5c5SDavid van Moolenbroek 	if (argc == 1) {
2591*7348b5c5SDavid van Moolenbroek 		printf("Commands may be abbreviated.  Commands are:\n\n");
2592*7348b5c5SDavid van Moolenbroek 		for (c = cmdtab; c->name; c++)
2593*7348b5c5SDavid van Moolenbroek 			if (c->help) {
2594*7348b5c5SDavid van Moolenbroek 				printf("%-*s\t%s\n", HELPINDENT, c->name,
2595*7348b5c5SDavid van Moolenbroek 								    c->help);
2596*7348b5c5SDavid van Moolenbroek 			}
2597*7348b5c5SDavid van Moolenbroek 		return 0;
2598*7348b5c5SDavid van Moolenbroek 	}
2599*7348b5c5SDavid van Moolenbroek 	while (--argc > 0) {
2600*7348b5c5SDavid van Moolenbroek 		char *arg;
2601*7348b5c5SDavid van Moolenbroek 		arg = *++argv;
2602*7348b5c5SDavid van Moolenbroek 		c = getcmd(arg);
2603*7348b5c5SDavid van Moolenbroek 		if (Ambiguous(c))
2604*7348b5c5SDavid van Moolenbroek 			printf("?Ambiguous help command %s\n", arg);
2605*7348b5c5SDavid van Moolenbroek 		else if (c == (Command *)0)
2606*7348b5c5SDavid van Moolenbroek 			printf("?Invalid help command %s\n", arg);
2607*7348b5c5SDavid van Moolenbroek 		else
2608*7348b5c5SDavid van Moolenbroek 			printf("%s\n", c->help);
2609*7348b5c5SDavid van Moolenbroek 	}
2610*7348b5c5SDavid van Moolenbroek 	return 0;
2611*7348b5c5SDavid van Moolenbroek }
2612*7348b5c5SDavid van Moolenbroek 
2613*7348b5c5SDavid van Moolenbroek static char *rcname = 0;
2614*7348b5c5SDavid van Moolenbroek static char rcbuf[128];
2615*7348b5c5SDavid van Moolenbroek 
2616*7348b5c5SDavid van Moolenbroek void
cmdrc(const char * m1,const char * m2)2617*7348b5c5SDavid van Moolenbroek cmdrc(const char *m1, const char *m2)
2618*7348b5c5SDavid van Moolenbroek {
2619*7348b5c5SDavid van Moolenbroek     Command *c;
2620*7348b5c5SDavid van Moolenbroek     FILE *rcfile;
2621*7348b5c5SDavid van Moolenbroek     int gotmachine = 0;
2622*7348b5c5SDavid van Moolenbroek     int l1 = strlen(m1);
2623*7348b5c5SDavid van Moolenbroek     int l2 = strlen(m2);
2624*7348b5c5SDavid van Moolenbroek     char m1save[MAXHOSTNAMELEN + 1];
2625*7348b5c5SDavid van Moolenbroek 
2626*7348b5c5SDavid van Moolenbroek     if (skiprc)
2627*7348b5c5SDavid van Moolenbroek 	return;
2628*7348b5c5SDavid van Moolenbroek 
2629*7348b5c5SDavid van Moolenbroek     strlcpy(m1save, m1, sizeof(m1save));
2630*7348b5c5SDavid van Moolenbroek     m1 = m1save;
2631*7348b5c5SDavid van Moolenbroek 
2632*7348b5c5SDavid van Moolenbroek     if (rcname == 0) {
2633*7348b5c5SDavid van Moolenbroek 	rcname = getenv("HOME");
2634*7348b5c5SDavid van Moolenbroek 	if (rcname)
2635*7348b5c5SDavid van Moolenbroek 	    strlcpy(rcbuf, rcname, sizeof(rcbuf));
2636*7348b5c5SDavid van Moolenbroek 	else
2637*7348b5c5SDavid van Moolenbroek 	    rcbuf[0] = '\0';
2638*7348b5c5SDavid van Moolenbroek 	strlcat(rcbuf, "/.telnetrc", sizeof(rcbuf));
2639*7348b5c5SDavid van Moolenbroek 	rcname = rcbuf;
2640*7348b5c5SDavid van Moolenbroek     }
2641*7348b5c5SDavid van Moolenbroek 
2642*7348b5c5SDavid van Moolenbroek     if ((rcfile = fopen(rcname, "r")) == 0) {
2643*7348b5c5SDavid van Moolenbroek 	return;
2644*7348b5c5SDavid van Moolenbroek     }
2645*7348b5c5SDavid van Moolenbroek 
2646*7348b5c5SDavid van Moolenbroek     for (;;) {
2647*7348b5c5SDavid van Moolenbroek 	if (fgets(line, sizeof(line), rcfile) == NULL)
2648*7348b5c5SDavid van Moolenbroek 	    break;
2649*7348b5c5SDavid van Moolenbroek 	if (line[0] == 0)
2650*7348b5c5SDavid van Moolenbroek 	    break;
2651*7348b5c5SDavid van Moolenbroek 	if (line[0] == '#')
2652*7348b5c5SDavid van Moolenbroek 	    continue;
2653*7348b5c5SDavid van Moolenbroek 	if (gotmachine) {
2654*7348b5c5SDavid van Moolenbroek 	    if (!isspace((unsigned char)line[0]))
2655*7348b5c5SDavid van Moolenbroek 		gotmachine = 0;
2656*7348b5c5SDavid van Moolenbroek 	}
2657*7348b5c5SDavid van Moolenbroek 	if (gotmachine == 0) {
2658*7348b5c5SDavid van Moolenbroek 	    if (isspace((unsigned char)line[0]))
2659*7348b5c5SDavid van Moolenbroek 		continue;
2660*7348b5c5SDavid van Moolenbroek 	    if (strncasecmp(line, m1, l1) == 0)
2661*7348b5c5SDavid van Moolenbroek 		strncpy(line, &line[l1], sizeof(line) - l1);
2662*7348b5c5SDavid van Moolenbroek 	    else if (strncasecmp(line, m2, l2) == 0)
2663*7348b5c5SDavid van Moolenbroek 		strncpy(line, &line[l2], sizeof(line) - l2);
2664*7348b5c5SDavid van Moolenbroek 	    else if (strncasecmp(line, "DEFAULT", 7) == 0)
2665*7348b5c5SDavid van Moolenbroek 		strncpy(line, &line[7], sizeof(line) - 7);
2666*7348b5c5SDavid van Moolenbroek 	    else
2667*7348b5c5SDavid van Moolenbroek 		continue;
2668*7348b5c5SDavid van Moolenbroek 	    if (line[0] != ' ' && line[0] != '\t' && line[0] != '\n')
2669*7348b5c5SDavid van Moolenbroek 		continue;
2670*7348b5c5SDavid van Moolenbroek 	    gotmachine = 1;
2671*7348b5c5SDavid van Moolenbroek 	}
2672*7348b5c5SDavid van Moolenbroek 	makeargv();
2673*7348b5c5SDavid van Moolenbroek 	if (margv[0] == 0)
2674*7348b5c5SDavid van Moolenbroek 	    continue;
2675*7348b5c5SDavid van Moolenbroek 	c = getcmd(margv[0]);
2676*7348b5c5SDavid van Moolenbroek 	if (Ambiguous(c)) {
2677*7348b5c5SDavid van Moolenbroek 	    printf("?Ambiguous command: %s\n", margv[0]);
2678*7348b5c5SDavid van Moolenbroek 	    continue;
2679*7348b5c5SDavid van Moolenbroek 	}
2680*7348b5c5SDavid van Moolenbroek 	if (c == 0) {
2681*7348b5c5SDavid van Moolenbroek 	    printf("?Invalid command: %s\n", margv[0]);
2682*7348b5c5SDavid van Moolenbroek 	    continue;
2683*7348b5c5SDavid van Moolenbroek 	}
2684*7348b5c5SDavid van Moolenbroek 	/*
2685*7348b5c5SDavid van Moolenbroek 	 * This should never happen...
2686*7348b5c5SDavid van Moolenbroek 	 */
2687*7348b5c5SDavid van Moolenbroek 	if (c->needconnect && !connected) {
2688*7348b5c5SDavid van Moolenbroek 	    printf("?Need to be connected first for %s.\n", margv[0]);
2689*7348b5c5SDavid van Moolenbroek 	    continue;
2690*7348b5c5SDavid van Moolenbroek 	}
2691*7348b5c5SDavid van Moolenbroek 	(*c->handler)(margc, margv);
2692*7348b5c5SDavid van Moolenbroek     }
2693*7348b5c5SDavid van Moolenbroek     fclose(rcfile);
2694*7348b5c5SDavid van Moolenbroek }
2695*7348b5c5SDavid van Moolenbroek 
2696*7348b5c5SDavid van Moolenbroek /*
2697*7348b5c5SDavid van Moolenbroek  * Source route is handed in as
2698*7348b5c5SDavid van Moolenbroek  *	[!]@hop1@hop2...@dst
2699*7348b5c5SDavid van Moolenbroek  *
2700*7348b5c5SDavid van Moolenbroek  * If the leading ! is present, it is a strict source route, otherwise it is
2701*7348b5c5SDavid van Moolenbroek  * assmed to be a loose source route.  Note that leading ! is effective
2702*7348b5c5SDavid van Moolenbroek  * only for IPv4 case.
2703*7348b5c5SDavid van Moolenbroek  *
2704*7348b5c5SDavid van Moolenbroek  * We fill in the source route option as
2705*7348b5c5SDavid van Moolenbroek  *	hop1,hop2,hop3...dest
2706*7348b5c5SDavid van Moolenbroek  * and return a pointer to hop1, which will
2707*7348b5c5SDavid van Moolenbroek  * be the address to connect() to.
2708*7348b5c5SDavid van Moolenbroek  *
2709*7348b5c5SDavid van Moolenbroek  * Arguments:
2710*7348b5c5SDavid van Moolenbroek  *	ai:	The address (by struct addrinfo) for the final destination.
2711*7348b5c5SDavid van Moolenbroek  *
2712*7348b5c5SDavid van Moolenbroek  *	arg:	Pointer to route list to decipher
2713*7348b5c5SDavid van Moolenbroek  *
2714*7348b5c5SDavid van Moolenbroek  *	cpp: 	Pointer to a pointer, so that sourceroute() can return
2715*7348b5c5SDavid van Moolenbroek  *		the address of result buffer (statically alloc'ed).
2716*7348b5c5SDavid van Moolenbroek  *
2717*7348b5c5SDavid van Moolenbroek  *	protop/optp:
2718*7348b5c5SDavid van Moolenbroek  *		Pointer to an integer.  The pointed variable
2719*7348b5c5SDavid van Moolenbroek  *	lenp:	pointer to an integer that contains the
2720*7348b5c5SDavid van Moolenbroek  *		length of *cpp if *cpp != NULL.
2721*7348b5c5SDavid van Moolenbroek  *
2722*7348b5c5SDavid van Moolenbroek  * Return values:
2723*7348b5c5SDavid van Moolenbroek  *
2724*7348b5c5SDavid van Moolenbroek  *	Returns the length of the option pointed to by *cpp.  If the
2725*7348b5c5SDavid van Moolenbroek  *	return value is -1, there was a syntax error in the
2726*7348b5c5SDavid van Moolenbroek  *	option, either arg contained unknown characters or too many hosts,
2727*7348b5c5SDavid van Moolenbroek  *	or hostname cannot be resolved.
2728*7348b5c5SDavid van Moolenbroek  *
2729*7348b5c5SDavid van Moolenbroek  *	The caller needs to pass return value (len), *cpp, *protop and *optp
2730*7348b5c5SDavid van Moolenbroek  *	to setsockopt(2).
2731*7348b5c5SDavid van Moolenbroek  *
2732*7348b5c5SDavid van Moolenbroek  *	*cpp:	Points to the result buffer.  The region is statically
2733*7348b5c5SDavid van Moolenbroek  *		allocated by the function.
2734*7348b5c5SDavid van Moolenbroek  *
2735*7348b5c5SDavid van Moolenbroek  *	*protop:
2736*7348b5c5SDavid van Moolenbroek  *		protocol # to be passed to setsockopt(2).
2737*7348b5c5SDavid van Moolenbroek  *
2738*7348b5c5SDavid van Moolenbroek  *	*optp:	option # to be passed to setsockopt(2).
2739*7348b5c5SDavid van Moolenbroek  *
2740*7348b5c5SDavid van Moolenbroek  */
2741*7348b5c5SDavid van Moolenbroek int
sourceroute(struct addrinfo * ai,char * arg,char ** cpp,int * protop,int * optp)2742*7348b5c5SDavid van Moolenbroek sourceroute(struct addrinfo *ai, char *arg, char **cpp, int *protop, int *optp)
2743*7348b5c5SDavid van Moolenbroek {
2744*7348b5c5SDavid van Moolenbroek 	char *cp, *cp2, *lsrp, *lsrep;
2745*7348b5c5SDavid van Moolenbroek 	struct addrinfo hints, *res;
2746*7348b5c5SDavid van Moolenbroek 	int len, error;
2747*7348b5c5SDavid van Moolenbroek 	struct sockaddr_in *sin;
2748*7348b5c5SDavid van Moolenbroek 	char c;
2749*7348b5c5SDavid van Moolenbroek 	static char lsr[44];
2750*7348b5c5SDavid van Moolenbroek #ifdef INET6
2751*7348b5c5SDavid van Moolenbroek 	struct cmsghdr *cmsg;
2752*7348b5c5SDavid van Moolenbroek 	struct sockaddr_in6 *sin6;
2753*7348b5c5SDavid van Moolenbroek 	static char rhbuf[1024];
2754*7348b5c5SDavid van Moolenbroek #endif
2755*7348b5c5SDavid van Moolenbroek 
2756*7348b5c5SDavid van Moolenbroek 	/*
2757*7348b5c5SDavid van Moolenbroek 	 * Verify the arguments.
2758*7348b5c5SDavid van Moolenbroek 	 */
2759*7348b5c5SDavid van Moolenbroek 	if (cpp == NULL)
2760*7348b5c5SDavid van Moolenbroek 		return -1;
2761*7348b5c5SDavid van Moolenbroek 
2762*7348b5c5SDavid van Moolenbroek 	cp = arg;
2763*7348b5c5SDavid van Moolenbroek 
2764*7348b5c5SDavid van Moolenbroek 	*cpp = NULL;
2765*7348b5c5SDavid van Moolenbroek 
2766*7348b5c5SDavid van Moolenbroek 	  /* init these just in case.... */
2767*7348b5c5SDavid van Moolenbroek 	lsrp = NULL;
2768*7348b5c5SDavid van Moolenbroek 	lsrep = NULL;
2769*7348b5c5SDavid van Moolenbroek #ifdef INET6
2770*7348b5c5SDavid van Moolenbroek 	cmsg = NULL;
2771*7348b5c5SDavid van Moolenbroek #endif
2772*7348b5c5SDavid van Moolenbroek 
2773*7348b5c5SDavid van Moolenbroek 	switch (ai->ai_family) {
2774*7348b5c5SDavid van Moolenbroek 	case AF_INET:
2775*7348b5c5SDavid van Moolenbroek 		lsrp = lsr;
2776*7348b5c5SDavid van Moolenbroek 		lsrep = lsrp + sizeof(lsr);
2777*7348b5c5SDavid van Moolenbroek 
2778*7348b5c5SDavid van Moolenbroek 		/*
2779*7348b5c5SDavid van Moolenbroek 		 * Next, decide whether we have a loose source
2780*7348b5c5SDavid van Moolenbroek 		 * route or a strict source route, and fill in
2781*7348b5c5SDavid van Moolenbroek 		 * the begining of the option.
2782*7348b5c5SDavid van Moolenbroek 		 */
2783*7348b5c5SDavid van Moolenbroek 		if (*cp == '!') {
2784*7348b5c5SDavid van Moolenbroek 			cp++;
2785*7348b5c5SDavid van Moolenbroek 			*lsrp++ = IPOPT_SSRR;
2786*7348b5c5SDavid van Moolenbroek 		} else
2787*7348b5c5SDavid van Moolenbroek 			*lsrp++ = IPOPT_LSRR;
2788*7348b5c5SDavid van Moolenbroek 		if (*cp != '@')
2789*7348b5c5SDavid van Moolenbroek 			return -1;
2790*7348b5c5SDavid van Moolenbroek 		lsrp++;		/* skip over length, we'll fill it in later */
2791*7348b5c5SDavid van Moolenbroek 		*lsrp++ = 4;
2792*7348b5c5SDavid van Moolenbroek 		cp++;
2793*7348b5c5SDavid van Moolenbroek 		*protop = IPPROTO_IP;
2794*7348b5c5SDavid van Moolenbroek 		*optp = IP_OPTIONS;
2795*7348b5c5SDavid van Moolenbroek 		break;
2796*7348b5c5SDavid van Moolenbroek #ifdef INET6
2797*7348b5c5SDavid van Moolenbroek 	case AF_INET6:
2798*7348b5c5SDavid van Moolenbroek #ifdef IPV6_PKTOPTIONS
2799*7348b5c5SDavid van Moolenbroek 		/* RFC2292 */
2800*7348b5c5SDavid van Moolenbroek 		cmsg = inet6_rthdr_init(rhbuf, IPV6_RTHDR_TYPE_0);
2801*7348b5c5SDavid van Moolenbroek 		if (*cp != '@')
2802*7348b5c5SDavid van Moolenbroek 			return -1;
2803*7348b5c5SDavid van Moolenbroek 		cp++;
2804*7348b5c5SDavid van Moolenbroek 		*protop = IPPROTO_IPV6;
2805*7348b5c5SDavid van Moolenbroek 		*optp = IPV6_PKTOPTIONS;
2806*7348b5c5SDavid van Moolenbroek 		break;
2807*7348b5c5SDavid van Moolenbroek #else
2808*7348b5c5SDavid van Moolenbroek 		/* no RFC2292 */
2809*7348b5c5SDavid van Moolenbroek 		return -1;
2810*7348b5c5SDavid van Moolenbroek #endif
2811*7348b5c5SDavid van Moolenbroek #endif
2812*7348b5c5SDavid van Moolenbroek 	default:
2813*7348b5c5SDavid van Moolenbroek 		return -1;
2814*7348b5c5SDavid van Moolenbroek 	}
2815*7348b5c5SDavid van Moolenbroek 
2816*7348b5c5SDavid van Moolenbroek 	memset(&hints, 0, sizeof(hints));
2817*7348b5c5SDavid van Moolenbroek 	hints.ai_family = ai->ai_family;
2818*7348b5c5SDavid van Moolenbroek 	hints.ai_socktype = SOCK_STREAM;
2819*7348b5c5SDavid van Moolenbroek 
2820*7348b5c5SDavid van Moolenbroek 	for (c = 0;;) {
2821*7348b5c5SDavid van Moolenbroek 		if (c == ':')
2822*7348b5c5SDavid van Moolenbroek 			cp2 = 0;
2823*7348b5c5SDavid van Moolenbroek 		else for (cp2 = cp; (c = *cp2) != '\0'; cp2++) {
2824*7348b5c5SDavid van Moolenbroek 			if (c == ',') {
2825*7348b5c5SDavid van Moolenbroek 				*cp2++ = '\0';
2826*7348b5c5SDavid van Moolenbroek 				if (*cp2 == '@')
2827*7348b5c5SDavid van Moolenbroek 					cp2++;
2828*7348b5c5SDavid van Moolenbroek 			} else if (c == '@') {
2829*7348b5c5SDavid van Moolenbroek 				*cp2++ = '\0';
2830*7348b5c5SDavid van Moolenbroek 			}
2831*7348b5c5SDavid van Moolenbroek #if 0	/*colon conflicts with IPv6 address*/
2832*7348b5c5SDavid van Moolenbroek 			else if (c == ':') {
2833*7348b5c5SDavid van Moolenbroek 				*cp2++ = '\0';
2834*7348b5c5SDavid van Moolenbroek 			}
2835*7348b5c5SDavid van Moolenbroek #endif
2836*7348b5c5SDavid van Moolenbroek 			else
2837*7348b5c5SDavid van Moolenbroek 				continue;
2838*7348b5c5SDavid van Moolenbroek 			break;
2839*7348b5c5SDavid van Moolenbroek 		}
2840*7348b5c5SDavid van Moolenbroek 		if (!c)
2841*7348b5c5SDavid van Moolenbroek 			cp2 = 0;
2842*7348b5c5SDavid van Moolenbroek 
2843*7348b5c5SDavid van Moolenbroek 		error = getaddrinfo(cp, NULL, &hints, &res);
2844*7348b5c5SDavid van Moolenbroek 		if (error) {
2845*7348b5c5SDavid van Moolenbroek 			fprintf(stderr, "%s: %s\n", cp, gai_strerror(error));
2846*7348b5c5SDavid van Moolenbroek 			return -1;
2847*7348b5c5SDavid van Moolenbroek 		}
2848*7348b5c5SDavid van Moolenbroek 		if (ai->ai_family != res->ai_family) {
2849*7348b5c5SDavid van Moolenbroek 			freeaddrinfo(res);
2850*7348b5c5SDavid van Moolenbroek 			return -1;
2851*7348b5c5SDavid van Moolenbroek 		}
2852*7348b5c5SDavid van Moolenbroek 		if (ai->ai_family == AF_INET) {
2853*7348b5c5SDavid van Moolenbroek 			/*
2854*7348b5c5SDavid van Moolenbroek 			 * Check to make sure there is space for address
2855*7348b5c5SDavid van Moolenbroek 			 */
2856*7348b5c5SDavid van Moolenbroek 			if (lsrp + 4 > lsrep) {
2857*7348b5c5SDavid van Moolenbroek 				freeaddrinfo(res);
2858*7348b5c5SDavid van Moolenbroek 				return -1;
2859*7348b5c5SDavid van Moolenbroek 			}
2860*7348b5c5SDavid van Moolenbroek 			sin = (struct sockaddr_in *)res->ai_addr;
2861*7348b5c5SDavid van Moolenbroek 			memcpy(lsrp, &sin->sin_addr, sizeof(struct in_addr));
2862*7348b5c5SDavid van Moolenbroek 			lsrp += sizeof(struct in_addr);
2863*7348b5c5SDavid van Moolenbroek 		}
2864*7348b5c5SDavid van Moolenbroek #ifdef INET6
2865*7348b5c5SDavid van Moolenbroek 		else if (ai->ai_family == AF_INET6) {
2866*7348b5c5SDavid van Moolenbroek 			sin6 = (struct sockaddr_in6 *)res->ai_addr;
2867*7348b5c5SDavid van Moolenbroek 			inet6_rthdr_add(cmsg, &sin6->sin6_addr,
2868*7348b5c5SDavid van Moolenbroek 				IPV6_RTHDR_LOOSE);
2869*7348b5c5SDavid van Moolenbroek 		}
2870*7348b5c5SDavid van Moolenbroek #endif
2871*7348b5c5SDavid van Moolenbroek 		else {
2872*7348b5c5SDavid van Moolenbroek 			freeaddrinfo(res);
2873*7348b5c5SDavid van Moolenbroek 			return -1;
2874*7348b5c5SDavid van Moolenbroek 		}
2875*7348b5c5SDavid van Moolenbroek 		freeaddrinfo(res);
2876*7348b5c5SDavid van Moolenbroek 		if (cp2)
2877*7348b5c5SDavid van Moolenbroek 			cp = cp2;
2878*7348b5c5SDavid van Moolenbroek 		else
2879*7348b5c5SDavid van Moolenbroek 			break;
2880*7348b5c5SDavid van Moolenbroek 	}
2881*7348b5c5SDavid van Moolenbroek 	switch (ai->ai_family) {
2882*7348b5c5SDavid van Moolenbroek 	case AF_INET:
2883*7348b5c5SDavid van Moolenbroek 		/* record the last hop */
2884*7348b5c5SDavid van Moolenbroek 		if (lsrp + 4 > lsrep)
2885*7348b5c5SDavid van Moolenbroek 			return -1;
2886*7348b5c5SDavid van Moolenbroek 		sin = (struct sockaddr_in *)ai->ai_addr;
2887*7348b5c5SDavid van Moolenbroek 		memcpy(lsrp, &sin->sin_addr, sizeof(struct in_addr));
2888*7348b5c5SDavid van Moolenbroek 		lsrp += sizeof(struct in_addr);
2889*7348b5c5SDavid van Moolenbroek 		lsr[IPOPT_OLEN] = lsrp - lsr;
2890*7348b5c5SDavid van Moolenbroek 		if (lsr[IPOPT_OLEN] <= 7 || lsr[IPOPT_OLEN] > 40)
2891*7348b5c5SDavid van Moolenbroek 			return -1;
2892*7348b5c5SDavid van Moolenbroek 		*lsrp++ = IPOPT_NOP;	/*32bit word align*/
2893*7348b5c5SDavid van Moolenbroek 		len = lsrp - lsr;
2894*7348b5c5SDavid van Moolenbroek 		*cpp = lsr;
2895*7348b5c5SDavid van Moolenbroek 		break;
2896*7348b5c5SDavid van Moolenbroek #ifdef INET6
2897*7348b5c5SDavid van Moolenbroek 	case AF_INET6:
2898*7348b5c5SDavid van Moolenbroek 		inet6_rthdr_lasthop(cmsg, IPV6_RTHDR_LOOSE);
2899*7348b5c5SDavid van Moolenbroek 		len = cmsg->cmsg_len;
2900*7348b5c5SDavid van Moolenbroek 		*cpp = rhbuf;
2901*7348b5c5SDavid van Moolenbroek 		break;
2902*7348b5c5SDavid van Moolenbroek #endif
2903*7348b5c5SDavid van Moolenbroek 	default:
2904*7348b5c5SDavid van Moolenbroek 		return -1;
2905*7348b5c5SDavid van Moolenbroek 	}
2906*7348b5c5SDavid van Moolenbroek 	return len;
2907*7348b5c5SDavid van Moolenbroek }
2908