#include "mutt.h"
#include "mapping.h"
#include "mutt_curses.h"
+#include "mutt_menu.h"
#include "mutt_regex.h"
#include "history.h"
#include "keymap.h"
#include "charset.h"
#include "mutt_crypt.h"
#include "mutt_idna.h"
+#include "group.h"
#if defined(USE_SSL)
#include "mutt_ssl.h"
#include <sys/utsname.h>
#include <errno.h>
#include <sys/wait.h>
+#include <sys/time.h>
#define CHECK_PAGER \
if ((CurrentMenu == MENU_PAGER) && (idx >= 0) && \
snprintf (err->data, err->dsize, \
_("Not available in this menu.")); \
return (-1); \
- } else
+ }
typedef struct myvar
{
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;
/* 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;
} 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);
/* 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
}
}
-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
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;
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)
/* 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;
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;
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)
{
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;
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));
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)
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;
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)
{
if (CurrentMenu == MENU_ALIAS)
{
- for (tmp = Aliases; tmp ; tmp = tmp->next)
+ for (tmp = Aliases; tmp ; tmp = tmp->next)
tmp->del = 1;
set_option (OPTFORCEREDRAWINDEX);
}
}
else
{
+ mutt_alias_delete_reverse (tmp);
/* override the previous value */
rfc822_free_address (&tmp->addr);
if (CurrentMenu == MENU_ALIAS)
}
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);
}
mutt_group_context_add_adrlist (gc, tmp->addr);
-
+ mutt_alias_add_reverse (tmp);
#ifdef DEBUG
if (debuglevel >= 2)
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));
}
}
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)
fprintf (stderr, _("mutt_restore_default(%s): error in regexp: %s\n"),
p->option, pp->pattern);
FREE (&pp->pattern);
- regfree (pp->rx);
FREE (&pp->rx);
}
}
*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;
}
else if (query || *s->dptr != '=')
{
- char _tmp[STRING];
+ char _tmp[LONG_STRING];
const char *val = NULL;
if (myvar)
{
_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
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);
}
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);
}
}
if ((e = REGCOMP (rx, p, flags)) != 0)
{
regerror (e, rx, err->data, err->dsize);
- regfree (rx);
FREE (&rx);
break;
}
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 != '=')
{
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)
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)
{
}
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)
}
FREE (&token.data);
FREE (&linebuf);
- fclose (f);
+ safe_fclose (&f);
if (pid != -1)
mutt_wait_filter (pid);
if (rc)
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);
#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)
{
{
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)
{
{
LIST *p;
- char errbuff[STRING];
+ char errbuff[LONG_STRING];
char command[STRING];
BUFFER err, token;
{
int i;
- char errbuff[STRING];
+ char errbuff[LONG_STRING];
char command[STRING];
BUFFER err, token;
{
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
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;
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?
*/