#include "putty.h"
#include "storage.h"
+/*
+ * Tables of string <-> enum value mappings
+ */
+struct keyval { char *s; int v; };
+
+static const struct keyval ciphernames[] = {
+ { "aes", CIPHER_AES },
+ { "blowfish", CIPHER_BLOWFISH },
+ { "3des", CIPHER_3DES },
+ { "WARN", CIPHER_WARN },
+ { "des", CIPHER_DES }
+};
+
static void gpps(void *handle, char *name, char *def, char *val, int len)
{
if (!read_setting_s(handle, name, val, len)) {
*i = read_setting_i(handle, name, def);
}
+static int key2val(const struct keyval *mapping, int nmaps, char *key)
+{
+ int i;
+ for (i = 0; i < nmaps; i++)
+ if (!strcmp(mapping[i].s, key)) return mapping[i].v;
+ return -1;
+}
+
+static const char *val2key(const struct keyval *mapping, int nmaps, int val)
+{
+ int i;
+ for (i = 0; i < nmaps; i++)
+ if (mapping[i].v == val) return mapping[i].s;
+ return NULL;
+}
+
+/*
+ * Helper function to parse a comma-separated list of strings into
+ * a preference list array of values. Any missing values are added
+ * to the end and duplicates are weeded.
+ * XXX: assumes vals in 'mapping' are small +ve integers
+ */
+static void gprefs(void *sesskey, char *name, char *def,
+ const struct keyval *mapping, int nvals,
+ int *array)
+{
+ char commalist[80];
+ int n;
+ unsigned long seen = 0; /* bitmap for weeding dups etc */
+ gpps(sesskey, name, def, commalist, sizeof(commalist));
+
+ /* Grotty parsing of commalist. */
+ n = 0;
+ do {
+ int v;
+ char *key;
+ key = strtok(n==0 ? commalist : NULL, ","); /* sorry */
+ if (!key) break;
+ if (((v = key2val(mapping, nvals, key)) != -1) &&
+ !(seen & 1<<v)) {
+ array[n] = v;
+ n++;
+ seen |= 1<<v;
+ }
+ } while (n < nvals);
+ /* Add any missing values (backward compatibility ect). */
+ {
+ int i, j;
+ for (i = 0; i < nvals; i++) {
+ if (!(seen & 1<<mapping[i].v)) {
+ array[n] = mapping[i].v;
+ n++;
+ }
+ }
+ }
+}
+
+/*
+ * Write out a preference list.
+ */
+static void wprefs(void *sesskey, char *name,
+ const struct keyval *mapping, int nvals,
+ int *array)
+{
+ char buf[80] = ""; /* XXX assumed big enough */
+ int l = sizeof(buf)-1, i;
+ buf[l] = '\0';
+ for (i = 0; l > 0 && i < nvals; i++) {
+ const char *s = val2key(mapping, nvals, array[i]);
+ if (s) {
+ int sl = strlen(s);
+ if (i > 0) {
+ strncat(buf, ",", l);
+ l--;
+ }
+ strncat(buf, s, l);
+ l -= sl;
+ }
+ }
+ write_setting_s(sesskey, name, buf);
+}
+
void save_settings(char *section, int do_host, Config * cfg)
{
int i;
write_setting_i(sesskey, "NoPTY", cfg->nopty);
write_setting_i(sesskey, "Compression", cfg->compression);
write_setting_i(sesskey, "AgentFwd", cfg->agentfwd);
- write_setting_s(sesskey, "Cipher",
- cfg->cipher == CIPHER_BLOWFISH ? "blowfish" :
- cfg->cipher == CIPHER_DES ? "des" :
- cfg->cipher == CIPHER_AES ? "aes" : "3des");
+ wprefs(sesskey, "Cipher", ciphernames, CIPHER_MAX,
+ cfg->ssh_cipherlist);
write_setting_i(sesskey, "AuthTIS", cfg->try_tis_auth);
write_setting_i(sesskey, "SshProt", cfg->sshprot);
write_setting_i(sesskey, "BuggyMAC", cfg->buggymac);
write_setting_i(sesskey, "CurType", cfg->cursor_type);
write_setting_i(sesskey, "BlinkCur", cfg->blink_cur);
write_setting_i(sesskey, "Beep", cfg->beep);
+ write_setting_i(sesskey, "BeepInd", cfg->beep_ind);
write_setting_s(sesskey, "BellWaveFile", cfg->bell_wavefile);
write_setting_i(sesskey, "BellOverload", cfg->bellovl);
write_setting_i(sesskey, "BellOverloadN", cfg->bellovl_n);
write_setting_i(sesskey, "BlinkText", cfg->blinktext);
write_setting_i(sesskey, "X11Forward", cfg->x11_forward);
write_setting_s(sesskey, "X11Display", cfg->x11_display);
+ write_setting_i(sesskey, "LocalPortAcceptAll", cfg->lport_acceptall);
+ {
+ char buf[2 * sizeof(cfg->portfwd)], *p, *q;
+ p = buf;
+ q = cfg->portfwd;
+ while (*q) {
+ while (*q) {
+ int c = *q++;
+ if (c == '=' || c == ',' || c == '\\')
+ *p++ = '\\';
+ if (c == '\t')
+ c = '=';
+ *p++ = c;
+ }
+ *p++ = ',';
+ q++;
+ }
+ *p = '\0';
+ write_setting_s(sesskey, "PortForwardings", buf);
+ }
close_settings_w(sesskey);
}
gppi(sesskey, "NoPTY", 0, &cfg->nopty);
gppi(sesskey, "Compression", 0, &cfg->compression);
gppi(sesskey, "AgentFwd", 0, &cfg->agentfwd);
- {
- char cipher[10];
- gpps(sesskey, "Cipher", "3des", cipher, 10);
- if (!strcmp(cipher, "blowfish"))
- cfg->cipher = CIPHER_BLOWFISH;
- else if (!strcmp(cipher, "des"))
- cfg->cipher = CIPHER_DES;
- else if (!strcmp(cipher, "aes"))
- cfg->cipher = CIPHER_AES;
- else
- cfg->cipher = CIPHER_3DES;
- }
+ gprefs(sesskey, "Cipher", "\0",
+ ciphernames, CIPHER_MAX, cfg->ssh_cipherlist);
gppi(sesskey, "SshProt", 1, &cfg->sshprot);
gppi(sesskey, "BuggyMAC", 0, &cfg->buggymac);
gppi(sesskey, "AuthTIS", 0, &cfg->try_tis_auth);
gppi(sesskey, "SunkenEdge", 0, &cfg->sunken_edge);
gppi(sesskey, "CurType", 0, &cfg->cursor_type);
gppi(sesskey, "BlinkCur", 0, &cfg->blink_cur);
- gppi(sesskey, "Beep", 1, &cfg->beep);
+ /* pedantic compiler tells me I can't use &cfg->beep as an int * :-) */
+ gppi(sesskey, "Beep", 1, &i); cfg->beep = i;
+ gppi(sesskey, "BeepInd", 0, &i); cfg->beep_ind = i;
gpps(sesskey, "BellWaveFile", "", cfg->bell_wavefile,
sizeof(cfg->bell_wavefile));
gppi(sesskey, "BellOverload", 1, &cfg->bellovl);
cfg->wordness[j] = atoi(q);
}
}
- gpps(sesskey, "LineCodePage", "", cfg->line_codepage,
+ gpps(sesskey, "LineCodePage", "ISO-8859-1:1987", cfg->line_codepage,
sizeof(cfg->line_codepage));
gppi(sesskey, "ScrollBar", 1, &cfg->scrollbar);
gppi(sesskey, "ScrollOnKey", 0, &cfg->scroll_on_key);
gpps(sesskey, "X11Display", "localhost:0", cfg->x11_display,
sizeof(cfg->x11_display));
+ gppi(sesskey, "LocalPortAcceptAll", 0, &cfg->lport_acceptall);
+ {
+ char buf[2 * sizeof(cfg->portfwd)], *p, *q;
+ gpps(sesskey, "PortForwardings", "", buf, sizeof(buf));
+ p = buf;
+ q = cfg->portfwd;
+ while (*p) {
+ while (*p && *p != ',') {
+ int c = *p++;
+ if (c == '=')
+ c = '\t';
+ if (c == '\\')
+ c = *p++;
+ *q++ = c;
+ }
+ if (*p == ',')
+ p++;
+ *q++ = '\0';
+ }
+ *q = '\0';
+ }
+
close_settings_r(sesskey);
}