Use STL algorithms more often
[TortoiseGit.git] / src / TortoisePlink / SETTINGS.C
blob80daa8398bea71b2de02dc3d5a2afea840b31b5d
1 /*\r
2  * settings.c: read and write saved sessions. (platform-independent)\r
3  */\r
4 \r
5 #include <assert.h>\r
6 #include <stdio.h>\r
7 #include <stdlib.h>\r
8 #include "putty.h"\r
9 #include "storage.h"\r
11 /* The cipher order given here is the default order. */\r
12 static const struct keyvalwhere ciphernames[] = {\r
13     { "aes",        CIPHER_AES,             -1, -1 },\r
14     { "chacha20",   CIPHER_CHACHA20,        CIPHER_AES, +1 },\r
15     { "blowfish",   CIPHER_BLOWFISH,        -1, -1 },\r
16     { "3des",       CIPHER_3DES,            -1, -1 },\r
17     { "WARN",       CIPHER_WARN,            -1, -1 },\r
18     { "arcfour",    CIPHER_ARCFOUR,         -1, -1 },\r
19     { "des",        CIPHER_DES,             -1, -1 }\r
20 };\r
22 /* The default order here is sometimes overridden by the backward-\r
23  * compatibility warts in load_open_settings(), and should be kept\r
24  * in sync with those. */\r
25 static const struct keyvalwhere kexnames[] = {\r
26     { "ecdh",               KEX_ECDH,       -1, +1 },\r
27     /* This name is misleading: it covers both SHA-256 and SHA-1 variants */\r
28     { "dh-gex-sha1",        KEX_DHGEX,      -1, -1 },\r
29     { "dh-group14-sha1",    KEX_DHGROUP14,  -1, -1 },\r
30     { "dh-group1-sha1",     KEX_DHGROUP1,   KEX_WARN, +1 },\r
31     { "rsa",                KEX_RSA,        KEX_WARN, -1 },\r
32     { "WARN",               KEX_WARN,       -1, -1 }\r
33 };\r
35 static const struct keyvalwhere hknames[] = {\r
36     { "ed25519",    HK_ED25519,             -1, +1 },\r
37     { "ecdsa",      HK_ECDSA,               -1, -1 },\r
38     { "dsa",        HK_DSA,                 -1, -1 },\r
39     { "rsa",        HK_RSA,                 -1, -1 },\r
40     { "WARN",       HK_WARN,                -1, -1 },\r
41 };\r
43 /*\r
44  * All the terminal modes that we know about for the "TerminalModes"\r
45  * setting. (Also used by config.c for the drop-down list.)\r
46  * This is currently precisely the same as the set in ssh.c, but could\r
47  * in principle differ if other backends started to support tty modes\r
48  * (e.g., the pty backend).\r
49  * The set of modes in in this array is currently significant for\r
50  * settings migration from old versions; if they change, review the\r
51  * gppmap() invocation for "TerminalModes".\r
52  */\r
53 const char *const ttymodes[] = {\r
54     "INTR",     "QUIT",     "ERASE",    "KILL",     "EOF",\r
55     "EOL",      "EOL2",     "START",    "STOP",     "SUSP",\r
56     "DSUSP",    "REPRINT",  "WERASE",   "LNEXT",    "FLUSH",\r
57     "SWTCH",    "STATUS",   "DISCARD",  "IGNPAR",   "PARMRK",\r
58     "INPCK",    "ISTRIP",   "INLCR",    "IGNCR",    "ICRNL",\r
59     "IUCLC",    "IXON",     "IXANY",    "IXOFF",    "IMAXBEL",\r
60     "IUTF8",    "ISIG",     "ICANON",   "XCASE",    "ECHO",\r
61     "ECHOE",    "ECHOK",    "ECHONL",   "NOFLSH",   "TOSTOP",\r
62     "IEXTEN",   "ECHOCTL",  "ECHOKE",   "PENDIN",   "OPOST",\r
63     "OLCUC",    "ONLCR",    "OCRNL",    "ONOCR",    "ONLRET",\r
64     "CS7",      "CS8",      "PARENB",   "PARODD",   NULL\r
65 };\r
67 /*\r
68  * Convenience functions to access the backends[] array\r
69  * (which is only present in tools that manage settings).\r
70  */\r
72 Backend *backend_from_name(const char *name)\r
73 {\r
74     Backend **p;\r
75     for (p = backends; *p != NULL; p++)\r
76         if (!strcmp((*p)->name, name))\r
77             return *p;\r
78     return NULL;\r
79 }\r
81 Backend *backend_from_proto(int proto)\r
82 {\r
83     Backend **p;\r
84     for (p = backends; *p != NULL; p++)\r
85         if ((*p)->protocol == proto)\r
86             return *p;\r
87     return NULL;\r
88 }\r
90 char *get_remote_username(Conf *conf)\r
91 {\r
92     char *username = conf_get_str(conf, CONF_username);\r
93     if (*username) {\r
94         return dupstr(username);\r
95     } else if (conf_get_int(conf, CONF_username_from_env)) {\r
96         /* Use local username. */\r
97         return get_username();     /* might still be NULL */\r
98     } else {\r
99         return NULL;\r
100     }\r
103 static char *gpps_raw(void *handle, const char *name, const char *def)\r
105     char *ret = read_setting_s(handle, name);\r
106     if (!ret)\r
107         ret = platform_default_s(name);\r
108     if (!ret)\r
109         ret = def ? dupstr(def) : NULL;   /* permit NULL as final fallback */\r
110     return ret;\r
113 static void gpps(void *handle, const char *name, const char *def,\r
114                  Conf *conf, int primary)\r
116     char *val = gpps_raw(handle, name, def);\r
117     conf_set_str(conf, primary, val);\r
118     sfree(val);\r
121 /*\r
122  * gppfont and gppfile cannot have local defaults, since the very\r
123  * format of a Filename or FontSpec is platform-dependent. So the\r
124  * platform-dependent functions MUST return some sort of value.\r
125  */\r
126 static void gppfont(void *handle, const char *name, Conf *conf, int primary)\r
128     FontSpec *result = read_setting_fontspec(handle, name);\r
129     if (!result)\r
130         result = platform_default_fontspec(name);\r
131     conf_set_fontspec(conf, primary, result);\r
132     fontspec_free(result);\r
134 static void gppfile(void *handle, const char *name, Conf *conf, int primary)\r
136     Filename *result = read_setting_filename(handle, name);\r
137     if (!result)\r
138         result = platform_default_filename(name);\r
139     conf_set_filename(conf, primary, result);\r
140     filename_free(result);\r
143 static int gppi_raw(void *handle, const char *name, int def)\r
145     def = platform_default_i(name, def);\r
146     return read_setting_i(handle, name, def);\r
149 static void gppi(void *handle, const char *name, int def,\r
150                  Conf *conf, int primary)\r
152     conf_set_int(conf, primary, gppi_raw(handle, name, def));\r
155 /*\r
156  * Read a set of name-value pairs in the format we occasionally use:\r
157  *   NAME\tVALUE\0NAME\tVALUE\0\0 in memory\r
158  *   NAME=VALUE,NAME=VALUE, in storage\r
159  * If there's no "=VALUE" (e.g. just NAME,NAME,NAME) then those keys\r
160  * are mapped to the empty string.\r
161  */\r
162 static int gppmap(void *handle, const char *name, Conf *conf, int primary)\r
164     char *buf, *p, *q, *key, *val;\r
166     /*\r
167      * Start by clearing any existing subkeys of this key from conf.\r
168      */\r
169     while ((key = conf_get_str_nthstrkey(conf, primary, 0)) != NULL)\r
170         conf_del_str_str(conf, primary, key);\r
172     /*\r
173      * Now read a serialised list from the settings and unmarshal it\r
174      * into its components.\r
175      */\r
176     buf = gpps_raw(handle, name, NULL);\r
177     if (!buf)\r
178         return FALSE;\r
180     p = buf;\r
181     while (*p) {\r
182         q = buf;\r
183         val = NULL;\r
184         while (*p && *p != ',') {\r
185             int c = *p++;\r
186             if (c == '=')\r
187                 c = '\0';\r
188             if (c == '\\')\r
189                 c = *p++;\r
190             *q++ = c;\r
191             if (!c)\r
192                 val = q;\r
193         }\r
194         if (*p == ',')\r
195             p++;\r
196         if (!val)\r
197             val = q;\r
198         *q = '\0';\r
200         if (primary == CONF_portfwd && strchr(buf, 'D') != NULL) {\r
201             /*\r
202              * Backwards-compatibility hack: dynamic forwardings are\r
203              * indexed in the data store as a third type letter in the\r
204              * key, 'D' alongside 'L' and 'R' - but really, they\r
205              * should be filed under 'L' with a special _value_,\r
206              * because local and dynamic forwardings both involve\r
207              * _listening_ on a local port, and are hence mutually\r
208              * exclusive on the same port number. So here we translate\r
209              * the legacy storage format into the sensible internal\r
210              * form, by finding the D and turning it into a L.\r
211              */\r
212             char *newkey = dupstr(buf);\r
213             *strchr(newkey, 'D') = 'L';\r
214             conf_set_str_str(conf, primary, newkey, "D");\r
215             sfree(newkey);\r
216         } else {\r
217             conf_set_str_str(conf, primary, buf, val);\r
218         }\r
219     }\r
220     sfree(buf);\r
222     return TRUE;\r
225 /*\r
226  * Write a set of name/value pairs in the above format, or just the\r
227  * names if include_values is FALSE.\r
228  */\r
229 static void wmap(void *handle, char const *outkey, Conf *conf, int primary,\r
230                  int include_values)\r
232     char *buf, *p, *key, *realkey;\r
233     const char *val, *q;\r
234     int len;\r
236     len = 1;                           /* allow for NUL */\r
238     for (val = conf_get_str_strs(conf, primary, NULL, &key);\r
239          val != NULL;\r
240          val = conf_get_str_strs(conf, primary, key, &key))\r
241         len += 2 + 2 * (strlen(key) + strlen(val));   /* allow for escaping */\r
243     buf = snewn(len, char);\r
244     p = buf;\r
246     for (val = conf_get_str_strs(conf, primary, NULL, &key);\r
247          val != NULL;\r
248          val = conf_get_str_strs(conf, primary, key, &key)) {\r
250         if (primary == CONF_portfwd && !strcmp(val, "D")) {\r
251             /*\r
252              * Backwards-compatibility hack, as above: translate from\r
253              * the sensible internal representation of dynamic\r
254              * forwardings (key "L<port>", value "D") to the\r
255              * conceptually incoherent legacy storage format (key\r
256              * "D<port>", value empty).\r
257              */\r
258             char *L;\r
260             realkey = key;             /* restore it at end of loop */\r
261             val = "";\r
262             key = dupstr(key);\r
263             L = strchr(key, 'L');\r
264             if (L) *L = 'D';\r
265         } else {\r
266             realkey = NULL;\r
267         }\r
269         if (p != buf)\r
270             *p++ = ',';\r
271         for (q = key; *q; q++) {\r
272             if (*q == '=' || *q == ',' || *q == '\\')\r
273                 *p++ = '\\';\r
274             *p++ = *q;\r
275         }\r
276         if (include_values) {\r
277             *p++ = '=';\r
278             for (q = val; *q; q++) {\r
279                 if (*q == '=' || *q == ',' || *q == '\\')\r
280                     *p++ = '\\';\r
281                 *p++ = *q;\r
282             }\r
283         }\r
285         if (realkey) {\r
286             free(key);\r
287             key = realkey;\r
288         }\r
289     }\r
290     *p = '\0';\r
291     write_setting_s(handle, outkey, buf);\r
292     sfree(buf);\r
295 static int key2val(const struct keyvalwhere *mapping,\r
296                    int nmaps, char *key)\r
298     int i;\r
299     for (i = 0; i < nmaps; i++)\r
300         if (!strcmp(mapping[i].s, key)) return mapping[i].v;\r
301     return -1;\r
304 static const char *val2key(const struct keyvalwhere *mapping,\r
305                            int nmaps, int val)\r
307     int i;\r
308     for (i = 0; i < nmaps; i++)\r
309         if (mapping[i].v == val) return mapping[i].s;\r
310     return NULL;\r
313 /*\r
314  * Helper function to parse a comma-separated list of strings into\r
315  * a preference list array of values. Any missing values are added\r
316  * to the end and duplicates are weeded.\r
317  * XXX: assumes vals in 'mapping' are small +ve integers\r
318  */\r
319 static void gprefs_from_str(const char *str,\r
320                             const struct keyvalwhere *mapping, int nvals,\r
321                             Conf *conf, int primary)\r
323     char *commalist = dupstr(str);\r
324     char *p, *q;\r
325     int i, j, n, v, pos;\r
326     unsigned long seen = 0;            /* bitmap for weeding dups etc */\r
328     /*\r
329      * Go through that list and convert it into values.\r
330      */\r
331     n = 0;\r
332     p = commalist;\r
333     while (1) {\r
334         while (*p && *p == ',') p++;\r
335         if (!*p)\r
336             break;                     /* no more words */\r
338         q = p;\r
339         while (*p && *p != ',') p++;\r
340         if (*p) *p++ = '\0';\r
342         v = key2val(mapping, nvals, q);\r
343         if (v != -1 && !(seen & (1 << v))) {\r
344             seen |= (1 << v);\r
345             conf_set_int_int(conf, primary, n, v);\r
346             n++;\r
347         }\r
348     }\r
350     sfree(commalist);\r
352     /*\r
353      * Now go through 'mapping' and add values that weren't mentioned\r
354      * in the list we fetched. We may have to loop over it multiple\r
355      * times so that we add values before other values whose default\r
356      * positions depend on them.\r
357      */\r
358     while (n < nvals) {\r
359         for (i = 0; i < nvals; i++) {\r
360             assert(mapping[i].v < 32);\r
362             if (!(seen & (1 << mapping[i].v))) {\r
363                 /*\r
364                  * This element needs adding. But can we add it yet?\r
365                  */\r
366                 if (mapping[i].vrel != -1 && !(seen & (1 << mapping[i].vrel)))\r
367                     continue;          /* nope */\r
369                 /*\r
370                  * OK, we can work out where to add this element, so\r
371                  * do so.\r
372                  */\r
373                 if (mapping[i].vrel == -1) {\r
374                     pos = (mapping[i].where < 0 ? n : 0);\r
375                 } else {\r
376                     for (j = 0; j < n; j++)\r
377                         if (conf_get_int_int(conf, primary, j) ==\r
378                             mapping[i].vrel)\r
379                             break;\r
380                     assert(j < n);     /* implied by (seen & (1<<vrel)) */\r
381                     pos = (mapping[i].where < 0 ? j : j+1);\r
382                 }\r
384                 /*\r
385                  * And add it.\r
386                  */\r
387                 for (j = n-1; j >= pos; j--)\r
388                     conf_set_int_int(conf, primary, j+1,\r
389                                      conf_get_int_int(conf, primary, j));\r
390                 conf_set_int_int(conf, primary, pos, mapping[i].v);\r
391                 seen |= (1 << mapping[i].v);\r
392                 n++;\r
393             }\r
394         }\r
395     }\r
398 /*\r
399  * Read a preference list.\r
400  */\r
401 static void gprefs(void *sesskey, const char *name, const char *def,\r
402                    const struct keyvalwhere *mapping, int nvals,\r
403                    Conf *conf, int primary)\r
405     /*\r
406      * Fetch the string which we'll parse as a comma-separated list.\r
407      */\r
408     char *value = gpps_raw(sesskey, name, def);\r
409     gprefs_from_str(value, mapping, nvals, conf, primary);\r
410     sfree(value);\r
413 /* \r
414  * Write out a preference list.\r
415  */\r
416 static void wprefs(void *sesskey, const char *name,\r
417                    const struct keyvalwhere *mapping, int nvals,\r
418                    Conf *conf, int primary)\r
420     char *buf, *p;\r
421     int i, maxlen;\r
423     for (maxlen = i = 0; i < nvals; i++) {\r
424         const char *s = val2key(mapping, nvals,\r
425                                 conf_get_int_int(conf, primary, i));\r
426         if (s) {\r
427             maxlen += (maxlen > 0 ? 1 : 0) + strlen(s);\r
428         }\r
429     }\r
431     buf = snewn(maxlen + 1, char);\r
432     p = buf;\r
434     for (i = 0; i < nvals; i++) {\r
435         const char *s = val2key(mapping, nvals,\r
436                                 conf_get_int_int(conf, primary, i));\r
437         if (s) {\r
438             p += sprintf(p, "%s%s", (p > buf ? "," : ""), s);\r
439         }\r
440     }\r
442     assert(p - buf == maxlen);\r
443     *p = '\0';\r
445     write_setting_s(sesskey, name, buf);\r
447     sfree(buf);\r
450 char *save_settings(const char *section, Conf *conf)\r
452     void *sesskey;\r
453     char *errmsg;\r
455     sesskey = open_settings_w(section, &errmsg);\r
456     if (!sesskey)\r
457         return errmsg;\r
458     save_open_settings(sesskey, conf);\r
459     close_settings_w(sesskey);\r
460     return NULL;\r
463 void save_open_settings(void *sesskey, Conf *conf)\r
465     int i;\r
466     const char *p;\r
468     write_setting_i(sesskey, "Present", 1);\r
469     write_setting_s(sesskey, "HostName", conf_get_str(conf, CONF_host));\r
470     write_setting_filename(sesskey, "LogFileName", conf_get_filename(conf, CONF_logfilename));\r
471     write_setting_i(sesskey, "LogType", conf_get_int(conf, CONF_logtype));\r
472     write_setting_i(sesskey, "LogFileClash", conf_get_int(conf, CONF_logxfovr));\r
473     write_setting_i(sesskey, "LogFlush", conf_get_int(conf, CONF_logflush));\r
474     write_setting_i(sesskey, "SSHLogOmitPasswords", conf_get_int(conf, CONF_logomitpass));\r
475     write_setting_i(sesskey, "SSHLogOmitData", conf_get_int(conf, CONF_logomitdata));\r
476     p = "raw";\r
477     {\r
478         const Backend *b = backend_from_proto(conf_get_int(conf, CONF_protocol));\r
479         if (b)\r
480             p = b->name;\r
481     }\r
482     write_setting_s(sesskey, "Protocol", p);\r
483     write_setting_i(sesskey, "PortNumber", conf_get_int(conf, CONF_port));\r
484     /* The CloseOnExit numbers are arranged in a different order from\r
485      * the standard FORCE_ON / FORCE_OFF / AUTO. */\r
486     write_setting_i(sesskey, "CloseOnExit", (conf_get_int(conf, CONF_close_on_exit)+2)%3);\r
487     write_setting_i(sesskey, "WarnOnClose", !!conf_get_int(conf, CONF_warn_on_close));\r
488     write_setting_i(sesskey, "PingInterval", conf_get_int(conf, CONF_ping_interval) / 60);      /* minutes */\r
489     write_setting_i(sesskey, "PingIntervalSecs", conf_get_int(conf, CONF_ping_interval) % 60);  /* seconds */\r
490     write_setting_i(sesskey, "TCPNoDelay", conf_get_int(conf, CONF_tcp_nodelay));\r
491     write_setting_i(sesskey, "TCPKeepalives", conf_get_int(conf, CONF_tcp_keepalives));\r
492     write_setting_s(sesskey, "TerminalType", conf_get_str(conf, CONF_termtype));\r
493     write_setting_s(sesskey, "TerminalSpeed", conf_get_str(conf, CONF_termspeed));\r
494     wmap(sesskey, "TerminalModes", conf, CONF_ttymodes, TRUE);\r
496     /* Address family selection */\r
497     write_setting_i(sesskey, "AddressFamily", conf_get_int(conf, CONF_addressfamily));\r
499     /* proxy settings */\r
500     write_setting_s(sesskey, "ProxyExcludeList", conf_get_str(conf, CONF_proxy_exclude_list));\r
501     write_setting_i(sesskey, "ProxyDNS", (conf_get_int(conf, CONF_proxy_dns)+2)%3);\r
502     write_setting_i(sesskey, "ProxyLocalhost", conf_get_int(conf, CONF_even_proxy_localhost));\r
503     write_setting_i(sesskey, "ProxyMethod", conf_get_int(conf, CONF_proxy_type));\r
504     write_setting_s(sesskey, "ProxyHost", conf_get_str(conf, CONF_proxy_host));\r
505     write_setting_i(sesskey, "ProxyPort", conf_get_int(conf, CONF_proxy_port));\r
506     write_setting_s(sesskey, "ProxyUsername", conf_get_str(conf, CONF_proxy_username));\r
507     write_setting_s(sesskey, "ProxyPassword", conf_get_str(conf, CONF_proxy_password));\r
508     write_setting_s(sesskey, "ProxyTelnetCommand", conf_get_str(conf, CONF_proxy_telnet_command));\r
509     write_setting_i(sesskey, "ProxyLogToTerm", conf_get_int(conf, CONF_proxy_log_to_term));\r
510     wmap(sesskey, "Environment", conf, CONF_environmt, TRUE);\r
511     write_setting_s(sesskey, "UserName", conf_get_str(conf, CONF_username));\r
512     write_setting_i(sesskey, "UserNameFromEnvironment", conf_get_int(conf, CONF_username_from_env));\r
513     write_setting_s(sesskey, "LocalUserName", conf_get_str(conf, CONF_localusername));\r
514     write_setting_i(sesskey, "NoPTY", conf_get_int(conf, CONF_nopty));\r
515     write_setting_i(sesskey, "Compression", conf_get_int(conf, CONF_compression));\r
516     write_setting_i(sesskey, "TryAgent", conf_get_int(conf, CONF_tryagent));\r
517     write_setting_i(sesskey, "AgentFwd", conf_get_int(conf, CONF_agentfwd));\r
518     write_setting_i(sesskey, "GssapiFwd", conf_get_int(conf, CONF_gssapifwd));\r
519     write_setting_i(sesskey, "ChangeUsername", conf_get_int(conf, CONF_change_username));\r
520     wprefs(sesskey, "Cipher", ciphernames, CIPHER_MAX, conf, CONF_ssh_cipherlist);\r
521     wprefs(sesskey, "KEX", kexnames, KEX_MAX, conf, CONF_ssh_kexlist);\r
522     wprefs(sesskey, "HostKey", hknames, HK_MAX, conf, CONF_ssh_hklist);\r
523     write_setting_i(sesskey, "RekeyTime", conf_get_int(conf, CONF_ssh_rekey_time));\r
524     write_setting_s(sesskey, "RekeyBytes", conf_get_str(conf, CONF_ssh_rekey_data));\r
525     write_setting_i(sesskey, "SshNoAuth", conf_get_int(conf, CONF_ssh_no_userauth));\r
526     write_setting_i(sesskey, "SshBanner", conf_get_int(conf, CONF_ssh_show_banner));\r
527     write_setting_i(sesskey, "AuthTIS", conf_get_int(conf, CONF_try_tis_auth));\r
528     write_setting_i(sesskey, "AuthKI", conf_get_int(conf, CONF_try_ki_auth));\r
529     write_setting_i(sesskey, "AuthGSSAPI", conf_get_int(conf, CONF_try_gssapi_auth));\r
530 #ifndef NO_GSSAPI\r
531     wprefs(sesskey, "GSSLibs", gsslibkeywords, ngsslibs, conf, CONF_ssh_gsslist);\r
532     write_setting_filename(sesskey, "GSSCustom", conf_get_filename(conf, CONF_ssh_gss_custom));\r
533 #endif\r
534     write_setting_i(sesskey, "SshNoShell", conf_get_int(conf, CONF_ssh_no_shell));\r
535     write_setting_i(sesskey, "SshProt", conf_get_int(conf, CONF_sshprot));\r
536     write_setting_s(sesskey, "LogHost", conf_get_str(conf, CONF_loghost));\r
537     write_setting_i(sesskey, "SSH2DES", conf_get_int(conf, CONF_ssh2_des_cbc));\r
538     write_setting_filename(sesskey, "PublicKeyFile", conf_get_filename(conf, CONF_keyfile));\r
539     write_setting_s(sesskey, "RemoteCommand", conf_get_str(conf, CONF_remote_cmd));\r
540     write_setting_i(sesskey, "RFCEnviron", conf_get_int(conf, CONF_rfc_environ));\r
541     write_setting_i(sesskey, "PassiveTelnet", conf_get_int(conf, CONF_passive_telnet));\r
542     write_setting_i(sesskey, "BackspaceIsDelete", conf_get_int(conf, CONF_bksp_is_delete));\r
543     write_setting_i(sesskey, "RXVTHomeEnd", conf_get_int(conf, CONF_rxvt_homeend));\r
544     write_setting_i(sesskey, "LinuxFunctionKeys", conf_get_int(conf, CONF_funky_type));\r
545     write_setting_i(sesskey, "NoApplicationKeys", conf_get_int(conf, CONF_no_applic_k));\r
546     write_setting_i(sesskey, "NoApplicationCursors", conf_get_int(conf, CONF_no_applic_c));\r
547     write_setting_i(sesskey, "NoMouseReporting", conf_get_int(conf, CONF_no_mouse_rep));\r
548     write_setting_i(sesskey, "NoRemoteResize", conf_get_int(conf, CONF_no_remote_resize));\r
549     write_setting_i(sesskey, "NoAltScreen", conf_get_int(conf, CONF_no_alt_screen));\r
550     write_setting_i(sesskey, "NoRemoteWinTitle", conf_get_int(conf, CONF_no_remote_wintitle));\r
551     write_setting_i(sesskey, "NoRemoteClearScroll", conf_get_int(conf, CONF_no_remote_clearscroll));\r
552     write_setting_i(sesskey, "RemoteQTitleAction", conf_get_int(conf, CONF_remote_qtitle_action));\r
553     write_setting_i(sesskey, "NoDBackspace", conf_get_int(conf, CONF_no_dbackspace));\r
554     write_setting_i(sesskey, "NoRemoteCharset", conf_get_int(conf, CONF_no_remote_charset));\r
555     write_setting_i(sesskey, "ApplicationCursorKeys", conf_get_int(conf, CONF_app_cursor));\r
556     write_setting_i(sesskey, "ApplicationKeypad", conf_get_int(conf, CONF_app_keypad));\r
557     write_setting_i(sesskey, "NetHackKeypad", conf_get_int(conf, CONF_nethack_keypad));\r
558     write_setting_i(sesskey, "AltF4", conf_get_int(conf, CONF_alt_f4));\r
559     write_setting_i(sesskey, "AltSpace", conf_get_int(conf, CONF_alt_space));\r
560     write_setting_i(sesskey, "AltOnly", conf_get_int(conf, CONF_alt_only));\r
561     write_setting_i(sesskey, "ComposeKey", conf_get_int(conf, CONF_compose_key));\r
562     write_setting_i(sesskey, "CtrlAltKeys", conf_get_int(conf, CONF_ctrlaltkeys));\r
563 #ifdef OSX_META_KEY_CONFIG\r
564     write_setting_i(sesskey, "OSXOptionMeta", conf_get_int(conf, CONF_osx_option_meta));\r
565     write_setting_i(sesskey, "OSXCommandMeta", conf_get_int(conf, CONF_osx_command_meta));\r
566 #endif\r
567     write_setting_i(sesskey, "TelnetKey", conf_get_int(conf, CONF_telnet_keyboard));\r
568     write_setting_i(sesskey, "TelnetRet", conf_get_int(conf, CONF_telnet_newline));\r
569     write_setting_i(sesskey, "LocalEcho", conf_get_int(conf, CONF_localecho));\r
570     write_setting_i(sesskey, "LocalEdit", conf_get_int(conf, CONF_localedit));\r
571     write_setting_s(sesskey, "Answerback", conf_get_str(conf, CONF_answerback));\r
572     write_setting_i(sesskey, "AlwaysOnTop", conf_get_int(conf, CONF_alwaysontop));\r
573     write_setting_i(sesskey, "FullScreenOnAltEnter", conf_get_int(conf, CONF_fullscreenonaltenter));\r
574     write_setting_i(sesskey, "HideMousePtr", conf_get_int(conf, CONF_hide_mouseptr));\r
575     write_setting_i(sesskey, "SunkenEdge", conf_get_int(conf, CONF_sunken_edge));\r
576     write_setting_i(sesskey, "WindowBorder", conf_get_int(conf, CONF_window_border));\r
577     write_setting_i(sesskey, "CurType", conf_get_int(conf, CONF_cursor_type));\r
578     write_setting_i(sesskey, "BlinkCur", conf_get_int(conf, CONF_blink_cur));\r
579     write_setting_i(sesskey, "Beep", conf_get_int(conf, CONF_beep));\r
580     write_setting_i(sesskey, "BeepInd", conf_get_int(conf, CONF_beep_ind));\r
581     write_setting_filename(sesskey, "BellWaveFile", conf_get_filename(conf, CONF_bell_wavefile));\r
582     write_setting_i(sesskey, "BellOverload", conf_get_int(conf, CONF_bellovl));\r
583     write_setting_i(sesskey, "BellOverloadN", conf_get_int(conf, CONF_bellovl_n));\r
584     write_setting_i(sesskey, "BellOverloadT", conf_get_int(conf, CONF_bellovl_t)\r
585 #ifdef PUTTY_UNIX_H\r
586                     * 1000\r
587 #endif\r
588                     );\r
589     write_setting_i(sesskey, "BellOverloadS", conf_get_int(conf, CONF_bellovl_s)\r
590 #ifdef PUTTY_UNIX_H\r
591                     * 1000\r
592 #endif\r
593                     );\r
594     write_setting_i(sesskey, "ScrollbackLines", conf_get_int(conf, CONF_savelines));\r
595     write_setting_i(sesskey, "DECOriginMode", conf_get_int(conf, CONF_dec_om));\r
596     write_setting_i(sesskey, "AutoWrapMode", conf_get_int(conf, CONF_wrap_mode));\r
597     write_setting_i(sesskey, "LFImpliesCR", conf_get_int(conf, CONF_lfhascr));\r
598     write_setting_i(sesskey, "CRImpliesLF", conf_get_int(conf, CONF_crhaslf));\r
599     write_setting_i(sesskey, "DisableArabicShaping", conf_get_int(conf, CONF_arabicshaping));\r
600     write_setting_i(sesskey, "DisableBidi", conf_get_int(conf, CONF_bidi));\r
601     write_setting_i(sesskey, "WinNameAlways", conf_get_int(conf, CONF_win_name_always));\r
602     write_setting_s(sesskey, "WinTitle", conf_get_str(conf, CONF_wintitle));\r
603     write_setting_i(sesskey, "TermWidth", conf_get_int(conf, CONF_width));\r
604     write_setting_i(sesskey, "TermHeight", conf_get_int(conf, CONF_height));\r
605     write_setting_fontspec(sesskey, "Font", conf_get_fontspec(conf, CONF_font));\r
606     write_setting_i(sesskey, "FontQuality", conf_get_int(conf, CONF_font_quality));\r
607     write_setting_i(sesskey, "FontVTMode", conf_get_int(conf, CONF_vtmode));\r
608     write_setting_i(sesskey, "UseSystemColours", conf_get_int(conf, CONF_system_colour));\r
609     write_setting_i(sesskey, "TryPalette", conf_get_int(conf, CONF_try_palette));\r
610     write_setting_i(sesskey, "ANSIColour", conf_get_int(conf, CONF_ansi_colour));\r
611     write_setting_i(sesskey, "Xterm256Colour", conf_get_int(conf, CONF_xterm_256_colour));\r
612     write_setting_i(sesskey, "BoldAsColour", conf_get_int(conf, CONF_bold_style)-1);\r
614     for (i = 0; i < 22; i++) {\r
615         char buf[20], buf2[30];\r
616         sprintf(buf, "Colour%d", i);\r
617         sprintf(buf2, "%d,%d,%d",\r
618                 conf_get_int_int(conf, CONF_colours, i*3+0),\r
619                 conf_get_int_int(conf, CONF_colours, i*3+1),\r
620                 conf_get_int_int(conf, CONF_colours, i*3+2));\r
621         write_setting_s(sesskey, buf, buf2);\r
622     }\r
623     write_setting_i(sesskey, "RawCNP", conf_get_int(conf, CONF_rawcnp));\r
624     write_setting_i(sesskey, "PasteRTF", conf_get_int(conf, CONF_rtf_paste));\r
625     write_setting_i(sesskey, "MouseIsXterm", conf_get_int(conf, CONF_mouse_is_xterm));\r
626     write_setting_i(sesskey, "RectSelect", conf_get_int(conf, CONF_rect_select));\r
627     write_setting_i(sesskey, "MouseOverride", conf_get_int(conf, CONF_mouse_override));\r
628     for (i = 0; i < 256; i += 32) {\r
629         char buf[20], buf2[256];\r
630         int j;\r
631         sprintf(buf, "Wordness%d", i);\r
632         *buf2 = '\0';\r
633         for (j = i; j < i + 32; j++) {\r
634             sprintf(buf2 + strlen(buf2), "%s%d",\r
635                     (*buf2 ? "," : ""),\r
636                     conf_get_int_int(conf, CONF_wordness, j));\r
637         }\r
638         write_setting_s(sesskey, buf, buf2);\r
639     }\r
640     write_setting_s(sesskey, "LineCodePage", conf_get_str(conf, CONF_line_codepage));\r
641     write_setting_i(sesskey, "CJKAmbigWide", conf_get_int(conf, CONF_cjk_ambig_wide));\r
642     write_setting_i(sesskey, "UTF8Override", conf_get_int(conf, CONF_utf8_override));\r
643     write_setting_s(sesskey, "Printer", conf_get_str(conf, CONF_printer));\r
644     write_setting_i(sesskey, "CapsLockCyr", conf_get_int(conf, CONF_xlat_capslockcyr));\r
645     write_setting_i(sesskey, "ScrollBar", conf_get_int(conf, CONF_scrollbar));\r
646     write_setting_i(sesskey, "ScrollBarFullScreen", conf_get_int(conf, CONF_scrollbar_in_fullscreen));\r
647     write_setting_i(sesskey, "ScrollOnKey", conf_get_int(conf, CONF_scroll_on_key));\r
648     write_setting_i(sesskey, "ScrollOnDisp", conf_get_int(conf, CONF_scroll_on_disp));\r
649     write_setting_i(sesskey, "EraseToScrollback", conf_get_int(conf, CONF_erase_to_scrollback));\r
650     write_setting_i(sesskey, "LockSize", conf_get_int(conf, CONF_resize_action));\r
651     write_setting_i(sesskey, "BCE", conf_get_int(conf, CONF_bce));\r
652     write_setting_i(sesskey, "BlinkText", conf_get_int(conf, CONF_blinktext));\r
653     write_setting_i(sesskey, "X11Forward", conf_get_int(conf, CONF_x11_forward));\r
654     write_setting_s(sesskey, "X11Display", conf_get_str(conf, CONF_x11_display));\r
655     write_setting_i(sesskey, "X11AuthType", conf_get_int(conf, CONF_x11_auth));\r
656     write_setting_filename(sesskey, "X11AuthFile", conf_get_filename(conf, CONF_xauthfile));\r
657     write_setting_i(sesskey, "LocalPortAcceptAll", conf_get_int(conf, CONF_lport_acceptall));\r
658     write_setting_i(sesskey, "RemotePortAcceptAll", conf_get_int(conf, CONF_rport_acceptall));\r
659     wmap(sesskey, "PortForwardings", conf, CONF_portfwd, TRUE);\r
660     write_setting_i(sesskey, "BugIgnore1", 2-conf_get_int(conf, CONF_sshbug_ignore1));\r
661     write_setting_i(sesskey, "BugPlainPW1", 2-conf_get_int(conf, CONF_sshbug_plainpw1));\r
662     write_setting_i(sesskey, "BugRSA1", 2-conf_get_int(conf, CONF_sshbug_rsa1));\r
663     write_setting_i(sesskey, "BugIgnore2", 2-conf_get_int(conf, CONF_sshbug_ignore2));\r
664     write_setting_i(sesskey, "BugHMAC2", 2-conf_get_int(conf, CONF_sshbug_hmac2));\r
665     write_setting_i(sesskey, "BugDeriveKey2", 2-conf_get_int(conf, CONF_sshbug_derivekey2));\r
666     write_setting_i(sesskey, "BugRSAPad2", 2-conf_get_int(conf, CONF_sshbug_rsapad2));\r
667     write_setting_i(sesskey, "BugPKSessID2", 2-conf_get_int(conf, CONF_sshbug_pksessid2));\r
668     write_setting_i(sesskey, "BugRekey2", 2-conf_get_int(conf, CONF_sshbug_rekey2));\r
669     write_setting_i(sesskey, "BugMaxPkt2", 2-conf_get_int(conf, CONF_sshbug_maxpkt2));\r
670     write_setting_i(sesskey, "BugOldGex2", 2-conf_get_int(conf, CONF_sshbug_oldgex2));\r
671     write_setting_i(sesskey, "BugWinadj", 2-conf_get_int(conf, CONF_sshbug_winadj));\r
672     write_setting_i(sesskey, "BugChanReq", 2-conf_get_int(conf, CONF_sshbug_chanreq));\r
673     write_setting_i(sesskey, "StampUtmp", conf_get_int(conf, CONF_stamp_utmp));\r
674     write_setting_i(sesskey, "LoginShell", conf_get_int(conf, CONF_login_shell));\r
675     write_setting_i(sesskey, "ScrollbarOnLeft", conf_get_int(conf, CONF_scrollbar_on_left));\r
676     write_setting_fontspec(sesskey, "BoldFont", conf_get_fontspec(conf, CONF_boldfont));\r
677     write_setting_fontspec(sesskey, "WideFont", conf_get_fontspec(conf, CONF_widefont));\r
678     write_setting_fontspec(sesskey, "WideBoldFont", conf_get_fontspec(conf, CONF_wideboldfont));\r
679     write_setting_i(sesskey, "ShadowBold", conf_get_int(conf, CONF_shadowbold));\r
680     write_setting_i(sesskey, "ShadowBoldOffset", conf_get_int(conf, CONF_shadowboldoffset));\r
681     write_setting_s(sesskey, "SerialLine", conf_get_str(conf, CONF_serline));\r
682     write_setting_i(sesskey, "SerialSpeed", conf_get_int(conf, CONF_serspeed));\r
683     write_setting_i(sesskey, "SerialDataBits", conf_get_int(conf, CONF_serdatabits));\r
684     write_setting_i(sesskey, "SerialStopHalfbits", conf_get_int(conf, CONF_serstopbits));\r
685     write_setting_i(sesskey, "SerialParity", conf_get_int(conf, CONF_serparity));\r
686     write_setting_i(sesskey, "SerialFlowControl", conf_get_int(conf, CONF_serflow));\r
687     write_setting_s(sesskey, "WindowClass", conf_get_str(conf, CONF_winclass));\r
688     write_setting_i(sesskey, "ConnectionSharing", conf_get_int(conf, CONF_ssh_connection_sharing));\r
689     write_setting_i(sesskey, "ConnectionSharingUpstream", conf_get_int(conf, CONF_ssh_connection_sharing_upstream));\r
690     write_setting_i(sesskey, "ConnectionSharingDownstream", conf_get_int(conf, CONF_ssh_connection_sharing_downstream));\r
691     wmap(sesskey, "SSHManualHostKeys", conf, CONF_ssh_manual_hostkeys, FALSE);\r
694 void load_settings(const char *section, Conf *conf)\r
696     void *sesskey;\r
698     sesskey = open_settings_r(section);\r
699     load_open_settings(sesskey, conf);\r
700     close_settings_r(sesskey);\r
702     if (conf_launchable(conf))\r
703         add_session_to_jumplist(section);\r
706 void load_open_settings(void *sesskey, Conf *conf)\r
708     int i;\r
709     char *prot;\r
711     conf_set_int(conf, CONF_ssh_subsys, 0);   /* FIXME: load this properly */\r
712     conf_set_str(conf, CONF_remote_cmd, "");\r
713     conf_set_str(conf, CONF_remote_cmd2, "");\r
714     conf_set_str(conf, CONF_ssh_nc_host, "");\r
716     gpps(sesskey, "HostName", "", conf, CONF_host);\r
717     gppfile(sesskey, "LogFileName", conf, CONF_logfilename);\r
718     gppi(sesskey, "LogType", 0, conf, CONF_logtype);\r
719     gppi(sesskey, "LogFileClash", LGXF_ASK, conf, CONF_logxfovr);\r
720     gppi(sesskey, "LogFlush", 1, conf, CONF_logflush);\r
721     gppi(sesskey, "SSHLogOmitPasswords", 1, conf, CONF_logomitpass);\r
722     gppi(sesskey, "SSHLogOmitData", 0, conf, CONF_logomitdata);\r
724     prot = gpps_raw(sesskey, "Protocol", "default");\r
725     conf_set_int(conf, CONF_protocol, default_protocol);\r
726     conf_set_int(conf, CONF_port, default_port);\r
727     {\r
728         const Backend *b = backend_from_name(prot);\r
729         if (b) {\r
730             conf_set_int(conf, CONF_protocol, b->protocol);\r
731             gppi(sesskey, "PortNumber", default_port, conf, CONF_port);\r
732         }\r
733     }\r
734     sfree(prot);\r
736     /* Address family selection */\r
737     gppi(sesskey, "AddressFamily", ADDRTYPE_UNSPEC, conf, CONF_addressfamily);\r
739     /* The CloseOnExit numbers are arranged in a different order from\r
740      * the standard FORCE_ON / FORCE_OFF / AUTO. */\r
741     i = gppi_raw(sesskey, "CloseOnExit", 1); conf_set_int(conf, CONF_close_on_exit, (i+1)%3);\r
742     gppi(sesskey, "WarnOnClose", 1, conf, CONF_warn_on_close);\r
743     {\r
744         /* This is two values for backward compatibility with 0.50/0.51 */\r
745         int pingmin, pingsec;\r
746         pingmin = gppi_raw(sesskey, "PingInterval", 0);\r
747         pingsec = gppi_raw(sesskey, "PingIntervalSecs", 0);\r
748         conf_set_int(conf, CONF_ping_interval, pingmin * 60 + pingsec);\r
749     }\r
750     gppi(sesskey, "TCPNoDelay", 1, conf, CONF_tcp_nodelay);\r
751     gppi(sesskey, "TCPKeepalives", 0, conf, CONF_tcp_keepalives);\r
752     gpps(sesskey, "TerminalType", "xterm", conf, CONF_termtype);\r
753     gpps(sesskey, "TerminalSpeed", "38400,38400", conf, CONF_termspeed);\r
754     if (gppmap(sesskey, "TerminalModes", conf, CONF_ttymodes)) {\r
755         /*\r
756          * Backwards compatibility with old saved settings.\r
757          *\r
758          * From the invention of this setting through 0.67, the set of\r
759          * terminal modes was fixed, and absence of a mode from this\r
760          * setting meant the user had explicitly removed it from the\r
761          * UI and we shouldn't send it.\r
762          *\r
763          * In 0.68, the IUTF8 mode was added, and in handling old\r
764          * settings we inadvertently removed the ability to not send\r
765          * a mode. Any mode not mentioned was treated as if it was\r
766          * set to 'auto' (A).\r
767          *\r
768          * After 0.68, we added explicit notation to the setting format\r
769          * when the user removes a known terminal mode from the list.\r
770          *\r
771          * So: if any of the modes from the original set is missing, we\r
772          * assume this was an intentional removal by the user and add\r
773          * an explicit removal ('N'); but if IUTF8 (or any other mode\r
774          * added after 0.67) is missing, we assume that its absence is\r
775          * due to the setting being old rather than intentional, and\r
776          * add it with its default setting.\r
777          *\r
778          * (This does mean that if a 0.68 user explicitly removed IUTF8,\r
779          * we add it back; but removing IUTF8 had no effect in 0.68, so\r
780          * we're preserving behaviour, which is the best we can do.)\r
781          */\r
782         for (i = 0; ttymodes[i]; i++) {\r
783             if (!conf_get_str_str_opt(conf, CONF_ttymodes, ttymodes[i])) {\r
784                 /* Mode not mentioned in setting. */\r
785                 const char *def;\r
786                 if (!strcmp(ttymodes[i], "IUTF8")) {\r
787                     /* Any new modes we add in future should be treated\r
788                      * this way too. */\r
789                     def = "A";  /* same as new-setting default below */\r
790                 } else {\r
791                     /* One of the original modes. Absence is probably\r
792                      * deliberate. */\r
793                     def = "N";  /* don't send */\r
794                 }\r
795                 conf_set_str_str(conf, CONF_ttymodes, ttymodes[i], def);\r
796             }\r
797         }\r
798     } else {\r
799         /* This hardcodes a big set of defaults in any new saved\r
800          * sessions. Let's hope we don't change our mind. */\r
801         for (i = 0; ttymodes[i]; i++)\r
802             conf_set_str_str(conf, CONF_ttymodes, ttymodes[i], "A");\r
803     }\r
805     /* proxy settings */\r
806     gpps(sesskey, "ProxyExcludeList", "", conf, CONF_proxy_exclude_list);\r
807     i = gppi_raw(sesskey, "ProxyDNS", 1); conf_set_int(conf, CONF_proxy_dns, (i+1)%3);\r
808     gppi(sesskey, "ProxyLocalhost", 0, conf, CONF_even_proxy_localhost);\r
809     gppi(sesskey, "ProxyMethod", -1, conf, CONF_proxy_type);\r
810     if (conf_get_int(conf, CONF_proxy_type) == -1) {\r
811         int i;\r
812         i = gppi_raw(sesskey, "ProxyType", 0);\r
813         if (i == 0)\r
814             conf_set_int(conf, CONF_proxy_type, PROXY_NONE);\r
815         else if (i == 1)\r
816             conf_set_int(conf, CONF_proxy_type, PROXY_HTTP);\r
817         else if (i == 3)\r
818             conf_set_int(conf, CONF_proxy_type, PROXY_TELNET);\r
819         else if (i == 4)\r
820             conf_set_int(conf, CONF_proxy_type, PROXY_CMD);\r
821         else {\r
822             i = gppi_raw(sesskey, "ProxySOCKSVersion", 5);\r
823             if (i == 5)\r
824                 conf_set_int(conf, CONF_proxy_type, PROXY_SOCKS5);\r
825             else\r
826                 conf_set_int(conf, CONF_proxy_type, PROXY_SOCKS4);\r
827         }\r
828     }\r
829     gpps(sesskey, "ProxyHost", "proxy", conf, CONF_proxy_host);\r
830     gppi(sesskey, "ProxyPort", 80, conf, CONF_proxy_port);\r
831     gpps(sesskey, "ProxyUsername", "", conf, CONF_proxy_username);\r
832     gpps(sesskey, "ProxyPassword", "", conf, CONF_proxy_password);\r
833     gpps(sesskey, "ProxyTelnetCommand", "connect %host %port\\n",\r
834          conf, CONF_proxy_telnet_command);\r
835     gppi(sesskey, "ProxyLogToTerm", FORCE_OFF, conf, CONF_proxy_log_to_term);\r
836     gppmap(sesskey, "Environment", conf, CONF_environmt);\r
837     gpps(sesskey, "UserName", "", conf, CONF_username);\r
838     gppi(sesskey, "UserNameFromEnvironment", 0, conf, CONF_username_from_env);\r
839     gpps(sesskey, "LocalUserName", "", conf, CONF_localusername);\r
840     gppi(sesskey, "NoPTY", 0, conf, CONF_nopty);\r
841     gppi(sesskey, "Compression", 0, conf, CONF_compression);\r
842     gppi(sesskey, "TryAgent", 1, conf, CONF_tryagent);\r
843     gppi(sesskey, "AgentFwd", 0, conf, CONF_agentfwd);\r
844     gppi(sesskey, "ChangeUsername", 0, conf, CONF_change_username);\r
845     gppi(sesskey, "GssapiFwd", 0, conf, CONF_gssapifwd);\r
846     gprefs(sesskey, "Cipher", "\0",\r
847            ciphernames, CIPHER_MAX, conf, CONF_ssh_cipherlist);\r
848     {\r
849         /* Backward-compatibility: before 0.58 (when the "KEX"\r
850          * preference was first added), we had an option to\r
851          * disable gex under the "bugs" panel after one report of\r
852          * a server which offered it then choked, but we never got\r
853          * a server version string or any other reports. */\r
854         const char *default_kexes,\r
855                    *normal_default = "ecdh,dh-gex-sha1,dh-group14-sha1,rsa,"\r
856                        "WARN,dh-group1-sha1",\r
857                    *bugdhgex2_default = "ecdh,dh-group14-sha1,rsa,"\r
858                        "WARN,dh-group1-sha1,dh-gex-sha1";\r
859         char *raw;\r
860         i = 2 - gppi_raw(sesskey, "BugDHGEx2", 0);\r
861         if (i == FORCE_ON)\r
862             default_kexes = bugdhgex2_default;\r
863         else\r
864             default_kexes = normal_default;\r
865         /* Migration: after 0.67 we decided we didn't like\r
866          * dh-group1-sha1. If it looks like the user never changed\r
867          * the defaults, quietly upgrade their settings to demote it.\r
868          * (If they did, they're on their own.) */\r
869         raw = gpps_raw(sesskey, "KEX", default_kexes);\r
870         assert(raw != NULL);\r
871         /* Lack of 'ecdh' tells us this was saved by 0.58-0.67\r
872          * inclusive. If it was saved by a later version, we need\r
873          * to leave it alone. */\r
874         if (strcmp(raw, "dh-group14-sha1,dh-group1-sha1,rsa,"\r
875                    "WARN,dh-gex-sha1") == 0) {\r
876             /* Previously migrated from BugDHGEx2. */\r
877             sfree(raw);\r
878             raw = dupstr(bugdhgex2_default);\r
879         } else if (strcmp(raw, "dh-gex-sha1,dh-group14-sha1,"\r
880                           "dh-group1-sha1,rsa,WARN") == 0) {\r
881             /* Untouched old default setting. */\r
882             sfree(raw);\r
883             raw = dupstr(normal_default);\r
884         }\r
885         gprefs_from_str(raw, kexnames, KEX_MAX, conf, CONF_ssh_kexlist);\r
886         sfree(raw);\r
887     }\r
888     gprefs(sesskey, "HostKey", "ed25519,ecdsa,rsa,dsa,WARN",\r
889            hknames, HK_MAX, conf, CONF_ssh_hklist);\r
890     gppi(sesskey, "RekeyTime", 60, conf, CONF_ssh_rekey_time);\r
891     gpps(sesskey, "RekeyBytes", "1G", conf, CONF_ssh_rekey_data);\r
892     {\r
893         /* SSH-2 only by default */\r
894         int sshprot = gppi_raw(sesskey, "SshProt", 3);\r
895         /* Old sessions may contain the values corresponding to the fallbacks\r
896          * we used to allow; migrate them */\r
897         if (sshprot == 1)      sshprot = 0; /* => "SSH-1 only" */\r
898         else if (sshprot == 2) sshprot = 3; /* => "SSH-2 only" */\r
899         conf_set_int(conf, CONF_sshprot, sshprot);\r
900     }\r
901     gpps(sesskey, "LogHost", "", conf, CONF_loghost);\r
902     gppi(sesskey, "SSH2DES", 0, conf, CONF_ssh2_des_cbc);\r
903     gppi(sesskey, "SshNoAuth", 0, conf, CONF_ssh_no_userauth);\r
904     gppi(sesskey, "SshBanner", 1, conf, CONF_ssh_show_banner);\r
905     gppi(sesskey, "AuthTIS", 0, conf, CONF_try_tis_auth);\r
906     gppi(sesskey, "AuthKI", 1, conf, CONF_try_ki_auth);\r
907     gppi(sesskey, "AuthGSSAPI", 1, conf, CONF_try_gssapi_auth);\r
908 #ifndef NO_GSSAPI\r
909     gprefs(sesskey, "GSSLibs", "\0",\r
910            gsslibkeywords, ngsslibs, conf, CONF_ssh_gsslist);\r
911     gppfile(sesskey, "GSSCustom", conf, CONF_ssh_gss_custom);\r
912 #endif\r
913     gppi(sesskey, "SshNoShell", 0, conf, CONF_ssh_no_shell);\r
914     gppfile(sesskey, "PublicKeyFile", conf, CONF_keyfile);\r
915     gpps(sesskey, "RemoteCommand", "", conf, CONF_remote_cmd);\r
916     gppi(sesskey, "RFCEnviron", 0, conf, CONF_rfc_environ);\r
917     gppi(sesskey, "PassiveTelnet", 0, conf, CONF_passive_telnet);\r
918     gppi(sesskey, "BackspaceIsDelete", 1, conf, CONF_bksp_is_delete);\r
919     gppi(sesskey, "RXVTHomeEnd", 0, conf, CONF_rxvt_homeend);\r
920     gppi(sesskey, "LinuxFunctionKeys", 0, conf, CONF_funky_type);\r
921     gppi(sesskey, "NoApplicationKeys", 0, conf, CONF_no_applic_k);\r
922     gppi(sesskey, "NoApplicationCursors", 0, conf, CONF_no_applic_c);\r
923     gppi(sesskey, "NoMouseReporting", 0, conf, CONF_no_mouse_rep);\r
924     gppi(sesskey, "NoRemoteResize", 0, conf, CONF_no_remote_resize);\r
925     gppi(sesskey, "NoAltScreen", 0, conf, CONF_no_alt_screen);\r
926     gppi(sesskey, "NoRemoteWinTitle", 0, conf, CONF_no_remote_wintitle);\r
927     gppi(sesskey, "NoRemoteClearScroll", 0, conf, CONF_no_remote_clearscroll);\r
928     {\r
929         /* Backward compatibility */\r
930         int no_remote_qtitle = gppi_raw(sesskey, "NoRemoteQTitle", 1);\r
931         /* We deliberately interpret the old setting of "no response" as\r
932          * "empty string". This changes the behaviour, but hopefully for\r
933          * the better; the user can always recover the old behaviour. */\r
934         gppi(sesskey, "RemoteQTitleAction",\r
935              no_remote_qtitle ? TITLE_EMPTY : TITLE_REAL,\r
936              conf, CONF_remote_qtitle_action);\r
937     }\r
938     gppi(sesskey, "NoDBackspace", 0, conf, CONF_no_dbackspace);\r
939     gppi(sesskey, "NoRemoteCharset", 0, conf, CONF_no_remote_charset);\r
940     gppi(sesskey, "ApplicationCursorKeys", 0, conf, CONF_app_cursor);\r
941     gppi(sesskey, "ApplicationKeypad", 0, conf, CONF_app_keypad);\r
942     gppi(sesskey, "NetHackKeypad", 0, conf, CONF_nethack_keypad);\r
943     gppi(sesskey, "AltF4", 1, conf, CONF_alt_f4);\r
944     gppi(sesskey, "AltSpace", 0, conf, CONF_alt_space);\r
945     gppi(sesskey, "AltOnly", 0, conf, CONF_alt_only);\r
946     gppi(sesskey, "ComposeKey", 0, conf, CONF_compose_key);\r
947     gppi(sesskey, "CtrlAltKeys", 1, conf, CONF_ctrlaltkeys);\r
948 #ifdef OSX_META_KEY_CONFIG\r
949     gppi(sesskey, "OSXOptionMeta", 1, conf, CONF_osx_option_meta);\r
950     gppi(sesskey, "OSXCommandMeta", 0, conf, CONF_osx_command_meta);\r
951 #endif\r
952     gppi(sesskey, "TelnetKey", 0, conf, CONF_telnet_keyboard);\r
953     gppi(sesskey, "TelnetRet", 1, conf, CONF_telnet_newline);\r
954     gppi(sesskey, "LocalEcho", AUTO, conf, CONF_localecho);\r
955     gppi(sesskey, "LocalEdit", AUTO, conf, CONF_localedit);\r
956     gpps(sesskey, "Answerback", "PuTTY", conf, CONF_answerback);\r
957     gppi(sesskey, "AlwaysOnTop", 0, conf, CONF_alwaysontop);\r
958     gppi(sesskey, "FullScreenOnAltEnter", 0, conf, CONF_fullscreenonaltenter);\r
959     gppi(sesskey, "HideMousePtr", 0, conf, CONF_hide_mouseptr);\r
960     gppi(sesskey, "SunkenEdge", 0, conf, CONF_sunken_edge);\r
961     gppi(sesskey, "WindowBorder", 1, conf, CONF_window_border);\r
962     gppi(sesskey, "CurType", 0, conf, CONF_cursor_type);\r
963     gppi(sesskey, "BlinkCur", 0, conf, CONF_blink_cur);\r
964     /* pedantic compiler tells me I can't use conf, CONF_beep as an int * :-) */\r
965     gppi(sesskey, "Beep", 1, conf, CONF_beep);\r
966     gppi(sesskey, "BeepInd", 0, conf, CONF_beep_ind);\r
967     gppfile(sesskey, "BellWaveFile", conf, CONF_bell_wavefile);\r
968     gppi(sesskey, "BellOverload", 1, conf, CONF_bellovl);\r
969     gppi(sesskey, "BellOverloadN", 5, conf, CONF_bellovl_n);\r
970     i = gppi_raw(sesskey, "BellOverloadT", 2*TICKSPERSEC\r
971 #ifdef PUTTY_UNIX_H\r
972                                    *1000\r
973 #endif\r
974                                    );\r
975     conf_set_int(conf, CONF_bellovl_t, i\r
976 #ifdef PUTTY_UNIX_H\r
977                  / 1000\r
978 #endif\r
979                  );\r
980     i = gppi_raw(sesskey, "BellOverloadS", 5*TICKSPERSEC\r
981 #ifdef PUTTY_UNIX_H\r
982                                    *1000\r
983 #endif\r
984                                    );\r
985     conf_set_int(conf, CONF_bellovl_s, i\r
986 #ifdef PUTTY_UNIX_H\r
987                  / 1000\r
988 #endif\r
989                  );\r
990     gppi(sesskey, "ScrollbackLines", 2000, conf, CONF_savelines);\r
991     gppi(sesskey, "DECOriginMode", 0, conf, CONF_dec_om);\r
992     gppi(sesskey, "AutoWrapMode", 1, conf, CONF_wrap_mode);\r
993     gppi(sesskey, "LFImpliesCR", 0, conf, CONF_lfhascr);\r
994     gppi(sesskey, "CRImpliesLF", 0, conf, CONF_crhaslf);\r
995     gppi(sesskey, "DisableArabicShaping", 0, conf, CONF_arabicshaping);\r
996     gppi(sesskey, "DisableBidi", 0, conf, CONF_bidi);\r
997     gppi(sesskey, "WinNameAlways", 1, conf, CONF_win_name_always);\r
998     gpps(sesskey, "WinTitle", "", conf, CONF_wintitle);\r
999     gppi(sesskey, "TermWidth", 80, conf, CONF_width);\r
1000     gppi(sesskey, "TermHeight", 24, conf, CONF_height);\r
1001     gppfont(sesskey, "Font", conf, CONF_font);\r
1002     gppi(sesskey, "FontQuality", FQ_DEFAULT, conf, CONF_font_quality);\r
1003     gppi(sesskey, "FontVTMode", VT_UNICODE, conf, CONF_vtmode);\r
1004     gppi(sesskey, "UseSystemColours", 0, conf, CONF_system_colour);\r
1005     gppi(sesskey, "TryPalette", 0, conf, CONF_try_palette);\r
1006     gppi(sesskey, "ANSIColour", 1, conf, CONF_ansi_colour);\r
1007     gppi(sesskey, "Xterm256Colour", 1, conf, CONF_xterm_256_colour);\r
1008     i = gppi_raw(sesskey, "BoldAsColour", 1); conf_set_int(conf, CONF_bold_style, i+1);\r
1010     for (i = 0; i < 22; i++) {\r
1011         static const char *const defaults[] = {\r
1012             "187,187,187", "255,255,255", "0,0,0", "85,85,85", "0,0,0",\r
1013             "0,255,0", "0,0,0", "85,85,85", "187,0,0", "255,85,85",\r
1014             "0,187,0", "85,255,85", "187,187,0", "255,255,85", "0,0,187",\r
1015             "85,85,255", "187,0,187", "255,85,255", "0,187,187",\r
1016             "85,255,255", "187,187,187", "255,255,255"\r
1017         };\r
1018         char buf[20], *buf2;\r
1019         int c0, c1, c2;\r
1020         sprintf(buf, "Colour%d", i);\r
1021         buf2 = gpps_raw(sesskey, buf, defaults[i]);\r
1022         if (sscanf(buf2, "%d,%d,%d", &c0, &c1, &c2) == 3) {\r
1023             conf_set_int_int(conf, CONF_colours, i*3+0, c0);\r
1024             conf_set_int_int(conf, CONF_colours, i*3+1, c1);\r
1025             conf_set_int_int(conf, CONF_colours, i*3+2, c2);\r
1026         }\r
1027         sfree(buf2);\r
1028     }\r
1029     gppi(sesskey, "RawCNP", 0, conf, CONF_rawcnp);\r
1030     gppi(sesskey, "PasteRTF", 0, conf, CONF_rtf_paste);\r
1031     gppi(sesskey, "MouseIsXterm", 0, conf, CONF_mouse_is_xterm);\r
1032     gppi(sesskey, "RectSelect", 0, conf, CONF_rect_select);\r
1033     gppi(sesskey, "MouseOverride", 1, conf, CONF_mouse_override);\r
1034     for (i = 0; i < 256; i += 32) {\r
1035         static const char *const defaults[] = {\r
1036             "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0",\r
1037             "0,1,2,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1",\r
1038             "1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,2",\r
1039             "1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1",\r
1040             "1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1",\r
1041             "1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1",\r
1042             "2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2",\r
1043             "2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2"\r
1044         };\r
1045         char buf[20], *buf2, *p;\r
1046         int j;\r
1047         sprintf(buf, "Wordness%d", i);\r
1048         buf2 = gpps_raw(sesskey, buf, defaults[i / 32]);\r
1049         p = buf2;\r
1050         for (j = i; j < i + 32; j++) {\r
1051             char *q = p;\r
1052             while (*p && *p != ',')\r
1053                 p++;\r
1054             if (*p == ',')\r
1055                 *p++ = '\0';\r
1056             conf_set_int_int(conf, CONF_wordness, j, atoi(q));\r
1057         }\r
1058         sfree(buf2);\r
1059     }\r
1060     /*\r
1061      * The empty default for LineCodePage will be converted later\r
1062      * into a plausible default for the locale.\r
1063      */\r
1064     gpps(sesskey, "LineCodePage", "", conf, CONF_line_codepage);\r
1065     gppi(sesskey, "CJKAmbigWide", 0, conf, CONF_cjk_ambig_wide);\r
1066     gppi(sesskey, "UTF8Override", 1, conf, CONF_utf8_override);\r
1067     gpps(sesskey, "Printer", "", conf, CONF_printer);\r
1068     gppi(sesskey, "CapsLockCyr", 0, conf, CONF_xlat_capslockcyr);\r
1069     gppi(sesskey, "ScrollBar", 1, conf, CONF_scrollbar);\r
1070     gppi(sesskey, "ScrollBarFullScreen", 0, conf, CONF_scrollbar_in_fullscreen);\r
1071     gppi(sesskey, "ScrollOnKey", 0, conf, CONF_scroll_on_key);\r
1072     gppi(sesskey, "ScrollOnDisp", 1, conf, CONF_scroll_on_disp);\r
1073     gppi(sesskey, "EraseToScrollback", 1, conf, CONF_erase_to_scrollback);\r
1074     gppi(sesskey, "LockSize", 0, conf, CONF_resize_action);\r
1075     gppi(sesskey, "BCE", 1, conf, CONF_bce);\r
1076     gppi(sesskey, "BlinkText", 0, conf, CONF_blinktext);\r
1077     gppi(sesskey, "X11Forward", 0, conf, CONF_x11_forward);\r
1078     gpps(sesskey, "X11Display", "", conf, CONF_x11_display);\r
1079     gppi(sesskey, "X11AuthType", X11_MIT, conf, CONF_x11_auth);\r
1080     gppfile(sesskey, "X11AuthFile", conf, CONF_xauthfile);\r
1082     gppi(sesskey, "LocalPortAcceptAll", 0, conf, CONF_lport_acceptall);\r
1083     gppi(sesskey, "RemotePortAcceptAll", 0, conf, CONF_rport_acceptall);\r
1084     gppmap(sesskey, "PortForwardings", conf, CONF_portfwd);\r
1085     i = gppi_raw(sesskey, "BugIgnore1", 0); conf_set_int(conf, CONF_sshbug_ignore1, 2-i);\r
1086     i = gppi_raw(sesskey, "BugPlainPW1", 0); conf_set_int(conf, CONF_sshbug_plainpw1, 2-i);\r
1087     i = gppi_raw(sesskey, "BugRSA1", 0); conf_set_int(conf, CONF_sshbug_rsa1, 2-i);\r
1088     i = gppi_raw(sesskey, "BugIgnore2", 0); conf_set_int(conf, CONF_sshbug_ignore2, 2-i);\r
1089     {\r
1090         int i;\r
1091         i = gppi_raw(sesskey, "BugHMAC2", 0); conf_set_int(conf, CONF_sshbug_hmac2, 2-i);\r
1092         if (2-i == AUTO) {\r
1093             i = gppi_raw(sesskey, "BuggyMAC", 0);\r
1094             if (i == 1)\r
1095                 conf_set_int(conf, CONF_sshbug_hmac2, FORCE_ON);\r
1096         }\r
1097     }\r
1098     i = gppi_raw(sesskey, "BugDeriveKey2", 0); conf_set_int(conf, CONF_sshbug_derivekey2, 2-i);\r
1099     i = gppi_raw(sesskey, "BugRSAPad2", 0); conf_set_int(conf, CONF_sshbug_rsapad2, 2-i);\r
1100     i = gppi_raw(sesskey, "BugPKSessID2", 0); conf_set_int(conf, CONF_sshbug_pksessid2, 2-i);\r
1101     i = gppi_raw(sesskey, "BugRekey2", 0); conf_set_int(conf, CONF_sshbug_rekey2, 2-i);\r
1102     i = gppi_raw(sesskey, "BugMaxPkt2", 0); conf_set_int(conf, CONF_sshbug_maxpkt2, 2-i);\r
1103     i = gppi_raw(sesskey, "BugOldGex2", 0); conf_set_int(conf, CONF_sshbug_oldgex2, 2-i);\r
1104     i = gppi_raw(sesskey, "BugWinadj", 0); conf_set_int(conf, CONF_sshbug_winadj, 2-i);\r
1105     i = gppi_raw(sesskey, "BugChanReq", 0); conf_set_int(conf, CONF_sshbug_chanreq, 2-i);\r
1106     conf_set_int(conf, CONF_ssh_simple, FALSE);\r
1107     gppi(sesskey, "StampUtmp", 1, conf, CONF_stamp_utmp);\r
1108     gppi(sesskey, "LoginShell", 1, conf, CONF_login_shell);\r
1109     gppi(sesskey, "ScrollbarOnLeft", 0, conf, CONF_scrollbar_on_left);\r
1110     gppi(sesskey, "ShadowBold", 0, conf, CONF_shadowbold);\r
1111     gppfont(sesskey, "BoldFont", conf, CONF_boldfont);\r
1112     gppfont(sesskey, "WideFont", conf, CONF_widefont);\r
1113     gppfont(sesskey, "WideBoldFont", conf, CONF_wideboldfont);\r
1114     gppi(sesskey, "ShadowBoldOffset", 1, conf, CONF_shadowboldoffset);\r
1115     gpps(sesskey, "SerialLine", "", conf, CONF_serline);\r
1116     gppi(sesskey, "SerialSpeed", 9600, conf, CONF_serspeed);\r
1117     gppi(sesskey, "SerialDataBits", 8, conf, CONF_serdatabits);\r
1118     gppi(sesskey, "SerialStopHalfbits", 2, conf, CONF_serstopbits);\r
1119     gppi(sesskey, "SerialParity", SER_PAR_NONE, conf, CONF_serparity);\r
1120     gppi(sesskey, "SerialFlowControl", SER_FLOW_XONXOFF, conf, CONF_serflow);\r
1121     gpps(sesskey, "WindowClass", "", conf, CONF_winclass);\r
1122     gppi(sesskey, "ConnectionSharing", 0, conf, CONF_ssh_connection_sharing);\r
1123     gppi(sesskey, "ConnectionSharingUpstream", 1, conf, CONF_ssh_connection_sharing_upstream);\r
1124     gppi(sesskey, "ConnectionSharingDownstream", 1, conf, CONF_ssh_connection_sharing_downstream);\r
1125     gppmap(sesskey, "SSHManualHostKeys", conf, CONF_ssh_manual_hostkeys);\r
1128 void do_defaults(const char *session, Conf *conf)\r
1130     load_settings(session, conf);\r
1133 static int sessioncmp(const void *av, const void *bv)\r
1135     const char *a = *(const char *const *) av;\r
1136     const char *b = *(const char *const *) bv;\r
1138     /*\r
1139      * Alphabetical order, except that "Default Settings" is a\r
1140      * special case and comes first.\r
1141      */\r
1142     if (!strcmp(a, "Default Settings"))\r
1143         return -1;                     /* a comes first */\r
1144     if (!strcmp(b, "Default Settings"))\r
1145         return +1;                     /* b comes first */\r
1146     /*\r
1147      * FIXME: perhaps we should ignore the first & in determining\r
1148      * sort order.\r
1149      */\r
1150     return strcmp(a, b);               /* otherwise, compare normally */\r
1153 void get_sesslist(struct sesslist *list, int allocate)\r
1155     char otherbuf[2048];\r
1156     int buflen, bufsize, i;\r
1157     char *p, *ret;\r
1158     void *handle;\r
1160     if (allocate) {\r
1162         buflen = bufsize = 0;\r
1163         list->buffer = NULL;\r
1164         if ((handle = enum_settings_start()) != NULL) {\r
1165             do {\r
1166                 ret = enum_settings_next(handle, otherbuf, sizeof(otherbuf));\r
1167                 if (ret) {\r
1168                     int len = strlen(otherbuf) + 1;\r
1169                     if (bufsize < buflen + len) {\r
1170                         bufsize = buflen + len + 2048;\r
1171                         list->buffer = sresize(list->buffer, bufsize, char);\r
1172                     }\r
1173                     strcpy(list->buffer + buflen, otherbuf);\r
1174                     buflen += strlen(list->buffer + buflen) + 1;\r
1175                 }\r
1176             } while (ret);\r
1177             enum_settings_finish(handle);\r
1178         }\r
1179         list->buffer = sresize(list->buffer, buflen + 1, char);\r
1180         list->buffer[buflen] = '\0';\r
1182         /*\r
1183          * Now set up the list of sessions. Note that "Default\r
1184          * Settings" must always be claimed to exist, even if it\r
1185          * doesn't really.\r
1186          */\r
1188         p = list->buffer;\r
1189         list->nsessions = 1;           /* "Default Settings" counts as one */\r
1190         while (*p) {\r
1191             if (strcmp(p, "Default Settings"))\r
1192                 list->nsessions++;\r
1193             while (*p)\r
1194                 p++;\r
1195             p++;\r
1196         }\r
1198         list->sessions = snewn(list->nsessions + 1, const char *);\r
1199         list->sessions[0] = "Default Settings";\r
1200         p = list->buffer;\r
1201         i = 1;\r
1202         while (*p) {\r
1203             if (strcmp(p, "Default Settings"))\r
1204                 list->sessions[i++] = p;\r
1205             while (*p)\r
1206                 p++;\r
1207             p++;\r
1208         }\r
1210         qsort(list->sessions, i, sizeof(const char *), sessioncmp);\r
1211     } else {\r
1212         sfree(list->buffer);\r
1213         sfree(list->sessions);\r
1214         list->buffer = NULL;\r
1215         list->sessions = NULL;\r
1216     }\r