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