* Copyright (c) 1988, 1990 Regents of the University of California.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
static char sccsid
[] = "@(#)commands.c 5.5 (Berkeley) 3/22/91";
#endif /* defined(unix) */
#include <netinet/in_systm.h>
# if (defined(vax) || defined(tahoe) || defined(hp300)) && !defined(ultrix)
# include <machine/endian.h>
#define MAXHOSTNAMELEN 64
#if defined(IPPROTO_IP) && defined(IP_TOS)
#endif /* defined(IPPROTO_IP) && defined(IP_TOS) */
static char _hostname
[MAXHOSTNAMELEN
];
char *name
; /* command name */
char *help
; /* help string (NULL for no help) */
int (*handler
)(); /* routine which executes command */
int needconnect
; /* Do we need to be connected to execute? */
static char saveline
[256];
register char *cp
, *cp2
, c
;
register char **argp
= margv
;
if (*cp
== '!') { /* Special case shell escape */
strcpy(saveline
, line
); /* save for shell command */
*argp
++ = "!"; /* No room in string to get this */
register int inquote
= 0;
for (cp2
= cp
; c
!= '\0'; c
= *++cp
) {
* Make a character string into a number.
* Todo: 1. Could take random integers (12, 0x12, 012, 0b1).
* Construct a control character sequence
* for a special character.
* The only way I could get the Sun 3.5 compiler
* if ((unsigned int)c >= 0x80)
* was to assign "c" to an unsigned int variable...
register unsigned int uic
= (unsigned int)c
;
if (c
== (cc_t
)_POSIX_VDISABLE
) {
buf
[1] = ((c
>>6)&07) + '0';
buf
[2] = ((c
>>3)&07) + '0';
} else if (uic
>= 0x20) {
* The following are data structures and routines for
char *name
; /* How user refers to it (case independent) */
char *help
; /* Help information (0 ==> no help) */
int needconnect
; /* Need to be connected */
int narg
; /* Number of arguments */
int (*handler
)(); /* Routine to perform (for special ops) */
int nbyte
; /* Number of bytes to send this command */
int what
; /* Character to be sent (<0 ==> special) */
send_dontcmd
P((char *)),
send_willcmd
P((char *)),
send_wontcmd
P((char *));
static struct sendlist Sendlist
[] = {
{ "ao", "Send Telnet Abort output", 1, 0, 0, 2, AO
},
{ "ayt", "Send Telnet 'Are You There'", 1, 0, 0, 2, AYT
},
{ "brk", "Send Telnet Break", 1, 0, 0, 2, BREAK
},
{ "break", 0, 1, 0, 0, 2, BREAK
},
{ "ec", "Send Telnet Erase Character", 1, 0, 0, 2, EC
},
{ "el", "Send Telnet Erase Line", 1, 0, 0, 2, EL
},
{ "escape", "Send current escape character", 1, 0, send_esc
, 1, 0 },
{ "ga", "Send Telnet 'Go Ahead' sequence", 1, 0, 0, 2, GA
},
{ "ip", "Send Telnet Interrupt Process", 1, 0, 0, 2, IP
},
{ "intp", 0, 1, 0, 0, 2, IP
},
{ "interrupt", 0, 1, 0, 0, 2, IP
},
{ "intr", 0, 1, 0, 0, 2, IP
},
{ "nop", "Send Telnet 'No operation'", 1, 0, 0, 2, NOP
},
{ "eor", "Send Telnet 'End of Record'", 1, 0, 0, 2, EOR
},
{ "abort", "Send Telnet 'Abort Process'", 1, 0, 0, 2, ABORT
},
{ "susp", "Send Telnet 'Suspend Process'", 1, 0, 0, 2, SUSP
},
{ "eof", "Send Telnet End of File Character", 1, 0, 0, 2, xEOF
},
{ "synch", "Perform Telnet 'Synch operation'", 1, 0, dosynch
, 2, 0 },
{ "getstatus", "Send request for STATUS", 1, 0, get_status
, 6, 0 },
{ "?", "Display send options", 0, 0, send_help
, 0, 0 },
{ "help", 0, 0, 0, send_help
, 0, 0 },
{ "do", 0, 0, 1, send_docmd
, 3, 0 },
{ "dont", 0, 0, 1, send_dontcmd
, 3, 0 },
{ "will", 0, 0, 1, send_willcmd
, 3, 0 },
{ "wont", 0, 0, 1, send_wontcmd
, 3, 0 },
#define GETSEND(name) ((struct sendlist *) genget(name, (char **) Sendlist, \
sizeof(struct sendlist)))
int count
; /* how many bytes we are going to need to send */
int question
= 0; /* was at least one argument a question */
struct sendlist
*s
; /* pointer to current command */
printf("need at least one argument for 'send' command\n");
printf("'send ?' for help\n");
* First, validate all the send arguments.
* In addition, we see how much space we are going to need, and
* whether or not we will be doing a "SYNCH" operation (which
* flushes the network queue).
for (i
= 1; i
< argc
; i
++) {
printf("Unknown send argument '%s'\n'send ?' for help.\n",
} else if (Ambiguous(s
)) {
printf("Ambiguous send argument '%s'\n'send ?' for help.\n",
if (i
+ s
->narg
>= argc
) {
"Need %d argument%s to 'send %s' command. 'send %s ?' for help.\n",
s
->narg
, s
->narg
== 1 ? "" : "s", s
->name
, s
->name
);
if (s
->handler
== send_help
) {
needconnect
+= s
->needconnect
;
if (!connected
&& needconnect
) {
printf("?Need to be connected first.\n");
printf("'send ?' for help\n");
/* Now, do we have enough room? */
printf("There is not enough room in the buffer TO the network\n");
printf("to process your request. Nothing will be done.\n");
printf("('send synch' will throw away most data in the network\n");
printf("buffer, if this might help.)\n");
/* OK, they are all OK, now go through again and actually send */
for (i
= 1; i
< argc
; i
++) {
if ((s
= GETSEND(argv
[i
])) == 0) {
fprintf(stderr
, "Telnet 'send' error - argument disappeared!\n");
success
+= (*s
->handler
)((s
->narg
> 0) ? argv
[i
+1] : 0,
(s
->narg
> 1) ? argv
[i
+2] : 0);
printoption("SENT", IAC
, s
->what
);
return (count
== success
);
return(send_tncmd(send_do
, "do", name
));
return(send_tncmd(send_dont
, "dont", name
));
return(send_tncmd(send_will
, "will", name
));
return(send_tncmd(send_wont
, "wont", name
));
send_tncmd(func
, cmd
, name
)
if (isprefix(name
, "help") || isprefix(name
, "?")) {
printf("Usage: send %s <option>\n", cmd
);
printf("Valid options are:\n\t");
for (cpp
= telopts
; *cpp
; cpp
++) {
cpp
= (char **)genget(name
, telopts
, sizeof(char *));
fprintf(stderr
,"'%s': ambiguous argument ('send %s ?' for help).\n",
fprintf(stderr
, "'%s': unknown argument ('send %s ?' for help).\n",
printf("?Need to be connected first.\n");
(*func
)(cpp
- telopts
, 1);
struct sendlist
*s
; /* pointer to current command */
for (s
= Sendlist
; s
->name
; s
++) {
printf("%-15s %s\n", s
->name
, s
->help
);
* The following are the routines and data structures referred
* to by the arguments to the "toggle" command.
(SetSockOpt(net
, SOL_SOCKET
, SO_DEBUG
, debug
)) < 0) {
perror("setsockopt (SO_DEBUG)");
if (net
> 0 && SetSockOpt(net
, SOL_SOCKET
, SO_DEBUG
, 0, 0) < 0)
perror("setsockopt (SO_DEBUG)");
printf("Cannot turn off socket debugging\n");
printf("Will send carriage returns as telnet <CR><LF>.\n");
printf("Will send carriage returns as telnet <CR><NUL>.\n");
if (my_want_state_is_will(TELOPT_BINARY
) &&
my_want_state_is_do(TELOPT_BINARY
)) {
} else if (my_want_state_is_wont(TELOPT_BINARY
) &&
my_want_state_is_dont(TELOPT_BINARY
)) {
if (my_want_state_is_will(TELOPT_BINARY
) &&
my_want_state_is_do(TELOPT_BINARY
)) {
printf("Already operating in binary mode with remote host.\n");
printf("Negotiating binary mode with remote host.\n");
if (my_want_state_is_wont(TELOPT_BINARY
) &&
my_want_state_is_dont(TELOPT_BINARY
)) {
printf("Already in network ascii mode with remote host.\n");
printf("Negotiating network ascii mode with remote host.\n");
val
= my_want_state_is_do(TELOPT_BINARY
) ? 0 : 1;
if (my_want_state_is_do(TELOPT_BINARY
)) {
printf("Already receiving in binary mode.\n");
printf("Negotiating binary mode on input.\n");
if (my_want_state_is_dont(TELOPT_BINARY
)) {
printf("Already receiving in network ascii mode.\n");
printf("Negotiating network ascii mode on input.\n");
val
= my_want_state_is_will(TELOPT_BINARY
) ? 0 : 1;
if (my_want_state_is_will(TELOPT_BINARY
)) {
printf("Already transmitting in binary mode.\n");
printf("Negotiating binary mode on output.\n");
if (my_want_state_is_wont(TELOPT_BINARY
)) {
printf("Already transmitting in network ascii mode.\n");
printf("Negotiating network ascii mode on output.\n");
extern int togglehelp
P((void));
#if defined(AUTHENTICATE)
extern int auth_togdebug
P((int));
extern int EncryptAutoEnc
P((int));
extern int EncryptAutoDec
P((int));
extern int EncryptDebug
P((int));
extern int EncryptVerbose
P((int));
char *name
; /* name of toggle */
char *help
; /* help message */
int (*handler
)(); /* routine to do actual setting */
static struct togglelist Togglelist
[] = {
"flushing of output when sending interrupt characters",
"flush output when sending interrupt characters" },
"automatic sending of interrupt characters in urgent mode",
"send interrupt characters in urgent mode" },
#if defined(AUTHENTICATE)
"automatic sending of login and/or authentication info",
"send login name and/or authentication information" },
"Toggle authentication debugging",
"print authentication debugging information" },
"automatic encryption of data stream",
"automatically encrypt output" },
"automatic decryption of data stream",
"automatically decrypt input" },
"Toggle verbose encryption output",
"print verbose encryption output" },
"Toggle encryption debugging",
"print encryption debugging information" },
"don't read ~/.telnetrc file",
"read ~/.telnetrc file" },
"sending and receiving of binary data",
"receiving of binary data",
"sending of binary data",
"sending carriage returns as telnet <CR><LF>",
"mapping of received carriage returns",
"map carriage return on output" },
"local recognition of certain control characters",
"recognize certain control characters" },
{ " ", "", 0 }, /* empty line */
#if defined(unix) && defined(TN3270)
"(debugging) toggle tracing of API transactions",
"trace API transactions" },
"(debugging) toggle printing of hexadecimal curses data",
"print hexadecimal representation of curses data" },
#endif /* defined(unix) && defined(TN3270) */
"turn on socket level debugging" },
"printing of hexadecimal network data (debugging)",
"print hexadecimal representation of network traffic" },
"output of \"netdata\" to user readable format (debugging)",
"print user readable output for \"netdata\"" },
"viewing of options processing (debugging)",
"show option processing" },
"(debugging) toggle printing of hexadecimal terminal data",
"print hexadecimal representation of terminal traffic" },
#endif /* defined(unix) */
for (c
= Togglelist
; c
->name
; c
++) {
printf("%-15s toggle %s\n", c
->name
, c
->help
);
printf("%-15s %s\n", "?", "display help information");
for (c
= Togglelist
; c
->name
; c
++) {
printf("%-15s %s %s\n", c
->name
, set
? "enable" : "disable",
#define GETTOGGLE(name) (struct togglelist *) \
genget(name, (char **) Togglelist, sizeof(struct togglelist))
"Need an argument to 'toggle' command. 'toggle ?' for help.\n");
fprintf(stderr
, "'%s': ambiguous argument ('toggle ?' for help).\n",
fprintf(stderr
, "'%s': unknown argument ('toggle ?' for help).\n",
*c
->variable
= !*c
->variable
; /* invert it */
if (c
->actionexplanation
) {
printf("%s %s.\n", *c
->variable
? "Will" : "Won't",
retval
&= (*c
->handler
)(-1);
* The following perform the "set" command.
struct termio new_tc
= { 0 };
char *help
; /* help information */
cc_t
*charp
; /* where it is located at */
static struct setlist Setlist
[] = {
{ "echo", "character to toggle local echoing on/off", 0, &echoc
},
{ "escape", "character to escape back to telnet command mode", 0, &escape
},
{ "rlogin", "rlogin escape character", 0, &rlogin
},
{ "tracefile", "file to write trace information to", SetNetTrace
, (cc_t
*)NetTraceFile
},
{ " ", "The following need 'localchars' to be toggled true", 0, 0 },
{ "flushoutput", "character to cause an Abort Output", 0, termFlushCharp
},
{ "interrupt", "character to cause an Interrupt Process", 0, termIntCharp
},
{ "quit", "character to cause an Abort process", 0, termQuitCharp
},
{ "eof", "character to cause an EOF ", 0, termEofCharp
},
{ " ", "The following are for local editing in linemode", 0, 0 },
{ "erase", "character to use to erase a character", 0, termEraseCharp
},
{ "kill", "character to use to erase a line", 0, termKillCharp
},
{ "lnext", "character to use for literal next", 0, termLiteralNextCharp
},
{ "susp", "character to cause a Suspend Process", 0, termSuspCharp
},
{ "reprint", "character to use for line reprint", 0, termRprntCharp
},
{ "worderase", "character to use to erase a word", 0, termWerasCharp
},
{ "start", "character to use for XON", 0, termStartCharp
},
{ "stop", "character to use for XOFF", 0, termStopCharp
},
{ "forw1", "alternate end of line character", 0, termForw1Charp
},
{ "forw2", "alternate end of line character", 0, termForw2Charp
},
{ "ayt", "alternate AYT character", 0, termAytCharp
},
#if defined(CRAY) && !defined(__STDC__)
/* Work around compiler bug in pcc 4.1.5 */
Setlist
[N
+0].charp
= &termFlushChar
;
Setlist
[N
+1].charp
= &termIntChar
;
Setlist
[N
+2].charp
= &termQuitChar
;
Setlist
[N
+3].charp
= &termEofChar
;
Setlist
[N
+6].charp
= &termEraseChar
;
Setlist
[N
+7].charp
= &termKillChar
;
Setlist
[N
+8].charp
= &termLiteralNextChar
;
Setlist
[N
+9].charp
= &termSuspChar
;
Setlist
[N
+10].charp
= &termRprntChar
;
Setlist
[N
+11].charp
= &termWerasChar
;
Setlist
[N
+12].charp
= &termStartChar
;
Setlist
[N
+13].charp
= &termStopChar
;
Setlist
[N
+14].charp
= &termForw1Char
;
Setlist
[N
+15].charp
= &termForw2Char
;
Setlist
[N
+16].charp
= &termAytChar
;
#endif /* defined(CRAY) && !defined(__STDC__) */
return (struct setlist
*)
genget(name
, (char **) Setlist
, sizeof(struct setlist
));
if (rlogin
!= _POSIX_VDISABLE
) {
rlogin
= (s
&& *s
) ? special(s
) : _POSIX_VDISABLE
;
printf("Telnet rlogin escape character is '%s'.\n",
escape
= (s
&& *s
) ? special(s
) : _POSIX_VDISABLE
;
printf("Telnet escape character is '%s'.\n", control(escape
));
if (argc
< 2 || argc
> 3) {
printf("Format is 'set Name Value'\n'set ?' for help.\n");
if ((argc
== 2) && (isprefix(argv
[1], "?") || isprefix(argv
[1], "help"))) {
for (ct
= Setlist
; ct
->name
; ct
++)
printf("%-15s %s\n", ct
->name
, ct
->help
);
printf("%-15s %s\n", "?", "display help information");
fprintf(stderr
, "'%s': unknown argument ('set ?' for help).\n",
} else if (Ambiguous(c
)) {
fprintf(stderr
, "'%s': ambiguous argument ('set ?' for help).\n",
if ((argc
== 2) || (strcmp("on", argv
[2]) == 0))
else if (strcmp("off", argv
[2]) == 0)
printf("Format is 'set togglename [on|off]'\n'set ?' for help.\n");
if (c
->actionexplanation
) {
printf("%s %s.\n", *c
->variable
? "Will" : "Won't",
printf("Format is 'set Name Value'\n'set ?' for help.\n");
} else if (Ambiguous(ct
)) {
fprintf(stderr
, "'%s': ambiguous argument ('set ?' for help).\n",
} else if (ct
->handler
) {
printf("%s set to \"%s\".\n", ct
->name
, (char *)ct
->charp
);
if (strcmp("off", argv
[2])) {
value
= special(argv
[2]);
*(ct
->charp
) = (cc_t
)value
;
printf("%s character is '%s'.\n", ct
->name
, control(*(ct
->charp
)));
"Need an argument to 'unset' command. 'unset ?' for help.\n");
if (isprefix(argv
[1], "?") || isprefix(argv
[1], "help")) {
for (ct
= Setlist
; ct
->name
; ct
++)
printf("%-15s %s\n", ct
->name
, ct
->help
);
printf("%-15s %s\n", "?", "display help information");
fprintf(stderr
, "'%s': unknown argument ('unset ?' for help).\n",
} else if (Ambiguous(c
)) {
fprintf(stderr
, "'%s': ambiguous argument ('unset ?' for help).\n",
if (c
->actionexplanation
) {
printf("%s %s.\n", *c
->variable
? "Will" : "Won't",
} else if (Ambiguous(ct
)) {
fprintf(stderr
, "'%s': ambiguous argument ('unset ?' for help).\n",
} else if (ct
->handler
) {
printf("%s reset to \"%s\".\n", ct
->name
, (char *)ct
->charp
);
*(ct
->charp
) = _POSIX_VDISABLE
;
printf("%s character is '%s'.\n", ct
->name
, control(*(ct
->charp
)));
* The following are the data structures and routines for the
extern int kludgelinemode
;
send_wont(TELOPT_LINEMODE
, 1);
send_dont(TELOPT_SGA
, 1);
send_dont(TELOPT_ECHO
, 1);
send_dont(TELOPT_SGA
, 1);
send_will(TELOPT_LINEMODE
, 1);
send_dont(TELOPT_ECHO
, 1);
send_wont(TELOPT_LINEMODE
, 1);
if (my_want_state_is_wont(TELOPT_LINEMODE
)) {
printf("?Need to have LINEMODE option enabled first.\n");
printf("'mode ?' for help.\n");
char *name
; /* command name */
char *help
; /* help string */
int (*handler
)(); /* routine which executes command */
int needconnect
; /* Do we need to be connected to execute? */
static struct modelist ModeList
[] = {
{ "character", "Disable LINEMODE option", docharmode
, 1 },
{ "", "(or disable obsolete line-by-line mode)", 0 },
{ "line", "Enable LINEMODE option", dolinemode
, 1 },
{ "", "(or enable obsolete line-by-line mode)", 0 },
{ "", "These require the LINEMODE option to be enabled", 0 },
{ "isig", "Enable signal trapping", setmode
, 1, MODE_TRAPSIG
},
{ "+isig", 0, setmode
, 1, MODE_TRAPSIG
},
{ "-isig", "Disable signal trapping", clearmode
, 1, MODE_TRAPSIG
},
{ "edit", "Enable character editing", setmode
, 1, MODE_EDIT
},
{ "+edit", 0, setmode
, 1, MODE_EDIT
},
{ "-edit", "Disable character editing", clearmode
, 1, MODE_EDIT
},
{ "softtabs", "Enable tab expansion", setmode
, 1, MODE_SOFT_TAB
},
{ "+softtabs", 0, setmode
, 1, MODE_SOFT_TAB
},
{ "-softtabs", "Disable character editing", clearmode
, 1, MODE_SOFT_TAB
},
{ "litecho", "Enable literal character echo", setmode
, 1, MODE_LIT_ECHO
},
{ "+litecho", 0, setmode
, 1, MODE_LIT_ECHO
},
{ "-litecho", "Disable literal character echo", clearmode
, 1, MODE_LIT_ECHO
},
{ "help", 0, modehelp
, 0 },
{ "kludgeline", 0, dokludgemode
, 1 },
{ "?", "Print help information", modehelp
, 0 },
printf("format is: 'mode Mode', where 'Mode' is one of:\n\n");
for (mt
= ModeList
; mt
->name
; mt
++) {
printf("%-15s %s\n", mt
->name
, mt
->help
);
#define GETMODECMD(name) (struct modelist *) \
genget(name, (char **) ModeList, sizeof(struct modelist))
printf("'mode' command requires an argument\n");
printf("'mode ?' for help.\n");
} else if ((mt
= GETMODECMD(argv
[1])) == 0) {
fprintf(stderr
, "Unknown mode '%s' ('mode ?' for help).\n", argv
[1]);
} else if (Ambiguous(mt
)) {
fprintf(stderr
, "Ambiguous mode '%s' ('mode ?' for help).\n", argv
[1]);
} else if (mt
->needconnect
&& !connected
) {
printf("?Need to be connected first.\n");
printf("'mode ?' for help.\n");
} else if (mt
->handler
) {
return (*mt
->handler
)(mt
->arg1
);
* The following data structures and routines implement the
#define dotog(tl) if (tl->variable && tl->actionexplanation) { \
printf(" %s.\n", tl->actionexplanation); \
#define doset(sl) if (sl->name && *sl->name != ' ') { \
printf("%-15s [%s]\n", sl->name, control(*sl->charp)); \
printf("%-15s \"%s\"\n", sl->name, (char *)sl->charp); \
for (tl
= Togglelist
; tl
->name
; tl
++) {
for (sl
= Setlist
; sl
->name
; sl
++) {
for (i
= 1; i
< argc
; i
++) {
if (Ambiguous(sl
) || Ambiguous(tl
)) {
printf("?Ambiguous argument '%s'.\n", argv
[i
]);
printf("?Unknown argument '%s'.\n", argv
[i
]);
* The following are the data structures, and many of the routines,
* relating to command processing.
* Set the escape character.
"Deprecated usage - please use 'set escape%s%s' in the future.\n",
(argc
> 2)? " ":"", (argc
> 2)? argv
[1]: "");
printf("new escape character: ");
(void) fgets(buf
, sizeof(buf
), stdin
);
printf("Escape character is '%s'.\n", control(escape
));
printf("Deprecated usage - please use 'toggle crmod' in the future.\n");
printf("%s map carriage return on output.\n", crmod
? "Will" : "Won't");
long oldrows
, oldcols
, newrows
, newcols
, err
;
err
= TerminalWindowSize(&oldrows
, &oldcols
);
err
+= TerminalWindowSize(&newrows
, &newcols
);
((oldrows
!= newrows
) || (oldcols
!= newcols
))) {
/* reget parameters in case they were changed */
printf("Suspend is not supported. Try the '!' command instead\n");
* Fire up the shell in the child.
register char *shellp
, *shellname
;
shellp
= getenv("SHELL");
if ((shellname
= rindex(shellp
, '/')) == 0)
execl(shellp
, shellname
, "-c", &saveline
[1], 0);
execl(shellp
, shellname
, 0);
(void)wait((int *)0); /* Wait for the shell to complete */
#endif /* !defined(TN3270) */
int argc
; /* Number of arguments */
char *argv
[]; /* arguments */
extern int resettermname
;
printf("Connection closed.\n");
#if defined(AUTHENTICATE) || defined(ENCRYPT)
auth_encrypt_connect(connected
);
SetIn3270(); /* Get out of 3270 mode */
#endif /* defined(TN3270) */
if ((argc
!= 2) || (strcmp(argv
[1], "fromquit") != 0)) {
return 1; /* Keep lint, etc., happy */
(void) call(bye
, "bye", "fromquit", 0);
send_do(TELOPT_LOGOUT
, 1);
struct slclist SlcList
[] = {
{ "export", "Use local special character definitions",
{ "import", "Use remote special character definitions",
{ "check", "Verify remote special character definitions",
{ "help", 0, slc_help
, 0 },
{ "?", "Print help information", slc_help
, 0 },
for (c
= SlcList
; c
->name
; c
++) {
printf("%-15s %s\n", c
->name
, c
->help
);
return (struct slclist
*)
genget(name
, (char **) SlcList
, sizeof(struct slclist
));
"Need an argument to 'slc' command. 'slc ?' for help.\n");
fprintf(stderr
, "'%s': unknown argument ('slc ?' for help).\n",
fprintf(stderr
, "'%s': ambiguous argument ('slc ?' for help).\n",
env_define
P((unsigned char *, unsigned char *));
env_undefine
P((unsigned char *)),
env_export
P((unsigned char *)),
env_unexport
P((unsigned char *)),
env_send
P((unsigned char *)),
struct envlist EnvList
[] = {
{ "define", "Define an environment variable",
(void (*)())env_define
, 2 },
{ "undefine", "Undefine an environment variable",
{ "export", "Mark an environment variable for automatic export",
{ "unexport", "Don't mark an environment variable for automatic export",
{ "send", "Send an environment variable", env_send
, 1 },
{ "list", "List the current environment variables",
{ "help", 0, env_help
, 0 },
{ "?", "Print help information", env_help
, 0 },
for (c
= EnvList
; c
->name
; c
++) {
printf("%-15s %s\n", c
->name
, c
->help
);
return (struct envlist
*)
genget(name
, (char **) EnvList
, sizeof(struct envlist
));
"Need an argument to 'environ' command. 'environ ?' for help.\n");
fprintf(stderr
, "'%s': unknown argument ('environ ?' for help).\n",
fprintf(stderr
, "'%s': ambiguous argument ('environ ?' for help).\n",
if (c
->narg
+ 2 != argc
) {
"Need %s%d argument%s to 'environ %s' command. 'environ ?' for help.\n",
c
->narg
< argc
+ 2 ? "only " : "",
c
->narg
, c
->narg
== 1 ? "" : "s", c
->name
);
(*c
->handler
)(argv
[2], argv
[3]);
struct env_lst
*next
; /* pointer to next structure */
struct env_lst
*prev
; /* pointer to next structure */
unsigned char *var
; /* pointer to variable name */
unsigned char *value
; /* pointer to varialbe value */
int export
; /* 1 -> export with default list of variables */
struct env_lst envlisthead
;
register struct env_lst
*ep
;
for (ep
= envlisthead
.next
; ep
; ep
= ep
->next
) {
if (strcmp((char *)ep
->var
, (char *)var
) == 0)
register char **epp
, *cp
;
register struct env_lst
*ep
;
for (epp
= environ
; *epp
; epp
++) {
if (cp
= index(*epp
, '=')) {
ep
= env_define((unsigned char *)*epp
,
* Special case for DISPLAY variable. If it is ":0.0" or
* "unix:0.0", we have to get rid of "unix" and insert our
if ((ep
= env_find("DISPLAY"))
|| (strncmp((char *)ep
->value
, "unix:", 5) == 0))) {
char *cp2
= index((char *)ep
->value
, ':');
cp
= (char *)malloc(strlen(hbuf
) + strlen(cp2
) + 1);
sprintf((char *)cp
, "%s%s", hbuf
, cp2
);
ep
->value
= (unsigned char *)cp
;
* If USER is not defined, but LOGNAME is, then add
* USER with the value from LOGNAME. By default, we
* don't export the USER variable.
if ((env_find("USER") == NULL
) && (ep
= env_find("LOGNAME"))) {
env_define((unsigned char *)"USER", ep
->value
);
env_unexport((unsigned char *)"USER");
env_export((unsigned char *)"DISPLAY");
env_export((unsigned char *)"PRINTER");
unsigned char *var
, *value
;
register struct env_lst
*ep
;
if (ep
= env_find(var
)) {
ep
= (struct env_lst
*)malloc(sizeof(struct env_lst
));
ep
->next
= envlisthead
.next
;
ep
->var
= (unsigned char *)strdup((char *)var
);
ep
->value
= (unsigned char *)strdup((char *)value
);
register struct env_lst
*ep
;
if (ep
= env_find(var
)) {
ep
->prev
->next
= ep
->next
;
ep
->next
->prev
= ep
->prev
;
register struct env_lst
*ep
;
register struct env_lst
*ep
;
register struct env_lst
*ep
;
if (my_state_is_wont(TELOPT_ENVIRON
)) {
"Cannot send '%s': Telnet ENVIRON option not enabled\n",
fprintf(stderr
, "Cannot send '%s': variable not defined\n",
register struct env_lst
*ep
;
for (ep
= envlisthead
.next
; ep
; ep
= ep
->next
) {
printf("%c %-20s %s\n", ep
->export
? '*' : ' ',
static struct env_lst
*nep
= NULL
;
while (nep
= nep
->next
) {
register struct env_lst
*ep
;
#if defined(AUTHENTICATE)
* The AUTHENTICATE command.
struct authlist AuthList
[] = {
{ "status", "Display current status of authentication information",
{ "disable", "Disable an authentication type ('auth disable ?' for more)",
{ "enable", "Enable an authentication type ('auth enable ?' for more)",
{ "help", 0, auth_help
, 0 },
{ "?", "Print help information", auth_help
, 0 },
for (c
= AuthList
; c
->name
; c
++) {
printf("%-15s %s\n", c
->name
, c
->help
);
genget(argv
[1], (char **) AuthList
, sizeof(struct authlist
));
fprintf(stderr
, "'%s': unknown argument ('auth ?' for help).\n",
fprintf(stderr
, "'%s': ambiguous argument ('auth ?' for help).\n",
if (c
->narg
+ 2 != argc
) {
"Need %s%d argument%s to 'auth %s' command. 'auth ?' for help.\n",
c
->narg
< argc
+ 2 ? "only " : "",
c
->narg
, c
->narg
== 1 ? "" : "s", c
->name
);
return((*c
->handler
)(argv
[2], argv
[3]));
EncryptEnable
P((char *, char *)),
EncryptDisable
P((char *, char *)),
EncryptType
P((char *, char *)),
EncryptStart
P((char *)),
EncryptStartInput
P((void)),
EncryptStartOutput
P((void)),
EncryptStopInput
P((void)),
EncryptStopOutput
P((void)),
struct encryptlist EncryptList
[] = {
{ "enable", "Enable encryption. ('encrypt enable ?' for more)",
EncryptEnable
, 1, 1, 2 },
{ "disable", "Disable encryption. ('encrypt enable ?' for more)",
EncryptDisable
, 0, 1, 2 },
{ "type", "Set encryptiong type. ('encrypt type ?' for more)",
{ "start", "Start encryption. ('encrypt start ?' for more)",
{ "stop", "Stop encryption. ('encrypt stop ?' for more)",
{ "input", "Start encrypting the input stream",
EncryptStartInput
, 1, 0, 0 },
{ "-input", "Stop encrypting the input stream",
EncryptStopInput
, 1, 0, 0 },
{ "output", "Start encrypting the output stream",
EncryptStartOutput
, 1, 0, 0 },
{ "-output", "Stop encrypting the output stream",
EncryptStopOutput
, 1, 0, 0 },
{ "status", "Display current status of authentication information",
EncryptStatus
, 0, 0, 0 },
{ "help", 0, EncryptHelp
, 0, 0, 0 },
{ "?", "Print help information", EncryptHelp
, 0, 0, 0 },
for (c
= EncryptList
; c
->name
; c
++) {
printf("%-15s %s\n", c
->name
, c
->help
);
c
= (struct encryptlist
*)
genget(argv
[1], (char **) EncryptList
, sizeof(struct encryptlist
));
fprintf(stderr
, "'%s': unknown argument ('encrypt ?' for help).\n",
fprintf(stderr
, "'%s': ambiguous argument ('encrypt ?' for help).\n",
if (argc
< c
->minarg
|| argc
> c
->maxarg
) {
if (c
->minarg
== c
->maxarg
) {
fprintf(stderr
, "Need %s%d argument%s ",
c
->minarg
< argc
? "only " : "", c
->minarg
,
c
->minarg
== 1 ? "" : "s");
fprintf(stderr
, "Need %s%d-%d arguments ",
c
->maxarg
< argc
? "only " : "", c
->minarg
, c
->maxarg
);
fprintf(stderr
, "to 'encrypt %s' command. 'encrypt ?' for help.\n",
if (c
->needconnect
&& !connected
) {
if (!(argc
&& (isprefix(argv
[2], "help") || isprefix(argv
[2], "?")))) {
printf("?Need to be connected first.\n");
return ((*c
->handler
)(argc
> 0 ? argv
[2] : 0,
argc
> 2 ? argv
[4] : 0));
#if defined(unix) && defined(TN3270)
char *oflgs
[] = { "read-only", "write-only", "read-write" };
res
= fcntl(fd
, F_GETOWN
, 0);
printf("\tOwner is %d.\n", res
);
res
= fcntl(fd
, F_GETFL
, 0);
printf("\tFlags are 0x%x: %s\n", res
, oflgs
[res
]);
#endif /* defined(unix) && defined(TN3270) */
* Print status about the connection.
printf("Connected to %s.\n", hostname
);
if ((argc
< 2) || strcmp(argv
[1], "notmuch")) {
int mode
= getconnmode();
if (my_want_state_is_will(TELOPT_LINEMODE
)) {
printf("Operating with LINEMODE option\n");
printf("%s line editing\n", (mode
&MODE_EDIT
) ? "Local" : "No");
printf("%s catching of signals\n",
(mode
&MODE_TRAPSIG
) ? "Local" : "No");
} else if (kludgelinemode
&& my_want_state_is_dont(TELOPT_SGA
)) {
printf("Operating in obsolete linemode\n");
printf("Operating in single character mode\n");
printf("Catching signals locally\n");
printf("%s character echo\n", (mode
&MODE_ECHO
) ? "Local" : "Remote");
if (my_want_state_is_will(TELOPT_LFLOW
))
printf("%s flow control\n", (mode
&MODE_FLOW
) ? "Local" : "No");
printf("No connection.\n");
printf("Escape character is '%s'.\n", control(escape
));
# else /* !defined(TN3270) */
if ((!In3270
) && ((argc
< 2) || strcmp(argv
[1], "notmuch"))) {
printf("Escape character is '%s'.\n", control(escape
));
if ((argc
>= 2) && !strcmp(argv
[1], "everything")) {
printf("SIGIO received %d time%s.\n",
sigiocount
, (sigiocount
== 1)? "":"s");
printf("Process ID %d, process group %d.\n",
getpid(), getpgrp(getpid()));
printf("Terminal input:\n");
printf("Terminal output:\n");
printf("Network socket:\n");
if (In3270
&& transcom
) {
printf("Transparent mode command is '%s'.\n", transcom
);
# endif /* defined(unix) */
# endif /* defined(TN3270) */
* Function that gets called when SIGINFO is received.
(void) call(status
, "status", "notmuch", 0);
register struct hostent
*host
= 0;
unsigned long temp
, inet_addr();
extern char *inet_ntoa();
#if defined(IP_OPTIONS) && defined(IPPROTO_IP)
char *srp
= 0, *strrchr();
unsigned long sourceroute(), srlen
;
char *cmd
, *hostp
= 0, *portp
= 0, *user
= 0;
/* clear the socket address prior to use */
bzero((char *)&sin
, sizeof(sin
));
printf("?Already connected to %s\n", hostname
);
(void) strcpy(line
, "open ");
(void) fgets(&line
[strlen(line
)], sizeof(line
) - strlen(line
), stdin
);
if (isprefix(*argv
, "help") || isprefix(*argv
, "?"))
if (strcmp(*argv
, "-l") == 0) {
if (strcmp(*argv
, "-a") == 0) {
printf("usage: %s [-l user] [-a] host-name [port]\n", cmd
);
#if defined(IP_OPTIONS) && defined(IPPROTO_IP)
if (hostp
[0] == '@' || hostp
[0] == '!') {
if ((hostname
= strrchr(hostp
, ':')) == NULL
)
hostname
= strrchr(hostp
, '@');
temp
= sourceroute(hostp
, &srp
, &srlen
);
printf("Bad source route option: %s\n", hostp
);
sin
.sin_addr
.s_addr
= temp
;
sin
.sin_family
= AF_INET
;
if (temp
!= (unsigned long) -1) {
sin
.sin_addr
.s_addr
= temp
;
sin
.sin_family
= AF_INET
;
(void) strcpy(_hostname
, hostp
);
host
= gethostbyname(hostp
);
sin
.sin_family
= host
->h_addrtype
;
#if defined(h_addr) /* In 4.3, this is a #define */
memcpy((caddr_t
)&sin
.sin_addr
,
host
->h_addr_list
[0], host
->h_length
);
#else /* defined(h_addr) */
memcpy((caddr_t
)&sin
.sin_addr
, host
->h_addr
, host
->h_length
);
#endif /* defined(h_addr) */
strncpy(_hostname
, host
->h_name
, sizeof(_hostname
));
_hostname
[sizeof(_hostname
)-1] = '\0';
#if defined(IP_OPTIONS) && defined(IPPROTO_IP)
sin
.sin_port
= atoi(portp
);
sp
= getservbyname(portp
, "tcp");
sin
.sin_port
= sp
->s_port
;
printf("%s: bad port number\n", portp
);
#endif /* !defined(htons) */
sin
.sin_port
= htons(sin
.sin_port
);
sp
= getservbyname("telnet", "tcp");
fprintf(stderr
, "telnet: tcp/telnet: unknown service\n");
sin
.sin_port
= sp
->s_port
;
printf("Trying %s...\n", inet_ntoa(sin
.sin_addr
));
net
= socket(AF_INET
, SOCK_STREAM
, 0);
perror("telnet: socket");
#if defined(IP_OPTIONS) && defined(IPPROTO_IP)
if (srp
&& setsockopt(net
, IPPROTO_IP
, IP_OPTIONS
, (char *)srp
, srlen
) < 0)
perror("setsockopt (IP_OPTIONS)");
#if defined(IPPROTO_IP) && defined(IP_TOS)
if (tos
< 0 && (tp
= gettosbyname("telnet", "tcp")))
tos
= 020; /* Low Delay bit */
&& (setsockopt(net
, IPPROTO_IP
, IP_TOS
, &tos
, sizeof(int)) < 0)
&& (errno
!= ENOPROTOOPT
))
perror("telnet: setsockopt (IP_TOS) (ignored)");
#endif /* defined(IPPROTO_IP) && defined(IP_TOS) */
if (debug
&& SetSockOpt(net
, SOL_SOCKET
, SO_DEBUG
, 1) < 0) {
perror("setsockopt (SO_DEBUG)");
if (connect(net
, (struct sockaddr
*)&sin
, sizeof (sin
)) < 0) {
#if defined(h_addr) /* In 4.3, this is a #define */
if (host
&& host
->h_addr_list
[1]) {
fprintf(stderr
, "telnet: connect to address %s: ",
inet_ntoa(sin
.sin_addr
));
memcpy((caddr_t
)&sin
.sin_addr
,
host
->h_addr_list
[0], host
->h_length
);
#endif /* defined(h_addr) */
perror("telnet: Unable to connect to remote host");
#if defined(AUTHENTICATE) || defined(ENCRYPT)
auth_encrypt_connect(connected
);
} while (connected
== 0);
if (autologin
&& user
== NULL
) {
(pw
= getpwnam(user
)) && pw
->pw_uid
!= getuid()) {
if (pw
= getpwuid(getuid()))
env_define((unsigned char *)"USER", (unsigned char *)user
);
env_export((unsigned char *)"USER");
(void) call(status
, "status", "notmuch", 0);
if (setjmp(peerdied
) == 0)
ExitString("Connection closed by foreign host.\n",1);
#define HELPINDENT (sizeof ("connect"))
openhelp
[] = "connect to a site",
closehelp
[] = "close current connection",
logouthelp
[] = "forcibly logout remote user and close the connection",
quithelp
[] = "exit telnet",
statushelp
[] = "print status information",
helphelp
[] = "print help information",
sendhelp
[] = "transmit special characters ('send ?' for more)",
sethelp
[] = "set operating parameters ('set ?' for more)",
unsethelp
[] = "unset operating parameters ('unset ?' for more)",
togglestring
[] ="toggle operating parameters ('toggle ?' for more)",
slchelp
[] = "change state of special charaters ('slc ?' for more)",
displayhelp
[] = "display operating parameters",
#if defined(TN3270) && defined(unix)
transcomhelp
[] = "specify Unix command for transparent mode pipe",
#endif /* defined(TN3270) && defined(unix) */
#if defined(AUTHENTICATE)
authhelp
[] = "turn on (off) authentication ('auth ?' for more)",
encrypthelp
[] = "turn on (off) encryption ('encrypt ?' for more)",
zhelp
[] = "suspend telnet",
#endif /* defined(unix) */
shellhelp
[] = "invoke a subshell",
envhelp
[] = "change environment variables ('environ ?' for more)",
modestring
[] = "try to enter line or character mode ('mode ?' for more)";
static Command cmdtab
[] = {
{ "close", closehelp
, bye
, 1 },
{ "logout", logouthelp
, logout
, 1 },
{ "display", displayhelp
, display
, 0 },
{ "mode", modestring
, modecmd
, 0 },
{ "open", openhelp
, tn
, 0 },
{ "quit", quithelp
, quit
, 0 },
{ "send", sendhelp
, sendcmd
, 0 },
{ "set", sethelp
, setcmd
, 0 },
{ "unset", unsethelp
, unsetcmd
, 0 },
{ "status", statushelp
, status
, 0 },
{ "toggle", togglestring
, toggle
, 0 },
{ "slc", slchelp
, slccmd
, 0 },
#if defined(TN3270) && defined(unix)
{ "transcom", transcomhelp
, settranscom
, 0 },
#endif /* defined(TN3270) && defined(unix) */
#if defined(AUTHENTICATE)
{ "auth", authhelp
, auth_cmd
, 0 },
{ "encrypt", encrypthelp
, encrypt_cmd
, 0 },
{ "z", zhelp
, suspend
, 0 },
#endif /* defined(unix) */
{ "!", shellhelp
, shell
, 1 },
{ "!", shellhelp
, shell
, 0 },
{ "environ", envhelp
, env_cmd
, 0 },
{ "?", helphelp
, help
, 0 },
static char crmodhelp
[] = "deprecated command -- use 'toggle crmod' instead";
static char escapehelp
[] = "deprecated command -- use 'set escape' instead";
static Command cmdtab2
[] = {
{ "escape", escapehelp
, setescape
, 0 },
{ "crmod", crmodhelp
, togcrmod
, 0 },
* Call routine with argc, argv set from args (terminated by 0).
typedef int (*intrtn_t
)();
routine
= (va_arg(ap
, intrtn_t
));
while ((args
[argno
++] = va_arg(ap
, char *)) != 0) {
return (*routine
)(argno
-1, args
);
if (cm
= (Command
*) genget(name
, (char **) cmdtab
, sizeof(Command
)))
return (Command
*) genget(name
, (char **) cmdtab2
, sizeof(Command
));
(void) signal(SIGINT
, SIG_DFL
);
(void) signal(SIGQUIT
, SIG_DFL
);
#endif /* defined(unix) */
if (rlogin
== _POSIX_VDISABLE
)
while (cnt
> 0 && (*cp
++ = *tbuf
++) != '\n')
if (cp
== line
|| *--cp
!= '\n' || cp
== line
)
if (rlogin
== _POSIX_VDISABLE
)
if (rlogin
!= _POSIX_VDISABLE
)
if (fgets(line
, sizeof(line
), stdin
) == NULL
) {
if (feof(stdin
) || ferror(stdin
)) {
printf("?Ambiguous command\n");
printf("?Invalid command\n");
if (c
->needconnect
&& !connected
) {
printf("?Need to be connected first.\n");
if ((*c
->handler
)(margc
, margv
)) {
#else /* defined(TN3270) */
#endif /* defined(TN3270) */
printf("Commands may be abbreviated. Commands are:\n\n");
for (c
= cmdtab
; c
->name
; c
++)
printf("%-*s\t%s\n", HELPINDENT
, c
->name
,
printf("?Ambiguous help command %s\n", arg
);
else if (c
== (Command
*)0)
printf("?Invalid help command %s\n", arg
);
strcat(rcbuf
, "/.telnetrc");
if ((rcfile
= fopen(rcname
, "r")) == 0) {
if (fgets(line
, sizeof(line
), rcfile
) == NULL
)
if (strncasecmp(line
, m1
, l1
) == 0)
strncpy(line
, &line
[l1
], sizeof(line
) - l1
);
else if (strncasecmp(line
, m2
, l2
) == 0)
strncpy(line
, &line
[l2
], sizeof(line
) - l2
);
else if (strncasecmp(line
, "DEFAULT", 7) == 0)
strncpy(line
, &line
[7], sizeof(line
) - 7);
if (line
[0] != ' ' && line
[0] != '\t' && line
[0] != '\n')
printf("?Ambiguous command: %s\n", margv
[0]);
printf("?Invalid command: %s\n", margv
[0]);
* This should never happen...
if (c
->needconnect
&& !connected
) {
printf("?Need to be connected first for %s.\n", margv
[0]);
(*c
->handler
)(margc
, margv
);
#if defined(IP_OPTIONS) && defined(IPPROTO_IP)
* Source route is handed in as
* [!]@hop1@hop2...[@|:]dst
* If the leading ! is present, it is a
* strict source route, otherwise it is
* assmed to be a loose source route.
* We fill in the source route option as
* and return a pointer to hop1, which will
* be the address to connect() to.
* arg: pointer to route list to decipher
* cpp: If *cpp is not equal to NULL, this is a
* pointer to a pointer to a character array
* that should be filled in with the option.
* lenp: pointer to an integer that contains the
* length of *cpp if *cpp != NULL.
* Returns the address of the host to connect to. If the
* return value is -1, there was a syntax error in the
* option, either unknown characters, or too many hosts.
* If the return value is 0, one of the hostnames in the
* path is unknown, and *cpp is set to point to the bad
* *cpp: If *cpp was equal to NULL, it will be filled
* in with a pointer to our static area that has
* the option filled in. This will be 32bit aligned.
* *lenp: This will be filled in with how long the option
sourceroute(arg
, cpp
, lenp
)
char *cp
, *cp2
, *lsrp
, *lsrep
;
register struct hostent
*host
= 0;
* Verify the arguments, and make sure we have
* at least 7 bytes for the option.
if (cpp
== NULL
|| lenp
== NULL
)
return((unsigned long)-1);
if (*cpp
!= NULL
&& *lenp
< 7)
return((unsigned long)-1);
* Decide whether we have a buffer passed to us,
* or if we need to use our own static buffer.
* Next, decide whether we have a loose source
* route or a strict source route, and fill in
* the begining of the option.
return((unsigned long)-1);
lsrp
++; /* skip over length, we'll fill it in later */
else for (cp2
= cp
; c
= *cp2
; cp2
++) {
if ((tmp
= inet_addr(cp
)) != -1) {
} else if (host
= gethostbyname(cp
)) {
memcpy((caddr_t
)&sin_addr
,
host
->h_addr_list
[0], host
->h_length
);
memcpy((caddr_t
)&sin_addr
, host
->h_addr
, host
->h_length
);
memcpy(lsrp
, (char *)&sin_addr
, 4);
* Check to make sure there is space for next address
return((unsigned long)-1);
if ((*(*cpp
+IPOPT_OLEN
) = lsrp
- *cpp
) <= 7) {
return((unsigned long)-1);
*lsrp
++ = IPOPT_NOP
; /* 32 bit word align it */