X-Git-Url: https://git.llucax.com/software/mutt-debian.git/blobdiff_plain/14c29200cb58d3c4a0830265f2433849781858d0..84b9ea1689a8189d41ea4a821a1fd6cc446b9332:/init.c diff --git a/init.c b/init.c index 23e32c6..7773a92 100644 --- a/init.c +++ b/init.c @@ -23,6 +23,7 @@ #include "mutt.h" #include "mapping.h" #include "mutt_curses.h" +#include "mutt_menu.h" #include "mutt_regex.h" #include "history.h" #include "keymap.h" @@ -30,6 +31,7 @@ #include "charset.h" #include "mutt_crypt.h" #include "mutt_idna.h" +#include "group.h" #if defined(USE_SSL) #include "mutt_ssl.h" @@ -48,6 +50,7 @@ #include #include #include +#include #define CHECK_PAGER \ if ((CurrentMenu == MENU_PAGER) && (idx >= 0) && \ @@ -56,7 +59,7 @@ snprintf (err->data, err->dsize, \ _("Not available in this menu.")); \ return (-1); \ - } else + } typedef struct myvar { @@ -73,7 +76,7 @@ static void myvar_set (const char* var, const char* val); static const char* myvar_get (const char* var); static void myvar_del (const char* var); -void toggle_quadoption (int opt) +static void toggle_quadoption (int opt) { int n = opt/4; int b = (opt % 4) * 2; @@ -119,7 +122,7 @@ int query_quadoption (int opt, const char *prompt) /* given the variable ``s'', return the index into the rc_vars array which matches, or -1 if the variable is not found. */ -int mutt_option_index (char *s) +static int mutt_option_index (char *s) { int i; @@ -236,7 +239,7 @@ int mutt_extract_token (BUFFER *dest, BUFFER *tok, int flags) } while (pc && *pc != '`'); if (!pc) { - dprint (1, (debugfile, "mutt_get_token: mismatched backtics\n")); + dprint (1, (debugfile, "mutt_get_token: mismatched backticks\n")); return (-1); } cmd = mutt_substrdup (tok->dptr, pc); @@ -252,8 +255,8 @@ int mutt_extract_token (BUFFER *dest, BUFFER *tok, int flags) /* read line */ memset (&expn, 0, sizeof (expn)); - expn.data = mutt_read_line (NULL, &expn.dsize, fp, &line); - fclose (fp); + expn.data = mutt_read_line (NULL, &expn.dsize, fp, &line, 0); + safe_fclose (&fp); mutt_wait_filter (pid); /* if we got output, make a new string consiting of the shell ouptput @@ -598,42 +601,6 @@ static void remove_from_list (LIST **l, const char *str) } } -static int remove_from_rx_list (RX_LIST **l, const char *str) -{ - RX_LIST *p, *last = NULL; - int rv = -1; - - if (mutt_strcmp ("*", str) == 0) - { - mutt_free_rx_list (l); /* ``unCMD *'' means delete all current entries */ - rv = 0; - } - else - { - p = *l; - last = NULL; - while (p) - { - if (ascii_strcasecmp (str, p->rx->pattern) == 0) - { - mutt_free_regexp (&p->rx); - if (last) - last->next = p->next; - else - (*l) = p->next; - FREE (&p); - rv = 0; - } - else - { - last = p; - p = p->next; - } - } - } - return (rv); -} - static int parse_unignore (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err) { do @@ -699,7 +666,7 @@ static int parse_alternates (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER if (parse_group_context (&gc, buf, s, data, err) == -1) goto bail; - remove_from_rx_list (&UnAlternates, buf->data); + mutt_remove_from_rx_list (&UnAlternates, buf->data); if (mutt_add_to_rx_list (&Alternates, buf->data, REG_ICASE, err) != 0) goto bail; @@ -723,7 +690,7 @@ static int parse_unalternates (BUFFER *buf, BUFFER *s, unsigned long data, BUFFE do { mutt_extract_token (buf, s, 0); - remove_from_rx_list (&Alternates, buf->data); + mutt_remove_from_rx_list (&Alternates, buf->data); if (mutt_strcmp (buf->data, "*") && mutt_add_to_rx_list (&UnAlternates, buf->data, REG_ICASE, err) != 0) @@ -773,7 +740,7 @@ static int parse_spam_list (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER * /* If not, try to remove from the nospam list. */ else { - remove_from_rx_list(&NoSpamList, buf->data); + mutt_remove_from_rx_list(&NoSpamList, buf->data); } return 0; @@ -840,7 +807,7 @@ static int parse_lists (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err) if (parse_group_context (&gc, buf, s, data, err) == -1) goto bail; - remove_from_rx_list (&UnMailLists, buf->data); + mutt_remove_from_rx_list (&UnMailLists, buf->data); if (mutt_add_to_rx_list (&MailLists, buf->data, REG_ICASE, err) != 0) goto bail; @@ -868,60 +835,70 @@ static int parse_group (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err) group_state_t state = NONE; ADDRESS *addr = NULL; char *estr = NULL; - - do + + do { mutt_extract_token (buf, s, 0); if (parse_group_context (&gc, buf, s, data, err) == -1) goto bail; - + + if (data == M_UNGROUP && !mutt_strcasecmp (buf->data, "*")) + { + if (mutt_group_context_clear (&gc) < 0) + goto bail; + goto out; + } + if (!mutt_strcasecmp (buf->data, "-rx")) state = RX; else if (!mutt_strcasecmp (buf->data, "-addr")) state = ADDR; - else + else { - switch (state) + switch (state) { case NONE: - strfcpy (err->data, _("Missing -rx or -addr."), err->dsize); + snprintf (err->data, err->dsize, _("%sgroup: missing -rx or -addr."), + data == M_UNGROUP ? "un" : ""); goto bail; - + case RX: - if (mutt_group_context_add_rx (gc, buf->data, REG_ICASE, err) != 0) + if (data == M_GROUP && + mutt_group_context_add_rx (gc, buf->data, REG_ICASE, err) != 0) + goto bail; + else if (data == M_UNGROUP && + mutt_group_context_remove_rx (gc, buf->data) < 0) goto bail; break; - + case ADDR: if ((addr = mutt_parse_adrlist (NULL, buf->data)) == NULL) goto bail; - if (mutt_addrlist_to_idna (addr, &estr)) - { - snprintf (err->data, err->dsize, _("Warning: Bad IDN '%s'.\n"), - estr); + if (mutt_addrlist_to_idna (addr, &estr)) + { + snprintf (err->data, err->dsize, _("%sgroup: warning: bad IDN '%s'.\n"), + data == 1 ? "un" : "", estr); goto bail; } - mutt_group_context_add_adrlist (gc, addr); + if (data == M_GROUP) + mutt_group_context_add_adrlist (gc, addr); + else if (data == M_UNGROUP) + mutt_group_context_remove_adrlist (gc, addr); rfc822_free_address (&addr); break; } } } while (MoreArgs (s)); +out: mutt_group_context_destroy (&gc); return 0; - bail: +bail: mutt_group_context_destroy (&gc); return -1; } -static int parse_ungroup (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err) -{ - strfcpy (err->data, "not implemented", err->dsize); - return -1; -} - /* always wise to do what someone else did before */ static void _attachments_clean (void) { @@ -940,11 +917,12 @@ static int parse_attach_list (BUFFER *buf, BUFFER *s, LIST **ldata, BUFFER *err) char *p; char *tmpminor; int len; + int ret; /* Find the last item in the list that data points to. */ lastp = NULL; - dprint(5, (debugfile, "parse_attach_list: ldata = %08x, *ldata = %08x\n", - (unsigned int)ldata, (unsigned int)*ldata)); + dprint(5, (debugfile, "parse_attach_list: ldata = %p, *ldata = %p\n", + (void *)ldata, (void *)*ldata)); for (listp = *ldata; listp; listp = listp->next) { a = (ATTACH_MATCH *)listp->data; @@ -989,10 +967,18 @@ static int parse_attach_list (BUFFER *buf, BUFFER *s, LIST **ldata, BUFFER *err) tmpminor[len+2] = '\0'; a->major_int = mutt_check_mime_type(a->major); - regcomp(&a->minor_rx, tmpminor, REG_ICASE|REG_EXTENDED); + ret = REGCOMP(&a->minor_rx, tmpminor, REG_ICASE); FREE(&tmpminor); + if (ret) + { + regerror(ret, &a->minor_rx, err->data, err->dsize); + FREE(&a->major); + FREE(&a); + return -1; + } + dprint(5, (debugfile, "parse_attach_list: added %s/%s [%d]\n", a->major, a->minor, a->major_int)); @@ -1192,8 +1178,8 @@ static int parse_unlists (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *er do { mutt_extract_token (buf, s, 0); - remove_from_rx_list (&SubscribedLists, buf->data); - remove_from_rx_list (&MailLists, buf->data); + mutt_remove_from_rx_list (&SubscribedLists, buf->data); + mutt_remove_from_rx_list (&MailLists, buf->data); if (mutt_strcmp (buf->data, "*") && mutt_add_to_rx_list (&UnMailLists, buf->data, REG_ICASE, err) != 0) @@ -1215,8 +1201,8 @@ static int parse_subscribe (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER * if (parse_group_context (&gc, buf, s, data, err) == -1) goto bail; - remove_from_rx_list (&UnMailLists, buf->data); - remove_from_rx_list (&UnSubscribedLists, buf->data); + mutt_remove_from_rx_list (&UnMailLists, buf->data); + mutt_remove_from_rx_list (&UnSubscribedLists, buf->data); if (mutt_add_to_rx_list (&MailLists, buf->data, REG_ICASE, err) != 0) goto bail; @@ -1240,7 +1226,7 @@ static int parse_unsubscribe (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER do { mutt_extract_token (buf, s, 0); - remove_from_rx_list (&SubscribedLists, buf->data); + mutt_remove_from_rx_list (&SubscribedLists, buf->data); if (mutt_strcmp (buf->data, "*") && mutt_add_to_rx_list (&UnSubscribedLists, buf->data, REG_ICASE, err) != 0) @@ -1263,7 +1249,7 @@ static int parse_unalias (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *er { if (CurrentMenu == MENU_ALIAS) { - for (tmp = Aliases; tmp ; tmp = tmp->next) + for (tmp = Aliases; tmp ; tmp = tmp->next) tmp->del = 1; set_option (OPTFORCEREDRAWINDEX); } @@ -1336,6 +1322,7 @@ static int parse_alias (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err) } else { + mutt_alias_delete_reverse (tmp); /* override the previous value */ rfc822_free_address (&tmp->addr); if (CurrentMenu == MENU_ALIAS) @@ -1343,7 +1330,7 @@ static int parse_alias (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err) } mutt_extract_token (buf, s, M_TOKEN_QUOTE | M_TOKEN_SPACE | M_TOKEN_SEMICOLON); - dprint (2, (debugfile, "parse_alias: Second token is '%s'.\n", + dprint (3, (debugfile, "parse_alias: Second token is '%s'.\n", buf->data)); tmp->addr = mutt_parse_adrlist (tmp->addr, buf->data); @@ -1360,7 +1347,7 @@ static int parse_alias (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err) } mutt_group_context_add_adrlist (gc, tmp->addr); - + mutt_alias_add_reverse (tmp); #ifdef DEBUG if (debuglevel >= 2) @@ -1370,10 +1357,10 @@ static int parse_alias (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err) for (a = tmp->addr; a && a->mailbox; a = a->next) { if (!a->group) - dprint (2, (debugfile, "parse_alias: %s\n", + dprint (3, (debugfile, "parse_alias: %s\n", a->mailbox)); else - dprint (2, (debugfile, "parse_alias: Group %s\n", + dprint (3, (debugfile, "parse_alias: Group %s\n", a->mailbox)); } } @@ -1544,25 +1531,22 @@ static void mutt_restore_default (struct option_t *p) switch (p->type & DT_MASK) { case DT_STR: - if (p->init) - mutt_str_replace ((char **) p->data, (char *) p->init); + mutt_str_replace ((char **) p->data, (char *) p->init); break; case DT_PATH: + FREE((char **) p->data); /* __FREE_CHECKED__ */ if (p->init) { char path[_POSIX_PATH_MAX]; - strfcpy (path, (char *) p->init, sizeof (path)); mutt_expand_path (path, sizeof (path)); - mutt_str_replace ((char **) p->data, path); + *((char **) p->data) = safe_strdup (path); } break; case DT_ADDR: + rfc822_free_address ((ADDRESS **) p->data); if (p->init) - { - rfc822_free_address ((ADDRESS **) p->data); *((ADDRESS **) p->data) = rfc822_parse_adrlist (NULL, (char *) p->init); - } break; case DT_BOOL: if (p->init) @@ -1608,7 +1592,6 @@ static void mutt_restore_default (struct option_t *p) fprintf (stderr, _("mutt_restore_default(%s): error in regexp: %s\n"), p->option, pp->pattern); FREE (&pp->pattern); - regfree (pp->rx); FREE (&pp->rx); } } @@ -1684,6 +1667,26 @@ static void pretty_var (char *dst, size_t len, const char *option, const char *v *p = 0; } +static int check_charset (struct option_t *opt, const char *val) +{ + char *p, *q = NULL, *s = safe_strdup (val); + int rc = 0, strict = strcmp (opt->option, "send_charset") == 0; + + for (p = strtok_r (s, ":", &q); p; p = strtok_r (NULL, ":", &q)) + { + if (!*p) + continue; + if (mutt_check_charset (p, strict) < 0) + { + rc = -1; + break; + } + } + + FREE(&s); + return rc; +} + static int parse_set (BUFFER *tmp, BUFFER *s, unsigned long data, BUFFER *err) { int query, unset, inv, reset, r = 0; @@ -1830,7 +1833,7 @@ static int parse_set (BUFFER *tmp, BUFFER *s, unsigned long data, BUFFER *err) } else if (query || *s->dptr != '=') { - char _tmp[STRING]; + char _tmp[LONG_STRING]; const char *val = NULL; if (myvar) @@ -1856,7 +1859,7 @@ static int parse_set (BUFFER *tmp, BUFFER *s, unsigned long data, BUFFER *err) { _tmp[0] = '\0'; strfcpy (_tmp, NONULL(*((char **) MuttVars[idx].data)), sizeof (_tmp)); - mutt_pretty_mailbox (_tmp); + mutt_pretty_mailbox (_tmp, sizeof (_tmp)); val = _tmp; } else @@ -1877,14 +1880,9 @@ static int parse_set (BUFFER *tmp, BUFFER *s, unsigned long data, BUFFER *err) myvar = safe_strdup (myvar); myvar_del (myvar); } - else if (DTYPE (MuttVars[idx].type) == DT_ADDR) - rfc822_free_address ((ADDRESS **) MuttVars[idx].data); - else - /* MuttVars[idx].data is already 'char**' (or some 'void**') or... - * so cast to 'void*' is okay */ - FREE ((void *) MuttVars[idx].data); /* __FREE_CHECKED__ */ mutt_extract_token (tmp, s, 0); + if (myvar) { myvar_set (myvar, tmp->data); @@ -1893,18 +1891,34 @@ static int parse_set (BUFFER *tmp, BUFFER *s, unsigned long data, BUFFER *err) } else if (DTYPE (MuttVars[idx].type) == DT_PATH) { + /* MuttVars[idx].data is already 'char**' (or some 'void**') or... + * so cast to 'void*' is okay */ + FREE ((void *) MuttVars[idx].data); /* __FREE_CHECKED__ */ + strfcpy (scratch, tmp->data, sizeof (scratch)); mutt_expand_path (scratch, sizeof (scratch)); *((char **) MuttVars[idx].data) = safe_strdup (scratch); } else if (DTYPE (MuttVars[idx].type) == DT_STR) { + if ((strstr (MuttVars[idx].option, "charset") && + check_charset (&MuttVars[idx], tmp->data) < 0) | + /* $charset can't be empty, others can */ + (strcmp(MuttVars[idx].option, "charset") == 0 && ! *tmp->data)) + { + snprintf (err->data, err->dsize, _("Invalid value for option %s: \"%s\""), + MuttVars[idx].option, tmp->data); + return (-1); + } + + FREE ((void *) MuttVars[idx].data); /* __FREE_CHECKED__ */ *((char **) MuttVars[idx].data) = safe_strdup (tmp->data); if (mutt_strcmp (MuttVars[idx].option, "charset") == 0) mutt_set_charset (Charset); } else { + rfc822_free_address ((ADDRESS **) MuttVars[idx].data); *((ADDRESS **) MuttVars[idx].data) = rfc822_parse_adrlist (NULL, tmp->data); } } @@ -1957,7 +1971,6 @@ static int parse_set (BUFFER *tmp, BUFFER *s, unsigned long data, BUFFER *err) if ((e = REGCOMP (rx, p, flags)) != 0) { regerror (e, rx, err->data, err->dsize); - regfree (rx); FREE (&rx); break; } @@ -2038,8 +2051,8 @@ static int parse_set (BUFFER *tmp, BUFFER *s, unsigned long data, BUFFER *err) else if (DTYPE(MuttVars[idx].type) == DT_NUM) { short *ptr = (short *) MuttVars[idx].data; - int val; - char *t; + short val; + int rc; if (query || *s->dptr != '=') { @@ -2057,16 +2070,17 @@ static int parse_set (BUFFER *tmp, BUFFER *s, unsigned long data, BUFFER *err) s->dptr++; mutt_extract_token (tmp, s, 0); - val = strtol (tmp->data, &t, 0); + rc = mutt_atos (tmp->data, (short *) &val); - if (!*tmp->data || *t || (short) val != val) + if (rc < 0 || !*tmp->data) { - snprintf (err->data, err->dsize, _("%s: invalid value"), tmp->data); + snprintf (err->data, err->dsize, _("%s: invalid value (%s)"), tmp->data, + rc == -1 ? _("format error") : _("number overflow")); r = -1; break; } else - *ptr = (short) val; + *ptr = val; /* these ones need a sanity check */ if (mutt_strcmp (MuttVars[idx].option, "history") == 0) @@ -2087,6 +2101,13 @@ static int parse_set (BUFFER *tmp, BUFFER *s, unsigned long data, BUFFER *err) else *ptr = -*ptr; } +#ifdef USE_IMAP + else if (mutt_strcmp (MuttVars[idx].option, "imap_pipeline_depth") == 0) + { + if (*ptr < 0) + *ptr = 0; + } +#endif } else if (DTYPE (MuttVars[idx].type) == DT_QUAD) { @@ -2230,7 +2251,7 @@ static int source_rc (const char *rcfile, BUFFER *err) } memset (&token, 0, sizeof (token)); - while ((linebuf = mutt_read_line (linebuf, &buflen, f, &line)) != NULL) + while ((linebuf = mutt_read_line (linebuf, &buflen, f, &line, M_CONT)) != NULL) { conv=ConfigCharset && (*ConfigCharset) && Charset; if (conv) @@ -2261,7 +2282,7 @@ static int source_rc (const char *rcfile, BUFFER *err) } FREE (&token.data); FREE (&linebuf); - fclose (f); + safe_fclose (&f); if (pid != -1) mutt_wait_filter (pid); if (rc) @@ -2310,6 +2331,9 @@ int mutt_parse_rc_line (/* const */ char *line, BUFFER *token, BUFFER *err) int i, r = -1; BUFFER expn; + if (!line || !*line) + return 0; + memset (&expn, 0, sizeof (expn)); expn.data = expn.dptr = line; expn.dsize = mutt_strlen (line); @@ -2354,13 +2378,13 @@ finish: #define NUMCOMMANDS (sizeof (Commands)/sizeof (Commands[0])) /* initial string that starts completion. No telling how much crap * the user has typed so far. Allocate LONG_STRING just to be sure! */ -char User_typed [LONG_STRING] = {0}; +static char User_typed [LONG_STRING] = {0}; -int Num_matched = 0; /* Number of matches for completion */ -char Completed [STRING] = {0}; /* completed string (command or variable) */ -const char **Matches; +static int Num_matched = 0; /* Number of matches for completion */ +static char Completed [STRING] = {0}; /* completed string (command or variable) */ +static const char **Matches; /* this is a lie until mutt_init runs: */ -int Matches_listsize = MAX(NUMVARS,NUMCOMMANDS) + 10; +static int Matches_listsize = MAX(NUMVARS,NUMCOMMANDS) + 10; static void matches_ensure_morespace(int current) { @@ -2618,7 +2642,7 @@ static int var_to_string (int idx, char* val, size_t len) { strfcpy (tmp, NONULL (*((char **) MuttVars[idx].data)), sizeof (tmp)); if (DTYPE (MuttVars[idx].type) == DT_PATH) - mutt_pretty_mailbox (tmp); + mutt_pretty_mailbox (tmp, sizeof (tmp)); } else if (DTYPE (MuttVars[idx].type) == DT_ADDR) { @@ -2703,7 +2727,7 @@ int mutt_query_variables (LIST *queries) { LIST *p; - char errbuff[STRING]; + char errbuff[LONG_STRING]; char command[STRING]; BUFFER err, token; @@ -2735,7 +2759,7 @@ int mutt_dump_variables (void) { int i; - char errbuff[STRING]; + char errbuff[LONG_STRING]; char command[STRING]; BUFFER err, token; @@ -2804,8 +2828,8 @@ static void start_debug (void) { t = time (0); setbuf (debugfile, NULL); /* don't buffer the debugging output! */ - fprintf (debugfile, "Mutt %s started at %s.\nDebugging at level %d.\n\n", - MUTT_VERSION, asctime (localtime (&t)), debuglevel); + dprint(1,(debugfile,"Mutt/%s (%s) debugging at level %d\n", + MUTT_VERSION, ReleaseDate, debuglevel)); } } #endif @@ -2832,6 +2856,23 @@ static int mutt_execute_commands (LIST *p) return 0; } +static void mutt_srandom (void) +{ + struct timeval tv; + unsigned seed; + + gettimeofday(&tv, NULL); + /* POSIX.1-2008 states that seed is 'unsigned' without specifying its width. + * Use as many of the lower order bits from the current time of day as the seed. + * If the upper bound is truncated, that is fine. + * + * tv_sec is integral of type integer or float. Cast to 'long long' before + * bitshift in case it is a float. + */ + seed = ((LONGLONG) tv.tv_sec << 20) | tv.tv_usec; + srandom(seed); +} + void mutt_init (int skip_sys_rc, LIST *commands) { struct passwd *pw; @@ -2844,8 +2885,12 @@ void mutt_init (int skip_sys_rc, LIST *commands) err.data = error; err.dsize = sizeof (error); - Groups = hash_create (1031); + Groups = hash_create (1031, 0); + ReverseAlias = hash_create (1031, 1); + mutt_menu_init (); + mutt_srandom (); + /* * XXX - use something even more difficult to predict? */