mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 17:38:00 +00:00
Centralise PuTTY and Plink's non-option argument handling.
This is another piece of long-overdue refactoring similar to the
recent commit e3796cb77
. But where that one dealt with normalisation
of stuff already stored _in_ a Conf by whatever means (including, in
particular, handling a user typing 'username@host.name' into the
Hostname box of the GUI session dialog box), this one deals with
handling argv entries and putting them into the Conf.
This isn't exactly a pure no-functional-change-at-all refactoring. On
the other hand, it isn't a full-on cleanup that completely
rationalises all the user-visible behaviour as well as the code
structure. It's somewhere in between: I've preserved all the behaviour
quirks that I could imagine a reason for having intended, but taken
the opportunity to _not_ faithfully replicate anything I thought was
clearly just a bug.
So, for example, the following inconsistency is carefully preserved:
the command 'plink -load session nextword' treats 'nextword' as a host
name if the loaded session hasn't provided a hostname already, and
otherwise treats 'nextword' as the remote command to execute on the
already-specified remote host, but the same combination of arguments
to GUI PuTTY will _always_ treat 'nextword' as a hostname, overriding
a hostname (if any) in the saved session. That makes some sense to me
because of the different shapes of the overall command lines.
On the other hand, there are two behaviour changes I know of as a
result of this commit: a third argument to GUI PuTTY (after a hostname
and port) now provokes an error message instead of being silently
ignored, and in Plink, if you combine a -P option (specifying a port
number) with the historical comma-separated protocol selection prefix
on the hostname argument (which I'd completely forgotten even existed
until this piece of work), then the -P will now override the selected
protocol's default port number, whereas previously the default port
would win. For example, 'plink -P 12345 telnet,hostname' will now
connect via Telnet to port 12345 instead of to port 23.
There may be scope for removing or rethinking some of the command-
line syntax quirks in the wake of this change. If we do decide to do
anything like that, then hopefully having it all in one place will
make it easier to remove or change things consistently across the
tools.
This commit is contained in:
parent
81345e9a82
commit
b9a25510b0
263
cmdline.c
263
cmdline.c
@ -159,11 +159,242 @@ static int cmdline_check_unavailable(int flag, const char *p)
|
||||
if (need_save < 0) return x; \
|
||||
} while (0)
|
||||
|
||||
static int seen_hostname_argument = FALSE;
|
||||
static int seen_port_argument = FALSE;
|
||||
|
||||
int cmdline_process_param(const char *p, char *value,
|
||||
int need_save, Conf *conf)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (p[0] != '-') {
|
||||
if (need_save < 0)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Common handling for the tools whose initial command-line
|
||||
* arguments specify a hostname to connect to, i.e. PuTTY and
|
||||
* Plink. Doesn't count the file transfer tools, because their
|
||||
* hostname specification appears as part of a more
|
||||
* complicated scheme.
|
||||
*/
|
||||
|
||||
if ((cmdline_tooltype & TOOLTYPE_HOST_ARG) &&
|
||||
!seen_hostname_argument &&
|
||||
(!(cmdline_tooltype & TOOLTYPE_HOST_ARG_FROM_LAUNCHABLE_LOAD) ||
|
||||
!loaded_session || !conf_launchable(conf))) {
|
||||
/*
|
||||
* Treat this argument as a host name, if we have not yet
|
||||
* seen a host name argument or -load.
|
||||
*
|
||||
* Exception, in some tools (Plink): if we have seen -load
|
||||
* but it didn't create a launchable session, then we
|
||||
* still accept a hostname argument following that -load.
|
||||
* This allows you to make saved sessions that configure
|
||||
* lots of other stuff (colour schemes, terminal settings
|
||||
* etc) and then say 'putty -load sessionname hostname'.
|
||||
*
|
||||
* Also, we carefully _don't_ test conf for launchability
|
||||
* if we haven't been explicitly told to load a session
|
||||
* (otherwise saving a host name into Default Settings
|
||||
* would cause 'putty' on its own to immediately launch
|
||||
* the default session and never be able to do anything
|
||||
* else).
|
||||
*/
|
||||
if (!strncmp(p, "telnet:", 7)) {
|
||||
/*
|
||||
* If the argument starts with "telnet:", set the
|
||||
* protocol to Telnet and process the string as a
|
||||
* Telnet URL.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Skip the "telnet:" or "telnet://" prefix.
|
||||
*/
|
||||
p += 7;
|
||||
if (p[0] == '/' && p[1] == '/')
|
||||
p += 2;
|
||||
conf_set_int(conf, CONF_protocol, PROT_TELNET);
|
||||
|
||||
/*
|
||||
* The next thing we expect is a host name.
|
||||
*/
|
||||
{
|
||||
const char *host = p;
|
||||
char *buf;
|
||||
|
||||
p += host_strcspn(p, ":/");
|
||||
buf = dupprintf("%.*s", (int)(p - host), host);
|
||||
conf_set_str(conf, CONF_host, buf);
|
||||
sfree(buf);
|
||||
seen_hostname_argument = TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the host name is followed by a colon, then
|
||||
* expect a port number after it.
|
||||
*/
|
||||
if (*p == ':') {
|
||||
p++;
|
||||
|
||||
conf_set_int(conf, CONF_port, atoi(p));
|
||||
/*
|
||||
* Set the flag that will stop us from treating
|
||||
* the next argument as a separate port; this one
|
||||
* counts as explicitly provided.
|
||||
*/
|
||||
seen_port_argument = TRUE;
|
||||
} else {
|
||||
conf_set_int(conf, CONF_port, -1);
|
||||
}
|
||||
} else {
|
||||
char *user = NULL, *hostname = NULL;
|
||||
const char *hostname_after_user;
|
||||
int port_override = -1;
|
||||
size_t len;
|
||||
|
||||
/*
|
||||
* Otherwise, treat it as a bare host name.
|
||||
*/
|
||||
|
||||
if (cmdline_tooltype & TOOLTYPE_HOST_ARG_PROTOCOL_PREFIX) {
|
||||
/*
|
||||
* Here Plink checks for a comma-separated
|
||||
* protocol prefix, e.g. 'ssh,hostname' or
|
||||
* 'ssh,user@hostname'.
|
||||
*
|
||||
* I'm not entirely sure why; this behaviour dates
|
||||
* from 2000 and isn't explained. But I _think_ it
|
||||
* has to do with CVS transport or similar use
|
||||
* cases, in which the end user invokes the SSH
|
||||
* client indirectly, via some means that only
|
||||
* lets them pass a single string argument, and it
|
||||
* was occasionally useful to shoehorn the choice
|
||||
* of protocol into that argument.
|
||||
*/
|
||||
const char *comma = strchr(p, ',');
|
||||
if (comma) {
|
||||
char *prefix = dupprintf("%.*s", (int)(comma - p), p);
|
||||
const Backend *b = backend_from_name(prefix);
|
||||
|
||||
if (b) {
|
||||
default_protocol = b->protocol;
|
||||
conf_set_int(conf, CONF_protocol,
|
||||
default_protocol);
|
||||
port_override = b->default_port;
|
||||
} else {
|
||||
cmdline_error("unrecognised protocol prefix '%s'",
|
||||
prefix);
|
||||
}
|
||||
|
||||
sfree(prefix);
|
||||
p = comma + 1;
|
||||
}
|
||||
}
|
||||
|
||||
hostname_after_user = p;
|
||||
if (cmdline_tooltype & TOOLTYPE_HOST_ARG_CAN_BE_SESSION) {
|
||||
/*
|
||||
* If the hostname argument can also be a saved
|
||||
* session (see below), then here we also check
|
||||
* for a user@ prefix, which will override the
|
||||
* username from the saved session.
|
||||
*
|
||||
* (If the hostname argument _isn't_ a saved
|
||||
* session, we don't do this.)
|
||||
*/
|
||||
const char *at = strrchr(p, '@');
|
||||
if (at) {
|
||||
user = dupprintf("%.*s", (int)(at - p), p);
|
||||
hostname_after_user = at + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the whole hostname argument (minus only that
|
||||
* optional protocol prefix) into the existing Conf,
|
||||
* for tools that don't treat it as a saved session
|
||||
* and as a fallback for those that do.
|
||||
*/
|
||||
hostname = dupstr(p + strspn(p, " \t"));
|
||||
len = strlen(hostname);
|
||||
while (len > 0 && (hostname[len-1] == ' ' ||
|
||||
hostname[len-1] == '\t'))
|
||||
hostname[--len] = '\0';
|
||||
seen_hostname_argument = TRUE;
|
||||
conf_set_str(conf, CONF_host, hostname);
|
||||
|
||||
if ((cmdline_tooltype & TOOLTYPE_HOST_ARG_CAN_BE_SESSION) &&
|
||||
!loaded_session) {
|
||||
/*
|
||||
* For some tools, we equivocate between a
|
||||
* hostname argument and an argument naming a
|
||||
* saved session. Here we attempt to load a
|
||||
* session with the specified name, and if that
|
||||
* succeeds, we overwrite the entire Conf with it.
|
||||
*
|
||||
* We skip this check if a -load option has
|
||||
* already happened, so that
|
||||
*
|
||||
* plink -load non-launchable-session hostname
|
||||
*
|
||||
* will treat 'hostname' as a hostname _even_ if a
|
||||
* saved session called 'hostname' exists. (This
|
||||
* doesn't lose any functionality someone could
|
||||
* have needed, because if 'hostname' did cause a
|
||||
* session to be loaded, then it would overwrite
|
||||
* everything from the previously loaded session.
|
||||
* So if that was the behaviour someone wanted,
|
||||
* then they could get it by leaving off the
|
||||
* -load completely.)
|
||||
*/
|
||||
Conf *conf2 = conf_new();
|
||||
do_defaults(hostname_after_user, conf2);
|
||||
if (conf_launchable(conf2)) {
|
||||
conf_copy_into(conf, conf2);
|
||||
loaded_session = TRUE;
|
||||
/* And override the username if one was given. */
|
||||
if (user)
|
||||
conf_set_str(conf, CONF_username, user);
|
||||
}
|
||||
conf_free(conf2);
|
||||
}
|
||||
|
||||
sfree(hostname);
|
||||
sfree(user);
|
||||
|
||||
if (port_override >= 0)
|
||||
conf_set_int(conf, CONF_port, port_override);
|
||||
}
|
||||
|
||||
return 1;
|
||||
} else if ((cmdline_tooltype & TOOLTYPE_PORT_ARG) &&
|
||||
!seen_port_argument) {
|
||||
/*
|
||||
* If we've already got a host name from the command line
|
||||
* (either as a hostname argument or a qualifying -load),
|
||||
* but not a port number, then treat the next argument as
|
||||
* a port number.
|
||||
*
|
||||
* We handle this by calling ourself recursively to
|
||||
* pretend we received a -P argument, so that it will be
|
||||
* deferred until it's a good moment to run it.
|
||||
*/
|
||||
char *dup = dupstr(p); /* 'value' is not a const char * */
|
||||
int retd = cmdline_process_param("-P", dup, 1, conf);
|
||||
sfree(dup);
|
||||
assert(retd == 2);
|
||||
seen_port_argument = TRUE;
|
||||
return 1;
|
||||
} else {
|
||||
/*
|
||||
* Refuse to recognise this argument, and give it back to
|
||||
* the tool's own command-line processing.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!strcmp(p, "-load")) {
|
||||
RETURN(2);
|
||||
/* This parameter must be processed immediately rather than being
|
||||
@ -648,3 +879,35 @@ void cmdline_run_saved(Conf *conf)
|
||||
saves[pri].nsaved = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int cmdline_host_ok(Conf *conf)
|
||||
{
|
||||
/*
|
||||
* Return TRUE if the command-line arguments we've processed in
|
||||
* TOOLTYPE_HOST_ARG mode are sufficient to justify launching a
|
||||
* session.
|
||||
*/
|
||||
assert(cmdline_tooltype & TOOLTYPE_HOST_ARG);
|
||||
|
||||
/*
|
||||
* Of course, if we _can't_ launch a session, the answer is
|
||||
* clearly no.
|
||||
*/
|
||||
if (!conf_launchable(conf))
|
||||
return FALSE;
|
||||
|
||||
/*
|
||||
* But also, if we haven't seen either a -load option or a
|
||||
* hostname argument, i.e. the only saved settings we've loaded
|
||||
* are Default Settings plus any non-hostname-based stuff from the
|
||||
* command line, then the answer is still no, _even_ if this Conf
|
||||
* is launchable. Otherwise, if you saved your favourite hostname
|
||||
* into Default Settings, then just running 'putty' without
|
||||
* arguments would connect to it without ever offering you the
|
||||
* option to connect to something else or change the setting.
|
||||
*/
|
||||
if (!seen_hostname_argument && !loaded_session)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
6
putty.h
6
putty.h
@ -1350,8 +1350,14 @@ int cmdline_process_param(const char *, char *, int, Conf *);
|
||||
void cmdline_run_saved(Conf *);
|
||||
void cmdline_cleanup(void);
|
||||
int cmdline_get_passwd_input(prompts_t *p, const unsigned char *in, int inlen);
|
||||
int cmdline_host_ok(Conf *);
|
||||
#define TOOLTYPE_FILETRANSFER 1
|
||||
#define TOOLTYPE_NONNETWORK 2
|
||||
#define TOOLTYPE_HOST_ARG 4
|
||||
#define TOOLTYPE_HOST_ARG_CAN_BE_SESSION 8
|
||||
#define TOOLTYPE_HOST_ARG_PROTOCOL_PREFIX 16
|
||||
#define TOOLTYPE_HOST_ARG_FROM_LAUNCHABLE_LOAD 32
|
||||
#define TOOLTYPE_PORT_ARG 64
|
||||
extern int cmdline_tooltype;
|
||||
|
||||
void cmdline_error(const char *, ...);
|
||||
|
@ -315,8 +315,7 @@ void window_setup_error(const char *errmsg)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int do_cmdline(int argc, char **argv, int do_everything, int *allow_launch,
|
||||
Conf *conf)
|
||||
int do_cmdline(int argc, char **argv, int do_everything, Conf *conf)
|
||||
{
|
||||
int err = 0;
|
||||
char *val;
|
||||
@ -536,10 +535,13 @@ int do_cmdline(int argc, char **argv, int do_everything, int *allow_launch,
|
||||
pgp_fingerprints();
|
||||
exit(1);
|
||||
|
||||
} else if(p[0] != '-' && (!do_everything ||
|
||||
process_nonoption_arg(p, conf,
|
||||
allow_launch))) {
|
||||
/* do nothing */
|
||||
} else if (p[0] != '-') {
|
||||
/* Non-option arguments not handled by cmdline.c are errors. */
|
||||
if (do_everything) {
|
||||
err = 1;
|
||||
fprintf(stderr, "%s: unexpected non-option argument '%s'\n",
|
||||
appname, p);
|
||||
}
|
||||
|
||||
} else {
|
||||
err = 1;
|
||||
@ -636,22 +638,15 @@ int main(int argc, char **argv)
|
||||
assert(!dup_check_launchable || conf_launchable(conf));
|
||||
need_config_box = FALSE;
|
||||
} else {
|
||||
/* By default, we bring up the config dialog, rather than launching
|
||||
* a session. This gets set to TRUE if something happens to change
|
||||
* that (e.g., a hostname is specified on the command-line). */
|
||||
int allow_launch = FALSE;
|
||||
if (do_cmdline(argc, argv, 0, &allow_launch, conf))
|
||||
if (do_cmdline(argc, argv, 0, conf))
|
||||
exit(1); /* pre-defaults pass to get -class */
|
||||
do_defaults(NULL, conf);
|
||||
if (do_cmdline(argc, argv, 1, &allow_launch, conf))
|
||||
if (do_cmdline(argc, argv, 1, conf))
|
||||
exit(1); /* post-defaults, do everything */
|
||||
|
||||
cmdline_run_saved(conf);
|
||||
|
||||
if (loaded_session)
|
||||
allow_launch = TRUE;
|
||||
|
||||
need_config_box = (!allow_launch || !conf_launchable(conf));
|
||||
need_config_box = !cmdline_host_ok(conf);
|
||||
}
|
||||
|
||||
if (need_config_box) {
|
||||
|
@ -194,7 +194,6 @@ GtkWidget *create_message_box(
|
||||
|
||||
/* Things pterm.c needs from {ptermm,uxputty}.c */
|
||||
char *make_default_wintitle(char *hostname);
|
||||
int process_nonoption_arg(const char *arg, Conf *conf, int *allow_launch);
|
||||
|
||||
/* pterm.c needs this special function in xkeysym.c */
|
||||
int keysym_to_unicode(int keysym);
|
||||
|
241
unix/uxplink.c
241
unix/uxplink.c
@ -597,14 +597,12 @@ const int buildinfo_gtk_relevant = FALSE;
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int sending;
|
||||
int portnumber = -1;
|
||||
int *fdlist;
|
||||
int fd;
|
||||
int i, fdcount, fdsize, fdstate;
|
||||
int exitcode;
|
||||
int errors;
|
||||
int use_subsystem = 0;
|
||||
int got_host = FALSE;
|
||||
int just_test_share_exists = FALSE;
|
||||
unsigned long now;
|
||||
struct winsize size;
|
||||
@ -623,6 +621,11 @@ int main(int argc, char **argv)
|
||||
outgoingeof = EOF_NO;
|
||||
|
||||
flags = FLAG_STDERR | FLAG_STDERR_TTY;
|
||||
cmdline_tooltype |=
|
||||
(TOOLTYPE_HOST_ARG |
|
||||
TOOLTYPE_HOST_ARG_CAN_BE_SESSION |
|
||||
TOOLTYPE_HOST_ARG_PROTOCOL_PREFIX |
|
||||
TOOLTYPE_HOST_ARG_FROM_LAUNCHABLE_LOAD);
|
||||
|
||||
stderr_tty_init();
|
||||
/*
|
||||
@ -651,175 +654,81 @@ int main(int argc, char **argv)
|
||||
}
|
||||
while (--argc) {
|
||||
char *p = *++argv;
|
||||
if (*p == '-') {
|
||||
int ret = cmdline_process_param(p, (argc > 1 ? argv[1] : NULL),
|
||||
1, conf);
|
||||
if (ret == -2) {
|
||||
fprintf(stderr,
|
||||
"plink: option \"%s\" requires an argument\n", p);
|
||||
errors = 1;
|
||||
} else if (ret == 2) {
|
||||
--argc, ++argv;
|
||||
} else if (ret == 1) {
|
||||
continue;
|
||||
} else if (!strcmp(p, "-batch")) {
|
||||
console_batch_mode = 1;
|
||||
} else if (!strcmp(p, "-s")) {
|
||||
/* Save status to write to conf later. */
|
||||
use_subsystem = 1;
|
||||
} else if (!strcmp(p, "-V") || !strcmp(p, "--version")) {
|
||||
version();
|
||||
} else if (!strcmp(p, "--help")) {
|
||||
usage();
|
||||
exit(0);
|
||||
} else if (!strcmp(p, "-pgpfp")) {
|
||||
pgp_fingerprints();
|
||||
exit(1);
|
||||
} else if (!strcmp(p, "-o")) {
|
||||
if (argc <= 1) {
|
||||
fprintf(stderr,
|
||||
"plink: option \"-o\" requires an argument\n");
|
||||
errors = 1;
|
||||
} else {
|
||||
--argc;
|
||||
provide_xrm_string(*++argv);
|
||||
}
|
||||
} else if (!strcmp(p, "-shareexists")) {
|
||||
just_test_share_exists = TRUE;
|
||||
} else if (!strcmp(p, "-fuzznet")) {
|
||||
conf_set_int(conf, CONF_proxy_type, PROXY_FUZZ);
|
||||
conf_set_str(conf, CONF_proxy_telnet_command,
|
||||
"%host");
|
||||
} else {
|
||||
fprintf(stderr, "plink: unknown option \"%s\"\n", p);
|
||||
errors = 1;
|
||||
}
|
||||
} else if (*p) {
|
||||
if (!conf_launchable(conf) || !(got_host || loaded_session)) {
|
||||
char *q = p;
|
||||
int ret = cmdline_process_param(p, (argc > 1 ? argv[1] : NULL),
|
||||
1, conf);
|
||||
if (ret == -2) {
|
||||
fprintf(stderr,
|
||||
"plink: option \"%s\" requires an argument\n", p);
|
||||
errors = 1;
|
||||
} else if (ret == 2) {
|
||||
--argc, ++argv;
|
||||
} else if (ret == 1) {
|
||||
continue;
|
||||
} else if (!strcmp(p, "-batch")) {
|
||||
console_batch_mode = 1;
|
||||
} else if (!strcmp(p, "-s")) {
|
||||
/* Save status to write to conf later. */
|
||||
use_subsystem = 1;
|
||||
} else if (!strcmp(p, "-V") || !strcmp(p, "--version")) {
|
||||
version();
|
||||
} else if (!strcmp(p, "--help")) {
|
||||
usage();
|
||||
exit(0);
|
||||
} else if (!strcmp(p, "-pgpfp")) {
|
||||
pgp_fingerprints();
|
||||
exit(1);
|
||||
} else if (!strcmp(p, "-o")) {
|
||||
if (argc <= 1) {
|
||||
fprintf(stderr,
|
||||
"plink: option \"-o\" requires an argument\n");
|
||||
errors = 1;
|
||||
} else {
|
||||
--argc;
|
||||
provide_xrm_string(*++argv);
|
||||
}
|
||||
} else if (!strcmp(p, "-shareexists")) {
|
||||
just_test_share_exists = TRUE;
|
||||
} else if (!strcmp(p, "-fuzznet")) {
|
||||
conf_set_int(conf, CONF_proxy_type, PROXY_FUZZ);
|
||||
conf_set_str(conf, CONF_proxy_telnet_command, "%host");
|
||||
} else if (*p != '-') {
|
||||
char *command;
|
||||
int cmdlen, cmdsize;
|
||||
cmdlen = cmdsize = 0;
|
||||
command = NULL;
|
||||
|
||||
/*
|
||||
* If the hostname starts with "telnet:", set the
|
||||
* protocol to Telnet and process the string as a
|
||||
* Telnet URL.
|
||||
*/
|
||||
if (!strncmp(q, "telnet:", 7)) {
|
||||
char c;
|
||||
while (argc) {
|
||||
while (*p) {
|
||||
if (cmdlen >= cmdsize) {
|
||||
cmdsize = cmdlen + 512;
|
||||
command = sresize(command, cmdsize, char);
|
||||
}
|
||||
command[cmdlen++]=*p++;
|
||||
}
|
||||
if (cmdlen >= cmdsize) {
|
||||
cmdsize = cmdlen + 512;
|
||||
command = sresize(command, cmdsize, char);
|
||||
}
|
||||
command[cmdlen++]=' '; /* always add trailing space */
|
||||
if (--argc) p = *++argv;
|
||||
}
|
||||
if (cmdlen) command[--cmdlen]='\0';
|
||||
/* change trailing blank to NUL */
|
||||
conf_set_str(conf, CONF_remote_cmd, command);
|
||||
conf_set_str(conf, CONF_remote_cmd2, "");
|
||||
conf_set_int(conf, CONF_nopty, TRUE); /* command => no tty */
|
||||
|
||||
q += 7;
|
||||
if (q[0] == '/' && q[1] == '/')
|
||||
q += 2;
|
||||
conf_set_int(conf, CONF_protocol, PROT_TELNET);
|
||||
p = q;
|
||||
p += host_strcspn(p, ":/");
|
||||
c = *p;
|
||||
if (*p)
|
||||
*p++ = '\0';
|
||||
if (c == ':')
|
||||
conf_set_int(conf, CONF_port, atoi(p));
|
||||
else
|
||||
conf_set_int(conf, CONF_port, -1);
|
||||
conf_set_str(conf, CONF_host, q);
|
||||
got_host = TRUE;
|
||||
} else {
|
||||
char *r, *user, *host;
|
||||
/*
|
||||
* Before we process the [user@]host string, we
|
||||
* first check for the presence of a protocol
|
||||
* prefix (a protocol name followed by ",").
|
||||
*/
|
||||
r = strchr(p, ',');
|
||||
if (r) {
|
||||
const Backend *b;
|
||||
*r = '\0';
|
||||
b = backend_from_name(p);
|
||||
if (b) {
|
||||
default_protocol = b->protocol;
|
||||
conf_set_int(conf, CONF_protocol,
|
||||
default_protocol);
|
||||
portnumber = b->default_port;
|
||||
}
|
||||
p = r + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* A nonzero length string followed by an @ is treated
|
||||
* as a username. (We discount an _initial_ @.) The
|
||||
* rest of the string (or the whole string if no @)
|
||||
* is treated as a session name and/or hostname.
|
||||
*/
|
||||
r = strrchr(p, '@');
|
||||
if (r == p)
|
||||
p++, r = NULL; /* discount initial @ */
|
||||
if (r) {
|
||||
*r++ = '\0';
|
||||
user = p, host = r;
|
||||
} else {
|
||||
user = NULL, host = p;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now attempt to load a saved session with the
|
||||
* same name as the hostname.
|
||||
*/
|
||||
{
|
||||
Conf *conf2 = conf_new();
|
||||
do_defaults(host, conf2);
|
||||
if (loaded_session || !conf_launchable(conf2)) {
|
||||
/* No settings for this host; use defaults */
|
||||
/* (or session was already loaded with -load) */
|
||||
conf_set_str(conf, CONF_host, host);
|
||||
conf_set_int(conf, CONF_port, default_port);
|
||||
got_host = TRUE;
|
||||
} else {
|
||||
conf_copy_into(conf, conf2);
|
||||
loaded_session = TRUE;
|
||||
}
|
||||
conf_free(conf2);
|
||||
}
|
||||
|
||||
if (user) {
|
||||
/* Patch in specified username. */
|
||||
conf_set_str(conf, CONF_username, user);
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
char *command;
|
||||
int cmdlen, cmdsize;
|
||||
cmdlen = cmdsize = 0;
|
||||
command = NULL;
|
||||
|
||||
while (argc) {
|
||||
while (*p) {
|
||||
if (cmdlen >= cmdsize) {
|
||||
cmdsize = cmdlen + 512;
|
||||
command = sresize(command, cmdsize, char);
|
||||
}
|
||||
command[cmdlen++]=*p++;
|
||||
}
|
||||
if (cmdlen >= cmdsize) {
|
||||
cmdsize = cmdlen + 512;
|
||||
command = sresize(command, cmdsize, char);
|
||||
}
|
||||
command[cmdlen++]=' '; /* always add trailing space */
|
||||
if (--argc) p = *++argv;
|
||||
}
|
||||
if (cmdlen) command[--cmdlen]='\0';
|
||||
/* change trailing blank to NUL */
|
||||
conf_set_str(conf, CONF_remote_cmd, command);
|
||||
conf_set_str(conf, CONF_remote_cmd2, "");
|
||||
conf_set_int(conf, CONF_nopty, TRUE); /* command => no tty */
|
||||
|
||||
break; /* done with cmdline */
|
||||
}
|
||||
break; /* done with cmdline */
|
||||
} else {
|
||||
fprintf(stderr, "plink: unknown option \"%s\"\n", p);
|
||||
errors = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (errors)
|
||||
return 1;
|
||||
|
||||
if (!conf_launchable(conf) || !(got_host || loaded_session)) {
|
||||
if (!cmdline_host_ok(conf)) {
|
||||
usage();
|
||||
}
|
||||
|
||||
@ -864,12 +773,6 @@ int main(int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Select port.
|
||||
*/
|
||||
if (portnumber != -1)
|
||||
conf_set_int(conf, CONF_port, portnumber);
|
||||
|
||||
/*
|
||||
* Block SIGPIPE, so that we'll get EPIPE individually on
|
||||
* particular network connections that go wrong.
|
||||
|
@ -35,11 +35,6 @@ void cleanup_exit(int code)
|
||||
exit(code);
|
||||
}
|
||||
|
||||
int process_nonoption_arg(const char *arg, Conf *conf, int *allow_launch)
|
||||
{
|
||||
return 0; /* pterm doesn't have any. */
|
||||
}
|
||||
|
||||
char *make_default_wintitle(char *hostname)
|
||||
{
|
||||
return dupstr("pterm");
|
||||
|
@ -51,69 +51,9 @@ void initial_config_box(Conf *conf, post_dialog_fn_t after, void *afterctx)
|
||||
sfree(title);
|
||||
}
|
||||
|
||||
static int got_host = 0;
|
||||
|
||||
const int use_event_log = 1, new_session = 1, saved_sessions = 1;
|
||||
const int dup_check_launchable = 1;
|
||||
|
||||
int process_nonoption_arg(const char *arg, Conf *conf, int *allow_launch)
|
||||
{
|
||||
char *argdup, *p, *q;
|
||||
argdup = dupstr(arg);
|
||||
q = argdup;
|
||||
|
||||
if (got_host) {
|
||||
/*
|
||||
* If we already have a host name, treat this argument as a
|
||||
* port number. NB we have to treat this as a saved -P
|
||||
* argument, so that it will be deferred until it's a good
|
||||
* moment to run it.
|
||||
*/
|
||||
int ret = cmdline_process_param("-P", argdup, 1, conf);
|
||||
assert(ret == 2);
|
||||
} else if (!strncmp(q, "telnet:", 7)) {
|
||||
/*
|
||||
* If the hostname starts with "telnet:",
|
||||
* set the protocol to Telnet and process
|
||||
* the string as a Telnet URL.
|
||||
*/
|
||||
char c;
|
||||
|
||||
q += 7;
|
||||
if (q[0] == '/' && q[1] == '/')
|
||||
q += 2;
|
||||
conf_set_int(conf, CONF_protocol, PROT_TELNET);
|
||||
p = q;
|
||||
p += host_strcspn(p, ":/");
|
||||
c = *p;
|
||||
if (*p)
|
||||
*p++ = '\0';
|
||||
if (c == ':')
|
||||
conf_set_int(conf, CONF_port, atoi(p));
|
||||
else
|
||||
conf_set_int(conf, CONF_port, -1);
|
||||
conf_set_str(conf, CONF_host, q);
|
||||
got_host = 1;
|
||||
} else {
|
||||
/*
|
||||
* Otherwise, treat this argument as a host name.
|
||||
*/
|
||||
p = argdup;
|
||||
while (*p && !isspace((unsigned char)*p))
|
||||
p++;
|
||||
if (*p)
|
||||
*p++ = '\0';
|
||||
conf_set_str(conf, CONF_host, q);
|
||||
got_host = 1;
|
||||
}
|
||||
if (got_host)
|
||||
*allow_launch = TRUE;
|
||||
|
||||
sfree(argdup);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *make_default_wintitle(char *hostname)
|
||||
{
|
||||
return dupcat(hostname, " - ", appname, NULL);
|
||||
@ -139,6 +79,7 @@ void setup(int single)
|
||||
{
|
||||
sk_init();
|
||||
flags = FLAG_VERBOSE | FLAG_INTERACTIVE;
|
||||
cmdline_tooltype |= TOOLTYPE_HOST_ARG | TOOLTYPE_PORT_ARG;
|
||||
default_protocol = be_default_protocol;
|
||||
/* Find the appropriate default port. */
|
||||
{
|
||||
|
@ -360,6 +360,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
|
||||
hinst = inst;
|
||||
hwnd = NULL;
|
||||
flags = FLAG_VERBOSE | FLAG_INTERACTIVE;
|
||||
cmdline_tooltype |= TOOLTYPE_HOST_ARG | TOOLTYPE_PORT_ARG;
|
||||
|
||||
sk_init();
|
||||
|
||||
@ -416,11 +417,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
|
||||
*/
|
||||
{
|
||||
char *p;
|
||||
int got_host = 0;
|
||||
/* By default, we bring up the config dialog, rather than launching
|
||||
* a session. This gets set to TRUE if something happens to change
|
||||
* that (e.g., a hostname is specified on the command-line). */
|
||||
int allow_launch = FALSE;
|
||||
int special_launchable_argument = FALSE;
|
||||
|
||||
default_protocol = be_default_protocol;
|
||||
/* Find the appropriate default port. */
|
||||
@ -470,7 +467,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
|
||||
if (!conf_launchable(conf) && !do_config()) {
|
||||
cleanup_exit(0);
|
||||
}
|
||||
allow_launch = TRUE; /* allow it to be launched directly */
|
||||
special_launchable_argument = TRUE;
|
||||
} else if (*p == '&') {
|
||||
/*
|
||||
* An initial & means we've been given a command line
|
||||
@ -490,7 +487,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
|
||||
} else if (!do_config()) {
|
||||
cleanup_exit(0);
|
||||
}
|
||||
allow_launch = TRUE;
|
||||
special_launchable_argument = TRUE;
|
||||
} else if (!*p) {
|
||||
/* Do-nothing case for an empty command line - or rather,
|
||||
* for a command line that's empty _after_ we strip off
|
||||
@ -545,52 +542,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
|
||||
pgp_fingerprints();
|
||||
exit(1);
|
||||
} else if (*p != '-') {
|
||||
char *q = p;
|
||||
if (got_host) {
|
||||
/*
|
||||
* If we already have a host name, treat
|
||||
* this argument as a port number. NB we
|
||||
* have to treat this as a saved -P
|
||||
* argument, so that it will be deferred
|
||||
* until it's a good moment to run it.
|
||||
*/
|
||||
int ret = cmdline_process_param("-P", p, 1, conf);
|
||||
assert(ret == 2);
|
||||
} else if (!strncmp(q, "telnet:", 7)) {
|
||||
/*
|
||||
* If the hostname starts with "telnet:",
|
||||
* set the protocol to Telnet and process
|
||||
* the string as a Telnet URL.
|
||||
*/
|
||||
char c;
|
||||
|
||||
q += 7;
|
||||
if (q[0] == '/' && q[1] == '/')
|
||||
q += 2;
|
||||
conf_set_int(conf, CONF_protocol, PROT_TELNET);
|
||||
p = q;
|
||||
p += host_strcspn(p, ":/");
|
||||
c = *p;
|
||||
if (*p)
|
||||
*p++ = '\0';
|
||||
if (c == ':')
|
||||
conf_set_int(conf, CONF_port, atoi(p));
|
||||
else
|
||||
conf_set_int(conf, CONF_port, -1);
|
||||
conf_set_str(conf, CONF_host, q);
|
||||
got_host = 1;
|
||||
} else {
|
||||
/*
|
||||
* Otherwise, treat this argument as a host
|
||||
* name.
|
||||
*/
|
||||
while (*p && !isspace(*p))
|
||||
p++;
|
||||
if (*p)
|
||||
*p++ = '\0';
|
||||
conf_set_str(conf, CONF_host, q);
|
||||
got_host = 1;
|
||||
}
|
||||
cmdline_error("unexpected argument \"%s\"", p);
|
||||
} else {
|
||||
cmdline_error("unknown option \"%s\"", p);
|
||||
}
|
||||
@ -599,11 +551,13 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
|
||||
|
||||
cmdline_run_saved(conf);
|
||||
|
||||
if (loaded_session || got_host)
|
||||
allow_launch = TRUE;
|
||||
|
||||
if ((!allow_launch || !conf_launchable(conf)) && !do_config()) {
|
||||
cleanup_exit(0);
|
||||
/*
|
||||
* Bring up the config dialog if the command line hasn't
|
||||
* (explicitly) specified a launchable configuration.
|
||||
*/
|
||||
if (!(special_launchable_argument || cmdline_host_ok(conf))) {
|
||||
if (!do_config())
|
||||
cleanup_exit(0);
|
||||
}
|
||||
|
||||
prepare_session(conf);
|
||||
|
@ -293,7 +293,6 @@ const int share_can_be_upstream = TRUE;
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int sending;
|
||||
int portnumber = -1;
|
||||
SOCKET *sklist;
|
||||
int skcount, sksize;
|
||||
int exitcode;
|
||||
@ -315,6 +314,12 @@ int main(int argc, char **argv)
|
||||
default_port = 22;
|
||||
|
||||
flags = FLAG_STDERR;
|
||||
cmdline_tooltype |=
|
||||
(TOOLTYPE_HOST_ARG |
|
||||
TOOLTYPE_HOST_ARG_CAN_BE_SESSION |
|
||||
TOOLTYPE_HOST_ARG_PROTOCOL_PREFIX |
|
||||
TOOLTYPE_HOST_ARG_FROM_LAUNCHABLE_LOAD);
|
||||
|
||||
/*
|
||||
* Process the command line.
|
||||
*/
|
||||
@ -341,160 +346,68 @@ int main(int argc, char **argv)
|
||||
}
|
||||
while (--argc) {
|
||||
char *p = *++argv;
|
||||
if (*p == '-') {
|
||||
int ret = cmdline_process_param(p, (argc > 1 ? argv[1] : NULL),
|
||||
1, conf);
|
||||
if (ret == -2) {
|
||||
fprintf(stderr,
|
||||
"plink: option \"%s\" requires an argument\n", p);
|
||||
errors = 1;
|
||||
} else if (ret == 2) {
|
||||
--argc, ++argv;
|
||||
} else if (ret == 1) {
|
||||
continue;
|
||||
} else if (!strcmp(p, "-batch")) {
|
||||
console_batch_mode = 1;
|
||||
} else if (!strcmp(p, "-s")) {
|
||||
/* Save status to write to conf later. */
|
||||
use_subsystem = 1;
|
||||
} else if (!strcmp(p, "-V") || !strcmp(p, "--version")) {
|
||||
version();
|
||||
} else if (!strcmp(p, "--help")) {
|
||||
usage();
|
||||
} else if (!strcmp(p, "-pgpfp")) {
|
||||
pgp_fingerprints();
|
||||
exit(1);
|
||||
} else if (!strcmp(p, "-shareexists")) {
|
||||
just_test_share_exists = TRUE;
|
||||
} else {
|
||||
fprintf(stderr, "plink: unknown option \"%s\"\n", p);
|
||||
errors = 1;
|
||||
}
|
||||
} else if (*p) {
|
||||
if (!conf_launchable(conf) || !(got_host || loaded_session)) {
|
||||
char *q = p;
|
||||
/*
|
||||
* If the hostname starts with "telnet:", set the
|
||||
* protocol to Telnet and process the string as a
|
||||
* Telnet URL.
|
||||
*/
|
||||
if (!strncmp(q, "telnet:", 7)) {
|
||||
char c;
|
||||
int ret = cmdline_process_param(p, (argc > 1 ? argv[1] : NULL),
|
||||
1, conf);
|
||||
if (ret == -2) {
|
||||
fprintf(stderr,
|
||||
"plink: option \"%s\" requires an argument\n", p);
|
||||
errors = 1;
|
||||
} else if (ret == 2) {
|
||||
--argc, ++argv;
|
||||
} else if (ret == 1) {
|
||||
continue;
|
||||
} else if (!strcmp(p, "-batch")) {
|
||||
console_batch_mode = 1;
|
||||
} else if (!strcmp(p, "-s")) {
|
||||
/* Save status to write to conf later. */
|
||||
use_subsystem = 1;
|
||||
} else if (!strcmp(p, "-V") || !strcmp(p, "--version")) {
|
||||
version();
|
||||
} else if (!strcmp(p, "--help")) {
|
||||
usage();
|
||||
} else if (!strcmp(p, "-pgpfp")) {
|
||||
pgp_fingerprints();
|
||||
exit(1);
|
||||
} else if (!strcmp(p, "-shareexists")) {
|
||||
just_test_share_exists = TRUE;
|
||||
} else if (*p != '-') {
|
||||
char *command;
|
||||
int cmdlen, cmdsize;
|
||||
cmdlen = cmdsize = 0;
|
||||
command = NULL;
|
||||
|
||||
q += 7;
|
||||
if (q[0] == '/' && q[1] == '/')
|
||||
q += 2;
|
||||
conf_set_int(conf, CONF_protocol, PROT_TELNET);
|
||||
p = q;
|
||||
p += host_strcspn(p, ":/");
|
||||
c = *p;
|
||||
if (*p)
|
||||
*p++ = '\0';
|
||||
if (c == ':')
|
||||
conf_set_int(conf, CONF_port, atoi(p));
|
||||
else
|
||||
conf_set_int(conf, CONF_port, -1);
|
||||
conf_set_str(conf, CONF_host, q);
|
||||
got_host = TRUE;
|
||||
} else {
|
||||
char *r, *user, *host;
|
||||
/*
|
||||
* Before we process the [user@]host string, we
|
||||
* first check for the presence of a protocol
|
||||
* prefix (a protocol name followed by ",").
|
||||
*/
|
||||
r = strchr(p, ',');
|
||||
if (r) {
|
||||
const Backend *b;
|
||||
*r = '\0';
|
||||
b = backend_from_name(p);
|
||||
if (b) {
|
||||
default_protocol = b->protocol;
|
||||
conf_set_int(conf, CONF_protocol,
|
||||
default_protocol);
|
||||
portnumber = b->default_port;
|
||||
}
|
||||
p = r + 1;
|
||||
}
|
||||
while (argc) {
|
||||
while (*p) {
|
||||
if (cmdlen >= cmdsize) {
|
||||
cmdsize = cmdlen + 512;
|
||||
command = sresize(command, cmdsize, char);
|
||||
}
|
||||
command[cmdlen++]=*p++;
|
||||
}
|
||||
if (cmdlen >= cmdsize) {
|
||||
cmdsize = cmdlen + 512;
|
||||
command = sresize(command, cmdsize, char);
|
||||
}
|
||||
command[cmdlen++]=' '; /* always add trailing space */
|
||||
if (--argc) p = *++argv;
|
||||
}
|
||||
if (cmdlen) command[--cmdlen]='\0';
|
||||
/* change trailing blank to NUL */
|
||||
conf_set_str(conf, CONF_remote_cmd, command);
|
||||
conf_set_str(conf, CONF_remote_cmd2, "");
|
||||
conf_set_int(conf, CONF_nopty, TRUE); /* command => no tty */
|
||||
|
||||
/*
|
||||
* A nonzero length string followed by an @ is treated
|
||||
* as a username. (We discount an _initial_ @.) The
|
||||
* rest of the string (or the whole string if no @)
|
||||
* is treated as a session name and/or hostname.
|
||||
*/
|
||||
r = strrchr(p, '@');
|
||||
if (r == p)
|
||||
p++, r = NULL; /* discount initial @ */
|
||||
if (r) {
|
||||
*r++ = '\0';
|
||||
user = p, host = r;
|
||||
} else {
|
||||
user = NULL, host = p;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now attempt to load a saved session with the
|
||||
* same name as the hostname.
|
||||
*/
|
||||
{
|
||||
Conf *conf2 = conf_new();
|
||||
do_defaults(host, conf2);
|
||||
if (loaded_session || !conf_launchable(conf2)) {
|
||||
/* No settings for this host; use defaults */
|
||||
/* (or session was already loaded with -load) */
|
||||
conf_set_str(conf, CONF_host, host);
|
||||
conf_set_int(conf, CONF_port, default_port);
|
||||
got_host = TRUE;
|
||||
} else {
|
||||
conf_copy_into(conf, conf2);
|
||||
loaded_session = TRUE;
|
||||
}
|
||||
conf_free(conf2);
|
||||
}
|
||||
|
||||
if (user) {
|
||||
/* Patch in specified username. */
|
||||
conf_set_str(conf, CONF_username, user);
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
char *command;
|
||||
int cmdlen, cmdsize;
|
||||
cmdlen = cmdsize = 0;
|
||||
command = NULL;
|
||||
|
||||
while (argc) {
|
||||
while (*p) {
|
||||
if (cmdlen >= cmdsize) {
|
||||
cmdsize = cmdlen + 512;
|
||||
command = sresize(command, cmdsize, char);
|
||||
}
|
||||
command[cmdlen++]=*p++;
|
||||
}
|
||||
if (cmdlen >= cmdsize) {
|
||||
cmdsize = cmdlen + 512;
|
||||
command = sresize(command, cmdsize, char);
|
||||
}
|
||||
command[cmdlen++]=' '; /* always add trailing space */
|
||||
if (--argc) p = *++argv;
|
||||
}
|
||||
if (cmdlen) command[--cmdlen]='\0';
|
||||
/* change trailing blank to NUL */
|
||||
conf_set_str(conf, CONF_remote_cmd, command);
|
||||
conf_set_str(conf, CONF_remote_cmd2, "");
|
||||
conf_set_int(conf, CONF_nopty, TRUE); /* command => no tty */
|
||||
|
||||
break; /* done with cmdline */
|
||||
}
|
||||
}
|
||||
break; /* done with cmdline */
|
||||
} else {
|
||||
fprintf(stderr, "plink: unknown option \"%s\"\n", p);
|
||||
errors = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (errors)
|
||||
return 1;
|
||||
|
||||
if (!conf_launchable(conf) || !(got_host || loaded_session)) {
|
||||
if (!cmdline_host_ok(conf)) {
|
||||
usage();
|
||||
}
|
||||
|
||||
@ -527,12 +440,6 @@ int main(int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Select port.
|
||||
*/
|
||||
if (portnumber != -1)
|
||||
conf_set_int(conf, CONF_port, portnumber);
|
||||
|
||||
sk_init();
|
||||
if (p_WSAEventSelect == NULL) {
|
||||
fprintf(stderr, "Plink requires WinSock 2\n");
|
||||
|
Loading…
Reference in New Issue
Block a user