inet6: only mark autoconf addresses tentative if detached
[dragonfly.git] / usr.bin / telnet / commands.c
blob6d2001afabab83dc058229d51faeaa8dbb197db4
1 /*
2 * Copyright (c) 1988, 1990, 1993
3 * The Regents of the University of California. All rights reserved.
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. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
29 * @(#)commands.c 8.4 (Berkeley) 5/30/95
30 * $FreeBSD: src/crypto/telnet/telnet/commands.c,v 1.12.2.7 2003/04/23 07:16:32 ru Exp $
33 #include <sys/param.h>
34 #include <sys/un.h>
35 #include <sys/file.h>
36 #include <sys/socket.h>
37 #include <sys/wait.h>
38 #include <netinet/in.h>
40 #include <assert.h>
41 #include <ctype.h>
42 #include <err.h>
43 #include <errno.h>
44 #include <netdb.h>
45 #include <pwd.h>
46 #include <signal.h>
47 #include <stdarg.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <unistd.h>
52 #include <arpa/telnet.h>
53 #include <arpa/inet.h>
55 #include "general.h"
57 #include "ring.h"
59 #include "externs.h"
60 #include "defines.h"
61 #include "types.h"
62 #include "misc.h"
64 #ifdef AUTHENTICATION
65 #include <libtelnet/auth.h>
66 #endif
67 #ifdef ENCRYPTION
68 #include <libtelnet/encrypt.h>
69 #endif
71 #include <netinet/in_systm.h>
72 #include <netinet/ip.h>
73 #include <netinet/ip6.h>
75 #ifndef MAXHOSTNAMELEN
76 #define MAXHOSTNAMELEN 256
77 #endif
79 typedef int (*intrtn_t)(int, char **);
81 #ifdef AUTHENTICATION
82 extern int auth_togdebug(int);
83 #endif
84 #ifdef ENCRYPTION
85 extern int EncryptAutoEnc(int);
86 extern int EncryptAutoDec(int);
87 extern int EncryptDebug(int);
88 extern int EncryptVerbose(int);
89 #endif /* ENCRYPTION */
90 #if defined(IPPROTO_IP) && defined(IP_TOS)
91 int tos = -1;
92 #endif /* defined(IPPROTO_IP) && defined(IP_TOS) */
94 char *hostname;
95 static char _hostname[MAXHOSTNAMELEN];
97 static int help(int, char **);
98 static int call(intrtn_t, ...);
99 static void cmdrc(const char *, const char *);
100 #ifdef INET6
101 static int switch_af(struct addrinfo **);
102 #endif
103 static int togglehelp(void);
104 static int send_tncmd(void (*)(int, int), const char *, char *);
105 static int setmod(int);
106 static int clearmode(int);
107 static int modehelp(void);
108 static int sourceroute(struct addrinfo *, char *, char **, int *, int *, int *);
110 typedef struct {
111 const char *name; /* command name */
112 const char *help; /* help string (NULL for no help) */
113 int (*handler)(int, char **); /* routine which executes command */
114 int needconnect; /* Do we need to be connected to execute? */
115 } Command;
117 static char line[256];
118 static char saveline[256];
119 static int margc;
120 static char *margv[20];
122 static void
123 makeargv(void)
125 char *cp, *cp2, c;
126 char **argp = margv;
128 margc = 0;
129 cp = line;
130 if (*cp == '!') { /* Special case shell escape */
131 strcpy(saveline, line); /* save for shell command */
132 *argp++ = strdup("!"); /* No room in string to get this */
133 margc++;
134 cp++;
136 while ((c = *cp)) {
137 int inquote = 0;
138 while (isspace(c))
139 c = *++cp;
140 if (c == '\0')
141 break;
142 *argp++ = cp;
143 margc += 1;
144 for (cp2 = cp; c != '\0'; c = *++cp) {
145 if (inquote) {
146 if (c == inquote) {
147 inquote = 0;
148 continue;
150 } else {
151 if (c == '\\') {
152 if ((c = *++cp) == '\0')
153 break;
154 } else if (c == '"') {
155 inquote = '"';
156 continue;
157 } else if (c == '\'') {
158 inquote = '\'';
159 continue;
160 } else if (isspace(c))
161 break;
163 *cp2++ = c;
165 *cp2 = '\0';
166 if (c == '\0')
167 break;
168 cp++;
170 *argp++ = NULL;
174 * Make a character string into a number.
176 * Todo: 1. Could take random integers (12, 0x12, 012, 0b1).
179 static int
180 special(char *s)
182 char c;
183 char b;
185 switch (*s) {
186 case '^':
187 b = *++s;
188 if (b == '?') {
189 c = b | 0x40; /* DEL */
190 } else {
191 c = b & 0x1f;
193 break;
194 default:
195 c = *s;
196 break;
198 return c;
202 * Construct a control character sequence
203 * for a special character.
205 static const char *
206 control(cc_t c)
208 static char buf[5];
210 * The only way I could get the Sun 3.5 compiler
211 * to shut up about
212 * if ((unsigned int)c >= 0x80)
213 * was to assign "c" to an unsigned int variable...
214 * Arggg....
216 unsigned int uic = (unsigned int)c;
218 if (uic == 0x7f)
219 return ("^?");
220 if (c == (cc_t)_POSIX_VDISABLE) {
221 return "off";
223 if (uic >= 0x80) {
224 buf[0] = '\\';
225 buf[1] = ((c>>6)&07) + '0';
226 buf[2] = ((c>>3)&07) + '0';
227 buf[3] = (c&07) + '0';
228 buf[4] = 0;
229 } else if (uic >= 0x20) {
230 buf[0] = c;
231 buf[1] = 0;
232 } else {
233 buf[0] = '^';
234 buf[1] = '@'+c;
235 buf[2] = 0;
237 return (buf);
241 * The following are data structures and routines for
242 * the "send" command.
246 struct sendlist {
247 const char *name; /* How user refers to it (case independent) */
248 const char *help; /* Help information (0 ==> no help) */
249 int needconnect; /* Need to be connected */
250 int narg; /* Number of arguments */
251 int (*handler)(char *, ...); /* Routine to perform (for special ops) */
252 int nbyte; /* Number of bytes to send this command */
253 int what; /* Character to be sent (<0 ==> special) */
257 static int
258 send_esc(void),
259 send_help(void),
260 send_docmd(char *),
261 send_dontcmd(char *),
262 send_willcmd(char *),
263 send_wontcmd(char *);
265 static struct sendlist Sendlist[] = {
266 { "ao", "Send Telnet Abort output", 1, 0, NULL, 2, AO },
267 { "ayt", "Send Telnet 'Are You There'", 1, 0, NULL, 2, AYT },
268 { "brk", "Send Telnet Break", 1, 0, NULL, 2, BREAK },
269 { "break", NULL, 1, 0, NULL, 2, BREAK },
270 { "ec", "Send Telnet Erase Character", 1, 0, NULL, 2, EC },
271 { "el", "Send Telnet Erase Line", 1, 0, NULL, 2, EL },
272 { "escape", "Send current escape character",1, 0, (int (*)(char *, ...))send_esc, 1, 0 },
273 { "ga", "Send Telnet 'Go Ahead' sequence", 1, 0, NULL, 2, GA },
274 { "ip", "Send Telnet Interrupt Process",1, 0, NULL, 2, IP },
275 { "intp", NULL, 1, 0, NULL, 2, IP },
276 { "interrupt", NULL, 1, 0, NULL, 2, IP },
277 { "intr", NULL, 1, 0, NULL, 2, IP },
278 { "nop", "Send Telnet 'No operation'", 1, 0, NULL, 2, NOP },
279 { "eor", "Send Telnet 'End of Record'", 1, 0, NULL, 2, EOR },
280 { "abort", "Send Telnet 'Abort Process'", 1, 0, NULL, 2, ABORT },
281 { "susp", "Send Telnet 'Suspend Process'",1, 0, NULL, 2, SUSP },
282 { "eof", "Send Telnet End of File Character", 1, 0, NULL, 2, xEOF },
283 { "synch", "Perform Telnet 'Synch operation'", 1, 0, (int (*)(char *, ...))dosynch, 2, 0 },
284 { "getstatus", "Send request for STATUS", 1, 0, (int (*)(char *, ...))get_status, 6, 0 },
285 { "?", "Display send options", 0, 0, (int (*)(char *, ...))send_help, 0, 0 },
286 { "help", NULL, 0, 0, (int (*)(char *, ...))send_help, 0, 0 },
287 { "do", NULL, 0, 1, (int (*)(char *, ...))send_docmd, 3, 0 },
288 { "dont", NULL, 0, 1, (int (*)(char *, ...))send_dontcmd, 3, 0 },
289 { "will", NULL, 0, 1, (int (*)(char *, ...))send_willcmd, 3, 0 },
290 { "wont", NULL, 0, 1, (int (*)(char *, ...))send_wontcmd, 3, 0 },
291 { NULL, NULL, 0, 0, NULL, 0, 0 }
294 #define GETSEND(name) ((struct sendlist *) genget(name, (char **) Sendlist, \
295 sizeof(struct sendlist)))
297 static int
298 sendcmd(int argc, char *argv[])
300 int count; /* how many bytes we are going to need to send */
301 int i;
302 struct sendlist *s; /* pointer to current command */
303 int success = 0;
304 int needconnect = 0;
306 if (argc < 2) {
307 printf("need at least one argument for 'send' command\n");
308 printf("'send ?' for help\n");
309 return 0;
312 * First, validate all the send arguments.
313 * In addition, we see how much space we are going to need, and
314 * whether or not we will be doing a "SYNCH" operation (which
315 * flushes the network queue).
317 count = 0;
318 for (i = 1; i < argc; i++) {
319 s = GETSEND(argv[i]);
320 if (s == NULL) {
321 printf("Unknown send argument '%s'\n'send ?' for help.\n",
322 argv[i]);
323 return 0;
324 } else if (Ambiguous((void *)s)) {
325 printf("Ambiguous send argument '%s'\n'send ?' for help.\n",
326 argv[i]);
327 return 0;
329 if (i + s->narg >= argc) {
330 fprintf(stderr,
331 "Need %d argument%s to 'send %s' command. 'send %s ?' for help.\n",
332 s->narg, s->narg == 1 ? "" : "s", s->name, s->name);
333 return 0;
335 count += s->nbyte;
336 if ((void *)s->handler == (void *)send_help) {
337 send_help();
338 return 0;
341 i += s->narg;
342 needconnect += s->needconnect;
344 if (!connected && needconnect) {
345 printf("?Need to be connected first.\n");
346 printf("'send ?' for help\n");
347 return 0;
349 /* Now, do we have enough room? */
350 if (NETROOM() < count) {
351 printf("There is not enough room in the buffer TO the network\n");
352 printf("to process your request. Nothing will be done.\n");
353 printf("('send synch' will throw away most data in the network\n");
354 printf("buffer, if this might help.)\n");
355 return 0;
357 /* OK, they are all OK, now go through again and actually send */
358 count = 0;
359 for (i = 1; i < argc; i++) {
360 if ((s = GETSEND(argv[i])) == NULL) {
361 fprintf(stderr, "Telnet 'send' error - argument disappeared!\n");
362 quit();
363 /*NOTREACHED*/
365 if (s->handler) {
366 count++;
367 success += (*s->handler)((s->narg > 0) ? argv[i+1] : 0,
368 (s->narg > 1) ? argv[i+2] : 0);
369 i += s->narg;
370 } else {
371 NET2ADD(IAC, s->what);
372 printoption("SENT", IAC, s->what);
375 return (count == success);
378 static int
379 send_esc(void)
381 NETADD(escape);
382 return 1;
385 static int
386 send_docmd(char *name)
388 return(send_tncmd(send_do, "do", name));
391 static int
392 send_dontcmd(char *name)
394 return(send_tncmd(send_dont, "dont", name));
397 static int
398 send_willcmd(char *name)
400 return(send_tncmd(send_will, "will", name));
403 static int
404 send_wontcmd(char *name)
406 return(send_tncmd(send_wont, "wont", name));
409 static int
410 send_tncmd(void (*func)(int, int), const char *cmd, char *name)
412 char **cpp;
413 extern char *telopts[];
414 int val = 0;
416 if (isprefix(name, "help") || isprefix(name, "?")) {
417 int col, len;
419 printf("Usage: send %s <value|option>\n", cmd);
420 printf("\"value\" must be from 0 to 255\n");
421 printf("Valid options are:\n\t");
423 col = 8;
424 for (cpp = telopts; *cpp; cpp++) {
425 len = strlen(*cpp) + 3;
426 if (col + len > 65) {
427 printf("\n\t");
428 col = 8;
430 printf(" \"%s\"", *cpp);
431 col += len;
433 printf("\n");
434 return 0;
436 cpp = (char **)genget(name, telopts, sizeof(char *));
437 if (Ambiguous(cpp)) {
438 fprintf(stderr,"'%s': ambiguous argument ('send %s ?' for help).\n",
439 name, cmd);
440 return 0;
442 if (cpp) {
443 val = cpp - telopts;
444 } else {
445 char *cp = name;
447 while (*cp >= '0' && *cp <= '9') {
448 val *= 10;
449 val += *cp - '0';
450 cp++;
452 if (*cp != 0) {
453 fprintf(stderr, "'%s': unknown argument ('send %s ?' for help).\n",
454 name, cmd);
455 return 0;
456 } else if (val < 0 || val > 255) {
457 fprintf(stderr, "'%s': bad value ('send %s ?' for help).\n",
458 name, cmd);
459 return 0;
462 if (!connected) {
463 printf("?Need to be connected first.\n");
464 return 0;
466 (*func)(val, 1);
467 return 1;
470 static int
471 send_help(void)
473 struct sendlist *s; /* pointer to current command */
474 for (s = Sendlist; s->name; s++) {
475 if (s->help)
476 printf("%-15s %s\n", s->name, s->help);
478 return(0);
482 * The following are the routines and data structures referred
483 * to by the arguments to the "toggle" command.
486 static int
487 lclchars(void)
489 donelclchars = 1;
490 return 1;
493 static int
494 togdebug(void)
496 #ifndef NOT43
497 if (net > 0 &&
498 (SetSockOpt(net, SOL_SOCKET, SO_DEBUG, telnet_debug)) < 0) {
499 perror("setsockopt (SO_DEBUG)");
501 #else /* NOT43 */
502 if (telnet_debug) {
503 if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0)
504 perror("setsockopt (SO_DEBUG)");
505 } else
506 printf("Cannot turn off socket debugging\n");
507 #endif /* NOT43 */
508 return 1;
512 static int
513 togcrlf(void)
515 if (crlf) {
516 printf("Will send carriage returns as telnet <CR><LF>.\n");
517 } else {
518 printf("Will send carriage returns as telnet <CR><NUL>.\n");
520 return 1;
523 int binmode;
525 static int
526 togbinary(int val)
528 donebinarytoggle = 1;
530 if (val >= 0) {
531 binmode = val;
532 } else {
533 if (my_want_state_is_will(TELOPT_BINARY) &&
534 my_want_state_is_do(TELOPT_BINARY)) {
535 binmode = 1;
536 } else if (my_want_state_is_wont(TELOPT_BINARY) &&
537 my_want_state_is_dont(TELOPT_BINARY)) {
538 binmode = 0;
540 val = binmode ? 0 : 1;
543 if (val == 1) {
544 if (my_want_state_is_will(TELOPT_BINARY) &&
545 my_want_state_is_do(TELOPT_BINARY)) {
546 printf("Already operating in binary mode with remote host.\n");
547 } else {
548 printf("Negotiating binary mode with remote host.\n");
549 tel_enter_binary(3);
551 } else {
552 if (my_want_state_is_wont(TELOPT_BINARY) &&
553 my_want_state_is_dont(TELOPT_BINARY)) {
554 printf("Already in network ascii mode with remote host.\n");
555 } else {
556 printf("Negotiating network ascii mode with remote host.\n");
557 tel_leave_binary(3);
560 return 1;
563 static int
564 togrbinary(int val)
566 donebinarytoggle = 1;
568 if (val == -1)
569 val = my_want_state_is_do(TELOPT_BINARY) ? 0 : 1;
571 if (val == 1) {
572 if (my_want_state_is_do(TELOPT_BINARY)) {
573 printf("Already receiving in binary mode.\n");
574 } else {
575 printf("Negotiating binary mode on input.\n");
576 tel_enter_binary(1);
578 } else {
579 if (my_want_state_is_dont(TELOPT_BINARY)) {
580 printf("Already receiving in network ascii mode.\n");
581 } else {
582 printf("Negotiating network ascii mode on input.\n");
583 tel_leave_binary(1);
586 return 1;
589 static int
590 togxbinary(int val)
592 donebinarytoggle = 1;
594 if (val == -1)
595 val = my_want_state_is_will(TELOPT_BINARY) ? 0 : 1;
597 if (val == 1) {
598 if (my_want_state_is_will(TELOPT_BINARY)) {
599 printf("Already transmitting in binary mode.\n");
600 } else {
601 printf("Negotiating binary mode on output.\n");
602 tel_enter_binary(2);
604 } else {
605 if (my_want_state_is_wont(TELOPT_BINARY)) {
606 printf("Already transmitting in network ascii mode.\n");
607 } else {
608 printf("Negotiating network ascii mode on output.\n");
609 tel_leave_binary(2);
612 return 1;
615 struct togglelist {
616 const char *name; /* name of toggle */
617 const char *help; /* help message */
618 int (*handler)(int); /* routine to do actual setting */
619 int *variable;
620 const char *actionexplanation;
623 static struct togglelist Togglelist[] = {
624 { "autoflush",
625 "flushing of output when sending interrupt characters",
627 &autoflush,
628 "flush output when sending interrupt characters" },
629 { "autosynch",
630 "automatic sending of interrupt characters in urgent mode",
632 &autosynch,
633 "send interrupt characters in urgent mode" },
634 #ifdef AUTHENTICATION
635 { "autologin",
636 "automatic sending of login and/or authentication info",
638 &autologin,
639 "send login name and/or authentication information" },
640 { "authdebug",
641 "Toggle authentication debugging",
642 auth_togdebug,
644 "print authentication debugging information" },
645 #endif
646 #ifdef ENCRYPTION
647 { "autoencrypt",
648 "automatic encryption of data stream",
649 EncryptAutoEnc,
651 "automatically encrypt output" },
652 { "autodecrypt",
653 "automatic decryption of data stream",
654 EncryptAutoDec,
656 "automatically decrypt input" },
657 { "verbose_encrypt",
658 "Toggle verbose encryption output",
659 EncryptVerbose,
661 "print verbose encryption output" },
662 { "encdebug",
663 "Toggle encryption debugging",
664 EncryptDebug,
666 "print encryption debugging information" },
667 #endif /* ENCRYPTION */
668 { "skiprc",
669 "don't read ~/.telnetrc file",
671 &skiprc,
672 "skip reading of ~/.telnetrc file" },
673 { "binary",
674 "sending and receiving of binary data",
675 togbinary,
677 0 },
678 { "inbinary",
679 "receiving of binary data",
680 togrbinary,
682 0 },
683 { "outbinary",
684 "sending of binary data",
685 togxbinary,
687 0 },
688 { "crlf",
689 "sending carriage returns as telnet <CR><LF>",
690 (int (*)(int))togcrlf,
691 &crlf,
692 0 },
693 { "crmod",
694 "mapping of received carriage returns",
696 &crmod,
697 "map carriage return on output" },
698 { "localchars",
699 "local recognition of certain control characters",
700 (int (*)(int))lclchars,
701 &localchars,
702 "recognize certain control characters" },
703 { " ", "", NULL, NULL, NULL }, /* empty line */
704 { "debug",
705 "debugging",
706 (int (*)(int))togdebug,
707 &telnet_debug,
708 "turn on socket level debugging" },
709 { "netdata",
710 "printing of hexadecimal network data (debugging)",
712 &netdata,
713 "print hexadecimal representation of network traffic" },
714 { "prettydump",
715 "output of \"netdata\" to user readable format (debugging)",
717 &prettydump,
718 "print user readable output for \"netdata\"" },
719 { "options",
720 "viewing of options processing (debugging)",
722 &showoptions,
723 "show option processing" },
724 { "termdata",
725 "(debugging) toggle printing of hexadecimal terminal data",
727 &termdata,
728 "print hexadecimal representation of terminal traffic" },
729 { "?",
730 NULL,
731 (int (*)(int))togglehelp,
732 NULL,
733 NULL },
734 { NULL, NULL, NULL, NULL, NULL },
735 { "help",
736 NULL,
737 (int (*)(int))togglehelp,
738 NULL,
739 NULL },
740 { NULL, NULL, NULL, NULL, NULL }
743 static int
744 togglehelp(void)
746 struct togglelist *c;
748 for (c = Togglelist; c->name; c++) {
749 if (c->help) {
750 if (*c->help)
751 printf("%-15s toggle %s\n", c->name, c->help);
752 else
753 printf("\n");
756 printf("\n");
757 printf("%-15s %s\n", "?", "display help information");
758 return 0;
761 static void
762 settogglehelp(int set)
764 struct togglelist *c;
766 for (c = Togglelist; c->name; c++) {
767 if (c->help) {
768 if (*c->help)
769 printf("%-15s %s %s\n", c->name, set ? "enable" : "disable",
770 c->help);
771 else
772 printf("\n");
777 #define GETTOGGLE(name) (struct togglelist *) \
778 genget(name, (char **) Togglelist, sizeof(struct togglelist))
780 static int
781 toggle(int argc, char *argv[])
783 int retval = 1;
784 char *name;
785 struct togglelist *c;
787 if (argc < 2) {
788 fprintf(stderr,
789 "Need an argument to 'toggle' command. 'toggle ?' for help.\n");
790 return 0;
792 argc--;
793 argv++;
794 while (argc--) {
795 name = *argv++;
796 c = GETTOGGLE(name);
797 if (Ambiguous((void *)c)) {
798 fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n",
799 name);
800 return 0;
801 } else if (c == NULL) {
802 fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n",
803 name);
804 return 0;
805 } else {
806 if (c->variable) {
807 *c->variable = !*c->variable; /* invert it */
808 if (c->actionexplanation) {
809 printf("%s %s.\n", *c->variable? "Will" : "Won't",
810 c->actionexplanation);
813 if (c->handler) {
814 retval &= (*c->handler)(-1);
818 return retval;
822 * The following perform the "set" command.
825 #ifdef USE_TERMIO
826 struct termio new_tc = { 0, 0, 0, 0, {}, 0, 0 };
827 #endif
829 struct setlist {
830 const char *name; /* name */
831 const char *help; /* help information */
832 void (*handler)(char *);
833 cc_t *charp; /* where it is located at */
836 static struct setlist Setlist[] = {
837 #ifdef KLUDGELINEMODE
838 { "echo", "character to toggle local echoing on/off", NULL, &echoc },
839 #endif
840 { "escape", "character to escape back to telnet command mode", NULL, &escape },
841 { "rlogin", "rlogin escape character", 0, &rlogin },
842 { "tracefile", "file to write trace information to", SetNetTrace, (cc_t *)NetTraceFile},
843 { " ", "", NULL, NULL },
844 { " ", "The following need 'localchars' to be toggled true", NULL, NULL },
845 { "flushoutput", "character to cause an Abort Output", NULL, termFlushCharp },
846 { "interrupt", "character to cause an Interrupt Process", NULL, termIntCharp },
847 { "quit", "character to cause an Abort process", NULL, termQuitCharp },
848 { "eof", "character to cause an EOF ", NULL, termEofCharp },
849 { " ", "", NULL, NULL },
850 { " ", "The following are for local editing in linemode", NULL, NULL },
851 { "erase", "character to use to erase a character", NULL, termEraseCharp },
852 { "kill", "character to use to erase a line", NULL, termKillCharp },
853 { "lnext", "character to use for literal next", NULL, termLiteralNextCharp },
854 { "susp", "character to cause a Suspend Process", NULL, termSuspCharp },
855 { "reprint", "character to use for line reprint", NULL, termRprntCharp },
856 { "worderase", "character to use to erase a word", NULL, termWerasCharp },
857 { "start", "character to use for XON", NULL, termStartCharp },
858 { "stop", "character to use for XOFF", NULL, termStopCharp },
859 { "forw1", "alternate end of line character", NULL, termForw1Charp },
860 { "forw2", "alternate end of line character", NULL, termForw2Charp },
861 { "ayt", "alternate AYT character", NULL, termAytCharp },
862 { NULL, NULL, NULL, NULL }
865 static struct setlist *
866 getset(char *name)
868 return (struct setlist *)
869 genget(name, (char **) Setlist, sizeof(struct setlist));
872 void
873 set_escape_char(char *s)
875 if (rlogin != _POSIX_VDISABLE) {
876 rlogin = (s && *s) ? special(s) : _POSIX_VDISABLE;
877 printf("Telnet rlogin escape character is '%s'.\n",
878 control(rlogin));
879 } else {
880 escape = (s && *s) ? special(s) : _POSIX_VDISABLE;
881 printf("Telnet escape character is '%s'.\n", control(escape));
885 static int
886 setcmd(int argc, char *argv[])
888 int value;
889 struct setlist *ct;
890 struct togglelist *c;
892 if (argc < 2 || argc > 3) {
893 printf("Format is 'set Name Value'\n'set ?' for help.\n");
894 return 0;
896 if ((argc == 2) && (isprefix(argv[1], "?") || isprefix(argv[1], "help"))) {
897 for (ct = Setlist; ct->name; ct++)
898 printf("%-15s %s\n", ct->name, ct->help);
899 printf("\n");
900 settogglehelp(1);
901 printf("%-15s %s\n", "?", "display help information");
902 return 0;
905 ct = getset(argv[1]);
906 if (ct == NULL) {
907 c = GETTOGGLE(argv[1]);
908 if (c == NULL) {
909 fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n",
910 argv[1]);
911 return 0;
912 } else if (Ambiguous((void *)c)) {
913 fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
914 argv[1]);
915 return 0;
917 if (c->variable) {
918 if ((argc == 2) || (strcmp("on", argv[2]) == 0))
919 *c->variable = 1;
920 else if (strcmp("off", argv[2]) == 0)
921 *c->variable = 0;
922 else {
923 printf("Format is 'set togglename [on|off]'\n'set ?' for help.\n");
924 return 0;
926 if (c->actionexplanation) {
927 printf("%s %s.\n", *c->variable? "Will" : "Won't",
928 c->actionexplanation);
931 if (c->handler)
932 (*c->handler)(1);
933 } else if (argc != 3) {
934 printf("Format is 'set Name Value'\n'set ?' for help.\n");
935 return 0;
936 } else if (Ambiguous((void *)ct)) {
937 fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
938 argv[1]);
939 return 0;
940 } else if (ct->handler) {
941 (*ct->handler)(argv[2]);
942 printf("%s set to \"%s\".\n", ct->name, (char *)ct->charp);
943 } else {
944 if (strcmp("off", argv[2])) {
945 value = special(argv[2]);
946 } else {
947 value = _POSIX_VDISABLE;
949 *(ct->charp) = (cc_t)value;
950 printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
952 slc_check();
953 return 1;
956 static int
957 unsetcmd(int argc, char *argv[])
959 struct setlist *ct;
960 struct togglelist *c;
961 char *name;
963 if (argc < 2) {
964 fprintf(stderr,
965 "Need an argument to 'unset' command. 'unset ?' for help.\n");
966 return 0;
968 if (isprefix(argv[1], "?") || isprefix(argv[1], "help")) {
969 for (ct = Setlist; ct->name; ct++)
970 printf("%-15s %s\n", ct->name, ct->help);
971 printf("\n");
972 settogglehelp(0);
973 printf("%-15s %s\n", "?", "display help information");
974 return 0;
977 argc--;
978 argv++;
979 while (argc--) {
980 name = *argv++;
981 ct = getset(name);
982 if (ct == NULL) {
983 c = GETTOGGLE(name);
984 if (c == NULL) {
985 fprintf(stderr, "'%s': unknown argument ('unset ?' for help).\n",
986 name);
987 return 0;
988 } else if (Ambiguous((void *)c)) {
989 fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n",
990 name);
991 return 0;
993 if (c->variable) {
994 *c->variable = 0;
995 if (c->actionexplanation) {
996 printf("%s %s.\n", *c->variable? "Will" : "Won't",
997 c->actionexplanation);
1000 if (c->handler)
1001 (*c->handler)(0);
1002 } else if (Ambiguous((void *)ct)) {
1003 fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n",
1004 name);
1005 return 0;
1006 } else if (ct->handler) {
1007 (*ct->handler)(0);
1008 printf("%s reset to \"%s\".\n", ct->name, (char *)ct->charp);
1009 } else {
1010 *(ct->charp) = _POSIX_VDISABLE;
1011 printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
1014 return 1;
1018 * The following are the data structures and routines for the
1019 * 'mode' command.
1021 #ifdef KLUDGELINEMODE
1022 extern int kludgelinemode;
1024 static int
1025 dokludgemode(void)
1027 kludgelinemode = 1;
1028 send_wont(TELOPT_LINEMODE, 1);
1029 send_dont(TELOPT_SGA, 1);
1030 send_dont(TELOPT_ECHO, 1);
1031 return 1;
1033 #endif
1035 static int
1036 dolinemode(void)
1038 #ifdef KLUDGELINEMODE
1039 if (kludgelinemode)
1040 send_dont(TELOPT_SGA, 1);
1041 #endif
1042 send_will(TELOPT_LINEMODE, 1);
1043 send_dont(TELOPT_ECHO, 1);
1044 return 1;
1047 static int
1048 docharmode(void)
1050 #ifdef KLUDGELINEMODE
1051 if (kludgelinemode)
1052 send_do(TELOPT_SGA, 1);
1053 else
1054 #endif
1055 send_wont(TELOPT_LINEMODE, 1);
1056 send_do(TELOPT_ECHO, 1);
1057 return 1;
1060 static int
1061 dolmmode(int bit, int on)
1063 unsigned char c;
1064 extern int linemode;
1066 if (my_want_state_is_wont(TELOPT_LINEMODE)) {
1067 printf("?Need to have LINEMODE option enabled first.\n");
1068 printf("'mode ?' for help.\n");
1069 return 0;
1072 if (on)
1073 c = (linemode | bit);
1074 else
1075 c = (linemode & ~bit);
1076 lm_mode(&c, 1, 1);
1077 return 1;
1080 static int
1081 setmod(int bit)
1083 return dolmmode(bit, 1);
1086 static int
1087 clearmode(int bit)
1089 return dolmmode(bit, 0);
1092 struct modelist {
1093 const char *name; /* command name */
1094 const char *help; /* help string */
1095 int (*handler)(int);/* routine which executes command */
1096 int needconnect; /* Do we need to be connected to execute? */
1097 int arg1;
1100 static struct modelist ModeList[] = {
1101 { "character", "Disable LINEMODE option", (int (*)(int))docharmode, 1, 0 },
1102 #ifdef KLUDGELINEMODE
1103 { "", "(or disable obsolete line-by-line mode)", NULL, 0, 0 },
1104 #endif
1105 { "line", "Enable LINEMODE option", (int (*)(int))dolinemode, 1, 0 },
1106 #ifdef KLUDGELINEMODE
1107 { "", "(or enable obsolete line-by-line mode)", NULL, 0, 0 },
1108 #endif
1109 { "", "", NULL, 0, 0 },
1110 { "", "These require the LINEMODE option to be enabled", NULL, 0, 0 },
1111 { "isig", "Enable signal trapping", setmod, 1, MODE_TRAPSIG },
1112 { "+isig", 0, setmod, 1, MODE_TRAPSIG },
1113 { "-isig", "Disable signal trapping", clearmode, 1, MODE_TRAPSIG },
1114 { "edit", "Enable character editing", setmod, 1, MODE_EDIT },
1115 { "+edit", 0, setmod, 1, MODE_EDIT },
1116 { "-edit", "Disable character editing", clearmode, 1, MODE_EDIT },
1117 { "softtabs", "Enable tab expansion", setmod, 1, MODE_SOFT_TAB },
1118 { "+softtabs", 0, setmod, 1, MODE_SOFT_TAB },
1119 { "-softtabs", "Disable character editing", clearmode, 1, MODE_SOFT_TAB },
1120 { "litecho", "Enable literal character echo", setmod, 1, MODE_LIT_ECHO },
1121 { "+litecho", 0, setmod, 1, MODE_LIT_ECHO },
1122 { "-litecho", "Disable literal character echo", clearmode, 1, MODE_LIT_ECHO },
1123 { "help", 0, (int (*)(int))modehelp, 0, 0 },
1124 #ifdef KLUDGELINEMODE
1125 { "kludgeline", 0, (int (*)(int))dokludgemode, 1, 0 },
1126 #endif
1127 { "", "", NULL, 0, 0 },
1128 { "?", "Print help information", (int (*)(int))modehelp, 0, 0 },
1129 { NULL, NULL, NULL, 0, 0 },
1133 static int
1134 modehelp(void)
1136 struct modelist *mt;
1138 printf("format is: 'mode Mode', where 'Mode' is one of:\n\n");
1139 for (mt = ModeList; mt->name; mt++) {
1140 if (mt->help) {
1141 if (*mt->help)
1142 printf("%-15s %s\n", mt->name, mt->help);
1143 else
1144 printf("\n");
1147 return 0;
1150 #define GETMODECMD(name) (struct modelist *) \
1151 genget(name, (char **) ModeList, sizeof(struct modelist))
1153 static int
1154 modecmd(int argc, char *argv[])
1156 struct modelist *mt;
1158 if (argc != 2) {
1159 printf("'mode' command requires an argument\n");
1160 printf("'mode ?' for help.\n");
1161 } else if ((mt = GETMODECMD(argv[1])) == NULL) {
1162 fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]);
1163 } else if (Ambiguous((void *)mt)) {
1164 fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]);
1165 } else if (mt->needconnect && !connected) {
1166 printf("?Need to be connected first.\n");
1167 printf("'mode ?' for help.\n");
1168 } else if (mt->handler) {
1169 return (*mt->handler)(mt->arg1);
1171 return 0;
1175 * The following data structures and routines implement the
1176 * "display" command.
1179 static int
1180 display(int argc, char *argv[])
1182 struct togglelist *tl;
1183 struct setlist *sl;
1185 #define dotog(tl) if (tl->variable && tl->actionexplanation) { \
1186 if (*tl->variable) { \
1187 printf("will"); \
1188 } else { \
1189 printf("won't"); \
1191 printf(" %s.\n", tl->actionexplanation); \
1194 #define doset(sl) if (sl->name && *sl->name != ' ') { \
1195 if (sl->handler == 0) \
1196 printf("%-15s [%s]\n", sl->name, control(*sl->charp)); \
1197 else \
1198 printf("%-15s \"%s\"\n", sl->name, (char *)sl->charp); \
1201 if (argc == 1) {
1202 for (tl = Togglelist; tl->name; tl++) {
1203 dotog(tl);
1205 printf("\n");
1206 for (sl = Setlist; sl->name; sl++) {
1207 doset(sl);
1209 } else {
1210 int i;
1212 for (i = 1; i < argc; i++) {
1213 sl = getset(argv[i]);
1214 tl = GETTOGGLE(argv[i]);
1215 if (Ambiguous((void *)sl) || Ambiguous((void *)tl)) {
1216 printf("?Ambiguous argument '%s'.\n", argv[i]);
1217 return 0;
1218 } else if (!sl && !tl) {
1219 printf("?Unknown argument '%s'.\n", argv[i]);
1220 return 0;
1221 } else {
1222 if (tl) {
1223 dotog(tl);
1225 if (sl) {
1226 doset(sl);
1231 /*@*/optionstatus();
1232 #ifdef ENCRYPTION
1233 EncryptStatus();
1234 #endif /* ENCRYPTION */
1235 return 1;
1236 #undef doset
1237 #undef dotog
1241 * The following are the data structures, and many of the routines,
1242 * relating to command processing.
1246 * Set the escape character.
1248 static int
1249 setescape(int argc, char *argv[])
1251 char *arg;
1252 char buf[50];
1254 printf(
1255 "Deprecated usage - please use 'set escape%s%s' in the future.\n",
1256 (argc > 2)? " ":"", (argc > 2)? argv[1]: "");
1257 if (argc > 2)
1258 arg = argv[1];
1259 else {
1260 printf("new escape character: ");
1261 (void) fgets(buf, sizeof(buf), stdin);
1262 arg = buf;
1264 if (arg[0] != '\0')
1265 escape = arg[0];
1266 (void) fflush(stdout);
1267 return 1;
1270 static int
1271 togcrmod(void)
1273 crmod = !crmod;
1274 printf("Deprecated usage - please use 'toggle crmod' in the future.\n");
1275 printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't");
1276 (void) fflush(stdout);
1277 return 1;
1280 static int
1281 suspend(void)
1283 #ifdef SIGTSTP
1284 setcommandmode();
1286 long oldrows, oldcols, newrows, newcols, err_;
1288 err_ = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0;
1289 (void) kill(0, SIGTSTP);
1291 * If we didn't get the window size before the SUSPEND, but we
1292 * can get them now (?), then send the NAWS to make sure that
1293 * we are set up for the right window size.
1295 if (TerminalWindowSize(&newrows, &newcols) && connected &&
1296 (err_ || ((oldrows != newrows) || (oldcols != newcols)))) {
1297 sendnaws();
1300 /* reget parameters in case they were changed */
1301 TerminalSaveState();
1302 setconnmode(0);
1303 #else
1304 printf("Suspend is not supported. Try the '!' command instead\n");
1305 #endif
1306 return 1;
1309 static int
1310 shell(int argc, char *argv[] __unused)
1312 long oldrows, oldcols, newrows, newcols, err_;
1314 setcommandmode();
1316 err_ = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0;
1317 switch(vfork()) {
1318 case -1:
1319 perror("Fork failed\n");
1320 break;
1322 case 0:
1325 * Fire up the shell in the child.
1327 const char *shellp, *shellname;
1329 shellp = getenv("SHELL");
1330 if (shellp == NULL)
1331 shellp = "/bin/sh";
1332 if ((shellname = strrchr(shellp, '/')) == NULL)
1333 shellname = shellp;
1334 else
1335 shellname++;
1336 if (argc > 1)
1337 execl(shellp, shellname, "-c", &saveline[1], NULL);
1338 else
1339 execl(shellp, shellname, NULL);
1340 perror("Execl");
1341 _exit(1);
1343 default:
1344 (void)wait(NULL); /* Wait for the shell to complete */
1346 if (TerminalWindowSize(&newrows, &newcols) && connected &&
1347 (err_ || ((oldrows != newrows) || (oldcols != newcols)))) {
1348 sendnaws();
1350 break;
1352 return 1;
1355 static int
1356 bye(int argc, char *argv[])
1358 extern int resettermname;
1360 if (connected) {
1361 (void) shutdown(net, SHUT_RDWR);
1362 printf("Connection closed.\n");
1363 (void) NetClose(net);
1364 connected = 0;
1365 resettermname = 1;
1366 #ifdef AUTHENTICATION
1367 #ifdef ENCRYPTION
1368 auth_encrypt_connect(connected);
1369 #endif
1370 #endif
1371 /* reset options */
1372 tninit();
1374 if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) {
1375 longjmp(toplevel, 1);
1376 /* NOTREACHED */
1378 return 1; /* Keep lint, etc., happy */
1381 void
1382 quit(void)
1384 (void) call(bye, "bye", "fromquit", 0);
1385 Exit(0);
1388 static int
1389 logout(void)
1391 send_do(TELOPT_LOGOUT, 1);
1392 (void) netflush();
1393 return 1;
1398 * The SLC command.
1401 struct slclist {
1402 const char *name;
1403 const char *help;
1404 void (*handler)(int);
1405 int arg;
1408 static void slc_help(void);
1410 struct slclist SlcList[] = {
1411 { "export", "Use local special character definitions",
1412 (void (*)(int))slc_mode_export, 0 },
1413 { "import", "Use remote special character definitions",
1414 slc_mode_import, 1 },
1415 { "check", "Verify remote special character definitions",
1416 slc_mode_import, 0 },
1417 { "help", NULL, (void (*)(int))slc_help, 0 },
1418 { "?", "Print help information", (void (*)(int))slc_help, 0 },
1419 { NULL, NULL, NULL, 0 },
1422 static void
1423 slc_help(void)
1425 struct slclist *c;
1427 for (c = SlcList; c->name; c++) {
1428 if (c->help) {
1429 if (*c->help)
1430 printf("%-15s %s\n", c->name, c->help);
1431 else
1432 printf("\n");
1437 static struct slclist *
1438 getslc(char *name)
1440 return (struct slclist *)
1441 genget(name, (char **) SlcList, sizeof(struct slclist));
1444 static int
1445 slccmd(int argc, char *argv[])
1447 struct slclist *c;
1449 if (argc != 2) {
1450 fprintf(stderr,
1451 "Need an argument to 'slc' command. 'slc ?' for help.\n");
1452 return 0;
1454 c = getslc(argv[1]);
1455 if (c == NULL) {
1456 fprintf(stderr, "'%s': unknown argument ('slc ?' for help).\n",
1457 argv[1]);
1458 return 0;
1460 if (Ambiguous((void *)c)) {
1461 fprintf(stderr, "'%s': ambiguous argument ('slc ?' for help).\n",
1462 argv[1]);
1463 return 0;
1465 (*c->handler)(c->arg);
1466 slcstate();
1467 return 1;
1471 * The ENVIRON command.
1474 struct envlist {
1475 const char *name;
1476 const char *help;
1477 void (*handler)(unsigned char *, unsigned char *);
1478 int narg;
1481 extern struct env_lst *
1482 env_define(const unsigned char *, unsigned char *);
1483 extern void
1484 env_undefine(const unsigned char *),
1485 env_export(const unsigned char *),
1486 env_unexport(const unsigned char *),
1487 env_send(const unsigned char *),
1488 #if defined(OLD_ENVIRON) && defined(ENV_HACK)
1489 env_varval(const unsigned char *),
1490 #endif
1491 env_list(void);
1492 static void
1493 env_help(void);
1495 struct envlist EnvList[] = {
1496 { "define", "Define an environment variable",
1497 (void (*)(unsigned char *, unsigned char *))env_define, 2 },
1498 { "undefine", "Undefine an environment variable",
1499 (void (*)(unsigned char *, unsigned char *))env_undefine, 1 },
1500 { "export", "Mark an environment variable for automatic export",
1501 (void (*)(unsigned char *, unsigned char *))env_export, 1 },
1502 { "unexport", "Don't mark an environment variable for automatic export",
1503 (void (*)(unsigned char *, unsigned char *))env_unexport, 1 },
1504 { "send", "Send an environment variable", (void (*)(unsigned char *, unsigned char *))env_send, 1 },
1505 { "list", "List the current environment variables",
1506 (void (*)(unsigned char *, unsigned char *))env_list, 0 },
1507 #if defined(OLD_ENVIRON) && defined(ENV_HACK)
1508 { "varval", "Reverse VAR and VALUE (auto, right, wrong, status)",
1509 (void (*)(unsigned char *, unsigned char *))env_varval, 1 },
1510 #endif
1511 { "help", NULL, (void (*)(unsigned char *, unsigned char *))env_help, 0 },
1512 { "?", "Print help information", (void (*)(unsigned char *, unsigned char *))env_help, 0 },
1513 { NULL, NULL, NULL, 0 },
1516 static void
1517 env_help(void)
1519 struct envlist *c;
1521 for (c = EnvList; c->name; c++) {
1522 if (c->help) {
1523 if (*c->help)
1524 printf("%-15s %s\n", c->name, c->help);
1525 else
1526 printf("\n");
1531 static struct envlist *
1532 getenvcmd(char *name)
1534 return (struct envlist *)
1535 genget(name, (char **) EnvList, sizeof(struct envlist));
1538 static int
1539 env_cmd(int argc, char *argv[])
1541 struct envlist *c;
1543 if (argc < 2) {
1544 fprintf(stderr,
1545 "Need an argument to 'environ' command. 'environ ?' for help.\n");
1546 return 0;
1548 c = getenvcmd(argv[1]);
1549 if (c == NULL) {
1550 fprintf(stderr, "'%s': unknown argument ('environ ?' for help).\n",
1551 argv[1]);
1552 return 0;
1554 if (Ambiguous((void *)c)) {
1555 fprintf(stderr, "'%s': ambiguous argument ('environ ?' for help).\n",
1556 argv[1]);
1557 return 0;
1559 if (c->narg + 2 != argc) {
1560 fprintf(stderr,
1561 "Need %s%d argument%s to 'environ %s' command. 'environ ?' for help.\n",
1562 c->narg < argc + 2 ? "only " : "",
1563 c->narg, c->narg == 1 ? "" : "s", c->name);
1564 return 0;
1566 (*c->handler)(argv[2], argv[3]);
1567 return 1;
1570 struct env_lst {
1571 struct env_lst *next; /* pointer to next structure */
1572 struct env_lst *prev; /* pointer to previous structure */
1573 unsigned char *var; /* pointer to variable name */
1574 unsigned char *value; /* pointer to variable value */
1575 int export; /* 1 -> export with default list of variables */
1576 int welldefined; /* A well defined variable */
1579 struct env_lst envlisthead;
1581 static struct env_lst *
1582 env_find(const unsigned char *var)
1584 struct env_lst *ep;
1586 for (ep = envlisthead.next; ep; ep = ep->next) {
1587 if (strcmp(ep->var, var) == 0)
1588 return(ep);
1590 return(NULL);
1593 void
1594 env_init(void)
1596 extern char **environ;
1597 char **epp, *cp;
1598 struct env_lst *ep;
1600 for (epp = environ; *epp; epp++) {
1601 if ((cp = strchr(*epp, '='))) {
1602 *cp = '\0';
1603 ep = env_define((unsigned char *)*epp,
1604 (unsigned char *)cp+1);
1605 ep->export = 0;
1606 *cp = '=';
1610 * Special case for DISPLAY variable. If it is ":0.0" or
1611 * "unix:0.0", we have to get rid of "unix" and insert our
1612 * hostname.
1614 if ((ep = env_find("DISPLAY"))
1615 && ((*ep->value == ':')
1616 || (strncmp((char *)ep->value, "unix:", 5) == 0))) {
1617 char hbuf[256+1];
1618 char *cp2 = strchr((char *)ep->value, ':');
1619 size_t buflen;
1621 gethostname(hbuf, sizeof(hbuf));
1622 hbuf[sizeof(hbuf)-1] = '\0';
1623 buflen = strlen(hbuf) + strlen(cp2) + 1;
1624 cp = (char *)malloc(sizeof(char)*buflen);
1625 assert(cp != NULL);
1626 snprintf((char *)cp, buflen, "%s%s", hbuf, cp2);
1627 free(ep->value);
1628 ep->value = (unsigned char *)cp;
1631 * If USER is not defined, but LOGNAME is, then add
1632 * USER with the value from LOGNAME. By default, we
1633 * don't export the USER variable.
1635 if ((env_find("USER") == NULL) && (ep = env_find("LOGNAME"))) {
1636 env_define("USER", ep->value);
1637 env_unexport("USER");
1639 env_export("DISPLAY");
1640 env_export("PRINTER");
1643 struct env_lst *
1644 env_define(const unsigned char *var, unsigned char *value)
1646 struct env_lst *ep;
1648 if ((ep = env_find(var))) {
1649 if (ep->var)
1650 free(ep->var);
1651 if (ep->value)
1652 free(ep->value);
1653 } else {
1654 ep = (struct env_lst *)malloc(sizeof(struct env_lst));
1655 ep->next = envlisthead.next;
1656 envlisthead.next = ep;
1657 ep->prev = &envlisthead;
1658 if (ep->next)
1659 ep->next->prev = ep;
1661 ep->welldefined = opt_welldefined(var);
1662 ep->export = 1;
1663 ep->var = strdup(var);
1664 ep->value = strdup(value);
1665 return(ep);
1668 void
1669 env_undefine(const unsigned char *var)
1671 struct env_lst *ep;
1673 if ((ep = env_find(var))) {
1674 ep->prev->next = ep->next;
1675 if (ep->next)
1676 ep->next->prev = ep->prev;
1677 if (ep->var)
1678 free(ep->var);
1679 if (ep->value)
1680 free(ep->value);
1681 free(ep);
1685 void
1686 env_export(const unsigned char *var)
1688 struct env_lst *ep;
1690 if ((ep = env_find(var)))
1691 ep->export = 1;
1694 void
1695 env_unexport(const unsigned char *var)
1697 struct env_lst *ep;
1699 if ((ep = env_find(var)))
1700 ep->export = 0;
1703 void
1704 env_send(const unsigned char *var)
1706 struct env_lst *ep;
1708 if (my_state_is_wont(TELOPT_NEW_ENVIRON)
1709 #ifdef OLD_ENVIRON
1710 && my_state_is_wont(TELOPT_OLD_ENVIRON)
1711 #endif
1713 fprintf(stderr,
1714 "Cannot send '%s': Telnet ENVIRON option not enabled\n",
1715 var);
1716 return;
1718 ep = env_find(var);
1719 if (ep == NULL) {
1720 fprintf(stderr, "Cannot send '%s': variable not defined\n",
1721 var);
1722 return;
1724 env_opt_start_info();
1725 env_opt_add(ep->var);
1726 env_opt_end(0);
1729 void
1730 env_list(void)
1732 struct env_lst *ep;
1734 for (ep = envlisthead.next; ep; ep = ep->next) {
1735 printf("%c %-20s %s\n", ep->export ? '*' : ' ',
1736 ep->var, ep->value);
1740 unsigned char *
1741 env_default(int init, int welldefined)
1743 static struct env_lst *nep = NULL;
1745 if (init) {
1746 nep = &envlisthead;
1747 return NULL;
1749 if (nep) {
1750 while ((nep = nep->next)) {
1751 if (nep->export && (nep->welldefined == welldefined))
1752 return(nep->var);
1755 return(NULL);
1758 unsigned char *
1759 env_getvalue(const unsigned char *var)
1761 struct env_lst *ep;
1763 if ((ep = env_find(var)))
1764 return(ep->value);
1765 return(NULL);
1768 #if defined(OLD_ENVIRON) && defined(ENV_HACK)
1769 void
1770 env_varval(const unsigned char *what)
1772 extern int old_env_var, old_env_value, env_auto;
1773 int len = strlen((char *)what);
1775 if (len == 0)
1776 goto unknown;
1778 if (strncasecmp((char *)what, "status", len) == 0) {
1779 if (env_auto)
1780 printf("%s%s", "VAR and VALUE are/will be ",
1781 "determined automatically\n");
1782 if (old_env_var == OLD_ENV_VAR)
1783 printf("VAR and VALUE set to correct definitions\n");
1784 else
1785 printf("VAR and VALUE definitions are reversed\n");
1786 } else if (strncasecmp((char *)what, "auto", len) == 0) {
1787 env_auto = 1;
1788 old_env_var = OLD_ENV_VALUE;
1789 old_env_value = OLD_ENV_VAR;
1790 } else if (strncasecmp((char *)what, "right", len) == 0) {
1791 env_auto = 0;
1792 old_env_var = OLD_ENV_VAR;
1793 old_env_value = OLD_ENV_VALUE;
1794 } else if (strncasecmp((char *)what, "wrong", len) == 0) {
1795 env_auto = 0;
1796 old_env_var = OLD_ENV_VALUE;
1797 old_env_value = OLD_ENV_VAR;
1798 } else {
1799 unknown:
1800 printf("Unknown \"varval\" command. (\"auto\", \"right\", \"wrong\", \"status\")\n");
1803 #endif
1805 #ifdef AUTHENTICATION
1807 * The AUTHENTICATE command.
1810 struct authlist {
1811 const char *name;
1812 const char *help;
1813 int (*handler)(char *);
1814 int narg;
1817 extern int
1818 auth_enable(char *),
1819 auth_disable(char *),
1820 auth_status(void);
1821 static int
1822 auth_help(void);
1824 struct authlist AuthList[] = {
1825 { "status", "Display current status of authentication information",
1826 (int (*)(char *))auth_status, 0 },
1827 { "disable", "Disable an authentication type ('auth disable ?' for more)",
1828 auth_disable, 1 },
1829 { "enable", "Enable an authentication type ('auth enable ?' for more)",
1830 auth_enable, 1 },
1831 { "help", NULL, (int (*)(char *))auth_help, 0 },
1832 { "?", "Print help information", (int (*)(char *))auth_help, 0 },
1833 { NULL, NULL, NULL, 0 },
1836 static int
1837 auth_help(void)
1839 struct authlist *c;
1841 for (c = AuthList; c->name; c++) {
1842 if (c->help) {
1843 if (*c->help)
1844 printf("%-15s %s\n", c->name, c->help);
1845 else
1846 printf("\n");
1849 return 0;
1853 auth_cmd(int argc, char *argv[])
1855 struct authlist *c;
1857 if (argc < 2) {
1858 fprintf(stderr,
1859 "Need an argument to 'auth' command. 'auth ?' for help.\n");
1860 return 0;
1863 c = (struct authlist *)
1864 genget(argv[1], (char **) AuthList, sizeof(struct authlist));
1865 if (c == NULL) {
1866 fprintf(stderr, "'%s': unknown argument ('auth ?' for help).\n",
1867 argv[1]);
1868 return 0;
1870 if (Ambiguous((void *)c)) {
1871 fprintf(stderr, "'%s': ambiguous argument ('auth ?' for help).\n",
1872 argv[1]);
1873 return 0;
1875 if (c->narg + 2 != argc) {
1876 fprintf(stderr,
1877 "Need %s%d argument%s to 'auth %s' command. 'auth ?' for help.\n",
1878 c->narg < argc + 2 ? "only " : "",
1879 c->narg, c->narg == 1 ? "" : "s", c->name);
1880 return 0;
1882 return((*c->handler)(argv[2]));
1884 #endif
1886 #ifdef ENCRYPTION
1888 * The ENCRYPT command.
1891 struct encryptlist {
1892 const char *name;
1893 const char *help;
1894 int (*handler)(char *, char *);
1895 int needconnect;
1896 int minarg;
1897 int maxarg;
1900 extern int
1901 EncryptEnable(char *, char *),
1902 EncryptDisable(char *, char *),
1903 EncryptType(char *, char *),
1904 EncryptStart(char *),
1905 EncryptStartInput(void),
1906 EncryptStartOutput(void),
1907 EncryptStop(char *),
1908 EncryptStopInput(void),
1909 EncryptStopOutput(void),
1910 EncryptStatus(void);
1911 static int
1912 EncryptHelp(void);
1914 struct encryptlist EncryptList[] = {
1915 { "enable", "Enable encryption. ('encrypt enable ?' for more)",
1916 EncryptEnable, 1, 1, 2 },
1917 { "disable", "Disable encryption. ('encrypt enable ?' for more)",
1918 EncryptDisable, 0, 1, 2 },
1919 { "type", "Set encryption type. ('encrypt type ?' for more)",
1920 EncryptType, 0, 1, 1 },
1921 { "start", "Start encryption. ('encrypt start ?' for more)",
1922 (int (*)(char *, char *))EncryptStart, 1, 0, 1 },
1923 { "stop", "Stop encryption. ('encrypt stop ?' for more)",
1924 (int (*)(char *, char *))EncryptStop, 1, 0, 1 },
1925 { "input", "Start encrypting the input stream",
1926 (int (*)(char *, char *))EncryptStartInput, 1, 0, 0 },
1927 { "-input", "Stop encrypting the input stream",
1928 (int (*)(char *, char *))EncryptStopInput, 1, 0, 0 },
1929 { "output", "Start encrypting the output stream",
1930 (int (*)(char *, char *))EncryptStartOutput, 1, 0, 0 },
1931 { "-output", "Stop encrypting the output stream",
1932 (int (*)(char *, char *))EncryptStopOutput, 1, 0, 0 },
1934 { "status", "Display current status of authentication information",
1935 (int (*)(char *, char *))EncryptStatus, 0, 0, 0 },
1936 { "help", NULL, (int (*)(char *, char *))EncryptHelp, 0, 0, 0 },
1937 { "?", "Print help information", (int (*)(char *, char *))EncryptHelp, 0, 0, 0 },
1938 { NULL, NULL, NULL, 0, 0, 0 },
1941 static int
1942 EncryptHelp(void)
1944 struct encryptlist *c;
1946 for (c = EncryptList; c->name; c++) {
1947 if (c->help) {
1948 if (*c->help)
1949 printf("%-15s %s\n", c->name, c->help);
1950 else
1951 printf("\n");
1954 return 0;
1957 static int
1958 encrypt_cmd(int argc, char *argv[])
1960 struct encryptlist *c;
1962 if (argc < 2) {
1963 fprintf(stderr,
1964 "Need an argument to 'encrypt' command. 'encrypt ?' for help.\n");
1965 return 0;
1968 c = (struct encryptlist *)
1969 genget(argv[1], (char **) EncryptList, sizeof(struct encryptlist));
1970 if (c == NULL) {
1971 fprintf(stderr, "'%s': unknown argument ('encrypt ?' for help).\n",
1972 argv[1]);
1973 return 0;
1975 if (Ambiguous((void *)c)) {
1976 fprintf(stderr, "'%s': ambiguous argument ('encrypt ?' for help).\n",
1977 argv[1]);
1978 return 0;
1980 argc -= 2;
1981 if (argc < c->minarg || argc > c->maxarg) {
1982 if (c->minarg == c->maxarg) {
1983 fprintf(stderr, "Need %s%d argument%s ",
1984 c->minarg < argc ? "only " : "", c->minarg,
1985 c->minarg == 1 ? "" : "s");
1986 } else {
1987 fprintf(stderr, "Need %s%d-%d arguments ",
1988 c->maxarg < argc ? "only " : "", c->minarg, c->maxarg);
1990 fprintf(stderr, "to 'encrypt %s' command. 'encrypt ?' for help.\n",
1991 c->name);
1992 return 0;
1994 if (c->needconnect && !connected) {
1995 if (!(argc && (isprefix(argv[2], "help") || isprefix(argv[2], "?")))) {
1996 printf("?Need to be connected first.\n");
1997 return 0;
2000 return ((*c->handler)(argc > 0 ? argv[2] : 0,
2001 argc > 1 ? argv[3] : 0));
2003 #endif /* ENCRYPTION */
2006 * Print status about the connection.
2008 /*ARGSUSED*/
2009 static int
2010 status(int argc, char *argv[])
2012 if (connected) {
2013 printf("Connected to %s.\n", hostname);
2014 if ((argc < 2) || strcmp(argv[1], "notmuch")) {
2015 int mode = getconnmode();
2017 if (my_want_state_is_will(TELOPT_LINEMODE)) {
2018 printf("Operating with LINEMODE option\n");
2019 printf("%s line editing\n", (mode&MODE_EDIT) ? "Local" : "No");
2020 printf("%s catching of signals\n",
2021 (mode&MODE_TRAPSIG) ? "Local" : "No");
2022 slcstate();
2023 #ifdef KLUDGELINEMODE
2024 } else if (kludgelinemode && my_want_state_is_dont(TELOPT_SGA)) {
2025 printf("Operating in obsolete linemode\n");
2026 #endif
2027 } else {
2028 printf("Operating in single character mode\n");
2029 if (localchars)
2030 printf("Catching signals locally\n");
2032 printf("%s character echo\n", (mode&MODE_ECHO) ? "Local" : "Remote");
2033 if (my_want_state_is_will(TELOPT_LFLOW))
2034 printf("%s flow control\n", (mode&MODE_FLOW) ? "Local" : "No");
2035 #ifdef ENCRYPTION
2036 encrypt_display();
2037 #endif /* ENCRYPTION */
2039 } else {
2040 printf("No connection.\n");
2042 printf("Escape character is '%s'.\n", control(escape));
2043 (void) fflush(stdout);
2044 return 1;
2047 #ifdef SIGINFO
2049 * Function that gets called when SIGINFO is received.
2051 void
2052 ayt_status(void)
2054 (void) call(status, "status", "notmuch", 0);
2056 #endif
2058 static const char *
2059 sockaddr_ntop(struct sockaddr *sa)
2061 void *addr;
2062 static char addrbuf[INET6_ADDRSTRLEN];
2064 switch (sa->sa_family) {
2065 case AF_INET:
2066 addr = &((struct sockaddr_in *)sa)->sin_addr;
2067 break;
2068 case AF_UNIX:
2069 addr = &((struct sockaddr_un *)sa)->sun_path;
2070 break;
2071 #ifdef INET6
2072 case AF_INET6:
2073 addr = &((struct sockaddr_in6 *)sa)->sin6_addr;
2074 break;
2075 #endif
2076 default:
2077 return NULL;
2079 inet_ntop(sa->sa_family, addr, addrbuf, sizeof(addrbuf));
2080 return addrbuf;
2083 #ifdef INET6
2085 * When an Address Family related error happend, check if retry with
2086 * another AF is possible or not.
2087 * Return 1, if retry with another af is OK. Else, return 0.
2089 static int
2090 switch_af(struct addrinfo **aip)
2092 int nextaf;
2093 struct addrinfo *ai;
2095 ai = *aip;
2096 nextaf = (ai->ai_family == AF_INET) ? AF_INET6 : AF_INET;
2098 ai=ai->ai_next;
2099 while (ai != NULL && ai->ai_family != nextaf);
2100 *aip = ai;
2101 if (*aip != NULL) {
2102 return 1;
2104 return 0;
2106 #endif
2109 tn(int argc, char *argv[])
2111 char *srp = NULL;
2112 int proto, opt;
2113 int srlen;
2114 int srcroute = 0, result;
2115 char *cmd, *hostp = NULL, *portp = NULL, *user = NULL;
2116 char *src_addr = NULL;
2117 struct addrinfo hints, *res, *res0 = NULL, *src_res, *src_res0 = NULL;
2118 int error = 0, af_error = 0;
2120 if (connected) {
2121 printf("?Already connected to %s\n", hostname);
2122 setuid(getuid());
2123 return 0;
2125 if (argc < 2) {
2126 (void) strlcpy(line, "open ", sizeof(line));
2127 printf("(to) ");
2128 (void) fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin);
2129 makeargv();
2130 argc = margc;
2131 argv = margv;
2133 cmd = *argv;
2134 --argc; ++argv;
2135 while (argc) {
2136 if (strcmp(*argv, "help") == 0 || isprefix(*argv, "?"))
2137 goto usage;
2138 if (strcmp(*argv, "-l") == 0) {
2139 --argc; ++argv;
2140 if (argc == 0)
2141 goto usage;
2142 user = *argv++;
2143 --argc;
2144 continue;
2146 if (strcmp(*argv, "-a") == 0) {
2147 --argc; ++argv;
2148 autologin = 1;
2149 continue;
2151 if (strcmp(*argv, "-s") == 0) {
2152 --argc; ++argv;
2153 if (argc == 0)
2154 goto usage;
2155 src_addr = *argv++;
2156 --argc;
2157 continue;
2159 if (hostp == NULL) {
2160 hostp = *argv++;
2161 --argc;
2162 continue;
2164 if (portp == NULL) {
2165 portp = *argv++;
2166 --argc;
2167 continue;
2169 usage:
2170 printf("usage: %s [-l user] [-a] [-s src_addr] host-name [port]\n", cmd);
2171 setuid(getuid());
2172 return 0;
2174 if (hostp == NULL)
2175 goto usage;
2177 if (src_addr != NULL) {
2178 memset(&hints, 0, sizeof(hints));
2179 hints.ai_flags = AI_NUMERICHOST;
2180 hints.ai_family = family;
2181 hints.ai_socktype = SOCK_STREAM;
2182 error = getaddrinfo(src_addr, 0, &hints, &src_res);
2183 if (error == EAI_NODATA) {
2184 hints.ai_flags = 0;
2185 error = getaddrinfo(src_addr, 0, &hints, &src_res);
2187 if (error != 0) {
2188 fprintf(stderr, "%s: %s\n", src_addr, gai_strerror(error));
2189 if (error == EAI_SYSTEM)
2190 fprintf(stderr, "%s: %s\n", src_addr, strerror(errno));
2191 setuid(getuid());
2192 return 0;
2194 src_res0 = src_res;
2196 if (hostp[0] == '/') {
2197 struct sockaddr_un su;
2199 if (strlen(hostp) >= sizeof(su.sun_path)) {
2200 fprintf(stderr, "hostname too long for unix domain socket: %s",
2201 hostp);
2202 goto fail;
2204 memset(&su, 0, sizeof su);
2205 su.sun_family = AF_UNIX;
2206 strncpy(su.sun_path, hostp, sizeof su.sun_path);
2207 printf("Trying %s...\n", hostp);
2208 net = socket(PF_UNIX, SOCK_STREAM, 0);
2209 if ( net < 0) {
2210 perror("socket");
2211 goto fail;
2213 if (connect(net, (struct sockaddr *)&su, sizeof su) == -1) {
2214 perror(su.sun_path);
2215 (void) NetClose(net);
2216 goto fail;
2218 goto af_unix;
2219 } else if (hostp[0] == '@' || hostp[0] == '!') {
2220 if (
2221 #ifdef INET6
2222 family == AF_INET6 ||
2223 #endif
2224 (hostname = strrchr(hostp, ':')) == NULL)
2225 hostname = strrchr(hostp, '@');
2226 if (hostname == NULL) {
2227 hostname = hostp;
2228 } else {
2229 hostname++;
2230 srcroute = 1;
2232 } else
2233 hostname = hostp;
2234 if (!portp) {
2235 telnetport = 1;
2236 portp = strdup("telnet");
2237 } else if (*portp == '-') {
2238 portp++;
2239 telnetport = 1;
2240 } else
2241 telnetport = 0;
2243 memset(&hints, 0, sizeof(hints));
2244 hints.ai_flags = AI_NUMERICHOST;
2245 hints.ai_family = family;
2246 hints.ai_socktype = SOCK_STREAM;
2247 error = getaddrinfo(hostname, portp, &hints, &res);
2248 if (error) {
2249 hints.ai_flags = AI_CANONNAME;
2250 error = getaddrinfo(hostname, portp, &hints, &res);
2252 if (error != 0) {
2253 fprintf(stderr, "%s: %s\n", hostname, gai_strerror(error));
2254 if (error == EAI_SYSTEM)
2255 fprintf(stderr, "%s: %s\n", hostname, strerror(errno));
2256 setuid(getuid());
2257 goto fail;
2259 if (hints.ai_flags == AI_NUMERICHOST) {
2260 /* hostname has numeric */
2261 int gni_err = 1;
2263 if (doaddrlookup)
2264 gni_err = getnameinfo(res->ai_addr, res->ai_addr->sa_len,
2265 _hostname, sizeof(_hostname) - 1, NULL, 0,
2266 NI_NAMEREQD);
2267 if (gni_err != 0)
2268 (void) strncpy(_hostname, hostp, sizeof(_hostname) - 1);
2269 _hostname[sizeof(_hostname)-1] = '\0';
2270 hostname = _hostname;
2271 } else {
2272 /* hostname has FQDN */
2273 if (srcroute != 0)
2274 (void) strncpy(_hostname, hostname, sizeof(_hostname) - 1);
2275 else if (res->ai_canonname != NULL)
2276 strcpy(_hostname, res->ai_canonname);
2277 else
2278 (void) strncpy(_hostname, hostp, sizeof(_hostname) - 1);
2279 _hostname[sizeof(_hostname)-1] = '\0';
2280 hostname = _hostname;
2282 res0 = res;
2283 #ifdef INET6
2284 af_again:
2285 #endif
2286 if (srcroute != 0) {
2287 static char hostbuf[BUFSIZ];
2289 if (af_error == 0) { /* save intermediate hostnames for retry */
2290 strncpy(hostbuf, hostp, BUFSIZ - 1);
2291 hostbuf[BUFSIZ - 1] = '\0';
2292 } else
2293 hostp = hostbuf;
2294 srp = NULL;
2295 result = sourceroute(res, hostp, &srp, &srlen, &proto, &opt);
2296 if (result == 0) {
2297 #ifdef INET6
2298 if (family == AF_UNSPEC && af_error == 0 &&
2299 switch_af(&res) == 1) {
2300 af_error = 1;
2301 goto af_again;
2303 #endif
2304 setuid(getuid());
2305 goto fail;
2306 } else if (result == -1) {
2307 printf("Bad source route option: %s\n", hostp);
2308 setuid(getuid());
2309 goto fail;
2312 do {
2313 printf("Trying %s...\n", sockaddr_ntop(res->ai_addr));
2314 net = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
2315 setuid(getuid());
2316 if (net < 0) {
2317 #ifdef INET6
2318 if (family == AF_UNSPEC && af_error == 0 &&
2319 switch_af(&res) == 1) {
2320 af_error = 1;
2321 goto af_again;
2323 #endif
2324 perror("telnet: socket");
2325 goto fail;
2327 if (srp && setsockopt(net, proto, opt, (char *)srp, srlen) < 0)
2328 perror("setsockopt (source route)");
2329 #if defined(IPPROTO_IP) && defined(IP_TOS)
2330 if (res->ai_family == PF_INET) {
2331 # if defined(HAS_GETTOS)
2332 struct tosent *tp;
2333 if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
2334 tos = tp->t_tos;
2335 # endif
2336 if (tos < 0)
2337 tos = IPTOS_LOWDELAY;
2338 if (tos
2339 && (setsockopt(net, IPPROTO_IP, IP_TOS,
2340 (char *)&tos, sizeof(int)) < 0)
2341 && (errno != ENOPROTOOPT))
2342 perror("telnet: setsockopt (IP_TOS) (ignored)");
2344 #endif /* defined(IPPROTO_IP) && defined(IP_TOS) */
2346 if (telnet_debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) {
2347 perror("setsockopt (SO_DEBUG)");
2350 if (src_addr != NULL) {
2351 for (src_res = src_res0; src_res != NULL; src_res = src_res->ai_next)
2352 if (src_res->ai_family == res->ai_family)
2353 break;
2354 if (src_res == NULL)
2355 src_res = src_res0;
2356 if (bind(net, src_res->ai_addr, src_res->ai_addrlen) == -1) {
2357 #ifdef INET6
2358 if (family == AF_UNSPEC && af_error == 0 &&
2359 switch_af(&res) == 1) {
2360 af_error = 1;
2361 (void) NetClose(net);
2362 goto af_again;
2364 #endif
2365 perror("bind");
2366 (void) NetClose(net);
2367 goto fail;
2371 if (connect(net, res->ai_addr, res->ai_addrlen) < 0) {
2372 struct addrinfo *next;
2374 next = res->ai_next;
2375 /* If already an af failed, only try same af. */
2376 if (af_error != 0)
2377 while (next != NULL && next->ai_family != res->ai_family)
2378 next = next->ai_next;
2379 warn("connect to address %s", sockaddr_ntop(res->ai_addr));
2380 if (next != NULL) {
2381 res = next;
2382 (void) NetClose(net);
2383 continue;
2385 warnx("Unable to connect to remote host");
2386 (void) NetClose(net);
2387 goto fail;
2389 connected++;
2390 #ifdef AUTHENTICATION
2391 #ifdef ENCRYPTION
2392 auth_encrypt_connect(connected);
2393 #endif
2394 #endif
2395 } while (connected == 0);
2396 freeaddrinfo(res0);
2397 if (src_res0 != NULL)
2398 freeaddrinfo(src_res0);
2399 cmdrc(hostp, hostname);
2400 af_unix:
2401 if (autologin && user == NULL) {
2402 struct passwd *pw;
2404 user = getenv("USER");
2405 if (user == NULL ||
2406 ((pw = getpwnam(user)) && pw->pw_uid != getuid())) {
2407 if ((pw = getpwuid(getuid())))
2408 user = pw->pw_name;
2409 else
2410 user = NULL;
2413 if (user) {
2414 env_define("USER", user);
2415 env_export("USER");
2417 (void) call(status, "status", "notmuch", 0);
2418 if (setjmp(peerdied) == 0)
2419 telnet(user);
2420 (void) NetClose(net);
2421 ExitString("Connection closed by foreign host.\n",1);
2422 /*NOTREACHED*/
2423 fail:
2424 if (res0 != NULL)
2425 freeaddrinfo(res0);
2426 if (src_res0 != NULL)
2427 freeaddrinfo(src_res0);
2428 return 0;
2431 #define HELPINDENT (sizeof ("connect"))
2433 static char
2434 openhelp[] = "connect to a site",
2435 closehelp[] = "close current connection",
2436 logouthelp[] = "forcibly logout remote user and close the connection",
2437 quithelp[] = "exit telnet",
2438 statushelp[] = "print status information",
2439 helphelp[] = "print help information",
2440 sendhelp[] = "transmit special characters ('send ?' for more)",
2441 sethelp[] = "set operating parameters ('set ?' for more)",
2442 unsethelp[] = "unset operating parameters ('unset ?' for more)",
2443 togglestring[] ="toggle operating parameters ('toggle ?' for more)",
2444 slchelp[] = "change state of special characters ('slc ?' for more)",
2445 displayhelp[] = "display operating parameters",
2446 #ifdef AUTHENTICATION
2447 authhelp[] = "turn on (off) authentication ('auth ?' for more)",
2448 #endif
2449 #ifdef ENCRYPTION
2450 encrypthelp[] = "turn on (off) encryption ('encrypt ?' for more)",
2451 #endif /* ENCRYPTION */
2452 zhelp[] = "suspend telnet",
2453 shellhelp[] = "invoke a subshell",
2454 envhelp[] = "change environment variables ('environ ?' for more)",
2455 modestring[] = "try to enter line or character mode ('mode ?' for more)";
2457 static Command cmdtab[] = {
2458 { "close", closehelp, bye, 1 },
2459 { "logout", logouthelp, (int (*)(int, char **))logout, 1 },
2460 { "display", displayhelp, display, 0 },
2461 { "mode", modestring, modecmd, 0 },
2462 { "telnet", openhelp, tn, 0 },
2463 { "open", openhelp, tn, 0 },
2464 { "quit", quithelp, (int (*)(int, char **))quit, 0 },
2465 { "send", sendhelp, sendcmd, 0 },
2466 { "set", sethelp, setcmd, 0 },
2467 { "unset", unsethelp, unsetcmd, 0 },
2468 { "status", statushelp, status, 0 },
2469 { "toggle", togglestring, toggle, 0 },
2470 { "slc", slchelp, slccmd, 0 },
2471 #ifdef AUTHENTICATION
2472 { "auth", authhelp, auth_cmd, 0 },
2473 #endif
2474 #ifdef ENCRYPTION
2475 { "encrypt", encrypthelp, encrypt_cmd, 0 },
2476 #endif /* ENCRYPTION */
2477 { "z", zhelp, (int (*)(int, char **))suspend, 0 },
2478 { "!", shellhelp, shell, 1 },
2479 { "environ", envhelp, env_cmd, 0 },
2480 { "?", helphelp, help, 0 },
2481 { NULL, NULL, NULL, 0 }
2484 static char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead";
2485 static char escapehelp[] = "deprecated command -- use 'set escape' instead";
2487 static Command cmdtab2[] = {
2488 { "help", 0, help, 0 },
2489 { "escape", escapehelp, setescape, 0 },
2490 { "crmod", crmodhelp, (int (*)(int, char **))togcrmod, 0 },
2491 { NULL, NULL, NULL, 0 }
2496 * Call routine with argc, argv set from args (terminated by 0).
2499 static int
2500 call(intrtn_t routine, ...)
2502 va_list ap;
2503 char *args[100];
2504 int argno = 0;
2506 va_start(ap, routine);
2507 while ((args[argno++] = va_arg(ap, char *)) != NULL);
2508 va_end(ap);
2509 return (*routine)(argno-1, args);
2513 static Command *
2514 getcmd(char *name)
2516 Command *cm;
2518 if ((cm = (Command *) genget(name, (char **) cmdtab, sizeof(Command))))
2519 return cm;
2520 return (Command *) genget(name, (char **) cmdtab2, sizeof(Command));
2523 void
2524 command(int top, const char *tbuf, int cnt)
2526 Command *c;
2528 setcommandmode();
2529 if (!top) {
2530 putchar('\n');
2531 } else {
2532 (void) signal(SIGINT, SIG_DFL);
2533 (void) signal(SIGQUIT, SIG_DFL);
2535 for (;;) {
2536 if (rlogin == _POSIX_VDISABLE)
2537 printf("%s> ", prompt);
2538 if (tbuf) {
2539 char *cp;
2540 cp = line;
2541 while (cnt > 0 && (*cp++ = *tbuf++) != '\n')
2542 cnt--;
2543 tbuf = NULL;
2544 if (cp == line || *--cp != '\n' || cp == line)
2545 goto getline;
2546 *cp = '\0';
2547 if (rlogin == _POSIX_VDISABLE)
2548 printf("%s\n", line);
2549 } else {
2550 getline:
2551 if (rlogin != _POSIX_VDISABLE)
2552 printf("%s> ", prompt);
2553 if (fgets(line, sizeof(line), stdin) == NULL) {
2554 if (feof(stdin) || ferror(stdin)) {
2555 (void) quit();
2556 /*NOTREACHED*/
2558 break;
2561 if (line[0] == 0)
2562 break;
2563 makeargv();
2564 if (margv[0] == NULL) {
2565 break;
2567 c = getcmd(margv[0]);
2568 if (Ambiguous((void *)c)) {
2569 printf("?Ambiguous command\n");
2570 continue;
2572 if (c == NULL) {
2573 printf("?Invalid command\n");
2574 continue;
2576 if (c->needconnect && !connected) {
2577 printf("?Need to be connected first.\n");
2578 continue;
2580 if ((*c->handler)(margc, margv)) {
2581 break;
2584 if (!top) {
2585 if (!connected) {
2586 longjmp(toplevel, 1);
2587 /*NOTREACHED*/
2589 setconnmode(0);
2594 * Help command.
2596 static int
2597 help(int argc, char *argv[])
2599 Command *c;
2601 if (argc == 1) {
2602 printf("Commands may be abbreviated. Commands are:\n\n");
2603 for (c = cmdtab; c->name; c++)
2604 if (c->help) {
2605 printf("%-*s\t%s\n", (int)HELPINDENT, c->name,
2606 c->help);
2608 return 0;
2610 else while (--argc > 0) {
2611 char *arg;
2612 arg = *++argv;
2613 c = getcmd(arg);
2614 if (Ambiguous((void *)c))
2615 printf("?Ambiguous help command %s\n", arg);
2616 else if (c == NULL)
2617 printf("?Invalid help command %s\n", arg);
2618 else
2619 printf("%s\n", c->help);
2621 return 0;
2624 static char *rcname = NULL;
2625 static char rcbuf[128];
2627 static void
2628 cmdrc(const char *m1, const char *m2)
2630 Command *c;
2631 FILE *rcfile;
2632 int gotmachine = 0;
2633 int l1 = strlen(m1);
2634 int l2 = strlen(m2);
2635 char m1save[MAXHOSTNAMELEN + 1];
2636 char temp[sizeof(line)];
2638 if (skiprc)
2639 return;
2641 strlcpy(m1save, m1, sizeof(m1save));
2642 m1 = m1save;
2644 if (rcname == NULL) {
2645 rcname = getenv("HOME");
2646 if (rcname && (strlen(rcname) + 10) < sizeof(rcbuf))
2647 strcpy(rcbuf, rcname);
2648 else
2649 rcbuf[0] = '\0';
2650 strcat(rcbuf, "/.telnetrc");
2651 rcname = rcbuf;
2654 if ((rcfile = fopen(rcname, "r")) == NULL) {
2655 return;
2658 for (;;) {
2659 if (fgets(line, sizeof(line), rcfile) == NULL)
2660 break;
2661 if (line[0] == 0)
2662 break;
2663 if (line[0] == '#')
2664 continue;
2665 if (gotmachine) {
2666 if (!isspace(line[0]))
2667 gotmachine = 0;
2669 if (gotmachine == 0) {
2670 if (isspace(line[0]))
2671 continue;
2672 if (strncasecmp(line, m1, l1) == 0) {
2673 strncpy(temp, &line[l1], sizeof(line) - l1);
2674 strncpy(line, temp, sizeof(line) - l1);
2675 } else if (strncasecmp(line, m2, l2) == 0) {
2676 strncpy(temp, &line[l2], sizeof(line) - l2);
2677 strncpy(line, temp, sizeof(line) - l2);
2678 } else if (strncasecmp(line, "DEFAULT", 7) == 0) {
2679 strncpy(temp, &line[7], sizeof(line) - 7);
2680 strncpy(line, temp, sizeof(line) - 7);
2681 } else
2682 continue;
2683 if (line[0] != ' ' && line[0] != '\t' && line[0] != '\n')
2684 continue;
2685 gotmachine = 1;
2687 makeargv();
2688 if (margv[0] == NULL)
2689 continue;
2690 c = getcmd(margv[0]);
2691 if (Ambiguous((void *)c)) {
2692 printf("?Ambiguous command: %s\n", margv[0]);
2693 continue;
2695 if (c == NULL) {
2696 printf("?Invalid command: %s\n", margv[0]);
2697 continue;
2700 * This should never happen...
2702 if (c->needconnect && !connected) {
2703 printf("?Need to be connected first for %s.\n", margv[0]);
2704 continue;
2706 (*c->handler)(margc, margv);
2708 fclose(rcfile);
2712 * Source route is handed in as
2713 * [!]@hop1@hop2...[@|:]dst
2714 * If the leading ! is present, it is a
2715 * strict source route, otherwise it is
2716 * assmed to be a loose source route.
2718 * We fill in the source route option as
2719 * hop1,hop2,hop3...dest
2720 * and return a pointer to hop1, which will
2721 * be the address to connect() to.
2723 * Arguments:
2725 * res: ponter to addrinfo structure which contains sockaddr to
2726 * the host to connect to.
2728 * arg: pointer to route list to decipher
2730 * cpp: If *cpp is not equal to NULL, this is a
2731 * pointer to a pointer to a character array
2732 * that should be filled in with the option.
2734 * lenp: pointer to an integer that contains the
2735 * length of *cpp if *cpp != NULL.
2737 * protop: pointer to an integer that should be filled in with
2738 * appropriate protocol for setsockopt, as socket
2739 * protocol family.
2741 * optp: pointer to an integer that should be filled in with
2742 * appropriate option for setsockopt, as socket protocol
2743 * family.
2745 * Return values:
2747 * If the return value is 1, then all operations are
2748 * successful. If the
2749 * return value is -1, there was a syntax error in the
2750 * option, either unknown characters, or too many hosts.
2751 * If the return value is 0, one of the hostnames in the
2752 * path is unknown, and *cpp is set to point to the bad
2753 * hostname.
2755 * *cpp: If *cpp was equal to NULL, it will be filled
2756 * in with a pointer to our static area that has
2757 * the option filled in. This will be 32bit aligned.
2759 * *lenp: This will be filled in with how long the option
2760 * pointed to by *cpp is.
2762 * *protop: This will be filled in with appropriate protocol for
2763 * setsockopt, as socket protocol family.
2765 * *optp: This will be filled in with appropriate option for
2766 * setsockopt, as socket protocol family.
2768 static int
2769 sourceroute(struct addrinfo *ai, char *arg, char **cpp, int *lenp, int *protop, int *optp)
2771 static char buf[1024 + ALIGNBYTES]; /*XXX*/
2772 char *cp, *cp2, *lsrp, *ep;
2773 struct sockaddr_in *_sin;
2774 #ifdef INET6
2775 #ifdef COMPAT_RFC1883 /* XXX */
2776 struct cmsghdr *cmsg;
2777 #endif
2778 #endif
2779 struct addrinfo hints, *res;
2780 int error;
2781 char c;
2784 * Verify the arguments, and make sure we have
2785 * at least 7 bytes for the option.
2787 if (cpp == NULL || lenp == NULL)
2788 return -1;
2789 if (*cpp != NULL) {
2790 switch (res->ai_family) {
2791 case AF_INET:
2792 if (*lenp < 7)
2793 return -1;
2794 break;
2795 #ifdef INET6
2796 case AF_INET6:
2797 if (*lenp < (int)CMSG_SPACE(sizeof(struct ip6_rthdr) +
2798 sizeof(struct in6_addr)))
2799 return -1;
2800 break;
2801 #endif
2805 * Decide whether we have a buffer passed to us,
2806 * or if we need to use our own static buffer.
2808 if (*cpp) {
2809 lsrp = *cpp;
2810 ep = lsrp + *lenp;
2811 } else {
2812 *cpp = lsrp = (char *)ALIGN(buf);
2813 ep = lsrp + 1024;
2816 cp = arg;
2818 #ifdef INET6
2819 if (ai->ai_family == AF_INET6) {
2821 * RFC3542 has obsoleted IPV6_PKTOPTIONS socket option.
2823 #ifdef COMPAT_RFC1883 /* XXX */
2824 cmsg = NULL;
2825 if (*cp != '@')
2826 return -1;
2827 *protop = IPPROTO_IPV6;
2828 *optp = IPV6_PKTOPTIONS;
2829 #else
2830 return -1;
2831 #endif /* COMPAT_RFC1883 */
2832 } else
2833 #endif
2836 * Next, decide whether we have a loose source
2837 * route or a strict source route, and fill in
2838 * the begining of the option.
2840 if (*cp == '!') {
2841 cp++;
2842 *lsrp++ = IPOPT_SSRR;
2843 } else
2844 *lsrp++ = IPOPT_LSRR;
2846 if (*cp != '@')
2847 return -1;
2849 lsrp++; /* skip over length, we'll fill it in later */
2850 *lsrp++ = 4;
2851 *protop = IPPROTO_IP;
2852 *optp = IP_OPTIONS;
2855 cp++;
2856 memset(&hints, 0, sizeof(hints));
2857 hints.ai_family = ai->ai_family;
2858 hints.ai_socktype = SOCK_STREAM;
2859 for (c = 0;;) {
2860 if (
2861 #ifdef INET6
2862 ai->ai_family != AF_INET6 &&
2863 #endif
2864 c == ':')
2865 cp2 = NULL;
2866 else for (cp2 = cp; (c = *cp2); cp2++) {
2867 if (c == ',') {
2868 *cp2++ = '\0';
2869 if (*cp2 == '@')
2870 cp2++;
2871 } else if (c == '@') {
2872 *cp2++ = '\0';
2873 } else if (
2874 #ifdef INET6
2875 ai->ai_family != AF_INET6 &&
2876 #endif
2877 c == ':') {
2878 *cp2++ = '\0';
2879 } else
2880 continue;
2881 break;
2883 if (!c)
2884 cp2 = NULL;
2886 hints.ai_flags = AI_NUMERICHOST;
2887 error = getaddrinfo(cp, NULL, &hints, &res);
2888 if (error == EAI_NODATA) {
2889 hints.ai_flags = 0;
2890 error = getaddrinfo(cp, NULL, &hints, &res);
2892 if (error != 0) {
2893 fprintf(stderr, "%s: %s\n", cp, gai_strerror(error));
2894 if (error == EAI_SYSTEM)
2895 fprintf(stderr, "%s: %s\n", cp,
2896 strerror(errno));
2897 *cpp = cp;
2898 return(0);
2900 #ifdef INET6
2901 if (res->ai_family == AF_INET6) {
2902 return(0);
2903 } else
2904 #endif
2906 _sin = (struct sockaddr_in *)res->ai_addr;
2907 memcpy(lsrp, (char *)&_sin->sin_addr, 4);
2908 lsrp += 4;
2910 if (cp2)
2911 cp = cp2;
2912 else
2913 break;
2915 * Check to make sure there is space for next address
2917 #ifdef INET6
2918 #ifdef COMPAT_RFC1883 /* XXX */
2919 if (res->ai_family == AF_INET6) {
2920 if (((char *)CMSG_DATA(cmsg) +
2921 sizeof(struct ip6_rthdr)) > ep)
2922 return -1;
2923 } else
2924 #endif /* COMPAT_RFC1883 */
2925 #endif
2926 if (lsrp + 4 > ep)
2927 return -1;
2928 freeaddrinfo(res);
2930 #ifdef INET6
2931 if (res->ai_family == AF_INET6) {
2932 #ifdef COMPAT_RFC1883 /* XXX */
2933 *lenp = 0;
2934 #endif /* COMPAT_RFC1883 */
2935 } else
2936 #endif
2938 if ((*(*cpp+IPOPT_OLEN) = lsrp - *cpp) <= 7) {
2939 *cpp = NULL;
2940 *lenp = 0;
2941 return -1;
2943 *lsrp++ = IPOPT_NOP; /* 32 bit word align it */
2944 *lenp = lsrp - *cpp;
2946 freeaddrinfo(res);
2947 return 1;