OSDN Git Service

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