From: Richard Russon Date: Wed, 10 Jan 2018 16:34:11 +0000 (+0000) Subject: register X-Git-Tag: 2019-10-25~739^2~3 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3513ea07584fdf5141e893feb4f9e3a0b5b229ed;p=neomutt register --- diff --git a/commands.c b/commands.c index 22ac254ac..04cf2902f 100644 --- a/commands.c +++ b/commands.c @@ -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); diff --git a/config/address.c b/config/address.c index 2bd203ee4..ead5c3aee 100644 --- a/config/address.c +++ b/config/address.c @@ -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; } diff --git a/config/dump.c b/config/dump.c index 768d37bb4..6a24223e8 100644 --- a/config/dump.c +++ b/config/dump.c @@ -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 diff --git a/curs_lib.c b/curs_lib.c index 635a4c690..0719a75db 100644 --- a/curs_lib.c +++ b/curs_lib.c @@ -54,6 +54,7 @@ #include "options.h" #include "pager.h" #include "protos.h" +#include "sidebar.h" #ifdef HAVE_ISWBLANK #include #endif diff --git a/globals.h b/globals.h index ca59820cb..c263cce87 100644 --- a/globals.h +++ b/globals.h @@ -27,6 +27,7 @@ #include #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 33989deb7..4af478616 100644 --- a/init.c +++ b/init.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -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" @@ -60,19 +60,12 @@ #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 #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 718646496..a2285ed0d 100644 --- 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. diff --git a/mailbox.h b/mailbox.h index a9225541e..f1a19cdc4 100644 --- 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 f6eba2982..91e64f2f6 100644 --- 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 7539a6ef4..b97f80b61 100644 --- 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 diff --git a/mutt/regex3.h b/mutt/regex3.h index bb943842d..8c79257bd 100644 --- a/mutt/regex3.h +++ b/mutt/regex3.h @@ -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 diff --git a/mutt_logging.c b/mutt_logging.c index 39977e570..93dae60df 100644 --- a/mutt_logging.c +++ b/mutt_logging.c @@ -45,10 +45,10 @@ 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; } diff --git a/mutt_logging.h b/mutt_logging.h index 1daf5a85a..c38316dce 100644 --- a/mutt_logging.h +++ b/mutt_logging.h @@ -25,6 +25,7 @@ #include #include +#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); diff --git a/mutt_lua.c b/mutt_lua.c index 04851e6b6..c373f5584 100644 --- a/mutt_lua.c +++ b/mutt_lua.c @@ -33,10 +33,12 @@ #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 d612bc68f..3fbb01186 100644 --- 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 cb842958c..3c72ba4e8 100644 --- a/myvar.h +++ b/myvar.h @@ -24,7 +24,7 @@ #include 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 */ diff --git a/ncrypt/cryptglue.c b/ncrypt/cryptglue.c index e8f1ae0bc..b80513538 100644 --- a/ncrypt/cryptglue.c +++ b/ncrypt/cryptglue.c @@ -38,6 +38,7 @@ #include #include #include "mutt/mutt.h" +#include "config/lib.h" #include "crypt_mod.h" #include "curs_lib.h" #include "ncrypt.h"