www.pudn.com > socks5.zip > commands.c


/* Copyright (c) 1988, 1990, 1993                                            */ 
/* The Regents of the University of California.  All rights reserved.        */ 
/*                                                                           */ 
/* Redistribution and use in source and binary forms, with or without        */ 
/* modification, are permitted provided that the following conditions        */ 
/* are met:                                                                  */ 
/* 1. Redistributions of source code must retain the above copyright         */ 
/* notice, this list of conditions and the following disclaimer.             */ 
/* 2. Redistributions in binary form must reproduce the above copyright      */ 
/* notice, this list of conditions and the following disclaimer in the       */ 
/* documentation and/or other materials provided with the distribution.      */ 
/* 3. All advertising materials mentioning features or use of this           */ 
/* software must display the following acknowledgement:                      */ 
/*   This product includes software developed by the University of           */ 
/*   California, Berkeley and its contributors.                              */ 
/* 4. Neither the name of the University nor the names of its contributors   */ 
/* may be used to endorse or promote products derived from this software     */ 
/* without specific prior written permission.                                */ 
/*                                                                           */ 
/* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND   */ 
/* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE     */ 
/* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR        */ 
/* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE */ 
/* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR       */ 
/* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF      */ 
/* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  */ 
/* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN   */ 
/* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)   */ 
/* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF    */ 
/* THE POSSIBILITY OF SUCH DAMAGE.                                           */ 
 
#ifdef SHOW_SCCIDS 
static char sccsid[] = "@(#)commands.c	8.4 (Berkeley) 5/30/95"; 
#endif 
 
#include "config.h" 
 
#ifdef HAVE_SYS_PARAM_H 
#include  
#endif 
 
#ifdef HAVE_SYS_TYPES_H 
#include  
#endif 
 
#ifdef HAVE_SYS_FILE_H 
#include  
#endif 
 
#ifdef HAVE_UNISTD_H 
#include  
#endif 
 
#include  
#include  
 
#ifdef HAVE_SYS_FCNTL_H 
#include  
#endif 
 
#ifdef HAVE_FCNTL_H 
#include  
#endif 
 
#include  
 
#ifdef HAVE_STRING_H 
#include  
#endif 
 
#ifdef HAVE_STRINGS_H 
#include  
#endif 
 
#ifdef HAVE_UNISTD_H 
#include  
#endif 
 
#ifdef HAVE_STDLIB_H 
#include  
#endif 
 
#include  
#include  
#include  
#include  
#include  
 
#include  
 
#include "general.h" 
#include "ring.h" 
#include "externs.h" 
#include "defines.h" 
#include "types.h" 
 
#ifdef HAVE_MACHINE_ENDIAN_H 
#include  
#endif 
 
#include  
 
#define DONT_NEED_SIGBLOCK 
#define DONT_NEED_SIGUNBLOCK 
#define DONT_NEED_SIGPAUSE 
#define DONT_NEED_SIGPENDING 
#include "sigfix.h" 
 
#ifndef	MAXHOSTNAMELEN 
#define	MAXHOSTNAMELEN 64 
#endif	 
 
#if defined(IPPROTO_IP) && defined(IP_TOS) 
int tos = -1; 
#endif 
 
char *hostname; 
static char _hostname[MAXHOSTNAMELEN]; 
 
extern int isprefix(); 
extern char **genget(); 
extern int Ambiguous(); 
extern void herror(); 
 
static call(); 
 
typedef struct { 
    char *name;		/* command name */ 
    char *help;		/* help string (NULL for no help) */ 
    int	(*handler)();	/* routine which executes command */ 
    int	needconnect;	/* Do we need to be connected to execute? */ 
} Command; 
 
static char line[256]; 
static char saveline[256]; 
static int margc; 
static char *margv[20]; 
 
void cmdrc P((char *, char *)); 
 
static void makeargv() { 
    register char *cp, *cp2, c; 
    register char **argp = margv; 
 
    margc = 0; 
    cp = line; 
    if (*cp == '!') {		/* Special case shell escape */ 
	strcpy(saveline, line);	/* save for shell command */ 
	*argp++ = "!";		/* No room in string to get this */ 
	margc++; 
	cp++; 
    } 
    while ((c = *cp)) { 
	register int inquote = 0; 
	while (isspace(c)) 
	    c = *++cp; 
	if (c == '\0') 
	    break; 
	*argp++ = cp; 
	margc += 1; 
	for (cp2 = cp; c != '\0'; c = *++cp) { 
	    if (inquote) { 
		if (c == inquote) { 
		    inquote = 0; 
		    continue; 
		} 
	    } else { 
		if (c == '\\') { 
		    if ((c = *++cp) == '\0') 
			break; 
		} else if (c == '"') { 
		    inquote = '"'; 
		    continue; 
		} else if (c == '\'') { 
		    inquote = '\''; 
		    continue; 
		} else if (isspace(c)) 
		    break; 
	    } 
	    *cp2++ = c; 
	} 
	*cp2 = '\0'; 
	if (c == '\0') 
	    break; 
	cp++; 
    } 
    *argp++ = 0; 
} 
 
/* Make a character string into a number.                                    */ 
/* Todo: 1.  Could take random integers (12, 0x12, 012, 0b1).                */ 
static char special(register char *s) { 
    register char c; 
    char b; 
     
    switch (*s) { 
	case '^': 
	    b = *++s; 
	    if (b == '?') { 
		c = b | 0x40;		/* DEL */ 
	    } else { 
		c = b & 0x1f; 
	    } 
	    break; 
	default: 
	    c = *s; 
	    break; 
    } 
 
    return c; 
} 
 
/* Construct a control character sequence for a special character.           */ 
static char *control(register cc_t c) { 
    static char buf[5]; 
    /* The only way I could get the Sun 3.5 compiler to shut up about "if    */ 
    /* ((unsigned int)c >= 0x80)" was to assign "c" to an unsigned int       */ 
    /* variable...  Arggg....                                                */ 
    register unsigned int uic = (unsigned int)c; 
 
    if (uic == 0x7f) { 
	return ("^?"); 
    } 
 
    if (c == (cc_t)_POSIX_VDISABLE) { 
	return "off"; 
    } 
 
    if (uic >= 0x80) { 
	buf[0] = '\\'; 
	buf[1] = ((c>>6)&07) + '0'; 
	buf[2] = ((c>>3)&07) + '0'; 
	buf[3] = (c&07) + '0'; 
	buf[4] = 0; 
    } else if (uic >= 0x20) { 
	buf[0] = c; 
	buf[1] = 0; 
    } else { 
	buf[0] = '^'; 
	buf[1] = '@'+c; 
	buf[2] = 0; 
    } 
 
    return (buf); 
} 
 
/* The following are data structures and routines for                        */ 
/* the "send" command.                                                       */ 
struct sendlist { 
    char	*name;		/* How user refers to it (case independent) */ 
    char	*help;		/* Help information (0 ==> no help) */ 
    int		needconnect;	/* Need to be connected */ 
    int		narg;		/* Number of arguments */ 
    int		(*handler)();	/* Routine to perform (for special ops) */ 
    int		nbyte;		/* Number of bytes to send this command */ 
    int		what;		/* Character to be sent (<0 ==> special) */ 
}; 
 
static int 
	send_esc P((void)), 
	send_help P((void)), 
	send_docmd P((char *)), 
	send_dontcmd P((char *)), 
	send_willcmd P((char *)), 
	send_wontcmd P((char *)); 
 
static struct sendlist Sendlist[] = { 
    { "ao",	"Send Telnet Abort output",		1, 0, 0, 2, AO }, 
    { "ayt",	"Send Telnet 'Are You There'",		1, 0, 0, 2, AYT }, 
    { "brk",	"Send Telnet Break",			1, 0, 0, 2, BREAK }, 
    { "break",	0,					1, 0, 0, 2, BREAK }, 
    { "ec",	"Send Telnet Erase Character",		1, 0, 0, 2, EC }, 
    { "el",	"Send Telnet Erase Line",		1, 0, 0, 2, EL }, 
    { "escape",	"Send current escape character",	1, 0, send_esc, 1, 0 }, 
    { "ga",	"Send Telnet 'Go Ahead' sequence",	1, 0, 0, 2, GA }, 
    { "ip",	"Send Telnet Interrupt Process",	1, 0, 0, 2, IP }, 
    { "intp",	0,					1, 0, 0, 2, IP }, 
    { "interrupt", 0,					1, 0, 0, 2, IP }, 
    { "intr",	0,					1, 0, 0, 2, IP }, 
    { "nop",	"Send Telnet 'No operation'",		1, 0, 0, 2, NOP }, 
    { "eor",	"Send Telnet 'End of Record'",		1, 0, 0, 2, EOR }, 
    { "abort",	"Send Telnet 'Abort Process'",		1, 0, 0, 2, ABORT }, 
    { "susp",	"Send Telnet 'Suspend Process'",	1, 0, 0, 2, SUSP }, 
    { "eof",	"Send Telnet End of File Character",	1, 0, 0, 2, xEOF }, 
    { "synch",	"Perform Telnet 'Synch operation'",	1, 0, dosynch, 2, 0 }, 
    { "getstatus", "Send request for STATUS",		1, 0, get_status, 6, 0 }, 
    { "?",	"Display send options",			0, 0, send_help, 0, 0 }, 
    { "help",	0,					0, 0, send_help, 0, 0 }, 
    { "do",	0,					0, 1, send_docmd, 3, 0 }, 
    { "dont",	0,					0, 1, send_dontcmd, 3, 0 }, 
    { "will",	0,					0, 1, send_willcmd, 3, 0 }, 
    { "wont",	0,					0, 1, send_wontcmd, 3, 0 }, 
    { 0 } 
}; 
 
#define	GETSEND(name) ((struct sendlist *) genget(name, (char **) Sendlist, \ 
				sizeof(struct sendlist))) 
 
/*VARARGS*/ 
static int bye(int argc, char *argv[]) { 
    extern int resettermname; 
 
    if (connected) { 
	(void) shutdown(net, 2); 
	printf("Connection closed.\n"); 
	(void) NetClose(net); 
	connected = 0; 
	resettermname = 1; 
	/* reset options */ 
	tninit(); 
#ifdef TN3270 
	SetIn3270();		/* Get out of 3270 mode */ 
#endif	/* defined(TN3270) */ 
    } 
    if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) { 
	longjmp(toplevel, 1); 
	/* NOTREACHED */ 
    } 
    return 1;			/* Keep lint, etc., happy */ 
} 
 
int quit() { 
    call(bye, "bye", "fromquit", 0); 
    Exit(0); 
 
    /*NOTREACHED*/ 
    return 0; 
} 
 
int logout() { 
    send_do(TELOPT_LOGOUT, 1); 
    netflush(); 
    return 1; 
} 
 
static int sendcmd(int argc, char **argv) {  
    int count;		/* how many bytes we are going to need to send */ 
    int i; 
    struct sendlist *s;	/* pointer to current command */ 
    int success = 0; 
    int needconnect = 0; 
 
    if (argc < 2) { 
	printf("need at least one argument for 'send' command\n"); 
	printf("'send ?' for help\n"); 
	return 0; 
    } 
    /* First, validate all the send arguments.  In addition, we see how much */ 
    /* space we are going to need, and whether or not we will be doing a     */ 
    /* "SYNCH" operation (which flushes the network queue).                  */ 
    count = 0; 
 
    for (i = 1; i < argc; i++) { 
	s = GETSEND(argv[i]); 
	if (s == 0) { 
	    printf("Unknown send argument '%s'\n'send ?' for help.\n", argv[i]); 
	    return 0; 
	} else if (Ambiguous(s)) { 
	    printf("Ambiguous send argument '%s'\n'send ?' for help.\n", argv[i]); 
	    return 0; 
	} 
 
	if (i + s->narg >= argc) { 
	    fprintf(stderr, "Need %d argument%s to 'send %s' command.  'send %s ?' for help.\n", 
		    s->narg, s->narg == 1 ? "" : "s", s->name, s->name); 
	    return 0; 
	} 
 
	count += s->nbyte; 
 
	if (s->handler == send_help) { 
	    send_help(); 
	    return 0; 
	} 
 
	i += s->narg; 
	needconnect += s->needconnect; 
    } 
 
    if (!connected && needconnect) { 
	printf("?Need to be connected first.\n"); 
	printf("'send ?' for help\n"); 
	return 0; 
    } 
 
    /* Now, do we have enough room? */ 
    if (NETROOM() < count) { 
	printf("There is not enough room in the buffer TO the network\n"); 
	printf("to process your request.  Nothing will be done.\n"); 
	printf("('send synch' will throw away most data in the network\n"); 
	printf("buffer, if this might help.)\n"); 
	return 0; 
    } 
 
    /* OK, they are all OK, now go through again and actually send */ 
    count = 0; 
 
    for (i = 1; i < argc; i++) { 
	if ((s = GETSEND(argv[i])) == 0) { 
	    fprintf(stderr, "Telnet 'send' error - argument disappeared!\n"); 
	    (void) quit(); 
	    /*NOTREACHED*/ 
	} 
	if (s->handler) { 
	    count++; 
	    success += (*s->handler)((s->narg > 0) ? argv[i+1] : 0, 
				  (s->narg > 1) ? argv[i+2] : 0); 
	    i += s->narg; 
	} else { 
	    NET2ADD(IAC, s->what); 
	    printoption("SENT", IAC, s->what); 
	} 
    } 
 
    return (count == success); 
} 
 
static int send_esc() { 
    NETADD(escape); 
    return 1; 
} 
 
static int send_tncmd(void (*func)(), char *cmd, char *name) { 
    char **cpp; 
    extern char *telopts[]; 
    register int val = 0; 
 
    if (isprefix(name, "help") || isprefix(name, "?")) { 
	register int col, len; 
 
	printf("Usage: send %s \n", cmd); 
	printf("\"value\" must be from 0 to 255\n"); 
	printf("Valid options are:\n\t"); 
 
	col = 8; 
 
	for (cpp = telopts; *cpp; cpp++) { 
	    len = strlen(*cpp) + 3; 
 
	    if (col + len > 65) { 
		printf("\n\t"); 
		col = 8; 
	    } 
 
	    printf(" \"%s\"", *cpp); 
	    col += len; 
	} 
 
	printf("\n"); 
	return 0; 
    } 
 
    cpp = (char **)genget(name, telopts, sizeof(char *)); 
 
    if (Ambiguous(cpp)) { 
	fprintf(stderr,"'%s': ambiguous argument ('send %s ?' for help).\n", name, cmd); 
	return 0; 
    } 
 
    if (cpp) { 
	val = cpp - telopts; 
    } else { 
	register char *cp = name; 
 
	while (*cp >= '0' && *cp <= '9') { 
	    val *= 10; 
	    val += *cp - '0'; 
	    cp++; 
	} 
 
	if (*cp != 0) { 
	    fprintf(stderr, "'%s': unknown argument ('send %s ?' for help).\n", name, cmd); 
	    return 0; 
	} else if (val < 0 || val > 255) { 
	    fprintf(stderr, "'%s': bad value ('send %s ?' for help).\n", name, cmd); 
	    return 0; 
	} 
    } 
 
    if (!connected) { 
	printf("?Need to be connected first.\n"); 
	return 0; 
    } 
 
    (*func)(val, 1); 
    return 1; 
} 
 
static int send_docmd(char *name) { 
    return(send_tncmd(send_do, "do", name)); 
} 
 
static int send_dontcmd(char *name) { 
    return(send_tncmd(send_dont, "dont", name)); 
} 
 
static int send_willcmd(char *name) { 
    return(send_tncmd(send_will, "will", name)); 
} 
 
static int send_wontcmd(char *name) { 
    return(send_tncmd(send_wont, "wont", name)); 
} 
 
static int send_help() { 
    struct sendlist *s;	/* pointer to current command */ 
 
    for (s = Sendlist; s->name; s++) { 
	if (s->help) printf("%-15s %s\n", s->name, s->help); 
    } 
 
    return(0); 
} 
 
/* The following are the routines and data structures referred to by the     */ 
/* arguments to the "toggle" command.                                        */ 
static int lclchars() { 
    donelclchars = 1; 
    return 1; 
} 
 
static int togdebug() { 
#ifdef NOT43 
    if (!debug) { 
	printf("Cannot turn off socket debugging\n"); 
	return 1; 
    } 
#endif 
 
    if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 0) < 0) 
	perror("setsockopt (SO_DEBUG)"); 
 
    return 1; 
} 
 
static int togcrlf() { 
    if (crlf) { 
	printf("Will send carriage returns as telnet .\n"); 
    } else { 
	printf("Will send carriage returns as telnet .\n"); 
    } 
 
    return 1; 
} 
 
int binmode; 
 
static int togbinary(int val) { 
    donebinarytoggle = 1; 
 
    if (val >= 0) { 
	binmode = val; 
    } else { 
	if (my_want_state_is_will(TELOPT_BINARY) && 
	    my_want_state_is_do(TELOPT_BINARY)) { 
	    binmode = 1; 
	} else if (my_want_state_is_wont(TELOPT_BINARY) && 
		   my_want_state_is_dont(TELOPT_BINARY)) { 
	    binmode = 0; 
	} 
 
	val = binmode ? 0 : 1; 
    } 
 
    if (val == 1) { 
	if (my_want_state_is_will(TELOPT_BINARY) && 
	    my_want_state_is_do(TELOPT_BINARY)) { 
	    printf("Already operating in binary mode with remote host.\n"); 
	} else { 
	    printf("Negotiating binary mode with remote host.\n"); 
	    tel_enter_binary(3); 
	} 
    } else { 
	if (my_want_state_is_wont(TELOPT_BINARY) && 
	    my_want_state_is_dont(TELOPT_BINARY)) { 
	    printf("Already in network ascii mode with remote host.\n"); 
	} else { 
	    printf("Negotiating network ascii mode with remote host.\n"); 
	    tel_leave_binary(3); 
	} 
    } 
 
    return 1; 
} 
 
static int togrbinary(int val) { 
    donebinarytoggle = 1; 
     
    if (val == -1) { 
	val = my_want_state_is_do(TELOPT_BINARY) ? 0 : 1; 
    } 
 
    if (val == 1) { 
	if (my_want_state_is_do(TELOPT_BINARY)) { 
	    printf("Already receiving in binary mode.\n"); 
	} else { 
	    printf("Negotiating binary mode on input.\n"); 
	    tel_enter_binary(1); 
	} 
    } else { 
	if (my_want_state_is_dont(TELOPT_BINARY)) { 
	    printf("Already receiving in network ascii mode.\n"); 
	} else { 
	    printf("Negotiating network ascii mode on input.\n"); 
	    tel_leave_binary(1); 
	} 
    } 
 
    return 1; 
} 
 
static int togxbinary(int val) { 
    donebinarytoggle = 1; 
 
    if (val == -1) { 
	val = my_want_state_is_will(TELOPT_BINARY) ? 0 : 1; 
    } 
 
    if (val == 1) { 
	if (my_want_state_is_will(TELOPT_BINARY)) { 
	    printf("Already transmitting in binary mode.\n"); 
	} else { 
	    printf("Negotiating binary mode on output.\n"); 
	    tel_enter_binary(2); 
	} 
    } else { 
	if (my_want_state_is_wont(TELOPT_BINARY)) { 
	    printf("Already transmitting in network ascii mode.\n"); 
	} else { 
	    printf("Negotiating network ascii mode on output.\n"); 
	    tel_leave_binary(2); 
	} 
    } 
 
    return 1; 
} 
 
 
static int togglehelp P((void)); 
 
 
struct togglelist { 
    char	*name;		/* name of toggle */ 
    char	*help;		/* help message */ 
    int		(*handler)();	/* routine to do actual setting */ 
    int		*variable; 
    char	*actionexplanation; 
}; 
 
static struct togglelist Togglelist[] = { 
    { "autoflush",  
      "flushing of output when sending interrupt characters", 
      0, 
      &autoflush, 
      "flush output when sending interrupt characters" }, 
    { "autosynch", 
      "automatic sending of interrupt characters in urgent mode", 
      0, 
      &autosynch, 
      "send interrupt characters in urgent mode" }, 
    { "skiprc", 
      "don't read ~/.telnetrc file", 
      0, 
      &skiprc, 
      "skip reading of ~/.telnetrc file" }, 
    { "binary", 
      "sending and receiving of binary data", 
      togbinary, 
      0, 
      0 }, 
    { "inbinary", 
      "receiving of binary data", 
      togrbinary, 
      0, 
      0 }, 
    { "outbinary", 
      "sending of binary data", 
      togxbinary, 
      0, 
      0 }, 
    { "crlf", 
      "sending carriage returns as telnet ", 
      togcrlf, 
      &crlf, 
      0 }, 
    { "crmod", 
      "mapping of received carriage returns", 
      0, 
      &crmod, 
      "map carriage return on output" }, 
    { "localchars", 
      "local recognition of certain control characters", 
      lclchars, 
      &localchars, 
      "recognize certain control characters" }, 
    { " ", "", 0 },		/* empty line */ 
#ifdef TN3270 
    { "apitrace", 
      "(debugging) toggle tracing of API transactions", 
      0, 
      &apitrace, 
      "trace API transactions" }, 
    { "cursesdata", 
      "(debugging) toggle printing of hexadecimal curses data", 
      0, 
      &cursesdata, 
      "print hexadecimal representation of curses data" }, 
#endif 
    { "debug", 
      "debugging", 
      togdebug, 
      &debug, 
      "turn on socket level debugging" }, 
    { "netdata", 
      "printing of hexadecimal network data (debugging)", 
      0, 
      &netdata, 
      "print hexadecimal representation of network traffic" }, 
    { "prettydump", 
      "output of \"netdata\" to user readable format (debugging)", 
      0, 
      &prettydump, 
      "print user readable output for \"netdata\"" }, 
    { "options", 
      "viewing of options processing (debugging)", 
      0, 
      &showoptions, 
      "show option processing" }, 
    { "termdata", 
      "(debugging) toggle printing of hexadecimal terminal data", 
      0, 
      &termdata, 
      "print hexadecimal representation of terminal traffic" }, 
    { "?", 
      0, 
      togglehelp }, 
    { "help", 
      0, 
      togglehelp }, 
    { 0 } 
}; 
 
static int togglehelp() { 
    struct togglelist *c; 
 
    for (c = Togglelist; c->name; c++) { 
	if (c->help) { 
	    if (*c->help) printf("%-15s toggle %s\n", c->name, c->help); 
	    else printf("\n"); 
	} 
    } 
 
    printf("\n"); 
    printf("%-15s %s\n", "?", "display help information"); 
 
    return 0; 
} 
 
static void settogglehelp(int set) { 
    struct togglelist *c; 
 
    for (c = Togglelist; c->name; c++) { 
	if (c->help) { 
	    if (*c->help) printf("%-15s %s %s\n", c->name, set ? "enable" : "disable", c->help); 
	    else printf("\n"); 
	} 
    } 
} 
 
#define	GETTOGGLE(name) (struct togglelist *) genget(name, (char **) Togglelist, sizeof(struct togglelist)) 
 
static int toggle(int argc, char *argv[]) { 
    int retval = 1; 
    char *name; 
    struct togglelist *c; 
 
    if (argc < 2) { 
	fprintf(stderr, "Need an argument to 'toggle' command.  'toggle ?' for help.\n"); 
	return 0; 
    } 
 
    argc--; 
    argv++; 
 
    while (argc--) { 
	name = *argv++; 
	c = GETTOGGLE(name); 
 
	if (Ambiguous(c)) { 
	    fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n", name); 
	    return 0; 
	} else if (c == 0) { 
	    fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n", name); 
	    return 0; 
	} else { 
	    if (c->variable) { 
		*c->variable = !*c->variable;		/* invert it */ 
		if (c->actionexplanation) { 
		    printf("%s %s.\n", *c->variable? "Will" : "Won't", c->actionexplanation); 
		} 
	    } 
 
	    if (c->handler) { 
		retval &= (*c->handler)(-1); 
	    } 
	} 
    } 
 
    return retval; 
} 
 
/* The following perform the "set" command.                                  */ 
#ifdef	USE_TERMIO 
struct termio new_tc = { 0 }; 
#endif 
 
struct setlist { 
    char *name;				/* name */ 
    char *help;				/* help information */ 
    void (*handler)(); 
    cc_t *charp;			/* where it is located at */ 
}; 
 
static struct setlist Setlist[] = { 
#ifdef	KLUDGELINEMODE 
    { "echo", 	"character to toggle local echoing on/off", 0, &echoc }, 
#endif 
    { "escape",	"character to escape back to telnet command mode", 0, &escape }, 
    { "rlogin", "rlogin escape character", 0, &rlogin }, 
    { "tracefile", "file to write trace information to", SetNetTrace, (cc_t *)NetTraceFile}, 
    { " ", "" }, 
    { " ", "The following need 'localchars' to be toggled true", 0, 0 }, 
    { "flushoutput", "character to cause an Abort Output", 0, termFlushCharp }, 
    { "interrupt", "character to cause an Interrupt Process", 0, termIntCharp }, 
    { "quit",	"character to cause an Abort process", 0, termQuitCharp }, 
    { "eof",	"character to cause an EOF ", 0, termEofCharp }, 
    { " ", "" }, 
    { " ", "The following are for local editing in linemode", 0, 0 }, 
    { "erase",	"character to use to erase a character", 0, termEraseCharp }, 
    { "kill",	"character to use to erase a line", 0, termKillCharp }, 
    { "lnext",	"character to use for literal next", 0, termLiteralNextCharp }, 
    { "susp",	"character to cause a Suspend Process", 0, termSuspCharp }, 
    { "reprint", "character to use for line reprint", 0, termRprntCharp }, 
    { "worderase", "character to use to erase a word", 0, termWerasCharp }, 
    { "start",	"character to use for XON", 0, termStartCharp }, 
    { "stop",	"character to use for XOFF", 0, termStopCharp }, 
    { "forw1",	"alternate end of line character", 0, termForw1Charp }, 
    { "forw2",	"alternate end of line character", 0, termForw2Charp }, 
    { "ayt",	"alternate AYT character", 0, termAytCharp }, 
    { 0 } 
}; 
 
#if defined(CRAY) && !defined(__STDC__) 
/* Work around compiler bug in pcc 4.1.5 */ 
void _setlist_init() { 
#ifndef	KLUDGELINEMODE 
#define	N 5 
#else 
#define	N 6 
#endif 
	Setlist[N+0].charp = &termFlushChar; 
	Setlist[N+1].charp = &termIntChar; 
	Setlist[N+2].charp = &termQuitChar; 
	Setlist[N+3].charp = &termEofChar; 
	Setlist[N+6].charp = &termEraseChar; 
	Setlist[N+7].charp = &termKillChar; 
	Setlist[N+8].charp = &termLiteralNextChar; 
	Setlist[N+9].charp = &termSuspChar; 
	Setlist[N+10].charp = &termRprntChar; 
	Setlist[N+11].charp = &termWerasChar; 
	Setlist[N+12].charp = &termStartChar; 
	Setlist[N+13].charp = &termStopChar; 
	Setlist[N+14].charp = &termForw1Char; 
	Setlist[N+15].charp = &termForw2Char; 
	Setlist[N+16].charp = &termAytChar; 
#undef	N 
} 
#endif	/* defined(CRAY) && !defined(__STDC__) */ 
 
static struct setlist *getset(char *name) { 
    return (struct setlist *)genget(name, (char **) Setlist, sizeof(struct setlist)); 
} 
 
void set_escape_char(char *s) { 
    if (rlogin != _POSIX_VDISABLE) { 
	rlogin = (s && *s) ? special(s) : _POSIX_VDISABLE; 
	printf("Telnet rlogin escape character is '%s'.\n", control(rlogin)); 
    } else { 
	escape = (s && *s) ? special(s) : _POSIX_VDISABLE; 
	printf("Telnet escape character is '%s'.\n", control(escape)); 
    } 
} 
 
static int setcmd(int argc, char *argv[]) { 
    int value; 
    struct setlist *ct; 
    struct togglelist *c; 
 
    if (argc < 2 || argc > 3) { 
	printf("Format is 'set Name Value'\n'set ?' for help.\n"); 
	return 0; 
    } 
 
    if ((argc == 2) && (isprefix(argv[1], "?") || isprefix(argv[1], "help"))) { 
	for (ct = Setlist; ct->name; ct++) printf("%-15s %s\n", ct->name, ct->help); 
	printf("\n"); 
 
	settogglehelp(1); 
 
	printf("%-15s %s\n", "?", "display help information"); 
	return 0; 
    } 
 
    ct = getset(argv[1]); 
 
    if (ct == 0) { 
	c = GETTOGGLE(argv[1]); 
 
	if (c == 0) {  
	    fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n", argv[1]); 
	    return 0; 
	} else if (Ambiguous(c)) { 
	    fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n", argv[1]); 
	    return 0; 
	} 
 
	if (c->variable) { 
	    if ((argc == 2) || (strcmp("on", argv[2]) == 0)) 
		*c->variable = 1; 
	    else if (strcmp("off", argv[2]) == 0) 
		*c->variable = 0; 
	    else { 
		printf("Format is 'set togglename [on|off]'\n'set ?' for help.\n"); 
		return 0; 
	    } 
 
	    if (c->actionexplanation) { 
		printf("%s %s.\n", *c->variable? "Will" : "Won't", c->actionexplanation); 
	    } 
	} 
 
	if (c->handler) (*c->handler)(1); 
    } else if (argc != 3) { 
	printf("Format is 'set Name Value'\n'set ?' for help.\n"); 
	return 0; 
    } else if (Ambiguous(ct)) { 
	fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n", argv[1]); 
	return 0; 
    } else if (ct->handler) { 
	(*ct->handler)(argv[2]); 
	printf("%s set to \"%s\".\n", ct->name, (char *)ct->charp); 
    } else { 
	if (strcmp("off", argv[2])) { 
	    value = special(argv[2]); 
	} else { 
	    value = _POSIX_VDISABLE; 
	} 
 
	*(ct->charp) = (cc_t)value; 
	printf("%s character is '%s'.\n", ct->name, control(*(ct->charp))); 
    } 
 
    slc_check(); 
    return 1; 
} 
 
static int unsetcmd(int argc, char *argv[]) { 
    struct setlist *ct; 
    struct togglelist *c; 
    register char *name; 
 
    if (argc < 2) { 
	fprintf(stderr, "Need an argument to 'unset' command.  'unset ?' for help.\n"); 
	return 0; 
    } 
 
    if (isprefix(argv[1], "?") || isprefix(argv[1], "help")) { 
	for (ct = Setlist; ct->name; ct++) printf("%-15s %s\n", ct->name, ct->help); 
	printf("\n"); 
 
	settogglehelp(0); 
 
	printf("%-15s %s\n", "?", "display help information"); 
	return 0; 
    } 
 
    argc--; 
    argv++; 
 
    while (argc--) { 
	name = *argv++; 
	ct = getset(name); 
 
	if (ct == 0) { 
	    c = GETTOGGLE(name); 
	    if (c == 0) { 
		fprintf(stderr, "'%s': unknown argument ('unset ?' for help).\n", name); 
		return 0; 
	    } else if (Ambiguous(c)) { 
		fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n", name); 
		return 0; 
	    } 
 
	    if (c->variable) { 
		*c->variable = 0; 
		if (c->actionexplanation) { 
		    printf("%s %s.\n", *c->variable? "Will" : "Won't", c->actionexplanation); 
		} 
	    } 
 
	    if (c->handler) (*c->handler)(0); 
	} else if (Ambiguous(ct)) { 
	    fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n", name); 
	    return 0; 
	} else if (ct->handler) { 
	    (*ct->handler)(0); 
	    printf("%s reset to \"%s\".\n", ct->name, (char *)ct->charp); 
	} else { 
	    *(ct->charp) = _POSIX_VDISABLE; 
	    printf("%s character is '%s'.\n", ct->name, control(*(ct->charp))); 
	} 
    } 
 
    return 1; 
} 
 
/* The following are the data structures and routines for the 'mode'         */ 
/* command.                                                                  */ 
#ifdef	KLUDGELINEMODE 
extern int kludgelinemode; 
 
static int dokludgemode() { 
    kludgelinemode = 1; 
    send_wont(TELOPT_LINEMODE, 1); 
    send_dont(TELOPT_SGA, 1); 
    send_dont(TELOPT_ECHO, 1); 
    return 1; 
} 
#endif 
 
static int dolinemode() { 
#ifdef	KLUDGELINEMODE 
    if (kludgelinemode) send_dont(TELOPT_SGA, 1); 
#endif 
    send_will(TELOPT_LINEMODE, 1); 
    send_dont(TELOPT_ECHO, 1); 
    return 1; 
} 
 
static int docharmode() { 
#ifdef	KLUDGELINEMODE 
    if (kludgelinemode) send_do(TELOPT_SGA, 1); 
    else 
#endif 
    send_wont(TELOPT_LINEMODE, 1); 
    send_do(TELOPT_ECHO, 1); 
    return 1; 
} 
 
static int dolmmode(int bit, int on) { 
    unsigned char c; 
    extern int linemode; 
 
    if (my_want_state_is_wont(TELOPT_LINEMODE)) { 
	printf("?Need to have LINEMODE option enabled first.\n"); 
	printf("'mode ?' for help.\n"); 
	return 0; 
    } 
 
    if (on) c = (linemode | bit); 
    else    c = (linemode & ~bit); 
 
    lm_mode(&c, 1, 1); 
    return 1; 
} 
 
static int tn_setmode(int bit) { 
    return dolmmode(bit, 1); 
} 
 
static int clearmode(int bit) { 
    return dolmmode(bit, 0); 
} 
 
struct modelist { 
    char *name;		/* command name */ 
    char *help;		/* help string */ 
    int	(*handler)();	/* routine which executes command */ 
    int	needconnect;	/* Do we need to be connected to execute? */ 
    int arg1; 
}; 
 
extern int modehelp(); 
 
static struct modelist ModeList[] = { 
    { "character", "Disable LINEMODE option",	     docharmode, 1 }, 
#ifdef	KLUDGELINEMODE 
    { "",	   "(or disable obsolete line-by-line mode)", 0 }, 
#endif 
    { "line",	   "Enable LINEMODE option",	     dolinemode, 1 }, 
#ifdef	KLUDGELINEMODE 
    { "",	"(or enable obsolete line-by-line mode)", 0 }, 
#endif 
    { "", "", 0 }, 
    { "",	   "These require the LINEMODE option to be enabled", 0 }, 
    { "isig",	   "Enable signal trapping",	     tn_setmode, 1, MODE_TRAPSIG }, 
    { "+isig",	   NULL,			     tn_setmode, 1, MODE_TRAPSIG }, 
    { "-isig",	   "Disable signal trapping",	     clearmode,  1, MODE_TRAPSIG }, 
    { "edit",	   "Enable character editing",	     tn_setmode, 1, MODE_EDIT }, 
    { "+edit",	   NULL,			     tn_setmode, 1, MODE_EDIT }, 
    { "-edit",	   "Disable character editing",	     clearmode,  1, MODE_EDIT }, 
    { "softtabs",  "Enable tab expansion",	     tn_setmode, 1, MODE_SOFT_TAB }, 
    { "+softtabs", NULL,			     tn_setmode, 1, MODE_SOFT_TAB }, 
    { "-softtabs", "Disable character editing",      clearmode,  1, MODE_SOFT_TAB }, 
    { "litecho",   "Enable literal character echo",  tn_setmode, 1, MODE_LIT_ECHO }, 
    { "+litecho",  NULL,			     tn_setmode, 1, MODE_LIT_ECHO }, 
    { "-litecho",  "Disable literal character echo", clearmode,  1, MODE_LIT_ECHO }, 
    { "help",	   NULL,			     modehelp,   0 }, 
#ifdef	KLUDGELINEMODE 
    { "kludgeline", 0,				     dokludgemode, 1 }, 
#endif 
    { "", "", 0 }, 
    { "?",	    "Print help information",	     modehelp, 0 }, 
    { 0 }, 
}; 
 
 
int modehelp() { 
    struct modelist *mt; 
 
    printf("format is:  'mode Mode', where 'Mode' is one of:\n\n"); 
 
    for (mt = ModeList; mt->name; mt++) { 
	if (mt->help) { 
	    if (*mt->help) printf("%-15s %s\n", mt->name, mt->help); 
	    else printf("\n"); 
	} 
    } 
 
    return 0; 
} 
 
#define	GETMODECMD(name) (struct modelist *) genget(name, (char **) ModeList, sizeof(struct modelist)) 
 
static int modecmd(int argc, char *argv[]) { 
    struct modelist *mt; 
 
    if (argc != 2) { 
	printf("'mode' command requires an argument\n"); 
	printf("'mode ?' for help.\n"); 
    } else if ((mt = GETMODECMD(argv[1])) == 0) { 
	fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]); 
    } else if (Ambiguous(mt)) { 
	fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]); 
    } else if (mt->needconnect && !connected) { 
	printf("?Need to be connected first.\n"); 
	printf("'mode ?' for help.\n"); 
    } else if (mt->handler) { 
	return (*mt->handler)(mt->arg1); 
    } 
    return 0; 
} 
 
/* The following data structures and routines implement the "display"        */ 
/* command.                                                                  */ 
static int display(int argc, char *argv[]) { 
    struct togglelist *tl; 
    struct setlist *sl; 
 
#define	dotog(tl)	if (tl->variable && tl->actionexplanation) { \ 
			    if (*tl->variable) { \ 
				printf("will"); \ 
			    } else { \ 
				printf("won't"); \ 
			    } \ 
			    printf(" %s.\n", tl->actionexplanation); \ 
			} 
 
#define	doset(sl)   if (sl->name && *sl->name != ' ') { \ 
			if (sl->handler == 0) \ 
			    printf("%-15s [%s]\n", sl->name, control(*sl->charp)); \ 
			else \ 
			    printf("%-15s \"%s\"\n", sl->name, (char *)sl->charp); \ 
		    } 
 
    if (argc == 1) { 
	for (tl = Togglelist; tl->name; tl++) { 
	    dotog(tl); 
	} 
 
	printf("\n"); 
 
	for (sl = Setlist; sl->name; sl++) { 
	    doset(sl); 
	} 
    } else { 
	int i; 
 
	for (i = 1; i < argc; i++) { 
	    sl = getset(argv[i]); 
	    tl = GETTOGGLE(argv[i]); 
	    if (Ambiguous(sl) || Ambiguous(tl)) { 
		printf("?Ambiguous argument '%s'.\n", argv[i]); 
		return 0; 
	    } else if (!sl && !tl) { 
		printf("?Unknown argument '%s'.\n", argv[i]); 
		return 0; 
	    } else { 
		if (tl) { 
		    dotog(tl); 
		} 
		if (sl) { 
		    doset(sl); 
		} 
	    } 
	} 
    } 
 
    /*@*/optionstatus(); 
    return 1; 
#undef	doset 
#undef	dotog 
} 
 
/* The following are the data structures, and many of the routines, relating */ 
/* to command processing.                                                    */ 
/*                                                                           */ 
 
/* Set the escape character.                                                 */ 
static int setescape(int argc, char *argv[]) { 
    register char *arg; 
    char buf[50]; 
     
    printf("Deprecated usage - please use 'set escape%s%s' in the future.\n", 
	   (argc > 2)? " ":"", (argc > 2)? argv[1]: ""); 
 
    if (argc > 2) arg = argv[1]; 
    else { 
	printf("new escape character: "); 
	fgets(buf, sizeof(buf), stdin); 
	arg = buf; 
    } 
 
    if (arg[0] != '\0') escape = arg[0]; 
 
    if (!In3270) { 
	printf("Escape character is '%s'.\n", control(escape)); 
    } 
 
    fflush(stdout); 
    return 1; 
} 
 
static int togcrmod() { 
    crmod = !crmod; 
    printf("Deprecated usage - please use 'toggle crmod' in the future.\n"); 
    printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't"); 
    fflush(stdout); 
    return 1; 
} 
 
int suspend() { 
#ifdef	SIGTSTP 
    long oldrows, oldcols, newrows, newcols, err; 
 
    setcommandmode(); 
    err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0; 
    kill(0, SIGTSTP); 
 
    /* If we didn't get the window size before the SUSPEND, but we can get   */ 
    /* them now (?), then send the NAWS to make sure that we are set up for  */ 
    /* the right window size. 	                                                                     */ 
    if (TerminalWindowSize(&newrows, &newcols) && connected && 
	(err || ((oldrows != newrows) || (oldcols != newcols)))) { 
	sendnaws(); 
    } 
 
    /* reget parameters in case they were changed */ 
    TerminalSaveState(); 
    setconnmode(0); 
#else 
    printf("Suspend is not supported.  Try the '!' command instead\n"); 
#endif 
    return 1; 
} 
 
#ifndef TN3270 
int shell(int argc, char *argv[]) { 
    long oldrows, oldcols, newrows, newcols, err; 
 
    setcommandmode(); 
 
    err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0; 
 
    switch(vfork()) { 
    case -1: 
	perror("Fork failed\n"); 
	break; 
    case 0: 
	{ 
	    /* Fire up the shell in the child. */ 
	    register char *shellp, *shellname; 
 
	    shellp = getenv("SHELL"); 
	    if (shellp == NULL) shellp = "/bin/sh"; 
 
	    if ((shellname = strrchr(shellp, '/')) == 0) shellname = shellp; 
	    else shellname++; 
 
	    if (argc > 1) execl(shellp, shellname, "-c", &saveline[1], 0); 
	    else execl(shellp, shellname, 0); 
 
	    perror("Execl"); 
	    _exit(1); 
	} 
    default: 
	wait(NULL);	/* Wait for the shell to complete */ 
 
	if (TerminalWindowSize(&newrows, &newcols) && connected && 
	    (err || ((oldrows != newrows) || (oldcols != newcols)))) { 
	    sendnaws(); 
	} 
 
	break; 
    } 
 
    return 1; 
} 
#else 
extern int shell(); 
#endif 
 
/* The SLC command.                                                          */ 
 
struct slclist { 
	char	*name; 
	char	*help; 
	void	(*handler)(); 
	int	arg; 
}; 
 
static void slc_help(); 
 
struct slclist SlcList[] = { 
    { "export",	"Use local special character definitions",     slc_mode_export,	0 }, 
    { "import",	"Use remote special character definitions",    slc_mode_import,	1 }, 
    { "check",	"Verify remote special character definitions", slc_mode_import,	0 }, 
    { "help",	0,				               slc_help,	0 }, 
    { "?",	"Print help information",	               slc_help,	0 }, 
    { 0 }, 
}; 
 
static void slc_help() { 
    struct slclist *c; 
 
    for (c = SlcList; c->name; c++) { 
	if (c->help) { 
	    if (*c->help) printf("%-15s %s\n", c->name, c->help); 
	    else printf("\n"); 
	} 
    } 
} 
 
static struct slclist *getslc(char *name) { 
    return (struct slclist *) genget(name, (char **) SlcList, sizeof(struct slclist)); 
} 
 
static int slccmd(int argc, char *argv[]) { 
    struct slclist *c; 
 
    if (argc != 2) { 
	fprintf(stderr, "Need an argument to 'slc' command.  'slc ?' for help.\n"); 
	return 0; 
    } 
     
    c = getslc(argv[1]); 
    if (c == 0) { 
	fprintf(stderr, "'%s': unknown argument ('slc ?' for help).\n", argv[1]); 
	return 0; 
    } 
     
    if (Ambiguous(c)) { 
	fprintf(stderr, "'%s': ambiguous argument ('slc ?' for help).\n", argv[1]); 
	return 0; 
    } 
     
    (*c->handler)(c->arg); 
    slcstate(); 
    return 1; 
} 
 
/* The ENVIRON command. */ 
struct envlist { 
	char	*name; 
	char	*help; 
	void	(*handler)(); 
	int	narg; 
}; 
 
extern struct env_lst * 
	env_define P((unsigned char *, unsigned char *)); 
extern void 
	env_undefine P((unsigned char *)), 
	env_export P((unsigned char *)), 
	env_unexport P((unsigned char *)), 
	env_send P((unsigned char *)), 
#if defined(OLD_ENVIRON) && defined(ENV_HACK) 
	env_varval P((unsigned char *)), 
#endif 
	env_list P((void)); 
static void 
	env_help P((void)); 
 
struct envlist EnvList[] = { 
    { "define",	"Define an environment variable", 
						(void (*)())env_define,	2 }, 
    { "undefine", "Undefine an environment variable", 
						env_undefine,	1 }, 
    { "export",	"Mark an environment variable for automatic export", 
						env_export,	1 }, 
    { "unexport", "Don't mark an environment variable for automatic export", 
						env_unexport,	1 }, 
    { "send",	"Send an environment variable", env_send,	1 }, 
    { "list",	"List the current environment variables", 
						env_list,	0 }, 
#if defined(OLD_ENVIRON) && defined(ENV_HACK) 
    { "varval", "Reverse VAR and VALUE (auto, right, wrong, status)", 
						env_varval,    1 }, 
#endif 
    { "help",	0,				env_help,		0 }, 
    { "?",	"Print help information",	env_help,		0 }, 
    { 0 }, 
}; 
 
static void env_help() { 
    struct envlist *c; 
 
    for (c = EnvList; c->name; c++) { 
	if (c->help) { 
	    if (*c->help) printf("%-15s %s\n", c->name, c->help); 
	    else printf("\n"); 
	} 
    } 
} 
 
static struct envlist *getenvcmd(char *name) { 
    return (struct envlist *)genget(name, (char **) EnvList, sizeof(struct envlist)); 
} 
 
int env_cmd(int argc, char *argv[]) { 
    struct envlist *c; 
 
    if (argc < 2) { 
	fprintf(stderr, "Need an argument to 'environ' command.  'environ ?' for help.\n"); 
	return 0; 
    } 
 
    c = getenvcmd(argv[1]); 
    if (c == 0) { 
	fprintf(stderr, "'%s': unknown argument ('environ ?' for help).\n", argv[1]); 
	return 0; 
    } 
 
    if (Ambiguous(c)) { 
	fprintf(stderr, "'%s': ambiguous argument ('environ ?' for help).\n", argv[1]); 
	return 0; 
    } 
     
    if (c->narg + 2 != argc) { 
	fprintf(stderr, "Need %s%d argument%s to 'environ %s' command.  'environ ?' for help.\n", 
		c->narg < argc + 2 ? "only " : "", c->narg, c->narg == 1 ? "" : "s", c->name); 
	return 0; 
    } 
 
    (*c->handler)(argv[2], argv[3]); 
    return 1; 
} 
 
struct env_lst { 
	struct env_lst *next;	/* pointer to next structure */ 
	struct env_lst *prev;	/* pointer to previous structure */ 
	unsigned char *var;	/* pointer to variable name */ 
	unsigned char *value;	/* pointer to variable value */ 
	int export;		/* 1 -> export with default list of variables */ 
	int welldefined;	/* A well defined variable */ 
}; 
 
struct env_lst envlisthead; 
 
struct env_lst *env_find(unsigned char *var) { 
    register struct env_lst *ep; 
 
    for (ep = envlisthead.next; ep; ep = ep->next) { 
	if (strcmp((char *)ep->var, (char *)var) == 0) 
	    return(ep); 
    } 
 
    return(NULL); 
} 
 
void env_init() { 
    extern char **environ; 
    register char **epp, *cp; 
    register struct env_lst *ep; 
 
    for (epp = environ; *epp; epp++) { 
	if ((cp = strchr(*epp, '='))) { 
	    *cp = '\0'; 
	    ep = env_define((unsigned char *)*epp, (unsigned char *)cp+1); 
	    ep->export = 0; 
	    *cp = '='; 
	} 
    } 
 
    /* Special case for DISPLAY variable.  If it is ":0.0" or "unix:0.0", we */ 
    /* have to get rid of "unix" and insert our hostname.                    */ 
    if ((ep = env_find("DISPLAY")) && ((*ep->value == ':') || (strncmp((char *)ep->value, "unix:", 5) == 0))) { 
	char hbuf[256+1]; 
	char *cp2 = strchr((char *)ep->value, ':'); 
	 
	gethostname(hbuf, 256); 
	hbuf[256] = '\0'; 
	cp = (char *)malloc(strlen(hbuf) + strlen(cp2) + 1); 
	sprintf((char *)cp, "%s%s", hbuf, cp2); 
	free(ep->value); 
	ep->value = (unsigned char *)cp; 
    } 
 
    /* If USER is not defined, but LOGNAME is, then add USER with the value  */ 
    /* from LOGNAME.  By default, we don't export the USER variable.         */ 
    if ((env_find("USER") == NULL) && (ep = env_find("LOGNAME"))) { 
	env_define((unsigned char *)"USER", ep->value); 
	env_unexport((unsigned char *)"USER"); 
    } 
 
    env_export((unsigned char *)"DISPLAY"); 
    env_export((unsigned char *)"PRINTER"); 
} 
 
struct env_lst *env_define(unsigned char *var, unsigned char *value) { 
    register struct env_lst *ep; 
	 
    if ((ep = env_find(var))) { 
	if (ep->var)   free(ep->var); 
	if (ep->value) free(ep->value); 
    } else { 
	ep = (struct env_lst *)malloc(sizeof(struct env_lst)); 
	ep->next = envlisthead.next; 
	envlisthead.next = ep; 
	ep->prev = &envlisthead; 
	if (ep->next) ep->next->prev = ep; 
    } 
 
    ep->welldefined = opt_welldefined((char *)var); 
    ep->export = 1; 
    ep->var = (unsigned char *)strdup((char *)var); 
    ep->value = (unsigned char *)strdup((char *)value); 
    return(ep); 
} 
 
void env_undefine(unsigned char *var) { 
    register struct env_lst *ep; 
	 
    if ((ep = env_find(var))) { 
	ep->prev->next = ep->next; 
	if (ep->next)  ep->next->prev = ep->prev; 
	if (ep->var)   free(ep->var); 
	if (ep->value) free(ep->value); 
	free(ep); 
    } 
} 
 
void env_export(unsigned char *var) { 
    register struct env_lst *ep; 
     
    if ((ep = env_find(var))) ep->export = 1; 
} 
 
void env_unexport(unsigned char *var) { 
    register struct env_lst *ep; 
	 
    if ((ep = env_find(var))) ep->export = 0; 
} 
 
void env_send(unsigned char *var) { 
    register struct env_lst *ep; 
 
    if (my_state_is_wont(TELOPT_NEW_ENVIRON) 
#ifdef	OLD_ENVIRON 
	&& my_state_is_wont(TELOPT_OLD_ENVIRON) 
#endif 
	) { 
	fprintf(stderr, "Cannot send '%s': Telnet ENVIRON option not enabled\n", var); 
	return; 
    } 
 
    ep = env_find(var); 
     
    if (ep == 0) { 
	fprintf(stderr, "Cannot send '%s': variable not defined\n", var); 
	return; 
    } 
 
    env_opt_start_info(); 
    env_opt_add(ep->var); 
    env_opt_end(0); 
} 
 
void env_list() { 
    register struct env_lst *ep; 
     
    for (ep = envlisthead.next; ep; ep = ep->next) { 
	printf("%c %-20s %s\n", ep->export ? '*' : ' ', ep->var, ep->value); 
    } 
} 
 
	unsigned char * 
env_default(init, welldefined) 
    int init, welldefined; 
{ 
	static struct env_lst *nep = NULL; 
 
	if (init) { 
		nep = &envlisthead; 
		return NULL; 
	} 
	if (nep) { 
		while ((nep = nep->next)) { 
			if (nep->export && (nep->welldefined == welldefined)) 
				return(nep->var); 
		} 
	} 
	return(NULL); 
} 
 
	unsigned char * 
env_getvalue(var) 
	unsigned char *var; 
{ 
	register struct env_lst *ep; 
	 
	if ((ep = env_find(var))) 
		return(ep->value); 
	return(NULL); 
} 
 
#if defined(OLD_ENVIRON) && defined(ENV_HACK) 
	void 
env_varval(what) 
	unsigned char *what; 
{ 
	extern int old_env_var, old_env_value, env_auto; 
	int len = strlen((char *)what); 
 
	if (len == 0) 
		goto unknown; 
 
	if (strncasecmp((char *)what, "status", len) == 0) { 
		if (env_auto) 
			printf("%s%s", "VAR and VALUE are/will be ", 
					"determined automatically\n"); 
		if (old_env_var == OLD_ENV_VAR) 
			printf("VAR and VALUE set to correct definitions\n"); 
		else 
			printf("VAR and VALUE definitions are reversed\n"); 
	} else if (strncasecmp((char *)what, "auto", len) == 0) { 
		env_auto = 1; 
		old_env_var = OLD_ENV_VALUE; 
		old_env_value = OLD_ENV_VAR; 
	} else if (strncasecmp((char *)what, "right", len) == 0) { 
		env_auto = 0; 
		old_env_var = OLD_ENV_VAR; 
		old_env_value = OLD_ENV_VALUE; 
	} else if (strncasecmp((char *)what, "wrong", len) == 0) { 
		env_auto = 0; 
		old_env_var = OLD_ENV_VALUE; 
		old_env_value = OLD_ENV_VAR; 
	} else { 
unknown: 
		printf("Unknown \"varval\" command. (\"auto\", \"right\", \"wrong\", \"status\")\n"); 
	} 
} 
#endif 
 
 
 
#ifdef TN3270 
    static void 
filestuff(fd) 
    int fd; 
{ 
    int res; 
 
#ifdef	F_GETOWN 
    setconnmode(0); 
    res = fcntl(fd, F_GETOWN, 0); 
    setcommandmode(); 
 
    if (res == -1) { 
	perror("fcntl"); 
	return; 
    } 
    printf("\tOwner is %d.\n", res); 
#endif 
 
    setconnmode(0); 
    res = fcntl(fd, F_GETFL, 0); 
    setcommandmode(); 
 
    if (res == -1) { 
	perror("fcntl"); 
	return; 
    } 
#ifdef notdef 
    printf("\tFlags are 0x%x: %s\n", res, decodeflags(res)); 
#endif 
} 
#endif 
 
/* 
 * Print status about the connection. 
 */ 
    /*ARGSUSED*/ 
    static int  
status(argc, argv) 
    int	 argc; 
    char *argv[]; 
{ 
    if (connected) { 
	printf("Connected to %s.\n", hostname); 
	if ((argc < 2) || strcmp(argv[1], "notmuch")) { 
	    int mode = getconnmode(); 
 
	    if (my_want_state_is_will(TELOPT_LINEMODE)) { 
		printf("Operating with LINEMODE option\n"); 
		printf("%s line editing\n", (mode&MODE_EDIT) ? "Local" : "No"); 
		printf("%s catching of signals\n", 
					(mode&MODE_TRAPSIG) ? "Local" : "No"); 
		slcstate(); 
#ifdef	KLUDGELINEMODE 
	    } else if (kludgelinemode && my_want_state_is_dont(TELOPT_SGA)) { 
		printf("Operating in obsolete linemode\n"); 
#endif 
	    } else { 
		printf("Operating in single character mode\n"); 
		if (localchars) 
		    printf("Catching signals locally\n"); 
	    } 
	    printf("%s character echo\n", (mode&MODE_ECHO) ? "Local" : "Remote"); 
	    if (my_want_state_is_will(TELOPT_LFLOW)) 
		printf("%s flow control\n", (mode&MODE_FLOW) ? "Local" : "No"); 
	} 
    } else { 
	printf("No connection.\n"); 
    } 
#ifndef TN3270 
    printf("Escape character is '%s'.\n", control(escape)); 
    (void) fflush(stdout); 
#   else /* !defined(TN3270) */ 
    if ((!In3270) && ((argc < 2) || strcmp(argv[1], "notmuch"))) { 
	printf("Escape character is '%s'.\n", control(escape)); 
    } 
 
    if ((argc >= 2) && !strcmp(argv[1], "everything")) { 
	printf("SIGIO received %d time%s.\n", 
				sigiocount, (sigiocount == 1)? "":"s"); 
	if (In3270) { 
	    printf("Process ID %d, process group %d.\n", 
					    getpid(), getpgrp(getpid())); 
	    printf("Terminal input:\n"); 
	    filestuff(tin); 
	    printf("Terminal output:\n"); 
	    filestuff(tout); 
	    printf("Network socket:\n"); 
	    filestuff(net); 
	} 
    } 
    if (In3270 && transcom) { 
       printf("Transparent mode command is '%s'.\n", transcom); 
    } 
 
    fflush(stdout); 
    if (In3270) return 0; 
#   endif /* defined(TN3270) */ 
    return 1; 
} 
 
#ifdef	SIGINFO 
/* 
 * Function that gets called when SIGINFO is received. 
 */ 
     void 
ayt_status() 
{ 
    (void) call(status, "status", "notmuch", 0); 
} 
#endif 
 
    int 
tn(argc, argv) 
    int argc; 
    char *argv[]; 
{ 
    register struct hostent *host = 0; 
    struct sockaddr_in sin; 
    struct servent *sp = 0; 
    unsigned int temp; 
#if defined(IP_OPTIONS) && defined(IPPROTO_IP) 
    char *srp = 0; 
    unsigned int sourceroute(), srlen; 
#endif 
    char *cmd, *hostp = 0, *portp = 0, *user = 0; 
 
    /* clear the socket address prior to use */ 
    memset((char *)&sin, 0, sizeof(sin)); 
 
    if (connected) { 
	printf("?Already connected to %s\n", hostname); 
	setuid(getuid()); 
	return 0; 
    } 
    if (argc < 2) { 
	(void) strcpy(line, "open "); 
	printf("(to) "); 
	(void) fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin); 
	makeargv(); 
	argc = margc; 
	argv = margv; 
    } 
    cmd = *argv; 
    --argc; ++argv; 
    while (argc) { 
	if (isprefix(*argv, "help") || isprefix(*argv, "?")) 
	    goto usage; 
	if (strcmp(*argv, "-l") == 0) { 
	    --argc; ++argv; 
	    if (argc == 0) 
		goto usage; 
	    user = *argv++; 
	    --argc; 
	    continue; 
	} 
	if (strcmp(*argv, "-a") == 0) { 
	    --argc; ++argv; 
	    autologin = 1; 
	    continue; 
	} 
	if (hostp == 0) { 
	    hostp = *argv++; 
	    --argc; 
	    continue; 
	} 
	if (portp == 0) { 
	    portp = *argv++; 
	    --argc; 
	    continue; 
	} 
    usage: 
	printf("usage: %s [-l user] [-a] host-name [port]\n", cmd); 
	setuid(getuid()); 
	return 0; 
    } 
    if (hostp == 0) 
	goto usage; 
 
#if defined(IP_OPTIONS) && defined(IPPROTO_IP) 
    if (hostp[0] == '@' || hostp[0] == '!') { 
	if ((hostname = strrchr(hostp, ':')) == NULL) 
	    hostname = strrchr(hostp, '@'); 
	hostname++; 
	srp = 0; 
	temp = sourceroute(hostp, &srp, &srlen); 
	if (temp == 0) { 
	    herror(srp); 
	    setuid(getuid()); 
	    return 0; 
	} else if (temp == -1) { 
	    printf("Bad source route option: %s\n", hostp); 
	    setuid(getuid()); 
	    return 0; 
	} else { 
	    sin.sin_addr.s_addr = temp; 
	    sin.sin_family = AF_INET; 
	} 
    } else { 
#endif 
	temp = (unsigned int)inet_addr(hostp); 
	if (temp != (unsigned int) -1) { 
	    sin.sin_addr.s_addr = temp; 
	    sin.sin_family = AF_INET; 
	    (void) strcpy(_hostname, hostp); 
	    hostname = _hostname; 
	} else { 
	    host = gethostbyname(hostp); 
	    if (host) { 
		sin.sin_family = host->h_addrtype; 
#ifdef h_addr		/* In 4.3, this is a #define */ 
		memmove((caddr_t)&sin.sin_addr, 
				host->h_addr_list[0], host->h_length); 
#else	/* defined(h_addr) */ 
		memmove((caddr_t)&sin.sin_addr, host->h_addr, host->h_length); 
#endif	/* defined(h_addr) */ 
		strncpy(_hostname, host->h_name, sizeof(_hostname)); 
		_hostname[sizeof(_hostname)-1] = '\0'; 
		hostname = _hostname; 
	    } else { 
		herror(hostp); 
		setuid(getuid()); 
		return 0; 
	    } 
	} 
#if defined(IP_OPTIONS) && defined(IPPROTO_IP) 
    } 
#endif 
    if (portp) { 
	if (*portp == '-') { 
	    portp++; 
	    telnetport = 1; 
	} else 
	    telnetport = 0; 
	sin.sin_port = atoi(portp); 
	if (sin.sin_port == 0) { 
	    sp = getservbyname(portp, "tcp"); 
	    if (sp) 
		sin.sin_port = sp->s_port; 
	    else { 
		printf("%s: bad port number\n", portp); 
		setuid(getuid()); 
		return 0; 
	    } 
	} else { 
	    sin.sin_port = htons(sin.sin_port); 
	} 
    } else { 
	if (sp == 0) { 
	    sp = getservbyname("telnet", "tcp"); 
	    if (sp == 0) { 
		fprintf(stderr, "telnet: tcp/telnet: unknown service\n"); 
		setuid(getuid()); 
		return 0; 
	    } 
	    sin.sin_port = sp->s_port; 
	} 
	telnetport = 1; 
    } 
    printf("Trying %s...\n", inet_ntoa(sin.sin_addr)); 
    do { 
	net = socket(AF_INET, SOCK_STREAM, 0); 
	setuid(getuid()); 
	if (net < 0) { 
	    perror("telnet: socket"); 
	    return 0; 
	} 
#if defined(IP_OPTIONS) && defined(IPPROTO_IP) 
	if (srp && setsockopt(net, IPPROTO_IP, IP_OPTIONS, (char *)srp, srlen) < 0) 
		perror("setsockopt (IP_OPTIONS)"); 
#endif 
#if defined(IPPROTO_IP) && defined(IP_TOS) 
	{ 
#ifdef HAS_GETTOS 
	    struct tosent *tp; 
	    if (tos < 0 && (tp = gettosbyname("telnet", "tcp"))) 
		tos = tp->t_tos; 
# endif 
	    if (tos < 0) 
		tos = 020;	/* Low Delay bit */ 
	    if (tos 
		&& (setsockopt(net, IPPROTO_IP, IP_TOS, 
		    (char *)&tos, sizeof(int)) < 0) 
		&& (errno != ENOPROTOOPT)) 
		    perror("telnet: setsockopt (IP_TOS) (ignored)"); 
	} 
#endif	/* defined(IPPROTO_IP) && defined(IP_TOS) */ 
 
	if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) { 
		perror("setsockopt (SO_DEBUG)"); 
	} 
 
	if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) { 
#ifdef h_addr		/* In 4.3, this is a #define */ 
	    if (host && host->h_addr_list[1]) { 
		int oerrno = errno; 
 
		fprintf(stderr, "telnet: connect to address %s: ", 
						inet_ntoa(sin.sin_addr)); 
		errno = oerrno; 
		perror((char *)0); 
		host->h_addr_list++; 
		memmove((caddr_t)&sin.sin_addr, 
			host->h_addr_list[0], host->h_length); 
		NetClose(net); 
		continue; 
	    } 
#endif	/* defined(h_addr) */ 
	    perror("telnet: Unable to connect to remote host"); 
	    return 0; 
	} 
	connected++; 
    } while (connected == 0); 
    cmdrc(hostp, hostname); 
    if (autologin && user == NULL) { 
	struct passwd *pw; 
 
	user = getenv("USER"); 
	if (user == NULL || 
	    (((pw = getpwnam(user))) && pw->pw_uid != getuid())) { 
		if ((pw = getpwuid(getuid()))) 
			user = pw->pw_name; 
		else 
			user = NULL; 
	} 
    } 
    if (user) { 
	env_define((unsigned char *)"USER", (unsigned char *)user); 
	env_export((unsigned char *)"USER"); 
    } 
    (void) call(status, "status", "notmuch", 0); 
    if (setjmp(peerdied) == 0) 
	telnet(user); 
    NetClose(net); 
    ExitString("Connection closed by foreign host.\n",1); 
    /*NOTREACHED*/ 
    return 0; 
} 
 
#define HELPINDENT (sizeof ("connect")) 
 
static char 
	openhelp[] =	"connect to a site", 
	closehelp[] =	"close current connection", 
	logouthelp[] =	"forcibly logout remote user and close the connection", 
	quithelp[] =	"exit telnet", 
	statushelp[] =	"print status information", 
	helphelp[] =	"print help information", 
	sendhelp[] =	"transmit special characters ('send ?' for more)", 
	sethelp[] = 	"set operating parameters ('set ?' for more)", 
	unsethelp[] = 	"unset operating parameters ('unset ?' for more)", 
	togglestring[] ="toggle operating parameters ('toggle ?' for more)", 
	slchelp[] =	"change state of special charaters ('slc ?' for more)", 
	displayhelp[] =	"display operating parameters", 
#ifdef TN3270 
	transcomhelp[] = "specify Unix command for transparent mode pipe", 
#endif	/* defined(TN3270) */ 
	zhelp[] =	"suspend telnet", 
	shellhelp[] =	"invoke a subshell", 
	envhelp[] =	"change environment variables ('environ ?' for more)", 
	modestring[] = "try to enter line or character mode ('mode ?' for more)"; 
 
static int	help(); 
 
static Command cmdtab[] = { 
	{ "close",	closehelp,	bye,		1 }, 
	{ "logout",	logouthelp,	logout,		1 }, 
	{ "display",	displayhelp,	display,	0 }, 
	{ "mode",	modestring,	modecmd,	0 }, 
	{ "open",	openhelp,	tn,		0 }, 
	{ "quit",	quithelp,	quit,		0 }, 
	{ "send",	sendhelp,	sendcmd,	0 }, 
	{ "set",	sethelp,	setcmd,		0 }, 
	{ "unset",	unsethelp,	unsetcmd,	0 }, 
	{ "status",	statushelp,	status,		0 }, 
	{ "toggle",	togglestring,	toggle,		0 }, 
	{ "slc",	slchelp,	slccmd,		0 }, 
#ifdef TN3270 
	{ "transcom",	transcomhelp,	settranscom,	0 }, 
#endif	/* defined(TN3270) */ 
	{ "z",		zhelp,		suspend,	0 }, 
#ifdef TN3270 
	{ "!",		shellhelp,	shell,		1 }, 
#else 
	{ "!",		shellhelp,	shell,		0 }, 
#endif 
	{ "environ",	envhelp,	env_cmd,	0 }, 
	{ "?",		helphelp,	help,		0 }, 
	{ 0 }  
}; 
 
static char	crmodhelp[] =	"deprecated command -- use 'toggle crmod' instead"; 
static char	escapehelp[] =	"deprecated command -- use 'set escape' instead"; 
 
static Command cmdtab2[] = { 
	{ "help",	0,		help,		0 }, 
	{ "escape",	escapehelp,	setescape,	0 }, 
	{ "crmod",	crmodhelp,	togcrmod,	0 }, 
	{ 0 } 
}; 
 
 
/* 
 * Call routine with argc, argv set from args (terminated by 0). 
 */ 
 
    /*VARARGS1*/ 
    static int 
call(va_alist) 
    va_dcl 
{ 
    va_list ap; 
    typedef int (*intrtn_t)(); 
    intrtn_t routine; 
    char *args[100]; 
    int argno = 0; 
 
    va_start(ap); 
    routine = (va_arg(ap, intrtn_t)); 
    while ((args[argno++] = va_arg(ap, char *)) != 0) { 
	; 
    } 
    va_end(ap); 
    return (*routine)(argno-1, args); 
} 
 
 
    static Command * 
getcmd(name) 
    char *name; 
{ 
    Command *cm; 
     
    if ((cm = (Command *) genget(name, (char **) cmdtab, sizeof(Command))))  
	return cm; 
    return (Command *) genget(name, (char **) cmdtab2, sizeof(Command)); 
} 
 
    void 
command(top, tbuf, cnt) 
    int top; 
    char *tbuf; 
    int cnt; 
{ 
    register Command *c; 
 
    setcommandmode(); 
    if (!top) { 
	putchar('\n'); 
    } else { 
	Signal(SIGINT, SIG_DFL); 
	Signal(SIGQUIT, SIG_DFL); 
    } 
    for (;;) { 
	if (rlogin == _POSIX_VDISABLE) 
		printf("%s> ", prompt); 
	if (tbuf) { 
	    register char *cp; 
	    cp = line; 
	    while (cnt > 0 && (*cp++ = *tbuf++) != '\n') 
		cnt--; 
	    tbuf = 0; 
	    if (cp == line || *--cp != '\n' || cp == line) 
		goto getline; 
	    *cp = '\0'; 
	    if (rlogin == _POSIX_VDISABLE) 
		printf("%s\n", line); 
	} else { 
	getline: 
	    if (rlogin != _POSIX_VDISABLE) 
		printf("%s> ", prompt); 
	    if (fgets(line, sizeof(line), stdin) == NULL) { 
		if (feof(stdin) || ferror(stdin)) { 
		    (void) quit(); 
		    /*NOTREACHED*/ 
		} 
		break; 
	    } 
	} 
	if (line[0] == 0) 
	    break; 
	makeargv(); 
	if (margv[0] == 0) { 
	    break; 
	} 
	c = getcmd(margv[0]); 
	if (Ambiguous(c)) { 
	    printf("?Ambiguous command\n"); 
	    continue; 
	} 
	if (c == 0) { 
	    printf("?Invalid command\n"); 
	    continue; 
	} 
	if (c->needconnect && !connected) { 
	    printf("?Need to be connected first.\n"); 
	    continue; 
	} 
	if ((*c->handler)(margc, margv)) { 
	    break; 
	} 
    } 
    if (!top) { 
	if (!connected) { 
	    longjmp(toplevel, 1); 
	    /*NOTREACHED*/ 
	} 
#ifdef TN3270 
	if (shell_active == 0) { 
	    setconnmode(0); 
	} 
#else	/* defined(TN3270) */ 
	setconnmode(0); 
#endif	/* defined(TN3270) */ 
    } 
} 
 
/* 
 * Help command. 
 */ 
	static int 
help(argc, argv) 
	int argc; 
	char *argv[]; 
{ 
	register Command *c; 
 
	if (argc == 1) { 
		printf("Commands may be abbreviated.  Commands are:\n\n"); 
		for (c = cmdtab; c->name; c++) 
			if (c->help) { 
			    printf("%-*s\t%s\n", (int)HELPINDENT, c->name, c->help); 
			} 
		return 0; 
	} 
	while (--argc > 0) { 
		register char *arg; 
		arg = *++argv; 
		c = getcmd(arg); 
		if (Ambiguous(c)) 
			printf("?Ambiguous help command %s\n", arg); 
		else if (c == (Command *)0) 
			printf("?Invalid help command %s\n", arg); 
		else 
			printf("%s\n", c->help); 
	} 
	return 0; 
} 
 
static char *rcname = 0; 
static char rcbuf[128]; 
 
    void 
cmdrc(m1, m2) 
    char *m1, *m2; 
{ 
    register Command *c; 
    FILE *rcfile; 
    int gotmachine = 0; 
    int l1 = strlen(m1); 
    int l2 = strlen(m2); 
    char m1save[64]; 
     
    if (skiprc) 
	return; 
 
    strcpy(m1save, m1); 
    m1 = m1save; 
 
    if (rcname == 0) { 
	rcname = getenv("HOME"); 
	if (rcname) 
	    strcpy(rcbuf, rcname); 
	else 
	    rcbuf[0] = '\0'; 
	strcat(rcbuf, "/.telnetrc"); 
	rcname = rcbuf; 
    } 
 
    if ((rcfile = fopen(rcname, "r")) == 0) { 
	return; 
    } 
 
    for (;;) { 
	if (fgets(line, sizeof(line), rcfile) == NULL) 
	    break; 
	if (line[0] == 0) 
	    break; 
	if (line[0] == '#') 
	    continue; 
	if (gotmachine) { 
	    if (!isspace(line[0])) 
		gotmachine = 0; 
	} 
	if (gotmachine == 0) { 
	    if (isspace(line[0])) 
		continue; 
	    if (strncasecmp(line, m1, l1) == 0) 
		strncpy(line, &line[l1], sizeof(line) - l1); 
	    else if (strncasecmp(line, m2, l2) == 0) 
		strncpy(line, &line[l2], sizeof(line) - l2); 
	    else if (strncasecmp(line, "DEFAULT", 7) == 0) 
		strncpy(line, &line[7], sizeof(line) - 7); 
	    else 
		continue; 
	    if (line[0] != ' ' && line[0] != '\t' && line[0] != '\n') 
		continue; 
	    gotmachine = 1; 
	} 
	makeargv(); 
	if (margv[0] == 0) 
	    continue; 
	c = getcmd(margv[0]); 
	if (Ambiguous(c)) { 
	    printf("?Ambiguous command: %s\n", margv[0]); 
	    continue; 
	} 
	if (c == 0) { 
	    printf("?Invalid command: %s\n", margv[0]); 
	    continue; 
	} 
	/* 
	 * This should never happen... 
	 */ 
	if (c->needconnect && !connected) { 
	    printf("?Need to be connected first for %s.\n", margv[0]); 
	    continue; 
	} 
	(*c->handler)(margc, margv); 
    } 
    fclose(rcfile); 
} 
 
#if defined(IP_OPTIONS) && defined(IPPROTO_IP) 
 
/* 
 * Source route is handed in as 
 *	[!]@hop1@hop2...[@|:]dst 
 * If the leading ! is present, it is a 
 * strict source route, otherwise it is 
 * assmed to be a loose source route. 
 * 
 * We fill in the source route option as 
 *	hop1,hop2,hop3...dest 
 * and return a pointer to hop1, which will 
 * be the address to connect() to. 
 * 
 * Arguments: 
 *	arg:	pointer to route list to decipher 
 * 
 *	cpp: 	If *cpp is not equal to NULL, this is a 
 *		pointer to a pointer to a character array 
 *		that should be filled in with the option. 
 * 
 *	lenp:	pointer to an integer that contains the 
 *		length of *cpp if *cpp != NULL. 
 * 
 * Return values: 
 * 
 *	Returns the address of the host to connect to.  If the 
 *	return value is -1, there was a syntax error in the 
 *	option, either unknown characters, or too many hosts. 
 *	If the return value is 0, one of the hostnames in the 
 *	path is unknown, and *cpp is set to point to the bad 
 *	hostname. 
 * 
 *	*cpp:	If *cpp was equal to NULL, it will be filled 
 *		in with a pointer to our static area that has 
 *		the option filled in.  This will be 32bit aligned. 
 * 
 *	*lenp:	This will be filled in with how long the option 
 *		pointed to by *cpp is. 
 * 
 */ 
	unsigned int 
sourceroute(arg, cpp, lenp) 
	char	*arg; 
	char	**cpp; 
	int	*lenp; 
{ 
	static char lsr[44]; 
#ifdef	sysV88 
	static IOPTN ipopt; 
#endif 
	char *cp, *cp2, *lsrp, *lsrep; 
	register int tmp; 
	struct in_addr sin_addr; 
	register struct hostent *host = 0; 
	register char c; 
 
	/* 
	 * Verify the arguments, and make sure we have 
	 * at least 7 bytes for the option. 
	 */ 
	if (cpp == NULL || lenp == NULL) 
		return((unsigned int)-1); 
	if (*cpp != NULL && *lenp < 7) 
		return((unsigned int)-1); 
	/* 
	 * Decide whether we have a buffer passed to us, 
	 * or if we need to use our own static buffer. 
	 */ 
	if (*cpp) { 
		lsrp = *cpp; 
		lsrep = lsrp + *lenp; 
	} else { 
		*cpp = lsrp = lsr; 
		lsrep = lsrp + 44; 
	} 
 
	cp = arg; 
 
	/* 
	 * Next, decide whether we have a loose source 
	 * route or a strict source route, and fill in 
	 * the begining of the option. 
	 */ 
#ifndef	sysV88 
	if (*cp == '!') { 
		cp++; 
		*lsrp++ = IPOPT_SSRR; 
	} else 
		*lsrp++ = IPOPT_LSRR; 
#else 
	if (*cp == '!') { 
		cp++; 
		ipopt.io_type = IPOPT_SSRR; 
	} else 
		ipopt.io_type = IPOPT_LSRR; 
#endif 
 
	if (*cp != '@') 
		return((unsigned int)-1); 
 
#ifndef	sysV88 
	lsrp++;		/* skip over length, we'll fill it in later */ 
	*lsrp++ = 4; 
#endif 
 
	cp++; 
 
	sin_addr.s_addr = 0; 
 
	for (c = 0;;) { 
		if (c == ':') 
			cp2 = 0; 
		else for (cp2 = cp; (c = *cp2); cp2++) { 
			if (c == ',') { 
				*cp2++ = '\0'; 
				if (*cp2 == '@') 
					cp2++; 
			} else if (c == '@') { 
				*cp2++ = '\0'; 
			} else if (c == ':') { 
				*cp2++ = '\0'; 
			} else 
				continue; 
			break; 
		} 
		if (!c) 
			cp2 = 0; 
 
		if ((tmp = inet_addr(cp)) != -1) { 
			sin_addr.s_addr = tmp; 
		} else if ((host = gethostbyname(cp))) { 
#ifdef h_addr 
			memmove((caddr_t)&sin_addr, 
				host->h_addr_list[0], host->h_length); 
#else 
			memmove((caddr_t)&sin_addr, host->h_addr, host->h_length); 
#endif 
		} else { 
			*cpp = cp; 
			return(0); 
		} 
		memmove(lsrp, (char *)&sin_addr, 4); 
		lsrp += 4; 
		if (cp2) 
			cp = cp2; 
		else 
			break; 
		/* 
		 * Check to make sure there is space for next address 
		 */ 
		if (lsrp + 4 > lsrep) 
			return((unsigned int)-1); 
	} 
#ifndef	sysV88 
	if ((*(*cpp+IPOPT_OLEN) = lsrp - *cpp) <= 7) { 
		*cpp = 0; 
		*lenp = 0; 
		return((unsigned int)-1); 
	} 
	*lsrp++ = IPOPT_NOP; /* 32 bit word align it */ 
	*lenp = lsrp - *cpp; 
#else 
	ipopt.io_len = lsrp - *cpp; 
	if (ipopt.io_len <= 5) {		/* Is 3 better ? */ 
		*cpp = 0; 
		*lenp = 0; 
		return((unsigned int)-1); 
	} 
	*lenp = sizeof(ipopt); 
	*cpp = (char *) &ipopt; 
#endif 
	return(sin_addr.s_addr); 
} 
#endif