Simplify sidebar code
[apps/madmutt.git] / mx.c
diff --git a/mx.c b/mx.c
index 974ce3c..fde597c 100644 (file)
--- a/mx.c
+++ b/mx.c
@@ -1,72 +1,56 @@
 /*
+ * Copyright notice from original mutt:
  * Copyright (C) 1996-2002 Michael R. Elkins <me@mutt.org>
  * Copyright (C) 1999-2000 Thomas Roessler <roessler@does-not-exist.org>
- * 
- *     This program is free software; you can redistribute it and/or modify
- *     it under the terms of the GNU General Public License as published by
- *     the Free Software Foundation; either version 2 of the License, or
- *     (at your option) any later version.
- * 
- *     This program is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- * 
- *     You should have received a copy of the GNU General Public License
- *     along with this program; if not, write to the Free Software
- *     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
- */ 
+ *
+ * This file is part of mutt-ng, see http://www.muttng.org/.
+ * It's licensed under the GNU General Public License,
+ * please see the file GPL in the top level source directory.
+ */
+
+#include <lib-lib/lib-lib.h>
+
+#include <utime.h>
+
+#include <lib-sys/unix.h>
+#include <lib-mime/mime.h>
+#include <lib-ui/sidebar.h>
 
 #include "mutt.h"
+#include "buffy.h"
 #include "mx.h"
-#include "rfc2047.h"
+#include "mbox.h"
+#include "mh.h"
 #include "sort.h"
-#include "mailbox.h"
+#include "thread.h"
 #include "copy.h"
 #include "keymap.h"
-#include "url.h"
-
-#ifdef USE_COMPRESSED
 #include "compress.h"
-#endif
 
-#ifdef USE_IMAP
-#include "imap.h"
-#endif
+#include <imap/imap.h>
+#include <imap/mx_imap.h>
 
-#ifdef USE_POP
-#include "pop.h"
-#endif
+#include <pop/pop.h>
+#include <pop/mx_pop.h>
 
 #ifdef USE_NNTP
-#include "nntp.h"
-#endif
-
-#ifdef BUFFY_SIZE
-#include "buffy.h"
+#include "nntp/nntp.h"
+#include "nntp/mx_nntp.h"
 #endif
 
 #ifdef USE_DOTLOCK
 #include "dotlock.h"
 #endif
 
-#include "mutt_crypt.h"
-
-#include <dirent.h>
-#include <fcntl.h>
-#include <sys/file.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#ifndef BUFFY_SIZE
-#include <utime.h>
-#endif
+#include <lib-crypt/crypt.h>
 
+#include "lib/list.h"
 
-#define mutt_is_spool(s)  (mutt_strcmp (Spoolfile, s) == 0)
+static list2_t* MailboxFormats = NULL;
+#define MX_COMMAND(idx,cmd) ((mx_t*) MailboxFormats->data[idx])->cmd
+#define MX_IDX(idx) (idx >= 0 && idx < MailboxFormats->length)
+
+#define mutt_is_spool(s)  (m_strcmp(Spoolfile, s) == 0)
 
 #ifdef USE_DOTLOCK
 /* parameters: 
  * retry - should retry if unable to lock?
  */
 
-#ifdef DL_STANDALONE
-
-static int invoke_dotlock (const char *path, int dummy, int flags, int retry)
+static int invoke_dotlock (const char *path, int flags, int retry)
 {
   char cmd[LONG_STRING + _POSIX_PATH_MAX];
   char f[SHORT_STRING + _POSIX_PATH_MAX];
   char r[SHORT_STRING];
-  
+
   if (flags & DL_FL_RETRY)
     snprintf (r, sizeof (r), "-r %d ", retry ? MAXLOCKATTEMPT : 0);
-  
+
   mutt_quote_filename (f, sizeof (f), path);
-  
+
   snprintf (cmd, sizeof (cmd),
-           "%s %s%s%s%s%s%s%s",
-           NONULL (MuttDotlock),
-           flags & DL_FL_TRY ? "-t " : "",
-           flags & DL_FL_UNLOCK ? "-u " : "",
-           flags & DL_FL_USEPRIV ? "-p " : "",
-           flags & DL_FL_FORCE ? "-f " : "",
-           flags & DL_FL_UNLINK ? "-d " : "",
-           flags & DL_FL_RETRY ? r : "",
-           f);
-  
+            "%s %s%s%s%s%s%s%s",
+            NONULL (MuttDotlock),
+            flags & DL_FL_TRY ? "-t " : "",
+            flags & DL_FL_UNLOCK ? "-u " : "",
+            flags & DL_FL_USEPRIV ? "-p " : "",
+            flags & DL_FL_FORCE ? "-f " : "",
+            flags & DL_FL_UNLINK ? "-d " : "",
+            flags & DL_FL_RETRY ? r : "", f);
+
   return mutt_system (cmd);
 }
 
-#else 
-
-#define invoke_dotlock dotlock_invoke
-
-#endif
-
-static int dotlock_file (const char *path, int fd, int retry)
+static int dotlock_file (const char *path, int retry)
 {
   int r;
   int flags = DL_FL_USEPRIV | DL_FL_RETRY;
 
-  if (retry) retry = 1;
+  if (retry)
+    retry = 1;
 
 retry_lock:
-  if ((r = invoke_dotlock(path, fd, flags, retry)) == DL_EX_EXIST)
-  {
-    if (!option (OPTNOCURSES))
-    {
+  if ((r = invoke_dotlock (path, flags, retry)) == DL_EX_EXIST) {
+    if (!option (OPTNOCURSES)) {
       char msg[LONG_STRING];
-      
-      snprintf(msg, sizeof(msg), _("Lock count exceeded, remove lock for %s?"),
-              path);
-      if(retry && mutt_yesorno(msg, M_YES) == M_YES)
-      {
-       flags |= DL_FL_FORCE;
-       retry--;
-       mutt_clear_error ();
-       goto retry_lock;
+
+      snprintf (msg, sizeof (msg),
+                _("Lock count exceeded, remove lock for %s?"), path);
+      if (retry && mutt_yesorno (msg, M_YES) == M_YES) {
+        flags |= DL_FL_FORCE;
+        retry--;
+        mutt_clear_error ();
+        goto retry_lock;
       }
-    } 
-    else
-    {
-      mutt_error ( _("Can't dotlock %s.\n"), path);
+    }
+    else {
+      mutt_error (_("Can't dotlock %s.\n"), path);
     }
   }
   return (r == DL_EX_OK ? 0 : -1);
 }
 
-static int undotlock_file (const char *path, int fd)
+static int undotlock_file (const char *path)
 {
-  return (invoke_dotlock(path, fd, DL_FL_USEPRIV | DL_FL_UNLOCK, 0) == DL_EX_OK ? 
-         0 : -1);
+  return (invoke_dotlock (path,  DL_FL_USEPRIV | DL_FL_UNLOCK, 0) ==
+          DL_EX_OK ? 0 : -1);
 }
 
 #endif /* USE_DOTLOCK */
 
+/* looks up index of type for path in MailboxFormats */
+static int mx_get_idx (const char* path) {
+  int i = 0, t = 0;
+  struct stat st;
+
+  /* first, test all non-local folders to avoid stat() call */
+  for (i = 0; i < MailboxFormats->length; i++) {
+    if (!MX_COMMAND(i,local))
+      t = MX_COMMAND(i,mx_is_magic)(path, NULL);
+    if (t >= 1)
+      return (t-1);
+  }
+  if (stat (path, &st) == 0) {
+    /* if stat() succeeded, keep testing until success and
+     * pass stat() info so that we only need to do it once */
+    for (i = 0; i < MailboxFormats->length; i++) {
+      if (MX_COMMAND(i,local))
+        t = MX_COMMAND(i,mx_is_magic)(path, &st);
+      if (t >= 1)
+        return (t-1);
+    }
+  }
+  return (-1);
+}
+
 /* Args:
  *     excl            if excl != 0, request an exclusive lock
  *     dot             if dot != 0, try to dotlock the file
- *     timeout         should retry locking?
+ *     time_out        should retry locking?
  */
-int mx_lock_file (const char *path, int fd, int excl, int dot, int timeout)
+int mx_lock_file (const char *path, int fd, int excl, int dot, int time_out)
 {
 #if defined (USE_FCNTL) || defined (USE_FLOCK)
   int count;
@@ -163,35 +160,35 @@ int mx_lock_file (const char *path, int fd, int excl, int dot, int timeout)
 
 #ifdef USE_FCNTL
   struct flock lck;
-  
 
-  memset (&lck, 0, sizeof (struct flock));
+
+  p_clear(&lck, 1);
   lck.l_type = excl ? F_WRLCK : F_RDLCK;
   lck.l_whence = SEEK_SET;
 
   count = 0;
   attempt = 0;
-  while (fcntl (fd, F_SETLK, &lck) == -1)
-  {
+  prev_sb.st_size = 0;
+  while (fcntl (fd, F_SETLK, &lck) == -1) {
     struct stat sb;
-    dprint(1,(debugfile, "mx_lock_file(): fcntl errno %d.\n", errno));
-    if (errno != EAGAIN && errno != EACCES)
-    {
+
+    if (errno != EAGAIN && errno != EACCES) {
       mutt_perror ("fcntl");
       return (-1);
     }
 
     if (fstat (fd, &sb) != 0)
-     sb.st_size = 0;
-    
+      sb.st_size = 0;
+
     if (count == 0)
       prev_sb = sb;
 
     /* only unlock file if it is unchanged */
-    if (prev_sb.st_size == sb.st_size && ++count >= (timeout?MAXLOCKATTEMPT:0))
-    {
-      if (timeout)
-       mutt_error _("Timeout exceeded while attempting fcntl lock!");
+    if (prev_sb.st_size == sb.st_size
+        && ++count >= (time_out ? MAXLOCKATTEMPT : 0)) {
+      if (time_out)
+        mutt_error _("Timeout exceeded while attempting fcntl lock!");
+
       return (-1);
     }
 
@@ -205,27 +202,27 @@ int mx_lock_file (const char *path, int fd, int excl, int dot, int timeout)
 #ifdef USE_FLOCK
   count = 0;
   attempt = 0;
-  while (flock (fd, (excl ? LOCK_EX : LOCK_SH) | LOCK_NB) == -1)
-  {
+  while (flock (fd, (excl ? LOCK_EX : LOCK_SH) | LOCK_NB) == -1) {
     struct stat sb;
-    if (errno != EWOULDBLOCK)
-    {
+
+    if (errno != EWOULDBLOCK) {
       mutt_perror ("flock");
       r = -1;
       break;
     }
 
-    if (fstat(fd,&sb) != 0 )
-     sb.st_size=0;
-    
+    if (fstat (fd, &sb) != 0)
+      sb.st_size = 0;
+
     if (count == 0)
-      prev_sb=sb;
+      prev_sb = sb;
 
     /* only unlock file if it is unchanged */
-    if (prev_sb.st_size == sb.st_size && ++count >= (timeout?MAXLOCKATTEMPT:0))
-    {
-      if (timeout)
-       mutt_error _("Timeout exceeded while attempting flock lock!");
+    if (prev_sb.st_size == sb.st_size
+        && ++count >= (time_out ? MAXLOCKATTEMPT : 0)) {
+      if (time_out)
+        mutt_error _("Timeout exceeded while attempting flock lock!");
+
       r = -1;
       break;
     }
@@ -239,11 +236,10 @@ int mx_lock_file (const char *path, int fd, int excl, int dot, int timeout)
 
 #ifdef USE_DOTLOCK
   if (r == 0 && dot)
-    r = dotlock_file (path, fd, timeout);
+    r = dotlock_file (path, time_out);
 #endif /* USE_DOTLOCK */
 
-  if (r == -1)
-  {
+  if (r == -1) {
     /* release any other locks obtained in this routine */
 
 #ifdef USE_FCNTL
@@ -264,9 +260,9 @@ int mx_lock_file (const char *path, int fd, int excl, int dot, int timeout)
 int mx_unlock_file (const char *path, int fd, int dot)
 {
 #ifdef USE_FCNTL
-  struct flock unlockit = { F_UNLCK, 0, 0, 0 };
+  struct flock unlockit;
 
-  memset (&unlockit, 0, sizeof (struct flock));
+  p_clear(&unlockit, 1);
   unlockit.l_type = F_UNLCK;
   unlockit.l_whence = SEEK_SET;
   fcntl (fd, F_SETLK, &unlockit);
@@ -278,15 +274,16 @@ int mx_unlock_file (const char *path, int fd, int dot)
 
 #ifdef USE_DOTLOCK
   if (dot)
-    undotlock_file (path, fd);
+    undotlock_file (path);
 #endif
-  
+
   return 0;
 }
 
-void mx_unlink_empty (const char *path)
+static void mx_unlink_empty (const char *path)
 {
   int fd;
+
 #ifndef USE_DOTLOCK
   struct stat sb;
 #endif
@@ -294,14 +291,13 @@ void mx_unlink_empty (const char *path)
   if ((fd = open (path, O_RDWR)) == -1)
     return;
 
-  if (mx_lock_file (path, fd, 1, 0, 1) == -1)
-  {
+  if (mx_lock_file (path, fd, 1, 0, 1) == -1) {
     close (fd);
     return;
   }
 
 #ifdef USE_DOTLOCK
-  invoke_dotlock (path, fd, DL_FL_UNLINK, 1);
+  invoke_dotlock (path, DL_FL_UNLINK, 1);
 #else
   if (fstat (fd, &sb) == 0 && sb.st_size == 0)
     unlink (path);
@@ -311,180 +307,21 @@ void mx_unlink_empty (const char *path)
   close (fd);
 }
 
-/* try to figure out what type of mailbox ``path'' is
- *
- * return values:
- *     M_*     mailbox type
- *     0       not a mailbox
- *     -1      error
- */
-
-#ifdef USE_IMAP
-
-int mx_is_imap(const char *p)
-{
-  url_scheme_t scheme;
-
-  if (!p)
-    return 0;
-
-  if (*p == '{')
-    return 1;
-
-  scheme = url_check_scheme (p);
-  if (scheme == U_IMAP || scheme == U_IMAPS)
-    return 1;
-
-  return 0;
-}
-
-#endif
-
-#ifdef USE_POP
-int mx_is_pop (const char *p)
-{
-  url_scheme_t scheme;
-
-  if (!p)
-    return 0;
-
-  scheme = url_check_scheme (p);
-  if (scheme == U_POP || scheme == U_POPS)
-    return 1;
-
-  return 0;
-}
-#endif
-
-#ifdef USE_NNTP
-int mx_is_nntp (const char *p)
-{
-  url_scheme_t scheme;
-
-  if (!p)
-    return 0;
-
-  scheme = url_check_scheme (p);
-  if (scheme == U_NNTP || scheme == U_NNTPS)
-    return 1;
-
-  return 0;
-}
-#endif
-
-int mx_get_magic (const char *path)
-{
-  struct stat st;
-  int magic = 0;
-  char tmp[_POSIX_PATH_MAX];
-  FILE *f;
-
-#ifdef USE_IMAP
-  if(mx_is_imap(path))
-    return M_IMAP;
-#endif /* USE_IMAP */
-
-#ifdef USE_POP
-  if (mx_is_pop (path))
-    return M_POP;
-#endif /* USE_POP */
-
-#ifdef USE_NNTP
-  if (mx_is_nntp (path))
-    return M_NNTP;
-#endif /* USE_NNTP */
-
-  if (stat (path, &st) == -1)
-  {
-    dprint (1, (debugfile, "mx_get_magic(): unable to stat %s: %s (errno %d).\n",
-               path, strerror (errno), errno));
-    return (-1);
-  }
-
-  if (S_ISDIR (st.st_mode))
-  {
-    /* check for maildir-style mailbox */
-
-    snprintf (tmp, sizeof (tmp), "%s/cur", path);
-    if (stat (tmp, &st) == 0 && S_ISDIR (st.st_mode))
-      return (M_MAILDIR);
-
-    /* check for mh-style mailbox */
-
-    snprintf (tmp, sizeof (tmp), "%s/.mh_sequences", path);
-    if (access (tmp, F_OK) == 0)
-      return (M_MH);
-
-    snprintf (tmp, sizeof (tmp), "%s/.xmhcache", path);
-    if (access (tmp, F_OK) == 0)
-      return (M_MH);
-    
-    snprintf (tmp, sizeof (tmp), "%s/.mew_cache", path);
-    if (access (tmp, F_OK) == 0)
-      return (M_MH);
-
-    snprintf (tmp, sizeof (tmp), "%s/.mew-cache", path);
-    if (access (tmp, F_OK) == 0)
-      return (M_MH);
-    
-    snprintf (tmp, sizeof (tmp), "%s/.sylpheed_cache", path);
-    if (access (tmp, F_OK) == 0)
-      return (M_MH);
-
-    /* 
-     * ok, this isn't an mh folder, but mh mode can be used to read
-     * Usenet news from the spool. ;-) 
-     */
-
-    snprintf (tmp, sizeof (tmp), "%s/.overview", path);
-    if (access (tmp, F_OK) == 0)
-      return (M_MH);
-
-  }
-  else if (st.st_size == 0)
-  {
-    /* hard to tell what zero-length files are, so assume the default magic */
-    if (DefaultMagic == M_MBOX || DefaultMagic == M_MMDF)
-      return (DefaultMagic);
-    else
-      return (M_MBOX);
-  }
-  else if ((f = fopen (path, "r")) != NULL)
-  {
-#ifndef BUFFY_SIZE
-    struct utimbuf times;
-#endif
+/* try to figure out what type of mailbox ``path'' is */
+int mx_get_magic (const char *path) {
+  int i = 0;
 
-    fgets (tmp, sizeof (tmp), f);
-    if (mutt_strncmp ("From ", tmp, 5) == 0)
-      magic = M_MBOX;
-    else if (mutt_strcmp (MMDF_SEP, tmp) == 0)
-      magic = M_MMDF;
-    safe_fclose (&f);
-#ifndef BUFFY_SIZE
-    /* need to restore the times here, the file was not really accessed,
-     * only the type was accessed.  This is important, because detection
-     * of "new mail" depends on those times set correctly.
-     */
-    times.actime = st.st_atime;
-    times.modtime = st.st_mtime;
-    utime (path, &times);
-#endif
-  }
-  else
-  {
-    dprint (1, (debugfile, "mx_get_magic(): unable to open file %s for reading.\n",
-               path));
-    mutt_perror (path);
+  if (m_strlen(path) == 0)
     return (-1);
-  }
-
-#ifdef USE_COMPRESSED
-  if (magic == 0 && mutt_can_read_compressed (path))
-    return M_COMPRESSED;
-#endif
+  if ((i = mx_get_idx (path)) >= 0)
+    return (MX_COMMAND(i,type));
+  return (-1);
+}
 
-  return (magic);
+int mx_is_local (int m) {
+  if (!MX_IDX(m))
+    return (0);
+  return (MX_COMMAND(m,local));
 }
 
 /*
@@ -509,141 +346,120 @@ int mx_set_magic (const char *s)
 /* mx_access: Wrapper for access, checks permissions on a given mailbox.
  *   We may be interested in using ACL-style flags at some point, currently
  *   we use the normal access() flags. */
-int mx_access (const charpath, int flags)
+int mx_access (const char *path, int flags)
 {
-#ifdef USE_IMAP
-  if (mx_is_imap (path))
-    return imap_access (path, flags);
-#endif
+  int i = 0;
 
-  return access (path, flags);
+  if ((i = mx_get_idx (path)) >= 0 && MX_COMMAND(i,mx_access))
+    return (MX_COMMAND(i,mx_access)(path,flags));
+  return (0);
 }
 
-static int mx_open_mailbox_append (CONTEXT *ctx, int flags)
+static int mx_open_mailbox_append (CONTEXT * ctx, int flags)
 {
   struct stat sb;
 
-#ifdef USE_COMPRESSED
   /* special case for appending to compressed folders -
    * even if we can not open them for reading */
   if (mutt_can_append_compressed (ctx->path))
     mutt_open_append_compressed (ctx);
-#endif
 
   ctx->append = 1;
 
-#ifdef USE_IMAP
-  
-  if(mx_is_imap(ctx->path))  
+  if (mx_get_magic (ctx->path) == M_IMAP)
     return imap_open_mailbox_append (ctx);
 
-#endif
-  
-  if(stat(ctx->path, &sb) == 0)
-  {
+  if (stat (ctx->path, &sb) == 0) {
     ctx->magic = mx_get_magic (ctx->path);
-    
-    switch (ctx->magic)
-    {
-      case 0:
-       mutt_error (_("%s is not a mailbox."), ctx->path);
-       /* fall through */
-      case -1:
-       return (-1);
+
+    switch (ctx->magic) {
+    case 0:
+      mutt_error (_("%s is not a mailbox."), ctx->path);
+      /* fall through */
+    case -1:
+      return (-1);
     }
   }
-  else if (errno == ENOENT)
-  {
+  else if (errno == ENOENT) {
     ctx->magic = DefaultMagic;
 
-    if (ctx->magic == M_MH || ctx->magic == M_MAILDIR)
-    {
+    if (ctx->magic == M_MH || ctx->magic == M_MAILDIR) {
       char tmp[_POSIX_PATH_MAX];
 
-      if (mkdir (ctx->path, S_IRWXU))
-      {
-       mutt_perror (ctx->path);
-       return (-1);
+      if (mkdir (ctx->path, S_IRWXU)) {
+        mutt_perror (ctx->path);
+        return (-1);
       }
 
-      if (ctx->magic == M_MAILDIR)
-      {
-       snprintf (tmp, sizeof (tmp), "%s/cur", ctx->path);
-       if (mkdir (tmp, S_IRWXU))
-       {
-         mutt_perror (tmp);
-         rmdir (ctx->path);
-         return (-1);
-       }
-
-       snprintf (tmp, sizeof (tmp), "%s/new", ctx->path);
-       if (mkdir (tmp, S_IRWXU))
-       {
-         mutt_perror (tmp);
-         snprintf (tmp, sizeof (tmp), "%s/cur", ctx->path);
-         rmdir (tmp);
-         rmdir (ctx->path);
-         return (-1);
-       }
-       snprintf (tmp, sizeof (tmp), "%s/tmp", ctx->path);
-       if (mkdir (tmp, S_IRWXU))
-       {
-         mutt_perror (tmp);
-         snprintf (tmp, sizeof (tmp), "%s/cur", ctx->path);
-         rmdir (tmp);
-         snprintf (tmp, sizeof (tmp), "%s/new", ctx->path);
-         rmdir (tmp);
-         rmdir (ctx->path);
-         return (-1);
-       }
+      if (ctx->magic == M_MAILDIR) {
+        snprintf (tmp, sizeof (tmp), "%s/cur", ctx->path);
+        if (mkdir (tmp, S_IRWXU)) {
+          mutt_perror (tmp);
+          rmdir (ctx->path);
+          return (-1);
+        }
+
+        snprintf (tmp, sizeof (tmp), "%s/new", ctx->path);
+        if (mkdir (tmp, S_IRWXU)) {
+          mutt_perror (tmp);
+          snprintf (tmp, sizeof (tmp), "%s/cur", ctx->path);
+          rmdir (tmp);
+          rmdir (ctx->path);
+          return (-1);
+        }
+        snprintf (tmp, sizeof (tmp), "%s/tmp", ctx->path);
+        if (mkdir (tmp, S_IRWXU)) {
+          mutt_perror (tmp);
+          snprintf (tmp, sizeof (tmp), "%s/cur", ctx->path);
+          rmdir (tmp);
+          snprintf (tmp, sizeof (tmp), "%s/new", ctx->path);
+          rmdir (tmp);
+          rmdir (ctx->path);
+          return (-1);
+        }
       }
-      else
-      {
-       int i;
-
-       snprintf (tmp, sizeof (tmp), "%s/.mh_sequences", ctx->path);
-       if ((i = creat (tmp, S_IRWXU)) == -1)
-       {
-         mutt_perror (tmp);
-         rmdir (ctx->path);
-         return (-1);
-       }
-       close (i);
+      else {
+        int i;
+
+        snprintf (tmp, sizeof (tmp), "%s/.mh_sequences", ctx->path);
+        if ((i = creat (tmp, S_IRWXU)) == -1) {
+          mutt_perror (tmp);
+          rmdir (ctx->path);
+          return (-1);
+        }
+        close (i);
       }
     }
   }
-  else
-  {
+  else {
     mutt_perror (ctx->path);
     return (-1);
   }
 
-  switch (ctx->magic)
-  {
-    case M_MBOX:
-    case M_MMDF:
-    if ((ctx->fp = safe_fopen (ctx->path, flags & M_NEWFOLDER ? "w" : "a")) == NULL ||
-         mbox_lock_mailbox (ctx, 1, 1) != 0)
-      {
-       if (!ctx->fp)
-         mutt_perror (ctx->path);
-       else
-       {
-         mutt_error (_("Couldn't lock %s\n"), ctx->path);
-         safe_fclose (&ctx->fp);
-       }
-       return (-1);
+  switch (ctx->magic) {
+  case M_MBOX:
+  case M_MMDF:
+    if ((ctx->fp =
+         safe_fopen (ctx->path, flags & M_NEWFOLDER ? "w" : "a")) == NULL
+        || mbox_lock_mailbox (ctx, 1, 1) != 0) {
+      if (!ctx->fp)
+        mutt_perror (ctx->path);
+      else {
+        mutt_error (_("Couldn't lock %s\n"), ctx->path);
+        safe_fclose (&ctx->fp);
       }
-      fseek (ctx->fp, 0, 2);
-      break;
+      return (-1);
+    }
+    fseeko (ctx->fp, 0, 2);
+    break;
 
-    case M_MH:
-    case M_MAILDIR:
-      /* nothing to do */
-      break;
+  case M_MH:
+  case M_MAILDIR:
+    /* nothing to do */
+    break;
 
-    default:
-      return (-1);
+  default:
+    return (-1);
   }
 
   return 0;
@@ -659,57 +475,55 @@ static int mx_open_mailbox_append (CONTEXT *ctx, int flags)
  *             M_QUIET         only print error messages
  *     ctx     if non-null, context struct to use
  */
-CONTEXT *mx_open_mailbox (const char *path, int flags, CONTEXT *pctx)
+CONTEXT *mx_open_mailbox (const char *path, int flags, CONTEXT * pctx)
 {
   CONTEXT *ctx = pctx;
   int rc;
 
   if (!ctx)
-    ctx = safe_malloc (sizeof (CONTEXT));
-  memset (ctx, 0, sizeof (CONTEXT));
-  ctx->path = safe_strdup (path);
+    ctx = p_new(CONTEXT, 1);
+  p_clear(ctx, 1);
+  ctx->path = m_strdup(path);
 
   ctx->msgnotreadyet = -1;
   ctx->collapsed = 0;
-  
+
   if (flags & M_QUIET)
     ctx->quiet = 1;
   if (flags & M_READONLY)
     ctx->readonly = 1;
+  if (flags & M_COUNT)
+    ctx->counting = 1;
 
-  if (flags & (M_APPEND|M_NEWFOLDER))
-  {
-    if (mx_open_mailbox_append (ctx, flags) != 0)
-    {
+  if (flags & (M_APPEND | M_NEWFOLDER)) {
+    if (mx_open_mailbox_append (ctx, flags) != 0) {
       mx_fastclose_mailbox (ctx);
       if (!pctx)
-       FREE (&ctx);
+        p_delete(&ctx);
       return NULL;
     }
     return ctx;
   }
 
-  ctx->magic = mx_get_magic (path);
-  
-#ifdef USE_COMPRESSED
+  if (!MX_IDX(ctx->magic-1))
+    ctx->magic = mx_get_magic (path);
+
   if (ctx->magic == M_COMPRESSED)
     mutt_open_read_compressed (ctx);
-#endif
 
-  if(ctx->magic == 0)
+  if (ctx->magic == 0)
     mutt_error (_("%s is not a mailbox."), path);
 
-  if(ctx->magic == -1)
-    mutt_perror(path);
-  
-  if(ctx->magic <= 0)
-  {
+  if (ctx->magic == -1)
+    mutt_perror (path);
+
+  if (ctx->magic <= 0) {
     mx_fastclose_mailbox (ctx);
     if (!pctx)
-      FREE (&ctx);
+      p_delete(&ctx);
     return (NULL);
   }
-  
+
   /* if the user has a `push' command in their .muttrc, or in a folder-hook,
    * it will cause the progress messages not to be displayed because
    * mutt_refresh() will think we are in the middle of a macro.  so set a
@@ -720,50 +534,12 @@ CONTEXT *mx_open_mailbox (const char *path, int flags, CONTEXT *pctx)
   if (!ctx->quiet)
     mutt_message (_("Reading %s..."), ctx->path);
 
-  switch (ctx->magic)
-  {
-    case M_MH:
-      rc = mh_read_dir (ctx, NULL);
-      break;
+  rc = MX_COMMAND(ctx->magic-1,mx_open_mailbox)(ctx);
 
-    case M_MAILDIR:
-      rc = maildir_read_dir (ctx);
-      break;
-
-    case M_MMDF:
-    case M_MBOX:
-      rc = mbox_open_mailbox (ctx);
-      break;
-
-#ifdef USE_IMAP
-    case M_IMAP:
-      rc = imap_open_mailbox (ctx);
-      break;
-#endif /* USE_IMAP */
-
-#ifdef USE_POP
-    case M_POP:
-      rc = pop_open_mailbox (ctx);
-      break;
-#endif /* USE_POP */
-
-#ifdef USE_NNTP
-    case M_NNTP:
-      rc = nntp_open_mailbox (ctx);
-      break;
-#endif /* USE_NNTP */
-
-    default:
-      rc = -1;
-      break;
-  }
-
-  if (rc == 0)
-  {
-    if ((flags & M_NOSORT) == 0)
-    {
+  if (rc == 0) {
+    if ((flags & M_NOSORT) == 0) {
       /* avoid unnecessary work since the mailbox is completely unthreaded
-        to begin with */
+         to begin with */
       unset_option (OPTSORTSUBTHREADS);
       unset_option (OPTNEEDRESCORE);
       mutt_sort_headers (ctx, 1);
@@ -771,11 +547,10 @@ CONTEXT *mx_open_mailbox (const char *path, int flags, CONTEXT *pctx)
     if (!ctx->quiet)
       mutt_clear_error ();
   }
-  else
-  {
+  else {
     mx_fastclose_mailbox (ctx);
     if (!pctx)
-      FREE (&ctx);
+      p_delete(&ctx);
   }
 
   unset_option (OPTFORCEREFRESH);
@@ -783,160 +558,102 @@ CONTEXT *mx_open_mailbox (const char *path, int flags, CONTEXT *pctx)
 }
 
 /* free up memory associated with the mailbox context */
-void mx_fastclose_mailbox (CONTEXT *ctx)
+void mx_fastclose_mailbox (CONTEXT * ctx)
 {
   int i;
 
-  if(!ctx) 
+  if (!ctx)
     return;
-  
-#ifdef USE_IMAP
-  if (ctx->magic == M_IMAP)
-    imap_close_mailbox (ctx);
-#endif /* USE_IMAP */
-#ifdef USE_POP
-  if (ctx->magic == M_POP)
-    pop_close_mailbox (ctx);
-#endif /* USE_POP */
-#ifdef USE_NNTP
-  if (ctx->magic == M_NNTP)
-    nntp_fastclose_mailbox (ctx);
-#endif /* USE_NNTP */
+
+  if (MX_IDX(ctx->magic-1) && MX_COMMAND(ctx->magic-1,mx_fastclose_mailbox))
+    MX_COMMAND(ctx->magic-1,mx_fastclose_mailbox(ctx));
   if (ctx->subj_hash)
     hash_destroy (&ctx->subj_hash, NULL);
   if (ctx->id_hash)
     hash_destroy (&ctx->id_hash, NULL);
   mutt_clear_threads (ctx);
   for (i = 0; i < ctx->msgcount; i++)
-    mutt_free_header (&ctx->hdrs[i]);
-  FREE (&ctx->hdrs);
-  FREE (&ctx->v2r);
-#ifdef USE_COMPRESSED
+    header_delete(&ctx->hdrs[i]);
+  p_delete(&ctx->hdrs);
+  p_delete(&ctx->v2r);
+
   if (ctx->compressinfo)
     mutt_fast_close_compressed (ctx);
-#endif
-  FREE (&ctx->path);
-  FREE (&ctx->pattern);
-  if (ctx->limit_pattern) 
+
+  p_delete(&ctx->path);
+  p_delete(&ctx->pattern);
+  if (ctx->limit_pattern)
     mutt_pattern_free (&ctx->limit_pattern);
   safe_fclose (&ctx->fp);
-  memset (ctx, 0, sizeof (CONTEXT));
+  p_clear(ctx, 1);
 }
 
 /* save changes to disk */
-static int sync_mailbox (CONTEXT *ctx, int *index_hint)
+static int sync_mailbox (CONTEXT * ctx, int *index_hint)
 {
-#ifdef BUFFY_SIZE
-  BUFFY *tmp = NULL;
-#endif
   int rc = -1;
 
   if (!ctx->quiet)
     mutt_message (_("Writing %s..."), ctx->path);
 
-  switch (ctx->magic)
-  {
-    case M_MBOX:
-    case M_MMDF:
-      rc = mbox_sync_mailbox (ctx, index_hint);
-#ifdef BUFFY_SIZE
-      tmp = mutt_find_mailbox (ctx->path);
-#endif
-      break;
-      
-    case M_MH:
-    case M_MAILDIR:
-      rc = mh_sync_mailbox (ctx, index_hint);
-      break;
-      
-#ifdef USE_IMAP
-    case M_IMAP:
-      /* extra argument means EXPUNGE */
-      rc = imap_sync_mailbox (ctx, 1, index_hint);
-      break;
-#endif /* USE_IMAP */
-
-#ifdef USE_POP
-    case M_POP:
-      rc = pop_sync_mailbox (ctx, index_hint);
-      break;
-#endif /* USE_POP */
+  if (MX_IDX(ctx->magic-1))
+    /* the 1 is only of interest for IMAP and means EXPUNGE */
+    rc = MX_COMMAND(ctx->magic-1,mx_sync_mailbox(ctx,1,index_hint));
 
-#ifdef USE_NNTP
-    case M_NNTP:
-      rc = nntp_sync_mailbox (ctx);
-      break;
-#endif /* USE_NNTP */
-  }
-
-#if 0
-  if (!ctx->quiet && !ctx->shutup && rc == -1)
-    mutt_error ( _("Could not synchronize mailbox %s!"), ctx->path);
-#endif
-  
-#ifdef BUFFY_SIZE
-  if (tmp && tmp->new == 0)
-    mutt_update_mailbox (tmp);
-#endif
-
-#ifdef USE_COMPRESSED
   if (rc == 0 && ctx->compressinfo)
     return mutt_sync_compressed (ctx);
-#endif
 
   return rc;
 }
 
 /* move deleted mails to the trash folder */
-static int trash_append (CONTEXT *ctx)
+static int trash_append (CONTEXT * ctx)
 {
-    CONTEXT *ctx_trash;
-    int i = 0;
-    struct stat st, stc;
+  CONTEXT *ctx_trash;
+  int i = 0;
+  struct stat st, stc;
 
-    if (!TrashPath || !ctx->deleted ||
-       (ctx->magic == M_MAILDIR && option (OPTMAILDIRTRASH)))
-      return 0;
+  if (!TrashPath || !ctx->deleted ||
+      (ctx->magic == M_MAILDIR && option (OPTMAILDIRTRASH)))
+    return 0;
 
-    for (;i < ctx->msgcount && (!ctx->hdrs[i]->deleted ||
-                               ctx->hdrs[i]->appended); i++);
-    if (i == ctx->msgcount)
-      return 0; /* nothing to be done */
+  for (; i < ctx->msgcount && (!ctx->hdrs[i]->deleted ||
+                               ctx->hdrs[i]->appended); i++);
+  if (i == ctx->msgcount)
+    return 0;                   /* nothing to be done */
 
-    if (mutt_save_confirm (TrashPath, &st) != 0)
-    {
-      mutt_error _("message(s) not deleted");
-      return -1;
-    }
+  if (mutt_save_confirm (TrashPath, &st) != 0) {
+    mutt_error _("message(s) not deleted");
 
-    if (lstat (ctx->path, &stc) == 0 && stc.st_ino == st.st_ino
-       && stc.st_dev == st.st_dev && stc.st_rdev == st.st_rdev)
-      return 0;  /* we are in the trash folder: simple sync */
+    return -1;
+  }
 
-    if ((ctx_trash = mx_open_mailbox (TrashPath, M_APPEND, NULL)) != NULL)
-    {
-      for (i = 0 ; i < ctx->msgcount ; i++)
-       if (ctx->hdrs[i]->deleted && !ctx->hdrs[i]->appended
-           && !ctx->hdrs[i]->purged
-           && mutt_append_message (ctx_trash, ctx, ctx->hdrs[i], 0, 0) == -1)
-         {
-           mx_close_mailbox (ctx_trash, NULL);
-           return -1;
-         }
-
-      mx_close_mailbox (ctx_trash, NULL);
-    }
-    else
-    {
-      mutt_error _("Can't open trash folder");
-      return -1;
-    }
+  if (lstat (ctx->path, &stc) == 0 && stc.st_ino == st.st_ino
+      && stc.st_dev == st.st_dev && stc.st_rdev == st.st_rdev)
+    return 0;                   /* we are in the trash folder: simple sync */
 
-    return 0;
+  if ((ctx_trash = mx_open_mailbox (TrashPath, M_APPEND, NULL)) != NULL) {
+    for (i = 0; i < ctx->msgcount; i++)
+      if (ctx->hdrs[i]->deleted && !ctx->hdrs[i]->appended
+          && !ctx->hdrs[i]->purged
+          && mutt_append_message (ctx_trash, ctx, ctx->hdrs[i], 0, 0) == -1) {
+        mx_close_mailbox (ctx_trash, NULL);
+        return -1;
+      }
+
+    mx_close_mailbox (ctx_trash, NULL);
+  }
+  else {
+    mutt_error _("Can't open trash folder");
+
+    return -1;
+  }
+
+  return 0;
 }
 
 /* save changes and close mailbox */
-int mx_close_mailbox (CONTEXT *ctx, int *index_hint)
+static int _mx_close_mailbox (CONTEXT * ctx, int *index_hint)
 {
   int i, move_messages = 0, purge = 1, read_msgs = 0;
   int check;
@@ -945,13 +662,13 @@ int mx_close_mailbox (CONTEXT *ctx, int *index_hint)
   char mbox[_POSIX_PATH_MAX];
   char buf[SHORT_STRING];
 
-  if (!ctx) return 0;
+  if (!ctx)
+    return 0;
 
   ctx->closing = 1;
 
 #ifdef USE_NNTP
-  if (ctx->magic == M_NNTP)
-  {
+  if (ctx->magic == M_NNTP) {
     int ret;
 
     ret = nntp_close_mailbox (ctx);
@@ -959,15 +676,13 @@ int mx_close_mailbox (CONTEXT *ctx, int *index_hint)
     return ret;
   }
 #endif
-  if (ctx->readonly || ctx->dontwrite)
-  {
+  if (ctx->readonly || ctx->dontwrite) {
     /* mailbox is readonly or we don't want to write */
     mx_fastclose_mailbox (ctx);
     return 0;
   }
 
-  if (ctx->append)
-  {
+  if (ctx->append) {
     /* mailbox was opened in write-mode */
     if (ctx->magic == M_MBOX || ctx->magic == M_MMDF)
       mbox_close_mailbox (ctx);
@@ -976,36 +691,30 @@ int mx_close_mailbox (CONTEXT *ctx, int *index_hint)
     return 0;
   }
 
-  for (i = 0; i < ctx->msgcount; i++)
-  {
-    if (!ctx->hdrs[i]->deleted && ctx->hdrs[i]->read 
+  for (i = 0; i < ctx->msgcount; i++) {
+    if (!ctx->hdrs[i]->deleted && ctx->hdrs[i]->read
         && !(ctx->hdrs[i]->flagged && option (OPTKEEPFLAGGED)))
       read_msgs++;
   }
 
-  if (read_msgs && quadoption (OPT_MOVE) != M_NO)
-  {
+  if (read_msgs && quadoption (OPT_MOVE) != M_NO) {
     char *p;
 
-    if ((p = mutt_find_hook (M_MBOXHOOK, ctx->path)))
-    {
+    if ((p = mutt_find_hook (M_MBOXHOOK, ctx->path))) {
       isSpool = 1;
-      strfcpy (mbox, p, sizeof (mbox));
+      m_strcpy(mbox, sizeof(mbox), p);
     }
-    else
-    {
-      strfcpy (mbox, NONULL(Inbox), sizeof (mbox));
+    else {
+      m_strcpy(mbox, sizeof(mbox), NONULL(Inbox));
       isSpool = mutt_is_spool (ctx->path) && !mutt_is_spool (mbox);
     }
     mutt_expand_path (mbox, sizeof (mbox));
 
-    if (isSpool)
-    {
+    if (isSpool) {
       snprintf (buf, sizeof (buf), _("Move read messages to %s?"), mbox);
-      if ((move_messages = query_quadoption (OPT_MOVE, buf)) == -1)
-      {
-       ctx->closing = 0;
-       return (-1);
+      if ((move_messages = query_quadoption (OPT_MOVE, buf)) == -1) {
+        ctx->closing = 0;
+        return (-1);
       }
     }
   }
@@ -1014,165 +723,148 @@ int mx_close_mailbox (CONTEXT *ctx, int *index_hint)
    * There is no point in asking whether or not to purge if we are
    * just marking messages as "trash".
    */
-  if (ctx->deleted && !(ctx->magic == M_MAILDIR && option (OPTMAILDIRTRASH)))
-  {
+  if (ctx->deleted && !(ctx->magic == M_MAILDIR && option (OPTMAILDIRTRASH))) {
     snprintf (buf, sizeof (buf), ctx->deleted == 1
-            ? _("Purge %d deleted message?") : _("Purge %d deleted messages?"),
-             ctx->deleted);
-    if ((purge = query_quadoption (OPT_DELETE, buf)) < 0)
-    {
+              ? _("Purge %d deleted message?") :
+              _("Purge %d deleted messages?"), ctx->deleted);
+    if ((purge = query_quadoption (OPT_DELETE, buf)) < 0) {
       ctx->closing = 0;
       return (-1);
     }
   }
 
-#ifdef USE_IMAP
   /* IMAP servers manage the OLD flag themselves */
   if (ctx->magic != M_IMAP)
-#endif
-  if (option (OPTMARKOLD))
-  {
-    for (i = 0; i < ctx->msgcount; i++)
-    {
-      if (!ctx->hdrs[i]->deleted && !ctx->hdrs[i]->old)
-       mutt_set_flag (ctx, ctx->hdrs[i], M_OLD, 1);
+    if (option (OPTMARKOLD)) {
+      for (i = 0; i < ctx->msgcount; i++) {
+        if (!ctx->hdrs[i]->deleted && !ctx->hdrs[i]->old)
+          mutt_set_flag (ctx, ctx->hdrs[i], M_OLD, 1);
+      }
     }
-  }
 
-  if (move_messages)
-  {
+  if (move_messages) {
     mutt_message (_("Moving read messages to %s..."), mbox);
 
-#ifdef USE_IMAP
     /* try to use server-side copy first */
     i = 1;
-    
-    if (ctx->magic == M_IMAP && mx_is_imap (mbox))
-    {
+
+    if (ctx->magic == M_IMAP && imap_is_magic (mbox, NULL) == M_IMAP) {
       /* tag messages for moving, and clear old tags, if any */
       for (i = 0; i < ctx->msgcount; i++)
-       if (ctx->hdrs[i]->read && !ctx->hdrs[i]->deleted
-            && !(ctx->hdrs[i]->flagged && option (OPTKEEPFLAGGED))) 
-         ctx->hdrs[i]->tagged = 1;
-       else
-         ctx->hdrs[i]->tagged = 0;
-      
+        if (ctx->hdrs[i]->read && !ctx->hdrs[i]->deleted
+            && !(ctx->hdrs[i]->flagged && option (OPTKEEPFLAGGED)))
+          ctx->hdrs[i]->tagged = 1;
+        else
+          ctx->hdrs[i]->tagged = 0;
+
       i = imap_copy_messages (ctx, NULL, mbox, 1);
     }
-    
-    if (i == 0) /* success */
+
+    if (i == 0)                 /* success */
       mutt_clear_error ();
-    else if (i == -1) /* horrible error, bail */
-    {
-      ctx->closing=0;
+    else if (i == -1) {         /* horrible error, bail */
+      ctx->closing = 0;
       return -1;
     }
-    else /* use regular append-copy mode */
-#endif
+    else                        /* use regular append-copy mode */
     {
-      if (mx_open_mailbox (mbox, M_APPEND, &f) == NULL)
-      {
-       ctx->closing = 0;
-       return -1;
+      if (mx_open_mailbox (mbox, M_APPEND, &f) == NULL) {
+        ctx->closing = 0;
+        return -1;
       }
 
-      for (i = 0; i < ctx->msgcount; i++)
-      {
-       if (ctx->hdrs[i]->read && !ctx->hdrs[i]->deleted
-            && !(ctx->hdrs[i]->flagged && option (OPTKEEPFLAGGED)))
-        {
-         if (mutt_append_message (&f, ctx, ctx->hdrs[i], 0, CH_UPDATE_LEN) == 0)
-         {
-           mutt_set_flag (ctx, ctx->hdrs[i], M_DELETE, 1);
-           mutt_set_flag (ctx, ctx->hdrs[i], M_APPENDED, 1);
-         }
-         else
-         {
-           mx_close_mailbox (&f, NULL);
-           ctx->closing = 0;
-           return -1;
-         }
-       }
+      for (i = 0; i < ctx->msgcount; i++) {
+        if (ctx->hdrs[i]->read && !ctx->hdrs[i]->deleted
+            && !(ctx->hdrs[i]->flagged && option (OPTKEEPFLAGGED))) {
+          if (mutt_append_message (&f, ctx, ctx->hdrs[i], 0, CH_UPDATE_LEN) ==
+              0) {
+            mutt_set_flag (ctx, ctx->hdrs[i], M_DELETE, 1);
+            mutt_set_flag (ctx, ctx->hdrs[i], M_APPENDED, 1);
+          }
+          else {
+            mx_close_mailbox (&f, NULL);
+            ctx->closing = 0;
+            return -1;
+          }
+        }
       }
-    
+
       mx_close_mailbox (&f, NULL);
     }
-    
+
   }
-  else if (!ctx->changed && ctx->deleted == 0)
-  {
+  else if (!ctx->changed && ctx->deleted == 0) {
     mutt_message _("Mailbox is unchanged.");
+
     mx_fastclose_mailbox (ctx);
     return 0;
   }
-  
+
   /* copy mails to the trash before expunging */
   if (purge && ctx->deleted)
-    if (trash_append (ctx) != 0)
-    {
+    if (trash_append (ctx) != 0) {
       ctx->closing = 0;
       return -1;
     }
 
-#ifdef USE_IMAP
   /* allow IMAP to preserve the deleted flag across sessions */
-  if (ctx->magic == M_IMAP)
-  {
-    if ((check = imap_sync_mailbox (ctx, purge, index_hint)) != 0)
-    {
+  if (ctx->magic == M_IMAP) {
+    if ((check = imap_sync_mailbox (ctx, purge, index_hint)) != 0) {
       ctx->closing = 0;
       return check;
     }
   }
   else
-#endif
   {
-    if (!purge)
-    {
+    if (!purge) {
       for (i = 0; i < ctx->msgcount; i++)
         ctx->hdrs[i]->deleted = 0;
       ctx->deleted = 0;
     }
 
-    if (ctx->changed || ctx->deleted)
-    {
-      if ((check = sync_mailbox (ctx, index_hint)) != 0)
-      {
-       ctx->closing = 0;
-       return check;
+    if (ctx->changed || ctx->deleted) {
+      if ((check = sync_mailbox (ctx, index_hint)) != 0) {
+        ctx->closing = 0;
+        return check;
       }
     }
   }
 
   if (move_messages)
-     mutt_message (_("%d kept, %d moved, %d deleted."),
-       ctx->msgcount - ctx->deleted, read_msgs, ctx->deleted);
+    mutt_message (_("%d kept, %d moved, %d deleted."),
+                  ctx->msgcount - ctx->deleted, read_msgs, ctx->deleted);
   else
     mutt_message (_("%d kept, %d deleted."),
-      ctx->msgcount - ctx->deleted, ctx->deleted);
+                  ctx->msgcount - ctx->deleted, ctx->deleted);
 
   if (ctx->msgcount == ctx->deleted &&
       (ctx->magic == M_MMDF || ctx->magic == M_MBOX) &&
-      !mutt_is_spool(ctx->path) && !option (OPTSAVEEMPTY))
+      !mutt_is_spool (ctx->path) && !option (OPTSAVEEMPTY))
     mx_unlink_empty (ctx->path);
 
-#ifdef USE_COMPRESSED
   if (ctx->compressinfo && mutt_slow_close_compressed (ctx))
     return (-1);
-#endif
 
   mx_fastclose_mailbox (ctx);
 
   return 0;
 }
 
+int mx_close_mailbox (CONTEXT * ctx, int *index_hint) {
+  int ret = 0;
+  if (!ctx)
+    return (0);
+  ret = _mx_close_mailbox (ctx, index_hint);
+  sidebar_set_buffystats (ctx);
+  return (ret);
+}
 
 /* update a Context structure's internal tables. */
 
-void mx_update_tables(CONTEXT *ctx, int committing)
+void mx_update_tables (CONTEXT * ctx, int committing)
 {
   int i, j;
-  
+
   /* update memory to reflect the new state of the mailbox */
   ctx->vcount = 0;
   ctx->vsize = 0;
@@ -1183,66 +875,67 @@ void mx_update_tables(CONTEXT *ctx, int committing)
   ctx->changed = 0;
   ctx->flagged = 0;
 #define this_body ctx->hdrs[j]->content
-  for (i = 0, j = 0; i < ctx->msgcount; i++)
-  {
-    if ((committing && (!ctx->hdrs[i]->deleted || 
-                       (ctx->magic == M_MAILDIR && option (OPTMAILDIRTRASH)))) ||
-       (!committing && ctx->hdrs[i]->active))
-    {
-      if (i != j)
-      {
-       ctx->hdrs[j] = ctx->hdrs[i];
-       ctx->hdrs[i] = NULL;
+  for (i = 0, j = 0; i < ctx->msgcount; i++) {
+    if ((committing && (!ctx->hdrs[i]->deleted ||
+                        (ctx->magic == M_MAILDIR
+                         && option (OPTMAILDIRTRASH)))) || (!committing
+                                                            && ctx->hdrs[i]->
+                                                            active)) {
+      if (i != j) {
+        ctx->hdrs[j] = ctx->hdrs[i];
+        ctx->hdrs[i] = NULL;
       }
       ctx->hdrs[j]->msgno = j;
-      if (ctx->hdrs[j]->virtual != -1)
-      {
-       ctx->v2r[ctx->vcount] = j;
-       ctx->hdrs[j]->virtual = ctx->vcount++;
-       ctx->vsize += this_body->length + this_body->offset -
-         this_body->hdr_offset;
+      if (ctx->hdrs[j]->virtual != -1) {
+        ctx->v2r[ctx->vcount] = j;
+        ctx->hdrs[j]->virtual = ctx->vcount++;
+        ctx->vsize += this_body->length + this_body->offset -
+          this_body->hdr_offset;
       }
 
       if (committing)
-       ctx->hdrs[j]->changed = 0;
+        ctx->hdrs[j]->changed = 0;
       else if (ctx->hdrs[j]->changed)
-       ctx->changed++;
-      
-      if (!committing || (ctx->magic == M_MAILDIR && option (OPTMAILDIRTRASH)))
-      {
-       if (ctx->hdrs[j]->deleted)
-         ctx->deleted++;
+        ctx->changed++;
+
+      if (!committing
+          || (ctx->magic == M_MAILDIR && option (OPTMAILDIRTRASH))) {
+        if (ctx->hdrs[j]->deleted)
+          ctx->deleted++;
       }
 
       if (ctx->hdrs[j]->tagged)
-       ctx->tagged++;
+        ctx->tagged++;
       if (ctx->hdrs[j]->flagged)
-       ctx->flagged++;
-      if (!ctx->hdrs[j]->read)
-      { 
-       ctx->unread++;
-       if (!ctx->hdrs[j]->old)
-         ctx->new++;
-      } 
+        ctx->flagged++;
+      if (!ctx->hdrs[j]->read) {
+        ctx->unread++;
+        if (!ctx->hdrs[j]->old)
+          ctx->new++;
+      }
 
       j++;
     }
-    else
-    {
+    else {
       if (ctx->magic == M_MH || ctx->magic == M_MAILDIR)
-       ctx->size -= (ctx->hdrs[i]->content->length +
-                     ctx->hdrs[i]->content->offset -
-                     ctx->hdrs[i]->content->hdr_offset);
+        ctx->size -= (ctx->hdrs[i]->content->length +
+                      ctx->hdrs[i]->content->offset -
+                      ctx->hdrs[i]->content->hdr_offset);
       /* remove message from the hash tables */
       if (ctx->subj_hash && ctx->hdrs[i]->env->real_subj)
-       hash_delete (ctx->subj_hash, ctx->hdrs[i]->env->real_subj, ctx->hdrs[i], NULL);
+        hash_delete (ctx->subj_hash, ctx->hdrs[i]->env->real_subj,
+                     ctx->hdrs[i], NULL);
       if (ctx->id_hash && ctx->hdrs[i]->env->message_id)
-       hash_delete (ctx->id_hash, ctx->hdrs[i]->env->message_id, ctx->hdrs[i], NULL);
-      mutt_free_header (&ctx->hdrs[i]);
+        hash_delete (ctx->id_hash, ctx->hdrs[i]->env->message_id,
+                     ctx->hdrs[i], NULL);
+      header_delete(&ctx->hdrs[i]);
     }
   }
 #undef this_body
   ctx->msgcount = j;
+
+  /* update sidebar count */
+  sidebar_set_buffystats (ctx);
 }
 
 
@@ -1252,61 +945,57 @@ void mx_update_tables(CONTEXT *ctx, int committing)
  *     0               success
  *     -1              error
  */
-int mx_sync_mailbox (CONTEXT *ctx, int *index_hint)
+static int _mx_sync_mailbox (CONTEXT * ctx, int *index_hint)
 {
   int rc, i;
   int purge = 1;
   int msgcount, deleted;
 
-  if (ctx->dontwrite)
-  {
+  if (ctx->dontwrite) {
     char buf[STRING], tmp[STRING];
-    if (km_expand_key (buf, sizeof(buf),
+
+    if (km_expand_key (buf, sizeof (buf),
                        km_find_func (MENU_MAIN, OP_TOGGLE_WRITE)))
-      snprintf (tmp, sizeof(tmp), _(" Press '%s' to toggle write"), buf);
+      snprintf (tmp, sizeof (tmp), _(" Press '%s' to toggle write"), buf);
     else
-      strfcpy (tmp, _("Use 'toggle-write' to re-enable write!"), sizeof(tmp));
+      m_strcpy(tmp, sizeof(tmp), _("Use 'toggle-write' to re-enable write!"));
 
     mutt_error (_("Mailbox is marked unwritable. %s"), tmp);
     return -1;
   }
-  else if (ctx->readonly)
-  {
+  else if (ctx->readonly) {
     mutt_error _("Mailbox is read-only.");
+
     return -1;
   }
 
-  if (!ctx->changed && !ctx->deleted)
-  {
+  if (!ctx->changed && !ctx->deleted) {
     mutt_message _("Mailbox is unchanged.");
+
     return (0);
   }
 
-  if (ctx->deleted)
-  {
+  if (ctx->deleted) {
     char buf[SHORT_STRING];
 
     snprintf (buf, sizeof (buf), ctx->deleted == 1
-            ? _("Purge %d deleted message?") : _("Purge %d deleted messages?"),
-             ctx->deleted);
+              ? _("Purge %d deleted message?") :
+              _("Purge %d deleted messages?"), ctx->deleted);
     if ((purge = query_quadoption (OPT_DELETE, buf)) < 0)
       return (-1);
-    else if (purge == M_NO)
-    {
+    else if (purge == M_NO) {
       if (!ctx->changed)
-       return 0; /* nothing to do! */
-#ifdef USE_IMAP
+        return 0;               /* nothing to do! */
       /* let IMAP servers hold on to D flags */
       if (ctx->magic != M_IMAP)
-#endif
       {
-        for (i = 0 ; i < ctx->msgcount ; i++)
+        for (i = 0; i < ctx->msgcount; i++)
           ctx->hdrs[i]->deleted = 0;
         ctx->deleted = 0;
       }
     }
     else if (ctx->last_tag && ctx->last_tag->deleted)
-      ctx->last_tag = NULL; /* reset last tagged msg now useless */
+      ctx->last_tag = NULL;     /* reset last tagged msg now useless */
   }
 
   /* really only for IMAP - imap_sync_mailbox results in a call to
@@ -1314,34 +1003,27 @@ int mx_sync_mailbox (CONTEXT *ctx, int *index_hint)
   msgcount = ctx->msgcount;
   deleted = ctx->deleted;
 
-  if (purge && ctx->deleted)
-  {
+  if (purge && ctx->deleted) {
     if (trash_append (ctx) == -1)
       return -1;
-  } 
+  }
 
-#ifdef USE_IMAP
   if (ctx->magic == M_IMAP)
     rc = imap_sync_mailbox (ctx, purge, index_hint);
   else
-#endif
     rc = sync_mailbox (ctx, index_hint);
-  if (rc == 0)
-  {
-#ifdef USE_IMAP
+  if (rc == 0) {
     if (ctx->magic == M_IMAP && !purge)
-      mutt_message _("Mailbox checkpointed.");
+      mutt_message (_("Mailbox checkpointed."));
+
     else
-#endif
-    mutt_message (_("%d kept, %d deleted."), msgcount - deleted,
-      deleted);
+      mutt_message (_("%d kept, %d deleted."), msgcount - deleted, deleted);
 
     mutt_sleep (0);
-    
+
     if (ctx->msgcount == ctx->deleted &&
-       (ctx->magic == M_MBOX || ctx->magic == M_MMDF) &&
-       !mutt_is_spool (ctx->path) && !option (OPTSAVEEMPTY))
-    {
+        (ctx->magic == M_MBOX || ctx->magic == M_MMDF) &&
+        !mutt_is_spool (ctx->path) && !option (OPTSAVEEMPTY)) {
       unlink (ctx->path);
       mx_fastclose_mailbox (ctx);
       return 0;
@@ -1354,15 +1036,12 @@ int mx_sync_mailbox (CONTEXT *ctx, int *index_hint)
      * MH and maildir are safe.  mbox-style seems to need re-sorting,
      * at least with the new threading code.
      */
-    if (purge || (ctx->magic != M_MAILDIR && ctx->magic != M_MH))
-    {
-#ifdef USE_IMAP
+    if (purge || (ctx->magic != M_MAILDIR && ctx->magic != M_MH)) {
       /* IMAP does this automatically after handling EXPUNGE */
       if (ctx->magic != M_IMAP)
-#endif
       {
-       mx_update_tables (ctx, 1);
-       mutt_sort_headers (ctx, 1); /* rethread from scratch */
+        mx_update_tables (ctx, 1);
+        mutt_sort_headers (ctx, 1);     /* rethread from scratch */
       }
     }
   }
@@ -1370,359 +1049,198 @@ int mx_sync_mailbox (CONTEXT *ctx, int *index_hint)
   return (rc);
 }
 
-
-/* {maildir,mh}_open_new_message are in mh.c. */
-
-int mbox_open_new_message (MESSAGE *msg, CONTEXT *dest, HEADER *hdr)
-{
-  msg->fp = dest->fp;
-  return 0;
+int mx_sync_mailbox (CONTEXT* ctx, int* index_hint) {
+  int ret = _mx_sync_mailbox (ctx, index_hint);
+  sidebar_set_buffystats (ctx);
+  return (ret);
 }
 
-#ifdef USE_IMAP
-int imap_open_new_message (MESSAGE *msg, CONTEXT *dest, HEADER *hdr)
-{
-  char tmp[_POSIX_PATH_MAX];
-
-  mutt_mktemp(tmp);
-  if ((msg->fp = safe_fopen (tmp, "w")) == NULL)
-    return (-1);
-  msg->path = safe_strdup(tmp);
-  return 0;
-}
-#endif
-
 /* args:
  *     dest    destintation mailbox
  *     hdr     message being copied (required for maildir support, because
  *             the filename depends on the message flags)
  */
-MESSAGE *mx_open_new_message (CONTEXT *dest, HEADER *hdr, int flags)
+MESSAGE *mx_open_new_message (CONTEXT * dest, HEADER * hdr, int flags)
 {
   MESSAGE *msg;
-  int (*func) (MESSAGE *, CONTEXT *, HEADER *);
-  ADDRESS *p = NULL;
+  address_t *p = NULL;
 
-  switch (dest->magic)
-  {
-    case M_MMDF:
-    case M_MBOX:
-      func = mbox_open_new_message;
-      break;
-    case M_MAILDIR:
-      func = maildir_open_new_message;
-      break;
-    case M_MH:
-      func = mh_open_new_message;
-      break;
-#ifdef USE_IMAP
-    case M_IMAP:
-      func = imap_open_new_message;
-      break;
-#endif
-    default:
-      dprint (1, (debugfile, "mx_open_new_message(): function unimplemented for mailbox type %d.\n",
-                 dest->magic));
-      return (NULL);
+  if (!MX_IDX(dest->magic-1)) {
+    return (NULL);
   }
 
-  msg = safe_calloc (1, sizeof (MESSAGE));
+  msg = p_new(MESSAGE, 1);
   msg->magic = dest->magic;
   msg->write = 1;
 
-  if (hdr)
-  {
+  if (hdr) {
     msg->flags.flagged = hdr->flagged;
     msg->flags.replied = hdr->replied;
-    msg->flags.read    = hdr->read;
+    msg->flags.read = hdr->read;
     msg->received = hdr->received;
   }
 
-  if(msg->received == 0)
-    time(&msg->received);
-  
-  if (func (msg, dest, hdr) == 0)
-  {
+  if (msg->received == 0)
+    time (&msg->received);
+
+  if (MX_COMMAND(dest->magic-1,mx_open_new_message)(msg, dest, hdr) == 0) {
     if (dest->magic == M_MMDF)
       fputs (MMDF_SEP, msg->fp);
 
-    if ((msg->magic == M_MBOX || msg->magic ==  M_MMDF) &&
-       flags & M_ADD_FROM)
-    {
-      if (hdr)
-      {
-       if (hdr->env->return_path)
-         p = hdr->env->return_path;
-       else if (hdr->env->sender)
-         p = hdr->env->sender;
-       else
-         p = hdr->env->from;
+    if ((msg->magic == M_MBOX || msg->magic == M_MMDF) && flags & M_ADD_FROM) {
+      if (hdr) {
+        if (hdr->env->return_path)
+          p = hdr->env->return_path;
+        else if (hdr->env->sender)
+          p = hdr->env->sender;
+        else
+          p = hdr->env->from;
       }
 
-      fprintf (msg->fp, "From %s %s", p ? p->mailbox : NONULL(Username), ctime (&msg->received));
+      fprintf (msg->fp, "From %s %s", p ? p->mailbox : NONULL (Username),
+               ctime (&msg->received));
     }
   }
   else
-    FREE (&msg);
+    p_delete(&msg);
 
   return msg;
 }
 
 /* check for new mail */
-int mx_check_mailbox (CONTEXT *ctx, int *index_hint, int lock)
-{
-  int rc;
-
-#ifdef USE_COMPRESSED
+int mx_check_mailbox (CONTEXT * ctx, int *index_hint, int lock) {
   if (ctx->compressinfo)
     return mutt_check_mailbox_compressed (ctx);
-#endif
-
-  if (ctx)
-  {
-    if (ctx->locked) lock = 0;
 
-    switch (ctx->magic)
-    {
-      case M_MBOX:
-      case M_MMDF:
-
-       if (lock)
-       {
-         mutt_block_signals ();
-         if (mbox_lock_mailbox (ctx, 0, 0) == -1)
-         {
-           mutt_unblock_signals ();
-           return M_LOCKED;
-         }
-       }
-       
-       rc = mbox_check_mailbox (ctx, index_hint);
-
-       if (lock)
-       {
-         mutt_unblock_signals ();
-         mbox_unlock_mailbox (ctx);
-       }
-       
-       return rc;
-
-
-      case M_MH:
-       return (mh_check_mailbox (ctx, index_hint));
-      case M_MAILDIR:
-       return (maildir_check_mailbox (ctx, index_hint));
-
-#ifdef USE_IMAP
-      case M_IMAP:
-       return (imap_check_mailbox (ctx, index_hint, 0));
-#endif /* USE_IMAP */
-
-#ifdef USE_POP
-      case M_POP:
-       return (pop_check_mailbox (ctx, index_hint));
-#endif /* USE_POP */
-
-#ifdef USE_NNTP
-      case M_NNTP:
-       return (nntp_check_mailbox (ctx));
-#endif /* USE_NNTP */
-    }
+  if (ctx) {
+    if (ctx->locked)
+      lock = 0;
+    if (MX_IDX(ctx->magic-1) && MX_COMMAND(ctx->magic-1,mx_check_mailbox))
+      return (MX_COMMAND(ctx->magic-1,mx_check_mailbox)(ctx, index_hint, lock));
   }
 
-  dprint (1, (debugfile, "mx_check_mailbox: null or invalid context.\n"));
   return (-1);
 }
 
 /* return a stream pointer for a message */
-MESSAGE *mx_open_message (CONTEXT *ctx, int msgno)
+MESSAGE *mx_open_message (CONTEXT * ctx, int msgno)
 {
   MESSAGE *msg;
-  
-  msg = safe_calloc (1, sizeof (MESSAGE));
-  switch (msg->magic = ctx->magic)
-  {
-    case M_MBOX:
-    case M_MMDF:
-      msg->fp = ctx->fp;
-      break;
 
-    case M_MH:
-    case M_MAILDIR:
+  msg = p_new(MESSAGE, 1);
+  switch (msg->magic = ctx->magic) {
+  case M_MBOX:
+  case M_MMDF:
+    msg->fp = ctx->fp;
+    break;
+
+  case M_MH:
+  case M_MAILDIR:
     {
       HEADER *cur = ctx->hdrs[msgno];
       char path[_POSIX_PATH_MAX];
-      
+
       snprintf (path, sizeof (path), "%s/%s", ctx->path, cur->path);
-      
+
       if ((msg->fp = fopen (path, "r")) == NULL && errno == ENOENT &&
-         ctx->magic == M_MAILDIR)
-       msg->fp = maildir_open_find_message (ctx->path, cur->path);
-      
-      if (msg->fp == NULL)
-      {
-       mutt_perror (path);
-       dprint (1, (debugfile, "mx_open_message: fopen: %s: %s (errno %d).\n",
-                   path, strerror (errno), errno));
-       FREE (&msg);
+          ctx->magic == M_MAILDIR)
+        msg->fp = maildir_open_find_message (ctx->path, cur->path);
+
+      if (msg->fp == NULL) {
+        mutt_perror (path);
+        p_delete(&msg);
       }
     }
     break;
-    
-#ifdef USE_IMAP
-    case M_IMAP:
+
+  case M_IMAP:
     {
       if (imap_fetch_message (msg, ctx, msgno) != 0)
-       FREE (&msg);
+        p_delete(&msg);
       break;
     }
-#endif /* USE_IMAP */
 
-#ifdef USE_POP
-    case M_POP:
+  case M_POP:
     {
       if (pop_fetch_message (msg, ctx, msgno) != 0)
-       FREE (&msg);
+        p_delete(&msg);
       break;
     }
-#endif /* USE_POP */
 
 #ifdef USE_NNTP
-    case M_NNTP:
+  case M_NNTP:
     {
       if (nntp_fetch_message (msg, ctx, msgno) != 0)
-       FREE (&msg);
+        p_delete(&msg);
       break;
     }
 #endif /* USE_NNTP */
 
-    default:
-      dprint (1, (debugfile, "mx_open_message(): function not implemented for mailbox type %d.\n", ctx->magic));
-      FREE (&msg);
-      break;
+  default:
+    p_delete(&msg);
+    break;
   }
   return (msg);
 }
 
 /* commit a message to a folder */
 
-int mx_commit_message (MESSAGE *msg, CONTEXT *ctx)
-{
-  int r = 0;
-
-  if (!(msg->write && ctx->append))
-  {
-    dprint (1, (debugfile, "mx_commit_message(): msg->write = %d, ctx->append = %d\n",
-               msg->write, ctx->append));
+int mx_commit_message (MESSAGE * msg, CONTEXT * ctx) {
+  if (!(msg->write && ctx->append)) {
     return -1;
   }
-
-  switch (msg->magic)
-  {
-    case M_MMDF:
-    {
-      if (fputs (MMDF_SEP, msg->fp) == EOF)
-       r = -1;
-      break;
-    }
-    
-    case M_MBOX:
-    {
-      if (fputc ('\n', msg->fp) == EOF)
-       r = -1;
-      break;
-    }
-
-#ifdef USE_IMAP
-    case M_IMAP:
-    {
-      if ((r = safe_fclose (&msg->fp)) == 0)
-       r = imap_append_message (ctx, msg);
-      break;
-    }
-#endif
-    
-    case M_MAILDIR:
-    {
-      r = maildir_commit_message (ctx, msg, NULL);
-      break;
-    }
-    
-    case M_MH:
-    {
-      r = mh_commit_message (ctx, msg, NULL);
-      break;
-    }
-  }
-  
-  if (r == 0 && (ctx->magic == M_MBOX || ctx->magic == M_MMDF)
-      && (fflush (msg->fp) == EOF || fsync (fileno (msg->fp)) == -1))
-  {
-    mutt_perror _("Can't write message");
-    r = -1;
-  }
-  return r;
+  if (!ctx || !MX_IDX(ctx->magic-1) || !MX_COMMAND(ctx->magic-1,mx_commit_message))
+    return (-1);
+  return (MX_COMMAND(ctx->magic-1,mx_commit_message) (msg, ctx));
 }
 
 /* close a pointer to a message */
-int mx_close_message (MESSAGE **msg)
+int mx_close_message (MESSAGE ** msg)
 {
   int r = 0;
 
   if ((*msg)->magic == M_MH || (*msg)->magic == M_MAILDIR
-#ifdef USE_IMAP
       || (*msg)->magic == M_IMAP
-#endif
-#ifdef USE_POP
       || (*msg)->magic == M_POP
-#endif
 #ifdef USE_NNTP
       || (*msg)->magic == M_NNTP
 #endif
-      )
-  {
+    ) {
     r = safe_fclose (&(*msg)->fp);
   }
   else
     (*msg)->fp = NULL;
 
-  if ((*msg)->path)
-  {
-    dprint (1, (debugfile, "mx_close_message (): unlinking %s\n",
-               (*msg)->path));
+  if ((*msg)->path) {
     unlink ((*msg)->path);
-    FREE (&(*msg)->path);
+    p_delete(&(*msg)->path);
   }
 
-  FREE (msg);
+  p_delete(msg);
   return (r);
 }
 
-void mx_alloc_memory (CONTEXT *ctx)
+void mx_alloc_memory (CONTEXT * ctx)
 {
   int i;
   size_t s = MAX (sizeof (HEADER *), sizeof (int));
-  
-  if ((ctx->hdrmax + 25) * s < ctx->hdrmax * s)
-  {
+
+  if ((ctx->hdrmax + 25) * s < ctx->hdrmax * s) {
     mutt_error _("Integer overflow -- can't allocate memory.");
+
     sleep (1);
     mutt_exit (1);
   }
-  
-  if (ctx->hdrs)
-  {
-    safe_realloc (&ctx->hdrs, sizeof (HEADER *) * (ctx->hdrmax += 25));
-    safe_realloc (&ctx->v2r, sizeof (int) * ctx->hdrmax);
+
+  if (ctx->hdrs) {
+    p_realloc(&ctx->hdrs, ctx->hdrmax += 25);
+    p_realloc(&ctx->v2r, ctx->hdrmax);
   }
-  else
-  {
-    ctx->hdrs = safe_calloc ((ctx->hdrmax += 25), sizeof (HEADER *));
-    ctx->v2r = safe_calloc (ctx->hdrmax, sizeof (int));
+  else {
+    ctx->hdrs = p_new(HEADER *, (ctx->hdrmax += 25));
+    ctx->v2r = p_new(int, ctx->hdrmax);
   }
-  for (i = ctx->msgcount ; i < ctx->hdrmax ; i++)
-  {
+  for (i = ctx->msgcount; i < ctx->hdrmax; i++) {
     ctx->hdrs[i] = NULL;
     ctx->v2r[i] = -1;
   }
@@ -1731,23 +1249,18 @@ void mx_alloc_memory (CONTEXT *ctx)
 /* this routine is called to update the counts in the context structure for
  * the last message header parsed.
  */
-void mx_update_context (CONTEXT *ctx, int new_messages)
+void mx_update_context (CONTEXT * ctx, int new_messages)
 {
   HEADER *h;
   int msgno;
 
-  for (msgno = ctx->msgcount - new_messages; msgno < ctx->msgcount; msgno++)
-  {
+  for (msgno = ctx->msgcount - new_messages; msgno < ctx->msgcount; msgno++) {
     h = ctx->hdrs[msgno];
 
-    if (WithCrypto)
-    {
-      /* NOTE: this _must_ be done before the check for mailcap! */
-      h->security = crypt_query (h->content);
-    }
+    /* NOTE: this _must_ be done before the check for mailcap! */
+    h->security = crypt_query (h->content);
 
-    if (!ctx->pattern)
-    {
+    if (!ctx->pattern) {
       ctx->v2r[ctx->vcount] = msgno;
       h->virtual = ctx->vcount++;
     }
@@ -1755,32 +1268,32 @@ void mx_update_context (CONTEXT *ctx, int new_messages)
       h->virtual = -1;
     h->msgno = msgno;
 
-    if (h->env->supersedes)
-    {
+    if (h->env->supersedes) {
       HEADER *h2;
 
-      if (!ctx->id_hash)       
-       ctx->id_hash = mutt_make_id_hash (ctx);
+      if (!ctx->id_hash)
+        ctx->id_hash = mutt_make_id_hash (ctx);
 
       h2 = hash_find (ctx->id_hash, h->env->supersedes);
 
-      /* FREE (&h->env->supersedes); should I ? */
-      if (h2)
-      {
-       h2->superseded = 1;
-       if (option (OPTSCORE)) 
-         mutt_score_message (ctx, h2, 1);
+      /* p_delete(&h->env->supersedes); should I ? */
+      if (h2) {
+        h2->superseded = 1;
+        if (!ctx->counting && option (OPTSCORE))
+          mutt_score_message (ctx, h2, 1);
       }
     }
 
     /* add this message to the hash tables */
     if (ctx->id_hash && h->env->message_id)
       hash_insert (ctx->id_hash, h->env->message_id, h, 0);
-    if (ctx->subj_hash && h->env->real_subj)
-      hash_insert (ctx->subj_hash, h->env->real_subj, h, 1);
+    if (!ctx->counting) {
+      if (ctx->subj_hash && h->env->real_subj)
+        hash_insert (ctx->subj_hash, h->env->real_subj, h, 1);
 
-    if (option (OPTSCORE)) 
-      mutt_score_message (ctx, h, 0);
+      if (option (OPTSCORE))
+        mutt_score_message (ctx, h, 0);
+    }
 
     if (h->changed)
       ctx->changed = 1;
@@ -1788,13 +1301,14 @@ void mx_update_context (CONTEXT *ctx, int new_messages)
       ctx->flagged++;
     if (h->deleted)
       ctx->deleted++;
-    if (!h->read)
-    {
+    if (!h->read) {
       ctx->unread++;
       if (!h->old)
-       ctx->new++;
+        ctx->new++;
     }
   }
+  /* update sidebar count */
+  sidebar_set_buffystats (ctx);
 }
 
 /*
@@ -1805,18 +1319,91 @@ void mx_update_context (CONTEXT *ctx, int new_messages)
  */
 int mx_check_empty (const char *path)
 {
-  switch (mx_get_magic (path))
-  {
-    case M_MBOX:
-    case M_MMDF:
-      return mbox_check_empty (path);
-    case M_MH:
-      return mh_check_empty (path);
-    case M_MAILDIR:
-      return maildir_check_empty (path);
-    default:
-      errno = EINVAL;
-      return -1;
+  int i = 0;
+  if ((i = mx_get_idx (path)) >= 0 && MX_COMMAND(i,mx_check_empty))
+    return (MX_COMMAND(i,mx_check_empty)(path));
+  errno = EINVAL;
+  return (-1);
+}
+
+int mx_acl_check (CONTEXT* ctx, int flag) {
+  if (!ctx || !MX_IDX(ctx->magic-1))
+    return (0);
+  /* if no acl_check defined for module, assume permission is granted */
+  if (!MX_COMMAND(ctx->magic-1,mx_acl_check))
+    return (1);
+  return (MX_COMMAND(ctx->magic-1,mx_acl_check)(ctx,flag));
+}
+
+void mx_init (void) {
+  list_push_back (&MailboxFormats, (void*) mbox_reg_mx ());
+  list_push_back (&MailboxFormats, (void*) mmdf_reg_mx ());
+  list_push_back (&MailboxFormats, (void*) mh_reg_mx ());
+  list_push_back (&MailboxFormats, (void*) maildir_reg_mx ());
+  list_push_back (&MailboxFormats, (void*) imap_reg_mx ());
+  list_push_back (&MailboxFormats, (void*) pop_reg_mx ());
+#ifdef USE_NNTP
+  list_push_back (&MailboxFormats, (void*) nntp_reg_mx ());
+#endif
+  list_push_back (&MailboxFormats, (void*) compress_reg_mx ());
+}
+
+int mx_rebuild_cache (void) {
+#ifndef USE_HCACHE
+  mutt_error (_("Support for header caching was not build in."));
+  return (1);
+#else
+  int i = 0, magic = 0;
+  CONTEXT* ctx = NULL;
+  BUFFY* b = NULL;
+
+  if (list_empty(Incoming)) {
+    mutt_error (_("No mailboxes defined."));
+    return (1);
+  }
+
+  for (i = 0; i < Incoming->length; i++) {
+    b = (BUFFY*) Incoming->data[i];
+    magic = mx_get_magic (b->path);
+    if (magic != M_MAILDIR && magic != M_MH && magic != M_IMAP)
+      continue;
+    sidebar_set_current (b->path);
+    sidebar_draw ();
+    if ((ctx = mx_open_mailbox (b->path,
+                                M_READONLY | M_NOSORT | M_COUNT,
+                                NULL)) != NULL)
+      mx_close_mailbox (ctx, 0);
   }
-  /* not reached */
+  mutt_clear_error ();
+
+  if (Context && Context->path)
+    sidebar_set_current (Context->path);
+  sidebar_draw ();
+
+  return (0);
+#endif
+}
+
+void mutt_parse_mime_message (CONTEXT * ctx, HEADER * cur)
+{
+  MESSAGE *msg;
+  int flags = 0;
+
+  do {
+    if (cur->content->type != TYPEMESSAGE
+        && cur->content->type != TYPEMULTIPART)
+      break;                     /* nothing to do */
+
+    if (cur->content->parts)
+      break;                     /* The message was parsed earlier. */
+
+    if ((msg = mx_open_message (ctx, cur->msgno))) {
+      mutt_parse_part (msg->fp, cur->content);
+
+      cur->security = crypt_query (cur->content);
+
+      mx_close_message (&msg);
+    }
+  } while (0);
+  mutt_count_body_parts (cur, flags | M_PARTS_RECOUNT);
 }