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