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