/*
* Copyright (C) 1997 and 1998 WIDE Project.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 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. Neither the name of the project 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 PROJECT 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 PROJECT 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
* SUCH DAMAGE.
*/
/*
* Copyright (c) 1988, 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 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. 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
* SUCH DAMAGE.
*/
typedef struct {
const char *name; /* command name */
const char *help; /* help string (NULL for no help) */
int (*handler) /* routine which executes command */
(int, char *[]);
int needconnect; /* Do we need to be connected to execute? */
} Command;
margc = 0;
margv[0] = NULL;
cp = line;
if (*cp == '!') { /* Special case shell escape */
/* save for shell command */
strlcpy(saveline, line, sizeof(saveline));
if (!addarg(bang))
return;
cp++;
}
while ((c = *cp) != '\0') {
int inquote = 0;
while (isspace((unsigned char)c))
c = *++cp;
if (c == '\0')
break;
if (!addarg(cp))
return;
for (cp2 = cp; c != '\0'; c = *++cp) {
if (inquote) {
if (c == inquote) {
inquote = 0;
continue;
}
} else {
if (c == '\\') {
if ((c = *++cp) == '\0')
break;
} else if (c == '"' || c == '\'') {
inquote = c;
continue;
} else if (isspace((unsigned char)c))
break;
}
*cp2++ = c;
}
*cp2 = '\0';
if (c == '\0')
break;
cp++;
}
}
/*
* Make a character string into a number.
*
* Todo: 1. Could take random integers (12, 0x12, 012, 0b1).
*/
static int
special(const char *s)
{
char c;
char b;
switch (*s) {
case '^':
b = *++s;
if (b == '?') {
c = b | 0x40; /* DEL */
} else {
c = b & 0x1f;
}
break;
default:
c = *s;
break;
}
return c;
}
/*
* Construct a control character sequence
* for a special character.
*/
static const char *
control(cc_t c)
{
static char buf[5];
/*
* The only way I could get the Sun 3.5 compiler
* to shut up about
* if ((unsigned int)c >= 0x80)
* was to assign "c" to an unsigned int variable...
* Arggg....
*/
unsigned int uic = (unsigned int)c;
/*
* The following are data structures and routines for
* the "send" command.
*
*/
struct sendlist {
const char *name; /* How user refers to it (case independent) */
const 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) */
(const char *);
int nbyte; /* Number of bytes to send this command */
int what; /* Character to be sent (<0 ==> special) */
};
static int
sendcmd(int argc, char **argv)
{
int count; /* how many bytes we are going to need to send */
int i;
struct sendlist *s; /* pointer to current command */
int success = 0;
int needconnect = 0;
if (argc < 2) {
printf("need at least one argument for 'send' command\n");
printf("'send ?' for help\n");
return 0;
}
/*
* 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).
*/
count = 0;
for (i = 1; i < argc; i++) {
s = GETSEND(argv[i]);
if (s == 0) {
printf("Unknown send argument '%s'\n'send ?' for help.\n",
argv[i]);
return 0;
} else if (Ambiguous(s)) {
printf("Ambiguous send argument '%s'\n'send ?' for help.\n",
argv[i]);
return 0;
}
if (i + s->narg >= argc) {
fprintf(stderr,
"Need %d argument%s to 'send %s' command. 'send %s ?' for help.\n",
s->narg, s->narg == 1 ? "" : "s", s->name, s->name);
return 0;
}
count += s->nbyte;
if (s->handler == send_help) {
send_help(NULL);
return 0;
}
i += s->narg;
needconnect += s->needconnect;
}
if (!connected && needconnect) {
printf("?Need to be connected first.\n");
printf("'send ?' for help\n");
return 0;
}
/* Now, do we have enough room? */
if (NETROOM() < count) {
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");
return 0;
}
/* OK, they are all OK, now go through again and actually send */
count = 0;
for (i = 1; i < argc; i++) {
if ((s = GETSEND(argv[i])) == 0) {
fprintf(stderr, "Telnet 'send' error - argument disappeared!\n");
(void) quit(0, NULL);
/*NOTREACHED*/
}
if (s->handler) {
count++;
success += (*s->handler)(argv[i+1]);
i += s->narg;
} else {
NET2ADD(IAC, (unsigned char)s->what);
printoption("SENT", IAC, s->what);
}
}
return (count == success);
}
static int
send_esc(const char *s)
{
NETADD(escape);
return 1;
}
static int
togcrlf(int n)
{
if (crlf) {
printf("Will send carriage returns as telnet <CR><LF>.\n");
} else {
printf("Will send carriage returns as telnet <CR><NUL>.\n");
}
return 1;
}
int binmode;
static int
togbinary(int val)
{
donebinarytoggle = 1;
if (val >= 0) {
binmode = val;
} else {
if (my_want_state_is_will(TELOPT_BINARY) &&
my_want_state_is_do(TELOPT_BINARY)) {
binmode = 1;
} else if (my_want_state_is_wont(TELOPT_BINARY) &&
my_want_state_is_dont(TELOPT_BINARY)) {
binmode = 0;
}
val = binmode ? 0 : 1;
}
if (val == 1) {
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");
} else {
printf("Negotiating binary mode with remote host.\n");
tel_enter_binary(3);
}
} else {
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");
} else {
printf("Negotiating network ascii mode with remote host.\n");
tel_leave_binary(3);
}
}
return 1;
}
static int
togrbinary(int val)
{
donebinarytoggle = 1;
if (val == -1)
val = my_want_state_is_do(TELOPT_BINARY) ? 0 : 1;
if (val == 1) {
if (my_want_state_is_do(TELOPT_BINARY)) {
printf("Already receiving in binary mode.\n");
} else {
printf("Negotiating binary mode on input.\n");
tel_enter_binary(1);
}
} else {
if (my_want_state_is_dont(TELOPT_BINARY)) {
printf("Already receiving in network ascii mode.\n");
} else {
printf("Negotiating network ascii mode on input.\n");
tel_leave_binary(1);
}
}
return 1;
}
static int
togxbinary(int val)
{
donebinarytoggle = 1;
if (val == -1)
val = my_want_state_is_will(TELOPT_BINARY) ? 0 : 1;
if (val == 1) {
if (my_want_state_is_will(TELOPT_BINARY)) {
printf("Already transmitting in binary mode.\n");
} else {
printf("Negotiating binary mode on output.\n");
tel_enter_binary(2);
}
} else {
if (my_want_state_is_wont(TELOPT_BINARY)) {
printf("Already transmitting in network ascii mode.\n");
} else {
printf("Negotiating network ascii mode on output.\n");
tel_leave_binary(2);
}
}
return 1;
}
#ifdef ENCRYPTION
extern int EncryptAutoEnc(int);
extern int EncryptAutoDec(int);
extern int EncryptDebug(int);
extern int EncryptVerbose(int);
#endif /* ENCRYPTION */
struct togglelist {
const char *name; /* name of toggle */
const char *help; /* help message */
int (*handler) /* routine to do actual setting */
(int);
int *variable;
const char *actionexplanation;
};
static struct togglelist Togglelist[] = {
{ "autoflush",
"flushing of output when sending interrupt characters",
0,
&autoflush,
"flush output when sending interrupt characters" },
{ "autosynch",
"automatic sending of interrupt characters in urgent mode",
0,
&autosynch,
"send interrupt characters in urgent mode" },
#ifdef AUTHENTICATION
{ "autologin",
"automatic sending of login and/or authentication info",
0,
&autologin,
"send login name and/or authentication information" },
{ "authdebug",
"Toggle authentication debugging",
auth_togdebug,
0,
"print authentication debugging information" },
#endif
#ifdef ENCRYPTION
{ "autoencrypt",
"automatic encryption of data stream",
EncryptAutoEnc,
0,
"automatically encrypt output" },
{ "autodecrypt",
"automatic decryption of data stream",
EncryptAutoDec,
0,
"automatically decrypt input" },
{ "verbose_encrypt",
"Toggle verbose encryption output",
EncryptVerbose,
0,
"print verbose encryption output" },
{ "encdebug",
"Toggle encryption debugging",
EncryptDebug,
0,
"print encryption debugging information" },
#endif /* ENCRYPTION */
{ "skiprc",
"don't read ~/.telnetrc file",
0,
&skiprc,
"skip reading of ~/.telnetrc file" },
{ "binary",
"sending and receiving of binary data",
togbinary,
0,
0 },
{ "inbinary",
"receiving of binary data",
togrbinary,
0,
0 },
{ "outbinary",
"sending of binary data",
togxbinary,
0,
0 },
{ "crlf",
"sending carriage returns as telnet <CR><LF>",
togcrlf,
&crlf,
0 },
{ "crmod",
"mapping of received carriage returns",
0,
&crmod,
"map carriage return on output" },
{ "localchars",
"local recognition of certain control characters",
lclchars,
&localchars,
"recognize certain control characters" },
{ " ", "", 0, NULL, NULL }, /* empty line */
{ "debug",
"debugging",
togdebug,
&telnet_debug,
"turn on socket level debugging" },
{ "netdata",
"printing of hexadecimal network data (debugging)",
0,
&netdata,
"print hexadecimal representation of network traffic" },
{ "prettydump",
"output of \"netdata\" to user readable format (debugging)",
0,
&prettydump,
"print user readable output for \"netdata\"" },
{ "options",
"viewing of options processing (debugging)",
0,
&showoptions,
"show option processing" },
{ "termdata",
"(debugging) toggle printing of hexadecimal terminal data",
0,
&termdata,
"print hexadecimal representation of terminal traffic" },
{ "?",
0,
togglehelp, NULL, NULL },
{ "help",
0,
togglehelp, NULL, NULL },
{ .name = 0 }
};
static int
togglehelp(int n)
{
struct togglelist *c;
for (c = Togglelist; c->name; c++) {
if (c->help) {
if (*c->help)
printf("%-15s toggle %s\n", c->name, c->help);
else
printf("\n");
}
}
printf("\n");
printf("%-15s %s\n", "?", "display help information");
return 0;
}
static int
toggle(int argc, char *argv[])
{
int retval = 1;
char *name;
struct togglelist *c;
if (argc < 2) {
fprintf(stderr,
"Need an argument to 'toggle' command. 'toggle ?' for help.\n");
return 0;
}
argc--;
argv++;
while (argc--) {
name = *argv++;
c = GETTOGGLE(name);
if (Ambiguous(c)) {
fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n",
name);
return 0;
} else if (c == 0) {
fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n",
name);
return 0;
} else {
if (c->variable) {
*c->variable = !*c->variable; /* invert it */
if (c->actionexplanation) {
printf("%s %s.\n", *c->variable? "Will" : "Won't",
c->actionexplanation);
}
}
if (c->handler) {
retval &= (*c->handler)(-1);
}
}
}
return retval;
}
/*
* The following perform the "set" command.
*/
struct termios new_tc = { .c_iflag = 0 };
struct setlist {
const char *name; /* name */
const char *help; /* help information */
void (*handler)(const char *);
cc_t *charp; /* where it is located at */
};
static struct setlist Setlist[] = {
#ifdef KLUDGELINEMODE
{ "echo", "character to toggle local echoing on/off", 0, &echoc },
#endif
{ "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},
{ " ", "", NULL, NULL },
{ " ", "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 },
{ " ", "", NULL, NULL },
{ " ", "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 },
{ .name = 0 }
};
static int
dolinemode(int n)
{
#ifdef KLUDGELINEMODE
if (kludgelinemode)
send_dont(TELOPT_SGA, 1);
#endif
send_will(TELOPT_LINEMODE, 1);
send_dont(TELOPT_ECHO, 1);
return 1;
}
static int
docharmode(int n)
{
#ifdef KLUDGELINEMODE
if (kludgelinemode)
send_do(TELOPT_SGA, 1);
else
#endif
send_wont(TELOPT_LINEMODE, 1);
send_do(TELOPT_ECHO, 1);
return 1;
}
static int
dolmmode(int bit, int on)
{
unsigned char c;
extern int linemode;
if (my_want_state_is_wont(TELOPT_LINEMODE)) {
printf("?Need to have LINEMODE option enabled first.\n");
printf("'mode ?' for help.\n");
return 0;
}
if (on)
c = (unsigned char)(linemode | bit);
else
c = (unsigned char)(linemode & ~bit);
lm_mode(&c, 1, 1);
return 1;
}
int
set_mode(int bit)
{
return dolmmode(bit, 1);
}
int
clear_mode(int bit)
{
return dolmmode(bit, 0);
}
struct modelist {
const char *name; /* command name */
const char *help; /* help string */
int (*handler) /* routine which executes command */
(int);
int needconnect; /* Do we need to be connected to execute? */
int arg1;
};
printf("format is: 'mode Mode', where 'Mode' is one of:\n\n");
for (mt = ModeList; mt->name; mt++) {
if (mt->help) {
if (*mt->help)
printf("%-15s %s\n", mt->name, mt->help);
else
printf("\n");
}
}
return 0;
}
/*
* The following are the data structures, and many of the routines,
* relating to command processing.
*/
/*
* Set the escape character.
*/
static int
setescape(int argc, char *argv[])
{
char *arg;
char buf[50];
printf(
"Deprecated usage - please use 'set escape%s%s' in the future.\n",
(argc > 2)? " ":"", (argc > 2)? argv[1]: "");
if (argc > 2)
arg = argv[1];
else {
printf("new escape character: ");
(void) fgets(buf, sizeof(buf), stdin);
arg = buf;
}
if (arg[0] != '\0')
escape = (cc_t)arg[0];
printf("Escape character is '%s'.\n", control(escape));
(void) fflush(stdout);
return 1;
}
/*VARARGS*/
static int
togcrmod(int argc, char *argv[])
{
crmod = !crmod;
printf("Deprecated usage - please use 'toggle crmod' in the future.\n");
printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't");
(void) fflush(stdout);
return 1;
}
/*VARARGS*/
int
suspend(int argc, char *argv[])
{
setcommandmode();
{
long oldrows, oldcols, newrows, newcols, err;
err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0;
(void) kill(0, SIGTSTP);
/*
* If we didn't get the window size before the SUSPEND, but we
* can get them now (?), then send the NAWS to make sure that
* we are set up for the right window size.
*/
if (TerminalWindowSize(&newrows, &newcols) && connected &&
(err || ((oldrows != newrows) || (oldcols != newcols)))) {
sendnaws();
}
}
/* reget parameters in case they were changed */
TerminalSaveState();
setconnmode(0);
return 1;
}
/*ARGSUSED*/
int
shell(int argc, char *argv[])
{
long oldrows, oldcols, newrows, newcols;
long volatile err; /* Avoid vfork clobbering */
int
env_cmd(int argc, char *argv[])
{
struct envlist *c;
if (argc < 2) {
fprintf(stderr,
"Need an argument to 'environ' command. 'environ ?' for help.\n");
return 0;
}
c = getenvcmd(argv[1]);
if (c == 0) {
fprintf(stderr, "'%s': unknown argument ('environ ?' for help).\n",
argv[1]);
return 0;
}
if (Ambiguous(c)) {
fprintf(stderr, "'%s': ambiguous argument ('environ ?' for help).\n",
argv[1]);
return 0;
}
if (c->narg + 2 != argc) {
fprintf(stderr,
"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);
return 0;
}
(*c->handler)(argv[2], argv[3]);
return 1;
}
struct env_lst {
struct env_lst *next; /* pointer to next structure */
struct env_lst *prev; /* pointer to previous structure */
unsigned char *var; /* pointer to variable name */
unsigned char *value; /* pointer to variable value */
int export; /* 1 -> export with default list of variables */
int welldefined; /* A well defined variable */
};
for (epp = environ; *epp; epp++) {
if ((cp = strchr(*epp, '=')) != NULL) {
*cp = '\0';
ep = env_define((unsigned char *)*epp,
(unsigned char *)cp+1);
ep->export = 0;
*cp = '=';
}
}
/*
* Special case for DISPLAY variable. If it is ":0.0" or
* "unix:0.0", we have to get rid of "unix" and insert our
* hostname.
*/
if ((ep = env_find("DISPLAY"))
&& ((*ep->value == ':')
|| (strncmp(ep->value, "unix:", 5) == 0))) {
char hbuf[MAXHOSTNAMELEN + 1];
char *cp2 = strchr(ep->value, ':');
gethostname(hbuf, sizeof hbuf);
hbuf[sizeof(hbuf) - 1] = '\0';
if (asprintf(&cp, "%s%s", hbuf, cp2) < 0)
err(1, "Out of memory");
free(ep->value);
ep->value = 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("USER", ep->value);
env_unexport("USER", NULL);
}
env_export("DISPLAY", NULL);
env_export("PRINTER", NULL);
}
/*
* Print status about the connection.
*/
/*ARGSUSED*/
static int
status(int argc, char *argv[])
{
if (connected) {
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");
slcstate();
#ifdef KLUDGELINEMODE
} else if (kludgelinemode && my_want_state_is_dont(TELOPT_SGA)) {
printf("Operating in obsolete linemode\n");
#endif
} else {
printf("Operating in single character mode\n");
if (localchars)
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");
#ifdef ENCRYPTION
encrypt_display();
#endif /* ENCRYPTION */
}
} else {
printf("No connection.\n");
}
printf("Escape character is '%s'.\n", control(escape));
(void) fflush(stdout);
return 1;
}
/*
* Function that gets called when SIGINFO is received.
*/
int
ayt_status(void)
{
return call(status, "status", "notmuch", 0);
}
#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
if (setpolicy(net, res, ipsec_policy_in) < 0) {
serrno = errno;
(void) NetClose(net);
net = -1;
continue;
}
if (setpolicy(net, res, ipsec_policy_out) < 0) {
serrno = errno;
(void) NetClose(net);
net = -1;
continue;
}
#endif
if (connect(net, res->ai_addr, res->ai_addrlen) < 0) {
if (res->ai_next) {
warn("Connect to address %s: ", sockaddr_ntop(res->ai_addr));
}
serrno = errno;
cause = "Unable to connect to remote host";
(void) NetClose(net);
net = -1;
continue;
}
cmdrc(hostp, hostname);
if (autologin && user == NULL) {
struct passwd *pw;
user = getenv("USER");
if (user == NULL ||
((pw = getpwnam(user)) && pw->pw_uid != getuid())) {
if ((pw = getpwuid(getuid())) != NULL)
user = pw->pw_name;
else
user = NULL;
}
}
if (user) {
env_define("USER", __UNCONST(user));
env_export("USER", NULL);
}
(void) call(status, "status", "notmuch", 0);
telnet(user);
(void) NetClose(net);
ExitString("Connection closed by foreign host.\n",1);
/*NOTREACHED*/
}
#define HELPINDENT ((int)sizeof ("connect"))
static char
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 characters ('slc ?' for more)",
displayhelp[] = "display operating parameters",
#ifdef AUTHENTICATION
authhelp[] = "turn on (off) authentication ('auth ?' for more)",
#endif
#ifdef ENCRYPTION
encrypthelp[] = "turn on (off) encryption ('encrypt ?' for more)",
#endif /* ENCRYPTION */
zhelp[] = "suspend telnet",
shellhelp[] = "invoke a subshell",
envhelp[] = "change environment variables ('environ ?' for more)",
modestring[] = "try to enter line or character mode ('mode ?' for more)";