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