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