1 /* $NetBSD: commands.c,v 1.68 2012/01/09 16:08:55 christos Exp $ */
4 * Copyright (C) 1997 and 1998 WIDE Project.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * Copyright (c) 1988, 1990, 1993
34 * The Regents of the University of California. All rights reserved.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 #include <sys/cdefs.h>
64 static char sccsid
[] = "@(#)commands.c 8.4 (Berkeley) 5/30/95";
66 __RCSID("$NetBSD: commands.c,v 1.68 2012/01/09 16:08:55 christos Exp $");
70 #include <sys/param.h>
73 #include <sys/socket.h>
74 #include <netinet/in.h>
75 #include <arpa/inet.h>
85 #include <arpa/telnet.h>
92 #include <libtelnet/misc.h>
94 #include <libtelnet/auth.h>
97 #include <libtelnet/encrypt.h>
100 #include <netinet/in_systm.h>
101 #include <netinet/ip.h>
104 #if defined(IPPROTO_IP) && defined(IP_TOS)
106 #endif /* defined(IPPROTO_IP) && defined(IP_TOS) */
109 static char _hostname
[MAXHOSTNAMELEN
];
112 const char *name
; /* command name */
113 const char *help
; /* help string (NULL for no help) */
114 int (*handler
) /* routine which executes command */
116 int needconnect
; /* Do we need to be connected to execute? */
119 static char line
[256];
120 static char saveline
[256];
122 static char *margv
[20];
124 static void makeargv(void);
125 static int special(char *);
126 static const char *control(cc_t
);
127 static int sendcmd(int, char **);
128 static int send_esc(char *);
129 static int send_docmd(char *);
130 static int send_dontcmd(char *);
131 static int send_willcmd(char *);
132 static int send_wontcmd(char *);
133 static int send_help(char *);
134 static int lclchars(int);
135 static int togdebug(int);
136 static int togcrlf(int);
137 static int togbinary(int);
138 static int togrbinary(int);
139 static int togxbinary(int);
140 static int togglehelp(int);
141 static void settogglehelp(int);
142 static int toggle(int, char *[]);
143 static struct setlist
*getset(char *);
144 static int setcmd(int, char *[]);
145 static int unsetcmd(int, char *[]);
146 static int dokludgemode(int);
147 static int dolinemode(int);
148 static int docharmode(int);
149 static int dolmmode(int, int );
150 static int modecmd(int, char *[]);
151 static int display(int, char *[]);
152 static int setescape(int, char *[]);
153 static int togcrmod(int, char *[]);
154 static int bye(int, char *[]);
155 static void slc_help(int);
156 static struct slclist
*getslc(char *);
157 static int slccmd(int, char *[]);
158 static struct env_lst
*env_help(const unsigned char *, unsigned char *);
159 static struct envlist
*getenvcmd(char *);
160 #ifdef AUTHENTICATION
161 static int auth_help(char *);
164 static void filestuff(int);
166 static int status(int, char *[]);
167 static const char *sockaddr_ntop (struct sockaddr
*);
168 typedef int (*intrtn_t
)(int, char **);
169 static int call(intrtn_t
, ...);
170 static Command
*getcmd(char *);
171 static int help(int, char *[]);
178 static char bang
[] = "!";
182 if (*cp
== '!') { /* Special case shell escape */
183 strlcpy(saveline
, line
, sizeof(saveline
)); /* save for shell command */
184 *argp
++ = bang
; /* No room in string to get this */
188 while ((c
= *cp
) != '\0') {
190 while (isspace((unsigned char)c
))
196 for (cp2
= cp
; c
!= '\0'; c
= *++cp
) {
204 if ((c
= *++cp
) == '\0')
206 } else if (c
== '"') {
209 } else if (c
== '\'') {
212 } else if (isspace((unsigned char)c
))
226 * Make a character string into a number.
228 * Todo: 1. Could take random integers (12, 0x12, 012, 0b1).
241 c
= b
| 0x40; /* DEL */
254 * Construct a control character sequence
255 * for a special character.
262 * The only way I could get the Sun 3.5 compiler
264 * if ((unsigned int)c >= 0x80)
265 * was to assign "c" to an unsigned int variable...
268 unsigned int uic
= (unsigned int)c
;
272 if (c
== (cc_t
)_POSIX_VDISABLE
) {
277 buf
[1] = ((c
>>6)&07) + '0';
278 buf
[2] = ((c
>>3)&07) + '0';
279 buf
[3] = (c
&07) + '0';
281 } else if (uic
>= 0x20) {
295 * The following are data structures and routines for
296 * the "send" command.
301 const char *name
; /* How user refers to it (case independent) */
302 const char *help
; /* Help information (0 ==> no help) */
303 int needconnect
; /* Need to be connected */
304 int narg
; /* Number of arguments */
305 int (*handler
) /* Routine to perform (for special ops) */
307 int nbyte
; /* Number of bytes to send this command */
308 int what
; /* Character to be sent (<0 ==> special) */
312 static struct sendlist Sendlist
[] = {
313 { "ao", "Send Telnet Abort output", 1, 0, 0, 2, AO
},
314 { "ayt", "Send Telnet 'Are You There'", 1, 0, 0, 2, AYT
},
315 { "brk", "Send Telnet Break", 1, 0, 0, 2, BREAK
},
316 { "break", 0, 1, 0, 0, 2, BREAK
},
317 { "ec", "Send Telnet Erase Character", 1, 0, 0, 2, EC
},
318 { "el", "Send Telnet Erase Line", 1, 0, 0, 2, EL
},
319 { "escape", "Send current escape character", 1, 0, send_esc
, 1, 0 },
320 { "ga", "Send Telnet 'Go Ahead' sequence", 1, 0, 0, 2, GA
},
321 { "ip", "Send Telnet Interrupt Process", 1, 0, 0, 2, IP
},
322 { "intp", 0, 1, 0, 0, 2, IP
},
323 { "interrupt", 0, 1, 0, 0, 2, IP
},
324 { "intr", 0, 1, 0, 0, 2, IP
},
325 { "nop", "Send Telnet 'No operation'", 1, 0, 0, 2, NOP
},
326 { "eor", "Send Telnet 'End of Record'", 1, 0, 0, 2, EOR
},
327 { "abort", "Send Telnet 'Abort Process'", 1, 0, 0, 2, ABORT
},
328 { "susp", "Send Telnet 'Suspend Process'", 1, 0, 0, 2, SUSP
},
329 { "eof", "Send Telnet End of File Character", 1, 0, 0, 2, xEOF
},
330 { "synch", "Perform Telnet 'Synch operation'", 1, 0, dosynch
, 2, 0 },
331 { "getstatus", "Send request for STATUS", 1, 0, get_status
, 6, 0 },
332 { "?", "Display send options", 0, 0, send_help
, 0, 0 },
333 { "help", 0, 0, 0, send_help
, 0, 0 },
334 { "do", 0, 0, 1, send_docmd
, 3, 0 },
335 { "dont", 0, 0, 1, send_dontcmd
, 3, 0 },
336 { "will", 0, 0, 1, send_willcmd
, 3, 0 },
337 { "wont", 0, 0, 1, send_wontcmd
, 3, 0 },
341 #define GETSEND(name) ((struct sendlist *) genget(name, (char **) Sendlist, \
342 sizeof(struct sendlist)))
345 sendcmd(int argc
, char **argv
)
347 int count
; /* how many bytes we are going to need to send */
349 struct sendlist
*s
; /* pointer to current command */
354 printf("need at least one argument for 'send' command\n");
355 printf("'send ?' for help\n");
359 * First, validate all the send arguments.
360 * In addition, we see how much space we are going to need, and
361 * whether or not we will be doing a "SYNCH" operation (which
362 * flushes the network queue).
365 for (i
= 1; i
< argc
; i
++) {
366 s
= GETSEND(argv
[i
]);
368 printf("Unknown send argument '%s'\n'send ?' for help.\n",
371 } else if (Ambiguous(s
)) {
372 printf("Ambiguous send argument '%s'\n'send ?' for help.\n",
376 if (i
+ s
->narg
>= argc
) {
378 "Need %d argument%s to 'send %s' command. 'send %s ?' for help.\n",
379 s
->narg
, s
->narg
== 1 ? "" : "s", s
->name
, s
->name
);
383 if (s
->handler
== send_help
) {
389 needconnect
+= s
->needconnect
;
391 if (!connected
&& needconnect
) {
392 printf("?Need to be connected first.\n");
393 printf("'send ?' for help\n");
396 /* Now, do we have enough room? */
397 if (NETROOM() < count
) {
398 printf("There is not enough room in the buffer TO the network\n");
399 printf("to process your request. Nothing will be done.\n");
400 printf("('send synch' will throw away most data in the network\n");
401 printf("buffer, if this might help.)\n");
404 /* OK, they are all OK, now go through again and actually send */
406 for (i
= 1; i
< argc
; i
++) {
407 if ((s
= GETSEND(argv
[i
])) == 0) {
408 fprintf(stderr
, "Telnet 'send' error - argument disappeared!\n");
409 (void) quit(0, NULL
);
414 success
+= (*s
->handler
)(argv
[i
+1]);
417 NET2ADD(IAC
, s
->what
);
418 printoption("SENT", IAC
, s
->what
);
421 return (count
== success
);
432 send_docmd(char *name
)
434 return(send_tncmd(send_do
, "do", name
));
438 send_dontcmd(char *name
)
440 return(send_tncmd(send_dont
, "dont", name
));
443 send_willcmd(char *name
)
445 return(send_tncmd(send_will
, "will", name
));
448 send_wontcmd(char *name
)
450 return(send_tncmd(send_wont
, "wont", name
));
454 send_tncmd(void (*func
)(int, int), const char *cmd
, char *name
)
459 if (isprefix(name
, "?")) {
462 printf("usage: send %s <value|option>\n", cmd
);
463 printf("\"value\" must be from 0 to 255\n");
464 printf("Valid options are:\n\t");
467 for (cpp
= telopts
; *cpp
; cpp
++) {
468 len
= strlen(*cpp
) + 3;
469 if (col
+ len
> 65) {
473 printf(" \"%s\"", *cpp
);
479 cpp
= (void *)genget(name
, __UNCONST(telopts
), sizeof(char *));
480 if (Ambiguous(cpp
)) {
481 fprintf(stderr
,"'%s': ambiguous argument ('send %s ?' for help).\n",
490 while (*cp
>= '0' && *cp
<= '9') {
496 fprintf(stderr
, "'%s': unknown argument ('send %s ?' for help).\n",
499 } else if (val
< 0 || val
> 255) {
500 fprintf(stderr
, "'%s': bad value ('send %s ?' for help).\n",
506 printf("?Need to be connected first.\n");
516 struct sendlist
*s
; /* pointer to current command */
517 for (s
= Sendlist
; s
->name
; s
++) {
519 printf("%-15s %s\n", s
->name
, s
->help
);
525 * The following are the routines and data structures referred
526 * to by the arguments to the "toggle" command.
540 (SetSockOpt(net
, SOL_SOCKET
, SO_DEBUG
, telnet_debug
)) < 0) {
541 perror("setsockopt (SO_DEBUG)");
550 printf("Will send carriage returns as telnet <CR><LF>.\n");
552 printf("Will send carriage returns as telnet <CR><NUL>.\n");
562 donebinarytoggle
= 1;
567 if (my_want_state_is_will(TELOPT_BINARY
) &&
568 my_want_state_is_do(TELOPT_BINARY
)) {
570 } else if (my_want_state_is_wont(TELOPT_BINARY
) &&
571 my_want_state_is_dont(TELOPT_BINARY
)) {
574 val
= binmode
? 0 : 1;
578 if (my_want_state_is_will(TELOPT_BINARY
) &&
579 my_want_state_is_do(TELOPT_BINARY
)) {
580 printf("Already operating in binary mode with remote host.\n");
582 printf("Negotiating binary mode with remote host.\n");
586 if (my_want_state_is_wont(TELOPT_BINARY
) &&
587 my_want_state_is_dont(TELOPT_BINARY
)) {
588 printf("Already in network ascii mode with remote host.\n");
590 printf("Negotiating network ascii mode with remote host.\n");
600 donebinarytoggle
= 1;
603 val
= my_want_state_is_do(TELOPT_BINARY
) ? 0 : 1;
606 if (my_want_state_is_do(TELOPT_BINARY
)) {
607 printf("Already receiving in binary mode.\n");
609 printf("Negotiating binary mode on input.\n");
613 if (my_want_state_is_dont(TELOPT_BINARY
)) {
614 printf("Already receiving in network ascii mode.\n");
616 printf("Negotiating network ascii mode on input.\n");
626 donebinarytoggle
= 1;
629 val
= my_want_state_is_will(TELOPT_BINARY
) ? 0 : 1;
632 if (my_want_state_is_will(TELOPT_BINARY
)) {
633 printf("Already transmitting in binary mode.\n");
635 printf("Negotiating binary mode on output.\n");
639 if (my_want_state_is_wont(TELOPT_BINARY
)) {
640 printf("Already transmitting in network ascii mode.\n");
642 printf("Negotiating network ascii mode on output.\n");
650 extern int EncryptAutoEnc(int);
651 extern int EncryptAutoDec(int);
652 extern int EncryptDebug(int);
653 extern int EncryptVerbose(int);
654 #endif /* ENCRYPTION */
657 const char *name
; /* name of toggle */
658 const char *help
; /* help message */
659 int (*handler
) /* routine to do actual setting */
662 const char *actionexplanation
;
665 static struct togglelist Togglelist
[] = {
667 "flushing of output when sending interrupt characters",
670 "flush output when sending interrupt characters" },
672 "automatic sending of interrupt characters in urgent mode",
675 "send interrupt characters in urgent mode" },
676 #ifdef AUTHENTICATION
678 "automatic sending of login and/or authentication info",
681 "send login name and/or authentication information" },
683 "Toggle authentication debugging",
686 "print authentication debugging information" },
690 "automatic encryption of data stream",
693 "automatically encrypt output" },
695 "automatic decryption of data stream",
698 "automatically decrypt input" },
700 "Toggle verbose encryption output",
703 "print verbose encryption output" },
705 "Toggle encryption debugging",
708 "print encryption debugging information" },
709 #endif /* ENCRYPTION */
711 "don't read ~/.telnetrc file",
714 "skip reading of ~/.telnetrc file" },
716 "sending and receiving of binary data",
721 "receiving of binary data",
726 "sending of binary data",
731 "sending carriage returns as telnet <CR><LF>",
736 "mapping of received carriage returns",
739 "map carriage return on output" },
741 "local recognition of certain control characters",
744 "recognize certain control characters" },
745 { " ", "", 0, NULL
, NULL
}, /* empty line */
748 "(debugging) toggle tracing of API transactions",
751 "trace API transactions" },
753 "(debugging) toggle printing of hexadecimal curses data",
756 "print hexadecimal representation of curses data" },
757 #endif /* defined(TN3270) */
762 "turn on socket level debugging" },
764 "printing of hexadecimal network data (debugging)",
767 "print hexadecimal representation of network traffic" },
769 "output of \"netdata\" to user readable format (debugging)",
772 "print user readable output for \"netdata\"" },
774 "viewing of options processing (debugging)",
777 "show option processing" },
779 "(debugging) toggle printing of hexadecimal terminal data",
782 "print hexadecimal representation of terminal traffic" },
785 togglehelp
, NULL
, NULL
},
788 togglehelp
, NULL
, NULL
},
795 struct togglelist
*c
;
797 for (c
= Togglelist
; c
->name
; c
++) {
800 printf("%-15s toggle %s\n", c
->name
, c
->help
);
806 printf("%-15s %s\n", "?", "display help information");
811 settogglehelp(int set
)
813 struct togglelist
*c
;
815 for (c
= Togglelist
; c
->name
; c
++) {
818 printf("%-15s %s %s\n", c
->name
, set
? "enable" : "disable",
826 #define GETTOGGLE(name) (struct togglelist *) \
827 genget(name, (char **) Togglelist, sizeof(struct togglelist))
830 toggle(int argc
, char *argv
[])
834 struct togglelist
*c
;
838 "Need an argument to 'toggle' command. 'toggle ?' for help.\n");
847 fprintf(stderr
, "'%s': ambiguous argument ('toggle ?' for help).\n",
851 fprintf(stderr
, "'%s': unknown argument ('toggle ?' for help).\n",
856 *c
->variable
= !*c
->variable
; /* invert it */
857 if (c
->actionexplanation
) {
858 printf("%s %s.\n", *c
->variable
? "Will" : "Won't",
859 c
->actionexplanation
);
863 retval
&= (*c
->handler
)(-1);
871 * The following perform the "set" command.
874 struct termios new_tc
= { .c_iflag
= 0 };
877 const char *name
; /* name */
878 const char *help
; /* help information */
879 void (*handler
)(char *);
880 cc_t
*charp
; /* where it is located at */
883 static struct setlist Setlist
[] = {
884 #ifdef KLUDGELINEMODE
885 { "echo", "character to toggle local echoing on/off", 0, &echoc
},
887 { "escape", "character to escape back to telnet command mode", 0, &escape
},
888 { "rlogin", "rlogin escape character", 0, &rlogin
},
889 { "tracefile", "file to write trace information to", SetNetTrace
, (cc_t
*)NetTraceFile
},
890 { " ", "", NULL
, NULL
},
891 { " ", "The following need 'localchars' to be toggled true", 0, 0 },
892 { "flushoutput", "character to cause an Abort Output", 0, termFlushCharp
},
893 { "interrupt", "character to cause an Interrupt Process", 0, termIntCharp
},
894 { "quit", "character to cause an Abort process", 0, termQuitCharp
},
895 { "eof", "character to cause an EOF ", 0, termEofCharp
},
896 { " ", "", NULL
, NULL
},
897 { " ", "The following are for local editing in linemode", 0, 0 },
898 { "erase", "character to use to erase a character", 0, termEraseCharp
},
899 { "kill", "character to use to erase a line", 0, termKillCharp
},
900 { "lnext", "character to use for literal next", 0, termLiteralNextCharp
},
901 { "susp", "character to cause a Suspend Process", 0, termSuspCharp
},
902 { "reprint", "character to use for line reprint", 0, termRprntCharp
},
903 { "worderase", "character to use to erase a word", 0, termWerasCharp
},
904 { "start", "character to use for XON", 0, termStartCharp
},
905 { "stop", "character to use for XOFF", 0, termStopCharp
},
906 { "forw1", "alternate end of line character", 0, termForw1Charp
},
907 { "forw2", "alternate end of line character", 0, termForw2Charp
},
908 { "ayt", "alternate AYT character", 0, termAytCharp
},
912 static struct setlist
*
915 return (struct setlist
*)
916 genget(name
, (char **) Setlist
, sizeof(struct setlist
));
920 set_escape_char(char *s
)
922 if (rlogin
!= _POSIX_VDISABLE
) {
923 rlogin
= (s
&& *s
) ? special(s
) : _POSIX_VDISABLE
;
924 printf("Telnet rlogin escape character is '%s'.\n",
927 escape
= (s
&& *s
) ? special(s
) : _POSIX_VDISABLE
;
928 printf("Telnet escape character is '%s'.\n", control(escape
));
933 setcmd(int argc
, char *argv
[])
937 struct togglelist
*c
;
939 if (argc
< 2 || argc
> 3) {
940 printf("Format is 'set Name Value'\n'set ?' for help.\n");
943 if ((argc
== 2) && (isprefix(argv
[1], "?") || isprefix(argv
[1], "help"))) {
944 for (ct
= Setlist
; ct
->name
; ct
++)
945 printf("%-15s %s\n", ct
->name
, ct
->help
);
948 printf("%-15s %s\n", "?", "display help information");
952 ct
= getset(argv
[1]);
954 c
= GETTOGGLE(argv
[1]);
956 fprintf(stderr
, "'%s': unknown argument ('set ?' for help).\n",
959 } else if (Ambiguous(c
)) {
960 fprintf(stderr
, "'%s': ambiguous argument ('set ?' for help).\n",
965 if ((argc
== 2) || (strcmp("on", argv
[2]) == 0))
967 else if (strcmp("off", argv
[2]) == 0)
970 printf("Format is 'set togglename [on|off]'\n'set ?' for help.\n");
973 if (c
->actionexplanation
) {
974 printf("%s %s.\n", *c
->variable
? "Will" : "Won't",
975 c
->actionexplanation
);
980 } else if (argc
!= 3) {
981 printf("Format is 'set Name Value'\n'set ?' for help.\n");
983 } else if (Ambiguous(ct
)) {
984 fprintf(stderr
, "'%s': ambiguous argument ('set ?' for help).\n",
987 } else if (ct
->handler
) {
988 (*ct
->handler
)(argv
[2]);
989 printf("%s set to \"%s\".\n", ct
->name
, (char *)ct
->charp
);
991 if (strcmp("off", argv
[2])) {
992 value
= special(argv
[2]);
994 value
= _POSIX_VDISABLE
;
996 *(ct
->charp
) = (cc_t
)value
;
997 printf("%s character is '%s'.\n", ct
->name
, control(*(ct
->charp
)));
1004 unsetcmd(int argc
, char *argv
[])
1007 struct togglelist
*c
;
1012 "Need an argument to 'unset' command. 'unset ?' for help.\n");
1015 if (isprefix(argv
[1], "?") || isprefix(argv
[1], "help")) {
1016 for (ct
= Setlist
; ct
->name
; ct
++)
1017 printf("%-15s %s\n", ct
->name
, ct
->help
);
1020 printf("%-15s %s\n", "?", "display help information");
1030 c
= GETTOGGLE(name
);
1032 fprintf(stderr
, "'%s': unknown argument ('unset ?' for help).\n",
1035 } else if (Ambiguous(c
)) {
1036 fprintf(stderr
, "'%s': ambiguous argument ('unset ?' for help).\n",
1042 if (c
->actionexplanation
) {
1043 printf("%s %s.\n", *c
->variable
? "Will" : "Won't",
1044 c
->actionexplanation
);
1049 } else if (Ambiguous(ct
)) {
1050 fprintf(stderr
, "'%s': ambiguous argument ('unset ?' for help).\n",
1053 } else if (ct
->handler
) {
1055 printf("%s reset to \"%s\".\n", ct
->name
, (char *)ct
->charp
);
1057 *(ct
->charp
) = _POSIX_VDISABLE
;
1058 printf("%s character is '%s'.\n", ct
->name
, control(*(ct
->charp
)));
1065 * The following are the data structures and routines for the
1068 #ifdef KLUDGELINEMODE
1069 extern int kludgelinemode
;
1075 send_wont(TELOPT_LINEMODE
, 1);
1076 send_dont(TELOPT_SGA
, 1);
1077 send_dont(TELOPT_ECHO
, 1);
1085 #ifdef KLUDGELINEMODE
1087 send_dont(TELOPT_SGA
, 1);
1089 send_will(TELOPT_LINEMODE
, 1);
1090 send_dont(TELOPT_ECHO
, 1);
1097 #ifdef KLUDGELINEMODE
1099 send_do(TELOPT_SGA
, 1);
1102 send_wont(TELOPT_LINEMODE
, 1);
1103 send_do(TELOPT_ECHO
, 1);
1108 dolmmode(int bit
, int on
)
1111 extern int linemode
;
1113 if (my_want_state_is_wont(TELOPT_LINEMODE
)) {
1114 printf("?Need to have LINEMODE option enabled first.\n");
1115 printf("'mode ?' for help.\n");
1120 c
= (linemode
| bit
);
1122 c
= (linemode
& ~bit
);
1130 return dolmmode(bit
, 1);
1136 return dolmmode(bit
, 0);
1140 const char *name
; /* command name */
1141 const char *help
; /* help string */
1142 int (*handler
) /* routine which executes command */
1144 int needconnect
; /* Do we need to be connected to execute? */
1148 static struct modelist ModeList
[] = {
1149 { "character", "Disable LINEMODE option", docharmode
, 1, 0 },
1150 #ifdef KLUDGELINEMODE
1151 { "", "(or disable obsolete line-by-line mode)", 0, 0, 0 },
1153 { "line", "Enable LINEMODE option", dolinemode
, 1, 0 },
1154 #ifdef KLUDGELINEMODE
1155 { "", "(or enable obsolete line-by-line mode)", 0, 0, 0 },
1157 { "", "", 0, 0, 0 },
1158 { "", "These require the LINEMODE option to be enabled", 0, 0, 0 },
1159 { "isig", "Enable signal trapping", set_mode
, 1, MODE_TRAPSIG
},
1160 { "+isig", 0, set_mode
, 1, MODE_TRAPSIG
},
1161 { "-isig", "Disable signal trapping", clear_mode
, 1, MODE_TRAPSIG
},
1162 { "edit", "Enable character editing", set_mode
, 1, MODE_EDIT
},
1163 { "+edit", 0, set_mode
, 1, MODE_EDIT
},
1164 { "-edit", "Disable character editing", clear_mode
, 1, MODE_EDIT
},
1165 { "softtabs", "Enable tab expansion", set_mode
, 1, MODE_SOFT_TAB
},
1166 { "+softtabs", 0, set_mode
, 1, MODE_SOFT_TAB
},
1167 { "-softtabs", "Disable character editing", clear_mode
, 1, MODE_SOFT_TAB
},
1168 { "litecho", "Enable literal character echo", set_mode
, 1, MODE_LIT_ECHO
},
1169 { "+litecho", 0, set_mode
, 1, MODE_LIT_ECHO
},
1170 { "-litecho", "Disable literal character echo", clear_mode
, 1, MODE_LIT_ECHO
},
1171 { "help", 0, modehelp
, 0, 0 },
1172 #ifdef KLUDGELINEMODE
1173 { "kludgeline", 0, dokludgemode
, 1, 0 },
1175 { "", "", 0, 0, 0 },
1176 { "?", "Print help information", modehelp
, 0, 0 },
1184 struct modelist
*mt
;
1186 printf("format is: 'mode Mode', where 'Mode' is one of:\n\n");
1187 for (mt
= ModeList
; mt
->name
; mt
++) {
1190 printf("%-15s %s\n", mt
->name
, mt
->help
);
1198 #define GETMODECMD(name) (struct modelist *) \
1199 genget(name, (char **) ModeList, sizeof(struct modelist))
1202 modecmd(int argc
, char *argv
[])
1204 struct modelist
*mt
;
1207 printf("'mode' command requires an argument\n");
1208 printf("'mode ?' for help.\n");
1209 } else if ((mt
= GETMODECMD(argv
[1])) == 0) {
1210 fprintf(stderr
, "Unknown mode '%s' ('mode ?' for help).\n", argv
[1]);
1211 } else if (Ambiguous(mt
)) {
1212 fprintf(stderr
, "Ambiguous mode '%s' ('mode ?' for help).\n", argv
[1]);
1213 } else if (mt
->needconnect
&& !connected
) {
1214 printf("?Need to be connected first.\n");
1215 printf("'mode ?' for help.\n");
1216 } else if (mt
->handler
) {
1217 return (*mt
->handler
)(mt
->arg1
);
1223 * The following data structures and routines implement the
1224 * "display" command.
1228 display(int argc
, char *argv
[])
1230 struct togglelist
*tl
;
1233 #define dotog(tl) if (tl->variable && tl->actionexplanation) { \
1234 if (*tl->variable) { \
1239 printf(" %s.\n", tl->actionexplanation); \
1242 #define doset(sl) if (sl->name && *sl->name != ' ') { \
1243 if (sl->handler == 0) \
1244 printf("%-15s [%s]\n", sl->name, control(*sl->charp)); \
1246 printf("%-15s \"%s\"\n", sl->name, (char *)sl->charp); \
1250 for (tl
= Togglelist
; tl
->name
; tl
++) {
1254 for (sl
= Setlist
; sl
->name
; sl
++) {
1260 for (i
= 1; i
< argc
; i
++) {
1261 sl
= getset(argv
[i
]);
1262 tl
= GETTOGGLE(argv
[i
]);
1263 if (Ambiguous(sl
) || Ambiguous(tl
)) {
1264 printf("?Ambiguous argument '%s'.\n", argv
[i
]);
1266 } else if (!sl
&& !tl
) {
1267 printf("?Unknown argument '%s'.\n", argv
[i
]);
1279 /*@*/optionstatus();
1282 #endif /* ENCRYPTION */
1289 * The following are the data structures, and many of the routines,
1290 * relating to command processing.
1294 * Set the escape character.
1297 setescape(int argc
, char *argv
[])
1303 "Deprecated usage - please use 'set escape%s%s' in the future.\n",
1304 (argc
> 2)? " ":"", (argc
> 2)? argv
[1]: "");
1308 printf("new escape character: ");
1309 (void) fgets(buf
, sizeof(buf
), stdin
);
1315 printf("Escape character is '%s'.\n", control(escape
));
1317 (void) fflush(stdout
);
1323 togcrmod(int argc
, char *argv
[])
1326 printf("Deprecated usage - please use 'toggle crmod' in the future.\n");
1327 printf("%s map carriage return on output.\n", crmod
? "Will" : "Won't");
1328 (void) fflush(stdout
);
1334 suspend(int argc
, char *argv
[])
1338 long oldrows
, oldcols
, newrows
, newcols
, err
;
1340 err
= (TerminalWindowSize(&oldrows
, &oldcols
) == 0) ? 1 : 0;
1341 (void) kill(0, SIGTSTP
);
1343 * If we didn't get the window size before the SUSPEND, but we
1344 * can get them now (?), then send the NAWS to make sure that
1345 * we are set up for the right window size.
1347 if (TerminalWindowSize(&newrows
, &newcols
) && connected
&&
1348 (err
|| ((oldrows
!= newrows
) || (oldcols
!= newcols
)))) {
1352 /* reget parameters in case they were changed */
1353 TerminalSaveState();
1361 shell(int argc
, char *argv
[])
1363 long oldrows
, oldcols
, newrows
, newcols
;
1364 long volatile err
; /* Avoid vfork clobbering */
1368 err
= (TerminalWindowSize(&oldrows
, &oldcols
) == 0) ? 1 : 0;
1371 perror("Fork failed");
1377 * Fire up the shell in the child.
1379 const char *shellp
, *shellname
;
1381 shellp
= getenv("SHELL");
1384 if ((shellname
= strrchr(shellp
, '/')) == 0)
1389 execl(shellp
, shellname
, "-c", &saveline
[1], NULL
);
1391 execl(shellp
, shellname
, NULL
);
1396 (void)wait((int *)0); /* Wait for the shell to complete */
1398 if (TerminalWindowSize(&newrows
, &newcols
) && connected
&&
1399 (err
|| ((oldrows
!= newrows
) || (oldcols
!= newcols
)))) {
1406 #endif /* !defined(TN3270) */
1410 bye(int argc
, char *argv
[])
1412 extern int resettermname
;
1415 (void) shutdown(net
, 2);
1416 printf("Connection closed.\n");
1417 (void) NetClose(net
);
1420 #if defined(AUTHENTICATION) || defined(ENCRYPTION)
1421 auth_encrypt_connect(connected
);
1422 #endif /* defined(AUTHENTICATION) */
1426 SetIn3270(); /* Get out of 3270 mode */
1427 #endif /* defined(TN3270) */
1429 if ((argc
!= 2) || (strcmp(argv
[1], "fromquit") != 0)) {
1430 longjmp(toplevel
, 1);
1433 return 1; /* Keep lint, etc., happy */
1438 quit(int argc
, char *argv
[])
1440 (void) call(bye
, "bye", "fromquit", 0);
1447 logout(int argc
, char *argv
[])
1449 send_do(TELOPT_LOGOUT
, 1);
1462 void (*handler
)(int);
1466 struct slclist SlcList
[] = {
1467 { "export", "Use local special character definitions",
1468 slc_mode_export
, 0 },
1469 { "import", "Use remote special character definitions",
1470 slc_mode_import
, 1 },
1471 { "check", "Verify remote special character definitions",
1472 slc_mode_import
, 0 },
1473 { "help", 0, slc_help
, 0 },
1474 { "?", "Print help information", slc_help
, 0 },
1483 for (c
= SlcList
; c
->name
; c
++) {
1486 printf("%-15s %s\n", c
->name
, c
->help
);
1493 static struct slclist
*
1496 return (struct slclist
*)
1497 genget(name
, (char **) SlcList
, sizeof(struct slclist
));
1501 slccmd(int argc
, char *argv
[])
1507 "Need an argument to 'slc' command. 'slc ?' for help.\n");
1510 c
= getslc(argv
[1]);
1512 fprintf(stderr
, "'%s': unknown argument ('slc ?' for help).\n",
1517 fprintf(stderr
, "'%s': ambiguous argument ('slc ?' for help).\n",
1521 (*c
->handler
)(c
->arg
);
1527 * The ENVIRON command.
1533 struct env_lst
*(*handler
)(const unsigned char *, unsigned char *);
1537 struct envlist EnvList
[] = {
1538 { "define", "Define an environment variable",
1540 { "undefine", "Undefine an environment variable",
1542 { "export", "Mark an environment variable for automatic export",
1544 { "unexport", "Don't mark an environment variable for automatic export",
1546 { "send", "Send an environment variable", env_send
, 1 },
1547 { "list", "List the current environment variables",
1549 #if defined(OLD_ENVIRON) && defined(ENV_HACK)
1550 { "varval", "Reverse VAR and VALUE (auto, right, wrong, status)",
1553 { "help", 0, env_help
, 0 },
1554 { "?", "Print help information", env_help
, 0 },
1558 static struct env_lst
*
1559 env_help(const unsigned char *us1
, unsigned char *us2
)
1563 for (c
= EnvList
; c
->name
; c
++) {
1566 printf("%-15s %s\n", c
->name
, c
->help
);
1574 static struct envlist
*
1575 getenvcmd(char *name
)
1577 return (struct envlist
*)
1578 genget(name
, (char **) EnvList
, sizeof(struct envlist
));
1582 env_cmd(int argc
, char *argv
[])
1588 "Need an argument to 'environ' command. 'environ ?' for help.\n");
1591 c
= getenvcmd(argv
[1]);
1593 fprintf(stderr
, "'%s': unknown argument ('environ ?' for help).\n",
1598 fprintf(stderr
, "'%s': ambiguous argument ('environ ?' for help).\n",
1602 if (c
->narg
+ 2 != argc
) {
1604 "Need %s%d argument%s to 'environ %s' command. 'environ ?' for help.\n",
1605 c
->narg
< argc
+ 2 ? "only " : "",
1606 c
->narg
, c
->narg
== 1 ? "" : "s", c
->name
);
1609 (*c
->handler
)(argv
[2], argv
[3]);
1614 struct env_lst
*next
; /* pointer to next structure */
1615 struct env_lst
*prev
; /* pointer to previous structure */
1616 unsigned char *var
; /* pointer to variable name */
1617 unsigned char *value
; /* pointer to variable value */
1618 int export
; /* 1 -> export with default list of variables */
1619 int welldefined
; /* A well defined variable */
1622 struct env_lst envlisthead
;
1625 env_find(const unsigned char *var
)
1629 for (ep
= envlisthead
.next
; ep
; ep
= ep
->next
) {
1630 if (strcmp((const char *)ep
->var
, (const char *)var
) == 0)
1639 extern char **environ
;
1643 for (epp
= environ
; *epp
; epp
++) {
1644 if ((cp
= strchr(*epp
, '=')) != NULL
) {
1646 ep
= env_define((unsigned char *)*epp
,
1647 (unsigned char *)cp
+1);
1653 * Special case for DISPLAY variable. If it is ":0.0" or
1654 * "unix:0.0", we have to get rid of "unix" and insert our
1657 if ((ep
= env_find("DISPLAY"))
1658 && ((*ep
->value
== ':')
1659 || (strncmp((char *)ep
->value
, "unix:", 5) == 0))) {
1660 char hbuf
[MAXHOSTNAMELEN
+ 1];
1661 char *cp2
= strchr((char *)ep
->value
, ':');
1663 gethostname(hbuf
, sizeof hbuf
);
1664 hbuf
[sizeof(hbuf
) - 1] = '\0';
1665 cp
= (char *)malloc(strlen(hbuf
) + strlen(cp2
) + 1);
1666 sprintf((char *)cp
, "%s%s", hbuf
, cp2
);
1668 ep
->value
= (unsigned char *)cp
;
1671 * If USER is not defined, but LOGNAME is, then add
1672 * USER with the value from LOGNAME. By default, we
1673 * don't export the USER variable.
1675 if ((env_find("USER") == NULL
) && (ep
= env_find("LOGNAME"))) {
1676 env_define((const unsigned char *)"USER", ep
->value
);
1677 env_unexport((const unsigned char *)"USER", NULL
);
1679 env_export((const unsigned char *)"DISPLAY", NULL
);
1680 env_export((const unsigned char *)"PRINTER", NULL
);
1684 env_define(const unsigned char *var
, unsigned char *value
)
1688 if ((ep
= env_find(var
)) != NULL
) {
1694 ep
= (struct env_lst
*)malloc(sizeof(struct env_lst
));
1695 ep
->next
= envlisthead
.next
;
1696 envlisthead
.next
= ep
;
1697 ep
->prev
= &envlisthead
;
1699 ep
->next
->prev
= ep
;
1701 ep
->welldefined
= opt_welldefined(var
);
1703 ep
->var
= (unsigned char *)strdup((const char *)var
);
1704 ep
->value
= (unsigned char *)strdup((const char *)value
);
1709 env_undefine(const unsigned char *var
, unsigned char *d
)
1713 if ((ep
= env_find(var
)) != NULL
) {
1714 ep
->prev
->next
= ep
->next
;
1716 ep
->next
->prev
= ep
->prev
;
1727 env_export(const unsigned char *var
, unsigned char *d
)
1731 if ((ep
= env_find(var
)) != NULL
)
1737 env_unexport(const unsigned char *var
, unsigned char *d
)
1741 if ((ep
= env_find(var
)) != NULL
)
1747 env_send(const unsigned char *var
, unsigned char *d
)
1751 if (my_state_is_wont(TELOPT_NEW_ENVIRON
)
1753 && my_state_is_wont(TELOPT_OLD_ENVIRON
)
1757 "Cannot send '%s': Telnet ENVIRON option not enabled\n",
1763 fprintf(stderr
, "Cannot send '%s': variable not defined\n",
1767 env_opt_start_info();
1768 env_opt_add(ep
->var
);
1774 env_list(const unsigned char *d1
, unsigned char *d2
)
1778 for (ep
= envlisthead
.next
; ep
; ep
= ep
->next
) {
1779 printf("%c %-20s %s\n", ep
->export
? '*' : ' ',
1780 ep
->var
, ep
->value
);
1786 env_default(int init
, int welldefined
)
1788 static struct env_lst
*nep
= NULL
;
1795 while ((nep
= nep
->next
) != NULL
) {
1796 if (nep
->export
&& (nep
->welldefined
== welldefined
))
1804 env_getvalue(const unsigned char *var
)
1808 if ((ep
= env_find(var
)) != NULL
)
1813 #if defined(OLD_ENVIRON) && defined(ENV_HACK)
1815 env_varval(const unsigned char *what
)
1817 extern int old_env_var
, old_env_value
, env_auto
;
1818 int len
= strlen((char *)what
);
1823 if (strncasecmp((char *)what
, "status", len
) == 0) {
1825 printf("%s%s", "VAR and VALUE are/will be ",
1826 "determined automatically\n");
1827 if (old_env_var
== OLD_ENV_VAR
)
1828 printf("VAR and VALUE set to correct definitions\n");
1830 printf("VAR and VALUE definitions are reversed\n");
1831 } else if (strncasecmp((char *)what
, "auto", len
) == 0) {
1833 old_env_var
= OLD_ENV_VALUE
;
1834 old_env_value
= OLD_ENV_VAR
;
1835 } else if (strncasecmp((char *)what
, "right", len
) == 0) {
1837 old_env_var
= OLD_ENV_VAR
;
1838 old_env_value
= OLD_ENV_VALUE
;
1839 } else if (strncasecmp((char *)what
, "wrong", len
) == 0) {
1841 old_env_var
= OLD_ENV_VALUE
;
1842 old_env_value
= OLD_ENV_VAR
;
1845 printf("Unknown \"varval\" command. (\"auto\", \"right\", \"wrong\", \"status\")\n");
1850 #ifdef AUTHENTICATION
1852 * The AUTHENTICATE command.
1858 int (*handler
)(char *);
1862 struct authlist AuthList
[] = {
1863 { "status", "Display current status of authentication information",
1865 { "disable", "Disable an authentication type ('auth disable ?' for more)",
1867 { "enable", "Enable an authentication type ('auth enable ?' for more)",
1869 { "help", 0, auth_help
, 0 },
1870 { "?", "Print help information", auth_help
, 0 },
1879 for (c
= AuthList
; c
->name
; c
++) {
1882 printf("%-15s %s\n", c
->name
, c
->help
);
1891 auth_cmd(int argc
, char *argv
[])
1897 "Need an argument to 'auth' command. 'auth ?' for help.\n");
1901 c
= (struct authlist
*)
1902 genget(argv
[1], (char **) AuthList
, sizeof(struct authlist
));
1904 fprintf(stderr
, "'%s': unknown argument ('auth ?' for help).\n",
1909 fprintf(stderr
, "'%s': ambiguous argument ('auth ?' for help).\n",
1913 if (c
->narg
+ 2 != argc
) {
1915 "Need %s%d argument%s to 'auth %s' command. 'auth ?' for help.\n",
1916 c
->narg
< argc
+ 2 ? "only " : "",
1917 c
->narg
, c
->narg
== 1 ? "" : "s", c
->name
);
1920 return((*c
->handler
)(argv
[2]));
1926 * The ENCRYPT command.
1929 struct encryptlist
{
1932 int (*handler
)(char *, char *);
1939 EncryptHelp(char *, char *);
1940 typedef int (*encrypthandler
)(char *, char *);
1942 struct encryptlist EncryptList
[] = {
1943 { "enable", "Enable encryption. ('encrypt enable ?' for more)",
1944 EncryptEnable
, 1, 1, 2 },
1945 { "disable", "Disable encryption. ('encrypt enable ?' for more)",
1946 EncryptDisable
, 0, 1, 2 },
1947 { "type", "Set encryption type. ('encrypt type ?' for more)",
1948 EncryptType
, 0, 1, 1 },
1949 { "start", "Start encryption. ('encrypt start ?' for more)",
1950 (encrypthandler
) EncryptStart
, 1, 0, 1 },
1951 { "stop", "Stop encryption. ('encrypt stop ?' for more)",
1952 (encrypthandler
) EncryptStop
, 1, 0, 1 },
1953 { "input", "Start encrypting the input stream",
1954 (encrypthandler
) EncryptStartInput
, 1, 0, 0 },
1955 { "-input", "Stop encrypting the input stream",
1956 (encrypthandler
) EncryptStopInput
, 1, 0, 0 },
1957 { "output", "Start encrypting the output stream",
1958 (encrypthandler
) EncryptStartOutput
, 1, 0, 0 },
1959 { "-output", "Stop encrypting the output stream",
1960 (encrypthandler
) EncryptStopOutput
, 1, 0, 0 },
1962 { "status", "Display current status of authentication information",
1963 (encrypthandler
) EncryptStatus
, 0, 0, 0 },
1964 { "help", 0, EncryptHelp
, 0, 0, 0 },
1965 { "?", "Print help information", EncryptHelp
, 0, 0, 0 },
1970 EncryptHelp(char *s1
, char *s2
)
1972 struct encryptlist
*c
;
1974 for (c
= EncryptList
; c
->name
; c
++) {
1977 printf("%-15s %s\n", c
->name
, c
->help
);
1986 encrypt_cmd(int argc
, char *argv
[])
1988 struct encryptlist
*c
;
1992 "Need an argument to 'encrypt' command. "
1993 "'encrypt ?' for help.\n");
1997 c
= (struct encryptlist
*)
1998 genget(argv
[1], (char **) EncryptList
, sizeof(struct encryptlist
));
2001 "'%s': unknown argument ('encrypt ?' for help).\n",
2007 "'%s': ambiguous argument ('encrypt ?' for help).\n",
2012 if (argc
< c
->minarg
|| argc
> c
->maxarg
) {
2013 if (c
->minarg
== c
->maxarg
) {
2014 fprintf(stderr
, "Need %s%d argument%s ",
2015 c
->minarg
< argc
? "only " : "", c
->minarg
,
2016 c
->minarg
== 1 ? "" : "s");
2018 fprintf(stderr
, "Need %s%d-%d arguments ",
2019 c
->maxarg
< argc
? "only " : "", c
->minarg
,
2023 "to 'encrypt %s' command. 'encrypt ?' for help.\n",
2027 if (c
->needconnect
&& !connected
) {
2028 if (!(argc
&& (isprefix(argv
[2], "help") ||
2029 isprefix(argv
[2], "?")))) {
2030 printf("?Need to be connected first.\n");
2034 return ((*c
->handler
)(argv
[2], argv
[3]));
2036 #endif /* ENCRYPTION */
2045 res
= fcntl(fd
, F_GETOWN
, 0);
2052 printf("\tOwner is %d.\n", res
);
2055 res
= fcntl(fd
, F_GETFL
, 0);
2063 printf("\tFlags are 0x%x: %s\n", res
, decodeflags(res
));
2066 #endif /* defined(TN3270) */
2069 * Print status about the connection.
2073 status(int argc
, char *argv
[])
2076 printf("Connected to %s.\n", hostname
);
2077 if ((argc
< 2) || strcmp(argv
[1], "notmuch")) {
2078 int mode
= getconnmode();
2080 if (my_want_state_is_will(TELOPT_LINEMODE
)) {
2081 printf("Operating with LINEMODE option\n");
2082 printf("%s line editing\n", (mode
&MODE_EDIT
) ? "Local" : "No");
2083 printf("%s catching of signals\n",
2084 (mode
&MODE_TRAPSIG
) ? "Local" : "No");
2086 #ifdef KLUDGELINEMODE
2087 } else if (kludgelinemode
&& my_want_state_is_dont(TELOPT_SGA
)) {
2088 printf("Operating in obsolete linemode\n");
2091 printf("Operating in single character mode\n");
2093 printf("Catching signals locally\n");
2095 printf("%s character echo\n", (mode
&MODE_ECHO
) ? "Local" : "Remote");
2096 if (my_want_state_is_will(TELOPT_LFLOW
))
2097 printf("%s flow control\n", (mode
&MODE_FLOW
) ? "Local" : "No");
2100 #endif /* ENCRYPTION */
2103 printf("No connection.\n");
2106 printf("Escape character is '%s'.\n", control(escape
));
2107 (void) fflush(stdout
);
2108 # else /* !defined(TN3270) */
2109 if ((!In3270
) && ((argc
< 2) || strcmp(argv
[1], "notmuch"))) {
2110 printf("Escape character is '%s'.\n", control(escape
));
2112 if ((argc
>= 2) && !strcmp(argv
[1], "everything")) {
2113 printf("SIGIO received %d time%s.\n",
2114 sigiocount
, (sigiocount
== 1)? "":"s");
2116 printf("Process ID %d, process group %d.\n",
2117 getpid(), getpgrp());
2118 printf("Terminal input:\n");
2120 printf("Terminal output:\n");
2122 printf("Network socket:\n");
2126 if (In3270
&& transcom
) {
2127 printf("Transparent mode command is '%s'.\n", transcom
);
2129 (void) fflush(stdout
);
2133 # endif /* defined(TN3270) */
2138 * Function that gets called when SIGINFO is received.
2143 return call(status
, "status", "notmuch", 0);
2147 sockaddr_ntop(struct sockaddr
*sa
)
2149 static char addrbuf
[NI_MAXHOST
];
2150 const int niflags
= NI_NUMERICHOST
;
2152 if (getnameinfo(sa
, sa
->sa_len
, addrbuf
, sizeof(addrbuf
),
2153 NULL
, 0, niflags
) == 0)
2159 #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
2160 static int setpolicy (int, struct addrinfo
*, char *);
2163 setpolicy(int netw
, struct addrinfo
*res
, char *policy
)
2172 buf
= ipsec_set_policy(policy
, strlen(policy
));
2174 printf("%s\n", ipsec_strerror());
2177 level
= res
->ai_family
== AF_INET
? IPPROTO_IP
: IPPROTO_IPV6
;
2178 optname
= res
->ai_family
== AF_INET
? IP_IPSEC_POLICY
: IPV6_IPSEC_POLICY
;
2179 if (setsockopt(netw
, level
, optname
, buf
, ipsec_get_policylen(buf
)) < 0){
2180 perror("setsockopt");
2190 tn(int argc
, char *argv
[])
2192 struct addrinfo hints
, *res
, *res0
;
2193 const char *cause
= "telnet: unknown";
2195 #if defined(IP_OPTIONS) && defined(IPPROTO_IP)
2200 char *cmd
, *hostp
= 0;
2201 const char *portp
= 0;
2202 const char *user
= 0;
2205 printf("?Already connected to %s\n", hostname
);
2209 (void) strlcpy(line
, "open ", sizeof(line
));
2211 (void) fgets(&line
[strlen(line
)], sizeof(line
) - strlen(line
), stdin
);
2219 if (strcmp(*argv
, "help") == 0 || isprefix(*argv
, "?"))
2221 if (strcmp(*argv
, "-l") == 0) {
2229 if (strcmp(*argv
, "-a") == 0) {
2245 printf("usage: %s [-l user] [-a] host-name [port]\n", cmd
);
2251 (void) strlcpy(_hostname
, hostp
, sizeof(_hostname
));
2252 if (hostp
[0] == '@' || hostp
[0] == '!') {
2255 for (p
= hostp
+ 1; *p
; p
++) {
2256 if (*p
== ',' || *p
== '@')
2259 if (hostname
== NULL
) {
2260 fprintf(stderr
, "%s: bad source route specification\n", hostp
);
2270 } else if (portp
[0] == '-') {
2271 /* use telnet negotiation if port number/name preceded by minus sign */
2277 memset(&hints
, 0, sizeof(hints
));
2278 hints
.ai_family
= family
;
2279 hints
.ai_socktype
= SOCK_STREAM
;
2280 hints
.ai_protocol
= 0;
2281 hints
.ai_flags
= AI_NUMERICHOST
; /* avoid forward lookup */
2282 error
= getaddrinfo(hostname
, portp
, &hints
, &res0
);
2286 getnameinfo(res0
->ai_addr
, res0
->ai_addrlen
,
2287 _hostname
, sizeof(_hostname
), NULL
, 0, NI_NAMEREQD
) == 0)
2290 strlcpy(_hostname
, hostname
, sizeof(_hostname
));
2292 /* FQDN - try again with forward DNS lookup */
2293 memset(&hints
, 0, sizeof(hints
));
2294 hints
.ai_family
= family
;
2295 hints
.ai_socktype
= SOCK_STREAM
;
2296 hints
.ai_protocol
= 0;
2297 hints
.ai_flags
= AI_CANONNAME
;
2298 error
= getaddrinfo(hostname
, portp
, &hints
, &res0
);
2299 if (error
== EAI_SERVICE
) {
2300 fprintf(stderr
, "tcp/%s: unknown service\n", portp
);
2303 fprintf(stderr
, "%s: %s\n", hostname
, gai_strerror(error
));
2306 if (res0
->ai_canonname
)
2307 (void)strlcpy(_hostname
, res0
->ai_canonname
, sizeof(_hostname
));
2309 (void)strlcpy(_hostname
, hostname
, sizeof(_hostname
));
2311 hostname
= _hostname
;
2314 for (res
= res0
; res
; res
= res
->ai_next
) {
2315 printf("Trying %s...\n", sockaddr_ntop(res
->ai_addr
));
2316 net
= socket(res
->ai_family
, res
->ai_socktype
, res
->ai_protocol
);
2318 cause
= "telnet: socket";
2322 if (telnet_debug
&& SetSockOpt(net
, SOL_SOCKET
, SO_DEBUG
, 1) < 0) {
2323 perror("setsockopt (SO_DEBUG)");
2325 if (hostp
[0] == '@' || hostp
[0] == '!') {
2326 if ((srlen
= sourceroute(res
, hostp
, &srp
, &proto
, &opt
)) < 0) {
2327 (void) NetClose(net
);
2331 if (srp
&& setsockopt(net
, proto
, opt
, srp
, srlen
) < 0)
2332 perror("setsockopt (source route)");
2335 #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
2336 if (setpolicy(net
, res
, ipsec_policy_in
) < 0) {
2337 (void) NetClose(net
);
2341 if (setpolicy(net
, res
, ipsec_policy_out
) < 0) {
2342 (void) NetClose(net
);
2348 if (connect(net
, res
->ai_addr
, res
->ai_addrlen
) < 0) {
2352 fprintf(stderr
, "telnet: connect to address %s: ",
2353 sockaddr_ntop(res
->ai_addr
));
2357 cause
= "telnet: Unable to connect to remote host";
2358 (void) NetClose(net
);
2364 #if defined(AUTHENTICATION) || defined(ENCRYPTION)
2365 auth_encrypt_connect(connected
);
2366 #endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */
2370 if (net
< 0 || connected
== 0) {
2375 cmdrc(hostp
, hostname
);
2376 if (autologin
&& user
== NULL
) {
2379 user
= getenv("USER");
2381 ((pw
= getpwnam(user
)) && pw
->pw_uid
!= getuid())) {
2382 if ((pw
= getpwuid(getuid())) != NULL
)
2389 env_define((const unsigned char *)"USER", __UNCONST(user
));
2390 env_export((const unsigned char *)"USER", NULL
);
2392 (void) call(status
, "status", "notmuch", 0);
2394 (void) NetClose(net
);
2395 ExitString("Connection closed by foreign host.\n",1);
2399 #define HELPINDENT ((int)sizeof ("connect"))
2402 openhelp
[] = "connect to a site",
2403 closehelp
[] = "close current connection",
2404 logouthelp
[] = "forcibly logout remote user and close the connection",
2405 quithelp
[] = "exit telnet",
2406 statushelp
[] = "print status information",
2407 helphelp
[] = "print help information",
2408 sendhelp
[] = "transmit special characters ('send ?' for more)",
2409 sethelp
[] = "set operating parameters ('set ?' for more)",
2410 unsethelp
[] = "unset operating parameters ('unset ?' for more)",
2411 togglestring
[] ="toggle operating parameters ('toggle ?' for more)",
2412 slchelp
[] = "change state of special characters ('slc ?' for more)",
2413 displayhelp
[] = "display operating parameters",
2415 transcomhelp
[] = "specify Unix command for transparent mode pipe",
2416 #endif /* defined(TN3270) */
2417 #ifdef AUTHENTICATION
2418 authhelp
[] = "turn on (off) authentication ('auth ?' for more)",
2421 encrypthelp
[] = "turn on (off) encryption ('encrypt ?' for more)",
2422 #endif /* ENCRYPTION */
2423 zhelp
[] = "suspend telnet",
2424 shellhelp
[] = "invoke a subshell",
2425 envhelp
[] = "change environment variables ('environ ?' for more)",
2426 modestring
[] = "try to enter line or character mode ('mode ?' for more)";
2428 static Command cmdtab
[] = {
2429 { "close", closehelp
, bye
, 1 },
2430 { "logout", logouthelp
, logout
, 1 },
2431 { "display", displayhelp
, display
, 0 },
2432 { "mode", modestring
, modecmd
, 0 },
2433 { "open", openhelp
, tn
, 0 },
2434 { "quit", quithelp
, quit
, 0 },
2435 { "send", sendhelp
, sendcmd
, 0 },
2436 { "set", sethelp
, setcmd
, 0 },
2437 { "unset", unsethelp
, unsetcmd
, 0 },
2438 { "status", statushelp
, status
, 0 },
2439 { "toggle", togglestring
, toggle
, 0 },
2440 { "slc", slchelp
, slccmd
, 0 },
2442 { "transcom", transcomhelp
, settranscom
, 0 },
2443 #endif /* defined(TN3270) */
2444 #ifdef AUTHENTICATION
2445 { "auth", authhelp
, auth_cmd
, 0 },
2448 { "encrypt", encrypthelp
, encrypt_cmd
, 0 },
2450 { "z", zhelp
, suspend
, 0 },
2452 { "!", shellhelp
, shell
, 1 },
2454 { "!", shellhelp
, shell
, 0 },
2456 { "environ", envhelp
, env_cmd
, 0 },
2457 { "?", helphelp
, help
, 0 },
2458 { NULL
, NULL
, NULL
, 0 }
2461 static char crmodhelp
[] = "deprecated command -- use 'toggle crmod' instead";
2462 static char escapehelp
[] = "deprecated command -- use 'set escape' instead";
2464 static Command cmdtab2
[] = {
2465 { "help", 0, help
, 0 },
2466 { "escape", escapehelp
, setescape
, 0 },
2467 { "crmod", crmodhelp
, togcrmod
, 0 },
2468 { NULL
, NULL
, NULL
, 0 }
2473 * Call routine with argc, argv set from args (terminated by 0).
2478 call(intrtn_t routine
, ...)
2484 va_start(ap
, routine
);
2485 while ((args
[argno
++] = va_arg(ap
, char *)) != 0) {
2489 return (*routine
)(argno
-1, args
);
2498 if ((cm
= (Command
*) genget(name
, (char **) cmdtab
, sizeof(Command
))) != NULL
)
2500 return (Command
*) genget(name
, (char **) cmdtab2
, sizeof(Command
));
2504 command(int top
, const char *tbuf
, int cnt
)
2512 (void) signal(SIGINT
, SIG_DFL
);
2513 (void) signal(SIGQUIT
, SIG_DFL
);
2516 if (rlogin
== _POSIX_VDISABLE
)
2517 printf("%s> ", prompt
);
2521 while (cnt
> 0 && (*cp
++ = *tbuf
++) != '\n')
2524 if (cp
== line
|| *--cp
!= '\n' || cp
== line
)
2527 if (rlogin
== _POSIX_VDISABLE
)
2528 printf("%s\n", line
);
2531 if (rlogin
!= _POSIX_VDISABLE
)
2532 printf("%s> ", prompt
);
2536 if (fgets(line
, sizeof(line
), stdin
) == NULL
) {
2537 if (feof(stdin
) || ferror(stdin
)) {
2538 (void) quit(0, NULL
);
2547 if (margv
[0] == 0) {
2550 c
= getcmd(margv
[0]);
2552 printf("?Ambiguous command\n");
2556 printf("?Invalid command\n");
2559 if (c
->needconnect
&& !connected
) {
2560 printf("?Need to be connected first.\n");
2563 if ((*c
->handler
)(margc
, margv
)) {
2569 longjmp(toplevel
, 1);
2573 if (shell_active
== 0) {
2576 #else /* defined(TN3270) */
2578 #endif /* defined(TN3270) */
2586 help(int argc
, char *argv
[])
2591 printf("Commands may be abbreviated. Commands are:\n\n");
2592 for (c
= cmdtab
; c
->name
; c
++)
2594 printf("%-*s\t%s\n", HELPINDENT
, c
->name
,
2599 while (--argc
> 0) {
2604 printf("?Ambiguous help command %s\n", arg
);
2605 else if (c
== (Command
*)0)
2606 printf("?Invalid help command %s\n", arg
);
2608 printf("%s\n", c
->help
);
2613 static char *rcname
= 0;
2614 static char rcbuf
[128];
2617 cmdrc(const char *m1
, const char *m2
)
2622 int l1
= strlen(m1
);
2623 int l2
= strlen(m2
);
2624 char m1save
[MAXHOSTNAMELEN
+ 1];
2629 strlcpy(m1save
, m1
, sizeof(m1save
));
2633 rcname
= getenv("HOME");
2635 strlcpy(rcbuf
, rcname
, sizeof(rcbuf
));
2638 strlcat(rcbuf
, "/.telnetrc", sizeof(rcbuf
));
2642 if ((rcfile
= fopen(rcname
, "r")) == 0) {
2647 if (fgets(line
, sizeof(line
), rcfile
) == NULL
)
2654 if (!isspace((unsigned char)line
[0]))
2657 if (gotmachine
== 0) {
2658 if (isspace((unsigned char)line
[0]))
2660 if (strncasecmp(line
, m1
, l1
) == 0)
2661 strncpy(line
, &line
[l1
], sizeof(line
) - l1
);
2662 else if (strncasecmp(line
, m2
, l2
) == 0)
2663 strncpy(line
, &line
[l2
], sizeof(line
) - l2
);
2664 else if (strncasecmp(line
, "DEFAULT", 7) == 0)
2665 strncpy(line
, &line
[7], sizeof(line
) - 7);
2668 if (line
[0] != ' ' && line
[0] != '\t' && line
[0] != '\n')
2675 c
= getcmd(margv
[0]);
2677 printf("?Ambiguous command: %s\n", margv
[0]);
2681 printf("?Invalid command: %s\n", margv
[0]);
2685 * This should never happen...
2687 if (c
->needconnect
&& !connected
) {
2688 printf("?Need to be connected first for %s.\n", margv
[0]);
2691 (*c
->handler
)(margc
, margv
);
2697 * Source route is handed in as
2698 * [!]@hop1@hop2...@dst
2700 * If the leading ! is present, it is a strict source route, otherwise it is
2701 * assmed to be a loose source route. Note that leading ! is effective
2702 * only for IPv4 case.
2704 * We fill in the source route option as
2705 * hop1,hop2,hop3...dest
2706 * and return a pointer to hop1, which will
2707 * be the address to connect() to.
2710 * ai: The address (by struct addrinfo) for the final destination.
2712 * arg: Pointer to route list to decipher
2714 * cpp: Pointer to a pointer, so that sourceroute() can return
2715 * the address of result buffer (statically alloc'ed).
2718 * Pointer to an integer. The pointed variable
2719 * lenp: pointer to an integer that contains the
2720 * length of *cpp if *cpp != NULL.
2724 * Returns the length of the option pointed to by *cpp. If the
2725 * return value is -1, there was a syntax error in the
2726 * option, either arg contained unknown characters or too many hosts,
2727 * or hostname cannot be resolved.
2729 * The caller needs to pass return value (len), *cpp, *protop and *optp
2732 * *cpp: Points to the result buffer. The region is statically
2733 * allocated by the function.
2736 * protocol # to be passed to setsockopt(2).
2738 * *optp: option # to be passed to setsockopt(2).
2742 sourceroute(struct addrinfo
*ai
, char *arg
, char **cpp
, int *protop
, int *optp
)
2744 char *cp
, *cp2
, *lsrp
, *lsrep
;
2745 struct addrinfo hints
, *res
;
2747 struct sockaddr_in
*sin
;
2749 static char lsr
[44];
2751 struct cmsghdr
*cmsg
;
2752 struct sockaddr_in6
*sin6
;
2753 static char rhbuf
[1024];
2757 * Verify the arguments.
2766 /* init these just in case.... */
2773 switch (ai
->ai_family
) {
2776 lsrep
= lsrp
+ sizeof(lsr
);
2779 * Next, decide whether we have a loose source
2780 * route or a strict source route, and fill in
2781 * the begining of the option.
2785 *lsrp
++ = IPOPT_SSRR
;
2787 *lsrp
++ = IPOPT_LSRR
;
2790 lsrp
++; /* skip over length, we'll fill it in later */
2793 *protop
= IPPROTO_IP
;
2798 #ifdef IPV6_PKTOPTIONS
2800 cmsg
= inet6_rthdr_init(rhbuf
, IPV6_RTHDR_TYPE_0
);
2804 *protop
= IPPROTO_IPV6
;
2805 *optp
= IPV6_PKTOPTIONS
;
2816 memset(&hints
, 0, sizeof(hints
));
2817 hints
.ai_family
= ai
->ai_family
;
2818 hints
.ai_socktype
= SOCK_STREAM
;
2823 else for (cp2
= cp
; (c
= *cp2
) != '\0'; cp2
++) {
2828 } else if (c
== '@') {
2831 #if 0 /*colon conflicts with IPv6 address*/
2832 else if (c
== ':') {
2843 error
= getaddrinfo(cp
, NULL
, &hints
, &res
);
2845 fprintf(stderr
, "%s: %s\n", cp
, gai_strerror(error
));
2848 if (ai
->ai_family
!= res
->ai_family
) {
2852 if (ai
->ai_family
== AF_INET
) {
2854 * Check to make sure there is space for address
2856 if (lsrp
+ 4 > lsrep
) {
2860 sin
= (struct sockaddr_in
*)res
->ai_addr
;
2861 memcpy(lsrp
, &sin
->sin_addr
, sizeof(struct in_addr
));
2862 lsrp
+= sizeof(struct in_addr
);
2865 else if (ai
->ai_family
== AF_INET6
) {
2866 sin6
= (struct sockaddr_in6
*)res
->ai_addr
;
2867 inet6_rthdr_add(cmsg
, &sin6
->sin6_addr
,
2881 switch (ai
->ai_family
) {
2883 /* record the last hop */
2884 if (lsrp
+ 4 > lsrep
)
2886 sin
= (struct sockaddr_in
*)ai
->ai_addr
;
2887 memcpy(lsrp
, &sin
->sin_addr
, sizeof(struct in_addr
));
2888 lsrp
+= sizeof(struct in_addr
);
2889 lsr
[IPOPT_OLEN
] = lsrp
- lsr
;
2890 if (lsr
[IPOPT_OLEN
] <= 7 || lsr
[IPOPT_OLEN
] > 40)
2892 *lsrp
++ = IPOPT_NOP
; /*32bit word align*/
2898 inet6_rthdr_lasthop(cmsg
, IPV6_RTHDR_LOOSE
);
2899 len
= cmsg
->cmsg_len
;