diff --git a/conf-enums.h b/conf-enums.h index 4820bef3..02341686 100644 --- a/conf-enums.h +++ b/conf-enums.h @@ -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), diff --git a/conf.h b/conf.h index b00300b6..b5d8bf4d 100644 --- a/conf.h +++ b/conf.h @@ -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. */ diff --git a/putty.h b/putty.h index b6d43d92..9a3aeb6e 100644 --- a/putty.h +++ b/putty.h @@ -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; }; diff --git a/settings.c b/settings.c index e5e762f1..8bd84dba 100644 --- a/settings.c +++ b/settings.c @@ -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); diff --git a/test/test_conf.c b/test/test_conf.c index 404827f4..d807a6ca 100644 --- a/test/test_conf.c +++ b/test/test_conf.c @@ -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; } diff --git a/utils/conf_data.c b/utils/conf_data.c index ab90a179..74bf60cd 100644 --- a/utils/conf_data.c +++ b/utils/conf_data.c @@ -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"