* Defined here so that backends can export their GSS library tables
* to the cross-platform settings code.
*/
-struct keyval { char *s; int v; };
+struct keyvalwhere {
+ /*
+ * Two fields which define a string and enum value to be
+ * equivalent to each other.
+ */
+ char *s;
+ int v;
+
+ /*
+ * The next pair of fields are used by gprefs() in settings.c to
+ * arrange that when it reads a list of strings representing a
+ * preference list and translates it into the corresponding list
+ * of integers, strings not appearing in the list are entered in a
+ * configurable position rather than uniformly at the end.
+ */
+
+ /*
+ * 'vrel' indicates which other value in the list to place this
+ * element relative to. It should be a value that has occurred in
+ * a 'v' field of some other element of the array, or -1 to
+ * indicate that we simply place relative to one or other end of
+ * the list.
+ *
+ * gprefs will try to process the elements in an order which makes
+ * this field work (i.e. so that the element referenced has been
+ * added before processing this one).
+ */
+ int vrel;
+
+ /*
+ * 'where' indicates whether to place the new value before or
+ * after the one referred to by vrel. -1 means before; +1 means
+ * after.
+ *
+ * When vrel is -1, this also implicitly indicates which end of
+ * the array to use. So vrel=-1, where=-1 means to place _before_
+ * some end of the list (hence, at the last element); vrel=-1,
+ * where=+1 means to place _after_ an end (hence, at the first).
+ */
+ int where;
+};
#ifndef NO_GSSAPI
extern const int ngsslibs;
-extern const char *const gsslibnames[];/* for displaying in configuration */
-extern const struct keyval gsslibkeywords[]; /* for storing by settings.c */
+extern const char *const gsslibnames[]; /* for displaying in configuration */
+extern const struct keyvalwhere gsslibkeywords[]; /* for settings.c */
#endif
extern const char *const ttymodes[];
#include "storage.h"
/* The cipher order given here is the default order. */
-static const struct keyval ciphernames[] = {
- { "aes", CIPHER_AES },
- { "blowfish", CIPHER_BLOWFISH },
- { "3des", CIPHER_3DES },
- { "WARN", CIPHER_WARN },
- { "arcfour", CIPHER_ARCFOUR },
- { "des", CIPHER_DES }
+static const struct keyvalwhere ciphernames[] = {
+ { "aes", CIPHER_AES, -1, -1 },
+ { "blowfish", CIPHER_BLOWFISH, -1, -1 },
+ { "3des", CIPHER_3DES, -1, -1 },
+ { "WARN", CIPHER_WARN, -1, -1 },
+ { "arcfour", CIPHER_ARCFOUR, -1, -1 },
+ { "des", CIPHER_DES, -1, -1 }
};
-static const struct keyval kexnames[] = {
- { "dh-gex-sha1", KEX_DHGEX },
- { "dh-group14-sha1", KEX_DHGROUP14 },
- { "dh-group1-sha1", KEX_DHGROUP1 },
- { "rsa", KEX_RSA },
- { "WARN", KEX_WARN }
+static const struct keyvalwhere kexnames[] = {
+ { "dh-gex-sha1", KEX_DHGEX, -1, -1 },
+ { "dh-group14-sha1", KEX_DHGROUP14, -1, -1 },
+ { "dh-group1-sha1", KEX_DHGROUP1, -1, -1 },
+ { "rsa", KEX_RSA, KEX_WARN, -1 },
+ { "WARN", KEX_WARN, -1, -1 }
};
/*
sfree(buf);
}
-static int key2val(const struct keyval *mapping, int nmaps, char *key)
+static int key2val(const struct keyvalwhere *mapping,
+ int nmaps, char *key)
{
int i;
for (i = 0; i < nmaps; i++)
return -1;
}
-static const char *val2key(const struct keyval *mapping, int nmaps, int val)
+static const char *val2key(const struct keyvalwhere *mapping,
+ int nmaps, int val)
{
int i;
for (i = 0; i < nmaps; i++)
* XXX: assumes vals in 'mapping' are small +ve integers
*/
static void gprefs(void *sesskey, char *name, char *def,
- const struct keyval *mapping, int nvals,
+ const struct keyvalwhere *mapping, int nvals,
int *array)
{
- char commalist[80];
- char *tokarg = commalist;
- int n;
+ char commalist[256];
+ char *p, *q;
+ int i, j, n, v, pos;
unsigned long seen = 0; /* bitmap for weeding dups etc */
+
+ /*
+ * Fetch the string which we'll parse as a comma-separated list.
+ */
gpps(sesskey, name, def, commalist, sizeof(commalist));
- /* Grotty parsing of commalist. */
+ /*
+ * Go through that list and convert it into values.
+ */
n = 0;
- do {
- int v;
- char *key;
- key = strtok(tokarg, ","); /* sorry */
- tokarg = NULL;
- if (!key) break;
- if (((v = key2val(mapping, nvals, key)) != -1) &&
- !(seen & 1<<v)) {
- array[n] = v;
- n++;
- seen |= 1<<v;
+ p = commalist;
+ while (1) {
+ while (*p && *p == ',') p++;
+ if (!*p)
+ break; /* no more words */
+
+ q = p;
+ while (*p && *p != ',') p++;
+ if (*p) *p++ = '\0';
+
+ v = key2val(mapping, nvals, q);
+ if (v != -1 && !(seen & (1 << v))) {
+ seen |= (1 << v);
+ array[n++] = v;
}
- } while (n < nvals);
- /* Add any missing values (backward compatibility ect). */
- {
- int i;
- for (i = 0; i < nvals; i++) {
+ }
+
+ /*
+ * Now go through 'mapping' and add values that weren't mentioned
+ * in the list we fetched. We may have to loop over it multiple
+ * times so that we add values before other values whose default
+ * positions depend on them.
+ */
+ while (n < nvals) {
+ for (i = 0; i < nvals; i++) {
assert(mapping[i].v < 32);
- if (!(seen & 1<<mapping[i].v)) {
- array[n] = mapping[i].v;
- n++;
- }
- }
+
+ if (!(seen & (1 << mapping[i].v))) {
+ /*
+ * This element needs adding. But can we add it yet?
+ */
+ if (mapping[i].vrel != -1 && !(seen & (1 << mapping[i].vrel)))
+ continue; /* nope */
+
+ /*
+ * OK, we can work out where to add this element, so
+ * do so.
+ */
+ if (mapping[i].vrel == -1) {
+ pos = (mapping[i].where < 0 ? n : 0);
+ } else {
+ for (j = 0; j < n; j++)
+ if (array[j] == mapping[i].vrel)
+ break;
+ assert(j < n); /* implied by (seen & (1<<vrel)) */
+ pos = (mapping[i].where < 0 ? j : j+1);
+ }
+
+ /*
+ * And add it.
+ */
+ for (j = n-1; j >= pos; j--)
+ array[j+1] = array[j];
+ array[pos] = mapping[i].v;
+ n++;
+ }
+ }
}
}
* Write out a preference list.
*/
static void wprefs(void *sesskey, char *name,
- const struct keyval *mapping, int nvals,
+ const struct keyvalwhere *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++) {
+ char *buf, *p;
+ int i, maxlen;
+
+ for (maxlen = i = 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;
+ maxlen += 1 + strlen(s);
+ }
+ }
+
+ buf = snewn(maxlen, char);
+ p = buf;
+
+ for (i = 0; i < nvals; i++) {
+ const char *s = val2key(mapping, nvals, array[i]);
+ if (s) {
+ p += sprintf(p, "%s%s", (p > buf ? "," : ""), s);
}
}
+
+ assert(p - buf == maxlen - 1); /* maxlen counted the NUL */
+
write_setting_s(sesskey, name, buf);
+
+ sfree(buf);
}
char *save_settings(char *section, Config * cfg)