1 /* $NetBSD: commands.c,v 1.66 2006/05/11 00:25:46 mrg 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.66 2006/05/11 00:25:46 mrg 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 char *name
; /* command name */
113 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 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(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 *[]);
181 if (*cp
== '!') { /* Special case shell escape */
182 strlcpy(saveline
, line
, sizeof(saveline
)); /* save for shell command */
183 *argp
++ = "!"; /* No room in string to get this */
187 while ((c
= *cp
) != '\0') {
189 while (isspace((unsigned char)c
))
195 for (cp2
= cp
; c
!= '\0'; c
= *++cp
) {
203 if ((c
= *++cp
) == '\0')
205 } else if (c
== '"') {
208 } else if (c
== '\'') {
211 } else if (isspace((unsigned char)c
))
225 * Make a character string into a number.
227 * Todo: 1. Could take random integers (12, 0x12, 012, 0b1).
240 c
= b
| 0x40; /* DEL */
253 * Construct a control character sequence
254 * for a special character.
261 * The only way I could get the Sun 3.5 compiler
263 * if ((unsigned int)c >= 0x80)
264 * was to assign "c" to an unsigned int variable...
267 unsigned int uic
= (unsigned int)c
;
271 if (c
== (cc_t
)_POSIX_VDISABLE
) {
276 buf
[1] = ((c
>>6)&07) + '0';
277 buf
[2] = ((c
>>3)&07) + '0';
278 buf
[3] = (c
&07) + '0';
280 } else if (uic
>= 0x20) {
294 * The following are data structures and routines for
295 * the "send" command.
300 char *name
; /* How user refers to it (case independent) */
301 char *help
; /* Help information (0 ==> no help) */
302 int needconnect
; /* Need to be connected */
303 int narg
; /* Number of arguments */
304 int (*handler
) /* Routine to perform (for special ops) */
306 int nbyte
; /* Number of bytes to send this command */
307 int what
; /* Character to be sent (<0 ==> special) */
311 static struct sendlist Sendlist
[] = {
312 { "ao", "Send Telnet Abort output", 1, 0, 0, 2, AO
},
313 { "ayt", "Send Telnet 'Are You There'", 1, 0, 0, 2, AYT
},
314 { "brk", "Send Telnet Break", 1, 0, 0, 2, BREAK
},
315 { "break", 0, 1, 0, 0, 2, BREAK
},
316 { "ec", "Send Telnet Erase Character", 1, 0, 0, 2, EC
},
317 { "el", "Send Telnet Erase Line", 1, 0, 0, 2, EL
},
318 { "escape", "Send current escape character", 1, 0, send_esc
, 1, 0 },
319 { "ga", "Send Telnet 'Go Ahead' sequence", 1, 0, 0, 2, GA
},
320 { "ip", "Send Telnet Interrupt Process", 1, 0, 0, 2, IP
},
321 { "intp", 0, 1, 0, 0, 2, IP
},
322 { "interrupt", 0, 1, 0, 0, 2, IP
},
323 { "intr", 0, 1, 0, 0, 2, IP
},
324 { "nop", "Send Telnet 'No operation'", 1, 0, 0, 2, NOP
},
325 { "eor", "Send Telnet 'End of Record'", 1, 0, 0, 2, EOR
},
326 { "abort", "Send Telnet 'Abort Process'", 1, 0, 0, 2, ABORT
},
327 { "susp", "Send Telnet 'Suspend Process'", 1, 0, 0, 2, SUSP
},
328 { "eof", "Send Telnet End of File Character", 1, 0, 0, 2, xEOF
},
329 { "synch", "Perform Telnet 'Synch operation'", 1, 0, dosynch
, 2, 0 },
330 { "getstatus", "Send request for STATUS", 1, 0, get_status
, 6, 0 },
331 { "?", "Display send options", 0, 0, send_help
, 0, 0 },
332 { "help", 0, 0, 0, send_help
, 0, 0 },
333 { "do", 0, 0, 1, send_docmd
, 3, 0 },
334 { "dont", 0, 0, 1, send_dontcmd
, 3, 0 },
335 { "will", 0, 0, 1, send_willcmd
, 3, 0 },
336 { "wont", 0, 0, 1, send_wontcmd
, 3, 0 },
340 #define GETSEND(name) ((struct sendlist *) genget(name, (char **) Sendlist, \
341 sizeof(struct sendlist)))
344 sendcmd(int argc
, char **argv
)
346 int count
; /* how many bytes we are going to need to send */
348 struct sendlist
*s
; /* pointer to current command */
353 printf("need at least one argument for 'send' command\n");
354 printf("'send ?' for help\n");
358 * First, validate all the send arguments.
359 * In addition, we see how much space we are going to need, and
360 * whether or not we will be doing a "SYNCH" operation (which
361 * flushes the network queue).
364 for (i
= 1; i
< argc
; i
++) {
365 s
= GETSEND(argv
[i
]);
367 printf("Unknown send argument '%s'\n'send ?' for help.\n",
370 } else if (Ambiguous(s
)) {
371 printf("Ambiguous send argument '%s'\n'send ?' for help.\n",
375 if (i
+ s
->narg
>= argc
) {
377 "Need %d argument%s to 'send %s' command. 'send %s ?' for help.\n",
378 s
->narg
, s
->narg
== 1 ? "" : "s", s
->name
, s
->name
);
382 if (s
->handler
== send_help
) {
388 needconnect
+= s
->needconnect
;
390 if (!connected
&& needconnect
) {
391 printf("?Need to be connected first.\n");
392 printf("'send ?' for help\n");
395 /* Now, do we have enough room? */
396 if (NETROOM() < count
) {
397 printf("There is not enough room in the buffer TO the network\n");
398 printf("to process your request. Nothing will be done.\n");
399 printf("('send synch' will throw away most data in the network\n");
400 printf("buffer, if this might help.)\n");
403 /* OK, they are all OK, now go through again and actually send */
405 for (i
= 1; i
< argc
; i
++) {
406 if ((s
= GETSEND(argv
[i
])) == 0) {
407 fprintf(stderr
, "Telnet 'send' error - argument disappeared!\n");
408 (void) quit(0, NULL
);
413 success
+= (*s
->handler
)(argv
[i
+1]);
416 NET2ADD(IAC
, s
->what
);
417 printoption("SENT", IAC
, s
->what
);
420 return (count
== success
);
431 send_docmd(char *name
)
433 return(send_tncmd(send_do
, "do", name
));
437 send_dontcmd(char *name
)
439 return(send_tncmd(send_dont
, "dont", name
));
442 send_willcmd(char *name
)
444 return(send_tncmd(send_will
, "will", name
));
447 send_wontcmd(char *name
)
449 return(send_tncmd(send_wont
, "wont", name
));
453 send_tncmd(void (*func
)(int, int), char *cmd
, char *name
)
458 if (isprefix(name
, "?")) {
461 printf("usage: send %s <value|option>\n", cmd
);
462 printf("\"value\" must be from 0 to 255\n");
463 printf("Valid options are:\n\t");
466 for (cpp
= telopts
; *cpp
; cpp
++) {
467 len
= strlen(*cpp
) + 3;
468 if (col
+ len
> 65) {
472 printf(" \"%s\"", *cpp
);
478 cpp
= (const char **)genget(name
, (char **)telopts
, sizeof(char *));
479 if (Ambiguous(cpp
)) {
480 fprintf(stderr
,"'%s': ambiguous argument ('send %s ?' for help).\n",
489 while (*cp
>= '0' && *cp
<= '9') {
495 fprintf(stderr
, "'%s': unknown argument ('send %s ?' for help).\n",
498 } else if (val
< 0 || val
> 255) {
499 fprintf(stderr
, "'%s': bad value ('send %s ?' for help).\n",
505 printf("?Need to be connected first.\n");
515 struct sendlist
*s
; /* pointer to current command */
516 for (s
= Sendlist
; s
->name
; s
++) {
518 printf("%-15s %s\n", s
->name
, s
->help
);
524 * The following are the routines and data structures referred
525 * to by the arguments to the "toggle" command.
539 (SetSockOpt(net
, SOL_SOCKET
, SO_DEBUG
, telnet_debug
)) < 0) {
540 perror("setsockopt (SO_DEBUG)");
549 printf("Will send carriage returns as telnet <CR><LF>.\n");
551 printf("Will send carriage returns as telnet <CR><NUL>.\n");
561 donebinarytoggle
= 1;
566 if (my_want_state_is_will(TELOPT_BINARY
) &&
567 my_want_state_is_do(TELOPT_BINARY
)) {
569 } else if (my_want_state_is_wont(TELOPT_BINARY
) &&
570 my_want_state_is_dont(TELOPT_BINARY
)) {
573 val
= binmode
? 0 : 1;
577 if (my_want_state_is_will(TELOPT_BINARY
) &&
578 my_want_state_is_do(TELOPT_BINARY
)) {
579 printf("Already operating in binary mode with remote host.\n");
581 printf("Negotiating binary mode with remote host.\n");
585 if (my_want_state_is_wont(TELOPT_BINARY
) &&
586 my_want_state_is_dont(TELOPT_BINARY
)) {
587 printf("Already in network ascii mode with remote host.\n");
589 printf("Negotiating network ascii mode with remote host.\n");
599 donebinarytoggle
= 1;
602 val
= my_want_state_is_do(TELOPT_BINARY
) ? 0 : 1;
605 if (my_want_state_is_do(TELOPT_BINARY
)) {
606 printf("Already receiving in binary mode.\n");
608 printf("Negotiating binary mode on input.\n");
612 if (my_want_state_is_dont(TELOPT_BINARY
)) {
613 printf("Already receiving in network ascii mode.\n");
615 printf("Negotiating network ascii mode on input.\n");
625 donebinarytoggle
= 1;
628 val
= my_want_state_is_will(TELOPT_BINARY
) ? 0 : 1;
631 if (my_want_state_is_will(TELOPT_BINARY
)) {
632 printf("Already transmitting in binary mode.\n");
634 printf("Negotiating binary mode on output.\n");
638 if (my_want_state_is_wont(TELOPT_BINARY
)) {
639 printf("Already transmitting in network ascii mode.\n");
641 printf("Negotiating network ascii mode on output.\n");
649 extern int EncryptAutoEnc(int);
650 extern int EncryptAutoDec(int);
651 extern int EncryptDebug(int);
652 extern int EncryptVerbose(int);
653 #endif /* ENCRYPTION */
656 char *name
; /* name of toggle */
657 char *help
; /* help message */
658 int (*handler
) /* routine to do actual setting */
661 char *actionexplanation
;
664 static struct togglelist Togglelist
[] = {
666 "flushing of output when sending interrupt characters",
669 "flush output when sending interrupt characters" },
671 "automatic sending of interrupt characters in urgent mode",
674 "send interrupt characters in urgent mode" },
675 #ifdef AUTHENTICATION
677 "automatic sending of login and/or authentication info",
680 "send login name and/or authentication information" },
682 "Toggle authentication debugging",
685 "print authentication debugging information" },
689 "automatic encryption of data stream",
692 "automatically encrypt output" },
694 "automatic decryption of data stream",
697 "automatically decrypt input" },
699 "Toggle verbose encryption output",
702 "print verbose encryption output" },
704 "Toggle encryption debugging",
707 "print encryption debugging information" },
708 #endif /* ENCRYPTION */
710 "don't read ~/.telnetrc file",
713 "skip reading of ~/.telnetrc file" },
715 "sending and receiving of binary data",
720 "receiving of binary data",
725 "sending of binary data",
730 "sending carriage returns as telnet <CR><LF>",
735 "mapping of received carriage returns",
738 "map carriage return on output" },
740 "local recognition of certain control characters",
743 "recognize certain control characters" },
744 { " ", "", 0 }, /* empty line */
747 "(debugging) toggle tracing of API transactions",
750 "trace API transactions" },
752 "(debugging) toggle printing of hexadecimal curses data",
755 "print hexadecimal representation of curses data" },
756 #endif /* defined(TN3270) */
761 "turn on socket level debugging" },
763 "printing of hexadecimal network data (debugging)",
766 "print hexadecimal representation of network traffic" },
768 "output of \"netdata\" to user readable format (debugging)",
771 "print user readable output for \"netdata\"" },
773 "viewing of options processing (debugging)",
776 "show option processing" },
778 "(debugging) toggle printing of hexadecimal terminal data",
781 "print hexadecimal representation of terminal traffic" },
794 struct togglelist
*c
;
796 for (c
= Togglelist
; c
->name
; c
++) {
799 printf("%-15s toggle %s\n", c
->name
, c
->help
);
805 printf("%-15s %s\n", "?", "display help information");
810 settogglehelp(int set
)
812 struct togglelist
*c
;
814 for (c
= Togglelist
; c
->name
; c
++) {
817 printf("%-15s %s %s\n", c
->name
, set
? "enable" : "disable",
825 #define GETTOGGLE(name) (struct togglelist *) \
826 genget(name, (char **) Togglelist, sizeof(struct togglelist))
829 toggle(int argc
, char *argv
[])
833 struct togglelist
*c
;
837 "Need an argument to 'toggle' command. 'toggle ?' for help.\n");
846 fprintf(stderr
, "'%s': ambiguous argument ('toggle ?' for help).\n",
850 fprintf(stderr
, "'%s': unknown argument ('toggle ?' for help).\n",
855 *c
->variable
= !*c
->variable
; /* invert it */
856 if (c
->actionexplanation
) {
857 printf("%s %s.\n", *c
->variable
? "Will" : "Won't",
858 c
->actionexplanation
);
862 retval
&= (*c
->handler
)(-1);
870 * The following perform the "set" command.
873 struct termios new_tc
= { 0 };
876 char *name
; /* name */
877 char *help
; /* help information */
878 void (*handler
)(char *);
879 cc_t
*charp
; /* where it is located at */
882 static struct setlist Setlist
[] = {
883 #ifdef KLUDGELINEMODE
884 { "echo", "character to toggle local echoing on/off", 0, &echoc
},
886 { "escape", "character to escape back to telnet command mode", 0, &escape
},
887 { "rlogin", "rlogin escape character", 0, &rlogin
},
888 { "tracefile", "file to write trace information to", SetNetTrace
, (cc_t
*)NetTraceFile
},
890 { " ", "The following need 'localchars' to be toggled true", 0, 0 },
891 { "flushoutput", "character to cause an Abort Output", 0, termFlushCharp
},
892 { "interrupt", "character to cause an Interrupt Process", 0, termIntCharp
},
893 { "quit", "character to cause an Abort process", 0, termQuitCharp
},
894 { "eof", "character to cause an EOF ", 0, termEofCharp
},
896 { " ", "The following are for local editing in linemode", 0, 0 },
897 { "erase", "character to use to erase a character", 0, termEraseCharp
},
898 { "kill", "character to use to erase a line", 0, termKillCharp
},
899 { "lnext", "character to use for literal next", 0, termLiteralNextCharp
},
900 { "susp", "character to cause a Suspend Process", 0, termSuspCharp
},
901 { "reprint", "character to use for line reprint", 0, termRprntCharp
},
902 { "worderase", "character to use to erase a word", 0, termWerasCharp
},
903 { "start", "character to use for XON", 0, termStartCharp
},
904 { "stop", "character to use for XOFF", 0, termStopCharp
},
905 { "forw1", "alternate end of line character", 0, termForw1Charp
},
906 { "forw2", "alternate end of line character", 0, termForw2Charp
},
907 { "ayt", "alternate AYT character", 0, termAytCharp
},
911 static struct setlist
*
914 return (struct setlist
*)
915 genget(name
, (char **) Setlist
, sizeof(struct setlist
));
919 set_escape_char(char *s
)
921 if (rlogin
!= _POSIX_VDISABLE
) {
922 rlogin
= (s
&& *s
) ? special(s
) : _POSIX_VDISABLE
;
923 printf("Telnet rlogin escape character is '%s'.\n",
926 escape
= (s
&& *s
) ? special(s
) : _POSIX_VDISABLE
;
927 printf("Telnet escape character is '%s'.\n", control(escape
));
932 setcmd(int argc
, char *argv
[])
936 struct togglelist
*c
;
938 if (argc
< 2 || argc
> 3) {
939 printf("Format is 'set Name Value'\n'set ?' for help.\n");
942 if ((argc
== 2) && (isprefix(argv
[1], "?") || isprefix(argv
[1], "help"))) {
943 for (ct
= Setlist
; ct
->name
; ct
++)
944 printf("%-15s %s\n", ct
->name
, ct
->help
);
947 printf("%-15s %s\n", "?", "display help information");
951 ct
= getset(argv
[1]);
953 c
= GETTOGGLE(argv
[1]);
955 fprintf(stderr
, "'%s': unknown argument ('set ?' for help).\n",
958 } else if (Ambiguous(c
)) {
959 fprintf(stderr
, "'%s': ambiguous argument ('set ?' for help).\n",
964 if ((argc
== 2) || (strcmp("on", argv
[2]) == 0))
966 else if (strcmp("off", argv
[2]) == 0)
969 printf("Format is 'set togglename [on|off]'\n'set ?' for help.\n");
972 if (c
->actionexplanation
) {
973 printf("%s %s.\n", *c
->variable
? "Will" : "Won't",
974 c
->actionexplanation
);
979 } else if (argc
!= 3) {
980 printf("Format is 'set Name Value'\n'set ?' for help.\n");
982 } else if (Ambiguous(ct
)) {
983 fprintf(stderr
, "'%s': ambiguous argument ('set ?' for help).\n",
986 } else if (ct
->handler
) {
987 (*ct
->handler
)(argv
[2]);
988 printf("%s set to \"%s\".\n", ct
->name
, (char *)ct
->charp
);
990 if (strcmp("off", argv
[2])) {
991 value
= special(argv
[2]);
993 value
= _POSIX_VDISABLE
;
995 *(ct
->charp
) = (cc_t
)value
;
996 printf("%s character is '%s'.\n", ct
->name
, control(*(ct
->charp
)));
1003 unsetcmd(int argc
, char *argv
[])
1006 struct togglelist
*c
;
1011 "Need an argument to 'unset' command. 'unset ?' for help.\n");
1014 if (isprefix(argv
[1], "?") || isprefix(argv
[1], "help")) {
1015 for (ct
= Setlist
; ct
->name
; ct
++)
1016 printf("%-15s %s\n", ct
->name
, ct
->help
);
1019 printf("%-15s %s\n", "?", "display help information");
1029 c
= GETTOGGLE(name
);
1031 fprintf(stderr
, "'%s': unknown argument ('unset ?' for help).\n",
1034 } else if (Ambiguous(c
)) {
1035 fprintf(stderr
, "'%s': ambiguous argument ('unset ?' for help).\n",
1041 if (c
->actionexplanation
) {
1042 printf("%s %s.\n", *c
->variable
? "Will" : "Won't",
1043 c
->actionexplanation
);
1048 } else if (Ambiguous(ct
)) {
1049 fprintf(stderr
, "'%s': ambiguous argument ('unset ?' for help).\n",
1052 } else if (ct
->handler
) {
1054 printf("%s reset to \"%s\".\n", ct
->name
, (char *)ct
->charp
);
1056 *(ct
->charp
) = _POSIX_VDISABLE
;
1057 printf("%s character is '%s'.\n", ct
->name
, control(*(ct
->charp
)));
1064 * The following are the data structures and routines for the
1067 #ifdef KLUDGELINEMODE
1068 extern int kludgelinemode
;
1074 send_wont(TELOPT_LINEMODE
, 1);
1075 send_dont(TELOPT_SGA
, 1);
1076 send_dont(TELOPT_ECHO
, 1);
1084 #ifdef KLUDGELINEMODE
1086 send_dont(TELOPT_SGA
, 1);
1088 send_will(TELOPT_LINEMODE
, 1);
1089 send_dont(TELOPT_ECHO
, 1);
1096 #ifdef KLUDGELINEMODE
1098 send_do(TELOPT_SGA
, 1);
1101 send_wont(TELOPT_LINEMODE
, 1);
1102 send_do(TELOPT_ECHO
, 1);
1107 dolmmode(int bit
, int on
)
1110 extern int linemode
;
1112 if (my_want_state_is_wont(TELOPT_LINEMODE
)) {
1113 printf("?Need to have LINEMODE option enabled first.\n");
1114 printf("'mode ?' for help.\n");
1119 c
= (linemode
| bit
);
1121 c
= (linemode
& ~bit
);
1129 return dolmmode(bit
, 1);
1135 return dolmmode(bit
, 0);
1139 char *name
; /* command name */
1140 char *help
; /* help string */
1141 int (*handler
) /* routine which executes command */
1143 int needconnect
; /* Do we need to be connected to execute? */
1147 static struct modelist ModeList
[] = {
1148 { "character", "Disable LINEMODE option", docharmode
, 1 },
1149 #ifdef KLUDGELINEMODE
1150 { "", "(or disable obsolete line-by-line mode)", 0 },
1152 { "line", "Enable LINEMODE option", dolinemode
, 1 },
1153 #ifdef KLUDGELINEMODE
1154 { "", "(or enable obsolete line-by-line mode)", 0 },
1157 { "", "These require the LINEMODE option to be enabled", 0 },
1158 { "isig", "Enable signal trapping", set_mode
, 1, MODE_TRAPSIG
},
1159 { "+isig", 0, set_mode
, 1, MODE_TRAPSIG
},
1160 { "-isig", "Disable signal trapping", clear_mode
, 1, MODE_TRAPSIG
},
1161 { "edit", "Enable character editing", set_mode
, 1, MODE_EDIT
},
1162 { "+edit", 0, set_mode
, 1, MODE_EDIT
},
1163 { "-edit", "Disable character editing", clear_mode
, 1, MODE_EDIT
},
1164 { "softtabs", "Enable tab expansion", set_mode
, 1, MODE_SOFT_TAB
},
1165 { "+softtabs", 0, set_mode
, 1, MODE_SOFT_TAB
},
1166 { "-softtabs", "Disable character editing", clear_mode
, 1, MODE_SOFT_TAB
},
1167 { "litecho", "Enable literal character echo", set_mode
, 1, MODE_LIT_ECHO
},
1168 { "+litecho", 0, set_mode
, 1, MODE_LIT_ECHO
},
1169 { "-litecho", "Disable literal character echo", clear_mode
, 1, MODE_LIT_ECHO
},
1170 { "help", 0, modehelp
, 0 },
1171 #ifdef KLUDGELINEMODE
1172 { "kludgeline", 0, dokludgemode
, 1 },
1175 { "?", "Print help information", modehelp
, 0 },
1183 struct modelist
*mt
;
1185 printf("format is: 'mode Mode', where 'Mode' is one of:\n\n");
1186 for (mt
= ModeList
; mt
->name
; mt
++) {
1189 printf("%-15s %s\n", mt
->name
, mt
->help
);
1197 #define GETMODECMD(name) (struct modelist *) \
1198 genget(name, (char **) ModeList, sizeof(struct modelist))
1201 modecmd(int argc
, char *argv
[])
1203 struct modelist
*mt
;
1206 printf("'mode' command requires an argument\n");
1207 printf("'mode ?' for help.\n");
1208 } else if ((mt
= GETMODECMD(argv
[1])) == 0) {
1209 fprintf(stderr
, "Unknown mode '%s' ('mode ?' for help).\n", argv
[1]);
1210 } else if (Ambiguous(mt
)) {
1211 fprintf(stderr
, "Ambiguous mode '%s' ('mode ?' for help).\n", argv
[1]);
1212 } else if (mt
->needconnect
&& !connected
) {
1213 printf("?Need to be connected first.\n");
1214 printf("'mode ?' for help.\n");
1215 } else if (mt
->handler
) {
1216 return (*mt
->handler
)(mt
->arg1
);
1222 * The following data structures and routines implement the
1223 * "display" command.
1227 display(int argc
, char *argv
[])
1229 struct togglelist
*tl
;
1232 #define dotog(tl) if (tl->variable && tl->actionexplanation) { \
1233 if (*tl->variable) { \
1238 printf(" %s.\n", tl->actionexplanation); \
1241 #define doset(sl) if (sl->name && *sl->name != ' ') { \
1242 if (sl->handler == 0) \
1243 printf("%-15s [%s]\n", sl->name, control(*sl->charp)); \
1245 printf("%-15s \"%s\"\n", sl->name, (char *)sl->charp); \
1249 for (tl
= Togglelist
; tl
->name
; tl
++) {
1253 for (sl
= Setlist
; sl
->name
; sl
++) {
1259 for (i
= 1; i
< argc
; i
++) {
1260 sl
= getset(argv
[i
]);
1261 tl
= GETTOGGLE(argv
[i
]);
1262 if (Ambiguous(sl
) || Ambiguous(tl
)) {
1263 printf("?Ambiguous argument '%s'.\n", argv
[i
]);
1265 } else if (!sl
&& !tl
) {
1266 printf("?Unknown argument '%s'.\n", argv
[i
]);
1278 /*@*/optionstatus();
1281 #endif /* ENCRYPTION */
1288 * The following are the data structures, and many of the routines,
1289 * relating to command processing.
1293 * Set the escape character.
1296 setescape(int argc
, char *argv
[])
1302 "Deprecated usage - please use 'set escape%s%s' in the future.\n",
1303 (argc
> 2)? " ":"", (argc
> 2)? argv
[1]: "");
1307 printf("new escape character: ");
1308 (void) fgets(buf
, sizeof(buf
), stdin
);
1314 printf("Escape character is '%s'.\n", control(escape
));
1316 (void) fflush(stdout
);
1322 togcrmod(int argc
, char *argv
[])
1325 printf("Deprecated usage - please use 'toggle crmod' in the future.\n");
1326 printf("%s map carriage return on output.\n", crmod
? "Will" : "Won't");
1327 (void) fflush(stdout
);
1333 suspend(int argc
, char *argv
[])
1337 long oldrows
, oldcols
, newrows
, newcols
, err
;
1339 err
= (TerminalWindowSize(&oldrows
, &oldcols
) == 0) ? 1 : 0;
1340 (void) kill(0, SIGTSTP
);
1342 * If we didn't get the window size before the SUSPEND, but we
1343 * can get them now (?), then send the NAWS to make sure that
1344 * we are set up for the right window size.
1346 if (TerminalWindowSize(&newrows
, &newcols
) && connected
&&
1347 (err
|| ((oldrows
!= newrows
) || (oldcols
!= newcols
)))) {
1351 /* reget parameters in case they were changed */
1352 TerminalSaveState();
1360 shell(int argc
, char *argv
[])
1362 long oldrows
, oldcols
, newrows
, newcols
;
1363 long volatile err
; /* Avoid vfork clobbering */
1367 err
= (TerminalWindowSize(&oldrows
, &oldcols
) == 0) ? 1 : 0;
1370 perror("Fork failed");
1376 * Fire up the shell in the child.
1378 char *shellp
, *shellname
;
1380 shellp
= getenv("SHELL");
1383 if ((shellname
= strrchr(shellp
, '/')) == 0)
1388 execl(shellp
, shellname
, "-c", &saveline
[1], NULL
);
1390 execl(shellp
, shellname
, NULL
);
1395 (void)wait((int *)0); /* Wait for the shell to complete */
1397 if (TerminalWindowSize(&newrows
, &newcols
) && connected
&&
1398 (err
|| ((oldrows
!= newrows
) || (oldcols
!= newcols
)))) {
1405 #endif /* !defined(TN3270) */
1409 bye(int argc
, char *argv
[])
1411 extern int resettermname
;
1414 (void) shutdown(net
, 2);
1415 printf("Connection closed.\n");
1416 (void) NetClose(net
);
1419 #if defined(AUTHENTICATION) || defined(ENCRYPTION)
1420 auth_encrypt_connect(connected
);
1421 #endif /* defined(AUTHENTICATION) */
1425 SetIn3270(); /* Get out of 3270 mode */
1426 #endif /* defined(TN3270) */
1428 if ((argc
!= 2) || (strcmp(argv
[1], "fromquit") != 0)) {
1429 longjmp(toplevel
, 1);
1432 return 1; /* Keep lint, etc., happy */
1437 quit(int argc
, char *argv
[])
1439 (void) call(bye
, "bye", "fromquit", 0);
1446 logout(int argc
, char *argv
[])
1448 send_do(TELOPT_LOGOUT
, 1);
1461 void (*handler
)(int);
1465 struct slclist SlcList
[] = {
1466 { "export", "Use local special character definitions",
1467 slc_mode_export
, 0 },
1468 { "import", "Use remote special character definitions",
1469 slc_mode_import
, 1 },
1470 { "check", "Verify remote special character definitions",
1471 slc_mode_import
, 0 },
1472 { "help", 0, slc_help
, 0 },
1473 { "?", "Print help information", slc_help
, 0 },
1482 for (c
= SlcList
; c
->name
; c
++) {
1485 printf("%-15s %s\n", c
->name
, c
->help
);
1492 static struct slclist
*
1495 return (struct slclist
*)
1496 genget(name
, (char **) SlcList
, sizeof(struct slclist
));
1500 slccmd(int argc
, char *argv
[])
1506 "Need an argument to 'slc' command. 'slc ?' for help.\n");
1509 c
= getslc(argv
[1]);
1511 fprintf(stderr
, "'%s': unknown argument ('slc ?' for help).\n",
1516 fprintf(stderr
, "'%s': ambiguous argument ('slc ?' for help).\n",
1520 (*c
->handler
)(c
->arg
);
1526 * The ENVIRON command.
1532 struct env_lst
*(*handler
)(unsigned char *, unsigned char *);
1536 struct envlist EnvList
[] = {
1537 { "define", "Define an environment variable",
1539 { "undefine", "Undefine an environment variable",
1541 { "export", "Mark an environment variable for automatic export",
1543 { "unexport", "Don't mark an environment variable for automatic export",
1545 { "send", "Send an environment variable", env_send
, 1 },
1546 { "list", "List the current environment variables",
1548 #if defined(OLD_ENVIRON) && defined(ENV_HACK)
1549 { "varval", "Reverse VAR and VALUE (auto, right, wrong, status)",
1552 { "help", 0, env_help
, 0 },
1553 { "?", "Print help information", env_help
, 0 },
1557 static struct env_lst
*
1558 env_help( unsigned char *us1
, unsigned char *us2
)
1562 for (c
= EnvList
; c
->name
; c
++) {
1565 printf("%-15s %s\n", c
->name
, c
->help
);
1573 static struct envlist
*
1574 getenvcmd(char *name
)
1576 return (struct envlist
*)
1577 genget(name
, (char **) EnvList
, sizeof(struct envlist
));
1581 env_cmd(int argc
, char *argv
[])
1587 "Need an argument to 'environ' command. 'environ ?' for help.\n");
1590 c
= getenvcmd(argv
[1]);
1592 fprintf(stderr
, "'%s': unknown argument ('environ ?' for help).\n",
1597 fprintf(stderr
, "'%s': ambiguous argument ('environ ?' for help).\n",
1601 if (c
->narg
+ 2 != argc
) {
1603 "Need %s%d argument%s to 'environ %s' command. 'environ ?' for help.\n",
1604 c
->narg
< argc
+ 2 ? "only " : "",
1605 c
->narg
, c
->narg
== 1 ? "" : "s", c
->name
);
1608 (*c
->handler
)(argv
[2], argv
[3]);
1613 struct env_lst
*next
; /* pointer to next structure */
1614 struct env_lst
*prev
; /* pointer to previous structure */
1615 unsigned char *var
; /* pointer to variable name */
1616 unsigned char *value
; /* pointer to variable value */
1617 int export
; /* 1 -> export with default list of variables */
1618 int welldefined
; /* A well defined variable */
1621 struct env_lst envlisthead
;
1624 env_find(unsigned char *var
)
1628 for (ep
= envlisthead
.next
; ep
; ep
= ep
->next
) {
1629 if (strcmp((char *)ep
->var
, (char *)var
) == 0)
1638 extern char **environ
;
1642 for (epp
= environ
; *epp
; epp
++) {
1643 if ((cp
= strchr(*epp
, '=')) != NULL
) {
1645 ep
= env_define((unsigned char *)*epp
,
1646 (unsigned char *)cp
+1);
1652 * Special case for DISPLAY variable. If it is ":0.0" or
1653 * "unix:0.0", we have to get rid of "unix" and insert our
1656 if ((ep
= env_find("DISPLAY"))
1657 && ((*ep
->value
== ':')
1658 || (strncmp((char *)ep
->value
, "unix:", 5) == 0))) {
1659 char hbuf
[MAXHOSTNAMELEN
+ 1];
1660 char *cp2
= strchr((char *)ep
->value
, ':');
1662 gethostname(hbuf
, sizeof hbuf
);
1663 hbuf
[sizeof(hbuf
) - 1] = '\0';
1664 cp
= (char *)malloc(strlen(hbuf
) + strlen(cp2
) + 1);
1665 sprintf((char *)cp
, "%s%s", hbuf
, cp2
);
1667 ep
->value
= (unsigned char *)cp
;
1670 * If USER is not defined, but LOGNAME is, then add
1671 * USER with the value from LOGNAME. By default, we
1672 * don't export the USER variable.
1674 if ((env_find("USER") == NULL
) && (ep
= env_find("LOGNAME"))) {
1675 env_define((unsigned char *)"USER", ep
->value
);
1676 env_unexport((unsigned char *)"USER", NULL
);
1678 env_export((unsigned char *)"DISPLAY", NULL
);
1679 env_export((unsigned char *)"PRINTER", NULL
);
1683 env_define(unsigned char *var
, unsigned char *value
)
1687 if ((ep
= env_find(var
)) != NULL
) {
1693 ep
= (struct env_lst
*)malloc(sizeof(struct env_lst
));
1694 ep
->next
= envlisthead
.next
;
1695 envlisthead
.next
= ep
;
1696 ep
->prev
= &envlisthead
;
1698 ep
->next
->prev
= ep
;
1700 ep
->welldefined
= opt_welldefined(var
);
1702 ep
->var
= (unsigned char *)strdup((char *)var
);
1703 ep
->value
= (unsigned char *)strdup((char *)value
);
1708 env_undefine(unsigned char *var
, unsigned char *d
)
1712 if ((ep
= env_find(var
)) != NULL
) {
1713 ep
->prev
->next
= ep
->next
;
1715 ep
->next
->prev
= ep
->prev
;
1726 env_export(unsigned char *var
, unsigned char *d
)
1730 if ((ep
= env_find(var
)) != NULL
)
1736 env_unexport(unsigned char *var
, unsigned char *d
)
1740 if ((ep
= env_find(var
)) != NULL
)
1746 env_send(unsigned char *var
, unsigned char *d
)
1750 if (my_state_is_wont(TELOPT_NEW_ENVIRON
)
1752 && my_state_is_wont(TELOPT_OLD_ENVIRON
)
1756 "Cannot send '%s': Telnet ENVIRON option not enabled\n",
1762 fprintf(stderr
, "Cannot send '%s': variable not defined\n",
1766 env_opt_start_info();
1767 env_opt_add(ep
->var
);
1773 env_list(unsigned char *d1
, unsigned char *d2
)
1777 for (ep
= envlisthead
.next
; ep
; ep
= ep
->next
) {
1778 printf("%c %-20s %s\n", ep
->export
? '*' : ' ',
1779 ep
->var
, ep
->value
);
1785 env_default(int init
, int welldefined
)
1787 static struct env_lst
*nep
= NULL
;
1794 while ((nep
= nep
->next
) != NULL
) {
1795 if (nep
->export
&& (nep
->welldefined
== welldefined
))
1803 env_getvalue(unsigned char *var
)
1807 if ((ep
= env_find(var
)) != NULL
)
1812 #if defined(OLD_ENVIRON) && defined(ENV_HACK)
1814 env_varval(unsigned char *what
)
1816 extern int old_env_var
, old_env_value
, env_auto
;
1817 int len
= strlen((char *)what
);
1822 if (strncasecmp((char *)what
, "status", len
) == 0) {
1824 printf("%s%s", "VAR and VALUE are/will be ",
1825 "determined automatically\n");
1826 if (old_env_var
== OLD_ENV_VAR
)
1827 printf("VAR and VALUE set to correct definitions\n");
1829 printf("VAR and VALUE definitions are reversed\n");
1830 } else if (strncasecmp((char *)what
, "auto", len
) == 0) {
1832 old_env_var
= OLD_ENV_VALUE
;
1833 old_env_value
= OLD_ENV_VAR
;
1834 } else if (strncasecmp((char *)what
, "right", len
) == 0) {
1836 old_env_var
= OLD_ENV_VAR
;
1837 old_env_value
= OLD_ENV_VALUE
;
1838 } else if (strncasecmp((char *)what
, "wrong", len
) == 0) {
1840 old_env_var
= OLD_ENV_VALUE
;
1841 old_env_value
= OLD_ENV_VAR
;
1844 printf("Unknown \"varval\" command. (\"auto\", \"right\", \"wrong\", \"status\")\n");
1849 #ifdef AUTHENTICATION
1851 * The AUTHENTICATE command.
1857 int (*handler
)(char *);
1861 struct authlist AuthList
[] = {
1862 { "status", "Display current status of authentication information",
1864 { "disable", "Disable an authentication type ('auth disable ?' for more)",
1866 { "enable", "Enable an authentication type ('auth enable ?' for more)",
1868 { "help", 0, auth_help
, 0 },
1869 { "?", "Print help information", auth_help
, 0 },
1878 for (c
= AuthList
; c
->name
; c
++) {
1881 printf("%-15s %s\n", c
->name
, c
->help
);
1890 auth_cmd(int argc
, char *argv
[])
1896 "Need an argument to 'auth' command. 'auth ?' for help.\n");
1900 c
= (struct authlist
*)
1901 genget(argv
[1], (char **) AuthList
, sizeof(struct authlist
));
1903 fprintf(stderr
, "'%s': unknown argument ('auth ?' for help).\n",
1908 fprintf(stderr
, "'%s': ambiguous argument ('auth ?' for help).\n",
1912 if (c
->narg
+ 2 != argc
) {
1914 "Need %s%d argument%s to 'auth %s' command. 'auth ?' for help.\n",
1915 c
->narg
< argc
+ 2 ? "only " : "",
1916 c
->narg
, c
->narg
== 1 ? "" : "s", c
->name
);
1919 return((*c
->handler
)(argv
[2]));
1925 * The ENCRYPT command.
1928 struct encryptlist
{
1931 int (*handler
)(char *, char *);
1938 EncryptHelp(char *, char *);
1939 typedef int (*encrypthandler
)(char *, char *);
1941 struct encryptlist EncryptList
[] = {
1942 { "enable", "Enable encryption. ('encrypt enable ?' for more)",
1943 EncryptEnable
, 1, 1, 2 },
1944 { "disable", "Disable encryption. ('encrypt enable ?' for more)",
1945 EncryptDisable
, 0, 1, 2 },
1946 { "type", "Set encryption type. ('encrypt type ?' for more)",
1947 EncryptType
, 0, 1, 1 },
1948 { "start", "Start encryption. ('encrypt start ?' for more)",
1949 (encrypthandler
) EncryptStart
, 1, 0, 1 },
1950 { "stop", "Stop encryption. ('encrypt stop ?' for more)",
1951 (encrypthandler
) EncryptStop
, 1, 0, 1 },
1952 { "input", "Start encrypting the input stream",
1953 (encrypthandler
) EncryptStartInput
, 1, 0, 0 },
1954 { "-input", "Stop encrypting the input stream",
1955 (encrypthandler
) EncryptStopInput
, 1, 0, 0 },
1956 { "output", "Start encrypting the output stream",
1957 (encrypthandler
) EncryptStartOutput
, 1, 0, 0 },
1958 { "-output", "Stop encrypting the output stream",
1959 (encrypthandler
) EncryptStopOutput
, 1, 0, 0 },
1961 { "status", "Display current status of authentication information",
1962 (encrypthandler
) EncryptStatus
, 0, 0, 0 },
1963 { "help", 0, EncryptHelp
, 0, 0, 0 },
1964 { "?", "Print help information", EncryptHelp
, 0, 0, 0 },
1969 EncryptHelp(char *s1
, char *s2
)
1971 struct encryptlist
*c
;
1973 for (c
= EncryptList
; c
->name
; c
++) {
1976 printf("%-15s %s\n", c
->name
, c
->help
);
1985 encrypt_cmd(int argc
, char *argv
[])
1987 struct encryptlist
*c
;
1991 "Need an argument to 'encrypt' command. "
1992 "'encrypt ?' for help.\n");
1996 c
= (struct encryptlist
*)
1997 genget(argv
[1], (char **) EncryptList
, sizeof(struct encryptlist
));
2000 "'%s': unknown argument ('encrypt ?' for help).\n",
2006 "'%s': ambiguous argument ('encrypt ?' for help).\n",
2011 if (argc
< c
->minarg
|| argc
> c
->maxarg
) {
2012 if (c
->minarg
== c
->maxarg
) {
2013 fprintf(stderr
, "Need %s%d argument%s ",
2014 c
->minarg
< argc
? "only " : "", c
->minarg
,
2015 c
->minarg
== 1 ? "" : "s");
2017 fprintf(stderr
, "Need %s%d-%d arguments ",
2018 c
->maxarg
< argc
? "only " : "", c
->minarg
,
2022 "to 'encrypt %s' command. 'encrypt ?' for help.\n",
2026 if (c
->needconnect
&& !connected
) {
2027 if (!(argc
&& (isprefix(argv
[2], "help") ||
2028 isprefix(argv
[2], "?")))) {
2029 printf("?Need to be connected first.\n");
2033 return ((*c
->handler
)(argv
[2], argv
[3]));
2035 #endif /* ENCRYPTION */
2044 res
= fcntl(fd
, F_GETOWN
, 0);
2051 printf("\tOwner is %d.\n", res
);
2054 res
= fcntl(fd
, F_GETFL
, 0);
2062 printf("\tFlags are 0x%x: %s\n", res
, decodeflags(res
));
2065 #endif /* defined(TN3270) */
2068 * Print status about the connection.
2072 status(int argc
, char *argv
[])
2075 printf("Connected to %s.\n", hostname
);
2076 if ((argc
< 2) || strcmp(argv
[1], "notmuch")) {
2077 int mode
= getconnmode();
2079 if (my_want_state_is_will(TELOPT_LINEMODE
)) {
2080 printf("Operating with LINEMODE option\n");
2081 printf("%s line editing\n", (mode
&MODE_EDIT
) ? "Local" : "No");
2082 printf("%s catching of signals\n",
2083 (mode
&MODE_TRAPSIG
) ? "Local" : "No");
2085 #ifdef KLUDGELINEMODE
2086 } else if (kludgelinemode
&& my_want_state_is_dont(TELOPT_SGA
)) {
2087 printf("Operating in obsolete linemode\n");
2090 printf("Operating in single character mode\n");
2092 printf("Catching signals locally\n");
2094 printf("%s character echo\n", (mode
&MODE_ECHO
) ? "Local" : "Remote");
2095 if (my_want_state_is_will(TELOPT_LFLOW
))
2096 printf("%s flow control\n", (mode
&MODE_FLOW
) ? "Local" : "No");
2099 #endif /* ENCRYPTION */
2102 printf("No connection.\n");
2105 printf("Escape character is '%s'.\n", control(escape
));
2106 (void) fflush(stdout
);
2107 # else /* !defined(TN3270) */
2108 if ((!In3270
) && ((argc
< 2) || strcmp(argv
[1], "notmuch"))) {
2109 printf("Escape character is '%s'.\n", control(escape
));
2111 if ((argc
>= 2) && !strcmp(argv
[1], "everything")) {
2112 printf("SIGIO received %d time%s.\n",
2113 sigiocount
, (sigiocount
== 1)? "":"s");
2115 printf("Process ID %d, process group %d.\n",
2116 getpid(), getpgrp());
2117 printf("Terminal input:\n");
2119 printf("Terminal output:\n");
2121 printf("Network socket:\n");
2125 if (In3270
&& transcom
) {
2126 printf("Transparent mode command is '%s'.\n", transcom
);
2128 (void) fflush(stdout
);
2132 # endif /* defined(TN3270) */
2137 * Function that gets called when SIGINFO is received.
2142 return call(status
, "status", "notmuch", 0);
2146 sockaddr_ntop(struct sockaddr
*sa
)
2148 static char addrbuf
[NI_MAXHOST
];
2149 const int niflags
= NI_NUMERICHOST
;
2151 if (getnameinfo(sa
, sa
->sa_len
, addrbuf
, sizeof(addrbuf
),
2152 NULL
, 0, niflags
) == 0)
2158 #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
2159 static int setpolicy (int, struct addrinfo
*, char *);
2162 setpolicy(int net
, struct addrinfo
*res
, char *policy
)
2171 buf
= ipsec_set_policy(policy
, strlen(policy
));
2173 printf("%s\n", ipsec_strerror());
2176 level
= res
->ai_family
== AF_INET
? IPPROTO_IP
: IPPROTO_IPV6
;
2177 optname
= res
->ai_family
== AF_INET
? IP_IPSEC_POLICY
: IPV6_IPSEC_POLICY
;
2178 if (setsockopt(net
, level
, optname
, buf
, ipsec_get_policylen(buf
)) < 0){
2179 perror("setsockopt");
2189 tn(int argc
, char *argv
[])
2191 struct addrinfo hints
, *res
, *res0
;
2192 char *cause
= "telnet: unknown";
2194 #if defined(IP_OPTIONS) && defined(IPPROTO_IP)
2196 unsigned long srlen
;
2199 char *cmd
, *hostp
= 0, *portp
= 0;
2200 const char *user
= 0;
2203 printf("?Already connected to %s\n", hostname
);
2207 (void) strlcpy(line
, "open ", sizeof(line
));
2209 (void) fgets(&line
[strlen(line
)], sizeof(line
) - strlen(line
), stdin
);
2217 if (strcmp(*argv
, "help") == 0 || isprefix(*argv
, "?"))
2219 if (strcmp(*argv
, "-l") == 0) {
2227 if (strcmp(*argv
, "-a") == 0) {
2243 printf("usage: %s [-l user] [-a] host-name [port]\n", cmd
);
2249 (void) strlcpy(_hostname
, hostp
, sizeof(_hostname
));
2250 if (hostp
[0] == '@' || hostp
[0] == '!') {
2253 for (p
= hostp
+ 1; *p
; p
++) {
2254 if (*p
== ',' || *p
== '@')
2257 if (hostname
== NULL
) {
2258 fprintf(stderr
, "%s: bad source route specification\n", hostp
);
2268 } else if (portp
[0] == '-') {
2269 /* use telnet negotiation if port number/name preceded by minus sign */
2275 memset(&hints
, 0, sizeof(hints
));
2276 hints
.ai_family
= family
;
2277 hints
.ai_socktype
= SOCK_STREAM
;
2278 hints
.ai_protocol
= 0;
2279 hints
.ai_flags
= AI_NUMERICHOST
; /* avoid forward lookup */
2280 error
= getaddrinfo(hostname
, portp
, &hints
, &res0
);
2284 getnameinfo(res0
->ai_addr
, res0
->ai_addrlen
,
2285 _hostname
, sizeof(_hostname
), NULL
, 0, NI_NAMEREQD
) == 0)
2288 strlcpy(_hostname
, hostname
, sizeof(_hostname
));
2290 /* FQDN - try again with forward DNS lookup */
2291 memset(&hints
, 0, sizeof(hints
));
2292 hints
.ai_family
= family
;
2293 hints
.ai_socktype
= SOCK_STREAM
;
2294 hints
.ai_protocol
= 0;
2295 hints
.ai_flags
= AI_CANONNAME
;
2296 error
= getaddrinfo(hostname
, portp
, &hints
, &res0
);
2297 if (error
== EAI_SERVICE
) {
2298 fprintf(stderr
, "tcp/%s: unknown service\n", portp
);
2301 fprintf(stderr
, "%s: %s\n", hostname
, gai_strerror(error
));
2304 if (res0
->ai_canonname
)
2305 (void)strlcpy(_hostname
, res0
->ai_canonname
, sizeof(_hostname
));
2307 (void)strlcpy(_hostname
, hostname
, sizeof(_hostname
));
2309 hostname
= _hostname
;
2312 for (res
= res0
; res
; res
= res
->ai_next
) {
2313 printf("Trying %s...\n", sockaddr_ntop(res
->ai_addr
));
2314 net
= socket(res
->ai_family
, res
->ai_socktype
, res
->ai_protocol
);
2316 cause
= "telnet: socket";
2320 if (telnet_debug
&& SetSockOpt(net
, SOL_SOCKET
, SO_DEBUG
, 1) < 0) {
2321 perror("setsockopt (SO_DEBUG)");
2323 if (hostp
[0] == '@' || hostp
[0] == '!') {
2324 if ((srlen
= sourceroute(res
, hostp
, &srp
, &proto
, &opt
)) < 0) {
2325 (void) NetClose(net
);
2329 if (srp
&& setsockopt(net
, proto
, opt
, srp
, srlen
) < 0)
2330 perror("setsockopt (source route)");
2333 #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
2334 if (setpolicy(net
, res
, ipsec_policy_in
) < 0) {
2335 (void) NetClose(net
);
2339 if (setpolicy(net
, res
, ipsec_policy_out
) < 0) {
2340 (void) NetClose(net
);
2346 if (connect(net
, res
->ai_addr
, res
->ai_addrlen
) < 0) {
2350 fprintf(stderr
, "telnet: connect to address %s: ",
2351 sockaddr_ntop(res
->ai_addr
));
2355 cause
= "telnet: Unable to connect to remote host";
2356 (void) NetClose(net
);
2362 #if defined(AUTHENTICATION) || defined(ENCRYPTION)
2363 auth_encrypt_connect(connected
);
2364 #endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */
2368 if (net
< 0 || connected
== 0) {
2373 cmdrc(hostp
, hostname
);
2374 if (autologin
&& user
== NULL
) {
2377 user
= getenv("USER");
2379 ((pw
= getpwnam(user
)) && pw
->pw_uid
!= getuid())) {
2380 if ((pw
= getpwuid(getuid())) != NULL
)
2387 env_define((unsigned char *)"USER", (unsigned char *)user
);
2388 env_export((unsigned char *)"USER", NULL
);
2390 (void) call(status
, "status", "notmuch", 0);
2392 (void) NetClose(net
);
2393 ExitString("Connection closed by foreign host.\n",1);
2397 #define HELPINDENT ((int)sizeof ("connect"))
2400 openhelp
[] = "connect to a site",
2401 closehelp
[] = "close current connection",
2402 logouthelp
[] = "forcibly logout remote user and close the connection",
2403 quithelp
[] = "exit telnet",
2404 statushelp
[] = "print status information",
2405 helphelp
[] = "print help information",
2406 sendhelp
[] = "transmit special characters ('send ?' for more)",
2407 sethelp
[] = "set operating parameters ('set ?' for more)",
2408 unsethelp
[] = "unset operating parameters ('unset ?' for more)",
2409 togglestring
[] ="toggle operating parameters ('toggle ?' for more)",
2410 slchelp
[] = "change state of special characters ('slc ?' for more)",
2411 displayhelp
[] = "display operating parameters",
2413 transcomhelp
[] = "specify Unix command for transparent mode pipe",
2414 #endif /* defined(TN3270) */
2415 #ifdef AUTHENTICATION
2416 authhelp
[] = "turn on (off) authentication ('auth ?' for more)",
2419 encrypthelp
[] = "turn on (off) encryption ('encrypt ?' for more)",
2420 #endif /* ENCRYPTION */
2421 zhelp
[] = "suspend telnet",
2422 shellhelp
[] = "invoke a subshell",
2423 envhelp
[] = "change environment variables ('environ ?' for more)",
2424 modestring
[] = "try to enter line or character mode ('mode ?' for more)";
2426 static Command cmdtab
[] = {
2427 { "close", closehelp
, bye
, 1 },
2428 { "logout", logouthelp
, logout
, 1 },
2429 { "display", displayhelp
, display
, 0 },
2430 { "mode", modestring
, modecmd
, 0 },
2431 { "open", openhelp
, tn
, 0 },
2432 { "quit", quithelp
, quit
, 0 },
2433 { "send", sendhelp
, sendcmd
, 0 },
2434 { "set", sethelp
, setcmd
, 0 },
2435 { "unset", unsethelp
, unsetcmd
, 0 },
2436 { "status", statushelp
, status
, 0 },
2437 { "toggle", togglestring
, toggle
, 0 },
2438 { "slc", slchelp
, slccmd
, 0 },
2440 { "transcom", transcomhelp
, settranscom
, 0 },
2441 #endif /* defined(TN3270) */
2442 #ifdef AUTHENTICATION
2443 { "auth", authhelp
, auth_cmd
, 0 },
2446 { "encrypt", encrypthelp
, encrypt_cmd
, 0 },
2448 { "z", zhelp
, suspend
, 0 },
2450 { "!", shellhelp
, shell
, 1 },
2452 { "!", shellhelp
, shell
, 0 },
2454 { "environ", envhelp
, env_cmd
, 0 },
2455 { "?", helphelp
, help
, 0 },
2456 { NULL
, NULL
, NULL
, 0 }
2459 static char crmodhelp
[] = "deprecated command -- use 'toggle crmod' instead";
2460 static char escapehelp
[] = "deprecated command -- use 'set escape' instead";
2462 static Command cmdtab2
[] = {
2463 { "help", 0, help
, 0 },
2464 { "escape", escapehelp
, setescape
, 0 },
2465 { "crmod", crmodhelp
, togcrmod
, 0 },
2466 { NULL
, NULL
, NULL
, 0 }
2471 * Call routine with argc, argv set from args (terminated by 0).
2476 call(intrtn_t routine
, ...)
2482 va_start(ap
, routine
);
2483 while ((args
[argno
++] = va_arg(ap
, char *)) != 0) {
2487 return (*routine
)(argno
-1, args
);
2496 if ((cm
= (Command
*) genget(name
, (char **) cmdtab
, sizeof(Command
))) != NULL
)
2498 return (Command
*) genget(name
, (char **) cmdtab2
, sizeof(Command
));
2502 command(int top
, char *tbuf
, int cnt
)
2510 (void) signal(SIGINT
, SIG_DFL
);
2511 (void) signal(SIGQUIT
, SIG_DFL
);
2514 if (rlogin
== _POSIX_VDISABLE
)
2515 printf("%s> ", prompt
);
2519 while (cnt
> 0 && (*cp
++ = *tbuf
++) != '\n')
2522 if (cp
== line
|| *--cp
!= '\n' || cp
== line
)
2525 if (rlogin
== _POSIX_VDISABLE
)
2526 printf("%s\n", line
);
2529 if (rlogin
!= _POSIX_VDISABLE
)
2530 printf("%s> ", prompt
);
2534 if (fgets(line
, sizeof(line
), stdin
) == NULL
) {
2535 if (feof(stdin
) || ferror(stdin
)) {
2536 (void) quit(0, NULL
);
2545 if (margv
[0] == 0) {
2548 c
= getcmd(margv
[0]);
2550 printf("?Ambiguous command\n");
2554 printf("?Invalid command\n");
2557 if (c
->needconnect
&& !connected
) {
2558 printf("?Need to be connected first.\n");
2561 if ((*c
->handler
)(margc
, margv
)) {
2567 longjmp(toplevel
, 1);
2571 if (shell_active
== 0) {
2574 #else /* defined(TN3270) */
2576 #endif /* defined(TN3270) */
2584 help(int argc
, char *argv
[])
2589 printf("Commands may be abbreviated. Commands are:\n\n");
2590 for (c
= cmdtab
; c
->name
; c
++)
2592 printf("%-*s\t%s\n", HELPINDENT
, c
->name
,
2597 while (--argc
> 0) {
2602 printf("?Ambiguous help command %s\n", arg
);
2603 else if (c
== (Command
*)0)
2604 printf("?Invalid help command %s\n", arg
);
2606 printf("%s\n", c
->help
);
2611 static char *rcname
= 0;
2612 static char rcbuf
[128];
2615 cmdrc(const char *m1
, const char *m2
)
2620 int l1
= strlen(m1
);
2621 int l2
= strlen(m2
);
2622 char m1save
[MAXHOSTNAMELEN
+ 1];
2627 strlcpy(m1save
, m1
, sizeof(m1save
));
2631 rcname
= getenv("HOME");
2633 strlcpy(rcbuf
, rcname
, sizeof(rcbuf
));
2636 strlcat(rcbuf
, "/.telnetrc", sizeof(rcbuf
));
2640 if ((rcfile
= fopen(rcname
, "r")) == 0) {
2645 if (fgets(line
, sizeof(line
), rcfile
) == NULL
)
2652 if (!isspace((unsigned char)line
[0]))
2655 if (gotmachine
== 0) {
2656 if (isspace((unsigned char)line
[0]))
2658 if (strncasecmp(line
, m1
, l1
) == 0)
2659 strncpy(line
, &line
[l1
], sizeof(line
) - l1
);
2660 else if (strncasecmp(line
, m2
, l2
) == 0)
2661 strncpy(line
, &line
[l2
], sizeof(line
) - l2
);
2662 else if (strncasecmp(line
, "DEFAULT", 7) == 0)
2663 strncpy(line
, &line
[7], sizeof(line
) - 7);
2666 if (line
[0] != ' ' && line
[0] != '\t' && line
[0] != '\n')
2673 c
= getcmd(margv
[0]);
2675 printf("?Ambiguous command: %s\n", margv
[0]);
2679 printf("?Invalid command: %s\n", margv
[0]);
2683 * This should never happen...
2685 if (c
->needconnect
&& !connected
) {
2686 printf("?Need to be connected first for %s.\n", margv
[0]);
2689 (*c
->handler
)(margc
, margv
);
2695 * Source route is handed in as
2696 * [!]@hop1@hop2...@dst
2698 * If the leading ! is present, it is a strict source route, otherwise it is
2699 * assmed to be a loose source route. Note that leading ! is effective
2700 * only for IPv4 case.
2702 * We fill in the source route option as
2703 * hop1,hop2,hop3...dest
2704 * and return a pointer to hop1, which will
2705 * be the address to connect() to.
2708 * ai: The address (by struct addrinfo) for the final destination.
2710 * arg: Pointer to route list to decipher
2712 * cpp: Pointer to a pointer, so that sourceroute() can return
2713 * the address of result buffer (statically alloc'ed).
2716 * Pointer to an integer. The pointed variable
2717 * lenp: pointer to an integer that contains the
2718 * length of *cpp if *cpp != NULL.
2722 * Returns the length of the option pointed to by *cpp. If the
2723 * return value is -1, there was a syntax error in the
2724 * option, either arg contained unknown characters or too many hosts,
2725 * or hostname cannot be resolved.
2727 * The caller needs to pass return value (len), *cpp, *protop and *optp
2730 * *cpp: Points to the result buffer. The region is statically
2731 * allocated by the function.
2734 * protocol # to be passed to setsockopt(2).
2736 * *optp: option # to be passed to setsockopt(2).
2740 sourceroute(struct addrinfo
*ai
, char *arg
, char **cpp
, int *protop
, int *optp
)
2742 char *cp
, *cp2
, *lsrp
, *lsrep
;
2743 struct addrinfo hints
, *res
;
2745 struct sockaddr_in
*sin
;
2747 static char lsr
[44];
2749 struct cmsghdr
*cmsg
;
2750 struct sockaddr_in6
*sin6
;
2751 static char rhbuf
[1024];
2755 * Verify the arguments.
2764 /* init these just in case.... */
2771 switch (ai
->ai_family
) {
2774 lsrep
= lsrp
+ sizeof(lsr
);
2777 * Next, decide whether we have a loose source
2778 * route or a strict source route, and fill in
2779 * the begining of the option.
2783 *lsrp
++ = IPOPT_SSRR
;
2785 *lsrp
++ = IPOPT_LSRR
;
2788 lsrp
++; /* skip over length, we'll fill it in later */
2791 *protop
= IPPROTO_IP
;
2796 #ifdef IPV6_PKTOPTIONS
2798 cmsg
= inet6_rthdr_init(rhbuf
, IPV6_RTHDR_TYPE_0
);
2802 *protop
= IPPROTO_IPV6
;
2803 *optp
= IPV6_PKTOPTIONS
;
2814 memset(&hints
, 0, sizeof(hints
));
2815 hints
.ai_family
= ai
->ai_family
;
2816 hints
.ai_socktype
= SOCK_STREAM
;
2821 else for (cp2
= cp
; (c
= *cp2
) != '\0'; cp2
++) {
2826 } else if (c
== '@') {
2829 #if 0 /*colon conflicts with IPv6 address*/
2830 else if (c
== ':') {
2841 error
= getaddrinfo(cp
, NULL
, &hints
, &res
);
2843 fprintf(stderr
, "%s: %s\n", cp
, gai_strerror(error
));
2846 if (ai
->ai_family
!= res
->ai_family
) {
2850 if (ai
->ai_family
== AF_INET
) {
2852 * Check to make sure there is space for address
2854 if (lsrp
+ 4 > lsrep
) {
2858 sin
= (struct sockaddr_in
*)res
->ai_addr
;
2859 memcpy(lsrp
, &sin
->sin_addr
, sizeof(struct in_addr
));
2860 lsrp
+= sizeof(struct in_addr
);
2863 else if (ai
->ai_family
== AF_INET6
) {
2864 sin6
= (struct sockaddr_in6
*)res
->ai_addr
;
2865 inet6_rthdr_add(cmsg
, &sin6
->sin6_addr
,
2879 switch (ai
->ai_family
) {
2881 /* record the last hop */
2882 if (lsrp
+ 4 > lsrep
)
2884 sin
= (struct sockaddr_in
*)ai
->ai_addr
;
2885 memcpy(lsrp
, &sin
->sin_addr
, sizeof(struct in_addr
));
2886 lsrp
+= sizeof(struct in_addr
);
2887 lsr
[IPOPT_OLEN
] = lsrp
- lsr
;
2888 if (lsr
[IPOPT_OLEN
] <= 7 || lsr
[IPOPT_OLEN
] > 40)
2890 *lsrp
++ = IPOPT_NOP
; /*32bit word align*/
2896 inet6_rthdr_lasthop(cmsg
, IPV6_RTHDR_LOOSE
);
2897 len
= cmsg
->cmsg_len
;