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