]> granicus.if.org Git - neomutt/commitdiff
register
authorRichard Russon <rich@flatcap.org>
Wed, 10 Jan 2018 16:34:11 +0000 (16:34 +0000)
committerRichard Russon <rich@flatcap.org>
Mon, 23 Jul 2018 14:50:10 +0000 (15:50 +0100)
17 files changed:
commands.c
config/address.c
config/dump.c
curs_lib.c
globals.h
init.c
init.h
mailbox.h
main.c
mutt.h
mutt/regex3.h
mutt_logging.c
mutt_logging.h
mutt_lua.c
mx.c
myvar.h
ncrypt/cryptglue.c

index 22ac254ac56e228878242f5a7a53722477f7674b..04cf2902f483bdd7c86c5a1a71d6d70d7806de68 100644 (file)
@@ -695,6 +695,7 @@ void mutt_enter_command(void)
   mutt_buffer_init(&err);
   err.dsize = STRING;
   err.data = mutt_mem_malloc(err.dsize);
+  err.dptr = err.data;
   mutt_buffer_init(&token);
   r = mutt_parse_rc_line(buffer, &token, &err);
   FREE(&token.data);
index 2bd203ee4bc0c4dfc7ce9059dd6d600896341262..ead5c3aee451cb44d8430fc0921f868c8b78f3ea 100644 (file)
@@ -294,8 +294,8 @@ void address_init(struct ConfigSet *cs)
 struct Address *address_create(const char *addr)
 {
   struct Address *a = mutt_mem_calloc(1, sizeof(*a));
-  a->personal = mutt_str_strdup(addr);
-  a->mailbox = mutt_str_strdup("dummy3");
+  // a->personal = mutt_str_strdup(addr);
+  a->mailbox = mutt_str_strdup(addr);
   return a;
 }
 
index 768d37bb44ab27e59f8bb3e2cd35d1264f96d563..6a24223e889bba39d187954a04c5fa7ae2f190c2 100644 (file)
@@ -40,9 +40,7 @@
 #include "set.h"
 #include "types.h"
 
-void mutt_pretty_mailbox(char *s, size_t buflen)
-{
-}
+void mutt_pretty_mailbox(char *s, size_t buflen);
 
 /**
  * escape_string - Write a string to a buffer, escaping special characters
index 635a4c69061bf95e288ef624bbab43eb61917956..0719a75db95c6f92443dc9c26597005950ca2e6d 100644 (file)
@@ -54,6 +54,7 @@
 #include "options.h"
 #include "pager.h"
 #include "protos.h"
+#include "sidebar.h"
 #ifdef HAVE_ISWBLANK
 #include <wctype.h>
 #endif
index ca59820cb1704382e6ea1b61d5c7f8192bf7c25b..c263cce875c0ace4f4a29a5e39c7c98544207355 100644 (file)
--- a/globals.h
+++ b/globals.h
@@ -27,6 +27,7 @@
 #include <stdbool.h>
 #include "mutt/mutt.h"
 #include "where.h"
+#include "config/lib.h"
 
 #ifdef MAIN_C
 /* so that global vars get included */
@@ -36,6 +37,8 @@
 #include "sort.h"
 #endif /* MAIN_C */
 
+WHERE struct ConfigSet *Config;
+
 WHERE struct Context *Context;
 
 WHERE bool ErrorBufMessage;
diff --git a/init.c b/init.c
index 33989deb72bde05e5e2330857929044d4ca364da..4af478616c29f2b8aae50d509a4b82547ba0f865 100644 (file)
--- a/init.c
+++ b/init.c
@@ -25,6 +25,7 @@
 #include <errno.h>
 #include <inttypes.h>
 #include <limits.h>
+#include <pwd.h>
 #include <regex.h>
 #include <stdbool.h>
 #include <stdio.h>
@@ -47,7 +48,6 @@
 #include "mailbox.h"
 #include "menu.h"
 #include "mutt_curses.h"
-#include "mutt_history.h"
 #include "mutt_window.h"
 #include "mx.h"
 #include "myvar.h"
 #include "notmuch/mutt_notmuch.h"
 #endif
 #ifdef USE_IMAP
-#include "imap/imap.h" /* for imap_subscribe() */
+#include "imap/imap.h"
 #endif
 #ifdef ENABLE_NLS
 #include <libintl.h>
 #endif
 
-#define CHECK_PAGER                                                                  \
-  if ((CurrentMenu == MENU_PAGER) && (idx >= 0) && (MuttVars[idx].flags & R_RESORT)) \
-  {                                                                                  \
-    mutt_buffer_printf(err, "%s", _("Not available in this menu."));                 \
-    return -1;                                                                       \
-  }
-
 /* LIFO designed to contain the list of config files that have been sourced and
  * avoid cyclic sourcing */
 static struct ListHead MuttrcStack = STAILQ_HEAD_INITIALIZER(MuttrcStack);
@@ -216,37 +209,6 @@ static void candidate(char *try, const char *src, char *dest, size_t dlen)
   }
 }
 
-/**
- * check_charset - Check a charset Option is valid
- * @param opt Option
- * @param val Value to check
- * @retval  0 Success
- * @retval -1 Error
- */
-static int check_charset(struct ConfigDef *opt, const char *val)
-{
-  char *q = NULL, *s = mutt_str_strdup(val);
-  int rc = 0;
-  bool strict = (strcmp(opt->name, "send_charset") == 0);
-
-  if (!s)
-    return rc;
-
-  for (char *p = strtok_r(s, ":", &q); p; p = strtok_r(NULL, ":", &q))
-  {
-    if (!*p)
-      continue;
-    if (!mutt_ch_check_charset(p, strict))
-    {
-      rc = -1;
-      break;
-    }
-  }
-
-  FREE(&s);
-  return rc;
-}
-
 /**
  * clear_subject_mods - Clear out all modified email subjects
  */
@@ -317,61 +279,6 @@ done:
 }
 #endif
 
-/**
- * esc_char - Escape a single character
- * @param c      Character to escape
- * @param p      Where in the buffer to place the escaped character
- * @param buf    Buffer for the result
- * @param buflen Length of the buffer
- */
-static void esc_char(char c, char *p, char *buf, size_t buflen)
-{
-  *p++ = '\\';
-  if (p - buf < buflen)
-    *p++ = c;
-}
-
-/**
- * escape_string - Escape a string
- * @param buf    Buffer for the result
- * @param buflen Length of the buffer
- * @param src    String to escape
- * @retval num Number of bytes written to the buffer
- */
-static size_t escape_string2(char *buf, size_t buflen, const char *src)
-{
-  char *p = buf;
-
-  if (!buflen)
-    return 0;
-  buflen--; /* save room for \0 */
-  while (p - buf < buflen && src && *src)
-  {
-    switch (*src)
-    {
-      case '\n':
-        esc_char('n', p, buf, buflen);
-        p += 2;
-        break;
-      case '\r':
-        esc_char('r', p, buf, buflen);
-        p += 2;
-        break;
-      case '\t':
-        esc_char('t', p, buf, buflen);
-        p += 2;
-        break;
-      default:
-        if ((*src == '\\' || *src == '"') && p - buf < buflen - 1)
-          *p++ = '\\';
-        *p++ = *src;
-    }
-    src++;
-  }
-  *p = '\0';
-  return p - buf;
-}
-
 /**
  * execute_commands - Execute a set of NeoMutt commands
  * @param p List of command strings
@@ -447,43 +354,6 @@ static char *find_cfg(const char *home, const char *xdg_cfg_home)
   return NULL;
 }
 
-/**
- * free_mbtable - Free an MbTable
- * @param t MbTable to free
- */
-static void free_mbtable(struct MbTable **t)
-{
-  if (!t || !*t)
-    return;
-
-  FREE(&(*t)->chars);
-  FREE(&(*t)->segmented_str);
-  FREE(&(*t)->orig_str);
-  FREE(t);
-}
-
-/**
- * free_opt - Free an Option
- * @param p Option to free
- */
-static void free_opt(struct ConfigDef *p)
-{
-  switch (DTYPE(p->type))
-  {
-    case DT_ADDRESS:
-      mutt_addr_free((struct Address **) p->var);
-      break;
-    case DT_REGEX:
-      mutt_regex_free((struct Regex **) p->var);
-      break;
-    case DT_PATH:
-    case DT_COMMAND:
-    case DT_STRING:
-      FREE((char **) p->var);
-      break;
-  }
-}
-
 #ifndef DOMAIN
 /**
  * getmailname - Try to retrieve the FQDN from mailname files
@@ -729,84 +599,6 @@ bail:
   return -1;
 }
 
-/**
- * parse_mbtable - Parse an MbTable string
- * @param s String to parse
- * @retval ptr New MbTable
- */
-static struct MbTable *parse_mbtable(const char *s)
-{
-  size_t slen, k;
-  mbstate_t mbstate;
-  char *d = NULL;
-
-  struct MbTable *t = mutt_mem_calloc(1, sizeof(struct MbTable));
-  slen = mutt_str_strlen(s);
-  if (slen == 0)
-    return t;
-
-  t->orig_str = mutt_str_strdup(s);
-  /* This could be more space efficient.  However, being used on tiny
-   * strings (ToChars and StatusChars), the overhead is not great. */
-  t->chars = mutt_mem_calloc(slen, sizeof(char *));
-  d = t->segmented_str = mutt_mem_calloc(slen * 2, sizeof(char));
-
-  memset(&mbstate, 0, sizeof(mbstate));
-  while (slen && (k = mbrtowc(NULL, s, slen, &mbstate)))
-  {
-    if (k == (size_t)(-1) || k == (size_t)(-2))
-    {
-      mutt_debug(1, "mbrtowc returned %d converting %s in %s\n",
-                 (k == (size_t)(-1)) ? -1 : -2, s, t->orig_str);
-      if (k == (size_t)(-1))
-        memset(&mbstate, 0, sizeof(mbstate));
-      k = (k == (size_t)(-1)) ? 1 : slen;
-    }
-
-    slen -= k;
-    t->chars[t->len++] = d;
-    while (k--)
-      *d++ = *s++;
-    *d++ = '\0';
-  }
-
-  return t;
-}
-
-/**
- * parse_regex - Parse a regular expression
- * @param idx Index of config item in MuttVars
- * @param tmp Temporary Buffer space
- * @param err Buffer for error messages
- * @retval 0 Success
- * @retval 1 Error
- */
-static int parse_regex(int idx, struct Buffer *tmp, struct Buffer *err)
-{
-  struct Regex **ptr = (struct Regex **) MuttVars[idx].var;
-
-  if (*ptr)
-  {
-    /* Same pattern as we already have */
-    if (mutt_str_strcmp((*ptr)->pattern, tmp->data) == 0)
-      return 0;
-  }
-
-  if (mutt_buffer_is_empty(tmp))
-  {
-    mutt_regex_free(ptr);
-    return 0;
-  }
-
-  struct Regex *rnew = mutt_regex_create(tmp->data, MuttVars[idx].type, err);
-  if (!rnew)
-    return 1;
-
-  mutt_regex_free(ptr);
-  *ptr = rnew;
-  return 0;
-}
-
 /**
  * parse_replace_list - Parse a string replacement rule
  * @param buf  Temporary Buffer space
@@ -848,43 +640,6 @@ static int parse_replace_list(struct Buffer *buf, struct Buffer *s,
   return 0;
 }
 
-/**
- * parse_sort - Parse a sort string
- * @param[out] val Sort ID, e.g. #SORT_DATE
- * @param[in]  s   Sort string
- * @param[in]  map Lookup table for the config item
- * @param[out] err Buffer for error messages
- * @retval 0  Success, valid sort string
- * @retval -1 Error, invalid sort string
- */
-static int parse_sort(short *val, const char *s, const struct Mapping *map, struct Buffer *err)
-{
-  int i, flags = 0;
-
-  if (mutt_str_strncmp("reverse-", s, 8) == 0)
-  {
-    s += 8;
-    flags = SORT_REVERSE;
-  }
-
-  if (mutt_str_strncmp("last-", s, 5) == 0)
-  {
-    s += 5;
-    flags |= SORT_LAST;
-  }
-
-  i = mutt_map_get_value(s, map);
-  if (i == -1)
-  {
-    mutt_buffer_printf(err, _("%s: unknown sorting method"), s);
-    return -1;
-  }
-
-  *val = i | flags;
-
-  return 0;
-}
-
 /**
  * parse_unattach_list - Parse the "unattachments" command
  * @param buf  Buffer for temporary storage
@@ -982,36 +737,6 @@ static int parse_unreplace_list(struct Buffer *buf, struct Buffer *s,
   return 0;
 }
 
-/**
- * pretty_var - Make a config value ready for user display
- * @param buf    Buffer for the result
- * @param buflen Length of the buffer
- * @param option Option
- * @param val    Value to format
- *
- * This function escapes and quotes the string value.
- */
-static void pretty_var2(char *buf, size_t buflen, const char *option, const char *val)
-{
-  char *p = NULL;
-
-  if (!buflen)
-    return;
-
-  mutt_str_strfcpy(buf, option, buflen);
-  buflen--; /* save room for \0 */
-  p = buf + mutt_str_strlen(buf);
-
-  if (p - buf < buflen)
-    *p++ = '=';
-  if (p - buf < buflen)
-    *p++ = '"';
-  p += escape_string2(p, buflen - (p - buf) + 1, val); /* \0 terminate it */
-  if (p - buf < buflen)
-    *p++ = '"';
-  *p = '\0';
-}
-
 /**
  * print_attach_list - Print a list of attachments
  * @param h    List of attachments
@@ -1059,146 +784,6 @@ static void remove_from_stailq(struct ListHead *head, const char *str)
   }
 }
 
-/**
- * restore_default - Restore the default of an Option
- * @param p Option to reset
- */
-static void restore_default(struct ConfigDef *p)
-{
-  switch (DTYPE(p->type))
-  {
-    case DT_STRING:
-    case DT_COMMAND:
-      mutt_str_replace((char **) p->var, (char *) p->initial);
-      break;
-    case DT_MBTABLE:
-      free_mbtable((struct MbTable **) p->var);
-      *((struct MbTable **) p->var) = parse_mbtable((char *) p->initial);
-      break;
-    case DT_PATH:
-    {
-      char *init = (char *) p->initial;
-      if (mutt_str_strcmp(p->name, "debug_file") == 0)
-      {
-        mutt_log_set_file(init, true);
-      }
-      else
-      {
-        FREE((char **) p->var);
-        if (init)
-        {
-          char path[PATH_MAX];
-          mutt_str_strfcpy(path, init, sizeof(path));
-          mutt_expand_path(path, sizeof(path));
-          *((char **) p->var) = mutt_str_strdup(path);
-        }
-      }
-      break;
-    }
-    case DT_ADDRESS:
-      mutt_addr_free((struct Address **) p->var);
-      if (p->initial)
-        *((struct Address **) p->var) = mutt_addr_parse_list(NULL, (char *) p->initial);
-      break;
-    case DT_BOOL:
-      if (p->initial)
-        *(bool *) p->var = true;
-      else
-        *(bool *) p->var = false;
-      break;
-    case DT_QUAD:
-      *(unsigned char *) p->var = p->initial;
-      break;
-    case DT_NUMBER:
-    case DT_SORT:
-    case DT_MAGIC:
-      if (mutt_str_strcmp(p->name, "debug_level") == 0)
-        mutt_log_set_level(p->initial, true);
-      else
-        *((short *) p->var) = p->initial;
-      break;
-    case DT_LONG:
-      *((long *) p->var) = p->initial;
-      break;
-    case DT_REGEX:
-    {
-      struct Regex **ptr = (struct Regex **) p->var;
-
-      if (*ptr)
-        mutt_regex_free(ptr);
-
-      *ptr = mutt_regex_create((const char *) p->initial, p->type, NULL);
-      break;
-    }
-  }
-
-  if (p->flags & R_INDEX)
-    mutt_menu_set_redraw_full(MENU_MAIN);
-  if (p->flags & R_PAGER)
-    mutt_menu_set_redraw_full(MENU_PAGER);
-  if (p->flags & R_PAGER_FLOW)
-  {
-    mutt_menu_set_redraw_full(MENU_PAGER);
-    mutt_menu_set_redraw(MENU_PAGER, REDRAW_FLOW);
-  }
-  if (p->flags & R_RESORT_SUB)
-    OptSortSubthreads = true;
-  if (p->flags & R_RESORT)
-    OptNeedResort = true;
-  if (p->flags & R_RESORT_INIT)
-    OptResortInit = true;
-  if (p->flags & R_TREE)
-    OptRedrawTree = true;
-  if (p->flags & R_REFLOW)
-    mutt_window_reflow();
-#ifdef USE_SIDEBAR
-  if (p->flags & R_SIDEBAR)
-    mutt_menu_set_current_redraw(REDRAW_SIDEBAR);
-#endif
-  if (p->flags & R_MENU)
-    mutt_menu_set_current_redraw_full();
-}
-
-/**
- * set_default - Set the default/initial value of a config item
- * @param p Option to set
- */
-static void set_default(struct ConfigDef *p)
-{
-  switch (DTYPE(p->type))
-  {
-    case DT_STRING:
-    case DT_COMMAND:
-      if (!p->initial && *((char **) p->var))
-        p->initial = (unsigned long) mutt_str_strdup(*((char **) p->var));
-      break;
-    case DT_PATH:
-      if (!p->initial && *((char **) p->var))
-      {
-        char *cp = mutt_str_strdup(*((char **) p->var));
-        /* mutt_pretty_mailbox (cp); */
-        p->initial = (unsigned long) cp;
-      }
-      break;
-    case DT_ADDRESS:
-      if (!p->initial && *((struct Address **) p->var))
-      {
-        char tmp[HUGE_STRING];
-        *tmp = '\0';
-        mutt_addr_write(tmp, sizeof(tmp), *((struct Address **) p->var), false);
-        p->initial = (unsigned long) mutt_str_strdup(tmp);
-      }
-      break;
-    case DT_REGEX:
-    {
-      struct Regex **ptr = (struct Regex **) p->var;
-      if (!p->initial && *ptr && (*ptr)->pattern)
-        p->initial = (unsigned long) mutt_str_strdup((*ptr)->pattern);
-      break;
-    }
-  }
-}
-
 /**
  * source_rc - Read an initialization file
  * @param rcfile_path Path to initialization file
@@ -1341,32 +926,6 @@ static int source_rc(const char *rcfile_path, struct Buffer *err)
   return rc;
 }
 
-/**
- * toggle_quadoption - Toggle the value of a quad-type
- * @param opt Option to toggle
- * @retval num New value
- *
- * Toggle the low bit:
- * MUTT_NO    <--> MUTT_YES
- * MUTT_ASKNO <--> MUTT_ASKYES
- */
-static int toggle_quadoption(int opt)
-{
-  return opt ^= 1;
-}
-
-/**
- * valid_show_multipart_alternative - Is a string a valid multipart descriptor?
- * @param val String to test
- * @retval true It is value
- */
-static bool valid_show_multipart_alternative(const char *val)
-{
-  return (mutt_str_strcmp(val, "inline") == 0) ||
-         (mutt_str_strcmp(val, "info")   == 0) ||
-         !val || (*val == 0);
-}
-
 /**
  * parse_alias - Parse the 'alias' command
  * @param buf  Temporary Buffer space
@@ -1974,627 +1533,295 @@ static int parse_path_unlist(struct Buffer *buf, struct Buffer *s,
 static int parse_set(struct Buffer *buf, struct Buffer *s, unsigned long data,
                      struct Buffer *err)
 {
-  int r = 0;
+  /* The order must match `enum MuttSetCommand` */
+  static const char *set_commands[] = { "set", "toggle", "unset", "reset" };
+
+  int rc = 0;
 
   while (MoreArgs(s))
   {
-    int query = 0;
-    int unset = (data == MUTT_SET_UNSET);
-    int inv = (data == MUTT_SET_INV);
-    int reset = (data == MUTT_SET_RESET);
-    int idx = -1;
-    const char *p = NULL;
-    const char *myvar = NULL;
+    bool prefix = false;
+    bool query = false;
+    bool inv = (data == MUTT_SET_INV);
+    bool reset = (data == MUTT_SET_RESET);
+    bool unset = (data == MUTT_SET_UNSET);
 
     if (*s->dptr == '?')
     {
-      query = 1;
+      prefix = true;
+      query = true;
       s->dptr++;
     }
     else if (mutt_str_strncmp("no", s->dptr, 2) == 0)
     {
-      s->dptr += 2;
+      prefix = true;
       unset = !unset;
+      s->dptr += 2;
     }
     else if (mutt_str_strncmp("inv", s->dptr, 3) == 0)
     {
-      s->dptr += 3;
+      prefix = true;
       inv = !inv;
+      s->dptr += 3;
     }
     else if (*s->dptr == '&')
     {
-      reset = 1;
+      prefix = true;
+      reset = true;
       s->dptr++;
     }
 
-    /* get the variable name */
-    mutt_extract_token(buf, s, MUTT_TOKEN_EQUAL);
-
-    mutt_buffer_reset(err);
-    if (mutt_str_strncmp("my_", buf->data, 3) == 0)
-      myvar = buf->data;
-    else if ((idx = mutt_option_index(buf->data)) == -1 &&
-             !(reset && (mutt_str_strcmp("all", buf->data) == 0)))
+    if (prefix && (data != MUTT_SET_SET))
     {
-      mutt_buffer_printf(err, _("%s: unknown variable"), buf->data);
+      mutt_buffer_printf(err, "ERR22 cannot use 'inv', 'no', '&' or '?' with the '%s' command",
+                         set_commands[data]);
       return -1;
     }
-    SKIPWS(s->dptr);
-
-    if (reset)
-    {
-      if (query || unset || inv)
-      {
-        mutt_buffer_printf(err, "%s", _("prefix is illegal with reset"));
-        return -1;
-      }
 
-      if (*s->dptr == '=')
-      {
-        mutt_buffer_printf(err, "%s", _("value is illegal with reset"));
-        return -1;
-      }
-
-      if (mutt_str_strcmp("all", buf->data) == 0)
-      {
-        if (CurrentMenu == MENU_PAGER)
-        {
-          mutt_buffer_printf(err, "%s", _("Not available in this menu."));
-          return -1;
-        }
-        for (idx = 0; MuttVars[idx].name; idx++)
-          restore_default(&MuttVars[idx]);
-        mutt_menu_set_current_redraw_full();
-        OptSortSubthreads = true;
-        OptNeedResort = true;
-        OptResortInit = true;
-        OptRedrawTree = true;
-        return 0;
-      }
-      else
-      {
-        CHECK_PAGER;
-        if (myvar)
-          myvar_del(myvar);
-        else
-          restore_default(&MuttVars[idx]);
-      }
-    }
-    else if (!myvar && (idx >= 0) && (DTYPE(MuttVars[idx].type) == DT_BOOL))
-    {
-      if (*s->dptr == '=')
-      {
-        if (unset || inv || query)
-        {
-          mutt_buffer_printf(err, "%s", _("Usage: set variable=yes|no"));
-          return -1;
-        }
+    /* get the variable name */
+    mutt_extract_token(buf, s, MUTT_TOKEN_EQUAL | MUTT_TOKEN_QUESTION);
 
-        s->dptr++;
-        mutt_extract_token(buf, s, MUTT_TOKEN_BACKTICK_VARS);
-        if (mutt_str_strcasecmp("yes", buf->data) == 0)
-          unset = inv = 0;
-        else if (mutt_str_strcasecmp("no", buf->data) == 0)
-          unset = 1;
-        else
-        {
-          mutt_buffer_printf(err, "%s", _("Usage: set variable=yes|no"));
-          return -1;
-        }
-      }
+    bool bq = false;
+    bool equals = false;
 
-      if (query)
-      {
-        mutt_buffer_printf(err, *(bool *) MuttVars[idx].var ? _("%s is set") : _("%s is unset"),
-                           buf->data);
-        return 0;
-      }
-
-      CHECK_PAGER;
-      if (unset)
-        *(bool *) MuttVars[idx].var = false;
-      else if (inv)
-        *(bool *) MuttVars[idx].var = !(*(bool *) MuttVars[idx].var);
-      else
-        *(bool *) MuttVars[idx].var = true;
-    }
-    else if (myvar || ((idx >= 0) && ((DTYPE(MuttVars[idx].type) == DT_STRING) ||
-                                      (DTYPE(MuttVars[idx].type) == DT_PATH) ||
-                                      (DTYPE(MuttVars[idx].type) == DT_COMMAND) ||
-                                      (DTYPE(MuttVars[idx].type) == DT_ADDRESS) ||
-                                      (DTYPE(MuttVars[idx].type) == DT_MBTABLE))))
+    struct HashElem *he = NULL;
+    bool my = (mutt_str_strncmp("my_", buf->data, 3) == 0);
+    if (!my)
     {
-      if (unset)
-      {
-        CHECK_PAGER;
-        if (myvar)
-          myvar_del(myvar);
-        else if (DTYPE(MuttVars[idx].type) == DT_ADDRESS)
-          mutt_addr_free((struct Address **) MuttVars[idx].var);
-        else if (DTYPE(MuttVars[idx].type) == DT_MBTABLE)
-          free_mbtable((struct MbTable **) MuttVars[idx].var);
-        else
-        {
-          FREE((void *) MuttVars[idx].var);
-        }
-      }
-      else if (query || *s->dptr != '=')
-      {
-        char tmp2[LONG_STRING];
-        const char *val = NULL;
-
-        if (myvar)
-        {
-          val = myvar_get(myvar);
-          if (val)
-          {
-            pretty_var2(err->data, err->dsize, myvar, val);
-            break;
-          }
-          else
-          {
-            mutt_buffer_printf(err, _("%s: unknown variable"), myvar);
-            return -1;
-          }
-        }
-        else if (DTYPE(MuttVars[idx].type) == DT_ADDRESS)
-        {
-          tmp2[0] = '\0';
-          mutt_addr_write(tmp2, sizeof(tmp2),
-                          *((struct Address **) MuttVars[idx].var), false);
-          val = tmp2;
-        }
-        else if (DTYPE(MuttVars[idx].type) == DT_PATH)
-        {
-          tmp2[0] = '\0';
-          mutt_str_strfcpy(tmp2, NONULL(*((char **) MuttVars[idx].var)), sizeof(tmp2));
-          mutt_pretty_mailbox(tmp2, sizeof(tmp2));
-          val = tmp2;
-        }
-        else if (DTYPE(MuttVars[idx].type) == DT_MBTABLE)
-        {
-          struct MbTable *mbt = (*((struct MbTable **) MuttVars[idx].var));
-          val = mbt ? NONULL(mbt->orig_str) : "";
-        }
-        else
-          val = *((char **) MuttVars[idx].var);
-
-        /* user requested the value of this variable */
-        pretty_var2(err->data, err->dsize, MuttVars[idx].name, NONULL(val));
-        break;
-      }
-      else
+      he = cs_get_elem(Config, buf->data);
+      if (!he)
       {
-        CHECK_PAGER;
-        s->dptr++;
-
-        if (myvar)
-        {
-          /* myvar is a pointer to buf and will be lost on extract_token */
-          myvar = mutt_str_strdup(myvar);
-        }
-
-        mutt_extract_token(buf, s, MUTT_TOKEN_BACKTICK_VARS);
-
-        if (myvar)
-        {
-          myvar_set(myvar, buf->data);
-          FREE(&myvar);
-          myvar = "don't resort";
-        }
-        else if ((idx >= 0) && (DTYPE(MuttVars[idx].type) == DT_PATH))
+        if (reset && (mutt_str_strcmp(buf->data, "all") == 0))
         {
-          char scratch[PATH_MAX];
-          mutt_str_strfcpy(scratch, buf->data, sizeof(scratch));
-          mutt_expand_path(scratch, sizeof(scratch));
-
-          size_t scratchlen = mutt_str_strlen(scratch);
-          if (scratchlen != 0)
-          {
-            if ((scratch[scratchlen - 1] != '|') &&       /* not a command */
-                (url_check_scheme(scratch) == U_UNKNOWN)) /* probably a local file */
-            {
-              struct ListNode *np = STAILQ_FIRST(&MuttrcStack);
-              if (!mutt_file_to_absolute_path(scratch, np ? NONULL(np->data) : "./"))
-              {
-                mutt_error(_("Error: impossible to build path of '%s'."), scratch);
-              }
-            }
-          }
-
-          if (mutt_str_strcmp(MuttVars[idx].name, "debug_file") == 0)
-          {
-            mutt_log_set_file(scratch, true);
-          }
-          else
-          {
-            FREE((void *) MuttVars[idx].var);
-            *((char **) MuttVars[idx].var) = mutt_str_strdup(scratch);
-          }
-        }
-        else if ((idx >= 0) && ((DTYPE(MuttVars[idx].type) == DT_STRING) ||
-                                (DTYPE(MuttVars[idx].type) == DT_COMMAND)))
-        {
-          if ((strstr(MuttVars[idx].name, "charset") &&
-               check_charset(&MuttVars[idx], buf->data) < 0) |
-              /* $charset can't be empty, others can */
-              ((strcmp(MuttVars[idx].name, "charset") == 0) && !*buf->data))
-          {
-            mutt_buffer_printf(err, _("Invalid value for option %s: \"%s\""),
-                               MuttVars[idx].name, buf->data);
+          struct HashElem **list = get_elem_list(Config);
+          if (!list)
             return -1;
-          }
 
-          FREE((void *) MuttVars[idx].var);
-          *((char **) MuttVars[idx].var) = mutt_str_strdup(buf->data);
-          if (mutt_str_strcmp(MuttVars[idx].name, "charset") == 0)
-            mutt_ch_set_charset(Charset);
+          for (size_t i = 0; list[i]; i++)
+            cs_he_reset(Config, list[i], NULL);
 
-          if ((mutt_str_strcmp(MuttVars[idx].name,
-                               "show_multipart_alternative") == 0) &&
-              !valid_show_multipart_alternative(buf->data))
-          {
-            mutt_buffer_printf(err, _("Invalid value for name %s: \"%s\""),
-                               MuttVars[idx].name, buf->data);
-            return -1;
-          }
-        }
-        else if (DTYPE(MuttVars[idx].type) == DT_MBTABLE)
-        {
-          free_mbtable((struct MbTable **) MuttVars[idx].var);
-          *((struct MbTable **) MuttVars[idx].var) = parse_mbtable(buf->data);
+          FREE(&list);
+          break;
         }
         else
         {
-          mutt_addr_free((struct Address **) MuttVars[idx].var);
-          *((struct Address **) MuttVars[idx].var) =
-              mutt_addr_parse_list(NULL, buf->data);
+          mutt_buffer_printf(err, "ERR01 unknown variable: %s", buf->data);
+          return -1;
         }
       }
+
+      bq = ((DTYPE(he->type) == DT_BOOL) || (DTYPE(he->type) == DT_QUAD));
     }
-    else if ((idx >= 0) && (DTYPE(MuttVars[idx].type) == DT_REGEX))
+
+    if (*s->dptr == '?')
     {
-      if (query || *s->dptr != '=')
+      if (prefix)
       {
-        /* user requested the value of this variable */
-        struct Regex *ptr = *(struct Regex **) MuttVars[idx].var;
-        const char *value = ptr ? ptr->pattern : NULL;
-        pretty_var2(err->data, err->dsize, MuttVars[idx].name, NONULL(value));
-        break;
+        mutt_buffer_printf(
+            err, "ERR02 cannot use a prefix when querying a variable");
+        return -1;
       }
 
-      if (OptAttachMsg && (mutt_str_strcmp(MuttVars[idx].name, "reply_regex") == 0))
+      if (reset || unset || inv)
       {
-        mutt_buffer_printf(
-            err, "Operation not permitted when in attach-message mode.");
-        r = -1;
-        break;
+        mutt_buffer_printf(err, "ERR03 cannot query a variable with the '%s' command",
+                           set_commands[data]);
+        return -1;
       }
 
-      CHECK_PAGER;
+      query = true;
       s->dptr++;
-
-      /* copy the value of the string */
-      mutt_extract_token(buf, s, MUTT_TOKEN_BACKTICK_VARS);
-
-      if (parse_regex(idx, buf, err))
-      {
-        /* $reply_regex and $alternates require special treatment */
-        if (Context && Context->msgcount &&
-            (mutt_str_strcmp(MuttVars[idx].name, "reply_regex") == 0))
-        {
-          regmatch_t pmatch[1];
-
-          for (int i = 0; i < Context->msgcount; i++)
-          {
-            struct Envelope *e = Context->hdrs[i]->env;
-            if (e && e->subject)
-            {
-              e->real_subj = (ReplyRegex && ReplyRegex->regex &&
-                              (regexec(ReplyRegex->regex, e->subject, 1, pmatch, 0))) ?
-                                 e->subject :
-                                 e->subject + pmatch[0].rm_eo;
-            }
-          }
-        }
-      }
     }
-    else if ((idx >= 0) && (DTYPE(MuttVars[idx].type) == DT_MAGIC))
+    else if (*s->dptr == '=')
     {
-      if (query || *s->dptr != '=')
+      if (prefix)
       {
-        switch (MboxType)
-        {
-          case MUTT_MBOX:
-            p = "mbox";
-            break;
-          case MUTT_MMDF:
-            p = "MMDF";
-            break;
-          case MUTT_MH:
-            p = "MH";
-            break;
-          case MUTT_MAILDIR:
-            p = "Maildir";
-            break;
-          default:
-            p = "unknown";
-            break;
-        }
-        mutt_buffer_printf(err, "%s=%s", MuttVars[idx].name, p);
-        break;
-      }
-
-      CHECK_PAGER;
-      s->dptr++;
-
-      /* copy the value of the string */
-      mutt_extract_token(buf, s, MUTT_TOKEN_BACKTICK_VARS);
-      if (mx_set_magic(buf->data))
-      {
-        mutt_buffer_printf(err, _("%s: invalid mailbox type"), buf->data);
-        r = -1;
-        break;
+        mutt_buffer_printf(err,
+                           "ERR04 cannot use prefix when setting a variable");
+        return -1;
       }
-    }
-    else if ((idx >= 0) && (DTYPE(MuttVars[idx].type) == DT_NUMBER))
-    {
-      short *ptr = (short *) MuttVars[idx].var;
-      short val;
-      int rc;
 
-      if (query || *s->dptr != '=')
+      if (reset || unset || inv)
       {
-        val = *ptr;
-        /* compatibility alias */
-        if (mutt_str_strcmp(MuttVars[idx].name, "wrapmargin") == 0)
-          val = *ptr < 0 ? -*ptr : 0;
-
-        /* user requested the value of this variable */
-        mutt_buffer_printf(err, "%s=%d", MuttVars[idx].name, val);
-        break;
+        mutt_buffer_printf(err, "ERR05 cannot set a variable with the '%s' command",
+                           set_commands[data]);
+        return -1;
       }
 
-      CHECK_PAGER;
+      equals = true;
       s->dptr++;
+    }
 
-      mutt_extract_token(buf, s, MUTT_TOKEN_BACKTICK_VARS);
-      rc = mutt_str_atos(buf->data, (short *) &val);
-
-      if (rc < 0 || !*buf->data)
-      {
-        mutt_buffer_printf(err, _("%s: invalid value (%s)"), buf->data,
-                           (rc == -1) ? _("format error") : _("number overflow"));
-        r = -1;
-        break;
-      }
-
-      if (mutt_str_strcmp(MuttVars[idx].name, "debug_level") == 0)
-        mutt_log_set_level(val, true);
+    if (!bq && (inv || unset))
+    {
+      if (data == MUTT_SET_SET)
+        mutt_buffer_printf(err, "ERR06 prefixes 'no' and 'inv' may only be "
+                                "used with bool/quad variables");
       else
-        *ptr = val;
-
-      /* these ones need a sanity check */
-      if (mutt_str_strcmp(MuttVars[idx].name, "history") == 0)
-      {
-        if (*ptr < 0)
-          *ptr = 0;
-        mutt_hist_init();
-      }
-      else if (mutt_str_strcmp(MuttVars[idx].name, "pager_index_lines") == 0)
-      {
-        if (*ptr < 0)
-          *ptr = 0;
-      }
-      else if (mutt_str_strcmp(MuttVars[idx].name, "wrapmargin") == 0)
-      {
-        if (*ptr < 0)
-          *ptr = 0;
-        else
-          *ptr = -*ptr;
-      }
-#ifdef USE_IMAP
-      else if (mutt_str_strcmp(MuttVars[idx].name, "imap_pipeline_depth") == 0)
-      {
-        if (*ptr < 0)
-          *ptr = 0;
-      }
-#endif
+        mutt_buffer_printf(err, "ERR07 command '%s' can only be used with bool/quad variables",
+                           set_commands[data]);
+      return -1;
     }
-    else if (DTYPE(MuttVars[idx].type) == DT_LONG)
-    {
-      long *ptr = (long *) MuttVars[idx].var;
-      long val;
 
-      if (query || *s->dptr != '=')
+    if (reset)
+    {
+      // mutt_buffer_printf(err, "ACT24 reset variable %s", buf->data);
+      if (he)
       {
-        val = *ptr;
-
-        /* user requested the value of this variable */
-        snprintf(err->data, err->dsize, "%s=%ld", MuttVars[idx].name, val);
-        break;
+        rc = cs_he_reset(Config, he, err);
+        if (CSR_RESULT(rc) != CSR_SUCCESS)
+          return -1;
       }
-
-      CHECK_PAGER;
-      s->dptr++;
-
-      mutt_extract_token(buf, s, 0);
-      int rc = mutt_str_atol(buf->data, (long *) &val);
-
-      if (rc < 0 || !*buf->data)
+      else
       {
-        snprintf(err->data, err->dsize, _("%s: invalid value (%s)"), buf->data,
-                 rc == -1 ? _("format error") : _("number overflow"));
-        r = -1;
-        break;
+        myvar_del(buf->data);
       }
-      else
-        *ptr = val;
+      continue;
     }
-    else if ((idx >= 0) && (DTYPE(MuttVars[idx].type) == DT_QUAD))
+
+    if ((data == MUTT_SET_SET) && !inv && !unset)
     {
       if (query)
       {
-        static const char *const vals[] = { "no", "yes", "ask-no", "ask-yes" };
-
-        mutt_buffer_printf(err, "%s=%s", MuttVars[idx].name,
-                           vals[*(unsigned char *) MuttVars[idx].var]);
-        break;
-      }
-
-      CHECK_PAGER;
-      if (*s->dptr == '=')
-      {
-        s->dptr++;
-        mutt_extract_token(buf, s, MUTT_TOKEN_BACKTICK_VARS);
-        if (mutt_str_strcasecmp("yes", buf->data) == 0)
-          *(unsigned char *) MuttVars[idx].var = MUTT_YES;
-        else if (mutt_str_strcasecmp("no", buf->data) == 0)
-          *(unsigned char *) MuttVars[idx].var = MUTT_NO;
-        else if (mutt_str_strcasecmp("ask-yes", buf->data) == 0)
-          *(unsigned char *) MuttVars[idx].var = MUTT_ASKYES;
-        else if (mutt_str_strcasecmp("ask-no", buf->data) == 0)
-          *(unsigned char *) MuttVars[idx].var = MUTT_ASKNO;
+        // mutt_buffer_printf(err, "ACT08 query variable %s", buf->data);
+        if (he)
+        {
+          mutt_buffer_addstr(err, buf->data);
+          mutt_buffer_addch(err, '=');
+          mutt_buffer_reset(buf);
+          rc = cs_he_string_get(Config, he, buf);
+          if (CSR_RESULT(rc) != CSR_SUCCESS)
+          {
+            mutt_buffer_addstr(err, buf->data);
+            return -1;
+          }
+          pretty_var(buf->data, err);
+        }
         else
         {
-          mutt_buffer_printf(err, _("%s: invalid value"), buf->data);
-          r = -1;
-          break;
+          const char *val = myvar_get(buf->data);
+          if (val)
+          {
+            mutt_buffer_addstr(err, buf->data);
+            mutt_buffer_addch(err, '=');
+            pretty_var(val, err);
+          }
+          else
+          {
+            mutt_buffer_printf(err, _("%s: unknown variable"), buf->data);
+            return -1;
+          }
         }
+        break;
       }
-      else
+      else if (equals)
       {
-        if (inv)
+        // mutt_buffer_printf(err, "ACT11 set variable %s to ", buf->data);
+        const char *name = NULL;
+        if (my)
+        {
+          name = mutt_str_strdup(buf->data);
+        }
+        mutt_extract_token(buf, s, MUTT_TOKEN_BACKTICK_VARS);
+        if (my)
         {
-          *(unsigned char *) MuttVars[idx].var =
-              toggle_quadoption(*(unsigned char *) MuttVars[idx].var);
+          myvar_set(name, buf->data);
+          FREE(&name);
         }
-        else if (unset)
-          *(unsigned char *) MuttVars[idx].var = MUTT_NO;
         else
-          *(unsigned char *) MuttVars[idx].var = MUTT_YES;
-      }
-    }
-    else if ((idx >= 0) && (DTYPE(MuttVars[idx].type) == DT_SORT))
-    {
-      const struct Mapping *map = NULL;
-
-      switch (MuttVars[idx].type & DT_SUBTYPE_MASK)
-      {
-        case DT_SORT_ALIAS:
-          map = SortAliasMethods;
-          break;
-        case DT_SORT_AUX:
-          map = SortAuxMethods;
-          break;
-        case DT_SORT_BROWSER:
-          map = SortBrowserMethods;
-          break;
-        case DT_SORT_KEYS:
-          if (WithCrypto & APPLICATION_PGP)
-            map = SortKeyMethods;
-          break;
-        case DT_SORT_SIDEBAR:
-          map = SortSidebarMethods;
-          break;
-        default:
-          map = SortMethods;
-          break;
-      }
-
-      if (!map)
-      {
-        mutt_buffer_printf(err, _("%s: Unknown type."), MuttVars[idx].name);
-        r = -1;
-        break;
-      }
-
-      if (query || *s->dptr != '=')
-      {
-        p = mutt_map_get_name(*((short *) MuttVars[idx].var) & SORT_MASK, map);
-
-        mutt_buffer_printf(
-            err, "%s=%s%s%s", MuttVars[idx].name,
-            (*((short *) MuttVars[idx].var) & SORT_REVERSE) ? "reverse-" : "",
-            (*((short *) MuttVars[idx].var) & SORT_LAST) ? "last-" : "", p);
-        return 0;
-      }
-      CHECK_PAGER;
-      s->dptr++;
-      mutt_extract_token(buf, s, MUTT_TOKEN_BACKTICK_VARS);
-
-      if (parse_sort((short *) MuttVars[idx].var, buf->data, map, err) == -1)
-      {
-        r = -1;
-        break;
-      }
-    }
-#ifdef USE_HCACHE
-    else if ((idx >= 0) && (DTYPE(MuttVars[idx].type) == DT_HCACHE))
-    {
-      if (query || (*s->dptr != '='))
-      {
-        pretty_var2(err->data, err->dsize, MuttVars[idx].name,
-                    NONULL((*(char **) MuttVars[idx].var)));
-        break;
-      }
-
-      CHECK_PAGER;
-      s->dptr++;
+        {
+          if (DTYPE(he->type) == DT_PATH)
+          {
+            mutt_expand_path(buf->data, buf->dsize);
+            char scratch[PATH_MAX];
+            size_t scratchlen = mutt_str_strlen(scratch);
+            if (scratchlen != 0)
+            {
+              if ((scratch[scratchlen - 1] != '|') &&       /* not a command */
+                  (url_check_scheme(scratch) == U_UNKNOWN)) /* probably a local file */
+              {
+                struct ListNode *np = STAILQ_FIRST(&MuttrcStack);
+                if (!mutt_file_to_absolute_path(scratch, np ? NONULL(np->data) : "./"))
+                {
+                  mutt_error(_("Error: impossible to build path of '%s'."), scratch);
+                }
+              }
+            }
 
-      /* copy the value of the string */
-      mutt_extract_token(buf, s, MUTT_TOKEN_BACKTICK_VARS);
-      if (mutt_hcache_is_valid_backend(buf->data))
-      {
-        FREE((void *) MuttVars[idx].var);
-        *(char **) (MuttVars[idx].var) = mutt_str_strdup(buf->data);
+          }
+          rc = cs_he_string_set(Config, he, buf->data, err);
+          if (CSR_RESULT(rc) != CSR_SUCCESS)
+            return -1;
+        }
+        continue;
       }
       else
       {
-        mutt_buffer_printf(err, _("%s: invalid backend"), buf->data);
-        r = -1;
-        break;
+        if (bq)
+        {
+          // mutt_buffer_printf(err, "ACT23 set variable %s to 'yes'", buf->data);
+          rc = cs_he_native_set(Config, he, true, err);
+          if (CSR_RESULT(rc) != CSR_SUCCESS)
+            return -1;
+          continue;
+        }
+        else
+        {
+          // mutt_buffer_printf(err, "ACT10 query variable %s", buf->data);
+          if (he)
+          {
+            mutt_buffer_addstr(err, buf->data);
+            mutt_buffer_addch(err, '=');
+            mutt_buffer_reset(buf);
+            rc = cs_he_string_get(Config, he, buf);
+            if (CSR_RESULT(rc) != CSR_SUCCESS)
+            {
+              mutt_buffer_addstr(err, buf->data);
+              return -1;
+            }
+            pretty_var(buf->data, err);
+          }
+          else
+          {
+            const char *val = myvar_get(buf->data);
+            if (val)
+            {
+              mutt_buffer_addstr(err, buf->data);
+              mutt_buffer_addch(err, '=');
+              pretty_var(val, err);
+            }
+            else
+            {
+              mutt_buffer_printf(err, _("%s: unknown variable"), buf->data);
+              return -1;
+            }
+          }
+          break;
+        }
       }
     }
-#endif
-    else
-    {
-      mutt_buffer_printf(err, _("%s: unknown type"),
-                         (idx >= 0) ? MuttVars[idx].name : "unknown");
-      r = -1;
-      break;
-    }
 
-    if (!myvar)
+    if (bq)
     {
-      if (MuttVars[idx].flags & R_INDEX)
-        mutt_menu_set_redraw_full(MENU_MAIN);
-      if (MuttVars[idx].flags & R_PAGER)
-        mutt_menu_set_redraw_full(MENU_PAGER);
-      if (MuttVars[idx].flags & R_PAGER_FLOW)
+      if (inv)
+      {
+        // mutt_buffer_printf(err, "ACT25 TOGGLE bool/quad variable %s", buf->data);
+        if (DTYPE(he->type) == DT_BOOL)
+          bool_he_toggle(Config, he, err);
+        else
+          quad_he_toggle(Config, he, err);
+      }
+      else
       {
-        mutt_menu_set_redraw_full(MENU_PAGER);
-        mutt_menu_set_redraw(MENU_PAGER, REDRAW_FLOW);
+        // mutt_buffer_printf(err, "ACT26 UNSET bool/quad variable %s", buf->data);
+        rc = cs_he_native_set(Config, he, false, err);
+        if (CSR_RESULT(rc) != CSR_SUCCESS)
+          return -1;
       }
-      if (MuttVars[idx].flags & R_RESORT_SUB)
-        OptSortSubthreads = true;
-      if (MuttVars[idx].flags & R_RESORT)
-        OptNeedResort = true;
-      if (MuttVars[idx].flags & R_RESORT_INIT)
-        OptResortInit = true;
-      if (MuttVars[idx].flags & R_TREE)
-        OptRedrawTree = true;
-      if (MuttVars[idx].flags & R_REFLOW)
-        mutt_window_reflow();
-#ifdef USE_SIDEBAR
-      if (MuttVars[idx].flags & R_SIDEBAR)
-        mutt_menu_set_current_redraw(REDRAW_SIDEBAR);
-#endif
-      if (MuttVars[idx].flags & R_MENU)
-        mutt_menu_set_current_redraw_full();
     }
   }
-  return r;
+
+  return 0;
 }
 
 /**
@@ -3501,6 +2728,7 @@ int mutt_extract_token(struct Buffer *dest, struct Buffer *tok, int flags)
       if ((ISSPACE(ch) && !(flags & MUTT_TOKEN_SPACE)) ||
           (ch == '#' && !(flags & MUTT_TOKEN_COMMENT)) ||
           (ch == '=' && (flags & MUTT_TOKEN_EQUAL)) ||
+          (ch == '?' && (flags & MUTT_TOKEN_QUESTION)) ||
           (ch == ';' && !(flags & MUTT_TOKEN_SEMICOLON)) ||
           ((flags & MUTT_TOKEN_PATTERN) && strchr("~%=!|", ch)))
       {
@@ -3685,18 +2913,18 @@ int mutt_extract_token(struct Buffer *dest, struct Buffer *tok, int flags)
       }
       if (var)
       {
-        int idx;
-        if ((env = myvar_get(var)))
+        struct Buffer result;
+        mutt_buffer_init(&result);
+        int rc = cs_str_string_get(Config, var, &result);
+
+        if (CSR_RESULT(rc) == CSR_SUCCESS)
         {
-          mutt_buffer_addstr(dest, env);
+          mutt_buffer_addstr(dest, result.data);
+          FREE(&result.data);
         }
-        else if ((idx = mutt_option_index(var)) != -1)
+        else if ((env = myvar_get(var)))
         {
-          /* expand settable neomutt variables */
-          char val[LONG_STRING];
-
-          if (var_to_string(idx, val, sizeof(val)))
-            mutt_buffer_addstr(dest, val);
+          mutt_buffer_addstr(dest, env);
         }
         else if (!(flags & MUTT_TOKEN_NOSHELL) && (env = mutt_str_getenv(var)))
         {
@@ -3740,8 +2968,7 @@ void mutt_free_attachmatch(struct AttachMatch **am)
  */
 void mutt_free_opts(void)
 {
-  for (int i = 0; MuttVars[i].name; i++)
-    free_opt(MuttVars + i);
+  mutt_list_free(&MuttrcStack);
 
   FREE(&Matches);
 
@@ -3796,6 +3023,8 @@ void mutt_free_opts(void)
 
   mutt_hist_free();
   mutt_free_keys();
+
+  mutt_regexlist_free(&NoSpamList);
 }
 
 /**
@@ -3842,20 +3071,21 @@ int mutt_init(bool skip_sys_rc, struct ListHead *commands)
   snprintf(AttachmentMarker, sizeof(AttachmentMarker), "\033]9;%" PRIu64 "\a",
            mutt_rand64());
 
+  /* "$spoolfile" precedence: config file, environment */
   const char *p = mutt_str_getenv("MAIL");
-  if (p)
-    Spoolfile = mutt_str_strdup(p);
-  else if ((p = mutt_str_getenv("MAILDIR")))
-    Spoolfile = mutt_str_strdup(p);
-  else
+  if (!p)
+    p = mutt_str_getenv("MAILDIR");
+  if (!p)
   {
 #ifdef HOMESPOOL
     mutt_file_concat_path(buffer, NONULL(HomeDir), MAILPATH, sizeof(buffer));
 #else
     mutt_file_concat_path(buffer, MAILPATH, NONULL(Username), sizeof(buffer));
 #endif
-    Spoolfile = mutt_str_strdup(buffer);
+    p = buffer;
   }
+  cs_str_initial_set(Config, "spoolfile", p, NULL);
+  cs_str_reset(Config, "spoolfile", NULL);
 
   p = mutt_str_getenv("REPLYTO");
   if (p)
@@ -3869,35 +3099,26 @@ int mutt_init(bool skip_sys_rc, struct ListHead *commands)
     buf.dsize = mutt_str_strlen(buffer);
 
     mutt_buffer_init(&token);
-    parse_my_hdr(&token, &buf, 0, &err);
+    parse_my_hdr(&token, &buf, 0, &err); /* adds to UserHeader */
     FREE(&token.data);
   }
 
   p = mutt_str_getenv("EMAIL");
   if (p)
-    From = mutt_addr_parse_list(NULL, p);
-
-  Charset = mutt_ch_get_langinfo_charset();
-  mutt_ch_set_charset(Charset);
-
-  Matches = mutt_mem_calloc(MatchesListsize, sizeof(char *));
-
-  /* Set standard defaults */
-  for (int i = 0; MuttVars[i].name; i++)
   {
-    set_default(&MuttVars[i]);
-    restore_default(&MuttVars[i]);
+    cs_str_initial_set(Config, "from", p, NULL);
+    cs_str_reset(Config, "from", NULL);
   }
 
   /* "$mailcap_path" precedence: config file, environment, code */
   const char *env_mc = mutt_str_getenv("MAILCAPS");
   if (env_mc)
-    MailcapPath = mutt_str_strdup(env_mc);
+    cs_str_string_set(Config, "mailcap_path", env_mc, NULL);
 
   /* "$tmpdir" precedence: config file, environment, code */
   const char *env_tmp = mutt_str_getenv("TMPDIR");
   if (env_tmp)
-    Tmpdir = mutt_str_strdup(env_tmp);
+    cs_str_string_set(Config, "tmpdir", env_tmp, NULL);
 
   /* "$visual", "$editor" precedence: config file, environment, code */
   const char *env_ed = mutt_str_getenv("VISUAL");
@@ -3905,10 +3126,15 @@ int mutt_init(bool skip_sys_rc, struct ListHead *commands)
     env_ed = mutt_str_getenv("EDITOR");
   if (env_ed)
   {
-    mutt_str_replace(&Editor, env_ed);
-    mutt_str_replace(&Visual, env_ed);
+    cs_str_string_set(Config, "editor", env_ed, NULL);
+    cs_str_string_set(Config, "visual", env_ed, NULL);
   }
 
+  Charset = mutt_ch_get_langinfo_charset();
+  mutt_ch_set_charset(Charset);
+
+  Matches = mutt_mem_calloc(MatchesListsize, sizeof(char *));
+
   CurrentMenu = MENU_MAIN;
 
 #ifdef HAVE_GETSID
@@ -3917,8 +3143,6 @@ int mutt_init(bool skip_sys_rc, struct ListHead *commands)
     Suspend = false;
 #endif
 
-  mutt_hist_init();
-
   /* RFC2368, "4. Unsafe headers"
    * The creator of a mailto URL cannot expect the resolver of a URL to
    * understand more than the "subject" and "body" headers. Clients that
@@ -3969,8 +3193,7 @@ int mutt_init(bool skip_sys_rc, struct ListHead *commands)
 
   if (!STAILQ_EMPTY(&Muttrc))
   {
-    FREE(&AliasFile);
-    AliasFile = mutt_str_strdup(STAILQ_FIRST(&Muttrc)->data);
+    cs_str_string_set(Config, "alias_file", STAILQ_FIRST(&Muttrc)->data, NULL);
   }
 
   /* Process the global rc file if it exists and the user hasn't explicitly
@@ -3996,6 +3219,7 @@ int mutt_init(bool skip_sys_rc, struct ListHead *commands)
 
       snprintf(buffer, sizeof(buffer), "%s/Muttrc", PKGDATADIR);
     } while (0);
+
     if (access(buffer, F_OK) == 0)
     {
       if (source_rc(buffer, &err) != 0)
@@ -4026,6 +3250,17 @@ int mutt_init(bool skip_sys_rc, struct ListHead *commands)
   if (!get_hostname())
     return 1;
 
+  if (!Realname)
+  {
+    struct passwd *pw = getpwuid(getuid());
+    if (pw)
+    {
+      char buf[STRING];
+      Realname = mutt_str_strdup(mutt_gecos_name(buf, sizeof(buf), pw));
+    }
+  }
+  cs_str_initial_set(Config, "realname", Realname, NULL);
+
   if (need_pause && !OptNoCurses)
   {
     log_queue_flush(log_disp_terminal);
@@ -4035,6 +3270,7 @@ int mutt_init(bool skip_sys_rc, struct ListHead *commands)
 
   mutt_file_mkdir(Tmpdir, S_IRWXU);
 
+  mutt_hist_init();
   mutt_hist_read_file();
 
 #ifdef USE_NOTMUCH
@@ -4045,7 +3281,7 @@ int mutt_init(bool skip_sys_rc, struct ListHead *commands)
     {
       if (b->magic == MUTT_NOTMUCH)
       {
-        mutt_str_replace(&Spoolfile, b->path);
+        cs_str_string_set(Config, "spoolfile", b->path, NULL);
         mutt_sb_toggle_virtual();
         break;
       }
@@ -4057,46 +3293,6 @@ int mutt_init(bool skip_sys_rc, struct ListHead *commands)
   return 0;
 }
 
-#ifdef USE_LUA
-/**
- * mutt_option_get - Get the Option for a config string
- * @param[in]  s   Name of the option
- * @param[out] opt Option result
- * @retval true  Success
- * @retval false Error, option doesn't exist
- *
- * @note The caller must not free the Option.
- */
-bool mutt_option_get(const char *s, struct ConfigDef *opt)
-{
-  mutt_debug(2, " * mutt_option_get(%s)\n", s);
-  int idx = mutt_option_index(s);
-  if (idx != -1)
-  {
-    if (opt)
-      *opt = MuttVars[idx];
-    return true;
-  }
-
-  if (mutt_str_strncmp("my_", s, 3) == 0)
-  {
-    const char *mv = myvar_get(s);
-    if (!mv)
-      return false;
-
-    if (opt)
-    {
-      memset(opt, 0, sizeof(*opt));
-      opt->name = s;
-      opt->type = DT_STRING;
-      opt->initial = (intptr_t) mv;
-    }
-    return true;
-  }
-  return false;
-}
-#endif
-
 /**
  * mutt_option_index - Find the index (in rc_vars) of a variable name
  * @param s Variable name to search for
@@ -4117,198 +3313,6 @@ int mutt_option_index(const char *s)
   return -1;
 }
 
-#ifdef USE_LUA
-/**
- * mutt_option_set - Set an Option
- * @param val Option to set
- * @param err Buffer for error messages
- * @retval  0 Success
- * @retval -1 Error
- */
-int mutt_option_set(const struct ConfigDef *val, struct Buffer *err)
-{
-  mutt_debug(2, " * mutt_option_set()\n");
-  int idx = mutt_option_index(val->name);
-  if (idx != -1)
-  {
-    switch (DTYPE(MuttVars[idx].type))
-    {
-      case DT_REGEX:
-      {
-        char err_str[LONG_STRING] = "";
-        struct Buffer err2 = { 0 };
-        err2.data = err_str;
-        err2.dsize = sizeof(err_str);
-
-        struct Buffer tmp = { 0 };
-        tmp.data = (char *) val->var;
-        tmp.dsize = strlen((char *) val->var);
-
-        if (parse_regex(idx, &tmp, &err2))
-        {
-          /* $reply_regex and $alternates require special treatment */
-          if (Context && Context->msgcount &&
-              (mutt_str_strcmp(MuttVars[idx].name, "reply_regex") == 0))
-          {
-            regmatch_t pmatch[1];
-
-            for (int i = 0; i < Context->msgcount; i++)
-            {
-              struct Envelope *e = Context->hdrs[i]->env;
-              if (e && e->subject)
-              {
-                e->real_subj = e->subject;
-                if (ReplyRegex && ReplyRegex->regex &&
-                    (regexec(ReplyRegex->regex, e->subject, 1, pmatch, 0) == 0))
-                {
-                  e->subject += pmatch[0].rm_eo;
-                }
-              }
-            }
-          }
-        }
-        else
-        {
-          mutt_buffer_printf(err, _("%s: Unknown type."), MuttVars[idx].name);
-          return -1;
-        }
-        break;
-      }
-      case DT_SORT:
-      {
-        const struct Mapping *map = NULL;
-
-        switch (MuttVars[idx].type & DT_SUBTYPE_MASK)
-        {
-          case DT_SORT_ALIAS:
-            map = SortAliasMethods;
-            break;
-          case DT_SORT_BROWSER:
-            map = SortBrowserMethods;
-            break;
-          case DT_SORT_KEYS:
-            if (WithCrypto & APPLICATION_PGP)
-              map = SortKeyMethods;
-            break;
-          case DT_SORT_AUX:
-            map = SortAuxMethods;
-            break;
-          case DT_SORT_SIDEBAR:
-            map = SortSidebarMethods;
-            break;
-          default:
-            map = SortMethods;
-            break;
-        }
-
-        if (!map)
-        {
-          mutt_buffer_printf(err, _("%s: Unknown type."), MuttVars[idx].name);
-          return -1;
-        }
-
-        if (parse_sort((short *) MuttVars[idx].var, (const char *) val->var, map, err) == -1)
-        {
-          return -1;
-        }
-      }
-      break;
-      case DT_MBTABLE:
-      {
-        struct MbTable **tbl = (struct MbTable **) MuttVars[idx].var;
-        free_mbtable(tbl);
-        *tbl = parse_mbtable((const char *) val->var);
-      }
-      break;
-      case DT_ADDRESS:
-        mutt_addr_free((struct Address **) MuttVars[idx].var);
-        *((struct Address **) MuttVars[idx].var) =
-            mutt_addr_parse_list(NULL, (const char *) val->var);
-        break;
-      case DT_PATH:
-      {
-        char scratch[LONG_STRING];
-        mutt_str_strfcpy(scratch, NONULL((const char *) val->var), sizeof(scratch));
-        mutt_expand_path(scratch, sizeof(scratch));
-
-        size_t scratchlen = mutt_str_strlen(scratch);
-        if (scratchlen != 0)
-        {
-          if ((scratch[scratchlen - 1] != '|') &&       /* not a command */
-              (url_check_scheme(scratch) == U_UNKNOWN)) /* probably a local file */
-          {
-            struct ListNode *np = STAILQ_FIRST(&MuttrcStack);
-            if (!mutt_file_to_absolute_path(scratch, np ? NONULL(np->data) : "./"))
-            {
-              mutt_error(_("Error: impossible to build path of '%s'."), scratch);
-            }
-          }
-        }
-
-        FREE((void *) MuttVars[idx].var);
-        *((char **) MuttVars[idx].var) = mutt_str_strdup(scratch);
-        break;
-      }
-      case DT_COMMAND:
-      {
-        char scratch[LONG_STRING];
-        mutt_str_strfcpy(scratch, NONULL((const char *) val->var), sizeof(scratch));
-        mutt_expand_path(scratch, sizeof(scratch));
-
-        FREE((void *) MuttVars[idx].var);
-        *((char **) MuttVars[idx].var) = mutt_str_strdup(scratch);
-        break;
-      }
-      case DT_STRING:
-      {
-        FREE((void *) MuttVars[idx].var);
-        *((char **) MuttVars[idx].var) = mutt_str_strdup((char *) val->var);
-      }
-      break;
-      case DT_BOOL:
-        if (val->var)
-          *(bool *) MuttVars[idx].var = true;
-        else
-          *(bool *) MuttVars[idx].var = false;
-        break;
-      case DT_QUAD:
-        *(short *) MuttVars[idx].var = (long) val->var;
-        break;
-      case DT_NUMBER:
-        *(short *) MuttVars[idx].var = (long) val->var;
-        break;
-      default:
-        return -1;
-    }
-  }
-  /* set the string as a myvar if it's one */
-  if (mutt_str_strncmp("my_", val->name, 3) == 0)
-  {
-    myvar_set(val->name, (const char *) val->var);
-  }
-  return 0;
-}
-#endif
-
-#ifdef USE_LUA
-/**
- * mutt_option_to_string - Convert an Option to a string
- * @param opt Option to convert
- * @param val Buffer for the result
- * @param len Length of the buffer
- * @retval 1 Success
- * @retval 0 Error
- */
-int mutt_option_to_string(const struct ConfigDef *opt, char *val, size_t len)
-{
-  mutt_debug(2, " * mutt_option_to_string(%s)\n", NONULL((char *) opt->var));
-  int idx = mutt_option_index((const char *) opt->name);
-  if (idx != -1)
-    return var_to_string(idx, val, len);
-  return 0;
-}
-#endif
-
 /**
  * mutt_parse_rc_line - Parse a line of user config
  * @param line  config line to read
@@ -4380,35 +3384,33 @@ finish:
  */
 int mutt_query_variables(struct ListHead *queries)
 {
-  char command[STRING];
-
-  struct Buffer err, token;
-
-  mutt_buffer_init(&err);
-  mutt_buffer_init(&token);
+  struct Buffer *value = mutt_buffer_alloc(STRING);
+  struct Buffer *err = mutt_buffer_alloc(STRING);
+  int rc = 0;
 
-  err.dsize = STRING;
-  err.data = mutt_mem_malloc(err.dsize);
+  mutt_buffer_init(value);
 
   struct ListNode *np = NULL;
   STAILQ_FOREACH(np, queries, entries)
   {
-    snprintf(command, sizeof(command), "set ?%s\n", np->data);
-    if (mutt_parse_rc_line(command, &token, &err) == -1)
-    {
-      mutt_error("%s", err.data);
-      FREE(&token.data);
-      FREE(&err.data);
+    mutt_buffer_reset(value);
 
-      return 1; // TEST15: neomutt -Q missing
+    if (var_to_string2(np->data, true, value, err) < 0)
+    {
+      mutt_error("%s", err->data);
+      rc = 1;
+      break;
     }
-    mutt_message("%s", err.data);
+
+    printf("set %s=%s\n", np->data, value->data);
+    // dump_config_mutt(Config, he, &value, NULL, 0);
+    // dump_config_neo(Config, he, value, NULL, 0);
   }
 
-  FREE(&token.data);
-  FREE(&err.data);
+  mutt_buffer_free(&value);
+  mutt_buffer_free(&err);
 
-  return 0; // TEST16: neomutt -Q charset
+  return rc; // TEST16: neomutt -Q charset
 }
 
 /**
@@ -4434,22 +3436,6 @@ int query_quadoption(int opt, const char *prompt)
   /* not reached */
 }
 
-/**
- * reset_value - Reset a config item to its default/initial value
- * @param name Name of config item
- */
-void reset_value(const char *name)
-{
-  if (!name)
-    return;
-
-  int idx = mutt_option_index(name);
-  if (idx < 0)
-    return;
-
-  restore_default(&MuttVars[idx]);
-}
-
 /**
  * set_default_value - Set a config item's default/initial value
  * @param name  Name of config item
@@ -4471,119 +3457,40 @@ bool set_default_value(const char *name, intptr_t value)
 }
 
 /**
- * var_to_string - Get a config item's value as a string
- * @param idx Index of config item in MuttVars
- * @param val Buffer for the result
- * @param len Length of the buffer
- * @retval 1 Success
- * @retval 0 Error
+ * var_to_string2 - XXX
  */
-int var_to_string(int idx, char *val, size_t len)
+int var_to_string2(const char *name, bool quote, struct Buffer *result, struct Buffer *err)
 {
-  char tmp[LONG_STRING];
-  static const char *const vals[] = { "no", "yes", "ask-no", "ask-yes" };
-
-  tmp[0] = '\0';
-
-  if ((DTYPE(MuttVars[idx].type) == DT_STRING) || (DTYPE(MuttVars[idx].type) == DT_PATH) ||
-      (DTYPE(MuttVars[idx].type) == DT_COMMAND))
-  {
-    mutt_str_strfcpy(tmp, NONULL(*((char **) MuttVars[idx].var)), sizeof(tmp));
-    if (DTYPE(MuttVars[idx].type) == DT_PATH)
-      mutt_pretty_mailbox(tmp, sizeof(tmp));
-  }
-  else if (DTYPE(MuttVars[idx].type) == DT_REGEX)
-  {
-    struct Regex *r = *(struct Regex **) MuttVars[idx].var;
-    if (r)
-      mutt_str_strfcpy(tmp, NONULL(r->pattern), sizeof(tmp));
-  }
-  else if (DTYPE(MuttVars[idx].type) == DT_MBTABLE)
-  {
-    struct MbTable *mbt = (*((struct MbTable **) MuttVars[idx].var));
-    mutt_str_strfcpy(tmp, mbt ? NONULL(mbt->orig_str) : "", sizeof(tmp));
-  }
-  else if (DTYPE(MuttVars[idx].type) == DT_ADDRESS)
-  {
-    mutt_addr_write(tmp, sizeof(tmp), *((struct Address **) MuttVars[idx].var), false);
-  }
-  else if (DTYPE(MuttVars[idx].type) == DT_QUAD)
-    mutt_str_strfcpy(tmp, vals[*(unsigned char *) MuttVars[idx].var], sizeof(tmp));
-  else if (DTYPE(MuttVars[idx].type) == DT_NUMBER)
-  {
-    short sval = *((short *) MuttVars[idx].var);
+  if (!name || !result)
+    return -1;
 
-    /* avert your eyes, gentle reader */
-    if (mutt_str_strcmp(MuttVars[idx].name, "wrapmargin") == 0)
-      sval = sval > 0 ? 0 : -sval;
+  struct Buffer *value = mutt_buffer_alloc(STRING);
+  int rc = -1;
 
-    snprintf(tmp, sizeof(tmp), "%d", sval);
-  }
-  else if (DTYPE(MuttVars[idx].type) == DT_LONG)
+  struct HashElem *he = cs_get_elem(Config, name);
+  if (!he)
   {
-    long sval = *((long *) MuttVars[idx].var);
-
-    snprintf(tmp, sizeof(tmp), "%ld", sval);
+    mutt_buffer_printf(err, _("%s: unknown variable"), name);
+    goto vts_out;
   }
-  else if (DTYPE(MuttVars[idx].type) == DT_SORT)
-  {
-    const struct Mapping *map = NULL;
-    const char *p = NULL;
 
-    switch (MuttVars[idx].type & DT_SUBTYPE_MASK)
-    {
-      case DT_SORT_ALIAS:
-        map = SortAliasMethods;
-        break;
-      case DT_SORT_BROWSER:
-        map = SortBrowserMethods;
-        break;
-      case DT_SORT_KEYS:
-        if (WithCrypto & APPLICATION_PGP)
-          map = SortKeyMethods;
-        else
-          map = SortMethods;
-        break;
-      default:
-        map = SortMethods;
-        break;
-    }
-    p = mutt_map_get_name(*((short *) MuttVars[idx].var) & SORT_MASK, map);
-    snprintf(tmp, sizeof(tmp), "%s%s%s",
-             (*((short *) MuttVars[idx].var) & SORT_REVERSE) ? "reverse-" : "",
-             (*((short *) MuttVars[idx].var) & SORT_LAST) ? "last-" : "", p);
-  }
-  else if (DTYPE(MuttVars[idx].type) == DT_MAGIC)
+  int grc = cs_he_string_get(Config, he, value);
+  if (CSR_RESULT(grc) != CSR_SUCCESS)
   {
-    char *p = NULL;
-
-    switch (MboxType)
-    {
-      case MUTT_MBOX:
-        p = "mbox";
-        break;
-      case MUTT_MMDF:
-        p = "MMDF";
-        break;
-      case MUTT_MH:
-        p = "MH";
-        break;
-      case MUTT_MAILDIR:
-        p = "Maildir";
-        break;
-      default:
-        p = "unknown";
-    }
-    mutt_str_strfcpy(tmp, p, sizeof(tmp));
+    mutt_buffer_printf(err, _("%s: unknown variable"), name);
+    goto vts_out;
   }
-  else if (DTYPE(MuttVars[idx].type) == DT_BOOL)
-    mutt_str_strfcpy(tmp, *(bool *) MuttVars[idx].var ? "yes" : "no", sizeof(tmp));
-  else
-    return 0;
 
-  escape_string2(val, len - 1, tmp);
+  if (quote)
+    mutt_buffer_addch(result, '"');
+  escape_string(result, value->data);
+  if (quote)
+    mutt_buffer_addch(result, '"');
 
-  return 1;
+  rc = 0;
+vts_out:
+  mutt_buffer_free(&value);
+  return rc;
 }
 
 /**
@@ -5003,8 +3910,6 @@ int mutt_var_value_complete(char *buf, size_t buflen, int pos)
 
   if (mutt_str_strncmp(buf, "set", 3) == 0)
   {
-    int idx;
-    char val[LONG_STRING];
     const char *myvarval = NULL;
     char var[STRING];
     mutt_str_strfcpy(var, pt, sizeof(var));
@@ -5014,22 +3919,69 @@ int mutt_var_value_complete(char *buf, size_t buflen, int pos)
       return 0;
 
     var[vlen - 1] = '\0';
-    idx = mutt_option_index(var);
-    if (idx == -1)
+
+    struct HashElem *he = cs_get_elem(Config, var);
+    if (!he)
     {
       myvarval = myvar_get(var);
       if (myvarval)
       {
-        pretty_var2(pt, buflen - (pt - buf), var, myvarval);
+        struct Buffer *pretty = mutt_buffer_alloc(STRING);
+        pretty_var(myvarval, pretty);
+        snprintf(pt, buflen - (pt - buf), "%s=%s", var, pretty->data);
+        mutt_buffer_free(&pretty);
         return 1;
       }
       return 0; /* no such variable. */
     }
-    else if (var_to_string(idx, val, sizeof(val)))
+    else
     {
-      snprintf(pt, buflen - (pt - buf), "%s=\"%s\"", var, val);
+      struct Buffer *value = mutt_buffer_alloc(STRING);
+      struct Buffer *pretty = mutt_buffer_alloc(STRING);
+      int rc = cs_he_string_get(Config, he, value);
+      if (CSR_RESULT(rc) == CSR_SUCCESS)
+      {
+        pretty_var(value->data, pretty);
+        snprintf(pt, buflen - (pt - buf), "%s=%s", var, pretty->data);
+        mutt_buffer_free(&value);
+        mutt_buffer_free(&pretty);
+        return 0;
+      }
+      mutt_buffer_free(&value);
+      mutt_buffer_free(&pretty);
       return 1;
     }
   }
   return 0;
 }
+
+/**
+ * init_config - Initialise the config system
+ * @retval ptr New Config Set
+ */
+struct ConfigSet *init_config(size_t size)
+{
+  struct ConfigSet *cs = cs_create(size);
+
+  address_init(cs);
+  bool_init(cs);
+  command_init(cs);
+  long_init(cs);
+  magic_init(cs);
+  mbtable_init(cs);
+  number_init(cs);
+  path_init(cs);
+  quad_init(cs);
+  regex_init(cs);
+  sort_init(cs);
+  string_init(cs);
+
+  if (!cs_register_variables(cs, MuttVars, 0))
+  {
+    mutt_error("cs_register_variables() failed");
+    cs_free(&cs);
+    return NULL;
+  }
+
+  return cs;
+}
diff --git a/init.h b/init.h
index 718646496afad664b8b75f03f8dc7b92c6f1afda..a2285ed0d9601eee6220a4a99f6e69815b4729fe 100644 (file)
--- a/init.h
+++ b/init.h
@@ -58,7 +58,6 @@
 #include "mutt_account.h"
 #include "mutt_commands.h"
 #include "mutt_logging.h"
-#include "mutt_options.h"
 #include "mutt_thread.h"
 #include "muttlib.h"
 #include "mx.h"
@@ -91,6 +90,7 @@
 
 // clang-format off
 #ifndef _MAKEDOC
+/* flags to parse_set() */
 enum MuttSetCommand
 {
   MUTT_SET_SET,   /**< default is to set all vars */
@@ -1203,7 +1203,7 @@ struct ConfigDef MuttVars[] = {
   ** Header caching can greatly improve speed when opening POP, IMAP
   ** MH or Maildir folders, see ``$caching'' for details.
   */
-  { "header_cache_backend", DT_HCACHE, R_NONE, &HeaderCacheBackend, 0 },
+  { "header_cache_backend", DT_STRING, R_NONE, &HeaderCacheBackend, 0 },
   /*
   ** .pp
   ** This variable specifies the header cache backend.
@@ -3282,7 +3282,7 @@ struct ConfigDef MuttVars[] = {
   ** process will be put in a temporary file.  If there is some error, you
   ** will be informed as to where to find the output.
   */
-  { "shell", DT_COMMAND, R_NONE, &Shell, 0 },
+  { "shell", DT_COMMAND, R_NONE, &Shell, IP "/bin/sh" },
   /*
   ** .pp
   ** Command to use when spawning a subshell.
index a9225541e58c9c831c167ab6fd3832ad30d221d8..f1a19cdc45d79ea1014461333f1b713ad414c5e1 100644 (file)
--- a/mailbox.h
+++ b/mailbox.h
@@ -91,7 +91,7 @@ int             mx_tags_commit (struct Context *ctx, struct Header *hdr, char *t
 void mx_fastclose_mailbox(struct Context *ctx);
 
 int mx_get_magic(const char *path);
-int mx_set_magic(const char *s);
+int mx_check_mailbox(struct Context *ctx, int *index_hint);
 #ifdef USE_IMAP
 bool mx_is_imap(const char *p);
 #endif
diff --git a/main.c b/main.c
index f6eba298260019311d42cf66308f390b7ad2ae54..91e64f2f6e707cf27a8ef5914c476b6fe930db44 100644 (file)
--- a/main.c
+++ b/main.c
@@ -93,6 +93,33 @@ bool ResumeEditedDraftFiles;
 #define MUTT_NEWS (1 << 5) /* -g and -G */
 #endif
 
+/**
+ * reset_tilde - Temporary measure
+ */
+static void reset_tilde(struct ConfigSet *cs)
+{
+  static const char *names[] = {
+    "alias_file", "certificate_file", "debug_file",
+    "folder",     "history_file",     "mbox",
+    "newsrc",     "news_cache_dir",   "postponed",
+    "record",     "signature",
+  };
+
+  struct Buffer *value = mutt_buffer_alloc(STRING);
+  for (size_t i = 0; i < mutt_array_size(names); i++)
+  {
+    struct HashElem *he = cs_get_elem(cs, names[i]);
+    if (!he)
+      continue;
+    mutt_buffer_reset(value);
+    cs_he_initial_get(cs, he, value);
+    mutt_expand_path(value->data, value->dsize);
+    cs_he_initial_set(cs, he, value->data, NULL);
+    cs_he_reset(cs, he, NULL);
+  }
+  mutt_buffer_free(&value);
+}
+
 /**
  * mutt_exit - Leave NeoMutt NOW
  * @param code Value to return to the calling environment
@@ -215,7 +242,10 @@ static int start_curses(void)
   meta(stdscr, true);
 #endif
   init_extended_keys();
-  mutt_window_reflow();
+  /* Now that curses is set up, we drop back to normal screen mode.
+   * This simplifies displaying error messages to the user.
+   * The first call to refresh() will swap us back to curses screen mode. */
+  endwin();
   return 0;
 }
 
@@ -247,16 +277,19 @@ static void init_locale(void)
 
 /**
  * get_user_info - Find the user's name, home and shell
- * @retval 0 Success
- * @retval 1 Error
+ * @param cs Config Set
+ * @retval true Success
  *
  * Find the login name, real name, home directory and shell.
  */
-static int get_user_info(void)
+bool get_user_info(struct ConfigSet *cs)
 {
-  Username = mutt_str_strdup(mutt_str_getenv("USER"));
-  HomeDir = mutt_str_strdup(mutt_str_getenv("HOME"));
-  Shell = mutt_str_strdup(mutt_str_getenv("SHELL"));
+  mutt_str_replace(&Username, mutt_str_getenv("USER"));
+  mutt_str_replace(&HomeDir, mutt_str_getenv("HOME"));
+
+  const char *shell = mutt_str_getenv("SHELL");
+  if (shell)
+    cs_str_initial_set(cs, "shell", shell, NULL);
 
   /* Get some information about the user */
   struct passwd *pw = getpwuid(getuid());
@@ -266,30 +299,24 @@ static int get_user_info(void)
       Username = mutt_str_strdup(pw->pw_name);
     if (!HomeDir)
       HomeDir = mutt_str_strdup(pw->pw_dir);
-    if (!Shell)
-      Shell = mutt_str_strdup(pw->pw_shell);
-
-    char rnbuf[STRING];
-    Realname = mutt_str_strdup(mutt_gecos_name(rnbuf, sizeof(rnbuf), pw));
-    endpwent();
+    if (!shell)
+      cs_str_initial_set(cs, "shell", pw->pw_shell, NULL);
   }
 
   if (!Username)
   {
     mutt_error(_("unable to determine username"));
-    return 1; // TEST05: neomutt (unset $USER, delete user from /etc/passwd)
+    return false; // TEST05: neomutt (unset $USER, delete user from /etc/passwd)
   }
 
   if (!HomeDir)
   {
     mutt_error(_("unable to determine home directory"));
-    return 1; // TEST06: neomutt (unset $HOME, delete user from /etc/passwd)
+    return false; // TEST06: neomutt (unset $HOME, delete user from /etc/passwd)
   }
 
-  if (!Shell)
-    Shell = mutt_str_strdup("/bin/sh");
-
-  return 0;
+  cs_str_reset(cs, "shell", NULL);
+  return true;
 }
 
 /**
@@ -352,7 +379,6 @@ int main(int argc, char *argv[], char *envp[])
   umask(077);
 
   mutt_envlist_init(envp);
-
   for (optind = 1; optind < double_dash;)
   {
     /* We're getopt'ing POSIXLY, so we'll be here every time getopt()
@@ -494,22 +520,19 @@ int main(int argc, char *argv[], char *envp[])
     goto main_ok; // TEST04: neomutt -v
   }
 
-  if (get_user_info() != 0)
-  {
+  Config = init_config(500);
+  if (!Config)
+    goto main_curses;
+
+  if (!get_user_info(Config))
     goto main_exit;
-  }
+
+  reset_tilde(Config);
 
   if (dfile)
   {
-    set_default_value("debug_file", (intptr_t) mutt_str_strdup(dfile));
-    mutt_str_replace(&DebugFile, dfile);
-  }
-  else
-  {
-    /* Make sure that the DebugFile has a value */
-    LogAllowDebugSet = true;
-    reset_value("debug_file");
-    LogAllowDebugSet = false;
+    cs_str_initial_set(Config, "debug_file", dfile, NULL);
+    cs_str_reset(Config, "debug_file", NULL);
   }
 
   if (dlevel)
@@ -520,14 +543,13 @@ int main(int argc, char *argv[], char *envp[])
       mutt_error(_("Error: value '%s' is invalid for -d."), dlevel);
       goto main_exit; // TEST07: neomutt -d xyz
     }
-    set_default_value("debug_level", (intptr_t) num);
-    DebugLevel = num;
+    cs_str_initial_set(Config, "debug_level", dlevel, NULL);
+    cs_str_reset(Config, "debug_level", NULL);
   }
 
+  mutt_log_prep();
   if (dlevel)
     mutt_log_start();
-  else
-    LogAllowDebugSet = true;
 
   MuttLogger = log_disp_queue;
 
@@ -570,16 +592,13 @@ int main(int argc, char *argv[], char *envp[])
   if (!OptNoCurses)
   {
     int crc = start_curses();
-    /* Now that curses is set up, we drop back to normal screen mode.
-     * This simplifies displaying error messages to the user.
-     * The first call to refresh() will swap us back to curses screen mode. */
-    endwin();
 
     if (crc != 0)
       goto main_curses; // TEST08: can't test -- fake term?
 
     /* check whether terminal status is supported (must follow curses init) */
     TsSupported = mutt_ts_capability();
+    mutt_window_reflow();
   }
 
   /* set defaults and read init files */
@@ -588,9 +607,9 @@ int main(int argc, char *argv[], char *envp[])
 
   /* The command line overrides the config */
   if (dlevel)
-    reset_value("debug_level");
+    cs_str_reset(Config, "debug_level", NULL);
   if (dfile)
-    reset_value("debug_file");
+    cs_str_reset(Config, "debug_file", NULL);
 
   if (mutt_log_start() < 0)
   {
@@ -598,25 +617,26 @@ int main(int argc, char *argv[], char *envp[])
     goto main_exit;
   }
 
-  LogAllowDebugSet = true;
-
   mutt_list_free(&commands);
 
 #ifdef USE_NNTP
   /* "$news_server" precedence: command line, config file, environment, system file */
   if (cli_nntp)
-    mutt_str_replace(&NewsServer, cli_nntp);
+    cs_str_string_set(Config, "news_server", cli_nntp, NULL);
   if (!NewsServer)
-    NewsServer = mutt_str_strdup(mutt_str_getenv("NNTPSERVER"));
+  {
+    const char *env_nntp = mutt_str_getenv("NNTPSERVER");
+    cs_str_string_set(Config, "news_server", env_nntp, NULL);
+  }
   if (!NewsServer)
   {
     char buffer[1024];
     char *server =
         mutt_file_read_keyword(SYSCONFDIR "/nntpserver", buffer, sizeof(buffer));
-    NewsServer = mutt_str_strdup(server);
+    cs_str_string_set(Config, "news_server", server, NULL);
   }
   if (NewsServer)
-    set_default_value("news_server", (intptr_t) mutt_str_strdup(NewsServer));
+    cs_str_initial_set(Config, "news_server", NewsServer, NULL);
 #endif
 
   /* Initialize crypto backends.  */
@@ -624,14 +644,20 @@ int main(int argc, char *argv[], char *envp[])
 
   if (new_magic)
   {
-    mx_set_magic(new_magic);
-    set_default_value("mbox_type", (intptr_t) MboxType);
+    struct Buffer *err = mutt_buffer_new();
+    int r = cs_str_initial_set(Config, "mbox_type", new_magic, err);
+    if (CSR_RESULT(r) != CSR_SUCCESS)
+    {
+      mutt_error(err->data);
+      mutt_buffer_free(&err);
+      goto main_curses;
+    }
+    mutt_buffer_free(&err);
+    cs_str_reset(Config, "mbox_type", NULL);
   }
 
   if (!STAILQ_EMPTY(&queries))
   {
-    for (; optind < argc; optind++)
-      mutt_list_insert_tail(&queries, mutt_str_strdup(argv[optind]));
     rc = mutt_query_variables(&queries);
     mutt_list_free(&queries);
     goto main_curses;
@@ -639,7 +665,7 @@ int main(int argc, char *argv[], char *envp[])
 
   if (dump_variables)
   {
-    rc = mutt_dump_variables(hide_sensitive);
+    dump_config(Config, CS_DUMP_STYLE_NEO, hide_sensitive ? CS_DUMP_HIDE_SENSITIVE : 0);
     goto main_curses; // TEST18: neomutt -D
   }
 
@@ -1100,6 +1126,7 @@ int main(int argc, char *argv[], char *envp[])
 #endif
     log_queue_empty();
     mutt_log_stop();
+    cs_free(&Config);
     mutt_window_free();
     // TEST43: neomutt (no change to mailbox)
     // TEST44: neomutt (change mailbox)
@@ -1118,5 +1145,6 @@ main_exit:
   mutt_envlist_free();
   mutt_free_opts();
   mutt_free_keys();
+  cs_free(&Config);
   return rc;
 }
diff --git a/mutt.h b/mutt.h
index 7539a6ef40d9181d72a6d4fff3041e9bb31ad4bc..b97f80b61737ac33a41a52a2371b15c3c829e4e4 100644 (file)
--- a/mutt.h
+++ b/mutt.h
@@ -79,6 +79,7 @@ struct Mapping;
 #define MUTT_TOKEN_SEMICOLON     (1<<6)  /**< don't treat ; as special */
 #define MUTT_TOKEN_BACKTICK_VARS (1<<7)  /**< expand variables within backticks */
 #define MUTT_TOKEN_NOSHELL       (1<<8)  /**< don't expand environment variables */
+#define MUTT_TOKEN_QUESTION      (1<<9)  /**< treat '?' as a special */
 
 /* tree characters for linearize_tree and print_enriched_string */
 #define MUTT_TREE_LLCORNER 1
@@ -195,6 +196,7 @@ enum MuttMisc
 #define MUTT_NOSPAM 2
 
 int mutt_init(bool skip_sys_rc, struct ListHead *commands);
+struct ConfigSet *init_config(size_t size);
 
 /**
  * struct AttachMatch - An attachment matching a regex
index bb943842d942fb0127e35ef169a8096a55b41b21..8c79257bd0e28fc9cc39cef24d66f4b8eced4c38 100644 (file)
@@ -30,8 +30,8 @@
 struct Buffer;
 
 /* ... DT_REGEX */
-#define DT_REGEX_MATCH_CASE 0x010 /**< Case-sensitive matching */
-#define DT_REGEX_ALLOW_NOT  0x020 /**< Regex can begin with '!' */
+#define DT_REGEX_MATCH_CASE 0x040 /**< Case-sensitive matching */
+#define DT_REGEX_ALLOW_NOT  0x080 /**< Regex can begin with '!' */
 #define DT_REGEX_NOSUB      0x100 /**< Do not report what was matched (REG_NOSUB) */
 
 /* This is a non-standard option supported by Solaris 2.5.x
index 39977e570fc831bfe5279582aa27d1b2b111429f..93dae60df1fa45ea7ea4db8ca7d5fec54cfc402c 100644 (file)
 
 struct timeval LastError = { 0 };
 
-short DebugLevel = 0;    /**< Log file logging level */
-char *DebugFile = NULL;  /**< Log file name */
-const int NumOfLogs = 5; /**< How many log files to rotate */
-bool LogAllowDebugSet = false;
+short DebugLevel = 0;     /**< Log file logging level */
+char *DebugFile = NULL;   /**< Log file name */
+char *CurrentFile = NULL; /**< The previous log file name */
+const int NumOfLogs = 5;  /**< How many log files to rotate */
 
 #define S_TO_NS 1000000000UL
 #define S_TO_US 1000000UL
@@ -232,36 +232,13 @@ int log_disp_curses(time_t stamp, const char *file, int line,
 }
 
 /**
- * mutt_log_start - Enable file logging
- * @retval  0 Success, or already running
- * @retval -1 Failed to start
- *
- * This also handles file rotation.
+ * mutt_log_prep - Prepare to log
  */
-int mutt_log_start(void)
+void mutt_log_prep(void)
 {
-  if (DebugLevel < 1)
-    return 0;
-
-  if (log_file_running())
-    return 0;
-
   char ver[64];
   snprintf(ver, sizeof(ver), "-%s%s", PACKAGE_VERSION, GitVer);
   log_file_set_version(ver);
-
-  const char *name = rotate_logs(DebugFile, NumOfLogs);
-  if (!name)
-    return -1;
-
-  log_file_set_filename(name, false);
-  FREE(&name);
-
-  /* This will trigger the file creation */
-  if (log_file_set_level(DebugLevel, true) < 1)
-    return -1;
-
-  return 0;
 }
 
 /**
@@ -270,6 +247,34 @@ int mutt_log_start(void)
 void mutt_log_stop(void)
 {
   log_file_close(false);
+  FREE(&CurrentFile);
+}
+
+/**
+ * mutt_log_set_file - Change the logging file
+ * @param file Name to use
+ * @param verbose If true, then log the event
+ * @retval  0 Success, file opened
+ * @retval -1 Error, see errno
+ *
+ * Close the old log, rotate the new logs and open the new log.
+ */
+int mutt_log_set_file(const char *file, bool verbose)
+{
+  if (mutt_str_strcmp(CurrentFile, DebugFile) != 0)
+  {
+    const char *name = rotate_logs(DebugFile, NumOfLogs);
+    if (!name)
+      return -1;
+
+    log_file_set_filename(name, false);
+    FREE(&name);
+    mutt_str_replace(&CurrentFile, DebugFile);
+  }
+
+  cs_str_string_set(Config, "debug_file", file, NULL);
+
+  return 0;
 }
 
 /**
@@ -281,40 +286,36 @@ void mutt_log_stop(void)
  */
 int mutt_log_set_level(int level, bool verbose)
 {
+  if (!CurrentFile)
+    mutt_log_set_file(DebugFile, false);
+
   if (log_file_set_level(level, verbose) != 0)
     return -1;
 
-  if (!LogAllowDebugSet)
-    return 0;
-
   DebugLevel = level;
   return 0;
 }
 
 /**
- * mutt_log_set_file - Change the logging file
- * @param file Name to use
- * @param verbose If true, then log the event
- * @retval  0 Success, file opened
- * @retval -1 Error, see errno
+ * mutt_log_start - Enable file logging
+ * @retval  0 Success, or already running
+ * @retval -1 Failed to start
  *
- * Close the old log, rotate the new logs and open the new log.
+ * This also handles file rotation.
  */
-int mutt_log_set_file(const char *file, bool verbose)
+int mutt_log_start(void)
 {
-  if (mutt_str_strcmp(DebugFile, file) == 0)
+  if (DebugLevel < 1)
     return 0;
 
-  if (!LogAllowDebugSet)
+  if (log_file_running())
     return 0;
 
-  const char *name = rotate_logs(file, NumOfLogs);
-  if (!name)
-    return 0;
+  mutt_log_set_file(DebugFile, false);
 
-  log_file_set_filename(name, verbose);
-  FREE(&name);
-  mutt_str_replace(&DebugFile, file);
+  /* This will trigger the file creation */
+  if (log_file_set_level(DebugLevel, true) < 0)
+    return -1;
 
   return 0;
 }
index 1daf5a85a0d7fe50017736299c504a6889ee9868..c38316dce2da0a4c907a407d67c1bf715e9c924f 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <stdbool.h>
 #include <time.h>
+#include "config/lib.h"
 
 extern short DebugLevel;
 extern char *DebugFile;
@@ -32,10 +33,12 @@ extern bool LogAllowDebugSet;
 
 int log_disp_curses(time_t stamp, const char *file, int line, const char *function, int level, ...);
 
+void mutt_log_prep(void);
 int  mutt_log_start(void);
 void mutt_log_stop(void);
-int mutt_log_set_level(int level, bool verbose);
-int mutt_log_set_file(const char *file, bool verbose);
+int  mutt_log_set_level(int level, bool verbose);
+int  mutt_log_set_file(const char *file, bool verbose);
+bool mutt_log_listener(const struct ConfigSet *cs, struct HashElem *he, const char *name, enum ConfigEvent ev);
 
 void mutt_clear_error(void);
 
index 04851e6b63fa0b80beef532b13a5f7b538e69bfe..c373f5584a49d6ddcda6f0bba26e9a26932e9123 100644 (file)
 #include "email/email.h"
 #include "mutt.h"
 #include "mutt_lua.h"
+#include "globals.h"
 #include "mailbox.h"
 #include "mutt_commands.h"
 #include "mutt_options.h"
 #include "muttlib.h"
+#include "myvar.h"
 
 static int handle_panic(lua_State *l)
 {
@@ -112,14 +114,8 @@ static int lua_mutt_call(lua_State *l)
 
 static int lua_mutt_set(lua_State *l)
 {
-  int rc = -1;
   const char *param = lua_tostring(l, -2);
   mutt_debug(2, " * lua_mutt_set(%s)\n", param);
-  struct ConfigDef opt;
-  char err_str[LONG_STRING];
-  struct Buffer err = { 0 };
-  err.data = err_str;
-  err.dsize = sizeof(err_str);
 
   if (mutt_str_strncmp("my_", param, 3) == 0)
   {
@@ -127,14 +123,20 @@ static int lua_mutt_set(lua_State *l)
     myvar_set(param, val);
     return 0;
   }
-  else if (!mutt_option_get(param, &opt))
+
+  struct HashElem *he = cs_get_elem(Config, param);
+  if (!he)
   {
-    luaL_error(l, "Error getting parameter %s", param);
+    luaL_error(l, "NeoMutt parameter not found %s", param);
     return -1;
   }
 
-  rc = 0;
-  switch (DTYPE(opt.type))
+  struct ConfigDef *cdef = he->data;
+
+  int rc = 0;
+  struct Buffer *err = mutt_buffer_alloc(STRING);
+
+  switch (DTYPE(cdef->type))
   {
     case DT_ADDRESS:
     case DT_MBTABLE:
@@ -143,60 +145,38 @@ static int lua_mutt_set(lua_State *l)
     case DT_COMMAND:
     case DT_SORT:
     case DT_STRING:
-      opt.var = mutt_str_strdup(lua_tostring(l, -1));
-      rc = mutt_option_set(&opt, &err);
-      FREE(&opt.var);
-      break;
-    case DT_QUAD:
+    case DT_MAGIC:
     {
-      long num = lua_tointeger(l, -1);
-      opt.var = (void *) num;
-      if ((num != MUTT_YES) && (num != MUTT_NO) && (num != MUTT_ASKYES) && (num != MUTT_ASKNO))
-      {
-        luaL_error(l,
-                   "Invalid opt for quad option %s (one of "
-                   "mutt.QUAD_YES, mutt.QUAD_NO, mutt.QUAD_ASKYES, "
-                   "mutt.QUAD_ASKNO",
-                   param);
+      const char *value = lua_tostring(l, -1);
+      int rv = cs_he_string_set(Config, he, value, err);
+      if (CSR_RESULT(rv) != CSR_SUCCESS)
         rc = -1;
-      }
-      else
-      {
-        rc = mutt_option_set(&opt, &err);
-      }
       break;
     }
-    case DT_MAGIC:
-      if (mx_set_magic(lua_tostring(l, -1)))
-      {
-        luaL_error(l, "Invalid mailbox type: %s", opt.var);
-        rc = -1;
-      }
-      break;
     case DT_NUMBER:
+    case DT_QUAD:
     {
-      lua_Integer i = lua_tointeger(l, -1);
-      if ((i > SHRT_MIN) && (i < SHRT_MAX))
-      {
-        opt.var = (void *) lua_tointeger(l, -1);
-        rc = mutt_option_set(&opt, &err);
-      }
-      else
-      {
-        luaL_error(l, "Integer overflow of %d, not in %d-%d", i, SHRT_MIN, SHRT_MAX);
+      const intptr_t value = lua_tointeger(l, -1);
+      int rv = cs_he_native_set(Config, he, value, err);
+      if (CSR_RESULT(rv) != CSR_SUCCESS)
         rc = -1;
-      }
       break;
     }
     case DT_BOOL:
-      *(bool *) opt.var = lua_toboolean(l, -1);
+    {
+      const intptr_t value = lua_toboolean(l, -1);
+      int rv = cs_he_native_set(Config, he, value, err);
+      if (CSR_RESULT(rv) != CSR_SUCCESS)
+        rc = -1;
       break;
+    }
     default:
-      luaL_error(l, "Unsupported NeoMutt parameter type %d for %s", opt.type, param);
+      luaL_error(l, "Unsupported NeoMutt parameter type %d for %s", DTYPE(cdef->type), param);
       rc = -1;
       break;
   }
 
+  mutt_buffer_free(&err);
   return rc;
 }
 
@@ -204,69 +184,69 @@ static int lua_mutt_get(lua_State *l)
 {
   const char *param = lua_tostring(l, -1);
   mutt_debug(2, " * lua_mutt_get(%s)\n", param);
-  struct ConfigDef opt;
 
-  if (mutt_option_get(param, &opt))
+  if (mutt_str_strncmp("my_", param, 3) == 0)
   {
-    switch (DTYPE(opt.type))
+    const char *mv = myvar_get(param);
+    if (!mv)
     {
-      case DT_ADDRESS:
-      {
-        char value[LONG_STRING] = "";
-        mutt_addr_write(value, LONG_STRING, *((struct Address **) opt.var), false);
-        lua_pushstring(l, value);
-        return 1;
-      }
-      case DT_MBTABLE:
-      {
-        struct MbTable *tbl = *(struct MbTable **) opt.var;
-        lua_pushstring(l, tbl->orig_str);
-        return 1;
-      }
-      case DT_PATH:
-      case DT_COMMAND:
-      case DT_STRING:
-        if (mutt_str_strncmp("my_", param, 3) == 0)
-        {
-          char *value = (char *) opt.initial;
-          lua_pushstring(l, value);
-        }
-        else
-        {
-          char *value = NONULL(*((char **) opt.var));
-          lua_pushstring(l, value);
-        }
-        return 1;
-      case DT_QUAD:
-        lua_pushinteger(l, *(unsigned char *) opt.var);
-        return 1;
-      case DT_REGEX:
-      case DT_MAGIC:
-      case DT_SORT:
+      luaL_error(l, "NeoMutt parameter not found %s", param);
+      return -1;
+    }
+
+    lua_pushstring(l, mv);
+    return 1;
+  }
+
+  struct HashElem *he = cs_get_elem(Config, param);
+  if (!he)
+  {
+    mutt_debug(2, " * error\n");
+    luaL_error(l, "NeoMutt parameter not found %s", param);
+    return -1;
+  }
+
+  struct ConfigDef *cdef = he->data;
+
+  switch (DTYPE(cdef->type))
+  {
+    case DT_ADDRESS:
+    case DT_COMMAND:
+    case DT_MAGIC:
+    case DT_MBTABLE:
+    case DT_PATH:
+    case DT_REGEX:
+    case DT_SORT:
+    case DT_STRING:
+    {
+      struct Buffer *value = mutt_buffer_alloc(STRING);
+      int rc = cs_he_string_get(Config, he, value);
+      if (CSR_RESULT(rc) != CSR_SUCCESS)
       {
-        char buf[LONG_STRING];
-        if (!mutt_option_to_string(&opt, buf, LONG_STRING))
-        {
-          luaL_error(l, "Couldn't load %s", param);
-          return -1;
-        }
-        lua_pushstring(l, buf);
-        return 1;
-      }
-      case DT_NUMBER:
-        lua_pushinteger(l, (signed short) *((unsigned long *) opt.var));
-        return 1;
-      case DT_BOOL:
-        lua_pushboolean(l, *((bool *) opt.var));
-        return 1;
-      default:
-        luaL_error(l, "NeoMutt parameter type %d unknown for %s", opt.type, param);
+        mutt_buffer_free(&value);
         return -1;
+      }
+
+      struct Buffer *escaped = mutt_buffer_alloc(STRING);
+      escape_string(escaped, value->data);
+      lua_pushstring(l, escaped->data);
+      mutt_buffer_free(&value);
+      mutt_buffer_free(&escaped);
+      return 1;
     }
+    case DT_QUAD:
+      lua_pushinteger(l, *(unsigned char *) cdef->var);
+      return 1;
+    case DT_NUMBER:
+      lua_pushinteger(l, (signed short) *((unsigned long *) cdef->var));
+      return 1;
+    case DT_BOOL:
+      lua_pushboolean(l, *((bool *) cdef->var));
+      return 1;
+    default:
+      luaL_error(l, "NeoMutt parameter type %d unknown for %s", cdef->type, param);
+      return -1;
   }
-  mutt_debug(2, " * error\n");
-  luaL_error(l, "NeoMutt parameter not found %s", param);
-  return -1;
 }
 
 static int lua_mutt_enter(lua_State *l)
diff --git a/mx.c b/mx.c
index d612bc68f24757e5f20d89ad9db4059aa83f4509..3fbb01186b7de548bdbded318895b25bd66bd2b1 100644 (file)
--- a/mx.c
+++ b/mx.c
@@ -340,29 +340,6 @@ int mx_get_magic(const char *path)
   return magic;
 }
 
-/**
- * mx_set_magic - set MboxType to the given value
- * @param s Mailbox type string
- * @retval num Magic number, e.g. #MUTT_MBOX
- */
-int mx_set_magic(const char *s)
-{
-  int type;
-  if (mutt_str_strcasecmp(s, "mbox") == 0)
-    type = MUTT_MBOX;
-  else if (mutt_str_strcasecmp(s, "mmdf") == 0)
-    type = MUTT_MMDF;
-  else if (mutt_str_strcasecmp(s, "mh") == 0)
-    type = MUTT_MH;
-  else if (mutt_str_strcasecmp(s, "maildir") == 0)
-    type = MUTT_MAILDIR;
-  else
-    return -1;
-
-  MboxType = type;
-  return 0;
-}
-
 /**
  * mx_access - Wrapper for access, checks permissions on a given mailbox
  * @param path  Path of mailbox
diff --git a/myvar.h b/myvar.h
index cb842958c1458b04c87352e3bb09b2d506c797de..3c72ba4e8982ca4baf7323ea9c61e4bb5bdbae5b 100644 (file)
--- a/myvar.h
+++ b/myvar.h
@@ -24,7 +24,7 @@
 #include <stddef.h>
 
 const char *myvar_get(const char *var);
-int var_to_string(int idx, char *val, size_t len);
+int var_to_string2(const char *name, bool quote, struct Buffer *result, struct Buffer *err);
 int mutt_option_index(const char *s);
 
 #endif /* _MUTT_MYVAR_H */
index e8f1ae0bc5f5ea5dea525b9663f117b69add03ca..b80513538436b4478247a03ecbd465e9c9f64ae1 100644 (file)
@@ -38,6 +38,7 @@
 #include <stdbool.h>
 #include <stdio.h>
 #include "mutt/mutt.h"
+#include "config/lib.h"
 #include "crypt_mod.h"
 #include "curs_lib.h"
 #include "ncrypt.h"