xref: /csrg-svn/usr.bin/telnet/commands.c (revision 35417)
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*35417Sminshall static char sccsid[] = "@(#)commands.c	1.9 (Berkeley) 08/28/88";
2033685Sbostic #endif /* not lint */
2133685Sbostic 
2232144Sminshall #include <sys/types.h>
2332144Sminshall #include <sys/socket.h>
2432144Sminshall #include <netinet/in.h>
2532144Sminshall 
2632144Sminshall #include <signal.h>
2732144Sminshall #include <netdb.h>
2832144Sminshall #include <ctype.h>
2935298Sminshall #include <varargs.h>
3032144Sminshall 
3132144Sminshall #include <arpa/telnet.h>
3232144Sminshall 
3334305Sminshall #include "general.h"
3434305Sminshall 
3532381Sminshall #include "ring.h"
3632381Sminshall 
3732144Sminshall #include "externs.h"
3832144Sminshall #include "defines.h"
3932144Sminshall #include "types.h"
4032144Sminshall 
4132144Sminshall char	*hostname;
4232144Sminshall 
4332144Sminshall #define Ambiguous(s)	((char *)s == ambiguous)
4432144Sminshall static char *ambiguous;		/* special return value for command routines */
4532144Sminshall 
4632144Sminshall typedef struct {
4732144Sminshall 	char	*name;		/* command name */
4832144Sminshall 	char	*help;		/* help string */
4932144Sminshall 	int	(*handler)();	/* routine which executes command */
5032144Sminshall 	int	dohelp;		/* Should we give general help information? */
5132144Sminshall 	int	needconnect;	/* Do we need to be connected to execute? */
5232144Sminshall } Command;
5332144Sminshall 
5432144Sminshall static char line[200];
5532144Sminshall static int margc;
5632144Sminshall static char *margv[20];
5732144Sminshall 
5832144Sminshall /*
5932144Sminshall  * Various utility routines.
6032144Sminshall  */
6132144Sminshall 
6232144Sminshall static void
6332144Sminshall makeargv()
6432144Sminshall {
6532144Sminshall     register char *cp;
6632144Sminshall     register char **argp = margv;
6732144Sminshall 
6832144Sminshall     margc = 0;
6932144Sminshall     cp = line;
7032144Sminshall     if (*cp == '!') {		/* Special case shell escape */
7132144Sminshall 	*argp++ = "!";		/* No room in string to get this */
7232144Sminshall 	margc++;
7332144Sminshall 	cp++;
7432144Sminshall     }
7532144Sminshall     while (*cp) {
7632144Sminshall 	while (isspace(*cp))
7732144Sminshall 	    cp++;
7832144Sminshall 	if (*cp == '\0')
7932144Sminshall 	    break;
8032144Sminshall 	*argp++ = cp;
8132144Sminshall 	margc += 1;
8232144Sminshall 	while (*cp != '\0' && !isspace(*cp))
8332144Sminshall 	    cp++;
8432144Sminshall 	if (*cp == '\0')
8532144Sminshall 	    break;
8632144Sminshall 	*cp++ = '\0';
8732144Sminshall     }
8832144Sminshall     *argp++ = 0;
8932144Sminshall }
9032144Sminshall 
9132144Sminshall 
9232144Sminshall static char **
9332144Sminshall genget(name, table, next)
9432144Sminshall char	*name;		/* name to match */
9532144Sminshall char	**table;		/* name entry in table */
9632144Sminshall char	**(*next)();	/* routine to return next entry in table */
9732144Sminshall {
9832144Sminshall 	register char *p, *q;
9932144Sminshall 	register char **c, **found;
10032144Sminshall 	register int nmatches, longest;
10132144Sminshall 
10232144Sminshall 	if (name == 0) {
10332144Sminshall 	    return 0;
10432144Sminshall 	}
10532144Sminshall 	longest = 0;
10632144Sminshall 	nmatches = 0;
10732144Sminshall 	found = 0;
10832144Sminshall 	for (c = table; (p = *c) != 0; c = (*next)(c)) {
10932144Sminshall 		for (q = name;
11032144Sminshall 		    (*q == *p) || (isupper(*q) && tolower(*q) == *p); p++, q++)
11132144Sminshall 			if (*q == 0)		/* exact match? */
11232144Sminshall 				return (c);
11332144Sminshall 		if (!*q) {			/* the name was a prefix */
11432144Sminshall 			if (q - name > longest) {
11532144Sminshall 				longest = q - name;
11632144Sminshall 				nmatches = 1;
11732144Sminshall 				found = c;
11832144Sminshall 			} else if (q - name == longest)
11932144Sminshall 				nmatches++;
12032144Sminshall 		}
12132144Sminshall 	}
12232144Sminshall 	if (nmatches > 1)
12332144Sminshall 		return (char **)ambiguous;
12432144Sminshall 	return (found);
12532144Sminshall }
12632144Sminshall 
12732144Sminshall /*
12832144Sminshall  * Make a character string into a number.
12932144Sminshall  *
13032144Sminshall  * Todo:  1.  Could take random integers (12, 0x12, 012, 0b1).
13132144Sminshall  */
13232144Sminshall 
13332144Sminshall static
13432144Sminshall special(s)
13532144Sminshall register char *s;
13632144Sminshall {
13732144Sminshall 	register char c;
13832144Sminshall 	char b;
13932144Sminshall 
14032144Sminshall 	switch (*s) {
14132144Sminshall 	case '^':
14232144Sminshall 		b = *++s;
14332144Sminshall 		if (b == '?') {
14432144Sminshall 		    c = b | 0x40;		/* DEL */
14532144Sminshall 		} else {
14632144Sminshall 		    c = b & 0x1f;
14732144Sminshall 		}
14832144Sminshall 		break;
14932144Sminshall 	default:
15032144Sminshall 		c = *s;
15132144Sminshall 		break;
15232144Sminshall 	}
15332144Sminshall 	return c;
15432144Sminshall }
15532144Sminshall 
15632144Sminshall /*
15732144Sminshall  * Construct a control character sequence
15832144Sminshall  * for a special character.
15932144Sminshall  */
16032144Sminshall static char *
16132144Sminshall control(c)
16232144Sminshall 	register int c;
16332144Sminshall {
16432144Sminshall 	static char buf[3];
16532144Sminshall 
16632144Sminshall 	if (c == 0x7f)
16732144Sminshall 		return ("^?");
16832144Sminshall 	if (c == '\377') {
16932144Sminshall 		return "off";
17032144Sminshall 	}
17132144Sminshall 	if (c >= 0x20) {
17232144Sminshall 		buf[0] = c;
17332144Sminshall 		buf[1] = 0;
17432144Sminshall 	} else {
17532144Sminshall 		buf[0] = '^';
17632144Sminshall 		buf[1] = '@'+c;
17732144Sminshall 		buf[2] = 0;
17832144Sminshall 	}
17932144Sminshall 	return (buf);
18032144Sminshall }
18132144Sminshall 
18232144Sminshall 
18332144Sminshall 
18432144Sminshall /*
18532144Sminshall  *	The following are data structures and routines for
18632144Sminshall  *	the "send" command.
18732144Sminshall  *
18832144Sminshall  */
18932144Sminshall 
19032144Sminshall struct sendlist {
19132144Sminshall     char	*name;		/* How user refers to it (case independent) */
19232144Sminshall     int		what;		/* Character to be sent (<0 ==> special) */
19332144Sminshall     char	*help;		/* Help information (0 ==> no help) */
19432144Sminshall #if	defined(NOT43)
19532144Sminshall     int		(*routine)();	/* Routine to perform (for special ops) */
19632144Sminshall #else	/* defined(NOT43) */
19732144Sminshall     void	(*routine)();	/* Routine to perform (for special ops) */
19832144Sminshall #endif	/* defined(NOT43) */
19932144Sminshall };
20032144Sminshall 
20132144Sminshall #define	SENDQUESTION	-1
20232144Sminshall #define	SENDESCAPE	-3
20332144Sminshall 
20432144Sminshall static struct sendlist Sendlist[] = {
20532144Sminshall     { "ao", AO, "Send Telnet Abort output" },
20632144Sminshall     { "ayt", AYT, "Send Telnet 'Are You There'" },
20732144Sminshall     { "brk", BREAK, "Send Telnet Break" },
20832144Sminshall     { "ec", EC, "Send Telnet Erase Character" },
20932144Sminshall     { "el", EL, "Send Telnet Erase Line" },
21032144Sminshall     { "escape", SENDESCAPE, "Send current escape character" },
21132144Sminshall     { "ga", GA, "Send Telnet 'Go Ahead' sequence" },
21232144Sminshall     { "ip", IP, "Send Telnet Interrupt Process" },
21332144Sminshall     { "nop", NOP, "Send Telnet 'No operation'" },
21432144Sminshall     { "synch", SYNCH, "Perform Telnet 'Synch operation'", dosynch },
21532144Sminshall     { "?", SENDQUESTION, "Display send options" },
21632144Sminshall     { 0 }
21732144Sminshall };
21832144Sminshall 
21932144Sminshall static struct sendlist Sendlist2[] = {		/* some synonyms */
22032144Sminshall 	{ "break", BREAK, 0 },
22132144Sminshall 
22232144Sminshall 	{ "intp", IP, 0 },
22332144Sminshall 	{ "interrupt", IP, 0 },
22432144Sminshall 	{ "intr", IP, 0 },
22532144Sminshall 
22632144Sminshall 	{ "help", SENDQUESTION, 0 },
22732144Sminshall 
22832144Sminshall 	{ 0 }
22932144Sminshall };
23032144Sminshall 
23132144Sminshall static char **
23232144Sminshall getnextsend(name)
23332144Sminshall char *name;
23432144Sminshall {
23532144Sminshall     struct sendlist *c = (struct sendlist *) name;
23632144Sminshall 
23732144Sminshall     return (char **) (c+1);
23832144Sminshall }
23932144Sminshall 
24032144Sminshall static struct sendlist *
24132144Sminshall getsend(name)
24232144Sminshall char *name;
24332144Sminshall {
24432144Sminshall     struct sendlist *sl;
24532144Sminshall 
24632144Sminshall     if ((sl = (struct sendlist *)
24732144Sminshall 			genget(name, (char **) Sendlist, getnextsend)) != 0) {
24832144Sminshall 	return sl;
24932144Sminshall     } else {
25032144Sminshall 	return (struct sendlist *)
25132144Sminshall 				genget(name, (char **) Sendlist2, getnextsend);
25232144Sminshall     }
25332144Sminshall }
25432144Sminshall 
25532144Sminshall static
25632144Sminshall sendcmd(argc, argv)
25732144Sminshall int	argc;
25832144Sminshall char	**argv;
25932144Sminshall {
26032144Sminshall     int what;		/* what we are sending this time */
26132144Sminshall     int count;		/* how many bytes we are going to need to send */
26232144Sminshall     int i;
26332144Sminshall     int question = 0;	/* was at least one argument a question */
26432144Sminshall     struct sendlist *s;	/* pointer to current command */
26532144Sminshall 
26632144Sminshall     if (argc < 2) {
26732144Sminshall 	printf("need at least one argument for 'send' command\n");
26832144Sminshall 	printf("'send ?' for help\n");
26932144Sminshall 	return 0;
27032144Sminshall     }
27132144Sminshall     /*
27232144Sminshall      * First, validate all the send arguments.
27332144Sminshall      * In addition, we see how much space we are going to need, and
27432144Sminshall      * whether or not we will be doing a "SYNCH" operation (which
27532144Sminshall      * flushes the network queue).
27632144Sminshall      */
27732144Sminshall     count = 0;
27832144Sminshall     for (i = 1; i < argc; i++) {
27932144Sminshall 	s = getsend(argv[i]);
28032144Sminshall 	if (s == 0) {
28132144Sminshall 	    printf("Unknown send argument '%s'\n'send ?' for help.\n",
28232144Sminshall 			argv[i]);
28332144Sminshall 	    return 0;
28432144Sminshall 	} else if (Ambiguous(s)) {
28532144Sminshall 	    printf("Ambiguous send argument '%s'\n'send ?' for help.\n",
28632144Sminshall 			argv[i]);
28732144Sminshall 	    return 0;
28832144Sminshall 	}
28932144Sminshall 	switch (s->what) {
29032144Sminshall 	case SENDQUESTION:
29132144Sminshall 	    break;
29232144Sminshall 	case SENDESCAPE:
29332144Sminshall 	    count += 1;
29432144Sminshall 	    break;
29532144Sminshall 	case SYNCH:
29632144Sminshall 	    count += 2;
29732144Sminshall 	    break;
29832144Sminshall 	default:
29932144Sminshall 	    count += 2;
30032144Sminshall 	    break;
30132144Sminshall 	}
30232144Sminshall     }
30332144Sminshall     /* Now, do we have enough room? */
30432144Sminshall     if (NETROOM() < count) {
30532144Sminshall 	printf("There is not enough room in the buffer TO the network\n");
30632144Sminshall 	printf("to process your request.  Nothing will be done.\n");
30732144Sminshall 	printf("('send synch' will throw away most data in the network\n");
30832144Sminshall 	printf("buffer, if this might help.)\n");
30932144Sminshall 	return 0;
31032144Sminshall     }
31132144Sminshall     /* OK, they are all OK, now go through again and actually send */
31232144Sminshall     for (i = 1; i < argc; i++) {
31332144Sminshall 	if ((s = getsend(argv[i])) == 0) {
31432144Sminshall 	    fprintf(stderr, "Telnet 'send' error - argument disappeared!\n");
31532144Sminshall 	    quit();
31632144Sminshall 	    /*NOTREACHED*/
31732144Sminshall 	}
31832144Sminshall 	if (s->routine) {
31932144Sminshall 	    (*s->routine)(s);
32032144Sminshall 	} else {
32132144Sminshall 	    switch (what = s->what) {
32232144Sminshall 	    case SYNCH:
32332144Sminshall 		dosynch();
32432144Sminshall 		break;
32532144Sminshall 	    case SENDQUESTION:
32632144Sminshall 		for (s = Sendlist; s->name; s++) {
32732144Sminshall 		    if (s->help) {
32832144Sminshall 			printf(s->name);
32932144Sminshall 			if (s->help) {
33032144Sminshall 			    printf("\t%s", s->help);
33132144Sminshall 			}
33232144Sminshall 			printf("\n");
33332144Sminshall 		    }
33432144Sminshall 		}
33532144Sminshall 		question = 1;
33632144Sminshall 		break;
33732144Sminshall 	    case SENDESCAPE:
33832144Sminshall 		NETADD(escape);
33932144Sminshall 		break;
34032144Sminshall 	    default:
34132144Sminshall 		NET2ADD(IAC, what);
34232144Sminshall 		break;
34332144Sminshall 	    }
34432144Sminshall 	}
34532144Sminshall     }
34632144Sminshall     return !question;
34732144Sminshall }
34832144Sminshall 
34932144Sminshall /*
35032144Sminshall  * The following are the routines and data structures referred
35132144Sminshall  * to by the arguments to the "toggle" command.
35232144Sminshall  */
35332144Sminshall 
35432144Sminshall static
35532144Sminshall lclchars()
35632144Sminshall {
35732144Sminshall     donelclchars = 1;
35832144Sminshall     return 1;
35932144Sminshall }
36032144Sminshall 
36132144Sminshall static
36232144Sminshall togdebug()
36332144Sminshall {
36432144Sminshall #ifndef	NOT43
36532144Sminshall     if (net > 0 &&
36632144Sminshall 	(SetSockOpt(net, SOL_SOCKET, SO_DEBUG, debug)) < 0) {
36732144Sminshall 	    perror("setsockopt (SO_DEBUG)");
36832144Sminshall     }
36932144Sminshall #else	/* NOT43 */
37032144Sminshall     if (debug) {
37132144Sminshall 	if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
37232144Sminshall 	    perror("setsockopt (SO_DEBUG)");
37332144Sminshall     } else
37432144Sminshall 	printf("Cannot turn off socket debugging\n");
37532144Sminshall #endif	/* NOT43 */
37632144Sminshall     return 1;
37732144Sminshall }
37832144Sminshall 
37932144Sminshall 
38032144Sminshall static int
38132144Sminshall togcrlf()
38232144Sminshall {
38332144Sminshall     if (crlf) {
38432144Sminshall 	printf("Will send carriage returns as telnet <CR><LF>.\n");
38532144Sminshall     } else {
38632144Sminshall 	printf("Will send carriage returns as telnet <CR><NUL>.\n");
38732144Sminshall     }
38832144Sminshall     return 1;
38932144Sminshall }
39032144Sminshall 
39132144Sminshall 
39232144Sminshall static int
39332144Sminshall togbinary()
39432144Sminshall {
39532144Sminshall     donebinarytoggle = 1;
39632144Sminshall 
39732144Sminshall     if (myopts[TELOPT_BINARY] == 0) {	/* Go into binary mode */
39832144Sminshall 	NET2ADD(IAC, DO);
39932144Sminshall 	NETADD(TELOPT_BINARY);
40032144Sminshall 	printoption("<SENT", doopt, TELOPT_BINARY, 0);
40132144Sminshall 	NET2ADD(IAC, WILL);
40232144Sminshall 	NETADD(TELOPT_BINARY);
40332144Sminshall 	printoption("<SENT", doopt, TELOPT_BINARY, 0);
40432144Sminshall 	hisopts[TELOPT_BINARY] = myopts[TELOPT_BINARY] = 1;
40532144Sminshall 	printf("Negotiating binary mode with remote host.\n");
40632144Sminshall     } else {				/* Turn off binary mode */
40732144Sminshall 	NET2ADD(IAC, DONT);
40832144Sminshall 	NETADD(TELOPT_BINARY);
40932144Sminshall 	printoption("<SENT", dont, TELOPT_BINARY, 0);
41032144Sminshall 	NET2ADD(IAC, DONT);
41132144Sminshall 	NETADD(TELOPT_BINARY);
41232144Sminshall 	printoption("<SENT", dont, TELOPT_BINARY, 0);
41332144Sminshall 	hisopts[TELOPT_BINARY] = myopts[TELOPT_BINARY] = 0;
41432144Sminshall 	printf("Negotiating network ascii mode with remote host.\n");
41532144Sminshall     }
41632144Sminshall     return 1;
41732144Sminshall }
41832144Sminshall 
41932144Sminshall 
42032144Sminshall 
42132144Sminshall extern int togglehelp();
42232144Sminshall 
42332144Sminshall struct togglelist {
42432144Sminshall     char	*name;		/* name of toggle */
42532144Sminshall     char	*help;		/* help message */
42632144Sminshall     int		(*handler)();	/* routine to do actual setting */
42732144Sminshall     int		dohelp;		/* should we display help information */
42832144Sminshall     int		*variable;
42932144Sminshall     char	*actionexplanation;
43032144Sminshall };
43132144Sminshall 
43232144Sminshall static struct togglelist Togglelist[] = {
43332144Sminshall     { "autoflush",
43432144Sminshall 	"toggle flushing of output when sending interrupt characters",
43532144Sminshall 	    0,
43632144Sminshall 		1,
43732144Sminshall 		    &autoflush,
43832144Sminshall 			"flush output when sending interrupt characters" },
43932144Sminshall     { "autosynch",
44032144Sminshall 	"toggle automatic sending of interrupt characters in urgent mode",
44132144Sminshall 	    0,
44232144Sminshall 		1,
44332144Sminshall 		    &autosynch,
44432144Sminshall 			"send interrupt characters in urgent mode" },
44532144Sminshall     { "binary",
44632144Sminshall 	"toggle sending and receiving of binary data",
44732144Sminshall 	    togbinary,
44832144Sminshall 		1,
44932144Sminshall 		    0,
45032144Sminshall 			0 },
45132144Sminshall     { "crlf",
45232144Sminshall 	"toggle sending carriage returns as telnet <CR><LF>",
45332144Sminshall 	    togcrlf,
45432144Sminshall 		1,
45532144Sminshall 		    &crlf,
45632144Sminshall 			0 },
45732144Sminshall     { "crmod",
45832144Sminshall 	"toggle mapping of received carriage returns",
45932144Sminshall 	    0,
46032144Sminshall 		1,
46132144Sminshall 		    &crmod,
46232144Sminshall 			"map carriage return on output" },
46332144Sminshall     { "localchars",
46432144Sminshall 	"toggle local recognition of certain control characters",
46532144Sminshall 	    lclchars,
46632144Sminshall 		1,
46732144Sminshall 		    &localchars,
46832144Sminshall 			"recognize certain control characters" },
46932144Sminshall     { " ", "", 0, 1 },		/* empty line */
47032144Sminshall     { "debug",
47132144Sminshall 	"(debugging) toggle debugging",
47232144Sminshall 	    togdebug,
47332144Sminshall 		1,
47432144Sminshall 		    &debug,
47532144Sminshall 			"turn on socket level debugging" },
47632144Sminshall     { "netdata",
47732144Sminshall 	"(debugging) toggle printing of hexadecimal network data",
47832144Sminshall 	    0,
47932144Sminshall 		1,
48032144Sminshall 		    &netdata,
48132144Sminshall 			"print hexadecimal representation of network traffic" },
48232144Sminshall     { "options",
48332144Sminshall 	"(debugging) toggle viewing of options processing",
48432144Sminshall 	    0,
48532144Sminshall 		1,
48632144Sminshall 		    &showoptions,
48732144Sminshall 			"show option processing" },
48832144Sminshall     { " ", "", 0, 1 },		/* empty line */
48932144Sminshall     { "?",
49032144Sminshall 	"display help information",
49132144Sminshall 	    togglehelp,
49232144Sminshall 		1 },
49332144Sminshall     { "help",
49432144Sminshall 	"display help information",
49532144Sminshall 	    togglehelp,
49632144Sminshall 		0 },
49732144Sminshall     { 0 }
49832144Sminshall };
49932144Sminshall 
50032144Sminshall static
50132144Sminshall togglehelp()
50232144Sminshall {
50332144Sminshall     struct togglelist *c;
50432144Sminshall 
50532144Sminshall     for (c = Togglelist; c->name; c++) {
50632144Sminshall 	if (c->dohelp) {
50732144Sminshall 	    printf("%s\t%s\n", c->name, c->help);
50832144Sminshall 	}
50932144Sminshall     }
51032144Sminshall     return 0;
51132144Sminshall }
51232144Sminshall 
51332144Sminshall static char **
51432144Sminshall getnexttoggle(name)
51532144Sminshall char *name;
51632144Sminshall {
51732144Sminshall     struct togglelist *c = (struct togglelist *) name;
51832144Sminshall 
51932144Sminshall     return (char **) (c+1);
52032144Sminshall }
52132144Sminshall 
52232144Sminshall static struct togglelist *
52332144Sminshall gettoggle(name)
52432144Sminshall char *name;
52532144Sminshall {
52632144Sminshall     return (struct togglelist *)
52732144Sminshall 			genget(name, (char **) Togglelist, getnexttoggle);
52832144Sminshall }
52932144Sminshall 
53032144Sminshall static
53132144Sminshall toggle(argc, argv)
53232144Sminshall int	argc;
53332144Sminshall char	*argv[];
53432144Sminshall {
53532144Sminshall     int retval = 1;
53632144Sminshall     char *name;
53732144Sminshall     struct togglelist *c;
53832144Sminshall 
53932144Sminshall     if (argc < 2) {
54032144Sminshall 	fprintf(stderr,
54132144Sminshall 	    "Need an argument to 'toggle' command.  'toggle ?' for help.\n");
54232144Sminshall 	return 0;
54332144Sminshall     }
54432144Sminshall     argc--;
54532144Sminshall     argv++;
54632144Sminshall     while (argc--) {
54732144Sminshall 	name = *argv++;
54832144Sminshall 	c = gettoggle(name);
54932144Sminshall 	if (Ambiguous(c)) {
55032144Sminshall 	    fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n",
55132144Sminshall 					name);
55232144Sminshall 	    return 0;
55332144Sminshall 	} else if (c == 0) {
55432144Sminshall 	    fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n",
55532144Sminshall 					name);
55632144Sminshall 	    return 0;
55732144Sminshall 	} else {
55832144Sminshall 	    if (c->variable) {
55932144Sminshall 		*c->variable = !*c->variable;		/* invert it */
56032144Sminshall 		if (c->actionexplanation) {
56132144Sminshall 		    printf("%s %s.\n", *c->variable? "Will" : "Won't",
56232144Sminshall 							c->actionexplanation);
56332144Sminshall 		}
56432144Sminshall 		printf("%s %s.\n", *c->variable? "Will" : "Won't",
56532144Sminshall 							c->actionexplanation);
56632144Sminshall 	    }
56732144Sminshall 	    if (c->handler) {
56832144Sminshall 		retval &= (*c->handler)(c);
56932144Sminshall 	    }
57032144Sminshall 	}
57132144Sminshall     }
57232144Sminshall     return retval;
57332144Sminshall }
57432144Sminshall 
57532144Sminshall /*
57632144Sminshall  * The following perform the "set" command.
57732144Sminshall  */
57832144Sminshall 
57932144Sminshall struct setlist {
58032144Sminshall     char *name;				/* name */
58132144Sminshall     char *help;				/* help information */
58232144Sminshall     char *charp;			/* where it is located at */
58332144Sminshall };
58432144Sminshall 
58532144Sminshall static struct setlist Setlist[] = {
58632144Sminshall     { "echo", 	"character to toggle local echoing on/off", &echoc },
58732144Sminshall     { "escape",	"character to escape back to telnet command mode", &escape },
58832144Sminshall     { " ", "" },
58932144Sminshall     { " ", "The following need 'localchars' to be toggled true", 0 },
59032144Sminshall     { "erase",	"character to cause an Erase Character", &termEraseChar },
59132144Sminshall     { "flushoutput", "character to cause an Abort Oubput", &termFlushChar },
59232144Sminshall     { "interrupt", "character to cause an Interrupt Process", &termIntChar },
59332144Sminshall     { "kill",	"character to cause an Erase Line", &termKillChar },
59432144Sminshall     { "quit",	"character to cause a Break", &termQuitChar },
59532144Sminshall     { "eof",	"character to cause an EOF ", &termEofChar },
59632144Sminshall     { 0 }
59732144Sminshall };
59832144Sminshall 
59932144Sminshall static char **
60032144Sminshall getnextset(name)
60132144Sminshall char *name;
60232144Sminshall {
60332144Sminshall     struct setlist *c = (struct setlist *)name;
60432144Sminshall 
60532144Sminshall     return (char **) (c+1);
60632144Sminshall }
60732144Sminshall 
60832144Sminshall static struct setlist *
60932144Sminshall getset(name)
61032144Sminshall char *name;
61132144Sminshall {
61232144Sminshall     return (struct setlist *) genget(name, (char **) Setlist, getnextset);
61332144Sminshall }
61432144Sminshall 
61532144Sminshall static
61632144Sminshall setcmd(argc, argv)
61732144Sminshall int	argc;
61832144Sminshall char	*argv[];
61932144Sminshall {
62032144Sminshall     int value;
62132144Sminshall     struct setlist *ct;
62232144Sminshall 
62332144Sminshall     /* XXX back we go... sigh */
62432144Sminshall     if (argc != 3) {
62532144Sminshall 	if ((argc == 2) &&
62632144Sminshall 		    ((!strcmp(argv[1], "?")) || (!strcmp(argv[1], "help")))) {
62732144Sminshall 	    for (ct = Setlist; ct->name; ct++) {
62832144Sminshall 		printf("%s\t%s\n", ct->name, ct->help);
62932144Sminshall 	    }
63032144Sminshall 	    printf("?\tdisplay help information\n");
63132144Sminshall 	} else {
63232144Sminshall 	    printf("Format is 'set Name Value'\n'set ?' for help.\n");
63332144Sminshall 	}
63432144Sminshall 	return 0;
63532144Sminshall     }
63632144Sminshall 
63732144Sminshall     ct = getset(argv[1]);
63832144Sminshall     if (ct == 0) {
63932144Sminshall 	fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n",
64032144Sminshall 			argv[1]);
64132144Sminshall 	return 0;
64232144Sminshall     } else if (Ambiguous(ct)) {
64332144Sminshall 	fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
64432144Sminshall 			argv[1]);
64532144Sminshall 	return 0;
64632144Sminshall     } else {
64732144Sminshall 	if (strcmp("off", argv[2])) {
64832144Sminshall 	    value = special(argv[2]);
64932144Sminshall 	} else {
65032144Sminshall 	    value = -1;
65132144Sminshall 	}
65232144Sminshall 	*(ct->charp) = value;
65332144Sminshall 	printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
65432144Sminshall     }
65532144Sminshall     return 1;
65632144Sminshall }
65732144Sminshall 
65832144Sminshall /*
65932144Sminshall  * The following are the data structures and routines for the
66032144Sminshall  * 'mode' command.
66132144Sminshall  */
66232144Sminshall 
66332144Sminshall static
66432144Sminshall dolinemode()
66532144Sminshall {
66632144Sminshall     if (hisopts[TELOPT_SGA]) {
66732144Sminshall 	wontoption(TELOPT_SGA, 0);
66832144Sminshall     }
66932144Sminshall     if (hisopts[TELOPT_ECHO]) {
67032144Sminshall 	wontoption(TELOPT_ECHO, 0);
67132144Sminshall     }
67232144Sminshall     return 1;
67332144Sminshall }
67432144Sminshall 
67532144Sminshall static
67632144Sminshall docharmode()
67732144Sminshall {
67832144Sminshall     if (!hisopts[TELOPT_SGA]) {
67932144Sminshall 	willoption(TELOPT_SGA, 0);
68032144Sminshall     }
68132144Sminshall     if (!hisopts[TELOPT_ECHO]) {
68232144Sminshall 	willoption(TELOPT_ECHO, 0);
68332144Sminshall     }
68432144Sminshall     return 1;
68532144Sminshall }
68632144Sminshall 
68732144Sminshall static Command Mode_commands[] = {
68832144Sminshall     { "character",	"character-at-a-time mode",	docharmode, 1, 1 },
68932144Sminshall     { "line",		"line-by-line mode",		dolinemode, 1, 1 },
69032144Sminshall     { 0 },
69132144Sminshall };
69232144Sminshall 
69332144Sminshall static char **
69432144Sminshall getnextmode(name)
69532144Sminshall char *name;
69632144Sminshall {
69732144Sminshall     Command *c = (Command *) name;
69832144Sminshall 
69932144Sminshall     return (char **) (c+1);
70032144Sminshall }
70132144Sminshall 
70232144Sminshall static Command *
70332144Sminshall getmodecmd(name)
70432144Sminshall char *name;
70532144Sminshall {
70632144Sminshall     return (Command *) genget(name, (char **) Mode_commands, getnextmode);
70732144Sminshall }
70832144Sminshall 
70932144Sminshall static
71032144Sminshall modecmd(argc, argv)
71132144Sminshall int	argc;
71232144Sminshall char	*argv[];
71332144Sminshall {
71432144Sminshall     Command *mt;
71532144Sminshall 
71632144Sminshall     if ((argc != 2) || !strcmp(argv[1], "?") || !strcmp(argv[1], "help")) {
71732144Sminshall 	printf("format is:  'mode Mode', where 'Mode' is one of:\n\n");
71832144Sminshall 	for (mt = Mode_commands; mt->name; mt++) {
71932144Sminshall 	    printf("%s\t%s\n", mt->name, mt->help);
72032144Sminshall 	}
72132144Sminshall 	return 0;
72232144Sminshall     }
72332144Sminshall     mt = getmodecmd(argv[1]);
72432144Sminshall     if (mt == 0) {
72532144Sminshall 	fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]);
72632144Sminshall 	return 0;
72732144Sminshall     } else if (Ambiguous(mt)) {
72832144Sminshall 	fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]);
72932144Sminshall 	return 0;
73032144Sminshall     } else {
73132144Sminshall 	(*mt->handler)();
73232144Sminshall     }
73332144Sminshall     return 1;
73432144Sminshall }
73532144Sminshall 
73632144Sminshall /*
73732144Sminshall  * The following data structures and routines implement the
73832144Sminshall  * "display" command.
73932144Sminshall  */
74032144Sminshall 
74132144Sminshall static
74232144Sminshall display(argc, argv)
74332144Sminshall int	argc;
74432144Sminshall char	*argv[];
74532144Sminshall {
74632144Sminshall #define	dotog(tl)	if (tl->variable && tl->actionexplanation) { \
74732144Sminshall 			    if (*tl->variable) { \
74832144Sminshall 				printf("will"); \
74932144Sminshall 			    } else { \
75032144Sminshall 				printf("won't"); \
75132144Sminshall 			    } \
75232144Sminshall 			    printf(" %s.\n", tl->actionexplanation); \
75332144Sminshall 			}
75432144Sminshall 
75532144Sminshall #define	doset(sl)   if (sl->name && *sl->name != ' ') { \
75632144Sminshall 			printf("[%s]\t%s.\n", control(*sl->charp), sl->name); \
75732144Sminshall 		    }
75832144Sminshall 
75932144Sminshall     struct togglelist *tl;
76032144Sminshall     struct setlist *sl;
76132144Sminshall 
76232144Sminshall     if (argc == 1) {
76332144Sminshall 	for (tl = Togglelist; tl->name; tl++) {
76432144Sminshall 	    dotog(tl);
76532144Sminshall 	}
76632144Sminshall 	printf("\n");
76732144Sminshall 	for (sl = Setlist; sl->name; sl++) {
76832144Sminshall 	    doset(sl);
76932144Sminshall 	}
77032144Sminshall     } else {
77132144Sminshall 	int i;
77232144Sminshall 
77332144Sminshall 	for (i = 1; i < argc; i++) {
77432144Sminshall 	    sl = getset(argv[i]);
77532144Sminshall 	    tl = gettoggle(argv[i]);
77632144Sminshall 	    if (Ambiguous(sl) || Ambiguous(tl)) {
77732144Sminshall 		printf("?Ambiguous argument '%s'.\n", argv[i]);
77832144Sminshall 		return 0;
77932144Sminshall 	    } else if (!sl && !tl) {
78032144Sminshall 		printf("?Unknown argument '%s'.\n", argv[i]);
78132144Sminshall 		return 0;
78232144Sminshall 	    } else {
78332144Sminshall 		if (tl) {
78432144Sminshall 		    dotog(tl);
78532144Sminshall 		}
78632144Sminshall 		if (sl) {
78732144Sminshall 		    doset(sl);
78832144Sminshall 		}
78932144Sminshall 	    }
79032144Sminshall 	}
79132144Sminshall     }
79232144Sminshall     return 1;
79332144Sminshall #undef	doset
79432144Sminshall #undef	dotog
79532144Sminshall }
79632144Sminshall 
79732144Sminshall /*
79832144Sminshall  * The following are the data structures, and many of the routines,
79932144Sminshall  * relating to command processing.
80032144Sminshall  */
80132144Sminshall 
80232144Sminshall /*
80332144Sminshall  * Set the escape character.
80432144Sminshall  */
80532144Sminshall static
80632144Sminshall setescape(argc, argv)
80732144Sminshall 	int argc;
80832144Sminshall 	char *argv[];
80932144Sminshall {
81032144Sminshall 	register char *arg;
81132144Sminshall 	char buf[50];
81232144Sminshall 
81332144Sminshall 	printf(
81432144Sminshall 	    "Deprecated usage - please use 'set escape%s%s' in the future.\n",
81532144Sminshall 				(argc > 2)? " ":"", (argc > 2)? argv[1]: "");
81632144Sminshall 	if (argc > 2)
81732144Sminshall 		arg = argv[1];
81832144Sminshall 	else {
81932144Sminshall 		printf("new escape character: ");
82034849Sminshall 		(void) gets(buf);
82132144Sminshall 		arg = buf;
82232144Sminshall 	}
82332144Sminshall 	if (arg[0] != '\0')
82432144Sminshall 		escape = arg[0];
82532144Sminshall 	if (!In3270) {
82632144Sminshall 		printf("Escape character is '%s'.\n", control(escape));
82732144Sminshall 	}
82834849Sminshall 	(void) fflush(stdout);
82932144Sminshall 	return 1;
83032144Sminshall }
83132144Sminshall 
83232144Sminshall /*VARARGS*/
83332144Sminshall static
83432144Sminshall togcrmod()
83532144Sminshall {
83632144Sminshall     crmod = !crmod;
83732144Sminshall     printf("Deprecated usage - please use 'toggle crmod' in the future.\n");
83832144Sminshall     printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't");
83934849Sminshall     (void) fflush(stdout);
84032144Sminshall     return 1;
84132144Sminshall }
84232144Sminshall 
84332144Sminshall /*VARARGS*/
84432144Sminshall suspend()
84532144Sminshall {
84632144Sminshall 	setcommandmode();
84732144Sminshall #if	defined(unix)
84834849Sminshall 	(void) kill(0, SIGTSTP);
84932144Sminshall #endif	/* defined(unix) */
85032144Sminshall 	/* reget parameters in case they were changed */
85132144Sminshall 	TerminalSaveState();
85232144Sminshall 	setconnmode();
85332144Sminshall 	return 1;
85432144Sminshall }
85532144Sminshall 
85632144Sminshall /*VARARGS*/
85732144Sminshall static
85832144Sminshall bye(argc, argv)
85932144Sminshall int	argc;		/* Number of arguments */
86032144Sminshall char	*argv[];	/* arguments */
86132144Sminshall {
86232144Sminshall     if (connected) {
86334849Sminshall 	(void) shutdown(net, 2);
86432144Sminshall 	printf("Connection closed.\n");
86534849Sminshall 	(void) NetClose(net);
86632144Sminshall 	connected = 0;
86732144Sminshall 	/* reset options */
86832144Sminshall 	tninit();
86932144Sminshall #if	defined(TN3270)
87032144Sminshall 	SetIn3270();		/* Get out of 3270 mode */
87132144Sminshall #endif	/* defined(TN3270) */
87232144Sminshall     }
87332144Sminshall     if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) {
87432144Sminshall 	longjmp(toplevel, 1);
87532144Sminshall 	/* NOTREACHED */
87632144Sminshall     }
87732144Sminshall     return 1;			/* Keep lint, etc., happy */
87832144Sminshall }
87932144Sminshall 
88032144Sminshall /*VARARGS*/
88132144Sminshall quit()
88232144Sminshall {
88332144Sminshall 	(void) call(bye, "bye", "fromquit", 0);
88432144Sminshall 	Exit(0);
88532144Sminshall 	return 1;			/* just to keep lint happy */
88632144Sminshall }
88732144Sminshall 
88832144Sminshall /*
88932144Sminshall  * Print status about the connection.
89032144Sminshall  */
89134849Sminshall /*ARGSUSED*/
89232144Sminshall static
89332144Sminshall status(argc, argv)
89432144Sminshall int	argc;
89532144Sminshall char	*argv[];
89632144Sminshall {
89732144Sminshall     if (connected) {
89832144Sminshall 	printf("Connected to %s.\n", hostname);
89932144Sminshall 	if (argc < 2) {
90032144Sminshall 	    printf("Operating in %s.\n",
90132144Sminshall 				modelist[getconnmode()].modedescriptions);
90232144Sminshall 	    if (localchars) {
90332144Sminshall 		printf("Catching signals locally.\n");
90432144Sminshall 	    }
90532144Sminshall 	}
90632144Sminshall     } else {
90732144Sminshall 	printf("No connection.\n");
90832144Sminshall     }
90932144Sminshall #   if !defined(TN3270)
91032144Sminshall     printf("Escape character is '%s'.\n", control(escape));
91134849Sminshall     (void) fflush(stdout);
91232144Sminshall #   else /* !defined(TN3270) */
91332144Sminshall     if ((!In3270) && ((argc < 2) || strcmp(argv[1], "notmuch"))) {
91432144Sminshall 	printf("Escape character is '%s'.\n", control(escape));
91532144Sminshall     }
91632144Sminshall #   if defined(unix)
91732144Sminshall     if (In3270 && transcom) {
91832144Sminshall        printf("Transparent mode command is '%s'.\n", transcom);
91932144Sminshall     }
92032144Sminshall #   endif /* defined(unix) */
92134849Sminshall     (void) fflush(stdout);
92232144Sminshall     if (In3270) {
92332144Sminshall 	return 0;
92432144Sminshall     }
92532144Sminshall #   endif /* defined(TN3270) */
92632144Sminshall     return 1;
92732144Sminshall }
92832144Sminshall 
92932144Sminshall 
93032144Sminshall 
93132144Sminshall int
93232144Sminshall tn(argc, argv)
93332144Sminshall 	int argc;
93432144Sminshall 	char *argv[];
93532144Sminshall {
93632144Sminshall     register struct hostent *host = 0;
93732144Sminshall     struct sockaddr_in sin;
93832144Sminshall     struct servent *sp = 0;
93932144Sminshall     static char	hnamebuf[32];
94034849Sminshall     unsigned long inet_addr();
94132144Sminshall 
94232144Sminshall 
94332144Sminshall #if defined(MSDOS)
94432144Sminshall     char *cp;
94532144Sminshall #endif	/* defined(MSDOS) */
94632144Sminshall 
94732144Sminshall     if (connected) {
94832144Sminshall 	printf("?Already connected to %s\n", hostname);
94932144Sminshall 	return 0;
95032144Sminshall     }
95132144Sminshall     if (argc < 2) {
95232144Sminshall 	(void) strcpy(line, "Connect ");
95332144Sminshall 	printf("(to) ");
95434849Sminshall 	(void) gets(&line[strlen(line)]);
95532144Sminshall 	makeargv();
95632144Sminshall 	argc = margc;
95732144Sminshall 	argv = margv;
95832144Sminshall     }
95932144Sminshall     if ((argc < 2) || (argc > 3)) {
96032144Sminshall 	printf("usage: %s host-name [port]\n", argv[0]);
96132144Sminshall 	return 0;
96232144Sminshall     }
96332144Sminshall #if	defined(MSDOS)
96432144Sminshall     for (cp = argv[1]; *cp; cp++) {
96532144Sminshall 	if (isupper(*cp)) {
96632144Sminshall 	    *cp = tolower(*cp);
96732144Sminshall 	}
96832144Sminshall     }
96932144Sminshall #endif	/* defined(MSDOS) */
97032144Sminshall     sin.sin_addr.s_addr = inet_addr(argv[1]);
97132144Sminshall     if (sin.sin_addr.s_addr != -1) {
97232144Sminshall 	sin.sin_family = AF_INET;
97332144Sminshall 	(void) strcpy(hnamebuf, argv[1]);
97432144Sminshall 	hostname = hnamebuf;
97532144Sminshall     } else {
97632144Sminshall 	host = gethostbyname(argv[1]);
97732144Sminshall 	if (host) {
97832144Sminshall 	    sin.sin_family = host->h_addrtype;
97932144Sminshall #if	defined(h_addr)		/* In 4.3, this is a #define */
98032144Sminshall 	    memcpy((caddr_t)&sin.sin_addr,
98132144Sminshall 				host->h_addr_list[0], host->h_length);
98232144Sminshall #else	/* defined(h_addr) */
98332144Sminshall 	    memcpy((caddr_t)&sin.sin_addr, host->h_addr, host->h_length);
98432144Sminshall #endif	/* defined(h_addr) */
98532144Sminshall 	    hostname = host->h_name;
98632144Sminshall 	} else {
98732144Sminshall 	    printf("%s: unknown host\n", argv[1]);
98832144Sminshall 	    return 0;
98932144Sminshall 	}
99032144Sminshall     }
99132144Sminshall     if (argc == 3) {
99232144Sminshall 	sin.sin_port = atoi(argv[2]);
99332144Sminshall 	if (sin.sin_port == 0) {
99432144Sminshall 	    sp = getservbyname(argv[2], "tcp");
99532144Sminshall 	    if (sp)
99632144Sminshall 		sin.sin_port = sp->s_port;
99732144Sminshall 	    else {
99832144Sminshall 		printf("%s: bad port number\n", argv[2]);
99932144Sminshall 		return 0;
100032144Sminshall 	    }
100132144Sminshall 	} else {
100234849Sminshall #if	!defined(htons)
100334849Sminshall 	    u_short htons();
100434849Sminshall #endif	/* !defined(htons) */
100534849Sminshall 
100632144Sminshall 	    sin.sin_port = atoi(argv[2]);
100732144Sminshall 	    sin.sin_port = htons(sin.sin_port);
100832144Sminshall 	}
100932144Sminshall 	telnetport = 0;
101032144Sminshall     } else {
101132144Sminshall 	if (sp == 0) {
101232144Sminshall 	    sp = getservbyname("telnet", "tcp");
101332144Sminshall 	    if (sp == 0) {
101434849Sminshall 		fprintf(stderr, "telnet: tcp/telnet: unknown service\n");
101532144Sminshall 		return 0;
101632144Sminshall 	    }
101732144Sminshall 	    sin.sin_port = sp->s_port;
101832144Sminshall 	}
101932144Sminshall 	telnetport = 1;
102032144Sminshall     }
102132144Sminshall     printf("Trying...\n");
102232144Sminshall     do {
102332144Sminshall 	net = socket(AF_INET, SOCK_STREAM, 0);
102432144Sminshall 	if (net < 0) {
102532144Sminshall 	    perror("telnet: socket");
102632144Sminshall 	    return 0;
102732144Sminshall 	}
102832144Sminshall 	if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) {
102932144Sminshall 		perror("setsockopt (SO_DEBUG)");
103032144Sminshall 	}
103132144Sminshall 
103232144Sminshall 	if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
103332144Sminshall #if	defined(h_addr)		/* In 4.3, this is a #define */
103432144Sminshall 	    if (host && host->h_addr_list[1]) {
103532144Sminshall 		int oerrno = errno;
103634849Sminshall 		extern char *inet_ntoa();
103732144Sminshall 
103832144Sminshall 		fprintf(stderr, "telnet: connect to address %s: ",
103932144Sminshall 						inet_ntoa(sin.sin_addr));
104032144Sminshall 		errno = oerrno;
104132144Sminshall 		perror((char *)0);
104232144Sminshall 		host->h_addr_list++;
104332144Sminshall 		memcpy((caddr_t)&sin.sin_addr,
104432144Sminshall 			host->h_addr_list[0], host->h_length);
104532144Sminshall 		fprintf(stderr, "Trying %s...\n",
104632144Sminshall 			inet_ntoa(sin.sin_addr));
104732144Sminshall 		(void) NetClose(net);
104832144Sminshall 		continue;
104932144Sminshall 	    }
105032144Sminshall #endif	/* defined(h_addr) */
105132144Sminshall 	    perror("telnet: Unable to connect to remote host");
105232144Sminshall 	    return 0;
105332144Sminshall 	    }
105432144Sminshall 	connected++;
105532144Sminshall     } while (connected == 0);
105634849Sminshall     (void) call(status, "status", "notmuch", 0);
105732144Sminshall     if (setjmp(peerdied) == 0)
105832144Sminshall 	telnet();
105934849Sminshall     (void) NetClose(net);
106032381Sminshall     ExitString("Connection closed by foreign host.\n",1);
106132144Sminshall     /*NOTREACHED*/
106232144Sminshall }
106332144Sminshall 
106432144Sminshall 
106532144Sminshall #define HELPINDENT (sizeof ("connect"))
106632144Sminshall 
106732144Sminshall static char
106832144Sminshall 	openhelp[] =	"connect to a site",
106932144Sminshall 	closehelp[] =	"close current connection",
107032144Sminshall 	quithelp[] =	"exit telnet",
107132144Sminshall 	statushelp[] =	"print status information",
107232144Sminshall 	helphelp[] =	"print help information",
107332144Sminshall 	sendhelp[] =	"transmit special characters ('send ?' for more)",
107432144Sminshall 	sethelp[] = 	"set operating parameters ('set ?' for more)",
107532144Sminshall 	togglestring[] ="toggle operating parameters ('toggle ?' for more)",
107632144Sminshall 	displayhelp[] =	"display operating parameters",
107732144Sminshall #if	defined(TN3270) && defined(unix)
107832144Sminshall 	transcomhelp[] = "specify Unix command for transparent mode pipe",
107932144Sminshall #endif	/* defined(TN3270) && defined(unix) */
108032144Sminshall #if	defined(unix)
108132144Sminshall 	zhelp[] =	"suspend telnet",
108232144Sminshall #endif	/* defined(unix */
108332144Sminshall #if	defined(TN3270)
108432144Sminshall 	shellhelp[] =	"invoke a subshell",
108532144Sminshall #endif	/* defined(TN3270) */
108632144Sminshall 	modehelp[] = "try to enter line-by-line or character-at-a-time mode";
108732144Sminshall 
108832144Sminshall extern int	help(), shell();
108932144Sminshall 
109032144Sminshall static Command cmdtab[] = {
109132144Sminshall 	{ "close",	closehelp,	bye,		1, 1 },
109232144Sminshall 	{ "display",	displayhelp,	display,	1, 0 },
109332144Sminshall 	{ "mode",	modehelp,	modecmd,	1, 1 },
109432144Sminshall 	{ "open",	openhelp,	tn,		1, 0 },
109532144Sminshall 	{ "quit",	quithelp,	quit,		1, 0 },
109632144Sminshall 	{ "send",	sendhelp,	sendcmd,	1, 1 },
109732144Sminshall 	{ "set",	sethelp,	setcmd,		1, 0 },
109832144Sminshall 	{ "status",	statushelp,	status,		1, 0 },
109932144Sminshall 	{ "toggle",	togglestring,	toggle,		1, 0 },
110032144Sminshall #if	defined(TN3270) && defined(unix)
110132144Sminshall 	{ "transcom",	transcomhelp,	settranscom,	1, 0 },
110232144Sminshall #endif	/* defined(TN3270) && defined(unix) */
110332144Sminshall #if	defined(unix)
110432144Sminshall 	{ "z",		zhelp,		suspend,	1, 0 },
110532144Sminshall #endif	/* defined(unix) */
110632144Sminshall #if	defined(TN3270)
110732144Sminshall 	{ "!",		shellhelp,	shell,		1, 1 },
110832144Sminshall #endif	/* defined(TN3270) */
110932144Sminshall 	{ "?",		helphelp,	help,		1, 0 },
111032144Sminshall 	0
111132144Sminshall };
111232144Sminshall 
111332144Sminshall static char	crmodhelp[] =	"deprecated command -- use 'toggle crmod' instead";
111432144Sminshall static char	escapehelp[] =	"deprecated command -- use 'set escape' instead";
111532144Sminshall 
111632144Sminshall static Command cmdtab2[] = {
111732144Sminshall 	{ "help",	helphelp,	help,		0, 0 },
111832144Sminshall 	{ "escape",	escapehelp,	setescape,	1, 0 },
111932144Sminshall 	{ "crmod",	crmodhelp,	togcrmod,	1, 0 },
112032144Sminshall 	0
112132144Sminshall };
112232144Sminshall 
112335298Sminshall 
112432144Sminshall /*
112532144Sminshall  * Call routine with argc, argv set from args (terminated by 0).
112632144Sminshall  */
112735298Sminshall 
1128*35417Sminshall /*VARARGS1*/
112932144Sminshall static
113035298Sminshall call(va_alist)
113135298Sminshall va_dcl
113232144Sminshall {
113335298Sminshall     va_list ap;
113435298Sminshall     typedef int (*intrtn_t)();
113535298Sminshall     intrtn_t routine;
113635298Sminshall     char *args[100];
113732144Sminshall 
113835298Sminshall     int argno = 0;
113935298Sminshall 
114035298Sminshall     va_start(ap);
114135298Sminshall     routine = (va_arg(ap, intrtn_t));
114235298Sminshall     while (args[argno++] = va_arg(ap, char *))
114335298Sminshall 	;
114435298Sminshall     va_end(ap);
114535298Sminshall     return (*routine)(argno, args);
114632144Sminshall }
114732144Sminshall 
114835298Sminshall 
114932144Sminshall static char **
115032144Sminshall getnextcmd(name)
115132144Sminshall char *name;
115232144Sminshall {
115332144Sminshall     Command *c = (Command *) name;
115432144Sminshall 
115532144Sminshall     return (char **) (c+1);
115632144Sminshall }
115732144Sminshall 
115832144Sminshall static Command *
115932144Sminshall getcmd(name)
116032144Sminshall char *name;
116132144Sminshall {
116232144Sminshall     Command *cm;
116332144Sminshall 
116432144Sminshall     if ((cm = (Command *) genget(name, (char **) cmdtab, getnextcmd)) != 0) {
116532144Sminshall 	return cm;
116632144Sminshall     } else {
116732144Sminshall 	return (Command *) genget(name, (char **) cmdtab2, getnextcmd);
116832144Sminshall     }
116932144Sminshall }
117032144Sminshall 
117132144Sminshall void
117232144Sminshall command(top)
117332144Sminshall 	int top;
117432144Sminshall {
117532144Sminshall     register Command *c;
117632144Sminshall 
117732144Sminshall     setcommandmode();
117832144Sminshall     if (!top) {
117932144Sminshall 	putchar('\n');
118032144Sminshall     } else {
118132144Sminshall #if	defined(unix)
118232144Sminshall 	signal(SIGINT, SIG_DFL);
118332144Sminshall 	signal(SIGQUIT, SIG_DFL);
118432144Sminshall #endif	/* defined(unix) */
118532144Sminshall     }
118632144Sminshall     for (;;) {
118732144Sminshall 	printf("%s> ", prompt);
118832144Sminshall 	if (gets(line) == NULL) {
118932144Sminshall 	    if (feof(stdin) || ferror(stdin))
119032144Sminshall 		quit();
119132144Sminshall 	    break;
119232144Sminshall 	}
119332144Sminshall 	if (line[0] == 0)
119432144Sminshall 	    break;
119532144Sminshall 	makeargv();
119632144Sminshall 	c = getcmd(margv[0]);
119732144Sminshall 	if (Ambiguous(c)) {
119832144Sminshall 	    printf("?Ambiguous command\n");
119932144Sminshall 	    continue;
120032144Sminshall 	}
120132144Sminshall 	if (c == 0) {
120232144Sminshall 	    printf("?Invalid command\n");
120332144Sminshall 	    continue;
120432144Sminshall 	}
120532144Sminshall 	if (c->needconnect && !connected) {
120632144Sminshall 	    printf("?Need to be connected first.\n");
120732144Sminshall 	    continue;
120832144Sminshall 	}
120932144Sminshall 	if ((*c->handler)(margc, margv)) {
121032144Sminshall 	    break;
121132144Sminshall 	}
121232144Sminshall     }
121332144Sminshall     if (!top) {
121432144Sminshall 	if (!connected) {
121532144Sminshall 	    longjmp(toplevel, 1);
121632144Sminshall 	    /*NOTREACHED*/
121732144Sminshall 	}
121832144Sminshall #if	defined(TN3270)
121932144Sminshall 	if (shell_active == 0) {
122032144Sminshall 	    setconnmode();
122132144Sminshall 	}
122232144Sminshall #else	/* defined(TN3270) */
122332144Sminshall 	setconnmode();
122432144Sminshall #endif	/* defined(TN3270) */
122532144Sminshall     }
122632144Sminshall }
122732144Sminshall 
122832144Sminshall /*
122932144Sminshall  * Help command.
123032144Sminshall  */
123132144Sminshall static
123232144Sminshall help(argc, argv)
123332144Sminshall 	int argc;
123432144Sminshall 	char *argv[];
123532144Sminshall {
123632144Sminshall 	register Command *c;
123732144Sminshall 
123832144Sminshall 	if (argc == 1) {
123932144Sminshall 		printf("Commands may be abbreviated.  Commands are:\n\n");
124032144Sminshall 		for (c = cmdtab; c->name; c++)
124132144Sminshall 			if (c->dohelp) {
124232144Sminshall 				printf("%-*s\t%s\n", HELPINDENT, c->name,
124332144Sminshall 								    c->help);
124432144Sminshall 			}
124532144Sminshall 		return 0;
124632144Sminshall 	}
124732144Sminshall 	while (--argc > 0) {
124832144Sminshall 		register char *arg;
124932144Sminshall 		arg = *++argv;
125032144Sminshall 		c = getcmd(arg);
125132144Sminshall 		if (Ambiguous(c))
125232144Sminshall 			printf("?Ambiguous help command %s\n", arg);
125332144Sminshall 		else if (c == (Command *)0)
125432144Sminshall 			printf("?Invalid help command %s\n", arg);
125532144Sminshall 		else
125632144Sminshall 			printf("%s\n", c->help);
125732144Sminshall 	}
125832144Sminshall 	return 0;
125932144Sminshall }
1260