]> git.notmuchmail.org Git - notmuch/blobdiff - notmuch-config.c
Merge branch 'debian/unstable' into release
[notmuch] / notmuch-config.c
index e029e3062846e9f3446c299841fac88be76f6b66..b7f0784f1d99b6bc967dc9958dca622443a1012f 100644 (file)
@@ -24,6 +24,8 @@
 #include <netdb.h>
 #include <assert.h>
 
+#include "unicode-util.h"
+
 static const char toplevel_config_comment[] =
     " .notmuch-config - Configuration file for the notmuch mail system\n"
     "\n"
@@ -790,20 +792,80 @@ _item_split (char *item, char **group, char **key)
     return 0;
 }
 
+/* These are more properly called Xapian fields, but the user facing
+   docs call them prefixes, so make the error message match */
+static bool
+validate_field_name (const char *str)
+{
+    const char *key;
+
+    if (! g_utf8_validate (str, -1, NULL)) {
+       fprintf (stderr, "Invalid utf8: %s\n", str);
+       return false;
+    }
+
+    key = g_utf8_strrchr (str, -1, '.');
+    if (! key ) {
+       INTERNAL_ERROR ("Impossible code path on input: %s\n", str);
+    }
+
+    key++;
+
+    if (! *key) {
+       fprintf (stderr, "Empty prefix name: %s\n", str);
+       return false;
+    }
+
+    if (! unicode_word_utf8 (key)) {
+       fprintf (stderr, "Non-word character in prefix name: %s\n", key);
+       return false;
+    }
+
+    if (key[0] >= 'a' && key[0] <= 'z') {
+       fprintf (stderr, "Prefix names starting with lower case letters are reserved: %s\n", key);
+       return false;
+    }
+
+    return true;
+}
+
 #define BUILT_WITH_PREFIX "built_with."
 
+typedef struct config_key {
+    const char *name;
+    bool in_db;
+    bool prefix;
+    bool (*validate)(const char *);
+} config_key_info_t;
+
+static struct config_key
+config_key_table[] = {
+    {"index.decrypt",  true,   false,  NULL},
+    {"index.header.",  true,   true,   validate_field_name},
+    {"query.",         true,   true,   NULL},
+};
+
+static config_key_info_t *
+_config_key_info (const char *item)
+{
+    for (size_t i = 0; i < ARRAY_SIZE (config_key_table); i++) {
+       if (config_key_table[i].prefix &&
+           strncmp (item, config_key_table[i].name,
+                    strlen(config_key_table[i].name)) == 0)
+           return config_key_table+i;
+       if (strcmp (item, config_key_table[i].name) == 0)
+           return config_key_table+i;
+    }
+    return NULL;
+}
+
 static bool
 _stored_in_db (const char *item)
 {
-    const char * db_configs[] = {
-       "index.decrypt",
-    };
-    if (STRNCMP_LITERAL (item, "query.") == 0)
-       return true;
-    for (size_t i = 0; i < ARRAY_SIZE (db_configs); i++)
-       if (strcmp (item, db_configs[i]) == 0)
-           return true;
-    return false;
+    config_key_info_t *info;
+    info = _config_key_info (item);
+
+    return (info && info->in_db);
 }
 
 static int
@@ -918,13 +980,18 @@ static int
 notmuch_config_command_set (notmuch_config_t *config, char *item, int argc, char *argv[])
 {
     char *group, *key;
+    config_key_info_t *key_info;
 
     if (STRNCMP_LITERAL (item, BUILT_WITH_PREFIX) == 0) {
        fprintf (stderr, "Error: read only option: %s\n", item);
        return 1;
     }
 
-    if (_stored_in_db (item)) {
+    key_info = _config_key_info (item);
+    if (key_info && key_info->validate && (! key_info->validate (item)))
+       return 1;
+
+    if (key_info && key_info->in_db) {
        return _set_db_config (config, item, argc, argv);
     }