xref: /csrg-svn/usr.bin/telnet/commands.c (revision 37219)
133685Sbostic /*
233685Sbostic  * Copyright (c) 1988 Regents of the University of California.
333685Sbostic  * All rights reserved.
433685Sbostic  *
533685Sbostic  * Redistribution and use in source and binary forms are permitted
634898Sbostic  * provided that the above copyright notice and this paragraph are
734898Sbostic  * duplicated in all such forms and that any documentation,
834898Sbostic  * advertising materials, and other materials related to such
934898Sbostic  * distribution and use acknowledge that the software was developed
1034898Sbostic  * by the University of California, Berkeley.  The name of the
1134898Sbostic  * University may not be used to endorse or promote products derived
1234898Sbostic  * from this software without specific prior written permission.
1334898Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1434898Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1534898Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1633685Sbostic  */
1733685Sbostic 
1833685Sbostic #ifndef lint
19*37219Sminshall static char sccsid[] = "@(#)commands.c	1.16 (Berkeley) 03/20/89";
2033685Sbostic #endif /* not lint */
2133685Sbostic 
2232144Sminshall #include <sys/types.h>
2336274Sminshall #if	defined(unix)
2436274Sminshall #include <sys/file.h>
2536274Sminshall #endif	/* defined(unix) */
2632144Sminshall #include <sys/socket.h>
2732144Sminshall #include <netinet/in.h>
2832144Sminshall 
2932144Sminshall #include <signal.h>
3032144Sminshall #include <netdb.h>
3132144Sminshall #include <ctype.h>
3235298Sminshall #include <varargs.h>
3332144Sminshall 
3432144Sminshall #include <arpa/telnet.h>
3532144Sminshall 
3634305Sminshall #include "general.h"
3734305Sminshall 
3832381Sminshall #include "ring.h"
3932381Sminshall 
4032144Sminshall #include "externs.h"
4132144Sminshall #include "defines.h"
4232144Sminshall #include "types.h"
4332144Sminshall 
4432144Sminshall char	*hostname;
4532144Sminshall 
4636180Sminshall #define Ambiguous(s)	((char **)s == &ambiguous)
4732144Sminshall static char *ambiguous;		/* special return value for command routines */
4832144Sminshall 
4932144Sminshall typedef struct {
5032144Sminshall 	char	*name;		/* command name */
5132144Sminshall 	char	*help;		/* help string */
5232144Sminshall 	int	(*handler)();	/* routine which executes command */
5332144Sminshall 	int	dohelp;		/* Should we give general help information? */
5432144Sminshall 	int	needconnect;	/* Do we need to be connected to execute? */
5532144Sminshall } Command;
5632144Sminshall 
5732144Sminshall static char line[200];
5832144Sminshall static int margc;
5932144Sminshall static char *margv[20];
6032144Sminshall 
6132144Sminshall /*
6232144Sminshall  * Various utility routines.
6332144Sminshall  */
6432144Sminshall 
6536180Sminshall #if	!defined(BSD) || (BSD <= 43)
6636180Sminshall 
6736180Sminshall char	*h_errlist[] = {
6836180Sminshall 	"Error 0",
6936180Sminshall 	"Unknown host",				/* 1 HOST_NOT_FOUND */
7036180Sminshall 	"Host name lookup failure",		/* 2 TRY_AGAIN */
7136180Sminshall 	"Unknown server error",			/* 3 NO_RECOVERY */
7236180Sminshall 	"No address associated with name",	/* 4 NO_ADDRESS */
7336180Sminshall };
7436180Sminshall int	h_nerr = { sizeof(h_errlist)/sizeof(h_errlist[0]) };
7536180Sminshall 
7636274Sminshall int h_errno;		/* In some version of SunOS this is necessary */
7736180Sminshall 
7836180Sminshall /*
7936180Sminshall  * herror --
8036180Sminshall  *	print the error indicated by the h_errno value.
8136180Sminshall  */
8236180Sminshall herror(s)
8336180Sminshall 	char *s;
8436180Sminshall {
8536180Sminshall 	if (s && *s) {
8636180Sminshall 		fprintf(stderr, "%s: ", s);
8736180Sminshall 	}
8836180Sminshall 	if ((h_errno < 0) || (h_errno >= h_nerr)) {
8936180Sminshall 		fprintf(stderr, "Unknown error\n");
9036274Sminshall 	} else if (h_errno == 0) {
9136274Sminshall #if	defined(sun)
9236274Sminshall 		fprintf(stderr, "Host unknown\n");
9336274Sminshall #endif	/* defined(sun) */
9436180Sminshall 	} else {
9536180Sminshall 		fprintf(stderr, "%s\n", h_errlist[h_errno]);
9636180Sminshall 	}
9736180Sminshall }
9836180Sminshall #endif	/* !define(BSD) || (BSD <= 43) */
9936180Sminshall 
10032144Sminshall static void
10132144Sminshall makeargv()
10232144Sminshall {
10332144Sminshall     register char *cp;
10432144Sminshall     register char **argp = margv;
10532144Sminshall 
10632144Sminshall     margc = 0;
10732144Sminshall     cp = line;
10832144Sminshall     if (*cp == '!') {		/* Special case shell escape */
10932144Sminshall 	*argp++ = "!";		/* No room in string to get this */
11032144Sminshall 	margc++;
11132144Sminshall 	cp++;
11232144Sminshall     }
11332144Sminshall     while (*cp) {
11432144Sminshall 	while (isspace(*cp))
11532144Sminshall 	    cp++;
11632144Sminshall 	if (*cp == '\0')
11732144Sminshall 	    break;
11832144Sminshall 	*argp++ = cp;
11932144Sminshall 	margc += 1;
12032144Sminshall 	while (*cp != '\0' && !isspace(*cp))
12132144Sminshall 	    cp++;
12232144Sminshall 	if (*cp == '\0')
12332144Sminshall 	    break;
12432144Sminshall 	*cp++ = '\0';
12532144Sminshall     }
12632144Sminshall     *argp++ = 0;
12732144Sminshall }
12832144Sminshall 
12932144Sminshall 
13032144Sminshall static char **
13132144Sminshall genget(name, table, next)
13232144Sminshall char	*name;		/* name to match */
13332144Sminshall char	**table;		/* name entry in table */
13432144Sminshall char	**(*next)();	/* routine to return next entry in table */
13532144Sminshall {
13632144Sminshall 	register char *p, *q;
13732144Sminshall 	register char **c, **found;
13832144Sminshall 	register int nmatches, longest;
13932144Sminshall 
14032144Sminshall 	if (name == 0) {
14132144Sminshall 	    return 0;
14232144Sminshall 	}
14332144Sminshall 	longest = 0;
14432144Sminshall 	nmatches = 0;
14532144Sminshall 	found = 0;
14632144Sminshall 	for (c = table; (p = *c) != 0; c = (*next)(c)) {
14732144Sminshall 		for (q = name;
14832144Sminshall 		    (*q == *p) || (isupper(*q) && tolower(*q) == *p); p++, q++)
14932144Sminshall 			if (*q == 0)		/* exact match? */
15032144Sminshall 				return (c);
15132144Sminshall 		if (!*q) {			/* the name was a prefix */
15232144Sminshall 			if (q - name > longest) {
15332144Sminshall 				longest = q - name;
15432144Sminshall 				nmatches = 1;
15532144Sminshall 				found = c;
15632144Sminshall 			} else if (q - name == longest)
15732144Sminshall 				nmatches++;
15832144Sminshall 		}
15932144Sminshall 	}
16032144Sminshall 	if (nmatches > 1)
16136180Sminshall 		return &ambiguous;
16232144Sminshall 	return (found);
16332144Sminshall }
16432144Sminshall 
16532144Sminshall /*
16632144Sminshall  * Make a character string into a number.
16732144Sminshall  *
16832144Sminshall  * Todo:  1.  Could take random integers (12, 0x12, 012, 0b1).
16932144Sminshall  */
17032144Sminshall 
17132144Sminshall static
17232144Sminshall special(s)
17332144Sminshall register char *s;
17432144Sminshall {
17532144Sminshall 	register char c;
17632144Sminshall 	char b;
17732144Sminshall 
17832144Sminshall 	switch (*s) {
17932144Sminshall 	case '^':
18032144Sminshall 		b = *++s;
18132144Sminshall 		if (b == '?') {
18232144Sminshall 		    c = b | 0x40;		/* DEL */
18332144Sminshall 		} else {
18432144Sminshall 		    c = b & 0x1f;
18532144Sminshall 		}
18632144Sminshall 		break;
18732144Sminshall 	default:
18832144Sminshall 		c = *s;
18932144Sminshall 		break;
19032144Sminshall 	}
19132144Sminshall 	return c;
19232144Sminshall }
19332144Sminshall 
19432144Sminshall /*
19532144Sminshall  * Construct a control character sequence
19632144Sminshall  * for a special character.
19732144Sminshall  */
19832144Sminshall static char *
19932144Sminshall control(c)
20032144Sminshall 	register int c;
20132144Sminshall {
20232144Sminshall 	static char buf[3];
20332144Sminshall 
20432144Sminshall 	if (c == 0x7f)
20532144Sminshall 		return ("^?");
20632144Sminshall 	if (c == '\377') {
20732144Sminshall 		return "off";
20832144Sminshall 	}
20932144Sminshall 	if (c >= 0x20) {
21032144Sminshall 		buf[0] = c;
21132144Sminshall 		buf[1] = 0;
21232144Sminshall 	} else {
21332144Sminshall 		buf[0] = '^';
21432144Sminshall 		buf[1] = '@'+c;
21532144Sminshall 		buf[2] = 0;
21632144Sminshall 	}
21732144Sminshall 	return (buf);
21832144Sminshall }
21932144Sminshall 
22032144Sminshall 
22132144Sminshall 
22232144Sminshall /*
22332144Sminshall  *	The following are data structures and routines for
22432144Sminshall  *	the "send" command.
22532144Sminshall  *
22632144Sminshall  */
22732144Sminshall 
22832144Sminshall struct sendlist {
22932144Sminshall     char	*name;		/* How user refers to it (case independent) */
23032144Sminshall     int		what;		/* Character to be sent (<0 ==> special) */
23132144Sminshall     char	*help;		/* Help information (0 ==> no help) */
23232144Sminshall #if	defined(NOT43)
23332144Sminshall     int		(*routine)();	/* Routine to perform (for special ops) */
23432144Sminshall #else	/* defined(NOT43) */
23532144Sminshall     void	(*routine)();	/* Routine to perform (for special ops) */
23632144Sminshall #endif	/* defined(NOT43) */
23732144Sminshall };
23832144Sminshall 
23932144Sminshall #define	SENDQUESTION	-1
24032144Sminshall #define	SENDESCAPE	-3
24132144Sminshall 
24232144Sminshall static struct sendlist Sendlist[] = {
24332144Sminshall     { "ao", AO, "Send Telnet Abort output" },
24432144Sminshall     { "ayt", AYT, "Send Telnet 'Are You There'" },
24532144Sminshall     { "brk", BREAK, "Send Telnet Break" },
24632144Sminshall     { "ec", EC, "Send Telnet Erase Character" },
24732144Sminshall     { "el", EL, "Send Telnet Erase Line" },
24832144Sminshall     { "escape", SENDESCAPE, "Send current escape character" },
24932144Sminshall     { "ga", GA, "Send Telnet 'Go Ahead' sequence" },
25032144Sminshall     { "ip", IP, "Send Telnet Interrupt Process" },
25132144Sminshall     { "nop", NOP, "Send Telnet 'No operation'" },
25232144Sminshall     { "synch", SYNCH, "Perform Telnet 'Synch operation'", dosynch },
25332144Sminshall     { "?", SENDQUESTION, "Display send options" },
25432144Sminshall     { 0 }
25532144Sminshall };
25632144Sminshall 
25732144Sminshall static struct sendlist Sendlist2[] = {		/* some synonyms */
25832144Sminshall 	{ "break", BREAK, 0 },
25932144Sminshall 
26032144Sminshall 	{ "intp", IP, 0 },
26132144Sminshall 	{ "interrupt", IP, 0 },
26232144Sminshall 	{ "intr", IP, 0 },
26332144Sminshall 
26432144Sminshall 	{ "help", SENDQUESTION, 0 },
26532144Sminshall 
26632144Sminshall 	{ 0 }
26732144Sminshall };
26832144Sminshall 
26932144Sminshall static char **
27032144Sminshall getnextsend(name)
27132144Sminshall char *name;
27232144Sminshall {
27332144Sminshall     struct sendlist *c = (struct sendlist *) name;
27432144Sminshall 
27532144Sminshall     return (char **) (c+1);
27632144Sminshall }
27732144Sminshall 
27832144Sminshall static struct sendlist *
27932144Sminshall getsend(name)
28032144Sminshall char *name;
28132144Sminshall {
28232144Sminshall     struct sendlist *sl;
28332144Sminshall 
28432144Sminshall     if ((sl = (struct sendlist *)
28532144Sminshall 			genget(name, (char **) Sendlist, getnextsend)) != 0) {
28632144Sminshall 	return sl;
28732144Sminshall     } else {
28832144Sminshall 	return (struct sendlist *)
28932144Sminshall 				genget(name, (char **) Sendlist2, getnextsend);
29032144Sminshall     }
29132144Sminshall }
29232144Sminshall 
29332144Sminshall static
29432144Sminshall sendcmd(argc, argv)
29532144Sminshall int	argc;
29632144Sminshall char	**argv;
29732144Sminshall {
29832144Sminshall     int what;		/* what we are sending this time */
29932144Sminshall     int count;		/* how many bytes we are going to need to send */
30032144Sminshall     int i;
30132144Sminshall     int question = 0;	/* was at least one argument a question */
30232144Sminshall     struct sendlist *s;	/* pointer to current command */
30332144Sminshall 
30432144Sminshall     if (argc < 2) {
30532144Sminshall 	printf("need at least one argument for 'send' command\n");
30632144Sminshall 	printf("'send ?' for help\n");
30732144Sminshall 	return 0;
30832144Sminshall     }
30932144Sminshall     /*
31032144Sminshall      * First, validate all the send arguments.
31132144Sminshall      * In addition, we see how much space we are going to need, and
31232144Sminshall      * whether or not we will be doing a "SYNCH" operation (which
31332144Sminshall      * flushes the network queue).
31432144Sminshall      */
31532144Sminshall     count = 0;
31632144Sminshall     for (i = 1; i < argc; i++) {
31732144Sminshall 	s = getsend(argv[i]);
31832144Sminshall 	if (s == 0) {
31932144Sminshall 	    printf("Unknown send argument '%s'\n'send ?' for help.\n",
32032144Sminshall 			argv[i]);
32132144Sminshall 	    return 0;
32232144Sminshall 	} else if (Ambiguous(s)) {
32332144Sminshall 	    printf("Ambiguous send argument '%s'\n'send ?' for help.\n",
32432144Sminshall 			argv[i]);
32532144Sminshall 	    return 0;
32632144Sminshall 	}
32732144Sminshall 	switch (s->what) {
32832144Sminshall 	case SENDQUESTION:
32932144Sminshall 	    break;
33032144Sminshall 	case SENDESCAPE:
33132144Sminshall 	    count += 1;
33232144Sminshall 	    break;
33332144Sminshall 	case SYNCH:
33432144Sminshall 	    count += 2;
33532144Sminshall 	    break;
33632144Sminshall 	default:
33732144Sminshall 	    count += 2;
33832144Sminshall 	    break;
33932144Sminshall 	}
34032144Sminshall     }
34132144Sminshall     /* Now, do we have enough room? */
34232144Sminshall     if (NETROOM() < count) {
34332144Sminshall 	printf("There is not enough room in the buffer TO the network\n");
34432144Sminshall 	printf("to process your request.  Nothing will be done.\n");
34532144Sminshall 	printf("('send synch' will throw away most data in the network\n");
34632144Sminshall 	printf("buffer, if this might help.)\n");
34732144Sminshall 	return 0;
34832144Sminshall     }
34932144Sminshall     /* OK, they are all OK, now go through again and actually send */
35032144Sminshall     for (i = 1; i < argc; i++) {
35132144Sminshall 	if ((s = getsend(argv[i])) == 0) {
35232144Sminshall 	    fprintf(stderr, "Telnet 'send' error - argument disappeared!\n");
35332144Sminshall 	    quit();
35432144Sminshall 	    /*NOTREACHED*/
35532144Sminshall 	}
35632144Sminshall 	if (s->routine) {
35732144Sminshall 	    (*s->routine)(s);
35832144Sminshall 	} else {
35932144Sminshall 	    switch (what = s->what) {
36032144Sminshall 	    case SYNCH:
36132144Sminshall 		dosynch();
36232144Sminshall 		break;
36332144Sminshall 	    case SENDQUESTION:
36432144Sminshall 		for (s = Sendlist; s->name; s++) {
36532144Sminshall 		    if (s->help) {
36632144Sminshall 			printf(s->name);
36732144Sminshall 			if (s->help) {
36832144Sminshall 			    printf("\t%s", s->help);
36932144Sminshall 			}
37032144Sminshall 			printf("\n");
37132144Sminshall 		    }
37232144Sminshall 		}
37332144Sminshall 		question = 1;
37432144Sminshall 		break;
37532144Sminshall 	    case SENDESCAPE:
37632144Sminshall 		NETADD(escape);
37732144Sminshall 		break;
37832144Sminshall 	    default:
37932144Sminshall 		NET2ADD(IAC, what);
38032144Sminshall 		break;
38132144Sminshall 	    }
38232144Sminshall 	}
38332144Sminshall     }
38432144Sminshall     return !question;
38532144Sminshall }
38632144Sminshall 
38732144Sminshall /*
38832144Sminshall  * The following are the routines and data structures referred
38932144Sminshall  * to by the arguments to the "toggle" command.
39032144Sminshall  */
39132144Sminshall 
39232144Sminshall static
39332144Sminshall lclchars()
39432144Sminshall {
39532144Sminshall     donelclchars = 1;
39632144Sminshall     return 1;
39732144Sminshall }
39832144Sminshall 
39932144Sminshall static
40032144Sminshall togdebug()
40132144Sminshall {
40232144Sminshall #ifndef	NOT43
40332144Sminshall     if (net > 0 &&
40432144Sminshall 	(SetSockOpt(net, SOL_SOCKET, SO_DEBUG, debug)) < 0) {
40532144Sminshall 	    perror("setsockopt (SO_DEBUG)");
40632144Sminshall     }
40732144Sminshall #else	/* NOT43 */
40832144Sminshall     if (debug) {
40932144Sminshall 	if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
41032144Sminshall 	    perror("setsockopt (SO_DEBUG)");
41132144Sminshall     } else
41232144Sminshall 	printf("Cannot turn off socket debugging\n");
41332144Sminshall #endif	/* NOT43 */
41432144Sminshall     return 1;
41532144Sminshall }
41632144Sminshall 
41732144Sminshall 
41832144Sminshall static int
41932144Sminshall togcrlf()
42032144Sminshall {
42132144Sminshall     if (crlf) {
42232144Sminshall 	printf("Will send carriage returns as telnet <CR><LF>.\n");
42332144Sminshall     } else {
42432144Sminshall 	printf("Will send carriage returns as telnet <CR><NUL>.\n");
42532144Sminshall     }
42632144Sminshall     return 1;
42732144Sminshall }
42832144Sminshall 
42932144Sminshall 
43032144Sminshall static int
43132144Sminshall togbinary()
43232144Sminshall {
43332144Sminshall     donebinarytoggle = 1;
43432144Sminshall 
43532144Sminshall     if (myopts[TELOPT_BINARY] == 0) {	/* Go into binary mode */
43632144Sminshall 	NET2ADD(IAC, DO);
43732144Sminshall 	NETADD(TELOPT_BINARY);
43832144Sminshall 	printoption("<SENT", doopt, TELOPT_BINARY, 0);
43932144Sminshall 	NET2ADD(IAC, WILL);
44032144Sminshall 	NETADD(TELOPT_BINARY);
44132144Sminshall 	printoption("<SENT", doopt, TELOPT_BINARY, 0);
44232144Sminshall 	hisopts[TELOPT_BINARY] = myopts[TELOPT_BINARY] = 1;
44332144Sminshall 	printf("Negotiating binary mode with remote host.\n");
44432144Sminshall     } else {				/* Turn off binary mode */
44532144Sminshall 	NET2ADD(IAC, DONT);
44632144Sminshall 	NETADD(TELOPT_BINARY);
44732144Sminshall 	printoption("<SENT", dont, TELOPT_BINARY, 0);
44832144Sminshall 	NET2ADD(IAC, DONT);
44932144Sminshall 	NETADD(TELOPT_BINARY);
45032144Sminshall 	printoption("<SENT", dont, TELOPT_BINARY, 0);
45132144Sminshall 	hisopts[TELOPT_BINARY] = myopts[TELOPT_BINARY] = 0;
45232144Sminshall 	printf("Negotiating network ascii mode with remote host.\n");
45332144Sminshall     }
45432144Sminshall     return 1;
45532144Sminshall }
45632144Sminshall 
45732144Sminshall 
45832144Sminshall 
45932144Sminshall extern int togglehelp();
46032144Sminshall 
46132144Sminshall struct togglelist {
46232144Sminshall     char	*name;		/* name of toggle */
46332144Sminshall     char	*help;		/* help message */
46432144Sminshall     int		(*handler)();	/* routine to do actual setting */
46532144Sminshall     int		dohelp;		/* should we display help information */
46632144Sminshall     int		*variable;
46732144Sminshall     char	*actionexplanation;
46832144Sminshall };
46932144Sminshall 
47032144Sminshall static struct togglelist Togglelist[] = {
47132144Sminshall     { "autoflush",
47232144Sminshall 	"toggle flushing of output when sending interrupt characters",
47332144Sminshall 	    0,
47432144Sminshall 		1,
47532144Sminshall 		    &autoflush,
47632144Sminshall 			"flush output when sending interrupt characters" },
47732144Sminshall     { "autosynch",
47832144Sminshall 	"toggle automatic sending of interrupt characters in urgent mode",
47932144Sminshall 	    0,
48032144Sminshall 		1,
48132144Sminshall 		    &autosynch,
48232144Sminshall 			"send interrupt characters in urgent mode" },
48332144Sminshall     { "binary",
48432144Sminshall 	"toggle sending and receiving of binary data",
48532144Sminshall 	    togbinary,
48632144Sminshall 		1,
48732144Sminshall 		    0,
48832144Sminshall 			0 },
48932144Sminshall     { "crlf",
49032144Sminshall 	"toggle sending carriage returns as telnet <CR><LF>",
49132144Sminshall 	    togcrlf,
49232144Sminshall 		1,
49332144Sminshall 		    &crlf,
49432144Sminshall 			0 },
49532144Sminshall     { "crmod",
49632144Sminshall 	"toggle mapping of received carriage returns",
49732144Sminshall 	    0,
49832144Sminshall 		1,
49932144Sminshall 		    &crmod,
50032144Sminshall 			"map carriage return on output" },
50132144Sminshall     { "localchars",
50232144Sminshall 	"toggle local recognition of certain control characters",
50332144Sminshall 	    lclchars,
50432144Sminshall 		1,
50532144Sminshall 		    &localchars,
50632144Sminshall 			"recognize certain control characters" },
50732144Sminshall     { " ", "", 0, 1 },		/* empty line */
50832144Sminshall     { "debug",
50932144Sminshall 	"(debugging) toggle debugging",
51032144Sminshall 	    togdebug,
51132144Sminshall 		1,
51232144Sminshall 		    &debug,
51332144Sminshall 			"turn on socket level debugging" },
51432144Sminshall     { "netdata",
51532144Sminshall 	"(debugging) toggle printing of hexadecimal network data",
51632144Sminshall 	    0,
51732144Sminshall 		1,
51832144Sminshall 		    &netdata,
51932144Sminshall 			"print hexadecimal representation of network traffic" },
52032144Sminshall     { "options",
52132144Sminshall 	"(debugging) toggle viewing of options processing",
52232144Sminshall 	    0,
52332144Sminshall 		1,
52432144Sminshall 		    &showoptions,
52532144Sminshall 			"show option processing" },
52632144Sminshall     { " ", "", 0, 1 },		/* empty line */
52732144Sminshall     { "?",
52832144Sminshall 	"display help information",
52932144Sminshall 	    togglehelp,
53032144Sminshall 		1 },
53132144Sminshall     { "help",
53232144Sminshall 	"display help information",
53332144Sminshall 	    togglehelp,
53432144Sminshall 		0 },
53532144Sminshall     { 0 }
53632144Sminshall };
53732144Sminshall 
53832144Sminshall static
53932144Sminshall togglehelp()
54032144Sminshall {
54132144Sminshall     struct togglelist *c;
54232144Sminshall 
54332144Sminshall     for (c = Togglelist; c->name; c++) {
54432144Sminshall 	if (c->dohelp) {
54532144Sminshall 	    printf("%s\t%s\n", c->name, c->help);
54632144Sminshall 	}
54732144Sminshall     }
54832144Sminshall     return 0;
54932144Sminshall }
55032144Sminshall 
55132144Sminshall static char **
55232144Sminshall getnexttoggle(name)
55332144Sminshall char *name;
55432144Sminshall {
55532144Sminshall     struct togglelist *c = (struct togglelist *) name;
55632144Sminshall 
55732144Sminshall     return (char **) (c+1);
55832144Sminshall }
55932144Sminshall 
56032144Sminshall static struct togglelist *
56132144Sminshall gettoggle(name)
56232144Sminshall char *name;
56332144Sminshall {
56432144Sminshall     return (struct togglelist *)
56532144Sminshall 			genget(name, (char **) Togglelist, getnexttoggle);
56632144Sminshall }
56732144Sminshall 
56832144Sminshall static
56932144Sminshall toggle(argc, argv)
57032144Sminshall int	argc;
57132144Sminshall char	*argv[];
57232144Sminshall {
57332144Sminshall     int retval = 1;
57432144Sminshall     char *name;
57532144Sminshall     struct togglelist *c;
57632144Sminshall 
57732144Sminshall     if (argc < 2) {
57832144Sminshall 	fprintf(stderr,
57932144Sminshall 	    "Need an argument to 'toggle' command.  'toggle ?' for help.\n");
58032144Sminshall 	return 0;
58132144Sminshall     }
58232144Sminshall     argc--;
58332144Sminshall     argv++;
58432144Sminshall     while (argc--) {
58532144Sminshall 	name = *argv++;
58632144Sminshall 	c = gettoggle(name);
58732144Sminshall 	if (Ambiguous(c)) {
58832144Sminshall 	    fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n",
58932144Sminshall 					name);
59032144Sminshall 	    return 0;
59132144Sminshall 	} else if (c == 0) {
59232144Sminshall 	    fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n",
59332144Sminshall 					name);
59432144Sminshall 	    return 0;
59532144Sminshall 	} else {
59632144Sminshall 	    if (c->variable) {
59732144Sminshall 		*c->variable = !*c->variable;		/* invert it */
59832144Sminshall 		if (c->actionexplanation) {
59932144Sminshall 		    printf("%s %s.\n", *c->variable? "Will" : "Won't",
60032144Sminshall 							c->actionexplanation);
60132144Sminshall 		}
60232144Sminshall 	    }
60332144Sminshall 	    if (c->handler) {
60432144Sminshall 		retval &= (*c->handler)(c);
60532144Sminshall 	    }
60632144Sminshall 	}
60732144Sminshall     }
60832144Sminshall     return retval;
60932144Sminshall }
61032144Sminshall 
61132144Sminshall /*
61232144Sminshall  * The following perform the "set" command.
61332144Sminshall  */
61432144Sminshall 
61532144Sminshall struct setlist {
61632144Sminshall     char *name;				/* name */
61732144Sminshall     char *help;				/* help information */
61832144Sminshall     char *charp;			/* where it is located at */
61932144Sminshall };
62032144Sminshall 
62132144Sminshall static struct setlist Setlist[] = {
62232144Sminshall     { "echo", 	"character to toggle local echoing on/off", &echoc },
62332144Sminshall     { "escape",	"character to escape back to telnet command mode", &escape },
62432144Sminshall     { " ", "" },
62532144Sminshall     { " ", "The following need 'localchars' to be toggled true", 0 },
62632144Sminshall     { "erase",	"character to cause an Erase Character", &termEraseChar },
62732144Sminshall     { "flushoutput", "character to cause an Abort Oubput", &termFlushChar },
62832144Sminshall     { "interrupt", "character to cause an Interrupt Process", &termIntChar },
62932144Sminshall     { "kill",	"character to cause an Erase Line", &termKillChar },
63032144Sminshall     { "quit",	"character to cause a Break", &termQuitChar },
63132144Sminshall     { "eof",	"character to cause an EOF ", &termEofChar },
63232144Sminshall     { 0 }
63332144Sminshall };
63432144Sminshall 
63532144Sminshall static char **
63632144Sminshall getnextset(name)
63732144Sminshall char *name;
63832144Sminshall {
63932144Sminshall     struct setlist *c = (struct setlist *)name;
64032144Sminshall 
64132144Sminshall     return (char **) (c+1);
64232144Sminshall }
64332144Sminshall 
64432144Sminshall static struct setlist *
64532144Sminshall getset(name)
64632144Sminshall char *name;
64732144Sminshall {
64832144Sminshall     return (struct setlist *) genget(name, (char **) Setlist, getnextset);
64932144Sminshall }
65032144Sminshall 
65132144Sminshall static
65232144Sminshall setcmd(argc, argv)
65332144Sminshall int	argc;
65432144Sminshall char	*argv[];
65532144Sminshall {
65632144Sminshall     int value;
65732144Sminshall     struct setlist *ct;
65832144Sminshall 
65932144Sminshall     /* XXX back we go... sigh */
66032144Sminshall     if (argc != 3) {
66132144Sminshall 	if ((argc == 2) &&
66232144Sminshall 		    ((!strcmp(argv[1], "?")) || (!strcmp(argv[1], "help")))) {
66332144Sminshall 	    for (ct = Setlist; ct->name; ct++) {
66432144Sminshall 		printf("%s\t%s\n", ct->name, ct->help);
66532144Sminshall 	    }
66632144Sminshall 	    printf("?\tdisplay help information\n");
66732144Sminshall 	} else {
66832144Sminshall 	    printf("Format is 'set Name Value'\n'set ?' for help.\n");
66932144Sminshall 	}
67032144Sminshall 	return 0;
67132144Sminshall     }
67232144Sminshall 
67332144Sminshall     ct = getset(argv[1]);
67432144Sminshall     if (ct == 0) {
67532144Sminshall 	fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n",
67632144Sminshall 			argv[1]);
67732144Sminshall 	return 0;
67832144Sminshall     } else if (Ambiguous(ct)) {
67932144Sminshall 	fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
68032144Sminshall 			argv[1]);
68132144Sminshall 	return 0;
68232144Sminshall     } else {
68332144Sminshall 	if (strcmp("off", argv[2])) {
68432144Sminshall 	    value = special(argv[2]);
68532144Sminshall 	} else {
68632144Sminshall 	    value = -1;
68732144Sminshall 	}
68832144Sminshall 	*(ct->charp) = value;
68932144Sminshall 	printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
69032144Sminshall     }
69132144Sminshall     return 1;
69232144Sminshall }
69332144Sminshall 
69432144Sminshall /*
69532144Sminshall  * The following are the data structures and routines for the
69632144Sminshall  * 'mode' command.
69732144Sminshall  */
69832144Sminshall 
69932144Sminshall static
70032144Sminshall dolinemode()
70132144Sminshall {
70232144Sminshall     if (hisopts[TELOPT_SGA]) {
70332144Sminshall 	wontoption(TELOPT_SGA, 0);
70432144Sminshall     }
70532144Sminshall     if (hisopts[TELOPT_ECHO]) {
70632144Sminshall 	wontoption(TELOPT_ECHO, 0);
70732144Sminshall     }
70832144Sminshall     return 1;
70932144Sminshall }
71032144Sminshall 
71132144Sminshall static
71232144Sminshall docharmode()
71332144Sminshall {
71432144Sminshall     if (!hisopts[TELOPT_SGA]) {
71532144Sminshall 	willoption(TELOPT_SGA, 0);
71632144Sminshall     }
71732144Sminshall     if (!hisopts[TELOPT_ECHO]) {
71832144Sminshall 	willoption(TELOPT_ECHO, 0);
71932144Sminshall     }
72032144Sminshall     return 1;
72132144Sminshall }
72232144Sminshall 
72332144Sminshall static Command Mode_commands[] = {
72432144Sminshall     { "character",	"character-at-a-time mode",	docharmode, 1, 1 },
72532144Sminshall     { "line",		"line-by-line mode",		dolinemode, 1, 1 },
72632144Sminshall     { 0 },
72732144Sminshall };
72832144Sminshall 
72932144Sminshall static char **
73032144Sminshall getnextmode(name)
73132144Sminshall char *name;
73232144Sminshall {
73332144Sminshall     Command *c = (Command *) name;
73432144Sminshall 
73532144Sminshall     return (char **) (c+1);
73632144Sminshall }
73732144Sminshall 
73832144Sminshall static Command *
73932144Sminshall getmodecmd(name)
74032144Sminshall char *name;
74132144Sminshall {
74232144Sminshall     return (Command *) genget(name, (char **) Mode_commands, getnextmode);
74332144Sminshall }
74432144Sminshall 
74532144Sminshall static
74632144Sminshall modecmd(argc, argv)
74732144Sminshall int	argc;
74832144Sminshall char	*argv[];
74932144Sminshall {
75032144Sminshall     Command *mt;
75132144Sminshall 
75232144Sminshall     if ((argc != 2) || !strcmp(argv[1], "?") || !strcmp(argv[1], "help")) {
75332144Sminshall 	printf("format is:  'mode Mode', where 'Mode' is one of:\n\n");
75432144Sminshall 	for (mt = Mode_commands; mt->name; mt++) {
75532144Sminshall 	    printf("%s\t%s\n", mt->name, mt->help);
75632144Sminshall 	}
75732144Sminshall 	return 0;
75832144Sminshall     }
75932144Sminshall     mt = getmodecmd(argv[1]);
76032144Sminshall     if (mt == 0) {
76132144Sminshall 	fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]);
76232144Sminshall 	return 0;
76332144Sminshall     } else if (Ambiguous(mt)) {
76432144Sminshall 	fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]);
76532144Sminshall 	return 0;
76632144Sminshall     } else {
76732144Sminshall 	(*mt->handler)();
76832144Sminshall     }
76932144Sminshall     return 1;
77032144Sminshall }
77132144Sminshall 
77232144Sminshall /*
77332144Sminshall  * The following data structures and routines implement the
77432144Sminshall  * "display" command.
77532144Sminshall  */
77632144Sminshall 
77732144Sminshall static
77832144Sminshall display(argc, argv)
77932144Sminshall int	argc;
78032144Sminshall char	*argv[];
78132144Sminshall {
78232144Sminshall #define	dotog(tl)	if (tl->variable && tl->actionexplanation) { \
78332144Sminshall 			    if (*tl->variable) { \
78432144Sminshall 				printf("will"); \
78532144Sminshall 			    } else { \
78632144Sminshall 				printf("won't"); \
78732144Sminshall 			    } \
78832144Sminshall 			    printf(" %s.\n", tl->actionexplanation); \
78932144Sminshall 			}
79032144Sminshall 
79132144Sminshall #define	doset(sl)   if (sl->name && *sl->name != ' ') { \
79232144Sminshall 			printf("[%s]\t%s.\n", control(*sl->charp), sl->name); \
79332144Sminshall 		    }
79432144Sminshall 
79532144Sminshall     struct togglelist *tl;
79632144Sminshall     struct setlist *sl;
79732144Sminshall 
79832144Sminshall     if (argc == 1) {
79932144Sminshall 	for (tl = Togglelist; tl->name; tl++) {
80032144Sminshall 	    dotog(tl);
80132144Sminshall 	}
80232144Sminshall 	printf("\n");
80332144Sminshall 	for (sl = Setlist; sl->name; sl++) {
80432144Sminshall 	    doset(sl);
80532144Sminshall 	}
80632144Sminshall     } else {
80732144Sminshall 	int i;
80832144Sminshall 
80932144Sminshall 	for (i = 1; i < argc; i++) {
81032144Sminshall 	    sl = getset(argv[i]);
81132144Sminshall 	    tl = gettoggle(argv[i]);
81232144Sminshall 	    if (Ambiguous(sl) || Ambiguous(tl)) {
81332144Sminshall 		printf("?Ambiguous argument '%s'.\n", argv[i]);
81432144Sminshall 		return 0;
81532144Sminshall 	    } else if (!sl && !tl) {
81632144Sminshall 		printf("?Unknown argument '%s'.\n", argv[i]);
81732144Sminshall 		return 0;
81832144Sminshall 	    } else {
81932144Sminshall 		if (tl) {
82032144Sminshall 		    dotog(tl);
82132144Sminshall 		}
82232144Sminshall 		if (sl) {
82332144Sminshall 		    doset(sl);
82432144Sminshall 		}
82532144Sminshall 	    }
82632144Sminshall 	}
82732144Sminshall     }
82832144Sminshall     return 1;
82932144Sminshall #undef	doset
83032144Sminshall #undef	dotog
83132144Sminshall }
83232144Sminshall 
83332144Sminshall /*
83432144Sminshall  * The following are the data structures, and many of the routines,
83532144Sminshall  * relating to command processing.
83632144Sminshall  */
83732144Sminshall 
83832144Sminshall /*
83932144Sminshall  * Set the escape character.
84032144Sminshall  */
84132144Sminshall static
84232144Sminshall setescape(argc, argv)
84332144Sminshall 	int argc;
84432144Sminshall 	char *argv[];
84532144Sminshall {
84632144Sminshall 	register char *arg;
84732144Sminshall 	char buf[50];
84832144Sminshall 
84932144Sminshall 	printf(
85032144Sminshall 	    "Deprecated usage - please use 'set escape%s%s' in the future.\n",
85132144Sminshall 				(argc > 2)? " ":"", (argc > 2)? argv[1]: "");
85232144Sminshall 	if (argc > 2)
85332144Sminshall 		arg = argv[1];
85432144Sminshall 	else {
85532144Sminshall 		printf("new escape character: ");
85634849Sminshall 		(void) gets(buf);
85732144Sminshall 		arg = buf;
85832144Sminshall 	}
85932144Sminshall 	if (arg[0] != '\0')
86032144Sminshall 		escape = arg[0];
86132144Sminshall 	if (!In3270) {
86232144Sminshall 		printf("Escape character is '%s'.\n", control(escape));
86332144Sminshall 	}
86434849Sminshall 	(void) fflush(stdout);
86532144Sminshall 	return 1;
86632144Sminshall }
86732144Sminshall 
86832144Sminshall /*VARARGS*/
86932144Sminshall static
87032144Sminshall togcrmod()
87132144Sminshall {
87232144Sminshall     crmod = !crmod;
87332144Sminshall     printf("Deprecated usage - please use 'toggle crmod' in the future.\n");
87432144Sminshall     printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't");
87534849Sminshall     (void) fflush(stdout);
87632144Sminshall     return 1;
87732144Sminshall }
87832144Sminshall 
87932144Sminshall /*VARARGS*/
88032144Sminshall suspend()
88132144Sminshall {
882*37219Sminshall     setcommandmode();
88332144Sminshall #if	defined(unix)
884*37219Sminshall     {
885*37219Sminshall 	long oldrows, oldcols, newrows, newcols;
886*37219Sminshall 
887*37219Sminshall 	TerminalWindowSize(&oldrows, &oldcols);
88834849Sminshall 	(void) kill(0, SIGTSTP);
889*37219Sminshall 	TerminalWindowSize(&newrows, &newcols);
890*37219Sminshall 	if ((oldrows != newrows) || (oldcols != newcols)) {
891*37219Sminshall 	    if (connected) {
892*37219Sminshall 		sendnaws();
893*37219Sminshall 	    }
894*37219Sminshall 	}
895*37219Sminshall     }
89632144Sminshall #endif	/* defined(unix) */
897*37219Sminshall     /* reget parameters in case they were changed */
898*37219Sminshall     TerminalSaveState();
899*37219Sminshall     setconnmode();
900*37219Sminshall     return 1;
90132144Sminshall }
90232144Sminshall 
90332144Sminshall /*VARARGS*/
90432144Sminshall static
90532144Sminshall bye(argc, argv)
90632144Sminshall int	argc;		/* Number of arguments */
90732144Sminshall char	*argv[];	/* arguments */
90832144Sminshall {
90932144Sminshall     if (connected) {
91034849Sminshall 	(void) shutdown(net, 2);
91132144Sminshall 	printf("Connection closed.\n");
91234849Sminshall 	(void) NetClose(net);
91332144Sminshall 	connected = 0;
91432144Sminshall 	/* reset options */
91532144Sminshall 	tninit();
91632144Sminshall #if	defined(TN3270)
91732144Sminshall 	SetIn3270();		/* Get out of 3270 mode */
91832144Sminshall #endif	/* defined(TN3270) */
91932144Sminshall     }
92032144Sminshall     if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) {
92132144Sminshall 	longjmp(toplevel, 1);
92232144Sminshall 	/* NOTREACHED */
92332144Sminshall     }
92432144Sminshall     return 1;			/* Keep lint, etc., happy */
92532144Sminshall }
92632144Sminshall 
92732144Sminshall /*VARARGS*/
92832144Sminshall quit()
92932144Sminshall {
93032144Sminshall 	(void) call(bye, "bye", "fromquit", 0);
93132144Sminshall 	Exit(0);
93232144Sminshall 	return 1;			/* just to keep lint happy */
93332144Sminshall }
93432144Sminshall 
93536274Sminshall #if	defined(unix)
93632144Sminshall /*
93736274Sminshall  * Some information about our file descriptors.
93836274Sminshall  */
93936274Sminshall 
94036274Sminshall char *
94136274Sminshall decodeflags(mask)
94236274Sminshall int mask;
94336274Sminshall {
94436274Sminshall     static char buffer[100];
94536274Sminshall #define do(m,s) \
94636274Sminshall 	if (mask&(m)) { \
94736274Sminshall 	    strcat(buffer, (s)); \
94836274Sminshall 	}
94936274Sminshall 
95036274Sminshall     buffer[0] = 0;			/* Terminate it */
95136274Sminshall 
95236274Sminshall #ifdef FREAD
95336274Sminshall     do(FREAD, " FREAD");
95436274Sminshall #endif
95536274Sminshall #ifdef FWRITE
95636274Sminshall     do(FWRITE, " FWRITE");
95736274Sminshall #endif
95836274Sminshall #ifdef F_DUPFP
95936274Sminshall     do(F_DUPFD, " F_DUPFD");
96036274Sminshall #endif
96136274Sminshall #ifdef FNDELAY
96236274Sminshall     do(FNDELAY, " FNDELAY");
96336274Sminshall #endif
96436274Sminshall #ifdef FAPPEND
96536274Sminshall     do(FAPPEND, " FAPPEND");
96636274Sminshall #endif
96736274Sminshall #ifdef FMARK
96836274Sminshall     do(FMARK, " FMARK");
96936274Sminshall #endif
97036274Sminshall #ifdef FDEFER
97136274Sminshall     do(FDEFER, " FDEFER");
97236274Sminshall #endif
97336274Sminshall #ifdef FASYNC
97436274Sminshall     do(FASYNC, " FASYNC");
97536274Sminshall #endif
97636274Sminshall #ifdef FSHLOCK
97736274Sminshall     do(FSHLOCK, " FSHLOCK");
97836274Sminshall #endif
97936274Sminshall #ifdef FEXLOCK
98036274Sminshall     do(FEXLOCK, " FEXLOCK");
98136274Sminshall #endif
98236274Sminshall #ifdef FCREAT
98336274Sminshall     do(FCREAT, " FCREAT");
98436274Sminshall #endif
98536274Sminshall #ifdef FTRUNC
98636274Sminshall     do(FTRUNC, " FTRUNC");
98736274Sminshall #endif
98836274Sminshall #ifdef FEXCL
98936274Sminshall     do(FEXCL, " FEXCL");
99036274Sminshall #endif
99136274Sminshall 
99236274Sminshall     return buffer;
99336274Sminshall }
99436274Sminshall #undef do
99536274Sminshall 
99636274Sminshall static void
99736274Sminshall filestuff(fd)
99836274Sminshall int fd;
99936274Sminshall {
100036274Sminshall     int res;
100136274Sminshall 
100236274Sminshall     setconnmode();
100336274Sminshall     res = fcntl(fd, F_GETOWN, 0);
100436274Sminshall     setcommandmode();
100536274Sminshall 
100636274Sminshall     if (res == -1) {
100736274Sminshall 	perror("fcntl");
100836274Sminshall 	return;
100936274Sminshall     }
101036274Sminshall     printf("\tOwner is %d.\n", res);
101136274Sminshall 
101236274Sminshall     setconnmode();
101336274Sminshall     res = fcntl(fd, F_GETFL, 0);
101436274Sminshall     setcommandmode();
101536274Sminshall 
101636274Sminshall     if (res == -1) {
101736274Sminshall 	perror("fcntl");
101836274Sminshall 	return;
101936274Sminshall     }
102036274Sminshall     printf("\tFlags are 0x%x: %s\n", res, decodeflags(res));
102136274Sminshall }
102236274Sminshall 
102336274Sminshall 
102436274Sminshall #endif	/* defined(unix) */
102536274Sminshall 
102636274Sminshall /*
102732144Sminshall  * Print status about the connection.
102832144Sminshall  */
102934849Sminshall /*ARGSUSED*/
103032144Sminshall static
103132144Sminshall status(argc, argv)
103232144Sminshall int	argc;
103332144Sminshall char	*argv[];
103432144Sminshall {
103532144Sminshall     if (connected) {
103632144Sminshall 	printf("Connected to %s.\n", hostname);
103736242Sminshall 	if ((argc < 2) || strcmp(argv[1], "notmuch")) {
103832144Sminshall 	    printf("Operating in %s.\n",
103932144Sminshall 				modelist[getconnmode()].modedescriptions);
104032144Sminshall 	    if (localchars) {
104132144Sminshall 		printf("Catching signals locally.\n");
104232144Sminshall 	    }
104332144Sminshall 	}
104432144Sminshall     } else {
104532144Sminshall 	printf("No connection.\n");
104632144Sminshall     }
104732144Sminshall #   if !defined(TN3270)
104832144Sminshall     printf("Escape character is '%s'.\n", control(escape));
104934849Sminshall     (void) fflush(stdout);
105032144Sminshall #   else /* !defined(TN3270) */
105132144Sminshall     if ((!In3270) && ((argc < 2) || strcmp(argv[1], "notmuch"))) {
105232144Sminshall 	printf("Escape character is '%s'.\n", control(escape));
105332144Sminshall     }
105432144Sminshall #   if defined(unix)
105536242Sminshall     if ((argc >= 2) && !strcmp(argv[1], "everything")) {
105636242Sminshall 	printf("SIGIO received %d time%s.\n",
105736242Sminshall 				sigiocount, (sigiocount == 1)? "":"s");
105836274Sminshall 	if (In3270) {
105936274Sminshall 	    printf("Process ID %d, process group %d.\n",
106036274Sminshall 					    getpid(), getpgrp(getpid()));
106136274Sminshall 	    printf("Terminal input:\n");
106236274Sminshall 	    filestuff(tin);
106336274Sminshall 	    printf("Terminal output:\n");
106436274Sminshall 	    filestuff(tout);
106536274Sminshall 	    printf("Network socket:\n");
106636274Sminshall 	    filestuff(net);
106736274Sminshall 	}
106836242Sminshall     }
106932144Sminshall     if (In3270 && transcom) {
107032144Sminshall        printf("Transparent mode command is '%s'.\n", transcom);
107132144Sminshall     }
107232144Sminshall #   endif /* defined(unix) */
107334849Sminshall     (void) fflush(stdout);
107432144Sminshall     if (In3270) {
107532144Sminshall 	return 0;
107632144Sminshall     }
107732144Sminshall #   endif /* defined(TN3270) */
107832144Sminshall     return 1;
107932144Sminshall }
108032144Sminshall 
108132144Sminshall 
108232144Sminshall 
108332144Sminshall int
108432144Sminshall tn(argc, argv)
108532144Sminshall 	int argc;
108632144Sminshall 	char *argv[];
108732144Sminshall {
108832144Sminshall     register struct hostent *host = 0;
108932144Sminshall     struct sockaddr_in sin;
109032144Sminshall     struct servent *sp = 0;
109132144Sminshall     static char	hnamebuf[32];
109234849Sminshall     unsigned long inet_addr();
1093*37219Sminshall     extern char *inet_ntoa();
109432144Sminshall 
109532144Sminshall 
109632144Sminshall #if defined(MSDOS)
109732144Sminshall     char *cp;
109832144Sminshall #endif	/* defined(MSDOS) */
109932144Sminshall 
110032144Sminshall     if (connected) {
110132144Sminshall 	printf("?Already connected to %s\n", hostname);
110232144Sminshall 	return 0;
110332144Sminshall     }
110432144Sminshall     if (argc < 2) {
110532144Sminshall 	(void) strcpy(line, "Connect ");
110632144Sminshall 	printf("(to) ");
110734849Sminshall 	(void) gets(&line[strlen(line)]);
110832144Sminshall 	makeargv();
110932144Sminshall 	argc = margc;
111032144Sminshall 	argv = margv;
111132144Sminshall     }
111232144Sminshall     if ((argc < 2) || (argc > 3)) {
111332144Sminshall 	printf("usage: %s host-name [port]\n", argv[0]);
111432144Sminshall 	return 0;
111532144Sminshall     }
111632144Sminshall #if	defined(MSDOS)
111732144Sminshall     for (cp = argv[1]; *cp; cp++) {
111832144Sminshall 	if (isupper(*cp)) {
111932144Sminshall 	    *cp = tolower(*cp);
112032144Sminshall 	}
112132144Sminshall     }
112232144Sminshall #endif	/* defined(MSDOS) */
112332144Sminshall     sin.sin_addr.s_addr = inet_addr(argv[1]);
112436694Sminshall     if (sin.sin_addr.s_addr != (unsigned long) -1) {
112532144Sminshall 	sin.sin_family = AF_INET;
112632144Sminshall 	(void) strcpy(hnamebuf, argv[1]);
112732144Sminshall 	hostname = hnamebuf;
112832144Sminshall     } else {
112932144Sminshall 	host = gethostbyname(argv[1]);
113032144Sminshall 	if (host) {
113132144Sminshall 	    sin.sin_family = host->h_addrtype;
113232144Sminshall #if	defined(h_addr)		/* In 4.3, this is a #define */
113332144Sminshall 	    memcpy((caddr_t)&sin.sin_addr,
113432144Sminshall 				host->h_addr_list[0], host->h_length);
113532144Sminshall #else	/* defined(h_addr) */
113632144Sminshall 	    memcpy((caddr_t)&sin.sin_addr, host->h_addr, host->h_length);
113732144Sminshall #endif	/* defined(h_addr) */
113832144Sminshall 	    hostname = host->h_name;
113932144Sminshall 	} else {
114035789Sbostic 	    herror(argv[1]);
114132144Sminshall 	    return 0;
114232144Sminshall 	}
114332144Sminshall     }
114432144Sminshall     if (argc == 3) {
114532144Sminshall 	sin.sin_port = atoi(argv[2]);
114632144Sminshall 	if (sin.sin_port == 0) {
114732144Sminshall 	    sp = getservbyname(argv[2], "tcp");
114832144Sminshall 	    if (sp)
114932144Sminshall 		sin.sin_port = sp->s_port;
115032144Sminshall 	    else {
115132144Sminshall 		printf("%s: bad port number\n", argv[2]);
115232144Sminshall 		return 0;
115332144Sminshall 	    }
115432144Sminshall 	} else {
115534849Sminshall #if	!defined(htons)
115634849Sminshall 	    u_short htons();
115734849Sminshall #endif	/* !defined(htons) */
115832144Sminshall 	    sin.sin_port = htons(sin.sin_port);
115932144Sminshall 	}
116032144Sminshall 	telnetport = 0;
116132144Sminshall     } else {
116232144Sminshall 	if (sp == 0) {
116332144Sminshall 	    sp = getservbyname("telnet", "tcp");
116432144Sminshall 	    if (sp == 0) {
116534849Sminshall 		fprintf(stderr, "telnet: tcp/telnet: unknown service\n");
116632144Sminshall 		return 0;
116732144Sminshall 	    }
116832144Sminshall 	    sin.sin_port = sp->s_port;
116932144Sminshall 	}
117032144Sminshall 	telnetport = 1;
117132144Sminshall     }
1172*37219Sminshall     printf("Trying %s...\n", inet_ntoa(sin.sin_addr));
117332144Sminshall     do {
117432144Sminshall 	net = socket(AF_INET, SOCK_STREAM, 0);
117532144Sminshall 	if (net < 0) {
117632144Sminshall 	    perror("telnet: socket");
117732144Sminshall 	    return 0;
117832144Sminshall 	}
117932144Sminshall 	if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) {
118032144Sminshall 		perror("setsockopt (SO_DEBUG)");
118132144Sminshall 	}
118232144Sminshall 
118332144Sminshall 	if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
118432144Sminshall #if	defined(h_addr)		/* In 4.3, this is a #define */
118532144Sminshall 	    if (host && host->h_addr_list[1]) {
118632144Sminshall 		int oerrno = errno;
118732144Sminshall 
118832144Sminshall 		fprintf(stderr, "telnet: connect to address %s: ",
118932144Sminshall 						inet_ntoa(sin.sin_addr));
119032144Sminshall 		errno = oerrno;
119132144Sminshall 		perror((char *)0);
119232144Sminshall 		host->h_addr_list++;
119332144Sminshall 		memcpy((caddr_t)&sin.sin_addr,
119432144Sminshall 			host->h_addr_list[0], host->h_length);
119532144Sminshall 		(void) NetClose(net);
119632144Sminshall 		continue;
119732144Sminshall 	    }
119832144Sminshall #endif	/* defined(h_addr) */
119932144Sminshall 	    perror("telnet: Unable to connect to remote host");
120032144Sminshall 	    return 0;
1201*37219Sminshall 	}
120232144Sminshall 	connected++;
120332144Sminshall     } while (connected == 0);
120434849Sminshall     (void) call(status, "status", "notmuch", 0);
120532144Sminshall     if (setjmp(peerdied) == 0)
120632144Sminshall 	telnet();
120734849Sminshall     (void) NetClose(net);
120832381Sminshall     ExitString("Connection closed by foreign host.\n",1);
120932144Sminshall     /*NOTREACHED*/
121032144Sminshall }
121132144Sminshall 
121232144Sminshall 
121332144Sminshall #define HELPINDENT (sizeof ("connect"))
121432144Sminshall 
121532144Sminshall static char
121632144Sminshall 	openhelp[] =	"connect to a site",
121732144Sminshall 	closehelp[] =	"close current connection",
121832144Sminshall 	quithelp[] =	"exit telnet",
121932144Sminshall 	statushelp[] =	"print status information",
122032144Sminshall 	helphelp[] =	"print help information",
122132144Sminshall 	sendhelp[] =	"transmit special characters ('send ?' for more)",
122232144Sminshall 	sethelp[] = 	"set operating parameters ('set ?' for more)",
122332144Sminshall 	togglestring[] ="toggle operating parameters ('toggle ?' for more)",
122432144Sminshall 	displayhelp[] =	"display operating parameters",
122532144Sminshall #if	defined(TN3270) && defined(unix)
122632144Sminshall 	transcomhelp[] = "specify Unix command for transparent mode pipe",
122732144Sminshall #endif	/* defined(TN3270) && defined(unix) */
122832144Sminshall #if	defined(unix)
122932144Sminshall 	zhelp[] =	"suspend telnet",
123032144Sminshall #endif	/* defined(unix */
123132144Sminshall #if	defined(TN3270)
123232144Sminshall 	shellhelp[] =	"invoke a subshell",
123332144Sminshall #endif	/* defined(TN3270) */
123432144Sminshall 	modehelp[] = "try to enter line-by-line or character-at-a-time mode";
123532144Sminshall 
123632144Sminshall extern int	help(), shell();
123732144Sminshall 
123832144Sminshall static Command cmdtab[] = {
123932144Sminshall 	{ "close",	closehelp,	bye,		1, 1 },
124032144Sminshall 	{ "display",	displayhelp,	display,	1, 0 },
124132144Sminshall 	{ "mode",	modehelp,	modecmd,	1, 1 },
124232144Sminshall 	{ "open",	openhelp,	tn,		1, 0 },
124332144Sminshall 	{ "quit",	quithelp,	quit,		1, 0 },
124432144Sminshall 	{ "send",	sendhelp,	sendcmd,	1, 1 },
124532144Sminshall 	{ "set",	sethelp,	setcmd,		1, 0 },
124632144Sminshall 	{ "status",	statushelp,	status,		1, 0 },
124732144Sminshall 	{ "toggle",	togglestring,	toggle,		1, 0 },
124832144Sminshall #if	defined(TN3270) && defined(unix)
124932144Sminshall 	{ "transcom",	transcomhelp,	settranscom,	1, 0 },
125032144Sminshall #endif	/* defined(TN3270) && defined(unix) */
125132144Sminshall #if	defined(unix)
125232144Sminshall 	{ "z",		zhelp,		suspend,	1, 0 },
125332144Sminshall #endif	/* defined(unix) */
125432144Sminshall #if	defined(TN3270)
125532144Sminshall 	{ "!",		shellhelp,	shell,		1, 1 },
125632144Sminshall #endif	/* defined(TN3270) */
125732144Sminshall 	{ "?",		helphelp,	help,		1, 0 },
125832144Sminshall 	0
125932144Sminshall };
126032144Sminshall 
126132144Sminshall static char	crmodhelp[] =	"deprecated command -- use 'toggle crmod' instead";
126232144Sminshall static char	escapehelp[] =	"deprecated command -- use 'set escape' instead";
126332144Sminshall 
126432144Sminshall static Command cmdtab2[] = {
126532144Sminshall 	{ "help",	helphelp,	help,		0, 0 },
126632144Sminshall 	{ "escape",	escapehelp,	setescape,	1, 0 },
126732144Sminshall 	{ "crmod",	crmodhelp,	togcrmod,	1, 0 },
126832144Sminshall 	0
126932144Sminshall };
127032144Sminshall 
127135298Sminshall 
127232144Sminshall /*
127332144Sminshall  * Call routine with argc, argv set from args (terminated by 0).
127432144Sminshall  */
127535298Sminshall 
127635417Sminshall /*VARARGS1*/
127732144Sminshall static
127835298Sminshall call(va_alist)
127935298Sminshall va_dcl
128032144Sminshall {
128135298Sminshall     va_list ap;
128235298Sminshall     typedef int (*intrtn_t)();
128335298Sminshall     intrtn_t routine;
128435298Sminshall     char *args[100];
128535298Sminshall     int argno = 0;
128635298Sminshall 
128735298Sminshall     va_start(ap);
128835298Sminshall     routine = (va_arg(ap, intrtn_t));
128935495Sminshall     while ((args[argno++] = va_arg(ap, char *)) != 0) {
129035298Sminshall 	;
129135495Sminshall     }
129235298Sminshall     va_end(ap);
129335495Sminshall     return (*routine)(argno-1, args);
129432144Sminshall }
129532144Sminshall 
129635298Sminshall 
129732144Sminshall static char **
129832144Sminshall getnextcmd(name)
129932144Sminshall char *name;
130032144Sminshall {
130132144Sminshall     Command *c = (Command *) name;
130232144Sminshall 
130332144Sminshall     return (char **) (c+1);
130432144Sminshall }
130532144Sminshall 
130632144Sminshall static Command *
130732144Sminshall getcmd(name)
130832144Sminshall char *name;
130932144Sminshall {
131032144Sminshall     Command *cm;
131132144Sminshall 
131232144Sminshall     if ((cm = (Command *) genget(name, (char **) cmdtab, getnextcmd)) != 0) {
131332144Sminshall 	return cm;
131432144Sminshall     } else {
131532144Sminshall 	return (Command *) genget(name, (char **) cmdtab2, getnextcmd);
131632144Sminshall     }
131732144Sminshall }
131832144Sminshall 
131932144Sminshall void
132032144Sminshall command(top)
132132144Sminshall 	int top;
132232144Sminshall {
132332144Sminshall     register Command *c;
132432144Sminshall 
132532144Sminshall     setcommandmode();
132632144Sminshall     if (!top) {
132732144Sminshall 	putchar('\n');
1328*37219Sminshall #if	defined(unix)
132932144Sminshall     } else {
133032144Sminshall 	signal(SIGINT, SIG_DFL);
133132144Sminshall 	signal(SIGQUIT, SIG_DFL);
133232144Sminshall #endif	/* defined(unix) */
133332144Sminshall     }
133432144Sminshall     for (;;) {
133532144Sminshall 	printf("%s> ", prompt);
133632144Sminshall 	if (gets(line) == NULL) {
133732144Sminshall 	    if (feof(stdin) || ferror(stdin))
133832144Sminshall 		quit();
133932144Sminshall 	    break;
134032144Sminshall 	}
134132144Sminshall 	if (line[0] == 0)
134232144Sminshall 	    break;
134332144Sminshall 	makeargv();
1344*37219Sminshall 	if (margv[0] == 0) {
1345*37219Sminshall 	    break;
1346*37219Sminshall 	}
134732144Sminshall 	c = getcmd(margv[0]);
134832144Sminshall 	if (Ambiguous(c)) {
134932144Sminshall 	    printf("?Ambiguous command\n");
135032144Sminshall 	    continue;
135132144Sminshall 	}
135232144Sminshall 	if (c == 0) {
135332144Sminshall 	    printf("?Invalid command\n");
135432144Sminshall 	    continue;
135532144Sminshall 	}
135632144Sminshall 	if (c->needconnect && !connected) {
135732144Sminshall 	    printf("?Need to be connected first.\n");
135832144Sminshall 	    continue;
135932144Sminshall 	}
136032144Sminshall 	if ((*c->handler)(margc, margv)) {
136132144Sminshall 	    break;
136232144Sminshall 	}
136332144Sminshall     }
136432144Sminshall     if (!top) {
136532144Sminshall 	if (!connected) {
136632144Sminshall 	    longjmp(toplevel, 1);
136732144Sminshall 	    /*NOTREACHED*/
136832144Sminshall 	}
136932144Sminshall #if	defined(TN3270)
137032144Sminshall 	if (shell_active == 0) {
137132144Sminshall 	    setconnmode();
137232144Sminshall 	}
137332144Sminshall #else	/* defined(TN3270) */
137432144Sminshall 	setconnmode();
137532144Sminshall #endif	/* defined(TN3270) */
137632144Sminshall     }
137732144Sminshall }
137832144Sminshall 
137932144Sminshall /*
138032144Sminshall  * Help command.
138132144Sminshall  */
138232144Sminshall static
138332144Sminshall help(argc, argv)
138432144Sminshall 	int argc;
138532144Sminshall 	char *argv[];
138632144Sminshall {
138732144Sminshall 	register Command *c;
138832144Sminshall 
138932144Sminshall 	if (argc == 1) {
139032144Sminshall 		printf("Commands may be abbreviated.  Commands are:\n\n");
139132144Sminshall 		for (c = cmdtab; c->name; c++)
139232144Sminshall 			if (c->dohelp) {
139332144Sminshall 				printf("%-*s\t%s\n", HELPINDENT, c->name,
139432144Sminshall 								    c->help);
139532144Sminshall 			}
139632144Sminshall 		return 0;
139732144Sminshall 	}
139832144Sminshall 	while (--argc > 0) {
139932144Sminshall 		register char *arg;
140032144Sminshall 		arg = *++argv;
140132144Sminshall 		c = getcmd(arg);
140232144Sminshall 		if (Ambiguous(c))
140332144Sminshall 			printf("?Ambiguous help command %s\n", arg);
140432144Sminshall 		else if (c == (Command *)0)
140532144Sminshall 			printf("?Invalid help command %s\n", arg);
140632144Sminshall 		else
140732144Sminshall 			printf("%s\n", c->help);
140832144Sminshall 	}
140932144Sminshall 	return 0;
141032144Sminshall }
1411