]> git.llucax.com Git - software/mutt-debian.git/blobdiff - init.c
Move Mutt with NNTP support to mutt-nntp package
[software/mutt-debian.git] / init.c
diff --git a/init.c b/init.c
index 23e32c63d105979f54ab0e70041fa15a7ffe22ed..7773a920a53e2a9539843aff92321afdb24a11dd 100644 (file)
--- a/init.c
+++ b/init.c
@@ -23,6 +23,7 @@
 #include "mutt.h"
 #include "mapping.h"
 #include "mutt_curses.h"
 #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 "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 "charset.h"
 #include "mutt_crypt.h"
 #include "mutt_idna.h"
+#include "group.h"
 
 #if defined(USE_SSL)
 #include "mutt_ssl.h"
 
 #if defined(USE_SSL)
 #include "mutt_ssl.h"
@@ -48,6 +50,7 @@
 #include <sys/utsname.h>
 #include <errno.h>
 #include <sys/wait.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) &&     \
 
 #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); \
          snprintf (err->data, err->dsize, \
            _("Not available in this menu.")); \
          return (-1); \
-       } else
+       }
 
 typedef struct myvar
 {
 
 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);
 
 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;
 {
   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.  */
 
 /* 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;
 
 {
   int i;
 
@@ -236,7 +239,7 @@ int mutt_extract_token (BUFFER *dest, BUFFER *tok, int flags)
       } while (pc && *pc != '`');
       if (!pc)
       {
       } 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);
        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));
 
       /* 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
       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
 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;
 
     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;
 
     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);
   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 (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
     {
     /* 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;
     }
 
     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;
     
     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;
     
     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;
   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;
   {
     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;
     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:
       {
        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;
          goto bail;
-       
+
        case RX:
        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;
            goto bail;
          break;
-       
+
        case ADDR:
          if ((addr = mutt_parse_adrlist (NULL, buf->data)) == NULL)
            goto bail;
        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;
          }
            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));
 
          rfc822_free_address (&addr);
          break;
       }
     }
   } while (MoreArgs (s));
 
+out:
   mutt_group_context_destroy (&gc);
   return 0;
 
   mutt_group_context_destroy (&gc);
   return 0;
 
-  bail:
+bail:
   mutt_group_context_destroy (&gc);
   return -1;
 }
 
   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)
 {
 /* 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;
   char *p;
   char *tmpminor;
   int len;
+  int ret;
 
   /* Find the last item in the list that data points to. */
   lastp = NULL;
 
   /* 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;
   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);
     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);
 
 
     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));
 
     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);
   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 (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;
     
     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;
 
     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);
   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 (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)
       {
     {
       if (CurrentMenu == MENU_ALIAS)
       {
-       for (tmp = Aliases; tmp ; tmp = tmp->next)
+       for (tmp = Aliases; tmp ; tmp = tmp->next) 
          tmp->del = 1;
        set_option (OPTFORCEREDRAWINDEX);
       }
          tmp->del = 1;
        set_option (OPTFORCEREDRAWINDEX);
       }
@@ -1336,6 +1322,7 @@ static int parse_alias (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
   }
   else
   {
   }
   else
   {
+    mutt_alias_delete_reverse (tmp);
     /* override the previous value */
     rfc822_free_address (&tmp->addr);
     if (CurrentMenu == MENU_ALIAS)
     /* 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);
   }
 
   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);
              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_group_context_add_adrlist (gc, tmp->addr);
-
+  mutt_alias_add_reverse (tmp);
 
 #ifdef DEBUG
   if (debuglevel >= 2) 
 
 #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)
     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
                    a->mailbox));
       else
-       dprint (2, (debugfile, "parse_alias:   Group %s\n",
+       dprint (3, (debugfile, "parse_alias:   Group %s\n",
                    a->mailbox));
     }
   }
                    a->mailbox));
     }
   }
@@ -1544,25 +1531,22 @@ static void mutt_restore_default (struct option_t *p)
   switch (p->type & DT_MASK)
   {
     case DT_STR:
   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:
       break;
     case DT_PATH:
+      FREE((char **) p->data);         /* __FREE_CHECKED__ */
       if (p->init)
       {
        char path[_POSIX_PATH_MAX];
       if (p->init)
       {
        char path[_POSIX_PATH_MAX];
-
        strfcpy (path, (char *) p->init, sizeof (path));
        mutt_expand_path (path, sizeof (path));
        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:
       }
       break;
     case DT_ADDR:
+      rfc822_free_address ((ADDRESS **) p->data);
       if (p->init)
       if (p->init)
-      {
-       rfc822_free_address ((ADDRESS **) p->data);
        *((ADDRESS **) p->data) = rfc822_parse_adrlist (NULL, (char *) p->init);
        *((ADDRESS **) p->data) = rfc822_parse_adrlist (NULL, (char *) p->init);
-      }
       break;
     case DT_BOOL:
       if (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);
            fprintf (stderr, _("mutt_restore_default(%s): error in regexp: %s\n"),
                     p->option, pp->pattern);
            FREE (&pp->pattern);
-           regfree (pp->rx);
            FREE (&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;
 }
 
   *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;
 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 != '=')
       {
       }
       else if (query || *s->dptr != '=')
       {
-       char _tmp[STRING];
+       char _tmp[LONG_STRING];
        const char *val = NULL;
 
         if (myvar)
        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));
        {
          _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
          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);
        }
          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);
 
         mutt_extract_token (tmp, s, 0);
+
         if (myvar)
         {
           myvar_set (myvar, tmp->data);
         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)
         {
         }
         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)
         {
          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
         {
          *((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);
         }
       }
          *((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);
        if ((e = REGCOMP (rx, p, flags)) != 0)
        {
          regerror (e, rx, err->data, err->dsize);
-         regfree (rx);
          FREE (&rx);
          break;
        }
          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;
     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 != '=')
       {
 
       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);
       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
        r = -1;
        break;
       }
       else
-       *ptr = (short) val;
+       *ptr = val;
 
       /* these ones need a sanity check */
       if (mutt_strcmp (MuttVars[idx].option, "history") == 0)
 
       /* 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;
       }
        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)
     {
     }
     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));
   }
 
   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) 
   {
     conv=ConfigCharset && (*ConfigCharset) && Charset;
     if (conv) 
@@ -2261,7 +2282,7 @@ static int source_rc (const char *rcfile, BUFFER *err)
   }
   FREE (&token.data);
   FREE (&linebuf);
   }
   FREE (&token.data);
   FREE (&linebuf);
-  fclose (f);
+  safe_fclose (&f);
   if (pid != -1)
     mutt_wait_filter (pid);
   if (rc)
   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;
 
   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);
   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! */
 #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: */
 /* 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)
 {
 
 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)
   {
     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)
   {
   }
   else if (DTYPE (MuttVars[idx].type) == DT_ADDR)
   {
@@ -2703,7 +2727,7 @@ int mutt_query_variables (LIST *queries)
 {
   LIST *p;
   
 {
   LIST *p;
   
-  char errbuff[STRING];
+  char errbuff[LONG_STRING];
   char command[STRING];
   
   BUFFER err, token;
   char command[STRING];
   
   BUFFER err, token;
@@ -2735,7 +2759,7 @@ int mutt_dump_variables (void)
 {
   int i;
   
 {
   int i;
   
-  char errbuff[STRING];
+  char errbuff[LONG_STRING];
   char command[STRING];
   
   BUFFER err, token;
   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! */
   {
     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
   }
 }
 #endif
@@ -2832,6 +2856,23 @@ static int mutt_execute_commands (LIST *p)
   return 0;
 }
 
   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;
 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);
 
   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?
    */
   /* 
    * XXX - use something even more difficult to predict?
    */