mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-06-30 11:02:48 -05: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:
@ -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. */
|
||||
{
|
||||
|
Reference in New Issue
Block a user