1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-03-28 17:27:08 -05:00

Add ability to specify custom load and save separately.

This allows a couple more settings to be treated automatically on
save, which are more complicated on load because they still honour
older alternative save keywords.

In particular, CONF_proxy_type and CONF_remote_qtitle_action now have
explicit enum mappings. These were needed for the automated save code,
but also, I've rewritten the custom load code to use them too. This
decouples the storage format of those settings from the order of
values in the internal enum, which is generally an advantage of
specifying storage enums explicitly.

Those two settings weren't already tested by test_conf, because I
wasn't changing them in previous commits. Now I've added extra code
that does test them, and verified it works when backported to commit
b567c9b2b5e159f where I introduced test_conf before beginning the main
refactoring.

A setting can also be specified explicitly as not loaded and saved at
all. There were quite a few commented that way, but now there's a
machine-readable indication of it.

test_conf will now check that all these settings make sense together -
things shouldn't have a save keyword unless they use it, and should
have one if they don't, and shouldn't specify combinations of options
that conflict.

(For that reason, test_conf is now also running the consistency check
before the main test, so that a missing keyword will cause an error
message _before_ it causes a segfault, saving some debugging!)
This commit is contained in:
Simon Tatham 2023-09-22 16:04:25 +01:00
parent 374bb4872e
commit b29758c1b6
6 changed files with 272 additions and 158 deletions

View File

@ -81,6 +81,26 @@ CONF_ENUM(supdup_charset,
VALUE(SUPDUP_CHARSET_WAITS, 2),
)
CONF_ENUM(proxy_type,
VALUE(PROXY_NONE, 0),
VALUE(PROXY_SOCKS4, 1),
VALUE(PROXY_SOCKS5, 2),
VALUE(PROXY_HTTP, 3),
VALUE(PROXY_TELNET, 4),
VALUE(PROXY_CMD, 5),
VALUE(PROXY_SSH_TCPIP, 6),
VALUE(PROXY_SSH_EXEC, 7),
VALUE(PROXY_SSH_SUBSYSTEM, 8),
)
CONF_ENUM(old_proxy_type,
VALUE(PROXY_NONE, 0),
VALUE(PROXY_HTTP, 1),
VALUE(PROXY_SOCKS5, 2), /* really, both SOCKS 4 and 5 */
VALUE(PROXY_TELNET, 3),
VALUE(PROXY_CMD, 4),
)
CONF_ENUM(funky_type,
VALUE(FUNKY_TILDE, 0),
VALUE(FUNKY_LINUX, 1),
@ -96,6 +116,12 @@ CONF_ENUM(sharrow_type,
VALUE(SHARROW_BITMAP, 1),
)
CONF_ENUM(remote_qtitle_action,
VALUE(TITLE_NONE, 0),
VALUE(TITLE_EMPTY, 1),
VALUE(TITLE_REAL, 2),
)
CONF_ENUM(cursor_type,
VALUE(CURSOR_BLOCK, 0),
VALUE(CURSOR_UNDERLINE, 1),

131
conf.h
View File

@ -18,14 +18,12 @@ CONF_OPTION(host,
)
CONF_OPTION(port,
VALUE_TYPE(INT),
/*
* Notionally SAVE_KEYWORD("PortNumber"), but saving/loading is
* handled by custom code because the default value depends on the
* value of CONF_protocol.
*/
SAVE_KEYWORD("PortNumber"),
LOAD_CUSTOM, /* default value depends on the value of CONF_protocol */
)
CONF_OPTION(protocol,
VALUE_TYPE(INT), /* PROT_SSH, PROT_TELNET etc */
LOAD_CUSTOM, SAVE_CUSTOM,
/*
* Notionally SAVE_KEYWORD("Protocol"), but saving/loading is handled by
* custom code because the stored value is a string representation
@ -51,6 +49,7 @@ CONF_OPTION(warn_on_close,
)
CONF_OPTION(ping_interval,
VALUE_TYPE(INT), /* in seconds */
LOAD_CUSTOM, SAVE_CUSTOM,
/*
* Saving/loading is handled by custom code because for historical
* reasons this value corresponds to two save keywords,
@ -95,11 +94,14 @@ CONF_OPTION(even_proxy_localhost,
)
CONF_OPTION(proxy_type,
VALUE_TYPE(INT), /* PROXY_NONE, PROXY_SOCKS4, ... */
STORAGE_ENUM(proxy_type),
SAVE_KEYWORD("ProxyMethod"),
LOAD_CUSTOM,
/*
* SAVE_KEYWORD("ProxyMethod"), for the current configuration
* format. But there was an earlier keyword "ProxyType" using a
* different enumeration, in which SOCKS4 and SOCKS5 shared a
* value, and a second keyword "ProxySOCKSVersion" disambiguated.
* Custom load code: there was an earlier keyword "ProxyType"
* using a different enumeration, in which SOCKS4 and SOCKS5
* shared a value, and a second keyword "ProxySOCKSVersion"
* disambiguated.
*/
)
CONF_OPTION(proxy_host,
@ -148,6 +150,7 @@ CONF_OPTION(remote_cmd2,
* by user configuration, or loaded or saved.
*/
VALUE_TYPE(STR),
NOT_SAVED,
)
CONF_OPTION(nopty,
VALUE_TYPE(BOOL),
@ -163,19 +166,13 @@ CONF_OPTION(ssh_kexlist,
SUBKEY_TYPE(INT), /* indices in preference order: 0,...,KEX_MAX-1
* (lower is more preferred) */
VALUE_TYPE(INT), /* KEX_* enum values */
/*
* Loading and saving is done by custom code for all preference
* lists
*/
LOAD_CUSTOM, SAVE_CUSTOM, /* necessary for preference lists */
)
CONF_OPTION(ssh_hklist,
SUBKEY_TYPE(INT), /* indices in preference order: 0,...,HK_MAX-1
* (lower is more preferred) */
VALUE_TYPE(INT), /* HK_* enum values */
/*
* Loading and saving is done by custom code for all preference
* lists
*/
LOAD_CUSTOM, SAVE_CUSTOM, /* necessary for preference lists */
)
CONF_OPTION(ssh_prefer_known_hostkeys,
VALUE_TYPE(BOOL),
@ -211,10 +208,7 @@ CONF_OPTION(ssh_cipherlist,
SUBKEY_TYPE(INT), /* indices in preference order: 0,...,CIPHER_MAX-1
* (lower is more preferred) */
VALUE_TYPE(INT), /* CIPHER_* enum values */
/*
* Loading and saving is done by custom code for all preference
* lists
*/
LOAD_CUSTOM, SAVE_CUSTOM, /* necessary for preference lists */
)
CONF_OPTION(keyfile,
VALUE_TYPE(FILENAME),
@ -261,6 +255,7 @@ CONF_OPTION(ssh_simple,
* user configuration, or loaded or saved.
*/
VALUE_TYPE(BOOL),
NOT_SAVED,
)
CONF_OPTION(ssh_connection_sharing,
VALUE_TYPE(BOOL),
@ -288,9 +283,7 @@ CONF_OPTION(ssh_manual_hostkeys,
*/
SUBKEY_TYPE(STR),
VALUE_TYPE(STR),
/*
* Loading and saving is done by custom code for all mappings
*/
LOAD_CUSTOM, SAVE_CUSTOM, /* necessary for mappings */
)
CONF_OPTION(ssh2_des_cbc, /* "des-cbc" unrecommended SSH-2 cipher */
VALUE_TYPE(BOOL),
@ -324,49 +317,31 @@ CONF_OPTION(try_ki_auth,
)
CONF_OPTION(try_gssapi_auth, /* attempt gssapi via ssh userauth */
VALUE_TYPE(BOOL),
/*
* Loading and saving is done by custom code because it's under
* #ifndef NO_GSSAPI
*/
LOAD_CUSTOM, SAVE_CUSTOM, /* under #ifndef NO_GSSAPI */
)
CONF_OPTION(try_gssapi_kex, /* attempt gssapi via ssh kex */
VALUE_TYPE(BOOL),
/*
* Loading and saving is done by custom code because it's under
* #ifndef NO_GSSAPI
*/
LOAD_CUSTOM, SAVE_CUSTOM, /* under #ifndef NO_GSSAPI */
)
CONF_OPTION(gssapifwd, /* forward tgt via gss */
VALUE_TYPE(BOOL),
/*
* Loading and saving is done by custom code because it's under
* #ifndef NO_GSSAPI
*/
LOAD_CUSTOM, SAVE_CUSTOM, /* under #ifndef NO_GSSAPI */
)
CONF_OPTION(gssapirekey, /* KEXGSS refresh interval (mins) */
VALUE_TYPE(INT),
/*
* Loading and saving is done by custom code because it's under
* #ifndef NO_GSSAPI
*/
LOAD_CUSTOM, SAVE_CUSTOM, /* under #ifndef NO_GSSAPI */
)
CONF_OPTION(ssh_gsslist,
SUBKEY_TYPE(INT), /* indices in preference order: 0,...,ngsslibs
* (lower is more preferred; ngsslibs is a platform-
* dependent value) */
VALUE_TYPE(INT), /* indices of GSSAPI lib types (platform-dependent) */
/*
* Loading and saving is done by custom code because it's under
* #ifndef NO_GSSAPI, and also because all preference lists are
* handled by custom code
*/
LOAD_CUSTOM, SAVE_CUSTOM, /* necessary for preference lists, also this
* setting is under #ifndef NO_GSSAPI */
)
CONF_OPTION(ssh_gss_custom,
VALUE_TYPE(FILENAME),
/*
* Loading and saving is done by custom code because it's under
* #ifndef NO_GSSAPI
*/
LOAD_CUSTOM, SAVE_CUSTOM, /* under #ifndef NO_GSSAPI */
)
CONF_OPTION(ssh_subsys, /* run a subsystem rather than a command */
/*
@ -374,6 +349,7 @@ CONF_OPTION(ssh_subsys, /* run a subsystem rather than a command */
* configuration, or loaded or saved.
*/
VALUE_TYPE(BOOL),
NOT_SAVED,
)
CONF_OPTION(ssh_subsys2, /* fallback to go with remote_cmd_ptr2 */
/*
@ -381,6 +357,7 @@ CONF_OPTION(ssh_subsys2, /* fallback to go with remote_cmd_ptr2 */
* configuration, or loaded or saved.
*/
VALUE_TYPE(BOOL),
NOT_SAVED,
)
CONF_OPTION(ssh_no_shell, /* avoid running a shell */
VALUE_TYPE(BOOL),
@ -394,6 +371,7 @@ CONF_OPTION(ssh_nc_host, /* host to connect to in `nc' mode */
* also never loaded or saved.
*/
VALUE_TYPE(STR),
NOT_SAVED,
)
CONF_OPTION(ssh_nc_port, /* port to connect to in `nc' mode */
/*
@ -402,6 +380,7 @@ CONF_OPTION(ssh_nc_port, /* port to connect to in `nc' mode */
* also never loaded or saved.
*/
VALUE_TYPE(INT),
NOT_SAVED,
)
/* Telnet options */
@ -418,16 +397,12 @@ CONF_OPTION(termspeed,
CONF_OPTION(ttymodes,
SUBKEY_TYPE(STR), /* subkeys are listed in ttymodes[] in settings.c */
VALUE_TYPE(STR), /* values are "Vvalue" or "A" */
/*
* Loading and saving is done by custom code for all mappings
*/
LOAD_CUSTOM, SAVE_CUSTOM, /* necessary for mappings */
)
CONF_OPTION(environmt,
SUBKEY_TYPE(STR), /* environment variable name */
VALUE_TYPE(STR), /* environment variable value */
/*
* Loading and saving is done by custom code for all mappings
*/
LOAD_CUSTOM, SAVE_CUSTOM, /* necessary for mappings */
)
CONF_OPTION(username,
VALUE_TYPE(STR),
@ -582,11 +557,10 @@ CONF_OPTION(no_remote_charset, /* disable remote charset config */
)
CONF_OPTION(remote_qtitle_action, /* handling of remote window title queries */
VALUE_TYPE(INT),
/*
* SAVE_KEYWORD("RemoteQTitleAction"), but loading and saving is
* done in custom code, because older versions had a boolean
* "NoRemoteQTitle" before we ended up with three options.
*/
STORAGE_ENUM(remote_qtitle_action),
SAVE_KEYWORD("RemoteQTitleAction"),
LOAD_CUSTOM, /* older versions had a boolean "NoRemoteQTitle"
* before we ended up with three options */
)
CONF_OPTION(app_cursor,
VALUE_TYPE(BOOL),
@ -677,17 +651,11 @@ CONF_OPTION(ctrlaltkeys,
)
CONF_OPTION(osx_option_meta,
VALUE_TYPE(BOOL),
/*
* Loading and saving is done in custom code because this is under
* #ifdef OSX_META_KEY_CONFIG
*/
LOAD_CUSTOM, SAVE_CUSTOM, /* under #ifdef OSX_META_KEY_CONFIG */
)
CONF_OPTION(osx_command_meta,
VALUE_TYPE(BOOL),
/*
* Loading and saving is done in custom code because this is under
* #ifdef OSX_META_KEY_CONFIG
*/
LOAD_CUSTOM, SAVE_CUSTOM, /* under #ifdef OSX_META_KEY_CONFIG */
)
CONF_OPTION(wintitle, /* initial window title */
VALUE_TYPE(STR),
@ -750,6 +718,7 @@ CONF_OPTION(bellovl_n, /* number of bells to cause overload */
)
CONF_OPTION(bellovl_t, /* time interval for overload (ticks) */
VALUE_TYPE(INT),
LOAD_CUSTOM, SAVE_CUSTOM,
/*
* Loading and saving is done in custom code because the format is
* platform-dependent for historical reasons: on Unix, the stored
@ -760,6 +729,7 @@ CONF_OPTION(bellovl_t, /* time interval for overload (ticks) */
)
CONF_OPTION(bellovl_s, /* period of silence to re-enable bell (s) */
VALUE_TYPE(INT),
LOAD_CUSTOM, SAVE_CUSTOM,
/*
* Loading and saving is done in custom code because the format is
* platform-dependent for historical reasons: on Unix, the stored
@ -930,9 +900,7 @@ CONF_OPTION(bold_style,
CONF_OPTION(colours,
SUBKEY_TYPE(INT), /* indexed by CONF_COLOUR_* enum encoding */
VALUE_TYPE(INT),
/*
* Loading and saving is done by custom code for all mappings
*/
LOAD_CUSTOM, SAVE_CUSTOM, /* necessary for mappings */
)
/* Selection options */
@ -975,9 +943,7 @@ CONF_OPTION(mouse_override,
CONF_OPTION(wordness,
SUBKEY_TYPE(INT), /* ASCII character codes (literally, just 00-7F) */
VALUE_TYPE(INT), /* arbitrary equivalence-class value for that char */
/*
* Loading and saving is done by custom code for all mappings
*/
LOAD_CUSTOM, SAVE_CUSTOM, /* necessary for mappings */
)
CONF_OPTION(mouseautocopy,
/*
@ -991,6 +957,7 @@ CONF_OPTION(mouseautocopy,
)
CONF_OPTION(mousepaste, /* clipboard used by one-mouse-click paste actions */
VALUE_TYPE(INT),
LOAD_CUSTOM, SAVE_CUSTOM,
/*
* SAVE_KEYWORD("MousePaste"), but loading and saving is done by
* custom code, because the saved value is a string, and also sets
@ -999,6 +966,7 @@ CONF_OPTION(mousepaste, /* clipboard used by one-mouse-click paste actions */
)
CONF_OPTION(ctrlshiftins, /* clipboard used by Ctrl+Ins and Shift+Ins */
VALUE_TYPE(INT),
LOAD_CUSTOM, SAVE_CUSTOM,
/*
* SAVE_KEYWORD("CtrlShiftIns"), but loading and saving is done by
* custom code, because the saved value is a string, and also sets
@ -1007,6 +975,7 @@ CONF_OPTION(ctrlshiftins, /* clipboard used by Ctrl+Ins and Shift+Ins */
)
CONF_OPTION(ctrlshiftcv, /* clipboard used by Ctrl+Shift+C and Ctrl+Shift+V */
VALUE_TYPE(INT),
LOAD_CUSTOM, SAVE_CUSTOM,
/*
* SAVE_KEYWORD("CtrlShiftCV"), but loading and saving is done by
* custom code, because the saved value is a string, and also sets
@ -1016,6 +985,7 @@ CONF_OPTION(ctrlshiftcv, /* clipboard used by Ctrl+Shift+C and Ctrl+Shift+V */
CONF_OPTION(mousepaste_custom,
/* Custom clipboard name if CONF_mousepaste is set to CLIPUI_CUSTOM */
VALUE_TYPE(STR),
LOAD_CUSTOM, SAVE_CUSTOM,
/*
* Loading and saving is handled by custom code in conjunction
* with CONF_mousepaste
@ -1024,6 +994,7 @@ CONF_OPTION(mousepaste_custom,
CONF_OPTION(ctrlshiftins_custom,
/* Custom clipboard name if CONF_ctrlshiftins is set to CLIPUI_CUSTOM */
VALUE_TYPE(STR),
LOAD_CUSTOM, SAVE_CUSTOM,
/*
* Loading and saving is handled by custom code in conjunction
* with CONF_ctrlshiftins
@ -1032,6 +1003,7 @@ CONF_OPTION(ctrlshiftins_custom,
CONF_OPTION(ctrlshiftcv_custom,
/* Custom clipboard name if CONF_ctrlshiftcv is set to CLIPUI_CUSTOM */
VALUE_TYPE(STR),
LOAD_CUSTOM, SAVE_CUSTOM,
/*
* Loading and saving is handled by custom code in conjunction
* with CONF_ctrlshiftcv
@ -1112,9 +1084,7 @@ CONF_OPTION(portfwd,
*/
SUBKEY_TYPE(STR),
VALUE_TYPE(STR),
/*
* Loading and saving is done by custom code for all mappings
*/
LOAD_CUSTOM, SAVE_CUSTOM, /* necessary for mappings */
)
/* SSH bug compatibility modes. All FORCE_ON/FORCE_OFF/AUTO */
@ -1210,11 +1180,10 @@ CONF_OPTION(sshbug_rsa_sha2_cert_userauth,
)
CONF_OPTION(sshbug_hmac2,
VALUE_TYPE(INT),
DEFAULT_INT(AUTO),
SAVE_KEYWORD("BugHMAC2"),
STORAGE_ENUM(auto_off_on),
/*
* Loading and saving is done by custom code because there was an
* earlier keyword called "BuggyMAC"
*/
LOAD_CUSTOM, /* there was an earlier keyword called "BuggyMAC" */
)
/* Options for Unix. Should split out into platform-dependent part. */

View File

@ -1820,6 +1820,10 @@ struct ConfKeyInfo {
const char *sval;
} default_value;
bool save_custom : 1;
bool load_custom : 1;
bool not_saved : 1;
const char *save_keyword;
const ConfSaveEnumType *storage_enum;
};

View File

@ -525,6 +525,11 @@ char *save_settings(const char *section, Conf *conf)
return NULL;
}
/* Declare extern references to conf_enum_* types */
#define CONF_ENUM(name, ...) extern const ConfSaveEnumType conf_enum_##name;
#include "conf-enums.h"
#undef CONF_ENUM
void save_open_settings(settings_w *sesskey, Conf *conf)
{
int i;
@ -533,7 +538,7 @@ void save_open_settings(settings_w *sesskey, Conf *conf)
/* Save the settings simple enough to handle automatically */
for (size_t key = 0; key < N_CONFIG_OPTIONS; key++) {
const ConfKeyInfo *info = &conf_key_info[key];
if (info->save_keyword) {
if (!info->save_custom && !info->not_saved) {
/* Mappings are handled individually below */
assert(info->subkey_type == CONF_TYPE_NONE);
switch (info->value_type) {
@ -578,13 +583,11 @@ void save_open_settings(settings_w *sesskey, Conf *conf)
p = vt->id;
}
write_setting_s(sesskey, "Protocol", p);
write_setting_i(sesskey, "PortNumber", conf_get_int(conf, CONF_port));
write_setting_i(sesskey, "PingInterval", conf_get_int(conf, CONF_ping_interval) / 60); /* minutes */
write_setting_i(sesskey, "PingIntervalSecs", conf_get_int(conf, CONF_ping_interval) % 60); /* seconds */
wmap(sesskey, "TerminalModes", conf, CONF_ttymodes, true);
/* proxy settings */
write_setting_i(sesskey, "ProxyMethod", conf_get_int(conf, CONF_proxy_type));
wmap(sesskey, "Environment", conf, CONF_environmt, true);
#ifndef NO_GSSAPI
write_setting_b(sesskey, "GssapiFwd", conf_get_bool(conf, CONF_gssapifwd));
@ -601,7 +604,6 @@ void save_open_settings(settings_w *sesskey, Conf *conf)
wprefs(sesskey, "GSSLibs", gsslibkeywords, ngsslibs, conf, CONF_ssh_gsslist);
write_setting_filename(sesskey, "GSSCustom", conf_get_filename(conf, CONF_ssh_gss_custom));
#endif
write_setting_i(sesskey, "RemoteQTitleAction", conf_get_int(conf, CONF_remote_qtitle_action));
#ifdef OSX_META_KEY_CONFIG
write_setting_b(sesskey, "OSXOptionMeta", conf_get_bool(conf, CONF_osx_option_meta));
write_setting_b(sesskey, "OSXCommandMeta", conf_get_bool(conf, CONF_osx_command_meta));
@ -645,7 +647,6 @@ void save_open_settings(settings_w *sesskey, Conf *conf)
write_clip_setting(sesskey, "CtrlShiftCV", conf,
CONF_ctrlshiftcv, CONF_ctrlshiftcv_custom);
wmap(sesskey, "PortForwardings", conf, CONF_portfwd, true);
write_setting_i(sesskey, "BugHMAC2", 2-conf_get_int(conf, CONF_sshbug_hmac2));
wmap(sesskey, "SSHManualHostKeys", conf, CONF_ssh_manual_hostkeys, false);
}
@ -677,7 +678,7 @@ void load_open_settings(settings_r *sesskey, Conf *conf)
/* Load the settings simple enough to handle automatically */
for (size_t key = 0; key < N_CONFIG_OPTIONS; key++) {
const ConfKeyInfo *info = &conf_key_info[key];
if (info->save_keyword) {
if (!info->load_custom && !info->not_saved) {
/* Mappings are handled individually below */
assert(info->subkey_type == CONF_TYPE_NONE);
switch (info->value_type) {
@ -804,26 +805,25 @@ void load_open_settings(settings_r *sesskey, Conf *conf)
}
/* proxy settings */
gppi(sesskey, "ProxyMethod", -1, conf, CONF_proxy_type);
if (conf_get_int(conf, CONF_proxy_type) == -1) {
int i;
i = gppi_raw(sesskey, "ProxyType", 0);
if (i == 0)
conf_set_int(conf, CONF_proxy_type, PROXY_NONE);
else if (i == 1)
conf_set_int(conf, CONF_proxy_type, PROXY_HTTP);
else if (i == 3)
conf_set_int(conf, CONF_proxy_type, PROXY_TELNET);
else if (i == 4)
conf_set_int(conf, CONF_proxy_type, PROXY_CMD);
else {
i = gppi_raw(sesskey, "ProxySOCKSVersion", 5);
if (i == 5)
conf_set_int(conf, CONF_proxy_type, PROXY_SOCKS5);
else
conf_set_int(conf, CONF_proxy_type, PROXY_SOCKS4);
{
int storageval = gppi_raw(sesskey, "ProxyMethod", -1);
int confval;
if (!conf_enum_map_from_storage(&conf_enum_proxy_type,
storageval, &confval)) {
/*
* Fall back to older ProxyType and ProxySOCKSVersion format
*/
storageval = gppi_raw(sesskey, "ProxyType", 0);
if (conf_enum_map_from_storage(&conf_enum_old_proxy_type,
storageval, &confval)) {
if (confval == PROXY_SOCKS5 &&
gppi_raw(sesskey, "ProxySOCKSVersion", 5) == 4)
confval = PROXY_SOCKS4;
}
}
conf_set_int(conf, CONF_proxy_type, confval);
}
gppmap(sesskey, "Environment", conf, CONF_environmt);
#ifndef NO_GSSAPI
gppb(sesskey, "GssapiFwd", false, conf, CONF_gssapifwd);
@ -881,8 +881,6 @@ void load_open_settings(settings_r *sesskey, Conf *conf)
hknames, HK_MAX, conf, CONF_ssh_hklist);
#ifndef NO_GSSAPI
gppi(sesskey, "GssapiRekey", GSS_DEF_REKEY_MINS, conf, CONF_gssapirekey);
#endif
#ifndef NO_GSSAPI
gppb(sesskey, "AuthGSSAPI", true, conf, CONF_try_gssapi_auth);
gppb(sesskey, "AuthGSSAPIKEX", true, conf, CONF_try_gssapi_kex);
gprefs(sesskey, "GSSLibs", "\0",
@ -890,14 +888,20 @@ void load_open_settings(settings_r *sesskey, Conf *conf)
gppfile(sesskey, "GSSCustom", conf, CONF_ssh_gss_custom);
#endif
{
/* Backward compatibility */
int no_remote_qtitle = gppi_raw(sesskey, "NoRemoteQTitle", 1);
/* We deliberately interpret the old setting of "no response" as
* "empty string". This changes the behaviour, but hopefully for
* the better; the user can always recover the old behaviour. */
gppi(sesskey, "RemoteQTitleAction",
no_remote_qtitle ? TITLE_EMPTY : TITLE_REAL,
conf, CONF_remote_qtitle_action);
int storageval = gppi_raw(sesskey, "RemoteQTitleAction", -1);
int confval;
if (!conf_enum_map_from_storage(&conf_enum_remote_qtitle_action,
storageval, &confval)) {
/*
* Fall back to older NoRemoteQTitle format
*/
storageval = gppi_raw(sesskey, "NoRemoteQTitle", 1);
/* We deliberately interpret the old setting of "no response" as
* "empty string". This changes the behaviour, but hopefully for
* the better; the user can always recover the old behaviour. */
confval = storageval ? TITLE_EMPTY : TITLE_REAL;
}
conf_set_int(conf, CONF_remote_qtitle_action, confval);
}
#ifdef OSX_META_KEY_CONFIG
gppb(sesskey, "OSXOptionMeta", true, conf, CONF_osx_option_meta);

View File

@ -323,7 +323,9 @@ void test_int_simple(int confid, const char *saveid, int defexp)
conf_free(conf);
}
void test_int_translated(int confid, const char *saveid, int defexp, ...)
void test_int_translated_internal(
int confid, const char *saveid, bool test_save, bool test_load,
void (*load_prepare)(settings_r *), int defexp, va_list ap)
{
Conf *conf = conf_new();
@ -335,52 +337,76 @@ void test_int_translated(int confid, const char *saveid, int defexp, ...)
nfails++;
}
va_list ap;
va_start(ap, defexp);
int confval = va_arg(ap, int);
while (confval != -1) {
int storageval = va_arg(ap, int);
settings_w sw = {
.n = 1,
.si[0].key = saveid,
.si[0].type = SAVE_UNSET,
};
conf_set_int(conf, confid, confval);
save_open_settings(&sw, conf);
if (sw.si[0].type != SAVE_I) {
printf("fail test_int_translated(%s): "
"saved type = %d, expected %d\n",
saveid, sw.si[0].type, SAVE_I);
nfails++;
} else if (sw.si[0].ival != storageval) {
printf("fail test_int_translated(%s.%d.%d): "
"saved integer = %d, expected %d\n",
saveid, confval, storageval, sw.si[0].ival, storageval);
nfails++;
if (test_save) {
settings_w sw = {
.n = 1,
.si[0].key = saveid,
.si[0].type = SAVE_UNSET,
};
conf_set_int(conf, confid, confval);
save_open_settings(&sw, conf);
if (sw.si[0].type != SAVE_I) {
printf("fail test_int_translated(%s): "
"saved type = %d, expected %d\n",
saveid, sw.si[0].type, SAVE_I);
nfails++;
} else if (sw.si[0].ival != storageval) {
printf("fail test_int_translated(%s.%d.%d): "
"saved integer = %d, expected %d\n",
saveid, confval, storageval, sw.si[0].ival, storageval);
nfails++;
}
}
conf_clear(conf);
settings_r sr = {
.n = 1,
.si[0].key = saveid,
.si[0].type = SAVE_I,
.si[0].ival = storageval,
};
load_open_settings(&sr, conf);
int loaded = conf_get_int(conf, confid);
if (loaded != confval) {
printf("fail test_int_translated(%s.%d.%d): "
"loaded integer = %d, expected %d\n",
saveid, confval, storageval, loaded, confval);
nfails++;
if (test_load) {
conf_clear(conf);
settings_r sr = {
.n = 1,
.si[0].key = saveid,
.si[0].type = SAVE_I,
.si[0].ival = storageval,
};
if (load_prepare)
load_prepare(&sr);
load_open_settings(&sr, conf);
int loaded = conf_get_int(conf, confid);
if (loaded != confval) {
printf("fail test_int_translated(%s.%d.%d): "
"loaded integer = %d, expected %d\n",
saveid, confval, storageval, loaded, confval);
nfails++;
}
}
confval = va_arg(ap, int);
}
va_end(ap);
conf_free(conf);
}
void test_int_translated(int confid, const char *saveid, int defexp, ...)
{
va_list ap;
va_start(ap, defexp);
test_int_translated_internal(confid, saveid, true, true, NULL, defexp, ap);
va_end(ap);
}
void test_int_translated_load_legacy(
int confid, const char *saveid, void (*load_prepare)(settings_r *),
int defexp, ...)
{
va_list ap;
va_start(ap, defexp);
test_int_translated_internal(confid, saveid, false, true, load_prepare,
defexp, ap);
va_end(ap);
}
void test_bool_simple(int confid, const char *saveid, bool defexp)
{
Conf *conf = conf_new();
@ -532,6 +558,14 @@ void test_font_simple(int confid, const char *saveid)
conf_free(conf);
}
static void load_prepare_socks4(settings_r *sr)
{
size_t pos = sr->n++;
sr->si[pos].key = "ProxySOCKSVersion";
sr->si[pos].type = SAVE_I;
sr->si[pos].ival = 4;
}
void test_simple(void)
{
test_str_simple(CONF_host, "HostName", "");
@ -764,6 +798,22 @@ void test_simple(void)
FORCE_OFF, 1, FORCE_ON, 2, -1);
test_int_translated(CONF_sshbug_rsa_sha2_cert_userauth, "BugRSASHA2CertUserauth", AUTO,
AUTO, 0, FORCE_OFF, 1, FORCE_ON, 2, -1);
test_int_translated(CONF_proxy_type, "ProxyMethod", PROXY_NONE,
PROXY_NONE, 0, PROXY_SOCKS4, 1, PROXY_SOCKS5, 2,
PROXY_HTTP, 3, PROXY_TELNET, 4, PROXY_CMD, 5,
PROXY_SSH_TCPIP, 6, PROXY_SSH_EXEC, 7,
PROXY_SSH_SUBSYSTEM, 8, -1);
test_int_translated_load_legacy(
CONF_proxy_type, "ProxyType", NULL, PROXY_NONE,
PROXY_HTTP, 1, PROXY_SOCKS5, 2, PROXY_TELNET, 3, PROXY_CMD, 4, -1);
test_int_translated_load_legacy(
CONF_proxy_type, "ProxyType", load_prepare_socks4, PROXY_NONE,
PROXY_HTTP, 1, PROXY_SOCKS4, 2, PROXY_TELNET, 3, PROXY_CMD, 4, -1);
test_int_translated(CONF_remote_qtitle_action, "RemoteQTitleAction", TITLE_EMPTY,
TITLE_NONE, 0, TITLE_EMPTY, 1, TITLE_REAL, 2, -1);
test_int_translated_load_legacy(
CONF_remote_qtitle_action, "NoRemoteQTitle", NULL, TITLE_EMPTY,
TITLE_REAL, 0, TITLE_EMPTY, 1, -1);
}
void test_conf_key_info(void)
@ -777,6 +827,9 @@ void test_conf_key_info(void)
bool got_default_bool : 1;
bool got_save_keyword : 1;
bool got_storage_enum : 1;
bool save_custom : 1;
bool load_custom : 1;
bool not_saved : 1;
};
#define CONF_OPTION(id, ...) { .name = "CONF_" #id, __VA_ARGS__ },
@ -787,6 +840,9 @@ void test_conf_key_info(void)
#define DEFAULT_BOOL(x) .got_default_bool = true
#define SAVE_KEYWORD(x) .got_save_keyword = true
#define STORAGE_ENUM(x) .got_storage_enum = true
#define SAVE_CUSTOM .save_custom = true
#define LOAD_CUSTOM .load_custom = true
#define NOT_SAVED .not_saved = true
static const struct test_data conf_key_test_data[] = {
#include "conf.h"
@ -807,12 +863,64 @@ void test_conf_key_info(void)
fprintf(stderr, "%s: default doesn't match type\n", td->name);
nfails++;
}
if (td->got_storage_enum && info->value_type != CONF_TYPE_INT) {
fprintf(stderr, "%s: has STORAGE_ENUM but isn't an int\n",
td->name);
nfails++;
}
if (td->not_saved) {
if (td->got_save_keyword) {
fprintf(stderr, "%s: not saved but has SAVE_KEYWORD\n",
td->name);
nfails++;
}
if (td->save_custom) {
fprintf(stderr, "%s: not saved but has SAVE_CUSTOM\n",
td->name);
nfails++;
}
if (td->load_custom) {
fprintf(stderr, "%s: not saved but has LOAD_CUSTOM\n",
td->name);
nfails++;
}
if (td->got_storage_enum) {
fprintf(stderr, "%s: not saved but has STORAGE_ENUM\n",
td->name);
nfails++;
}
} else {
if (td->load_custom && td->save_custom) {
if (td->got_save_keyword) {
fprintf(stderr, "%s: no automatic save or load but has "
"SAVE_KEYWORD\n", td->name);
nfails++;
}
if (td->got_storage_enum) {
fprintf(stderr, "%s: no automatic save or load but has "
"STORAGE_ENUM\n", td->name);
nfails++;
}
} else {
if (!td->got_save_keyword) {
fprintf(stderr, "%s: missing SAVE_KEYWORD\n", td->name);
nfails++;
}
}
}
}
}
int main(void)
{
test_simple();
test_conf_key_info();
test_simple();
return nfails != 0;
}

View File

@ -1,11 +1,11 @@
#include "putty.h"
#define CONF_ENUM(name, ...) \
static const ConfSaveEnumValue enum_values_##name[] = { \
__VA_ARGS__ \
}; static const ConfSaveEnumType enum_##name = { \
.values = enum_values_##name, \
.nvalues = lenof(enum_values_##name), \
#define CONF_ENUM(name, ...) \
static const ConfSaveEnumValue conf_enum_values_##name[] = { \
__VA_ARGS__ \
}; const ConfSaveEnumType conf_enum_##name = { \
.values = conf_enum_values_##name, \
.nvalues = lenof(conf_enum_values_##name), \
};
#define VALUE(eval, sval) { eval, sval, false }
@ -43,7 +43,10 @@ bool conf_enum_map_from_storage(const ConfSaveEnumType *etype,
#define DEFAULT_STR(x) .default_value.sval = x
#define DEFAULT_BOOL(x) .default_value.bval = x
#define SAVE_KEYWORD(x) .save_keyword = x
#define STORAGE_ENUM(x) .storage_enum = &enum_ ## x
#define STORAGE_ENUM(x) .storage_enum = &conf_enum_ ## x
#define SAVE_CUSTOM .save_custom = true
#define LOAD_CUSTOM .load_custom = true
#define NOT_SAVED .not_saved = true
const ConfKeyInfo conf_key_info[] = {
#include "conf.h"