[mutt] 01/02: New upstream NeoMutt release, 2016-07-23.

Faidon Liambotis paravoid at moszumanska.debian.org
Mon Jul 25 08:46:10 UTC 2016


This is an automated email from the git hooks/post-receive script.

paravoid pushed a commit to branch master
in repository mutt.

commit 74d3ff7a2d3fcf9163b6be2381a2c6d041754573
Author: Faidon Liambotis <paravoid at debian.org>
Date:   Sun Jul 24 21:13:32 2016 +0300

    New upstream NeoMutt release, 2016-07-23.
---
 debian/changelog                                   |     1 +
 ...omutt-20160611.patch => neomutt-20160723.patch} | 52912 ++++++++++---------
 debian/patches/series                              |     3 +-
 debian/patches/upstream/fix-version-sh.patch       |    15 -
 4 files changed, 27595 insertions(+), 25336 deletions(-)

diff --git a/debian/changelog b/debian/changelog
index 4296a28..b4db57d 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,6 +1,7 @@
 mutt (1.6.2-1) UNRELEASED; urgency=medium
 
   * New upstream release.
+  * New upstream NeoMutt release, 2016-07-23.
   * Ship our patched Muttrc instead of the stock, non-generated Muttrc,
     something that regressed with 1.6.1-2. (Closes: #830692, #830695)
 
diff --git a/debian/patches/neomutt-20160611.patch b/debian/patches/neomutt-20160723.patch
similarity index 69%
rename from debian/patches/neomutt-20160611.patch
rename to debian/patches/neomutt-20160723.patch
index 9820b96..4547cad 100644
--- a/debian/patches/neomutt-20160611.patch
+++ b/debian/patches/neomutt-20160723.patch
@@ -1,27422 +1,29621 @@
-diff -urN mutt-1.6.1/account.c mutt-1.6.1-neomutt/account.c
---- mutt-1.6.1/account.c	2016-06-12 18:43:00.395447481 +0100
-+++ mutt-1.6.1-neomutt/account.c	2016-06-12 18:43:00.673451816 +0100
-@@ -51,8 +51,17 @@
-     user = PopUser;
- #endif
-   
-+#ifdef USE_NNTP
-+  if (a1->type == M_ACCT_TYPE_NNTP && NntpUser)
-+    user = NntpUser;
-+#endif
+diff --git a/ChangeLog.neomutt b/ChangeLog.neomutt
+new file mode 100644
+index 0000000..d648ab8
+--- /dev/null
++++ b/ChangeLog.neomutt
+@@ -0,0 +1,135 @@
++2016-07-23  Richard Russon  <rich at flatcap.org>
++* New Motto: "Teaching an Old Dog New Tricks"
++  - Thanks to Alok Singh
++* New Features
++  - New Mail Command - Execute a command on receipt of new mail
++  - vim-keybindings - Mutt config for vim users
++  - LMDB: In-memory header caching database
++  - SMIME Encrypt to Self - Secure storage of sensitive email
++* Bug Fixes
++  - rework mutt_draw_statusline()
++  - fix cursor position after sidebar redraw
++  - Add sidebar_format flag '%n' to display 'N' on new mail.
++  - fix index_format truncation problem
++  - Fix compiler warnings due to always true condition
++  - Change sidebar next/prev-new to look at buffy->new too.
++  - Change the default for sidebar_format to use %n.
++  - sidebar "unsorted" order to match Buffy list order.
++  - Include ncurses tinfo library if found.
++  - Sidebar width problem
++  - sidebar crash for non-existent mailbox
++  - Temporary compatibility workaround
++  - Reset buffy->new for the current mailbox in IMAP.
++  - version.sh regression
++  - crash when notmuch tries to read a message
++  - status line wrapping
++* Docs
++  - Mass tidy up of the docs
++  - Fix xml validation
++  - Add missing docs for new features
++* Travis
++  - New build system:
++    https://github.com/neomutt/travis-build
++    Now we have central control over what gets built
++
++2016-07-09  Richard Russon  <rich at flatcap.org>
++* Bug-fixes
++  - This release was a temporary measure
 +
-   if (a1->flags & a2->flags & M_ACCT_USER)
-     return (!strcmp (a1->user, a2->user));
-+#ifdef USE_NNTP
-+  if (a1->type == M_ACCT_TYPE_NNTP)
-+    return a1->flags & M_ACCT_USER && a1->user[0] ? 0 : 1;
-+#endif
-   if (a1->flags & M_ACCT_USER)
-     return (!strcmp (a1->user, user));
-   if (a2->flags & M_ACCT_USER)
-@@ -130,6 +139,16 @@
-   }
- #endif
- 
-+#ifdef USE_NNTP
-+  if (account->type == M_ACCT_TYPE_NNTP)
-+  {
-+    if (account->flags & M_ACCT_SSL)
-+      url->scheme = U_NNTPS;
-+    else
-+      url->scheme = U_NNTP;
-+  }
-+#endif
++2016-06-11  Richard Russon  <rich at flatcap.org>
++* Change in behaviour
++  - Temporarily disable $sidebar_refresh_time
++    Unfortunately, this was causing too many problems.
++    It will be fixed and re-enabled as soon as possible.
++* Bug Fixes
++  - Fix several crashes, on startup, in Keywords
++  - Reflow text now works as it should
++  - Lots of typos fixed
++  - Compress config bug prevented it working
++  - Some minor bug-fixes from mutt/default
++  - Single quote at line beginning misinterpreted by groff
++  - Setting $sidebar_width to more than 128 would cause bad things to happen.
++  - Fix alignment in the compose menu.
++  - Fix sidebar buffy stats updating on mailbox close.
++* Build Changes
++  - Sync whitespace to mutt/default
++  - Alter ChangeLog date format to simplify Makefiles
++  - Use the new notmuch functions that return a status
++  - Rename sidebar functions sb_* -> mutt_sb_*
 +
-   url->host = account->host;
-   if (account->flags & M_ACCT_PORT)
-     url->port = account->port;
-@@ -155,6 +174,10 @@
-   else if ((account->type == M_ACCT_TYPE_POP) && PopUser)
-     strfcpy (account->user, PopUser, sizeof (account->user));
- #endif
-+#ifdef USE_NNTP
-+  else if ((account->type == M_ACCT_TYPE_NNTP) && NntpUser)
-+    strfcpy (account->user, NntpUser, sizeof (account->user));
-+#endif
-   else if (option (OPTNOCURSES))
-     return -1;
-   /* prompt (defaults to unix username), copy into account->user */
-@@ -217,6 +240,10 @@
-   else if ((account->type == M_ACCT_TYPE_SMTP) && SmtpPass)
-     strfcpy (account->pass, SmtpPass, sizeof (account->pass));
- #endif
-+#ifdef USE_NNTP
-+  else if ((account->type == M_ACCT_TYPE_NNTP) && NntpPass)
-+    strfcpy (account->pass, NntpPass, sizeof (account->pass));
-+#endif
-   else if (option (OPTNOCURSES))
-     return -1;
-   else
-diff -urN mutt-1.6.1/account.h mutt-1.6.1-neomutt/account.h
---- mutt-1.6.1/account.h	2016-06-12 18:43:00.395447481 +0100
-+++ mutt-1.6.1-neomutt/account.h	2016-06-12 18:43:00.673451816 +0100
-@@ -29,7 +29,8 @@
-   M_ACCT_TYPE_NONE = 0,
-   M_ACCT_TYPE_IMAP,
-   M_ACCT_TYPE_POP,
--  M_ACCT_TYPE_SMTP
-+  M_ACCT_TYPE_SMTP,
-+  M_ACCT_TYPE_NNTP
- };
- 
- /* account flags */
-diff -urN mutt-1.6.1/alias.c mutt-1.6.1-neomutt/alias.c
---- mutt-1.6.1/alias.c	2016-06-12 18:43:00.396447497 +0100
-+++ mutt-1.6.1-neomutt/alias.c	2016-06-12 18:43:00.673451816 +0100
-@@ -27,6 +27,7 @@
- 
- #include <string.h>
- #include <ctype.h>
-+#include <errno.h>
- 
- ADDRESS *mutt_lookup_alias (const char *s)
- {
-@@ -379,8 +380,10 @@
-     recode_buf (buf, sizeof (buf));
-     write_safe_address (rc, buf);
-     fputc ('\n', rc);
--    safe_fclose (&rc);
--    mutt_message _("Alias added.");
-+    if (safe_fsync_close(&rc) != 0)
-+      mutt_message ("Trouble adding alias: %s.", strerror(errno));
-+    else
-+      mutt_message _("Alias added.");
-   }
-   else
-     mutt_perror (buf);
-diff -urN mutt-1.6.1/attach.c mutt-1.6.1-neomutt/attach.c
---- mutt-1.6.1/attach.c	2016-06-12 18:43:00.396447497 +0100
-+++ mutt-1.6.1-neomutt/attach.c	2016-06-12 18:43:00.673451816 +0100
-@@ -765,7 +765,7 @@
-       fseeko ((s.fpin = fp), m->offset, 0);
-       mutt_decode_attachment (m, &s);
-       
--      if (fclose (s.fpout) != 0)
-+      if (safe_fsync_close (&s.fpout) != 0)
-       {
- 	mutt_perror ("fclose");
- 	mutt_sleep (2);
-@@ -800,7 +800,10 @@
-       return (-1);
-     }
-     safe_fclose (&ofp);
--    safe_fclose (&nfp);
-+    if (safe_fsync_close (&nfp) != 0) {
-+      mutt_error _("Write fault!");
-+      return (-1);
-+    }
-   }
- 
-   return 0;
-@@ -814,6 +817,7 @@
-   unsigned int saved_encoding = 0;
-   BODY *saved_parts = NULL;
-   HEADER *saved_hdr = NULL;
-+  int ret = 0;
- 
-   memset (&s, 0, sizeof (s));
-   s.flags = displaying;
-@@ -871,7 +875,10 @@
- 
-   mutt_body_handler (m, &s);
- 
--  safe_fclose (&s.fpout);
-+  if (safe_fsync_close (&s.fpout) != 0) {
-+    mutt_perror("fclose");
-+    ret = -1;
-+  }
-   if (fp == NULL)
-   {
-     m->length = 0;
-@@ -885,7 +892,7 @@
-     safe_fclose (&s.fpin);
-   }
- 
--  return (0);
-+  return ret;
- }
- 
- /* Ok, the difference between send and receive:
-diff -urN mutt-1.6.1/attach.h mutt-1.6.1-neomutt/attach.h
---- mutt-1.6.1/attach.h	2016-06-12 18:43:00.396447497 +0100
-+++ mutt-1.6.1-neomutt/attach.h	2016-06-12 18:43:00.674451832 +0100
-@@ -50,7 +50,7 @@
- 
- void mutt_attach_bounce (FILE *, HEADER *, ATTACHPTR **, short, BODY *);
- void mutt_attach_resend (FILE *, HEADER *, ATTACHPTR **, short, BODY *);
--void mutt_attach_forward (FILE *, HEADER *, ATTACHPTR **, short, BODY *);
-+void mutt_attach_forward (FILE *, HEADER *, ATTACHPTR **, short, BODY *, int);
- void mutt_attach_reply (FILE *, HEADER *, ATTACHPTR **, short, BODY *, int);
- 
- #endif /* _ATTACH_H_ */
-diff -urN mutt-1.6.1/browser.c mutt-1.6.1-neomutt/browser.c
---- mutt-1.6.1/browser.c	2016-06-12 18:43:00.396447497 +0100
-+++ mutt-1.6.1-neomutt/browser.c	2016-06-12 18:43:00.674451832 +0100
-@@ -29,9 +29,16 @@
- #include "sort.h"
- #include "mailbox.h"
- #include "browser.h"
-+#include "mx.h"
- #ifdef USE_IMAP
- #include "imap.h"
- #endif
-+#ifdef USE_NOTMUCH
-+#include "mutt_notmuch.h"
-+#endif
-+#ifdef USE_NNTP
-+#include "nntp.h"
-+#endif
- 
- #include <stdlib.h>
- #include <dirent.h>
-@@ -50,6 +57,19 @@
-   { NULL,	 0 }
- };
- 
-+#ifdef USE_NNTP
-+static struct mapping_t FolderNewsHelp[] = {
-+  { N_("Exit"),        OP_EXIT },
-+  { N_("List"),        OP_TOGGLE_MAILBOXES },
-+  { N_("Subscribe"),   OP_BROWSER_SUBSCRIBE },
-+  { N_("Unsubscribe"), OP_BROWSER_UNSUBSCRIBE },
-+  { N_("Catchup"),     OP_CATCHUP },
-+  { N_("Mask"),        OP_ENTER_MASK },
-+  { N_("Help"),        OP_HELP },
-+  { NULL,              0 }
-+};
-+#endif
++2016-05-23  Richard Russon  <rich at flatcap.org>
++* New Features:
++  - Keywords: Email Label/Keywords/Tagging
++  - Compress: Compressed mailboxes support
++  - NNTP: Talk to a usenet news server
++  - Separate mappings for <enter> and <return>
++  - New configure option: --enable-quick-build
++  - Various build fixes
 +
- typedef struct folder_t
- {
-   struct folder_file *ff;
-@@ -86,6 +106,16 @@
-   return ((BrowserSort & SORT_REVERSE) ? -r : r);
- }
- 
-+static int browser_compare_desc (const void *a, const void *b)
-+{
-+  struct folder_file *pa = (struct folder_file *) a;
-+  struct folder_file *pb = (struct folder_file *) b;
++2016-05-02  Richard Russon  <rich at flatcap.org>
++* Update for Mutt-1.6.0
++* Bug Fixes:
++  - Build for Notmuch works if Sidebar is disabled
++  - Sidebar functions work even if the Sidebar is hidden
++  - sidebar-next-new, etc, only find *new* mail, as documented
++  - Notmuch supports *very* long queries
 +
-+  int r = mutt_strcoll (pa->desc, pb->desc);
++2016-04-16  Richard Russon  <rich at flatcap.org>
++* Big Bugfix Release
++* Bug Fixes:
++  - Fix crash caused by sidebar_folder_indent
++  - Allow the user to change mailboxes again
++  - Correct sidebar's messages counts
++  - Only sort the sidebar if we're asked to
++  - Fix refresh of pager when toggling the sidebar
++  - Compose mode: make messages respect the TITLE_FMT
++  - Conditional include if sys/syscall.h
++  - Build fix for old compilers
++  - Try harder to keep track of the open mailbox
++* Changes to Features
++  - Allow sidebar_divider_char to be longer
++    (it was limited to one character)
++  - Ignore case when sorting the sidebar alphabetically
++* Other Changes
++  - Numerous small tweaks to the docs
++  - Lots of minor code tidy-ups
++  - Enabling NotMuch now forcibly enables Sidebar
++    (it is dependent on it, for now)
++  - A couple of bug fixes from mutt/stable
 +
-+  return ((BrowserSort & SORT_REVERSE) ? -r : r);
-+}
++2016-04-04  Richard Russon  <rich at flatcap.org>
++* Update for Mutt-1.6.0
++* No other changes in this release
 +
- static int browser_compare_date (const void *a, const void *b)
- {
-   struct folder_file *pa = (struct folder_file *) a;
-@@ -106,6 +136,26 @@
-   return ((BrowserSort & SORT_REVERSE) ? -r : r);
- }
- 
-+static int browser_compare_count (const void *a, const void *b)
-+{
-+  struct folder_file *pa = (struct folder_file *) a;
-+  struct folder_file *pb = (struct folder_file *) b;
++2016-03-28  Richard Russon  <rich at flatcap.org>
++* New Features
++  - skip-quoted          - skip quoted text
++  - limit-current-thread - limit index view to current thread
++* Sidebar Intro - A Gentle Introduction to the Sidebar (with pictures).
 +
-+  int r = pa->all - pb->all;
++2016-03-20  Richard Russon  <rich at flatcap.org>
++* Numerous small bugfixes
++* TravisCI integration
 +
-+  return ((BrowserSort & SORT_REVERSE) ? -r : r);
-+}
++2016-03-17  Richard Russon  <rich at flatcap.org>
++* New Features
++  - notmuch - email search support
++  - ifdef   - improvements
 +
-+static int browser_compare_count_new (const void *a, const void *b)
-+{
-+  struct folder_file *pa = (struct folder_file *) a;
-+  struct folder_file *pb = (struct folder_file *) b;
++2016-03-07  Richard Russon  <rich at flatcap.org>
++* First NeoMutt release
++* List of Features:
++  - bug-fixes    - various bug fixes
++  - cond-date    - use rules to choose date format
++  - fmemopen     - use memory buffers instead of files
++  - ifdef        - conditional config options
++  - index-color  - theme the email index
++  - initials     - expando for author's initials
++  - nested-if    - allow deeply nested conditions
++  - progress     - show a visual progress bar
++  - quasi-delete - mark emails to be hidden
++  - sidebar      - overview of mailboxes
++  - status-color - theming the status bar
++  - tls-sni      - negotiate for a certificate
++  - trash        - move 'deleted' emails to a trash bin
 +
-+  int r = pa->new - pb->new;
+diff --git a/ChangeLog.nntp b/ChangeLog.nntp
+new file mode 100644
+index 0000000..1452e86
+--- /dev/null
++++ b/ChangeLog.nntp
+@@ -0,0 +1,416 @@
++* Wed Apr  6 2016 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.6.0
++- %R changed to %x in format strings
 +
-+  return ((BrowserSort & SORT_REVERSE) ? -r : r);
-+}
++* Wed Nov 25 2015 Vsevolod Volkov <vvv at mutt.org.ua>
++- fixed memory leaks
++- fixed SIGSEGV when reading hcache in some cases
 +
- static void browser_sort (struct browser_state *state)
- {
-   int (*f) (const void *, const void *);
-@@ -115,11 +165,28 @@
-     case SORT_ORDER:
-       return;
-     case SORT_DATE:
-+#ifdef USE_NNTP
-+      if (option (OPTNEWS))
-+	return;
-+#endif
-       f = browser_compare_date;
-       break;
-     case SORT_SIZE:
-+#ifdef USE_NNTP
-+      if (option (OPTNEWS))
-+	return;
-+#endif
-       f = browser_compare_size;
-       break;
-+    case SORT_DESC:
-+      f = browser_compare_desc;
-+      break;
-+    case SORT_COUNT:
-+      f = browser_compare_count;
-+      break;
-+    case SORT_COUNT_NEW:
-+      f = browser_compare_count_new;
-+      break;
-     case SORT_SUBJECT:
-     default:
-       f = browser_compare_subject;
-@@ -192,6 +259,12 @@
-     case 'f':
-     {
-       char *s;
++* Tue Nov 10 2015 Vsevolod Volkov <vvv at mutt.org.ua>
++- fixed error compiling with nntp and without imap or pop3
++- fixed error loading articles after <change-newsgroup> and <quit>
 +
-+#ifdef USE_NOTMUCH
-+      if (mx_is_notmuch(folder->ff->name))
-+        s = NONULL (folder->ff->desc);
-+      else
-+#endif
- #ifdef USE_IMAP
-       if (folder->ff->imap)
- 	s = NONULL (folder->ff->desc);
-@@ -260,7 +333,16 @@
-       else
- 	mutt_format_s (dest, destlen, fmt, "");
-       break;
--      
++* Wed Sep  2 2015 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.5.24
++- new option nntp_listgroup
++- use range in LISTGROUP command if possible
 +
-+    case 'n':
-+      if (!optional) {
-+	snprintf (tmp, sizeof (tmp), "%%%sd", fmt);
-+	snprintf (dest, destlen, tmp, folder->ff->all);
-+      } else if (!folder->ff->all) {
-+	optional = 0;
-+      }
-+      break;
++* Thu Mar 13 2014 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.5.23
 +
-     case 'N':
- #ifdef USE_IMAP
-       if (mx_is_imap (folder->ff->desc))
-@@ -275,6 +357,18 @@
- 	break;
-       }
- #endif
-+#ifdef USE_NOTMUCH
-+      if (mx_is_notmuch (folder->ff->name))
-+      {
-+	if (!optional)
-+	{
-+	  snprintf (tmp, sizeof (tmp), "%%%sd", fmt);
-+	  snprintf (dest, destlen, tmp, folder->ff->new);
-+	} else if (!folder->ff->new)
-+	  optional = 0;
-+	break;
-+      }
-+#endif
-       snprintf (tmp, sizeof (tmp), "%%%sc", fmt);
-       snprintf (dest, destlen, tmp, folder->ff->new ? 'N' : ' ');
-       break;
-@@ -324,8 +418,112 @@
-   return (src);
- }
- 
-+#ifdef USE_NNTP
-+static const char *
-+newsgroup_format_str (char *dest, size_t destlen, size_t col, char op, const char *src,
-+		      const char *fmt, const char *ifstring, const char *elsestring,
-+		      unsigned long data, format_flag flags)
-+{
-+  char fn[SHORT_STRING], tmp[SHORT_STRING];
-+  FOLDER *folder = (FOLDER *) data;
++* Tue Oct 29 2013 Vsevolod Volkov <vvv at mutt.org.ua>
++- minor bug fixed while removing new articles
 +
-+  switch (op)
-+  {
-+    case 'C':
-+      snprintf (tmp, sizeof (tmp), "%%%sd", fmt);
-+      snprintf (dest, destlen, tmp, folder->num + 1);
-+      break;
++* Fri Oct 18 2013 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.5.22
 +
-+    case 'f':
-+      strncpy (fn, folder->ff->name, sizeof(fn) - 1);
-+      snprintf (tmp, sizeof (tmp), "%%%ss", fmt);
-+      snprintf (dest, destlen, tmp, fn);
-+      break;
++* Tue Nov 27 2012 Vsevolod Volkov <vvv at mutt.org.ua>
++- SASL authentication
++- new option nntp_authenticators
 +
-+    case 'N':
-+      snprintf (tmp, sizeof (tmp), "%%%sc", fmt);
-+      if (folder->ff->nd->subscribed)
-+	snprintf (dest, destlen, tmp, ' ');
-+      else
-+	snprintf (dest, destlen, tmp, folder->ff->new ? 'N' : 'u');
-+      break;
++* Fri Nov 16 2012 Vsevolod Volkov <vvv at mutt.org.ua>
++- support of NNTP commands: CAPABILITIES, STARTTLS, LIST NEWSGROUPS,
++  LIST OVERVIEW.FMT, OVER, DATE
++- added bcache support
++- newss URI scheme renamed to snews
++- removed option nntp_reconnect
 +
-+    case 'M':
-+      snprintf (tmp, sizeof (tmp), "%%%sc", fmt);
-+      if (folder->ff->nd->deleted)
-+	snprintf (dest, destlen, tmp, 'D');
-+      else
-+	snprintf (dest, destlen, tmp, folder->ff->nd->allowed ? ' ' : '-');
-+      break;
++* Sun Sep 16 2012 Vsevolod Volkov <vvv at mutt.org.ua>
++- internal header caching replaced with hcache
++- new option newsgroups_charset
 +
-+    case 's':
-+      if (flags & M_FORMAT_OPTIONAL)
-+      {
-+	if (folder->ff->nd->unread != 0)
-+	  mutt_FormatString (dest, destlen, col, ifstring, newsgroup_format_str,
-+		data, flags);
-+	else
-+	  mutt_FormatString (dest, destlen, col, elsestring, newsgroup_format_str,
-+		data, flags);
-+      }
-+      else if (Context && Context->data == folder->ff->nd)
-+      {
-+	snprintf (tmp, sizeof (tmp), "%%%sd", fmt);
-+	snprintf (dest, destlen, tmp, Context->unread);
-+      }
-+      else
-+      {
-+	snprintf (tmp, sizeof (tmp), "%%%sd", fmt);
-+	snprintf (dest, destlen, tmp, folder->ff->nd->unread);
-+      }
-+      break;
++* Wed Sep 16 2010 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.5.21
 +
-+    case 'n':
-+      if (Context && Context->data == folder->ff->nd)
-+      {
-+	snprintf (tmp, sizeof (tmp), "%%%sd", fmt);
-+	snprintf (dest, destlen, tmp, Context->new);
-+      }
-+      else if (option (OPTMARKOLD) &&
-+		folder->ff->nd->lastCached >= folder->ff->nd->firstMessage &&
-+		folder->ff->nd->lastCached <= folder->ff->nd->lastMessage)
-+      {
-+	snprintf (tmp, sizeof (tmp), "%%%sd", fmt);
-+	snprintf (dest, destlen, tmp, folder->ff->nd->lastMessage - folder->ff->nd->lastCached);
-+      }
-+      else
-+      {
-+	snprintf (tmp, sizeof (tmp), "%%%sd", fmt);
-+	snprintf (dest, destlen, tmp, folder->ff->nd->unread);
-+      }
-+      break;
++* Thu Aug 13 2009 Vsevolod Volkov <vvv at mutt.org.ua>
++- fixed writting references in nntp_save_cache_group()
 +
-+    case 'd':
-+      if (folder->ff->nd->desc != NULL)
-+      {
-+	char *buf = safe_strdup (folder->ff->nd->desc);
-+	if (NewsgroupsCharset && *NewsgroupsCharset)
-+	  mutt_convert_string (&buf, NewsgroupsCharset, Charset, M_ICONV_HOOK_FROM);
-+	mutt_filter_unprintable (&buf);
++* Tue Jun 15 2009 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.5.20
 +
-+	snprintf (tmp, sizeof (tmp), "%%%ss", fmt);
-+	snprintf (dest, destlen, tmp, buf);
-+	FREE (&buf);
-+      }
-+      else
-+      {
-+	snprintf (tmp, sizeof (tmp), "%%%ss", fmt);
-+	snprintf (dest, destlen, tmp, "");
-+      }
-+      break;
-+  }
-+  return (src);
-+}
-+#endif /* USE_NNTP */
++* Tue Mar 20 2009 Vsevolod Volkov <vvv at mutt.org.ua>
++- save Date: header of recorded outgoing articles
 +
- static void add_folder (MUTTMENU *m, struct browser_state *state,
--			const char *name, const struct stat *s, unsigned int new)
-+		const char *name, const char *desc, const struct stat *s,
-+		unsigned int new, unsigned int all, void *data)
- {
-   if (state->entrylen == state->entrymax)
-   {
-@@ -349,11 +547,16 @@
-   }
- 
-   (state->entry)[state->entrylen].new = new;
-+  (state->entry)[state->entrylen].all = all;
-   (state->entry)[state->entrylen].name = safe_strdup (name);
--  (state->entry)[state->entrylen].desc = safe_strdup (name);
-+  (state->entry)[state->entrylen].desc = safe_strdup(desc ? desc : name);
- #ifdef USE_IMAP
-   (state->entry)[state->entrylen].imap = 0;
- #endif
-+#ifdef USE_NNTP
-+  if (option (OPTNEWS))
-+    (state->entry)[state->entrylen].nd = (NNTP_DATA *)data;
-+#endif
-   (state->entrylen)++;
- }
- 
-@@ -369,9 +572,35 @@
-     menu->data = state->entry;
- }
- 
-+/* get list of all files/newsgroups with mask */
- static int examine_directory (MUTTMENU *menu, struct browser_state *state,
- 			      char *d, const char *prefix)
- {
-+#ifdef USE_NNTP
-+  if (option (OPTNEWS))
-+  {
-+    NNTP_SERVER *nserv = CurrentNewsSrv;
-+    unsigned int i;
++* Tue Jan  6 2009 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.5.19
 +
-+/*  mutt_buffy_check (0); */
-+    init_state (state, menu);
++* Mon May 19 2008 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.5.18
++- fixed SIGSEGV when followup or forward to newsgroup
 +
-+    for (i = 0; i < nserv->groups_num; i++)
-+    {
-+      NNTP_DATA *nntp_data = nserv->groups_list[i];
-+      if (!nntp_data)
-+	continue;
-+      if (prefix && *prefix &&
-+	  strncmp (prefix, nntp_data->group, strlen (prefix)))
-+	continue;
-+      if (!((regexec (Mask.rx, nntp_data->group, 0, NULL, 0) == 0) ^ Mask.not))
-+	continue;
-+      add_folder (menu, state, nntp_data->group, NULL, NULL, nntp_data->new, nntp_data->newsrc_len, nntp_data);
-+    }
-+  }
-+  else
-+#endif /* USE_NNTP */
-+  {
-   struct stat s;
-   DIR *dp;
-   struct dirent *de;
-@@ -432,17 +661,66 @@
-     tmp = Incoming;
-     while (tmp && mutt_strcmp (buffer, tmp->path))
-       tmp = tmp->next;
--    add_folder (menu, state, de->d_name, &s, (tmp) ? tmp->new : 0);
-+    add_folder (menu, state, de->d_name, NULL, &s, (tmp) ? tmp->new : 0, (tmp) ? tmp->msg_count : 0, NULL);
-   }
-   closedir (dp);  
-+  }
-   browser_sort (state);
-   return 0;
- }
- 
-+#ifdef USE_NOTMUCH
-+static int examine_vfolders (MUTTMENU *menu, struct browser_state *state)
-+{
-+  BUFFY *tmp = VirtIncoming;
++* Sun Nov  4 2007 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.5.17
 +
-+  if (!VirtIncoming)
-+    return (-1);
-+  mutt_buffy_check (0);
++* Tue Jul  3 2007 Vsevolod Volkov <vvv at mutt.org.ua>
++- fixed arguments of nntp_format_str()
 +
-+  init_state (state, menu);
++* Fri Jun 15 2007 Vsevolod Volkov <vvv at mutt.org.ua>
++- fixed error selecting news group
 +
-+  do
-+  {
-+    if (mx_is_notmuch (tmp->path))
-+    {
-+      nm_nonctx_get_count(tmp->path, &tmp->msg_count, &tmp->msg_unread);
-+      add_folder (menu, state, tmp->path, tmp->desc, NULL, tmp->msg_unread, tmp->msg_count, NULL);
-+      continue;
-+    }
-+  }
-+  while ((tmp = tmp->next));
-+  browser_sort (state);
-+  return 0;
-+}
-+#endif
++* Tue Jun 12 2007 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.5.16
 +
-+/* get list of mailboxes/subscribed newsgroups */
- static int examine_mailboxes (MUTTMENU *menu, struct browser_state *state)
- {
-   struct stat s;
-   char buffer[LONG_STRING];
++* Wed Apr 11 2007 Vsevolod Volkov <vvv at mutt.org.ua>
++- fixed posting error if $smtp_url is set
++- added support of print-style sequence %R (x-comment-to)
 +
-+#ifdef USE_NNTP
-+  if (option (OPTNEWS))
-+  {
-+    NNTP_SERVER *nserv = CurrentNewsSrv;
-+    unsigned int i;
++* Sun Apr  8 2007 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.5.15
++- nntp://... url changed to news://...
++- added indicator of fetching descriptions progress
 +
-+/*  mutt_buffy_check (0); */
-+    init_state (state, menu);
++* Tue Feb 28 2007 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.5.14
 +
-+    for (i = 0; i < nserv->groups_num; i++)
-+    {
-+      NNTP_DATA *nntp_data = nserv->groups_list[i];
-+      if (nntp_data && (nntp_data->new || (nntp_data->subscribed &&
-+	 (nntp_data->unread || !option (OPTSHOWONLYUNREAD)))))
-+	add_folder (menu, state, nntp_data->group, NULL, NULL, nntp_data->new, nntp_data->newsrc_len, nntp_data);
-+    }
-+  }
-+  else
-+#endif
-+  {
-   BUFFY *tmp = Incoming;
- #ifdef USE_IMAP
-   struct mailbox_state mbox;
-@@ -460,14 +738,21 @@
-     if (mx_is_imap (tmp->path))
-     {
-       imap_mailbox_state (tmp->path, &mbox);
--      add_folder (menu, state, tmp->path, NULL, mbox.new);
-+      add_folder (menu, state, tmp->path, NULL, NULL, mbox.new, mbox.messages, NULL);
-       continue;
-     }
- #endif
- #ifdef USE_POP
-     if (mx_is_pop (tmp->path))
-     {
--      add_folder (menu, state, tmp->path, NULL, tmp->new);
-+      add_folder (menu, state, tmp->path, NULL, NULL, tmp->new, tmp->msg_count, NULL);
-+      continue;
-+    }
-+#endif
-+#ifdef USE_NNTP
-+    if (mx_is_nntp (tmp->path))
-+    {
-+      add_folder (menu, state, tmp->path, NULL, NULL, tmp->new, tmp->msg_count, NULL);
-       continue;
-     }
- #endif
-@@ -496,18 +781,30 @@
-     strfcpy (buffer, NONULL(tmp->path), sizeof (buffer));
-     mutt_pretty_mailbox (buffer, sizeof (buffer));
- 
--    add_folder (menu, state, buffer, &s, tmp->new);
-+    add_folder (menu, state, buffer, NULL, &s, tmp->new, tmp->msg_count, NULL);
-   }
-   while ((tmp = tmp->next));
-+  }
-   browser_sort (state);
-   return 0;
- }
- 
- static int select_file_search (MUTTMENU *menu, regex_t *re, int n)
- {
-+#ifdef USE_NNTP
-+  if (option (OPTNEWS))
-+    return (regexec (re, ((struct folder_file *) menu->data)[n].desc, 0, NULL, 0));
-+#endif
-   return (regexec (re, ((struct folder_file *) menu->data)[n].name, 0, NULL, 0));
- }
- 
-+#ifdef USE_NOTMUCH
-+static int select_vfolder_search (MUTTMENU *menu, regex_t *re, int n)
-+{
-+  return (regexec (re, ((struct folder_file *) menu->data)[n].desc, 0, NULL, 0));
-+}
-+#endif
++* Tue Aug 15 2006 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.5.13
 +
- static void folder_entry (char *s, size_t slen, MUTTMENU *menu, int num)
- {
-   FOLDER folder;
-@@ -515,10 +812,29 @@
-   folder.ff = &((struct folder_file *) menu->data)[num];
-   folder.num = num;
-   
-+#ifdef USE_NNTP
-+  if (option (OPTNEWS))
-+    mutt_FormatString (s, slen, 0, NONULL(GroupFormat), newsgroup_format_str, 
-+      (unsigned long) &folder, M_FORMAT_ARROWCURSOR);
-+  else
-+#endif
-   mutt_FormatString (s, slen, 0, NONULL(FolderFormat), folder_format_str, 
-       (unsigned long) &folder, M_FORMAT_ARROWCURSOR);
- }
- 
-+#ifdef USE_NOTMUCH
-+static void vfolder_entry (char *s, size_t slen, MUTTMENU *menu, int num)
-+{
-+  FOLDER folder;
++* Mon Jul 17 2006 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.5.12
++- fixed reading empty .newsrc
 +
-+  folder.ff = &((struct folder_file *) menu->data)[num];
-+  folder.num = num;
++* Sat Sep 17 2005 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.5.11
 +
-+  mutt_FormatString (s, slen, 0, NONULL(VirtFolderFormat), folder_format_str,
-+      (unsigned long) &folder, M_FORMAT_ARROWCURSOR);
-+}
-+#endif
++* Sat Aug 13 2005 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.5.10
 +
- static void init_menu (struct browser_state *state, MUTTMENU *menu, char *title,
- 		       size_t titlelen, int buffy)
- {
-@@ -535,6 +851,17 @@
- 
-   menu->tagged = 0;
-   
-+#ifdef USE_NNTP
-+  if (option (OPTNEWS))
-+  {
-+    if (buffy)
-+      snprintf (title, titlelen, _("Subscribed newsgroups"));
-+    else
-+      snprintf (title, titlelen, _("Newsgroups on server [%s]"),
-+		CurrentNewsSrv->conn->account.host);
-+  }
-+  else
-+#endif
-   if (buffy)
-     snprintf (title, titlelen, _("Mailboxes [%d]"), mutt_buffy_check (0));
-   else
-@@ -584,12 +911,37 @@
-   int buffy    = (flags & M_SEL_BUFFY)  ? 1 : 0;
- 
-   buffy = buffy && folder;
--  
++* Sun Mar 13 2005 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.5.9
 +
-   memset (&state, 0, sizeof (struct browser_state));
- 
-   if (!folder)
-     strfcpy (LastDirBackup, LastDir, sizeof (LastDirBackup));
- 
-+#ifdef USE_NNTP
-+  if (option (OPTNEWS))
-+  {
-+    if (*f)
-+      strfcpy (prefix, f, sizeof (prefix));
-+    else
-+    {
-+      NNTP_SERVER *nserv = CurrentNewsSrv;
-+      unsigned int i;
++* Sun Feb 13 2005 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.5.8
 +
-+      /* default state for news reader mode is browse subscribed newsgroups */
-+      buffy = 0;
-+      for (i = 0; i < nserv->groups_num; i++)
-+      {
-+	NNTP_DATA *nntp_data = nserv->groups_list[i];
-+	if (nntp_data && nntp_data->subscribed)
-+	{
-+	  buffy = 1;
-+	  break;
-+	}
-+      }
-+    }
-+  }
-+  else
-+#endif
-   if (*f)
-   {
-     mutt_expand_path (f, flen);
-@@ -637,13 +989,17 @@
-     }
- #endif
-   }
--  else 
-+#ifdef USE_NOTMUCH
-+  else if (!(flags & M_SEL_VFOLDER))
-+#else
-+  else
-+#endif
-   {
-     if (!folder)
-       getcwd (LastDir, sizeof (LastDir));
-     else if (!LastDir[0])
-       strfcpy (LastDir, NONULL(Maildir), sizeof (LastDir));
--    
++* Sat Feb  5 2005 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.5.7
++- function mutt_update_list_file() moved to newsrc.c and changed algorithm
 +
- #ifdef USE_IMAP
-     if (!buffy && mx_is_imap (LastDir))
-     {
-@@ -665,6 +1021,12 @@
- 
-   *f = 0;
- 
-+#ifdef USE_NOTMUCH
-+  if (flags & M_SEL_VFOLDER) {
-+    if (examine_vfolders (NULL, &state) == -1)
-+      goto bail;
-+  } else
-+#endif
-   if (buffy)
-   {
-     if (examine_mailboxes (NULL, &state) == -1)
-@@ -674,18 +1036,29 @@
- #ifdef USE_IMAP
-   if (!state.imap_browse)
- #endif
-+  {
-   if (examine_directory (NULL, &state, LastDir, prefix) == -1)
-     goto bail;
--
-+  }
-   menu = mutt_new_menu (MENU_FOLDER);
--  menu->make_entry = folder_entry;
-   menu->search = select_file_search;
-   menu->title = title;
-   menu->data = state.entry;
-   if (multiple)
-     menu->tag = file_tag;
- 
-+#ifdef USE_NOTMUCH
-+  if (flags & M_SEL_VFOLDER) {
-+    menu->make_entry = vfolder_entry;
-+    menu->search = select_vfolder_search;
-+  } else
-+#endif
-+    menu->make_entry = folder_entry;
++* Thu Jul  8 2004 Vsevolod Volkov <vvv at mutt.org.ua>
++- fixed error in nntp_logout_all()
 +
-   menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_FOLDER,
-+#ifdef USE_NNTP
-+    option (OPTNEWS) ? FolderNewsHelp :
-+#endif
-     FolderHelp);
- 
-   init_menu (&state, menu, title, sizeof (title), buffy);
-@@ -824,7 +1197,11 @@
- 	  }
- 	}
- 
-+#ifdef USE_NNTP
-+	if (buffy || option (OPTNEWS))
-+#else
- 	if (buffy)
-+#endif
- 	{
- 	  strfcpy (f, state.entry[menu->current].name, flen);
- 	  mutt_expand_path (f, flen);
-@@ -833,6 +1210,10 @@
- 	else if (state.imap_browse)
-           strfcpy (f, state.entry[menu->current].name, flen);
- #endif
-+#ifdef USE_NOTMUCH
-+	else if (mx_is_notmuch(state.entry[menu->current].name))
-+	  strfcpy (f, state.entry[menu->current].name, flen);
-+#endif
- 	else
- 	  mutt_concat_path (f, LastDir, state.entry[menu->current].name, flen);
- 
-@@ -882,14 +1263,6 @@
-         break;
- 
- #ifdef USE_IMAP
--      case OP_BROWSER_SUBSCRIBE:
--	imap_subscribe (state.entry[menu->current].name, 1);
--	break;
--
--      case OP_BROWSER_UNSUBSCRIBE:
--	imap_subscribe (state.entry[menu->current].name, 0);
--	break;
--
-       case OP_BROWSER_TOGGLE_LSUB:
- 	if (option (OPTIMAPLSUB))
- 	  unset_option (OPTIMAPLSUB);
-@@ -987,9 +1360,14 @@
-         }
-         break;
- #endif
--      
++* Sat Apr  3 2004 Vsevolod Volkov <vvv at mutt.org.ua>
++- fixed debug output in mutt_newsrc_update()
++- added optional support of LISTGROUP command
++- fixed typo in nntp_parse_xref()
 +
-       case OP_CHANGE_DIRECTORY:
- 
-+#ifdef USE_NNTP
-+	if (option (OPTNEWS))
-+	  break;
-+#endif
++* Tue Feb  3 2004 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.5.6
 +
- 	strfcpy (buf, LastDir, sizeof (buf));
- #ifdef USE_IMAP
- 	if (!state.imap_browse)
-@@ -1136,9 +1514,9 @@
- 	  int reverse = (i == OP_SORT_REVERSE);
- 	  
- 	  switch (mutt_multi_choice ((reverse) ?
--	      _("Reverse sort by (d)ate, (a)lpha, si(z)e or do(n)'t sort? ") :
--	      _("Sort by (d)ate, (a)lpha, si(z)e or do(n)'t sort? "),
--	      _("dazn")))
-+	      _("Reverse sort by (d)ate, (a)lpha, si(z)e, d(e)scription, (c)ount, ne(w) count, or do(n)'t sort? ") :
-+	      _("Sort by (d)ate, (a)lpha, si(z)e, d(e)scription, (c)ount, ne(w) count, or do(n)'t sort? "),
-+	      _("dazecwn")))
- 	  {
- 	    case -1: /* abort */
- 	      resort = 0;
-@@ -1156,7 +1534,19 @@
- 	      BrowserSort = SORT_SIZE;
- 	      break;
- 
--            case 4: /* do(n)'t sort */
-+            case 4: /* d(e)scription */
-+	      BrowserSort = SORT_DESC;
-+	      break;
++* Thu Dec 18 2003 Vsevolod Volkov <vvv at mutt.org.ua>
++- fixed compose menu
 +
-+            case 5: /* (c)ount */
-+	      BrowserSort = SORT_COUNT;
-+	      break;
++* Thu Nov  6 2003 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.5.5.1
 +
-+            case 6: /* ne(w) count */
-+	      BrowserSort = SORT_COUNT_NEW;
-+	      break;
++* Wed Nov  5 2003 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.5.5
++- added space after newsgroup name in .newsrc file
 +
-+            case 7: /* do(n)'t sort */
- 	      BrowserSort = SORT_ORDER;
- 	      resort = 0;
- 	      break;
-@@ -1255,6 +1645,209 @@
- 	  else
- 	    mutt_error _("Error trying to view file");
- 	}
-+	break;
++* Sun May 18 2003 Vsevolod Volkov <vvv at mutt.org.ua>
++- fixed SIGSEGV when posting article
 +
-+#ifdef USE_NNTP
-+      case OP_CATCHUP:
-+      case OP_UNCATCHUP:
-+	if (option (OPTNEWS))
-+	{
-+	  struct folder_file *f = &state.entry[menu->current];
-+	  int rc;
-+	  NNTP_DATA *nntp_data;
++* Sat Mar 22 2003 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.5.4
 +
-+	  rc = nntp_newsrc_parse (CurrentNewsSrv);
-+	  if (rc < 0)
-+	    break;
++* Sat Dec 21 2002 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.5.3
++- replace safe_free calls by the FREE macro
 +
-+	  if (i == OP_CATCHUP)
-+	    nntp_data = mutt_newsgroup_catchup (CurrentNewsSrv, f->name);
-+	  else
-+	    nntp_data = mutt_newsgroup_uncatchup (CurrentNewsSrv, f->name);
++* Fri Dec  6 2002 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.5.2
++- nntp authentication can be passed after any command
 +
-+	  if (nntp_data)
-+	  {
-+/*	    FOLDER folder;
-+	    struct folder_file ff;
-+	    char buffer[_POSIX_PATH_MAX + SHORT_STRING];
++* Sat May  4 2002 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.5.1
 +
-+	    folder.ff = &ff;
-+	    folder.ff->name = f->name;
-+	    folder.ff->st = NULL;
-+	    folder.ff->is_new = nntp_data->new;
-+	    folder.ff->nntp_data = nntp_data;
-+	    FREE (&f->desc);
-+	    mutt_FormatString (buffer, sizeof (buffer), 0, NONULL(GroupFormat),
-+		  newsgroup_format_str, (unsigned long) &folder,
-+		  M_FORMAT_ARROWCURSOR);
-+	    f->desc = safe_strdup (buffer); */
-+	    nntp_newsrc_update (CurrentNewsSrv);
-+	    if (menu->current + 1 < menu->max)
-+	      menu->current++;
-+	    menu->redraw = REDRAW_MOTION_RESYNCH;
-+	  }
-+	  if (rc)
-+	    menu->redraw = REDRAW_INDEX;
-+	  nntp_newsrc_close (CurrentNewsSrv);
-+	}
-+	break;
++* Thu May  2 2002 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.3.99
 +
-+      case OP_LOAD_ACTIVE:
-+	if (option (OPTNEWS))
-+	{
-+	  NNTP_SERVER *nserv = CurrentNewsSrv;
-+	  unsigned int i;
++* Wed Mar 13 2002 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.3.28
++- fixed SIGSEGV in <get-message>, <get-parent>, <get-children>,
++  <reconstruct-thread> functions
++- fixed message about nntp reconnect
++- fixed <attach-news-message> function using browser
++- added support of Followup-To: poster
++- added %n (new articles) in group_index_format
++- posting articles without inews by default
 +
-+	  if (nntp_newsrc_parse (nserv) < 0)
-+	    break;
++* Wed Jan 23 2002 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.3.27
 +
-+	  for (i = 0; i < nserv->groups_num; i++)
-+	  {
-+	    NNTP_DATA *nntp_data = nserv->groups_list[i];
-+	    if (nntp_data)
-+	      nntp_data->deleted = 1;
-+	  }
-+	  nntp_active_fetch (nserv);
-+	  nntp_newsrc_update (nserv);
-+	  nntp_newsrc_close (nserv);
++* Fri Jan 18 2002 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.3.26
 +
-+	  destroy_state (&state);
-+	  if (buffy)
-+	    examine_mailboxes (menu, &state);
-+	  else
-+	    examine_directory (menu, &state, NULL, NULL);
-+	  init_menu (&state, menu, title, sizeof (title), buffy);
-+	}
-+	break;
-+#endif /* USE_NNTP */
++* Thu Jan  3 2002 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.3.25
++- accelerated speed of access to news->newsgroups hash (by <gul at gul.kiev.ua>)
++- added default content disposition
 +
-+#if defined USE_IMAP || defined USE_NNTP
-+      case OP_BROWSER_SUBSCRIBE:
-+      case OP_BROWSER_UNSUBSCRIBE:
-+#endif
-+#ifdef USE_NNTP
-+      case OP_SUBSCRIBE_PATTERN:
-+      case OP_UNSUBSCRIBE_PATTERN:
-+	if (option (OPTNEWS))
-+	{
-+	  NNTP_SERVER *nserv = CurrentNewsSrv;
-+	  NNTP_DATA *nntp_data;
-+	  regex_t *rx = (regex_t *) safe_malloc (sizeof (regex_t));
-+	  char *s = buf;
-+	  int rc, j = menu->current;
++* Mon Dec  3 2001 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.3.24
 +
-+	  if (i == OP_SUBSCRIBE_PATTERN || i == OP_UNSUBSCRIBE_PATTERN)
-+	  {
-+	    char tmp[STRING];
-+	    int err;
++* Fri Nov  9 2001 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.3.23.2
++- fixed segfault if mutt_conn_find() returns null
 +
-+	    buf[0] = 0;
-+	    if (i == OP_SUBSCRIBE_PATTERN)
-+	      snprintf (tmp, sizeof (tmp), _("Subscribe pattern: "));
-+	    else
-+	      snprintf (tmp, sizeof (tmp), _("Unsubscribe pattern: "));
-+	    if (mutt_get_field (tmp, buf, sizeof (buf), 0) != 0 || !buf[0])
-+	    {
-+	      FREE (&rx);
-+	      break;
-+	    }
++* Wed Oct 31 2001 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.3.23.1
++- added support of LISTGROUP command
++- added support for servers with broken overview
++- disabled <flag-message> function on news server
++- fixed error storing bad authentication information
 +
-+	    err = REGCOMP (rx, s, REG_NOSUB);
-+	    if (err)
-+	    {
-+	      regerror (err, rx, buf, sizeof (buf));
-+	      regfree (rx);
-+	      FREE (&rx);
-+	      mutt_error ("%s", buf);
-+	      break;
-+	    }
-+	    menu->redraw = REDRAW_FULL;
-+	    j = 0;
-+	  }
-+	  else if (!state.entrylen)
-+	  {
-+	    mutt_error _("No newsgroups match the mask");
-+	    break;
-+	  }
++* Wed Oct 10 2001 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.3.23
++- fixed typo in buffy.c
++- added substitution of %s parameter in $inews variable
 +
-+	  rc = nntp_newsrc_parse (nserv);
-+	  if (rc < 0)
-+	    break;
++* Fri Aug 31 2001 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.3.22.1
++- update to 1.3.22
 +
-+	  for ( ; j < state.entrylen; j++)
-+	  {
-+	    struct folder_file *f = &state.entry[j];
++* Thu Aug 23 2001 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.3.21
 +
-+	    if (i == OP_BROWSER_SUBSCRIBE || i == OP_BROWSER_UNSUBSCRIBE ||
-+		  regexec (rx, f->name, 0, NULL, 0) == 0)
-+	    {
-+	      if (i == OP_BROWSER_SUBSCRIBE || i == OP_SUBSCRIBE_PATTERN)
-+		nntp_data = mutt_newsgroup_subscribe (nserv, f->name);
-+	      else
-+		nntp_data = mutt_newsgroup_unsubscribe (nserv, f->name);
-+/*	      if (nntp_data)
-+	      {
-+		FOLDER folder;
-+		char buffer[_POSIX_PATH_MAX + SHORT_STRING];
++* Wed Jul 25 2001 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.3.20
++- removed 'server-hook', use 'account-hook' instead
++- fixed error opening NNTP server without newsgroup using -f option
 +
-+		folder.name = f->name;
-+		folder.f = NULL;
-+		folder.new = nntp_data->new;
-+		folder.nd = nntp_data;
-+		FREE (&f->desc);
-+		mutt_FormatString (buffer, sizeof (buffer), 0, NONULL(GroupFormat),
-+			newsgroup_format_str, (unsigned long) &folder,
-+			M_FORMAT_ARROWCURSOR);
-+		f->desc = safe_strdup (buffer);
-+	      } */
-+	    }
-+	    if (i == OP_BROWSER_SUBSCRIBE || i == OP_BROWSER_UNSUBSCRIBE)
-+	    {
-+	      if (menu->current + 1 < menu->max)
-+		menu->current++;
-+	      menu->redraw = REDRAW_MOTION_RESYNCH;
-+	      break;
-+	    }
-+	  }
-+	  if (i == OP_SUBSCRIBE_PATTERN)
-+	  {
-+	    unsigned int i;
++* Fri Jun  8 2001 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.3.19
 +
-+	    for (i = 0; nserv && i < nserv->groups_num; i++)
-+	    {
-+	      nntp_data = nserv->groups_list[i];
-+	      if (nntp_data && nntp_data->group && !nntp_data->subscribed)
-+	      {
-+		if (regexec (rx, nntp_data->group, 0, NULL, 0) == 0)
-+		{
-+		  mutt_newsgroup_subscribe (nserv, nntp_data->group);
-+		  add_folder (menu, &state, nntp_data->group, NULL, NULL, nntp_data->new, nntp_data->newsrc_len, nntp_data);
-+		}
-+	      }
-+	    }
-+	    init_menu (&state, menu, title, sizeof (title), buffy);
-+	  }
-+	  if (rc > 0)
-+	    menu->redraw = REDRAW_FULL;
-+	  nntp_newsrc_update (nserv);
-+	  nntp_clear_cache (nserv);
-+	  nntp_newsrc_close (nserv);
-+	  if (i != OP_BROWSER_SUBSCRIBE && i != OP_BROWSER_UNSUBSCRIBE)
-+	    regfree (rx);
-+	  FREE (&rx);
-+	}
-+#ifdef USE_IMAP
-+	else
-+#endif /* USE_IMAP && USE_NNTP */
-+#endif /* USE_NNTP */
-+#ifdef USE_IMAP
-+	{
-+	  if (i == OP_BROWSER_SUBSCRIBE)
-+	    imap_subscribe (state.entry[menu->current].name, 1);
-+	  else
-+	    imap_subscribe (state.entry[menu->current].name, 0);
-+	}
-+#endif /* USE_IMAP */
-     }
-   }
-   
-diff -urN mutt-1.6.1/browser.h mutt-1.6.1-neomutt/browser.h
---- mutt-1.6.1/browser.h	2016-06-12 18:43:00.396447497 +0100
-+++ mutt-1.6.1-neomutt/browser.h	2016-06-12 18:43:00.674451832 +0100
-@@ -19,6 +19,10 @@
- #ifndef _BROWSER_H
- #define _BROWSER_H 1
- 
-+#ifdef USE_NNTP
-+#include "nntp.h"
-+#endif
++* Sat May  5 2001 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.3.18
++- fixed typo in nntp_attempt_features()
++- changed algorithm of XGTITLE command testing
++- disabled writing of NNTP password in debug file
++- fixed reading and writing of long newsrc lines
++- changed checking of last line while reading lines from server
++- fixed possible buffer overrun in nntp_parse_newsrc_line()
++- removed checking of XHDR command
++- compare NNTP return codes without trailing space
 +
- struct folder_file
- {
-   mode_t mode;
-@@ -30,6 +34,8 @@
-   char *desc;
- 
-   unsigned int new;
-+  unsigned int all;
++* Thu Mar 29 2001 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.3.17
++- support for 'LIST NEWSGROUPS' command to read descriptions
 +
- #ifdef USE_IMAP
-   char delim;
-   
-@@ -37,6 +43,9 @@
-   unsigned selectable : 1;
-   unsigned inferiors : 1;
- #endif
-+#ifdef USE_NNTP
-+  NNTP_DATA *nd;
-+#endif
-   unsigned tagged : 1;
- };
- 
-diff -urN mutt-1.6.1/buffy.c mutt-1.6.1-neomutt/buffy.c
---- mutt-1.6.1/buffy.c	2016-06-12 18:43:00.397447512 +0100
-+++ mutt-1.6.1-neomutt/buffy.c	2016-06-12 18:43:00.675451848 +0100
-@@ -27,10 +27,18 @@
- 
- #include "mutt_curses.h"
- 
-+#ifdef USE_SIDEBAR
-+#include "sidebar.h"
-+#endif
++* Fri Mar  2 2001 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.3.16
 +
- #ifdef USE_IMAP
- #include "imap.h"
- #endif
- 
-+#ifdef USE_NOTMUCH
-+#include "mutt_notmuch.h"
-+#endif
++* Wed Feb 14 2001 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.3.15
 +
- #include <string.h>
- #include <sys/stat.h>
- #include <dirent.h>
-@@ -196,9 +204,17 @@
- static BUFFY *buffy_new (const char *path)
- {
-   BUFFY* buffy;
-+#ifdef USE_SIDEBAR
-+  char rp[PATH_MAX] = "";
-+  char *r = NULL;
-+#endif
- 
-   buffy = (BUFFY *) safe_calloc (1, sizeof (BUFFY));
-   strfcpy (buffy->path, path, sizeof (buffy->path));
-+#ifdef USE_SIDEBAR
-+  r = realpath (path, rp);
-+  strfcpy (buffy->realpath, r ? rp : path, sizeof (buffy->realpath));
-+#endif
-   buffy->next = NULL;
-   buffy->magic = 0;
- 
-@@ -207,6 +223,8 @@
- 
- static void buffy_free (BUFFY **mailbox)
- {
-+  if (mailbox && *mailbox)
-+    FREE (&(*mailbox)->desc);
-   FREE (mailbox); /* __FREE_CHECKED__ */
- }
- 
-@@ -215,7 +233,10 @@
-   BUFFY **tmp,*tmp1;
-   char buf[_POSIX_PATH_MAX];
-   struct stat sb;
--  char f1[PATH_MAX], f2[PATH_MAX];
-+  char f1[PATH_MAX];
-+#ifndef USE_SIDEBAR
-+  char f2[PATH_MAX];
-+#endif
-   char *p, *q;
- 
-   while (MoreArgs (s))
-@@ -228,6 +249,9 @@
-       for (tmp = &Incoming; *tmp;)
-       {
-         tmp1=(*tmp)->next;
-+#ifdef USE_SIDEBAR
-+	mutt_sb_notify_mailbox (*tmp, 0);
-+#endif
-         buffy_free (tmp);
-         *tmp=tmp1;
-       }
-@@ -243,8 +267,13 @@
-     p = realpath (buf, f1);
-     for (tmp = &Incoming; *tmp; tmp = &((*tmp)->next))
-     {
-+#ifdef USE_SIDEBAR
-+      q = (*tmp)->realpath;
-+      if (mutt_strcmp (p ? p : buf, q) == 0)
-+#else
-       q = realpath ((*tmp)->path, f2);
-       if (mutt_strcmp (p ? p : buf, q ? q : (*tmp)->path) == 0)
-+#endif
-       {
- 	dprint(3,(debugfile,"mailbox '%s' already registered as '%s'\n", buf, (*tmp)->path));
- 	break;
-@@ -256,14 +285,21 @@
-       if(*tmp)
-       {
-         tmp1=(*tmp)->next;
-+#ifdef USE_SIDEBAR
-+	mutt_sb_notify_mailbox (*tmp, 0);
-+#endif
-         buffy_free (tmp);
-         *tmp=tmp1;
-       }
-       continue;
-     }
- 
--    if (!*tmp)
-+    if (!*tmp) {
-       *tmp = buffy_new (buf);
-+#ifdef USE_SIDEBAR
-+      mutt_sb_notify_mailbox (*tmp, 1);
-+#endif
-+    }
- 
-     (*tmp)->new = 0;
-     (*tmp)->notified = 1;
-@@ -306,6 +342,13 @@
-       return 0;
-   }
- 
-+#ifdef USE_SIDEBAR
-+  if (option (OPTSIDEBAR) && mailbox->msg_unread > 0) {
-+    mailbox->new = 1;
-+    return 1;
-+  }
-+#endif
++* Sun Jan 28 2001 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.3.14
++- show number of tagged messages patch from Felix von Leitner <leitner at fefe.de>
 +
-   if ((dirp = opendir (path)) == NULL)
-   {
-     mailbox->magic = 0;
-@@ -340,6 +383,54 @@
-   return rc;
- }
- 
-+#ifdef USE_NOTMUCH
-+int mutt_parse_virtual_mailboxes (BUFFER *path, BUFFER *s, unsigned long data, BUFFER *err)
-+{
-+  BUFFY **tmp;
-+  char buf[_POSIX_PATH_MAX + LONG_STRING + 32];   /* path to DB + query + URI "decoration" */
++* Sun Dec 31 2000 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.3.13
 +
-+  while (MoreArgs (s))
-+  {
-+    char *desc;
++* Sat Dec 30 2000 Vsevolod Volkov <vvv at mutt.org.ua>
++- Fixed problem if last article in group is deleted
 +
-+    mutt_extract_token (path, s, 0);
-+    if (path->data && *path->data)
-+      desc = safe_strdup( path->data);
-+    else
-+      continue;
++* Fri Dec 22 2000 Vsevolod Volkov <vvv at mutt.org.ua>
++- Fixed checking of XGTITLE command on some servers
 +
-+    mutt_extract_token (path, s, 0);
-+    strfcpy (buf, path->data, sizeof (buf));
++* Mon Dec 18 2000 Vsevolod Volkov <vvv at mutt.org.ua>
++- Added \r in AUTHINFO commands
 +
-+    /* Skip empty tokens. */
-+    if(!*buf) {
-+	    FREE(&desc);
-+	    continue;
-+    }
++* Mon Nov 27 2000 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.3.12
 +
-+    /* avoid duplicates */
-+    for (tmp = &VirtIncoming; *tmp; tmp = &((*tmp)->next))
-+    {
-+      if (mutt_strcmp (buf, (*tmp)->path) == 0)
-+      {
-+	dprint(3,(debugfile,"virtual mailbox '%s' already registered as '%s'\n", buf, (*tmp)->path));
-+	break;
-+      }
-+    }
++* Wed Nov  1 2000 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.3.11
++- fixed error opening newsgroup from mutt started with -g or -G
 +
-+    if (!*tmp)
-+      *tmp = buffy_new (buf);
++* Thu Oct 12 2000 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.3.10
++- hotkey 'G' (get-message) replaced with '^G'
 +
-+    (*tmp)->new = 0;
-+    (*tmp)->notified = 1;
-+    (*tmp)->newly_created = 0;
-+    (*tmp)->size = 0;
-+    (*tmp)->desc = desc;
-+  }
-+  return 0;
-+}
-+#endif
++* Thu Sep 21 2000 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.3.9
++- changed delay displaying error messages from 1 to 2 seconds
++- fixed error compiling with nntp and without imap
 +
- /* returns 1 if maildir has new mail */
- static int buffy_maildir_hasnew (BUFFY* mailbox)
- {
-@@ -357,6 +448,92 @@
- 
-   return 0;
- }
++* Wed Sep  6 2000 Vsevolod Volkov <vvv at mutt.org.ua>
++- fixed catchup in index
++- fixed nntp_open_mailbox()
 +
-+#ifdef USE_SIDEBAR
-+/**
-+ * buffy_maildir_update_dir - Update counts for one directory
-+ * @mailbox: BUFFY representing a maildir mailbox
-+ * @dir:     Which directory to search
-+ *
-+ * Look through one directory of a maildir mailbox.  The directory could
-+ * be either "new" or "cur".
-+ *
-+ * Count how many new, or flagged, messages there are.
-+ */
-+static void
-+buffy_maildir_update_dir (BUFFY *mailbox, const char *dir)
-+{
-+  char path[_POSIX_PATH_MAX] = "";
-+  DIR *dirp = NULL;
-+  struct dirent *de = NULL;
-+  char *p = NULL;
-+  int read;
++* Sat Sep  2 2000 Vsevolod Volkov <vvv at mutt.org.ua>
++- functions <edit> and <delete-entry> disabled
++- format of news mailbox names changed to url form
++- option nntp_attempts removed
++- option reconnect_news renamed to nntp_reconnect
++- default value of nntp_poll changed from 30 to 60
++- error handling improved
 +
-+  snprintf (path, sizeof (path), "%s/%s", mailbox->path, dir);
++* Wed Aug 30 2000 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.3.8
++- new option show_only_unread
++- add newsgroup completion
 +
-+  dirp = opendir (path);
-+  if (!dirp)
-+  {
-+    mailbox->magic = 0;
-+    return;
-+  }
++* Fri Aug  4 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- update to 1.3.7
 +
-+  while ((de = readdir (dirp)) != NULL)
-+  {
-+    if (*de->d_name == '.')
-+      continue;
++* Sat Jul 29 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- update to 1.3.6
 +
-+    /* Matches maildir_parse_flags logic */
-+    read = 0;
-+    mailbox->msg_count++;
-+    p = strstr (de->d_name, ":2,");
-+    if (p)
-+    {
-+      p += 3;
-+      if (strchr (p, 'S'))
-+        read = 1;
-+      if (strchr (p, 'F'))
-+        mailbox->msg_flagged++;
-+    }
-+    if (!read) {
-+      mailbox->msg_unread++;
-+    }
-+  }
++* Sun Jul  9 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- update to 1.3.5
++- authentication code update
++- fix for changing to newsgroup from mailbox with read messages
++- socket code optimization
 +
-+  closedir (dirp);
-+}
++* Wed Jun 21 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- update to 1.3.4
 +
-+/**
-+ * buffy_maildir_update - Update messages counts for a maildir mailbox
-+ * @mailbox: BUFFY representing a maildir mailbox
-+ *
-+ * Open a mailbox directories and update our record of how many new, or
-+ * flagged, messages there are.
-+ */
-+void
-+buffy_maildir_update (BUFFY *mailbox)
-+{
-+	if (!option (OPTSIDEBAR))
-+		return;
++* Wed Jun 14 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- don't substitute current newsgroup with deleted new messages
 +
-+	mailbox->msg_count   = 0;
-+	mailbox->msg_unread  = 0;
-+	mailbox->msg_flagged = 0;
++* Mon Jun 12 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- update to 1.3.3
++- fix for substitution of newsgroup after reconnection
++- fix for loading newsgroups with very long names
++- fix for loading more than 32768 newsgroups
 +
-+	buffy_maildir_update_dir (mailbox, "new");
-+	if (mailbox->msg_count) {
-+		mailbox->new = 1;
-+	}
-+	buffy_maildir_update_dir (mailbox, "cur");
++* Wed May 24 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- update to 1.3.2
 +
-+	mailbox->sb_last_checked = time (NULL);
++* Sat May 20 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- update to 1.3.1
 +
-+	/* make sure the updates are actually put on screen */
-+	mutt_sb_draw();
-+}
++* Fri May 12 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- update to 1.3
 +
-+#endif
++* Thu May 11 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- update to 1.2
 +
- /* returns 1 if mailbox has new mail */ 
- static int buffy_mbox_hasnew (BUFFY* mailbox, struct stat *sb)
- {
-@@ -368,7 +545,11 @@
-   else
-     statcheck = sb->st_mtime > sb->st_atime
-       || (mailbox->newly_created && sb->st_ctime == sb->st_mtime && sb->st_ctime == sb->st_atime);
-+#ifdef USE_SIDEBAR
-+  if ((!option (OPTSIDEBAR) && statcheck) || (option (OPTSIDEBAR) && mailbox->msg_unread > 0))
-+#else
-   if (statcheck)
-+#endif
-   {
-     if (!option(OPTMAILCHECKRECENT) || sb->st_mtime > mailbox->last_visited)
-     {
-@@ -388,48 +569,48 @@
-   return rc;
- }
- 
--int mutt_buffy_check (int force)
-+#ifdef USE_SIDEBAR
-+/**
-+ * buffy_mbox_update - Update messages counts for an mbox mailbox
-+ * @mailbox: BUFFY representing an mbox mailbox
-+ * @sb:      stat(2) infomation about the mailbox file
-+ *
-+ * Open a mbox file and update our record of how many new, or flagged,
-+ * messages there are. If the mailbox hasn't changed since the last call,
-+ * the function does nothing.
-+ */
-+void
-+buffy_mbox_update (BUFFY *mailbox, struct stat *sb)
- {
--  BUFFY *tmp;
--  struct stat sb;
--  struct stat contex_sb;
--  time_t t;
-+  CONTEXT *ctx = NULL;
- 
--  sb.st_size=0;
--  contex_sb.st_dev=0;
--  contex_sb.st_ino=0;
-+  if (!option (OPTSIDEBAR))
-+    return;
-+  if ((mailbox->sb_last_checked > sb->st_mtime) && (mailbox->msg_count != 0))
-+    return; /* no check necessary */
- 
--#ifdef USE_IMAP
--  /* update postponed count as well, on force */
--  if (force)
--    mutt_update_num_postponed ();
-+  ctx = mx_open_mailbox (mailbox->path, M_READONLY | M_QUIET | M_NOSORT | M_PEEK, NULL);
-+  if (ctx)
-+  {
-+    mailbox->msg_count       = ctx->msgcount;
-+    mailbox->msg_unread      = ctx->unread;
-+    mailbox->msg_flagged     = ctx->flagged;
-+    mailbox->sb_last_checked = time (NULL);
-+    mx_close_mailbox (ctx, 0);
-+  }
++* Thu May  4 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- update to 1.1.14
 +
-+  /* make sure the updates are actually put on screen */
-+  mutt_sb_draw();
-+}
- #endif
- 
--  /* fastest return if there are no mailboxes */
--  if (!Incoming)
--    return 0;
--  t = time (NULL);
--  if (!force && (t - BuffyTime < BuffyTimeout))
--    return BuffyCount;
-- 
--  BuffyTime = t;
--  BuffyCount = 0;
--  BuffyNotify = 0;
- 
--#ifdef USE_IMAP
--  BuffyCount += imap_buffy_check (force);
--#endif
-+static void buffy_check(BUFFY *tmp, struct stat *contex_sb)
-+{
-+    struct stat sb;
++* Sun Apr 23 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- update to 1.1.12
 +
-+    sb.st_size=0;
- 
--  /* check device ID and serial number instead of comparing paths */
--  if (!Context || Context->magic == M_IMAP || Context->magic == M_POP
--      || stat (Context->path, &contex_sb) != 0)
--  {
--    contex_sb.st_dev=0;
--    contex_sb.st_ino=0;
--  }
--  
--  for (tmp = Incoming; tmp; tmp = tmp->next)
--  {
-     if (tmp->magic != M_IMAP)
-     {
-       tmp->new = 0;
-@@ -438,6 +619,16 @@
- 	tmp->magic = M_POP;
-       else
- #endif
-+#ifdef USE_NOTMUCH
-+      if (mx_is_notmuch (tmp->path))
-+	tmp->magic = M_NOTMUCH;
-+      else
-+#endif
-+#ifdef USE_NNTP
-+      if ((tmp->magic == M_NNTP) || mx_is_nntp (tmp->path))
-+	tmp->magic = M_NNTP;
-+      else
-+#endif
-       if (stat (tmp->path, &sb) != 0 || (S_ISREG(sb.st_mode) && sb.st_size == 0) ||
- 	  (!tmp->magic && (tmp->magic = mx_get_magic (tmp->path)) <= 0))
-       {
-@@ -446,35 +637,66 @@
- 	tmp->newly_created = 1;
- 	tmp->magic = 0;
- 	tmp->size = 0;
--	continue;
-+	return;
-       }
-     }
- 
-     /* check to see if the folder is the currently selected folder
-      * before polling */
-     if (!Context || !Context->path ||
--	(( tmp->magic == M_IMAP || tmp->magic == M_POP )
-+#ifdef USE_NNTP
-+	(( tmp->magic == M_IMAP || tmp->magic == M_POP || tmp->magic == M_NNTP )
-+#else
-+	(( tmp->magic == M_IMAP || tmp->magic == M_POP || tmp->magic == M_NOTMUCH)
-+#endif
- 	    ? mutt_strcmp (tmp->path, Context->path) :
--	      (sb.st_dev != contex_sb.st_dev || sb.st_ino != contex_sb.st_ino)))
-+	      (sb.st_dev != contex_sb->st_dev || sb.st_ino != contex_sb->st_ino)))
-     {
-       switch (tmp->magic)
-       {
-       case M_MBOX:
-       case M_MMDF:
-+#ifdef USE_SIDEBAR
-+	if (option(OPTSIDEBAR))
-+	  buffy_mbox_update (tmp, &sb);
-+#endif
- 	if (buffy_mbox_hasnew (tmp, &sb) > 0)
- 	  BuffyCount++;
- 	break;
- 
-       case M_MAILDIR:
-+#ifdef USE_SIDEBAR
-+	if (option(OPTSIDEBAR))
-+	  buffy_maildir_update (tmp);
-+#endif
- 	if (buffy_maildir_hasnew (tmp) > 0)
- 	  BuffyCount++;
- 	break;
- 
-       case M_MH:
-+#ifdef USE_SIDEBAR
-+	if (option(OPTSIDEBAR))
-+	  mh_buffy_update (tmp);
-+#endif
- 	mh_buffy(tmp);
- 	if (tmp->new)
- 	  BuffyCount++;
- 	break;
-+#ifdef USE_NOTMUCH
-+      case M_NOTMUCH:
-+	tmp->msg_count = 0;
-+	tmp->msg_unread = 0;
-+	tmp->msg_flagged = 0;
-+	nm_nonctx_get_count(tmp->path, &tmp->msg_count, &tmp->msg_unread);
-+	if (tmp->msg_unread > 0) {
-+	  BuffyCount++;
-+	  tmp->new = 1;
-+	}
-+#ifdef USE_SIDEBAR
-+	mutt_sb_set_update_time();
-+#endif
-+	break;
-+#endif
-       }
-     }
-     else if (option(OPTCHECKMBOXSIZE) && Context && Context->path)
-@@ -484,8 +706,62 @@
-       tmp->notified = 0;
-     else if (!tmp->notified)
-       BuffyNotify++;
-+}
++* Fri Apr  7 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- add substitution of newsgroup with new messages by default
 +
-+int mutt_buffy_check (int force)
-+{
-+  BUFFY *tmp;
-+  struct stat contex_sb;
-+  time_t t;
++* Wed Apr  5 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- add attach message from newsgroup
++- add one-line help in newsreader mode
++- disable 'change-dir' command in newsgroups browser
++- add -G option
 +
-+  contex_sb.st_dev=0;
-+  contex_sb.st_ino=0;
++* Tue Apr  4 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- get default news server name from file /etc/nntpserver
++- use case insensitive server names
++- add print-style sequence %s to $newsrc
++- add -g option
 +
-+#ifdef USE_IMAP
-+  /* update postponed count as well, on force */
-+  if (force)
-+    mutt_update_num_postponed ();
-+#endif
++* Sat Apr  1 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- remove 'X-FTN-Origin' header processing
 +
-+  /* fastest return if there are no mailboxes */
-+#ifdef USE_NOTMUCH
-+  if (!Incoming && !VirtIncoming)
-+    return 0;
-+#else
-+  if (!Incoming)
-+    return 0;
-+#endif
-+  t = time (NULL);
-+  if (!force && (t - BuffyTime < BuffyTimeout))
-+    return BuffyCount;
++* Thu Mar 30 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- update to 1.1.11
++- update to 1.1.10
 +
-+  BuffyTime = t;
-+  BuffyCount = 0;
-+  BuffyNotify = 0;
++* Thu Mar 23 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- fix mutt_select_newsserver()
++- remove 'toggle-mode' function
++- add 'change-newsgroup' function
 +
-+#ifdef USE_IMAP
-+  BuffyCount += imap_buffy_check (force);
-+#endif
++* Wed Mar 22 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- fix server-hook
 +
-+  /* check device ID and serial number instead of comparing paths */
-+  if (!Context || Context->magic == M_IMAP || Context->magic == M_POP
-+#ifdef USE_NNTP
-+      || Context->magic == M_NNTP
-+#endif
-+      || stat (Context->path, &contex_sb) != 0)
-+  {
-+    contex_sb.st_dev=0;
-+    contex_sb.st_ino=0;
-   }
- 
-+  for (tmp = Incoming; tmp; tmp = tmp->next)
-+    buffy_check(tmp, &contex_sb);
++* Tue Mar 21 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- fix error 'bounce' function after 'post'
++- add 'forward to newsgroup' function
 +
-+#ifdef USE_NOTMUCH
-+  for (tmp = VirtIncoming; tmp; tmp = tmp->next)
-+    buffy_check(tmp, &contex_sb);
-+#endif
++* Mon Mar 20 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- 'forward' function works in newsreader mode
++- add 'post' and 'followup' functions to pager and attachment menu
++- fix active descriptions and allowed flag reload
 +
-   BuffyDoneTime = BuffyTime;
-   return (BuffyCount);
- }
-@@ -600,6 +876,35 @@
-   *s = '\0';
- }
- 
-+#ifdef USE_NOTMUCH
-+void mutt_buffy_vfolder (char *s, size_t slen)
-+{
-+  BUFFY *tmp;
-+  int pass, found = 0;
++* Tue Mar 14 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- update to 1.1.9
++- remove deleted newsgroups from list
 +
-+  if (mutt_buffy_check (0))
-+  {
-+    for (pass = 0; pass < 2; pass++) {
-+      for (tmp = VirtIncoming; tmp; tmp = tmp->next)
-+      {
-+	if ((found || pass) && tmp->new)
-+	{
-+	  strfcpy (s, tmp->desc, slen);
-+	  return;
-+	}
-+	if (mutt_strcmp (s, tmp->path) == 0)
-+	  found = 1;
-+      }
-+    }
++* Mon Mar 13 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- update .newsrc in browser
 +
-+    mutt_buffy_check (1); /* buffy was wrong - resync things */
-+  }
++* Sun Mar 12 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- reload .newsrc if externally modified
++- fix active cache update
 +
-+  /* no folders with new mail */
-+  *s = '\0';
-+}
-+#endif
++* Sun Mar  5 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- update to 1.1.8
 +
- /* fetch buffy object for given path, if present */
- static BUFFY* buffy_get (const char *path)
- {
-diff -urN mutt-1.6.1/buffy.h mutt-1.6.1-neomutt/buffy.h
---- mutt-1.6.1/buffy.h	2016-06-12 18:43:00.397447512 +0100
-+++ mutt-1.6.1-neomutt/buffy.h	2016-06-12 18:43:00.675451848 +0100
-@@ -16,6 +16,9 @@
-  *     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-  */
- 
-+#ifndef _BUFFY_H
-+#define _BUFFY_H
++* Sat Mar  4 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- patch *.update_list_file is not required
++- count lines when loading descriptions
++- remove cache of unsubscribed newsgroups
 +
- /*parameter to mutt_parse_mailboxes*/
- #define M_MAILBOXES   1
- #define M_UNMAILBOXES 2 
-@@ -23,19 +26,38 @@
- typedef struct buffy_t
- {
-   char path[_POSIX_PATH_MAX];
-+#ifdef USE_SIDEBAR
-+  char realpath[_POSIX_PATH_MAX];
-+#endif
-+  char *desc;
-   off_t size;
-   struct buffy_t *next;
-+#ifdef USE_SIDEBAR
-+  struct buffy_t *prev;
-+#endif
-   short new;			/* mailbox has new mail */
-+  int msg_count;		/* total number of messages */
-+  int msg_unread;		/* number of unread messages */
-+  int msg_flagged;		/* number of flagged messages */
-+  short is_hidden;		/* is hidden from the sidebar */
-   short notified;		/* user has been notified */
-   short magic;			/* mailbox type */
-   short newly_created;		/* mbox or mmdf just popped into existence */
-   time_t last_visited;		/* time of last exit from this mailbox */
-+#ifdef USE_SIDEBAR
-+  time_t sb_last_checked;	/* time of last buffy check from sidebar */
-+#endif
- }
- BUFFY;
- 
- WHERE BUFFY *Incoming INITVAL (0);
- WHERE short BuffyTimeout INITVAL (3);
- 
-+#ifdef USE_NOTMUCH
-+WHERE BUFFY *VirtIncoming INITVAL (0);
-+void mutt_buffy_vfolder (char *s, size_t slen);
-+#endif
++* Thu Mar  2 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- load list of newsgroups from cache faster
 +
- extern time_t BuffyDoneTime;	/* last time we knew for sure how much mail there was */
- 
- BUFFY *mutt_find_mailbox (const char *path);
-@@ -49,3 +71,5 @@
- void mutt_buffy_setnotified (const char *path);
- 
- void mh_buffy (BUFFY *);
++* Wed Mar  1 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- update to 1.1.7
 +
-+#endif /* _BUFFY_H */
-diff -urN mutt-1.6.1/ChangeLog.neomutt mutt-1.6.1-neomutt/ChangeLog.neomutt
---- mutt-1.6.1/ChangeLog.neomutt	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/ChangeLog.neomutt	2016-06-12 18:43:00.662451645 +0100
-@@ -0,0 +1,97 @@
-+2016-06-11  Richard Russon  <rich at flatcap.org>
-+* Change in behaviour
-+  - Temporarily disable $sidebar_refresh_time
-+    Unfortunately, this was causing too many problems.
-+    It will be fixed and re-enabled as soon as possible.
-+* Bug Fixes
-+  - Fix several crashes, on startup, in Keywords
-+  - Reflow text now works as it should
-+  - Lots of typos fixed
-+  - Compress config bug prevented it working
-+  - Some minor bug-fixes from mutt/default
-+  - Single quote at line beginning misinterpreted by groff
-+  - Setting $sidebar_width to more than 128 would cause bad things to happen.
-+  - Fix alignment in the compose menu.
-+  - Fix sidebar buffy stats updating on mailbox close.
-+* Build Changes
-+  - Sync whitespace to mutt/default
-+  - Alter ChangeLog date format to simplify Makefiles
-+  - Use the new notmuch functions that return a status
-+  - Rename sidebar functions sb_* -> mutt_sb_*
++* Tue Feb 29 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- fix unread messages in browser
++- fix newsrc_gen_entries()
 +
-+2016-05-23  Richard Russon  <rich at flatcap.org>
-+* New Features:
-+  - Keywords: Email Label/Keywords/Tagging
-+  - Compress: Compressed mailboxes support
-+  - NNTP: Talk to a usenet news server
-+  - Separate mappings for <enter> and <return>
-+  - New configure option: --enable-quick-build
-+  - Various build fixes
++* Mon Feb 28 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- fix mutt_newsgroup_stat()
++- fix nntp_delete_cache()
++- fix nntp_get_status()
++- fix check_children()
++- fix nntp_fetch_headers()
 +
-+2016-05-02  Richard Russon  <rich at flatcap.org>
-+* Update for Mutt-1.6.0
-+* Bug Fixes:
-+  - Build for Notmuch works if Sidebar is disabled
-+  - Sidebar functions work even if the Sidebar is hidden
-+  - sidebar-next-new, etc, only find *new* mail, as documented
-+  - Notmuch supports *very* long queries
++* Fri Feb 25 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- update to 1.1.5
 +
-+2016-04-16  Richard Russon  <rich at flatcap.org>
-+* Big Bugfix Release
-+* Bug Fixes:
-+  - Fix crash caused by sidebar_folder_indent
-+  - Allow the user to change mailboxes again
-+  - Correct sidebar's messages counts
-+  - Only sort the sidebar if we're asked to
-+  - Fix refresh of pager when toggling the sidebar
-+  - Compose mode: make messages respect the TITLE_FMT
-+  - Conditional include if sys/syscall.h
-+  - Build fix for old compilers
-+  - Try harder to keep track of the open mailbox
-+* Changes to Features
-+  - Allow sidebar_divider_char to be longer
-+    (it was limited to one character)
-+  - Ignore case when sorting the sidebar alphabetically
-+* Other Changes
-+  - Numerous small tweaks to the docs
-+  - Lots of minor code tidy-ups
-+  - Enabling NotMuch now forcibly enables Sidebar
-+    (it is dependent on it, for now)
-+  - A couple of bug fixes from mutt/stable
++* Thu Feb 24 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- fix updating new messages in cache
 +
-+2016-04-04  Richard Russon  <rich at flatcap.org>
-+* Update for Mutt-1.6.0
-+* No other changes in this release
++* Mon Feb 21 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- change default cache filenames
++- fix updating new messages in cache
 +
-+2016-03-28  Richard Russon  <rich at flatcap.org>
-+* New Features
-+  - skip-quoted          - skip quoted text
-+  - limit-current-thread - limit index view to current thread
-+* Sidebar Intro - A Gentle Introduction to the Sidebar (with pictures).
++* Fri Feb 18 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- fix segmentation fault in news groups browser
 +
-+2016-03-20  Richard Russon  <rich at flatcap.org>
-+* Numerous small bugfixes
-+* TravisCI integration
++* Tue Feb 15 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- update to 1.1.4
 +
-+2016-03-17  Richard Russon  <rich at flatcap.org>
-+* New Features
-+  - notmuch - email search support
-+  - ifdef   - improvements
++* Thu Feb 10 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- update to 1.1.3
 +
-+2016-03-07  Richard Russon  <rich at flatcap.org>
-+* First NeoMutt release
-+* List of Features:
-+  - bug-fixes    - various bug fixes
-+  - cond-date    - use rules to choose date format
-+  - fmemopen     - use memory buffers instead of files
-+  - ifdef        - conditional config options
-+  - index-color  - theme the email index
-+  - initials     - expando for author's initials
-+  - nested-if    - allow deeply nested conditions
-+  - progress     - show a visual progress bar
-+  - quasi-delete - mark emails to be hidden
-+  - sidebar      - overview of mailboxes
-+  - status-color - theming the status bar
-+  - tls-sni      - negotiate for a certificate
-+  - trash        - move 'deleted' emails to a trash bin
++* Sun Jan 30 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- add X-Comment-To editing
++- add my_hdr support for Newsgroups:, Followup-To: and X-Comment-To: headers
++- add variables $ask_followup_to and $ask_x_comment_to
 +
-diff -urN mutt-1.6.1/ChangeLog.nntp mutt-1.6.1-neomutt/ChangeLog.nntp
---- mutt-1.6.1/ChangeLog.nntp	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/ChangeLog.nntp	2016-06-12 18:43:00.662451645 +0100
-@@ -0,0 +1,416 @@
-+* Wed Apr  6 2016 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.6.0
-+- %R changed to %x in format strings
++* Fri Jan 28 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- update to 1.1.2
+diff --git a/GPL b/GPL
+index b6f92f3..0daa041 100644
+--- a/GPL
++++ b/GPL
+@@ -1,73 +1,74 @@
+-		    GNU GENERAL PUBLIC LICENSE
+-		       Version 2, June 1991
++GNU General Public License
++==========================
+ 
+- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+-                 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+- Everyone is permitted to copy and distribute verbatim copies
+- of this license document, but changing it is not allowed.
++_Version 2, June 1991_  
++_Copyright © 1989, 1991 Free Software Foundation, Inc.,_  
++_51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA_
+ 
+-			    Preamble
++Everyone is permitted to copy and distribute verbatim copies
++of this license document, but changing it is not allowed.
+ 
+-  The licenses for most software are designed to take away your
++### Preamble
 +
-+* Wed Nov 25 2015 Vsevolod Volkov <vvv at mutt.org.ua>
-+- fixed memory leaks
-+- fixed SIGSEGV when reading hcache in some cases
++The licenses for most software are designed to take away your
+ freedom to share and change it.  By contrast, the GNU General Public
+ License is intended to guarantee your freedom to share and change free
+ software--to make sure the software is free for all its users.  This
+ General Public License applies to most of the Free Software
+ Foundation's software and to any other program whose authors commit to
+ using it.  (Some other Free Software Foundation software is covered by
+-the GNU Library General Public License instead.)  You can apply it to
++the GNU Lesser General Public License instead.)  You can apply it to
+ your programs, too.
+ 
+-  When we speak of free software, we are referring to freedom, not
++When we speak of free software, we are referring to freedom, not
+ price.  Our General Public Licenses are designed to make sure that you
+ have the freedom to distribute copies of free software (and charge for
+ this service if you wish), that you receive source code or can get it
+ if you want it, that you can change the software or use pieces of it
+ in new free programs; and that you know you can do these things.
+ 
+-  To protect your rights, we need to make restrictions that forbid
++To protect your rights, we need to make restrictions that forbid
+ anyone to deny you these rights or to ask you to surrender the rights.
+ These restrictions translate to certain responsibilities for you if you
+ distribute copies of the software, or if you modify it.
+ 
+-  For example, if you distribute copies of such a program, whether
++For example, if you distribute copies of such a program, whether
+ gratis or for a fee, you must give the recipients all the rights that
+ you have.  You must make sure that they, too, receive or can get the
+ source code.  And you must show them these terms so they know their
+ rights.
+ 
+-  We protect your rights with two steps: (1) copyright the software, and
+-(2) offer you this license which gives you legal permission to copy,
++We protect your rights with two steps: **(1)** copyright the software, and
++**(2)** offer you this license which gives you legal permission to copy,
+ distribute and/or modify the software.
+ 
+-  Also, for each author's protection and ours, we want to make certain
++Also, for each author's protection and ours, we want to make certain
+ that everyone understands that there is no warranty for this free
+ software.  If the software is modified by someone else and passed on, we
+ want its recipients to know that what they have is not the original, so
+ that any problems introduced by others will not reflect on the original
+ authors' reputations.
+ 
+-  Finally, any free program is threatened constantly by software
++Finally, any free program is threatened constantly by software
+ patents.  We wish to avoid the danger that redistributors of a free
+ program will individually obtain patent licenses, in effect making the
+ program proprietary.  To prevent this, we have made it clear that any
+ patent must be licensed for everyone's free use or not licensed at all.
+ 
+-  The precise terms and conditions for copying, distribution and
++The precise terms and conditions for copying, distribution and
+ modification follow.
+-

+-		    GNU GENERAL PUBLIC LICENSE
+-   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+ 
+-  0. This License applies to any program or other work which contains
++### TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
 +
-+* Tue Nov 10 2015 Vsevolod Volkov <vvv at mutt.org.ua>
-+- fixed error compiling with nntp and without imap or pop3
-+- fixed error loading articles after <change-newsgroup> and <quit>
++**0.** This License applies to any program or other work which contains
+ a notice placed by the copyright holder saying it may be distributed
+-under the terms of this General Public License.  The "Program", below,
+-refers to any such program or work, and a "work based on the Program"
++under the terms of this General Public License.  The “Program”, below,
++refers to any such program or work, and a “work based on the Program”
+ means either the Program or any derivative work under copyright law:
+ that is to say, a work containing the Program or a portion of it,
+ either verbatim or with modifications and/or translated into another
+ language.  (Hereinafter, translation is included without limitation in
+-the term "modification".)  Each licensee is addressed as "you".
++the term “modification”.)  Each licensee is addressed as “you”.
+ 
+ Activities other than copying, distribution and modification are not
+ covered by this License; they are outside its scope.  The act of
+@@ -76,7 +77,7 @@ is covered only if its contents constitute a work based on the
+ Program (independent of having been made by running the Program).
+ Whether that is true depends on what the Program does.
+ 
+-  1. You may copy and distribute verbatim copies of the Program's
++**1.** You may copy and distribute verbatim copies of the Program's
+ source code as you receive it, in any medium, provided that you
+ conspicuously and appropriately publish on each copy an appropriate
+ copyright notice and disclaimer of warranty; keep intact all the
+@@ -87,30 +88,28 @@ along with the Program.
+ You may charge a fee for the physical act of transferring a copy, and
+ you may at your option offer warranty protection in exchange for a fee.
+ 
+-  2. You may modify your copy or copies of the Program or any portion
++**2.** You may modify your copy or copies of the Program or any portion
+ of it, thus forming a work based on the Program, and copy and
+ distribute such modifications or work under the terms of Section 1
+ above, provided that you also meet all of these conditions:
+ 
+-    a) You must cause the modified files to carry prominent notices
+-    stating that you changed the files and the date of any change.
+-
+-    b) You must cause any work that you distribute or publish, that in
+-    whole or in part contains or is derived from the Program or any
+-    part thereof, to be licensed as a whole at no charge to all third
+-    parties under the terms of this License.
+-
+-    c) If the modified program normally reads commands interactively
+-    when run, you must cause it, when started running for such
+-    interactive use in the most ordinary way, to print or display an
+-    announcement including an appropriate copyright notice and a
+-    notice that there is no warranty (or else, saying that you provide
+-    a warranty) and that users may redistribute the program under
+-    these conditions, and telling the user how to view a copy of this
+-    License.  (Exception: if the Program itself is interactive but
+-    does not normally print such an announcement, your work based on
+-    the Program is not required to print an announcement.)
+-

++* **a)** You must cause the modified files to carry prominent notices
++stating that you changed the files and the date of any change.
++* **b)** You must cause any work that you distribute or publish, that in
++whole or in part contains or is derived from the Program or any
++part thereof, to be licensed as a whole at no charge to all third
++parties under the terms of this License.
++* **c)** If the modified program normally reads commands interactively
++when run, you must cause it, when started running for such
++interactive use in the most ordinary way, to print or display an
++announcement including an appropriate copyright notice and a
++notice that there is no warranty (or else, saying that you provide
++a warranty) and that users may redistribute the program under
++these conditions, and telling the user how to view a copy of this
++License.  (Exception: if the Program itself is interactive but
++does not normally print such an announcement, your work based on
++the Program is not required to print an announcement.)
 +
-+* Wed Sep  2 2015 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.5.24
-+- new option nntp_listgroup
-+- use range in LISTGROUP command if possible
-+
-+* Thu Mar 13 2014 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.5.23
-+
-+* Tue Oct 29 2013 Vsevolod Volkov <vvv at mutt.org.ua>
-+- minor bug fixed while removing new articles
-+
-+* Fri Oct 18 2013 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.5.22
-+
-+* Tue Nov 27 2012 Vsevolod Volkov <vvv at mutt.org.ua>
-+- SASL authentication
-+- new option nntp_authenticators
-+
-+* Fri Nov 16 2012 Vsevolod Volkov <vvv at mutt.org.ua>
-+- support of NNTP commands: CAPABILITIES, STARTTLS, LIST NEWSGROUPS,
-+  LIST OVERVIEW.FMT, OVER, DATE
-+- added bcache support
-+- newss URI scheme renamed to snews
-+- removed option nntp_reconnect
-+
-+* Sun Sep 16 2012 Vsevolod Volkov <vvv at mutt.org.ua>
-+- internal header caching replaced with hcache
-+- new option newsgroups_charset
-+
-+* Wed Sep 16 2010 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.5.21
-+
-+* Thu Aug 13 2009 Vsevolod Volkov <vvv at mutt.org.ua>
-+- fixed writting references in nntp_save_cache_group()
-+
-+* Tue Jun 15 2009 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.5.20
-+
-+* Tue Mar 20 2009 Vsevolod Volkov <vvv at mutt.org.ua>
-+- save Date: header of recorded outgoing articles
-+
-+* Tue Jan  6 2009 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.5.19
-+
-+* Mon May 19 2008 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.5.18
-+- fixed SIGSEGV when followup or forward to newsgroup
-+
-+* Sun Nov  4 2007 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.5.17
-+
-+* Tue Jul  3 2007 Vsevolod Volkov <vvv at mutt.org.ua>
-+- fixed arguments of nntp_format_str()
-+
-+* Fri Jun 15 2007 Vsevolod Volkov <vvv at mutt.org.ua>
-+- fixed error selecting news group
-+
-+* Tue Jun 12 2007 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.5.16
-+
-+* Wed Apr 11 2007 Vsevolod Volkov <vvv at mutt.org.ua>
-+- fixed posting error if $smtp_url is set
-+- added support of print-style sequence %R (x-comment-to)
-+
-+* Sun Apr  8 2007 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.5.15
-+- nntp://... url changed to news://...
-+- added indicator of fetching descriptions progress
-+
-+* Tue Feb 28 2007 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.5.14
-+
-+* Tue Aug 15 2006 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.5.13
-+
-+* Mon Jul 17 2006 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.5.12
-+- fixed reading empty .newsrc
-+
-+* Sat Sep 17 2005 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.5.11
-+
-+* Sat Aug 13 2005 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.5.10
-+
-+* Sun Mar 13 2005 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.5.9
-+
-+* Sun Feb 13 2005 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.5.8
-+
-+* Sat Feb  5 2005 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.5.7
-+- function mutt_update_list_file() moved to newsrc.c and changed algorithm
-+
-+* Thu Jul  8 2004 Vsevolod Volkov <vvv at mutt.org.ua>
-+- fixed error in nntp_logout_all()
-+
-+* Sat Apr  3 2004 Vsevolod Volkov <vvv at mutt.org.ua>
-+- fixed debug output in mutt_newsrc_update()
-+- added optional support of LISTGROUP command
-+- fixed typo in nntp_parse_xref()
-+
-+* Tue Feb  3 2004 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.5.6
-+
-+* Thu Dec 18 2003 Vsevolod Volkov <vvv at mutt.org.ua>
-+- fixed compose menu
+ These requirements apply to the modified work as a whole.  If
+ identifiable sections of that work are not derived from the Program,
+ and can be reasonably considered independent and separate works in
+@@ -131,26 +130,24 @@ with the Program (or with a work based on the Program) on a volume of
+ a storage or distribution medium does not bring the other work under
+ the scope of this License.
+ 
+-  3. You may copy and distribute the Program (or a work based on it,
++**3.** You may copy and distribute the Program (or a work based on it,
+ under Section 2) in object code or executable form under the terms of
+ Sections 1 and 2 above provided that you also do one of the following:
+ 
+-    a) Accompany it with the complete corresponding machine-readable
+-    source code, which must be distributed under the terms of Sections
+-    1 and 2 above on a medium customarily used for software interchange; or,
+-
+-    b) Accompany it with a written offer, valid for at least three
+-    years, to give any third party, for a charge no more than your
+-    cost of physically performing source distribution, a complete
+-    machine-readable copy of the corresponding source code, to be
+-    distributed under the terms of Sections 1 and 2 above on a medium
+-    customarily used for software interchange; or,
+-
+-    c) Accompany it with the information you received as to the offer
+-    to distribute corresponding source code.  (This alternative is
+-    allowed only for noncommercial distribution and only if you
+-    received the program in object code or executable form with such
+-    an offer, in accord with Subsection b above.)
++* **a)** Accompany it with the complete corresponding machine-readable
++source code, which must be distributed under the terms of Sections
++1 and 2 above on a medium customarily used for software interchange; or,
++* **b)** Accompany it with a written offer, valid for at least three
++years, to give any third party, for a charge no more than your
++cost of physically performing source distribution, a complete
++machine-readable copy of the corresponding source code, to be
++distributed under the terms of Sections 1 and 2 above on a medium
++customarily used for software interchange; or,
++* **c)** Accompany it with the information you received as to the offer
++to distribute corresponding source code.  (This alternative is
++allowed only for noncommercial distribution and only if you
++received the program in object code or executable form with such
++an offer, in accord with Subsection b above.)
+ 
+ The source code for a work means the preferred form of the work for
+ making modifications to it.  For an executable work, complete source
+@@ -168,8 +165,8 @@ access to copy from a designated place, then offering equivalent
+ access to copy the source code from the same place counts as
+ distribution of the source code, even though third parties are not
+ compelled to copy the source along with the object code.
+-

+-  4. You may not copy, modify, sublicense, or distribute the Program
 +
-+* Thu Nov  6 2003 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.5.5.1
++**4.** You may not copy, modify, sublicense, or distribute the Program
+ except as expressly provided under this License.  Any attempt
+ otherwise to copy, modify, sublicense or distribute the Program is
+ void, and will automatically terminate your rights under this License.
+@@ -177,7 +174,7 @@ However, parties who have received copies, or rights, from you under
+ this License will not have their licenses terminated so long as such
+ parties remain in full compliance.
+ 
+-  5. You are not required to accept this License, since you have not
++**5.** You are not required to accept this License, since you have not
+ signed it.  However, nothing else grants you permission to modify or
+ distribute the Program or its derivative works.  These actions are
+ prohibited by law if you do not accept this License.  Therefore, by
+@@ -186,7 +183,7 @@ Program), you indicate your acceptance of this License to do so, and
+ all its terms and conditions for copying, distributing or modifying
+ the Program or works based on it.
+ 
+-  6. Each time you redistribute the Program (or any work based on the
++**6.** Each time you redistribute the Program (or any work based on the
+ Program), the recipient automatically receives a license from the
+ original licensor to copy, distribute or modify the Program subject to
+ these terms and conditions.  You may not impose any further
+@@ -194,7 +191,7 @@ restrictions on the recipients' exercise of the rights granted herein.
+ You are not responsible for enforcing compliance by third parties to
+ this License.
+ 
+-  7. If, as a consequence of a court judgment or allegation of patent
++**7.** If, as a consequence of a court judgment or allegation of patent
+ infringement or for any other reason (not limited to patent issues),
+ conditions are imposed on you (whether by court order, agreement or
+ otherwise) that contradict the conditions of this License, they do not
+@@ -225,8 +222,8 @@ impose that choice.
+ 
+ This section is intended to make thoroughly clear what is believed to
+ be a consequence of the rest of this License.
+-

+-  8. If the distribution and/or use of the Program is restricted in
 +
-+* Wed Nov  5 2003 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.5.5
-+- added space after newsgroup name in .newsrc file
++**8.** If the distribution and/or use of the Program is restricted in
+ certain countries either by patents or by copyrighted interfaces, the
+ original copyright holder who places the Program under this License
+ may add an explicit geographical distribution limitation excluding
+@@ -234,20 +231,20 @@ those countries, so that distribution is permitted only in or among
+ countries not thus excluded.  In such case, this License incorporates
+ the limitation as if written in the body of this License.
+ 
+-  9. The Free Software Foundation may publish revised and/or new versions
++**9.** The Free Software Foundation may publish revised and/or new versions
+ of the General Public License from time to time.  Such new versions will
+ be similar in spirit to the present version, but may differ in detail to
+ address new problems or concerns.
+ 
+ Each version is given a distinguishing version number.  If the Program
+-specifies a version number of this License which applies to it and "any
+-later version", you have the option of following the terms and conditions
++specifies a version number of this License which applies to it and “any
++later version”, you have the option of following the terms and conditions
+ either of that version or of any later version published by the Free
+ Software Foundation.  If the Program does not specify a version number of
+ this License, you may choose any version ever published by the Free Software
+ Foundation.
+ 
+-  10. If you wish to incorporate parts of the Program into other free
++**10.** If you wish to incorporate parts of the Program into other free
+ programs whose distribution conditions are different, write to the author
+ to ask for permission.  For software which is copyrighted by the Free
+ Software Foundation, write to the Free Software Foundation; we sometimes
+@@ -255,19 +252,19 @@ make exceptions for this.  Our decision will be guided by the two goals
+ of preserving the free status of all derivatives of our free software and
+ of promoting the sharing and reuse of software generally.
+ 
+-			    NO WARRANTY
++### NO WARRANTY
+ 
+-  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
++**11.** BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+ FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+ OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
++PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+ OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+ TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+ PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+ REPAIR OR CORRECTION.
+ 
+-  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
++**12.** IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+ WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+ REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+ INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+@@ -277,36 +274,35 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+ PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGES.
+ 
+-		     END OF TERMS AND CONDITIONS
+-

+-	    How to Apply These Terms to Your New Programs
++END OF TERMS AND CONDITIONS
+ 
+-  If you develop a new program, and you want it to be of the greatest
++### How to Apply These Terms to Your New Programs
 +
-+* Sun May 18 2003 Vsevolod Volkov <vvv at mutt.org.ua>
-+- fixed SIGSEGV when posting article
-+
-+* Sat Mar 22 2003 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.5.4
-+
-+* Sat Dec 21 2002 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.5.3
-+- replace safe_free calls by the FREE macro
-+
-+* Fri Dec  6 2002 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.5.2
-+- nntp authentication can be passed after any command
-+
-+* Sat May  4 2002 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.5.1
-+
-+* Thu May  2 2002 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.3.99
-+
-+* Wed Mar 13 2002 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.3.28
-+- fixed SIGSEGV in <get-message>, <get-parent>, <get-children>,
-+  <reconstruct-thread> functions
-+- fixed message about nntp reconnect
-+- fixed <attach-news-message> function using browser
-+- added support of Followup-To: poster
-+- added %n (new articles) in group_index_format
-+- posting articles without inews by default
-+
-+* Wed Jan 23 2002 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.3.27
-+
-+* Fri Jan 18 2002 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.3.26
-+
-+* Thu Jan  3 2002 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.3.25
-+- accelerated speed of access to news->newsgroups hash (by <gul at gul.kiev.ua>)
-+- added default content disposition
-+
-+* Mon Dec  3 2001 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.3.24
-+
-+* Fri Nov  9 2001 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.3.23.2
-+- fixed segfault if mutt_conn_find() returns null
-+
-+* Wed Oct 31 2001 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.3.23.1
-+- added support of LISTGROUP command
-+- added support for servers with broken overview
-+- disabled <flag-message> function on news server
-+- fixed error storing bad authentication information
-+
-+* Wed Oct 10 2001 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.3.23
-+- fixed typo in buffy.c
-+- added substitution of %s parameter in $inews variable
-+
-+* Fri Aug 31 2001 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.3.22.1
-+- update to 1.3.22
-+
-+* Thu Aug 23 2001 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.3.21
-+
-+* Wed Jul 25 2001 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.3.20
-+- removed 'server-hook', use 'account-hook' instead
-+- fixed error opening NNTP server without newsgroup using -f option
-+
-+* Fri Jun  8 2001 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.3.19
-+
-+* Sat May  5 2001 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.3.18
-+- fixed typo in nntp_attempt_features()
-+- changed algorithm of XGTITLE command testing
-+- disabled writing of NNTP password in debug file
-+- fixed reading and writing of long newsrc lines
-+- changed checking of last line while reading lines from server
-+- fixed possible buffer overrun in nntp_parse_newsrc_line()
-+- removed checking of XHDR command
-+- compare NNTP return codes without trailing space
-+
-+* Thu Mar 29 2001 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.3.17
-+- support for 'LIST NEWSGROUPS' command to read descriptions
-+
-+* Fri Mar  2 2001 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.3.16
-+
-+* Wed Feb 14 2001 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.3.15
-+
-+* Sun Jan 28 2001 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.3.14
-+- show number of tagged messages patch from Felix von Leitner <leitner at fefe.de>
-+
-+* Sun Dec 31 2000 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.3.13
-+
-+* Sat Dec 30 2000 Vsevolod Volkov <vvv at mutt.org.ua>
-+- Fixed problem if last article in group is deleted
-+
-+* Fri Dec 22 2000 Vsevolod Volkov <vvv at mutt.org.ua>
-+- Fixed checking of XGTITLE command on some servers
-+
-+* Mon Dec 18 2000 Vsevolod Volkov <vvv at mutt.org.ua>
-+- Added \r in AUTHINFO commands
-+
-+* Mon Nov 27 2000 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.3.12
-+
-+* Wed Nov  1 2000 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.3.11
-+- fixed error opening newsgroup from mutt started with -g or -G
++If you develop a new program, and you want it to be of the greatest
+ possible use to the public, the best way to achieve this is to make it
+ free software which everyone can redistribute and change under these terms.
+ 
+-  To do so, attach the following notices to the program.  It is safest
++To do so, attach the following notices to the program.  It is safest
+ to attach them to the start of each source file to most effectively
+ convey the exclusion of warranty; and each file should have at least
+-the "copyright" line and a pointer to where the full notice is found.
++the “copyright” line and a pointer to where the full notice is found.
+ 
+     <one line to give the program's name and a brief idea of what it does.>
+     Copyright (C) <year>  <name of author>
+-
++    
+     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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+-
++    
++    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.,
++    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ 
+ Also add information on how to contact you by electronic and paper mail.
+ 
+@@ -318,23 +314,23 @@ when it starts in an interactive mode:
+     This is free software, and you are welcome to redistribute it
+     under certain conditions; type `show c' for details.
+ 
+-The hypothetical commands `show w' and `show c' should show the appropriate
++The hypothetical commands `show w` and `show c` should show the appropriate
+ parts of the General Public License.  Of course, the commands you use may
+-be called something other than `show w' and `show c'; they could even be
++be called something other than `show w` and `show c`; they could even be
+ mouse-clicks or menu items--whatever suits your program.
+ 
+ You should also get your employer (if you work as a programmer) or your
+-school, if any, to sign a "copyright disclaimer" for the program, if
++school, if any, to sign a “copyright disclaimer” for the program, if
+ necessary.  Here is a sample; alter the names:
+ 
+-  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+-  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+-
+-  <signature of Ty Coon>, 1 April 1989
+-  Ty Coon, President of Vice
++    Yoyodyne, Inc., hereby disclaims all copyright interest in the program
++    `Gnomovision' (which makes passes at compilers) written by James Hacker.
++    
++    <signature of Ty Coon>, 1 April 1989
++    Ty Coon, President of Vice
+ 
+ This General Public License does not permit incorporating your program into
+ proprietary programs.  If your program is a subroutine library, you may
+ consider it more useful to permit linking proprietary applications with the
+-library.  If this is what you want to do, use the GNU Library General
++library.  If this is what you want to do, use the GNU Lesser General
+ Public License instead of this License.
+diff --git a/LICENSE.md b/LICENSE.md
+new file mode 120000
+index 0000000..3a3e12b
+--- /dev/null
++++ b/LICENSE.md
+@@ -0,0 +1 @@
++GPL
+\ No newline at end of file
+diff --git a/Makefile.am b/Makefile.am
+index 9ee3fae..ecdbfaf 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -10,7 +10,11 @@ IMAP_SUBDIR = imap
+ IMAP_INCLUDES = -I$(top_srcdir)/imap
+ endif
+ 
++if QUICK_BUILD
++SUBDIRS = $(IMAP_SUBDIR)
++else
+ SUBDIRS = m4 po intl doc contrib $(IMAP_SUBDIR)
++endif
+ 
+ bin_SCRIPTS = muttbug flea $(SMIMEAUX_TARGET)
+ 
+@@ -34,7 +38,7 @@ mutt_SOURCES = \
+ 	score.c send.c sendlib.c signal.c sort.c \
+ 	status.c system.c thread.c charset.c history.c lib.c \
+ 	muttlib.c editmsg.c mbyte.c \
+-	url.c ascii.c crypt-mod.c crypt-mod.h safe_asprintf.c
++	url.c ascii.c crypt-mod.c crypt-mod.h safe_asprintf.c version.c
+ 
+ nodist_mutt_SOURCES = $(BUILT_SOURCES)
+ 
+@@ -50,33 +54,44 @@ DEFS=-DPKGDATADIR=\"$(pkgdatadir)\" -DSYSCONFDIR=\"$(sysconfdir)\" \
+ 
+ AM_CPPFLAGS=-I. -I$(top_srcdir) $(IMAP_INCLUDES) $(GPGME_CFLAGS) -Iintl
+ 
+-EXTRA_mutt_SOURCES = account.c bcache.c crypt-gpgme.c crypt-mod-pgp-classic.c \
++EXTRA_mutt_SOURCES = account.c bcache.c compress.c crypt-gpgme.c crypt-mod-pgp-classic.c \
+ 	crypt-mod-pgp-gpgme.c crypt-mod-smime-classic.c \
+ 	crypt-mod-smime-gpgme.c dotlock.c gnupgparse.c hcache.c md5.c \
+ 	mutt_idna.c mutt_sasl.c mutt_socket.c mutt_ssl.c mutt_ssl_gnutls.c \
+ 	mutt_tunnel.c pgp.c pgpinvoke.c pgpkey.c pgplib.c pgpmicalg.c \
+ 	pgppacket.c pop.c pop_auth.c pop_lib.c remailer.c resize.c sha1.c \
+-	smime.c smtp.c utf8.c wcwidth.c \
++	nntp.c newsrc.c \
++	sidebar.c smime.c smtp.c utf8.c wcwidth.c \
+ 	bcache.h browser.h hcache.h mbyte.h mutt_idna.h remailer.h url.h
+ 
+ EXTRA_DIST = COPYRIGHT GPL OPS OPS.PGP OPS.CRYPT OPS.SMIME TODO UPDATING \
+ 	configure account.h \
+-	attach.h buffy.h charset.h copy.h crypthash.h dotlock.h functions.h gen_defs \
++	attach.h buffy.h charset.h compress.h copy.h crypthash.h dotlock.h functions.h gen_defs \
+ 	globals.h hash.h history.h init.h keymap.h mutt_crypt.h \
+ 	mailbox.h mapping.h md5.h mime.h mutt.h mutt_curses.h mutt_menu.h \
+ 	mutt_regex.h mutt_sasl.h mutt_socket.h mutt_ssl.h mutt_tunnel.h \
+ 	mx.h pager.h pgp.h pop.h protos.h rfc1524.h rfc2047.h \
+ 	rfc2231.h rfc822.h rfc3676.h sha1.h sort.h mime.types VERSION prepare \
++	nntp.h ChangeLog.nntp \
+ 	_regex.h OPS.MIX README.SECURITY remailer.c remailer.h browser.h \
+ 	mbyte.h lib.h extlib.c pgpewrap.c smime_keys.pl pgplib.h \
+ 	README.SSL smime.h group.h \
+ 	muttbug pgppacket.h depcomp ascii.h BEWARE PATCHES patchlist.sh \
+-	ChangeLog mkchangelog.sh mutt_idna.h \
++	ChangeLog mkchangelog.sh mutt_idna.h sidebar.h OPS.SIDEBAR \
+ 	snprintf.c regex.c crypt-gpgme.h hcachever.sh.in sys_socket.h \
+-	txt2c.c txt2c.sh version.sh check_sec.sh
++	txt2c.c txt2c.sh version.sh check_sec.sh version.h
+ 
+ EXTRA_SCRIPTS = smime_keys
+ 
++if BUILD_NOTMUCH
++mutt_SOURCES += mutt_notmuch.c mutt_notmuch.h
++mutt_LDADD += $(NOTMUCH_LIBS)
++endif
 +
-+* Thu Oct 12 2000 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.3.10
-+- hotkey 'G' (get-message) replaced with '^G'
++# kz
++EXTRA_DIST += UPDATING.kz README.notmuch OPS.NOTMUCH
 +
-+* Thu Sep 21 2000 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.3.9
-+- changed delay displaying error messages from 1 to 2 seconds
-+- fixed error compiling with nntp and without imap
 +
-+* Wed Sep  6 2000 Vsevolod Volkov <vvv at mutt.org.ua>
-+- fixed catchup in index
-+- fixed nntp_open_mailbox()
+ mutt_dotlock_SOURCES = mutt_dotlock.c
+ mutt_dotlock_LDADD = $(LIBOBJS)
+ mutt_dotlock_DEPENDENCIES = $(LIBOBJS)
+@@ -129,14 +144,15 @@ smime_keys: $(srcdir)/smime_keys.pl
+ keymap_defs.h: $(OPS) $(srcdir)/gen_defs
+ 	$(srcdir)/gen_defs $(OPS) > keymap_defs.h
+ 
+-keymap_alldefs.h: $(srcdir)/OPS $(srcdir)/OPS.PGP $(srcdir)/OPS.MIX $(srcdir)/OPS.CRYPT $(srcdir)/OPS.SMIME $(srcdir)/gen_defs
++keymap_alldefs.h: $(srcdir)/OPS $(srcdir)/OPS.SIDEBAR $(srcdir)/OPS.NOTMUCH $(srcdir)/OPS.PGP $(srcdir)/OPS.MIX $(srcdir)/OPS.CRYPT $(srcdir)/OPS.SMIME $(srcdir)/gen_defs
+ 	rm -f $@
+-	$(srcdir)/gen_defs $(srcdir)/OPS $(srcdir)/OPS.PGP \
++	$(srcdir)/gen_defs $(srcdir)/OPS $(srcdir)/OPS.SIDEBAR $(srcdir)/OPS.NOTMUCH $(srcdir)/OPS.PGP \
+ 		$(srcdir)/OPS.MIX $(srcdir)/OPS.CRYPT $(srcdir)/OPS.SMIME \
+ 			> keymap_alldefs.h
+ 
+-reldate.h: $(srcdir)/ChangeLog
+-	echo 'const char *ReleaseDate = "'`head -n 1 $(srcdir)/ChangeLog | LC_ALL=C cut -d ' ' -f 1`'";' > reldate.h.tmp; \
++reldate.h: $(top_srcdir)/ChangeLog.neomutt
++	date=`head -n 1 $(top_srcdir)/ChangeLog.neomutt | LC_ALL=C cut -b 1-10` && \
++	echo 'const char *ReleaseDate = "'$$date'";' > reldate.h.tmp; \
+ 	cmp -s reldate.h.tmp reldate.h || cp reldate.h.tmp reldate.h; \
+ 	rm reldate.h.tmp
+ 
+@@ -184,17 +200,6 @@ pclean:
+ check-security:
+ 	(cd $(top_srcdir) && ./check_sec.sh)
+ 
+-commit:
+-	@echo "make commit is obsolete; use hg-commit"; false
+-
+-update-changelog:
+-	(cd $(top_srcdir); \
+-	sh ./mkchangelog.sh | cat  - ChangeLog > ChangeLog.$$$$ && mv ChangeLog.$$$$ ChangeLog; \
+-	$${VISUAL:-vi} ChangeLog)
+-
+-mutt-dist:
+-	(cd $(srcdir) && ./build-release )
+-
+ update-doc:
+ 	(cd doc && $(MAKE) update-doc)
+ 
+diff --git a/OPS b/OPS
+index 8414a8b..76d2672 100644
+--- a/OPS
++++ b/OPS
+@@ -8,14 +8,16 @@ OP_BOUNCE_MESSAGE "remail a message to another user"
+ OP_BROWSER_NEW_FILE "select a new file in this directory"
+ OP_BROWSER_VIEW_FILE "view file"
+ OP_BROWSER_TELL "display the currently selected file's name"
+-OP_BROWSER_SUBSCRIBE "subscribe to current mailbox (IMAP only)"
+-OP_BROWSER_UNSUBSCRIBE "unsubscribe from current mailbox (IMAP only)"
++OP_BROWSER_SUBSCRIBE "subscribe to current mbox (IMAP/NNTP only)"
++OP_BROWSER_UNSUBSCRIBE "unsubscribe from current mbox (IMAP/NNTP only)"
+ OP_BROWSER_TOGGLE_LSUB "toggle view all/subscribed mailboxes (IMAP only)"
+ OP_BUFFY_LIST "list mailboxes with new mail"
++OP_CATCHUP "mark all articles in newsgroup as read"
+ OP_CHANGE_DIRECTORY "change directories"
+ OP_CHECK_NEW "check mailboxes for new mail"
+ OP_COMPOSE_ATTACH_FILE "attach file(s) to this message"
+ OP_COMPOSE_ATTACH_MESSAGE "attach message(s) to this message"
++OP_COMPOSE_ATTACH_NEWS_MESSAGE "attach news article(s) to this message"
+ OP_COMPOSE_EDIT_BCC "edit the BCC list"
+ OP_COMPOSE_EDIT_CC "edit the CC list"
+ OP_COMPOSE_EDIT_DESCRIPTION "edit attachment description"
+@@ -26,7 +28,10 @@ OP_COMPOSE_EDIT_FROM "edit the from field"
+ OP_COMPOSE_EDIT_HEADERS "edit the message with headers"
+ OP_COMPOSE_EDIT_MESSAGE "edit the message"
+ OP_COMPOSE_EDIT_MIME "edit attachment using mailcap entry"
++OP_COMPOSE_EDIT_NEWSGROUPS "edit the newsgroups list"
+ OP_COMPOSE_EDIT_REPLY_TO "edit the Reply-To field"
++OP_COMPOSE_EDIT_FOLLOWUP_TO "edit the Followup-To field"
++OP_COMPOSE_EDIT_X_COMMENT_TO "edit the X-Comment-To field"
+ OP_COMPOSE_EDIT_SUBJECT "edit the subject of this message"
+ OP_COMPOSE_EDIT_TO "edit the TO list"
+ OP_CREATE_MAILBOX "create a new mailbox (IMAP only)"
+@@ -56,6 +61,7 @@ OP_DELETE_THREAD "delete all messages in thread"
+ OP_DISPLAY_ADDRESS "display full address of sender"
+ OP_DISPLAY_HEADERS "display message and toggle header weeding"
+ OP_DISPLAY_MESSAGE "display a message"
++OP_EDIT_LABEL "add, change, or delete a message's label"
+ OP_EDIT_MESSAGE "edit the raw message"
+ OP_EDITOR_BACKSPACE "delete the char in front of the cursor"
+ OP_EDITOR_BACKWARD_CHAR "move the cursor one character to the left"
+@@ -85,8 +91,13 @@ OP_EXIT "exit this menu"
+ OP_FILTER "filter attachment through a shell command"
+ OP_FIRST_ENTRY "move to the first entry"
+ OP_FLAG_MESSAGE "toggle a message's 'important' flag"
++OP_FOLLOWUP "followup to newsgroup"
++OP_FORWARD_TO_GROUP "forward to newsgroup"
+ OP_FORWARD_MESSAGE "forward a message with comments"
+ OP_GENERIC_SELECT_ENTRY "select the current entry"
++OP_GET_CHILDREN "get all children of the current message"
++OP_GET_MESSAGE "get message with Message-Id"
++OP_GET_PARENT "get parent of the current message"
+ OP_GROUP_REPLY "reply to all recipients"
+ OP_HALF_DOWN "scroll down 1/2 page"
+ OP_HALF_UP "scroll up 1/2 page"
+@@ -94,11 +105,14 @@ OP_HELP "this screen"
+ OP_JUMP "jump to an index number"
+ OP_LAST_ENTRY "move to the last entry"
+ OP_LIST_REPLY "reply to specified mailing list"
++OP_LOAD_ACTIVE "load list of all newsgroups from NNTP server"
+ OP_MACRO "execute a macro"
+ OP_MAIL "compose a new mail message"
+ OP_MAIN_BREAK_THREAD "break the thread in two"
+ OP_MAIN_CHANGE_FOLDER "open a different folder"
+ OP_MAIN_CHANGE_FOLDER_READONLY "open a different folder in read only mode"
++OP_MAIN_CHANGE_GROUP "open a different newsgroup"
++OP_MAIN_CHANGE_GROUP_READONLY "open a different newsgroup in read only mode"
+ OP_MAIN_CLEAR_FLAG "clear a status flag from a message"
+ OP_MAIN_DELETE_PATTERN "delete messages matching a pattern"
+ OP_MAIN_IMAP_FETCH "force retrieval of mail from IMAP server"
+@@ -127,6 +141,7 @@ OP_MAIN_READ_SUBTHREAD "mark the current subthread as read"
+ OP_MAIN_SET_FLAG "set a status flag on a message"
+ OP_MAIN_SYNC_FOLDER "save changes to mailbox"
+ OP_MAIN_TAG_PATTERN "tag messages matching a pattern"
++OP_MAIN_QUASI_DELETE "delete from mutt, don't touch on disk"
+ OP_MAIN_UNDELETE_PATTERN "undelete messages matching a pattern"
+ OP_MAIN_UNTAG_PATTERN "untag messages matching a pattern"
+ OP_MIDDLE_PAGE "move to the middle of the page"
+@@ -138,14 +153,17 @@ OP_PAGER_HIDE_QUOTED "toggle display of quoted text"
+ OP_PAGER_SKIP_QUOTED "skip beyond quoted text"
+ OP_PAGER_TOP "jump to the top of the message"
+ OP_PIPE "pipe message/attachment to a shell command"
++OP_POST "post message to newsgroup"
+ OP_PREV_ENTRY "move to the previous entry"
+ OP_PREV_LINE "scroll up one line"
+ OP_PREV_PAGE "move to the previous page"
+ OP_PRINT "print the current entry"
++OP_PURGE_MESSAGE "really delete the current entry, bypassing the trash folder"
+ OP_QUERY "query external program for addresses"
+ OP_QUERY_APPEND "append new query results to current results"
+ OP_QUIT "save changes to mailbox and quit"
+ OP_RECALL_MESSAGE "recall a postponed message"
++OP_RECONSTRUCT_THREAD "reconstruct thread containing current message"
+ OP_REDRAW "clear and redraw the screen"
+ OP_REFORMAT_WINCH "{internal}"
+ OP_RENAME_MAILBOX "rename the current mailbox (IMAP only)"
+@@ -160,22 +178,27 @@ OP_SEARCH_TOGGLE "toggle search pattern coloring"
+ OP_SHELL_ESCAPE "invoke a command in a subshell"
+ OP_SORT "sort messages"
+ OP_SORT_REVERSE "sort messages in reverse order"
++OP_SUBSCRIBE_PATTERN "subscribe to newsgroups matching a pattern"
+ OP_TAG "tag the current entry"
+ OP_TAG_PREFIX "apply next function to tagged messages"
+ OP_TAG_PREFIX_COND "apply next function ONLY to tagged messages"
+ OP_TAG_SUBTHREAD "tag the current subthread"
+ OP_TAG_THREAD "tag the current thread"
+ OP_TOGGLE_NEW "toggle a message's 'new' flag"
++OP_TOGGLE_READ "toggle view of read messages"
+ OP_TOGGLE_WRITE "toggle whether the mailbox will be rewritten"
+ OP_TOGGLE_MAILBOXES "toggle whether to browse mailboxes or all files"
+ OP_TOP_PAGE "move to the top of the page"
++OP_UNCATCHUP "mark all articles in newsgroup as unread"
+ OP_UNDELETE "undelete the current entry"
+ OP_UNDELETE_THREAD "undelete all messages in thread"
+ OP_UNDELETE_SUBTHREAD "undelete all messages in subthread"
++OP_UNSUBSCRIBE_PATTERN "unsubscribe from newsgroups matching a pattern"
+ OP_VERSION "show the Mutt version number and date"
+ OP_VIEW_ATTACH "view attachment using mailcap entry if necessary"
+ OP_VIEW_ATTACHMENTS "show MIME attachments"
+ OP_WHAT_KEY "display the keycode for a key press"
++OP_LIMIT_CURRENT_THREAD "limit view to current thread"
+ OP_MAIN_SHOW_LIMIT "show currently active limit pattern"
+ OP_MAIN_COLLAPSE_THREAD "collapse/uncollapse current thread"
+ OP_MAIN_COLLAPSE_ALL "collapse/uncollapse all threads"
+diff --git a/OPS.MIX b/OPS.MIX
+index 4988333..a836226 100644
+--- a/OPS.MIX
++++ b/OPS.MIX
+@@ -1,7 +1,7 @@
+-OP_MIX_USE "Accept the chain constructed"
+-OP_MIX_APPEND "Append a remailer to the chain"
+-OP_MIX_INSERT "Insert a remailer into the chain"
+-OP_MIX_DELETE "Delete a remailer from the chain"
+-OP_MIX_CHAIN_PREV "Select the previous element of the chain"
+-OP_MIX_CHAIN_NEXT "Select the next element of the chain"
++OP_MIX_USE "accept the chain constructed"
++OP_MIX_APPEND "append a remailer to the chain"
++OP_MIX_INSERT "insert a remailer into the chain"
++OP_MIX_DELETE "delete a remailer from the chain"
++OP_MIX_CHAIN_PREV "select the previous element of the chain"
++OP_MIX_CHAIN_NEXT "select the next element of the chain"
+ OP_COMPOSE_MIX "send the message through a mixmaster remailer chain"
+diff --git a/OPS.NOTMUCH b/OPS.NOTMUCH
+new file mode 100644
+index 0000000..4508e4e
+--- /dev/null
++++ b/OPS.NOTMUCH
+@@ -0,0 +1,5 @@
++OP_MAIN_CHANGE_VFOLDER "open a different virtual folder"
++OP_MAIN_VFOLDER_FROM_QUERY "generate virtual folder from query"
++OP_MAIN_MODIFY_LABELS "modify (notmuch) tags"
++OP_MAIN_MODIFY_LABELS_THEN_HIDE "modify labels and then hide message"
++OP_MAIN_ENTIRE_THREAD "read entire thread of the current message"
+diff --git a/OPS.SIDEBAR b/OPS.SIDEBAR
+new file mode 100644
+index 0000000..e39f80c
+--- /dev/null
++++ b/OPS.SIDEBAR
+@@ -0,0 +1,9 @@
++OP_SIDEBAR_NEXT "move the highlight to next mailbox"
++OP_SIDEBAR_NEXT_NEW "move the highlight to next mailbox with new mail"
++OP_SIDEBAR_OPEN "open highlighted mailbox"
++OP_SIDEBAR_PAGE_DOWN "scroll the sidebar down 1 page"
++OP_SIDEBAR_PAGE_UP "scroll the sidebar up 1 page"
++OP_SIDEBAR_PREV "move the highlight to previous mailbox"
++OP_SIDEBAR_PREV_NEW "move the highlight to previous mailbox with new mail"
++OP_SIDEBAR_TOGGLE_VIRTUAL "toggle between mailboxes and virtual mailboxes"
++OP_SIDEBAR_TOGGLE_VISIBLE "make the sidebar (in)visible"
+diff --git a/PATCHES b/PATCHES
+index e69de29..62367db 100644
+--- a/PATCHES
++++ b/PATCHES
+@@ -0,0 +1,21 @@
++patch-quasi-delete-neo-git
++patch-progress-neo-git
++patch-status-color-neo-git
++patch-index-color-neo-git
++patch-nested-if-neo-git
++patch-cond-date-neo-git
++patch-tls-sni-neo-git
++patch-sidebar-neo-git
++patch-ifdef-neo-git
++patch-fmemopen-neo-git
++patch-initials-neo-git
++patch-trash-neo-git
++patch-limit-current-thread-neo-git
++patch-skip-quoted-neo-git
++patch-compress-neo-git
++patch-keywords-neo-git
++patch-nntp-neo-git
++patch-lmdb-neo-git
++patch-1.5.23.smime-encrypt-self.1
++patch-new-mail-neo-git
++patch-smime-encrypt-to-self-neo-git
+diff --git a/README.SSL b/README.SSL
+index 75cac80..90290e0 100644
+--- a/README.SSL
++++ b/README.SSL
+@@ -5,7 +5,7 @@ Compilation
+ -----------
+ If you want to have SSL support in mutt, you need to install OpenSSL
+ (http://www.openssl.org) libraries and headers before compiling.
+-OpenSSL versions 0.9.3 through 0.9.6a have been tested.
++OpenSSL versions 0.9.3 through 1.0.1c have been tested.
+ 
+ For SSL support to be enabled, you need to run the ``configure''
+ script with ``--enable-imap --with-ssl[=PFX]'' parameters.  If the
+@@ -65,6 +65,12 @@ certificate, the connection will be established. Accepted certificates
+ can also be saved so that further connections to the server are
+ automatically accepted. 
+ 
++If OpenSSL was built with support for ServerNameIndication (SNI) and TLS
++is used in the negotiation, mutt will send its idea of the server-name
++as part of the TLS negotiation.  This allows the server to select an
++appropriate certificate, in the event that one server handles multiple
++hostnames with different certificates.
 +
-+* Sat Sep  2 2000 Vsevolod Volkov <vvv at mutt.org.ua>
-+- functions <edit> and <delete-entry> disabled
-+- format of news mailbox names changed to url form
-+- option nntp_attempts removed
-+- option reconnect_news renamed to nntp_reconnect
-+- default value of nntp_poll changed from 30 to 60
-+- error handling improved
+ If your organization has several equivalent IMAP-servers, each of them
+ should have a unique certificate which is signed with a common
+ certificate.  If you want to use all of those servers, you don't need to
+@@ -102,9 +108,15 @@ you know which options do not work, you can set the variables for non-working
+ protocols to know.  The variables for the protocols are ssl_use_tlsv1, 
+ ssl_use_sslv2, and ssl_use_sslv3.
+ 
++To verify TLS SNI support by a server, you can use:
++    openssl s_client -host <imap server> -port <port> \
++        -tls1 -servername <imap server>
 +
-+* Wed Aug 30 2000 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.3.8
-+- new option show_only_unread
-+- add newsgroup completion
 +
-+* Fri Aug  4 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- update to 1.3.7
+ -- 
+ Tommi Komulainen
+ Tommi.Komulainen at iki.fi
+ 
+-Updated by Jeremy Katz
+-katzj at linuxpower.org
++Updated by:
++  Jeremy Katz <katzj at linuxpower.org>
++  Phil Pennock <mutt-dev at spodhuis.org>
+diff --git a/README.compress b/README.compress
+new file mode 100644
+index 0000000..f14569a
+--- /dev/null
++++ b/README.compress
+@@ -0,0 +1,163 @@
++Compressed Folders Patch
++========================
 +
-+* Sat Jul 29 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- update to 1.3.6
++    Read from/write to compressed mailboxes
 +
-+* Sun Jul  9 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- update to 1.3.5
-+- authentication code update
-+- fix for changing to newsgroup from mailbox with read messages
-+- socket code optimization
++Patch
++-----
 +
-+* Wed Jun 21 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- update to 1.3.4
++    To check if Mutt supports "Compress Folders", look for "+USE_COMPRESSED" in
++    the mutt version.
 +
-+* Wed Jun 14 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- don't substitute current newsgroup with deleted new messages
++    Dependencies
++    * mutt-1.6.2
 +
-+* Mon Jun 12 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- update to 1.3.3
-+- fix for substitution of newsgroup after reconnection
-+- fix for loading newsgroups with very long names
-+- fix for loading more than 32768 newsgroups
++Introduction
++------------
 +
-+* Wed May 24 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- update to 1.3.2
++    The Compressed Folder patch allows Mutt to read mailbox files that are
++    compressed. But it isn't limited to compressed files. It works well with
++    encrypted files, too. In fact, if you can create a program/script to
++    convert to and from your format, then Mutt can read it.
 +
-+* Sat May 20 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- update to 1.3.1
++    The patch adds three hooks to Mutt: 'open-hook', 'close-hook' and
++    'append-hook'. They define commands to: uncompress a file; compress a file;
++    append messages to an already compressed file.
 +
-+* Fri May 12 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- update to 1.3
++    There are some examples of both compressed and encrypted files, later. For
++    now, the documentation will just concentrate on compressed files.
 +
-+* Thu May 11 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- update to 1.2
++Commands
++--------
 +
-+* Thu May  4 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- update to 1.1.14
++        open-hook   pattern shell-command
++        close-hook  pattern shell-command
++        append-hook pattern shell-command
 +
-+* Sun Apr 23 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- update to 1.1.12
++    The shell-command must contain two placeholders for filenames: '%f' and
++    '%t'. These represent "from" and "to" filenames. It's a good idea to put
++    quotes around these placeholders.
 +
-+* Fri Apr  7 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- add substitution of newsgroup with new messages by default
++    If you need the exact string "%f" or "%t" in your command, simply double up
++    the "%" character, e.g. "%%f" or "%%t".
 +
-+* Wed Apr  5 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- add attach message from newsgroup
-+- add one-line help in newsreader mode
-+- disable 'change-dir' command in newsgroups browser
-+- add -G option
++    Not all Hooks are Required
 +
-+* Tue Apr  4 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- get default news server name from file /etc/nntpserver
-+- use case insensitive server names
-+- add print-style sequence %s to $newsrc
-+- add -g option
++    | Open | Close | Append | Effect                                      | Useful if                                       |
++    |------|-------|--------|---------------------------------------------|-------------------------------------------------|
++    | Open | -     | -      | Folder is readonly                          | Folder is just a backup                         |
++    | Open | Close | -      | Folder is read/write, but the entire folder | Compression format doesn't support appending    |
++    |      |       |        |     must be written if anything is changed  | Compression format doesn't support appending    |
++    | Open | Close | Append | Folder is read/write and emails can be      | Compression format supports appending           |
++    |      |       |        |     efficiently added to the end            | Compression format supports appending           |
++    | Open | -     | Append | Folder is readonly, but can be appended to  | You want to store emails, but never change them |
 +
-+* Sat Apr  1 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- remove 'X-FTN-Origin' header processing
++    > Note
++    >
++    > The command:
++    > -   should return a non-zero exit status on failure
++    > -   should not delete any files
 +
-+* Thu Mar 30 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- update to 1.1.11
-+- update to 1.1.10
++### Read from compressed mailbox
 +
-+* Thu Mar 23 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- fix mutt_select_newsserver()
-+- remove 'toggle-mode' function
-+- add 'change-newsgroup' function
++        open-hook regexp shell-command
 +
-+* Wed Mar 22 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- fix server-hook
++    If Mutt is unable to open a file, it then looks for 'open-hook' that
++    matches the filename.
 +
-+* Tue Mar 21 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- fix error 'bounce' function after 'post'
-+- add 'forward to newsgroup' function
++    If your compression program doesn't have a well-defined extension, then you
++    can use '.' as the regexp.
 +
-+* Mon Mar 20 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- 'forward' function works in newsreader mode
-+- add 'post' and 'followup' functions to pager and attachment menu
-+- fix active descriptions and allowed flag reload
++#### Example of open-hook
 +
-+* Tue Mar 14 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- update to 1.1.9
-+- remove deleted newsgroups from list
++        open-hook '.gz$' "gzip -cd '%f' > '%t'"
 +
-+* Mon Mar 13 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- update .newsrc in browser
++    * Mutt finds a file, "example.gz", that it can't read
++    * Mutt has an 'open-hook' whose regexp matches the filename: '.gz$'
++    * Mutt uses the command 'gzip -cd' to create a temporary file that it *can*
++    read
 +
-+* Sun Mar 12 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- reload .newsrc if externally modified
-+- fix active cache update
++### Write to a compressed mailbox
 +
-+* Sun Mar  5 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- update to 1.1.8
++        close-hook regexp shell-command
 +
-+* Sat Mar  4 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- patch *.update_list_file is not required
-+- count lines when loading descriptions
-+- remove cache of unsubscribed newsgroups
++    When Mutt has finished with a compressed mail folder, it will look for a
++    matching 'close-hook' to recompress the file. This hook is optional.
 +
-+* Thu Mar  2 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- load list of newsgroups from cache faster
++    > Note
++    >
++    > If the folder has not been modifed, the 'close-hook' will not be called.
 +
-+* Wed Mar  1 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- update to 1.1.7
++#### Example of close-hook
 +
-+* Tue Feb 29 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- fix unread messages in browser
-+- fix newsrc_gen_entries()
++        close-hook '.gz$' "gzip -c '%t' > '%f'"
 +
-+* Mon Feb 28 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- fix mutt_newsgroup_stat()
-+- fix nntp_delete_cache()
-+- fix nntp_get_status()
-+- fix check_children()
-+- fix nntp_fetch_headers()
++    * Mutt has finished with a folder, "example.gz", that it opened with
++    'open-hook'
++    * The folder has been modified
++    * Mutt has a 'close-hook' whose regexp matches the filename: '.gz$'
++    * Mutt uses the command 'gzip -c' to create a new compressed file
 +
-+* Fri Feb 25 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- update to 1.1.5
++### Append to a compressed mailbox
 +
-+* Thu Feb 24 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- fix updating new messages in cache
++        append-hook regexp shell-command
 +
-+* Mon Feb 21 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- change default cache filenames
-+- fix updating new messages in cache
++    When Mutt wants to append an email to a compressed mail folder, it will
++    look for a matching 'append-hook'. This hook is optional.
 +
-+* Fri Feb 18 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- fix segmentation fault in news groups browser
++    Using the 'append-hook' will save time, but Mutt won't be able to determine
++    the type of the mail folder inside the compressed file.
 +
-+* Tue Feb 15 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- update to 1.1.4
++    Mutt will *assume* the type to be that of the '$mbox_type' variable. Mutt
++    also uses this type for temporary files.
 +
-+* Thu Feb 10 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- update to 1.1.3
++    Mutt will only use the 'append-hook' for existing files. The 'close-hook'
++    will be used for empty, or missing files.
 +
-+* Sun Jan 30 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- add X-Comment-To editing
-+- add my_hdr support for Newsgroups:, Followup-To: and X-Comment-To: headers
-+- add variables $ask_followup_to and $ask_x_comment_to
++#### Example of append-hook
 +
-+* Fri Jan 28 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- update to 1.1.2
-diff -urN mutt-1.6.1/color.c mutt-1.6.1-neomutt/color.c
---- mutt-1.6.1/color.c	2016-06-12 18:43:00.397447512 +0100
-+++ mutt-1.6.1-neomutt/color.c	2016-06-12 18:43:00.675451848 +0100
-@@ -34,7 +34,14 @@
- int ColorDefs[MT_COLOR_MAX];
- COLOR_LINE *ColorHdrList = NULL;
- COLOR_LINE *ColorBodyList = NULL;
-+COLOR_LINE *ColorStatusList = NULL;
- COLOR_LINE *ColorIndexList = NULL;
-+COLOR_LINE *ColorIndexAuthorList = NULL;
-+COLOR_LINE *ColorIndexFlagsList = NULL;
-+COLOR_LINE *ColorIndexSubjectList = NULL;
-+#ifdef USE_NOTMUCH
-+COLOR_LINE *ColorIndexTagList = NULL;
-+#endif
- 
- /* local to this file */
- static int ColorQuoteSize;
-@@ -93,7 +100,28 @@
-   { "bold",		MT_COLOR_BOLD },
-   { "underline",	MT_COLOR_UNDERLINE },
-   { "index",		MT_COLOR_INDEX },
-+  { "progress",		MT_COLOR_PROGRESS },
-+  { "index_author",	MT_COLOR_INDEX_AUTHOR },
-+  { "index_collapsed",	MT_COLOR_INDEX_COLLAPSED },
-+  { "index_date",	MT_COLOR_INDEX_DATE },
-+  { "index_flags",	MT_COLOR_INDEX_FLAGS },
-+  { "index_label",	MT_COLOR_INDEX_LABEL },
-+  { "index_number",	MT_COLOR_INDEX_NUMBER },
-+  { "index_size",	MT_COLOR_INDEX_SIZE },
-+  { "index_subject",	MT_COLOR_INDEX_SUBJECT },
-+#ifdef USE_NOTMUCH
-+  { "index_tag",	MT_COLOR_INDEX_TAG },
-+  { "index_tags",	MT_COLOR_INDEX_TAGS },
-+#endif
-   { "prompt",		MT_COLOR_PROMPT },
-+#ifdef USE_SIDEBAR
-+  { "sidebar_divider",	MT_COLOR_DIVIDER },
-+  { "sidebar_flagged",	MT_COLOR_FLAGGED },
-+  { "sidebar_highlight",MT_COLOR_HIGHLIGHT },
-+  { "sidebar_indicator",MT_COLOR_SB_INDICATOR },
-+  { "sidebar_new",	MT_COLOR_NEW },
-+  { "sidebar_spoolfile",MT_COLOR_SB_SPOOLFILE },
-+#endif
-   { NULL,		0 }
- };
- 
-@@ -146,6 +174,9 @@
-   ColorDefs[MT_COLOR_INDICATOR] = A_REVERSE;
-   ColorDefs[MT_COLOR_SEARCH] = A_REVERSE;
-   ColorDefs[MT_COLOR_MARKERS] = A_REVERSE;
-+#ifdef USE_SIDEBAR
-+  ColorDefs[MT_COLOR_HIGHLIGHT] = A_UNDERLINE;
-+#endif
-   /* special meaning: toggle the relevant attribute */
-   ColorDefs[MT_COLOR_BOLD] = 0;
-   ColorDefs[MT_COLOR_UNDERLINE] = 0;
-@@ -384,12 +415,52 @@
-   return _mutt_parse_uncolor(buf, s, data, err, 0);
- }
- 
-+/**
-+ * mutt_do_uncolor - XXX
-+ */
-+static void
-+mutt_do_uncolor (BUFFER *buf, BUFFER *s, COLOR_LINE **ColorList,
-+                 int *do_cache, int parse_uncolor)
-+{
-+	COLOR_LINE *tmp, *last = NULL;
++        append-hook '.gz$' "gzip -c '%t' >> '%f'"
 +
-+	do {
-+		mutt_extract_token (buf, s, 0);
-+		if (mutt_strcmp ("*", buf->data) == 0) {
-+			for (tmp = *ColorList; tmp; ) {
-+				if (!*do_cache) {
-+					*do_cache = 1;
-+				}
-+				last = tmp;
-+				tmp = tmp->next;
-+				mutt_free_color_line (&last, parse_uncolor);
-+			}
-+			*ColorList = NULL;
-+		} else {
-+			for (last = NULL, tmp = *ColorList; tmp; last = tmp, tmp = tmp->next) {
-+				if (mutt_strcmp (buf->data, tmp->pattern) == 0) {
-+					if (!*do_cache) {
-+						*do_cache = 1;
-+					}
-+					dprint (1, (debugfile,"Freeing pattern \"%s\" from ColorList\n",
-+															 tmp->pattern));
-+					if (last) {
-+						last->next = tmp->next;
-+					} else {
-+						*ColorList = tmp->next;
-+					}
-+					mutt_free_color_line (&tmp, parse_uncolor);
-+					break;
-+				}
-+			}
-+		}
-+	} while (MoreArgs (s));
-+}
++    * Mutt wants to append an email to a folder, "example.gz", that it opened
++      with 'open-hook'
++    * Mutt has an 'append-hook' whose regexp matches the filename: '.gz$'
++    * Mutt knows the mailbox type from the '$mbox' variable
++    * Mutt uses the command 'gzip -c' to append to an existing compressed file
 +
- static int _mutt_parse_uncolor (BUFFER *buf, BUFFER *s, unsigned long data,
- 				BUFFER *err, short parse_uncolor)
- {
-   int object = 0, do_cache = 0;
--  COLOR_LINE *tmp, *last = NULL;
--  COLOR_LINE **list;
- 
-   mutt_extract_token (buf, s, 0);
- 
-@@ -399,13 +470,15 @@
-     return (-1);
-   }
- 
--  if (mutt_strncmp (buf->data, "index", 5) == 0)
--    list = &ColorIndexList;
--  else if (mutt_strncmp (buf->data, "body", 4) == 0)
--    list = &ColorBodyList;
--  else if (mutt_strncmp (buf->data, "header", 7) == 0)
--    list = &ColorHdrList;
--  else
-+  if (object > MT_COLOR_INDEX_SUBJECT) { /* uncolor index column */
-+    ColorDefs[object] = 0;
-+    set_option (OPTFORCEREDRAWINDEX);
-+    return 0;
-+  }
++### Empty Files
 +
-+  if ((mutt_strncmp (buf->data, "body",   4) != 0) &&
-+      (mutt_strncmp (buf->data, "header", 6) != 0) &&
-+      (mutt_strncmp (buf->data, "index",  5) != 0))
-   {
-     snprintf (err->data, err->dsize,
- 	      _("%s: command valid only for index, body, header objects"),
-@@ -442,43 +515,22 @@
-     return 0;
-   }
- 
--  do
--  {
--    mutt_extract_token (buf, s, 0);
--    if (!mutt_strcmp ("*", buf->data))
--    {
--      for (tmp = *list; tmp; )
--      {
--        if (!do_cache)
--	  do_cache = 1;
--	last = tmp;
--	tmp = tmp->next;
--	mutt_free_color_line(&last, parse_uncolor);
--      }
--      *list = NULL;
--    }
--    else
--    {
--      for (last = NULL, tmp = *list; tmp; last = tmp, tmp = tmp->next)
--      {
--	if (!mutt_strcmp (buf->data, tmp->pattern))
--	{
--          if (!do_cache)
--	    do_cache = 1;
--	  dprint(1,(debugfile,"Freeing pattern \"%s\" from color list\n",
--	                       tmp->pattern));
--	  if (last)
--	    last->next = tmp->next;
--	  else
--	    *list = tmp->next;
--	  mutt_free_color_line(&tmp, parse_uncolor);
--	  break;
--	}
--      }
--    }
--  }
--  while (MoreArgs (s));
--
-+  if (object == MT_COLOR_BODY)
-+    mutt_do_uncolor (buf, s, &ColorBodyList, &do_cache, parse_uncolor);
-+  else if (object == MT_COLOR_HEADER)
-+    mutt_do_uncolor (buf, s, &ColorHdrList, &do_cache, parse_uncolor);
-+  else if (object == MT_COLOR_INDEX)
-+    mutt_do_uncolor (buf, s, &ColorIndexList, &do_cache, parse_uncolor);
-+  else if (object == MT_COLOR_INDEX_AUTHOR)
-+    mutt_do_uncolor (buf, s, &ColorIndexAuthorList, &do_cache, parse_uncolor);
-+  else if (object == MT_COLOR_INDEX_FLAGS)
-+    mutt_do_uncolor (buf, s, &ColorIndexFlagsList, &do_cache, parse_uncolor);
-+  else if (object == MT_COLOR_INDEX_SUBJECT)
-+    mutt_do_uncolor (buf, s, &ColorIndexSubjectList, &do_cache, parse_uncolor);
-+#ifdef USE_NOTMUCH
-+  else if (object == MT_COLOR_INDEX_TAG)
-+    mutt_do_uncolor(buf, s, &ColorIndexTagList, &do_cache, parse_uncolor);
-+#endif
- 
-   if (do_cache && !option (OPTNOCURSES))
-   {
-@@ -495,7 +547,7 @@
- static int 
- add_pattern (COLOR_LINE **top, const char *s, int sensitive,
- 	     int fg, int bg, int attr, BUFFER *err,
--	     int is_index)
-+	     int is_index, int match)
- {
- 
-   /* is_index used to store compiled pattern
-@@ -566,6 +618,7 @@
-     }
-     tmp->next = *top;
-     tmp->pattern = safe_strdup (s);
-+    tmp->match = match;
- #ifdef HAVE_COLOR
-     if(fg != -1 && bg != -1)
-     {
-@@ -708,7 +761,7 @@
- 		   parser_callback_t callback, short dry_run)
- {
-   int object = 0, attr = 0, fg = 0, bg = 0, q_level = 0;
--  int r = 0;
-+  int r = 0, match = 0;
- 
-   if(parse_object(buf, s, &object, &q_level, err) == -1)
-     return -1;
-@@ -718,18 +771,25 @@
- 
-   /* extract a regular expression if needed */
-   
--  if (object == MT_COLOR_HEADER || object == MT_COLOR_BODY || object == MT_COLOR_INDEX)
--  {
--    if (!MoreArgs (s))
--    {
-+  if ((object == MT_COLOR_BODY) ||
-+      (object == MT_COLOR_HEADER) ||
-+      (object == MT_COLOR_INDEX) ||
-+      (object == MT_COLOR_INDEX_AUTHOR) ||
-+      (object == MT_COLOR_INDEX_FLAGS) ||
-+      (object == MT_COLOR_INDEX_SUBJECT)
-+#ifdef USE_NOTMUCH
-+      || (object == MT_COLOR_INDEX_TAG)
-+#endif
-+      ) {
-+    if (!MoreArgs (s)) {
-       strfcpy (err->data, _("too few arguments"), err->dsize);
--      return (-1);
-+      return -1;
-     }
- 
-     mutt_extract_token (buf, s, 0);
-   }
-    
--  if (MoreArgs (s))
-+  if (MoreArgs (s) && (object != MT_COLOR_STATUS))
-   {
-     strfcpy (err->data, _("too many arguments"), err->dsize);
-     return (-1);
-@@ -754,14 +814,59 @@
- #endif
-   
-   if (object == MT_COLOR_HEADER)
--    r = add_pattern (&ColorHdrList, buf->data, 0, fg, bg, attr, err,0);
-+    r = add_pattern (&ColorHdrList, buf->data, 0, fg, bg, attr, err, 0, match);
-   else if (object == MT_COLOR_BODY)
--    r = add_pattern (&ColorBodyList, buf->data, 1, fg, bg, attr, err, 0);
-+    r = add_pattern (&ColorBodyList, buf->data, 1, fg, bg, attr, err, 0, match);
-+  else if ((object == MT_COLOR_STATUS) && MoreArgs (s)) {
-+    /* 'color status fg bg' can have up to 2 arguments:
-+     * 0 arguments: sets the default status color (handled below by else part)
-+     * 1 argument : colorize pattern on match
-+     * 2 arguments: colorize nth submatch of pattern
-+     */
-+    mutt_extract_token (buf, s, 0);
++    Mutt assumes that an empty file is not compressed. In this situation, unset
++    $save_empty, so that the compressed file will be removed if you delete all
++    of the messages.
 +
-+    if (MoreArgs (s)) {
-+      BUFFER temporary;
-+      memset (&temporary, 0, sizeof (BUFFER));
-+      mutt_extract_token (&temporary, s, 0);
-+      match = atoi (temporary.data);
-+      FREE(&temporary.data);
-+    }
++### Security
 +
-+    if (MoreArgs (s)) {
-+      strfcpy (err->data, _("too many arguments"), err->dsize);
-+      return -1;
-+    }
++    Encrypted files are decrypted into temporary files which are stored in the
++    $tmpdir directory. This could be a security risk.
 +
-+    r = add_pattern (&ColorStatusList, buf->data, 1,
-+		    fg, bg, attr, err, 0, match);
-+  }
-   else if (object == MT_COLOR_INDEX)
-   {
--    r = add_pattern (&ColorIndexList, buf->data, 1, fg, bg, attr, err, 1);
-+    r = add_pattern (&ColorIndexList, buf->data, 1,
-+		    fg, bg, attr, err, 1, match);
-+    set_option (OPTFORCEREDRAWINDEX);
-+  } else if (object == MT_COLOR_INDEX_AUTHOR) {
-+    r = add_pattern (&ColorIndexAuthorList, buf->data, 1,
-+		    fg, bg, attr, err, 1, match);
-+    set_option (OPTFORCEREDRAWINDEX);
-+  } else if (object == MT_COLOR_INDEX_FLAGS) {
-+    r = add_pattern (&ColorIndexFlagsList, buf->data, 1,
-+		    fg, bg, attr, err, 1, match);
-+    set_option (OPTFORCEREDRAWINDEX);
-+  } else if (object == MT_COLOR_INDEX_SUBJECT) {
-+    r = add_pattern (&ColorIndexSubjectList, buf->data, 1,
-+		    fg, bg, attr, err, 1, match);
-+    set_option (OPTFORCEREDRAWINDEX);
-+  }
-+#ifdef USE_NOTMUCH
-+  else if (object == MT_COLOR_INDEX_TAG)
-+  {
-+    r = add_pattern (&ColorIndexTagList, buf->data, 1,
-+		    fg, bg, attr, err, 1, match);
-     set_option (OPTFORCEREDRAWINDEX);
-   }
-+#endif
-   else if (object == MT_COLOR_QUOTED)
-   {
-     if (q_level >= ColorQuoteSize)
-@@ -787,7 +892,11 @@
-       ColorQuote[q_level] = fgbgattr_to_color(fg, bg, attr);
-   }
-   else
-+  {
-     ColorDefs[object] = fgbgattr_to_color(fg, bg, attr);
-+    if (object > MT_COLOR_INDEX_AUTHOR)
-+      set_option (OPTFORCEREDRAWINDEX);
-+  }
- 
-   return (r);
- }
-diff -urN mutt-1.6.1/commands.c mutt-1.6.1-neomutt/commands.c
---- mutt-1.6.1/commands.c	2016-06-12 18:43:00.397447512 +0100
-+++ mutt-1.6.1-neomutt/commands.c	2016-06-12 18:43:00.676451863 +0100
-@@ -40,6 +40,10 @@
- #include "imap.h"
- #endif
- 
-+#ifdef USE_NOTMUCH
-+#include "mutt_notmuch.h"
-+#endif
++See Also
++--------
 +
- #include "buffy.h"
- 
- #include <errno.h>
-@@ -146,7 +150,9 @@
-   }
- 
-   res = mutt_copy_message (fpout, Context, cur, cmflags,
--       	(option (OPTWEED) ? (CH_WEED | CH_REORDER) : 0) | CH_DECODE | CH_FROM | CH_DISPLAY);
-+		(option (OPTWEED) ? (CH_WEED | CH_REORDER) : 0)
-+		| CH_DECODE | CH_FROM | CH_DISPLAY | CH_VIRTUAL);
++    * NeoMutt project
++    * Compile-Time Features
++    * Regular Expressions
++    * $tmpdir
++    * $mbox_type
++    * $save_empty
++    * folder-hook
 +
-   if ((safe_fclose (&fpout) != 0 && errno != EPIPE) || res < 0)
-   {
-     mutt_error (_("Could not copy message"));
-@@ -533,9 +539,9 @@
-   int method = Sort; /* save the current method in case of abort */
- 
-   switch (mutt_multi_choice (reverse ?
--			     _("Rev-Sort (d)ate/(f)rm/(r)ecv/(s)ubj/t(o)/(t)hread/(u)nsort/si(z)e/s(c)ore/s(p)am?: ") :
--			     _("Sort (d)ate/(f)rm/(r)ecv/(s)ubj/t(o)/(t)hread/(u)nsort/si(z)e/s(c)ore/s(p)am?: "),
--			     _("dfrsotuzcp")))
-+			     _("Rev-Sort Date/Frm/Recv/Subj/tO/Thread/Unsort/siZe/sCore/sPam/Label?: ") :
-+			     _("Sort Date/Frm/Recv/Subj/tO/Thread/Unsort/siZe/sCore/sPam/Label?: "),
-+			     _("dfrsotuzcpl")))
-   {
-   case -1: /* abort - don't resort */
-     return -1;
-@@ -579,6 +585,10 @@
-   case 10: /* s(p)am */
-     Sort = SORT_SPAM;
-     break;
++Known Bugs
++----------
 +
-+  case 11: /* (l)abel */
-+    Sort = SORT_LABEL;
-+    break;
-   }
-   if (reverse)
-     Sort |= SORT_REVERSE;
-@@ -720,6 +730,7 @@
-     if (option (OPTDELETEUNTAG))
-       mutt_set_flag (Context, h, M_TAG, 0);
-   }
-+  mutt_set_flag (Context, h, M_APPENDED, 1);
-   
-   return 0;
- }
-@@ -846,19 +857,30 @@
-     }
-     else
-     {
-+      int rc = 0;
++    * The Compressed Folder hooks cannot deal with filenames that contains
++      quotes/apostrophes.
 +
-+#ifdef USE_NOTMUCH
-+      if (Context->magic == M_NOTMUCH)
-+        nm_longrun_init(Context, TRUE);
-+#endif
-       for (i = 0; i < Context->vcount; i++)
-       {
- 	if (Context->hdrs[Context->v2r[i]]->tagged)
- 	{
- 	  mutt_message_hook (Context, Context->hdrs[Context->v2r[i]], M_MESSAGEHOOK);
--	  if (_mutt_save_message(Context->hdrs[Context->v2r[i]],
--			     &ctx, delete, decode, decrypt) != 0)
--          {
--            mx_close_mailbox (&ctx, NULL);
--            return -1;
--          }
-+	  if ((rc = _mutt_save_message(Context->hdrs[Context->v2r[i]],
-+			     &ctx, delete, decode, decrypt) != 0))
-+	    break;
- 	}
-       }
-+#ifdef USE_NOTMUCH
-+      if (Context->magic == M_NOTMUCH)
-+        nm_longrun_done(Context);
-+#endif
-+      if (rc != 0) {
-+	mx_close_mailbox (&ctx, NULL);
-+	return -1;
-+      }
-     }
- 
-     need_buffy_cleanup = (ctx.magic == M_MBOX || ctx.magic == M_MMDF);
-diff -urN mutt-1.6.1/complete.c mutt-1.6.1-neomutt/complete.c
---- mutt-1.6.1/complete.c	2016-06-12 18:43:00.397447512 +0100
-+++ mutt-1.6.1-neomutt/complete.c	2016-06-12 18:43:00.676451863 +0100
-@@ -25,6 +25,9 @@
- #include "mailbox.h"
- #include "imap.h"
- #endif
-+#ifdef USE_NNTP
-+#include "nntp.h"
-+#endif
- 
- #include <dirent.h>
- #include <string.h>
-@@ -48,9 +51,70 @@
-   char filepart[_POSIX_PATH_MAX];
- #ifdef USE_IMAP
-   char imap_path[LONG_STRING];
-+#endif
- 
-   dprint (2, (debugfile, "mutt_complete: completing %s\n", s));
- 
-+#ifdef USE_NNTP
-+  if (option (OPTNEWS))
-+  {
-+    NNTP_SERVER *nserv = CurrentNewsSrv;
-+    unsigned int n = 0;
++Credits
++-------
 +
-+    strfcpy (filepart, s, sizeof (filepart));
++    * Roland Rosenfeld <roland at spinnaker.de>
++    * Alain Penders <Alain at Finale-Dev.com>
++    * Christoph "Myon" Berg <myon at debian.org>
++    * Evgeni Golov <evgeni at debian.org>
++    * Richard Russon <rich at flatcap.org>
 +
-+    /* special case to handle when there is no filepart yet
-+     * find the first subscribed newsgroup */
-+    len = mutt_strlen (filepart);
-+    if (len == 0)
-+    {
-+      for (; n < nserv->groups_num; n++)
-+      {
-+	NNTP_DATA *nntp_data = nserv->groups_list[n];
+diff --git a/README.cond-date b/README.cond-date
+new file mode 100644
+index 0000000..099b02e
+--- /dev/null
++++ b/README.cond-date
+@@ -0,0 +1,163 @@
++Conditional Dates Patch
++=======================
 +
-+	if (nntp_data && nntp_data->subscribed)
-+	{
-+	  strfcpy (filepart, nntp_data->group, sizeof (filepart));
-+	  init = 1;
-+	  n++;
-+	  break;
-+	}
-+      }
-+    }
++    Use rules to choose date format
 +
-+    for (; n < nserv->groups_num; n++)
-+    {
-+      NNTP_DATA *nntp_data = nserv->groups_list[n];
++Patch
++-----
 +
-+      if (nntp_data && nntp_data->subscribed &&
-+	  mutt_strncmp (nntp_data->group, filepart, len) == 0)
-+      {
-+	if (init)
-+	{
-+	  for (i = 0; filepart[i] && nntp_data->group[i]; i++)
-+	  {
-+	    if (filepart[i] != nntp_data->group[i])
-+	    {
-+	      filepart[i] = 0;
-+	      break;
-+	    }
-+	  }
-+	  filepart[i] = 0;
-+	}
-+	else
-+	{
-+	  strfcpy (filepart, nntp_data->group, sizeof (filepart));
-+	  init = 1;
-+	}
-+      }
-+    }
++    To check if Mutt supports "Conditional Dates", look for "patch-cond-date"
++    in the mutt version.
 +
-+    strcpy (s, filepart);
-+    return (init ? 0 : -1);
-+  }
-+#endif
++    Dependencies
++    * mutt-1.6.2
++    * nested-if patch
 +
-+#ifdef USE_IMAP
-   /* we can use '/' as a delimiter, imap_complete rewrites it */
-   if (*s == '=' || *s == '+' || *s == '!')
-   {
-diff -urN mutt-1.6.1/compose.c mutt-1.6.1-neomutt/compose.c
---- mutt-1.6.1/compose.c	2016-06-12 18:43:00.398447528 +0100
-+++ mutt-1.6.1-neomutt/compose.c	2016-06-12 18:43:00.676451863 +0100
-@@ -32,11 +32,19 @@
- #include "mailbox.h"
- #include "sort.h"
- #include "charset.h"
-+#ifdef USE_SIDEBAR
-+#include "sidebar.h"
-+#endif
-+#include "mx.h"
- 
- #ifdef MIXMASTER
- #include "remailer.h"
- #endif
- 
-+#ifdef USE_NNTP
-+#include "nntp.h"
-+#endif
++Introduction
++------------
 +
- #include <errno.h>
- #include <string.h>
- #include <sys/stat.h>
-@@ -67,12 +75,18 @@
-   HDR_CRYPT,
-   HDR_CRYPTINFO,
- 
-+#ifdef USE_NNTP
-+  HDR_NEWSGROUPS,
-+  HDR_FOLLOWUPTO,
-+  HDR_XCOMMENTTO,
-+#endif
++    The "cond-date" patch allows you to construct $index_format expressions
++    based on the age of the email.
 +
-   HDR_ATTACH  = (HDR_FCC + 5) /* where to start printing the attachments */
- };
- 
--#define HDR_XOFFSET 10
--#define TITLE_FMT "%10s" /* Used for Prompts, which are ASCII */
--#define W (COLS - HDR_XOFFSET)
-+#define HDR_XOFFSET 14
-+#define TITLE_FMT "%14s" /* Used for Prompts, which are ASCII */
-+#define W (COLS - HDR_XOFFSET - SidebarWidth)
- 
- static const char * const Prompts[] =
- {
-@@ -83,6 +97,16 @@
-   "Subject: ",
-   "Reply-To: ",
-   "Fcc: "
-+#ifdef USE_NNTP
-+#ifdef MIXMASTER
-+  ,""
-+#endif
-+  ,""
-+  ,""
-+  ,"Newsgroups: "
-+  ,"Followup-To: "
-+  ,"X-Comment-To: "
-+#endif
- };
- 
- static const struct mapping_t ComposeHelp[] = {
-@@ -97,6 +121,19 @@
-   { NULL,	0 }
- };
- 
-+#ifdef USE_NNTP
-+static struct mapping_t ComposeNewsHelp[] = {
-+  { N_("Send"),		OP_COMPOSE_SEND_MESSAGE },
-+  { N_("Abort"),	OP_EXIT },
-+  { "Newsgroups",	OP_COMPOSE_EDIT_NEWSGROUPS },
-+  { "Subj",		OP_COMPOSE_EDIT_SUBJECT },
-+  { N_("Attach file"),	OP_COMPOSE_ATTACH_FILE },
-+  { N_("Descrip"),	OP_COMPOSE_EDIT_DESCRIPTION },
-+  { N_("Help"),		OP_HELP },
-+  { NULL,		0 }
-+};
-+#endif
++    Mutt's default '$index_format' displays email dates in the form:
++    abbreviated-month day-of-month — "Jan 14".
 +
- static void snd_entry (char *b, size_t blen, MUTTMENU *menu, int num)
- {
-     mutt_FormatString (b, blen, 0, NONULL (AttachFormat), mutt_attach_fmt,
-@@ -110,7 +147,7 @@
- 
- static void redraw_crypt_lines (HEADER *msg)
- {
--  mvaddstr (HDR_CRYPT, 0, "Security: ");
-+  mvprintw (HDR_CRYPT, SidebarWidth, TITLE_FMT, "Security: ");
- 
-   if ((WithCrypto & (APPLICATION_PGP | APPLICATION_SMIME)) == 0)
-   {
-@@ -145,16 +182,24 @@
-       addstr (_(" (OppEnc mode)"));
- 
-   clrtoeol ();
--  move (HDR_CRYPTINFO, 0);
-+  move (HDR_CRYPTINFO, SidebarWidth);
-   clrtoeol ();
- 
-   if ((WithCrypto & APPLICATION_PGP)
-       && (msg->security & APPLICATION_PGP) && (msg->security & SIGN))
--    printw ("%s%s", _(" sign as: "), PgpSignAs ? PgpSignAs : _("<default>"));
-+  {
-+    char *s = _(" sign as: ");
-+    int offset = HDR_XOFFSET + SidebarWidth - mbstowcs (NULL, s, 0);
-+    mvprintw (HDR_CRYPTINFO, offset < 0 ? 0 : offset, "%s%s", s,
-+	      PgpSignAs ? PgpSignAs : _("<default>"));
-+  }
- 
-   if ((WithCrypto & APPLICATION_SMIME)
-       && (msg->security & APPLICATION_SMIME) && (msg->security & SIGN)) {
--      printw ("%s%s", _(" sign as: "), SmimeDefaultKey ? SmimeDefaultKey : _("<default>"));
-+    char *s = _(" sign as: ");
-+    int offset = HDR_XOFFSET + SidebarWidth - mbstowcs (NULL, s, 0);
-+    mvprintw (HDR_CRYPTINFO, offset < 0 ? 0 : offset, "%s%s", s,
-+	      SmimeDefaultKey ? SmimeDefaultKey : _("<default>"));
-   }
- 
-   if ((WithCrypto & APPLICATION_SMIME)
-@@ -162,7 +207,7 @@
-       && (msg->security & ENCRYPT)
-       && SmimeCryptAlg
-       && *SmimeCryptAlg) {
--      mvprintw (HDR_CRYPTINFO, 40, "%s%s", _("Encrypt with: "),
-+      mvprintw (HDR_CRYPTINFO, SidebarWidth + 40, "%s%s", _("Encrypt with: "),
- 		NONULL(SmimeCryptAlg));
-   }
- }
-@@ -175,7 +220,8 @@
-   int c;
-   char *t;
- 
--  mvaddstr (HDR_MIX, 0,     "     Mix: ");
-+  /* L10N: "Mix" refers to the MixMaster chain for anonymous email */
-+  mvprintw (HDR_MIX, SidebarWidth, TITLE_FMT, _("Mix: "));
- 
-   if (!chain)
-   {
-@@ -190,7 +236,7 @@
-     if (t && t[0] == '0' && t[1] == '\0')
-       t = "<random>";
-     
--    if (c + mutt_strlen (t) + 2 >= COLS)
-+    if (c + mutt_strlen (t) + 2 >= COLS - SidebarWidth)
-       break;
- 
-     addstr (NONULL(t));
-@@ -242,20 +288,42 @@
- 
-   buf[0] = 0;
-   rfc822_write_address (buf, sizeof (buf), addr, 1);
--  mvprintw (line, 0, TITLE_FMT, Prompts[line - 1]);
-+  mvprintw (line, SidebarWidth, TITLE_FMT, Prompts[line - 1]);
-   mutt_paddstr (W, buf);
- }
- 
- static void draw_envelope (HEADER *msg, char *fcc)
- {
-+#ifdef USE_SIDEBAR
-+  mutt_sb_draw();
-+#endif
-   draw_envelope_addr (HDR_FROM, msg->env->from);
-+#ifdef USE_NNTP
-+  if (!option (OPTNEWSSEND))
-+  {
-+#endif
-   draw_envelope_addr (HDR_TO, msg->env->to);
-   draw_envelope_addr (HDR_CC, msg->env->cc);
-   draw_envelope_addr (HDR_BCC, msg->env->bcc);
--  mvprintw (HDR_SUBJECT, 0, TITLE_FMT, Prompts[HDR_SUBJECT - 1]);
-+#ifdef USE_NNTP
-+  }
-+  else
-+  {
-+    mvprintw (HDR_TO, 0, TITLE_FMT , Prompts[HDR_NEWSGROUPS - 1]);
-+    mutt_paddstr (W, NONULL (msg->env->newsgroups));
-+    mvprintw (HDR_CC, 0, TITLE_FMT , Prompts[HDR_FOLLOWUPTO - 1]);
-+    mutt_paddstr (W, NONULL (msg->env->followup_to));
-+    if (option (OPTXCOMMENTTO))
-+    {
-+      mvprintw (HDR_BCC, 0, TITLE_FMT , Prompts[HDR_XCOMMENTTO - 1]);
-+      mutt_paddstr (W, NONULL (msg->env->x_comment_to));
-+    }
-+  }
-+#endif
-+  mvprintw (HDR_SUBJECT, SidebarWidth, TITLE_FMT, Prompts[HDR_SUBJECT - 1]);
-   mutt_paddstr (W, NONULL (msg->env->subject));
-   draw_envelope_addr (HDR_REPLYTO, msg->env->reply_to);
--  mvprintw (HDR_FCC, 0, TITLE_FMT, Prompts[HDR_FCC - 1]);
-+  mvprintw (HDR_FCC, SidebarWidth, TITLE_FMT, Prompts[HDR_FCC - 1]);
-   mutt_paddstr (W, fcc);
- 
-   if (WithCrypto)
-@@ -266,7 +334,7 @@
- #endif
- 
-   SETCOLOR (MT_COLOR_STATUS);
--  mvaddstr (HDR_ATTACH - 1, 0, _("-- Attachments"));
-+  mvaddstr (HDR_ATTACH - 1, SidebarWidth, _("-- Attachments"));
-   clrtoeol ();
- 
-   NORMAL_COLOR;
-@@ -302,7 +370,7 @@
-   /* redraw the expanded list so the user can see the result */
-   buf[0] = 0;
-   rfc822_write_address (buf, sizeof (buf), *addr, 1);
--  move (line, HDR_XOFFSET);
-+  move (line, HDR_XOFFSET + SidebarWidth);
-   mutt_paddstr (W, buf);
-   
-   return 0;
-@@ -504,6 +572,12 @@
-   /* Sort, SortAux could be changed in mutt_index_menu() */
-   int oldSort, oldSortAux;
-   struct stat st;
-+#ifdef USE_NNTP
-+  int news = 0;		/* is it a news article ? */
++    The format is configurable but only per-mailbox. This patch allows you to
++    configure the display depending on the age of the email.
 +
-+  if (option (OPTNEWSSEND))
-+    news++;
-+#endif
- 
-   mutt_attach_init (msg->content);
-   idx = mutt_gen_attach_list (msg->content, -1, idx, &idxlen, &idxmax, 0, 1);
-@@ -514,10 +588,18 @@
-   menu->make_entry = snd_entry;
-   menu->tag = mutt_tag_attach;
-   menu->data = idx;
-+#ifdef USE_NNTP
-+  if (news)
-+    menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_COMPOSE, ComposeNewsHelp);
-+  else
-+#endif
-   menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_COMPOSE, ComposeHelp);
--  
++    Potential Formatting Scheme
 +
-   while (loop)
-   {
-+#ifdef USE_NNTP
-+    unset_option (OPTNEWS);	/* for any case */
-+#endif
-     switch (op = mutt_menuLoop (menu))
-     {
-       case OP_REDRAW:
-@@ -530,6 +612,10 @@
-         mutt_message_hook (NULL, msg, M_SEND2HOOK);
- 	break;
-       case OP_COMPOSE_EDIT_TO:
-+#ifdef USE_NNTP
-+	if (news)
-+	  break;
-+#endif
- 	menu->redraw = edit_address_list (HDR_TO, &msg->env->to);
- 	if (option (OPTCRYPTOPPORTUNISTICENCRYPT))
- 	{
-@@ -539,6 +625,10 @@
-         mutt_message_hook (NULL, msg, M_SEND2HOOK);
-         break;
-       case OP_COMPOSE_EDIT_BCC:
-+#ifdef USE_NNTP
-+	if (news)
-+	  break;
-+#endif
- 	menu->redraw = edit_address_list (HDR_BCC, &msg->env->bcc);
- 	if (option (OPTCRYPTOPPORTUNISTICENCRYPT))
- 	{
-@@ -548,6 +638,10 @@
-         mutt_message_hook (NULL, msg, M_SEND2HOOK);
- 	break;
-       case OP_COMPOSE_EDIT_CC:
-+#ifdef USE_NNTP
-+	if (news)
-+	  break;
-+#endif
- 	menu->redraw = edit_address_list (HDR_CC, &msg->env->cc);
- 	if (option (OPTCRYPTOPPORTUNISTICENCRYPT))
- 	{
-@@ -556,6 +650,62 @@
- 	}
-         mutt_message_hook (NULL, msg, M_SEND2HOOK);	
-         break;
-+#ifdef USE_NNTP
-+      case OP_COMPOSE_EDIT_NEWSGROUPS:
-+	if (news)
-+	{
-+	  if (msg->env->newsgroups)
-+	    strfcpy (buf, msg->env->newsgroups, sizeof (buf));
-+	  else
-+	    buf[0] = 0;
-+	  if (mutt_get_field ("Newsgroups: ", buf, sizeof (buf), 0) == 0)
-+	  {
-+	    mutt_str_replace (&msg->env->newsgroups, buf);
-+	    move (HDR_TO, HDR_XOFFSET);
-+	    if (msg->env->newsgroups)
-+	      mutt_paddstr (W, msg->env->newsgroups);
-+	    else
-+	      clrtoeol ();
-+	  }
-+	}
-+	break;
-+      case OP_COMPOSE_EDIT_FOLLOWUP_TO:
-+	if (news)
-+	{
-+	  if (msg->env->followup_to)
-+	    strfcpy (buf, msg->env->followup_to, sizeof (buf));
-+	  else
-+	    buf[0] = 0;
-+	  if (mutt_get_field ("Followup-To: ", buf, sizeof (buf), 0) == 0)
-+	  {
-+	    mutt_str_replace (&msg->env->followup_to, buf);
-+	    move (HDR_CC, HDR_XOFFSET);
-+	    if (msg->env->followup_to)
-+	      mutt_paddstr (W, msg->env->followup_to);
-+	    else
-+	      clrtoeol ();
-+	  }
-+	}
-+	break;
-+      case OP_COMPOSE_EDIT_X_COMMENT_TO:
-+	if (news && option (OPTXCOMMENTTO))
-+	{
-+	  if (msg->env->x_comment_to)
-+	    strfcpy (buf, msg->env->x_comment_to, sizeof (buf));
-+	  else
-+	    buf[0] = 0;
-+	  if (mutt_get_field ("X-Comment-To: ", buf, sizeof (buf), 0) == 0)
-+	  {
-+	    mutt_str_replace (&msg->env->x_comment_to, buf);
-+	    move (HDR_BCC, HDR_XOFFSET);
-+	    if (msg->env->x_comment_to)
-+	      mutt_paddstr (W, msg->env->x_comment_to);
-+	    else
-+	      clrtoeol ();
-+	  }
-+	}
-+	break;
-+#endif
-       case OP_COMPOSE_EDIT_SUBJECT:
- 	if (msg->env->subject)
- 	  strfcpy (buf, msg->env->subject, sizeof (buf));
-@@ -564,7 +714,7 @@
- 	if (mutt_get_field ("Subject: ", buf, sizeof (buf), 0) == 0)
- 	{
- 	  mutt_str_replace (&msg->env->subject, buf);
--	  move (HDR_SUBJECT, HDR_XOFFSET);
-+	  move (HDR_SUBJECT, HDR_XOFFSET + SidebarWidth);
- 	  if (msg->env->subject)
- 	    mutt_paddstr (W, msg->env->subject);
- 	  else
-@@ -582,7 +732,7 @@
- 	{
- 	  strfcpy (fcc, buf, fcclen);
- 	  mutt_pretty_mailbox (fcc, fcclen);
--	  move (HDR_FCC, HDR_XOFFSET);
-+	  move (HDR_FCC, HDR_XOFFSET + SidebarWidth);
- 	  mutt_paddstr (W, fcc);
- 	  fccSet = 1;
- 	}
-@@ -686,7 +836,8 @@
- 	  numfiles = 0;
- 	  files = NULL;
- 
--	  if (_mutt_enter_fname (prompt, fname, sizeof (fname), &menu->redraw, 0, 1, &files, &numfiles) == -1 ||
-+	  if (_mutt_enter_fname (prompt, fname, sizeof (fname),
-+			&menu->redraw, 0, 1, &files, &numfiles, 0) == -1 ||
- 	      *fname == '\0')
- 	    break;
- 
-@@ -724,6 +875,9 @@
-         break;
- 
-       case OP_COMPOSE_ATTACH_MESSAGE:
-+#ifdef USE_NNTP
-+      case OP_COMPOSE_ATTACH_NEWS_MESSAGE:
-+#endif
- 	{
- 	  char *prompt;
- 	  HEADER *h;
-@@ -731,7 +885,22 @@
- 	  fname[0] = 0;
- 	  prompt = _("Open mailbox to attach message from");
- 
-+#ifdef USE_NNTP
-+	  unset_option (OPTNEWS);
-+	  if (op == OP_COMPOSE_ATTACH_NEWS_MESSAGE)
-+	  {
-+	    if (!(CurrentNewsSrv = nntp_select_server (NewsServer, 0)))
-+	      break;
++    | Email Sent        | Format  | Example |
++    |-------------------|---------|---------|
++    | Today             | '%H:%M' | 13:23   |
++    | This Month        | '%a %d' | Thu 17  |
++    | This Year         | '%b %d' | Dec 10  |
++    | Older than 1 Year | '%m/%y' | 06/14   |
 +
-+	    prompt = _("Open newsgroup to attach message from");
-+	    set_option (OPTNEWS);
-+	  }
-+#endif
++    For an explanation of the date formatting strings, see 'strftime(3).'
 +
- 	  if (Context)
-+#ifdef USE_NNTP
-+	  if ((op == OP_COMPOSE_ATTACH_MESSAGE) ^ (Context->magic == M_NNTP))
-+#endif
- 	  {
- 	    strfcpy (fname, NONULL (Context->path), sizeof (fname));
- 	    mutt_pretty_mailbox (fname, sizeof (fname));
-@@ -740,6 +909,11 @@
- 	  if (mutt_enter_fname (prompt, fname, sizeof (fname), &menu->redraw, 1) == -1 || !fname[0])
- 	    break;
- 
-+#ifdef USE_NNTP
-+	  if (option (OPTNEWS))
-+	    nntp_expand_path (fname, sizeof (fname), &CurrentNewsSrv->conn->account);
-+	  else
-+#endif
- 	  mutt_expand_path (fname, sizeof (fname));
- #ifdef USE_IMAP
-           if (!mx_is_imap (fname))
-@@ -747,6 +921,9 @@
- #ifdef USE_POP
-           if (!mx_is_pop (fname))
- #endif
-+#ifdef USE_NNTP
-+	  if (!mx_is_nntp (fname) && !option (OPTNEWS))
-+#endif
- 	  /* check to make sure the file exists and is readable */
- 	  if (access (fname, R_OK) == -1)
- 	  {
-@@ -1231,7 +1408,7 @@
-          if (msg->content->next)
-            msg->content = mutt_make_multipart (msg->content);
- 
--         if (mutt_write_fcc (fname, msg, NULL, 0, NULL) < 0)
-+         if (mutt_write_fcc (fname, msg, NULL, 0, NULL, NULL) < 0)
-            msg->content = mutt_remove_multipart (msg->content);
-          else
-            mutt_message _("Message written.");
-diff -urN mutt-1.6.1/compress.c mutt-1.6.1-neomutt/compress.c
---- mutt-1.6.1/compress.c	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/compress.c	2016-06-12 18:43:00.677451879 +0100
-@@ -0,0 +1,826 @@
-+/* Copyright (C) 1997 Alain Penders <Alain at Finale-Dev.com>
-+ * Copyright (C) 2016 Richard Russon <rich at flatcap.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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-+ */
++    By carefully picking your formats, the dates can remain unambiguous and
++    compact.
 +
-+#if HAVE_CONFIG_H
-+#include "config.h"
-+#endif
++    Mutt's conditional format strings have the form: (whitespace introduced for
++    clarity)
 +
-+#include <errno.h>
-+#include <string.h>
-+#include <sys/stat.h>
-+#include <unistd.h>
++        %? TEST ? TRUE & FALSE ?
 +
-+#include "mutt.h"
-+#include "mailbox.h"
-+#include "mutt_curses.h"
-+#include "mx.h"
++    The examples below use the test "%[" — the date of the message in the local
++    timezone. They will also work with "%(" — the local time that the message
++    arrived.
 +
-+/* Notes:
-+ * Any references to compressed files also apply to encrypted files.
-+ * ctx->path     == plaintext file
-+ * ctx->realpath == compressed file
-+ */
++    The date tests are of the form:
 +
-+/**
-+ * struct COMPRESS_INFO - Private data for compress
-+ *
-+ * This object gets attached to the mailbox's CONTEXT.
-+ */
-+typedef struct
-+{
-+	const char *append;   /* append-hook command */
-+	const char *close;    /* close-hook  command */
-+	const char *open;     /* open-hook   command */
-+	off_t size;           /* size of the compressed file */
-+} COMPRESS_INFO;
++        %[nX? TRUE & FALSE ?
 +
-+char echo_cmd[HUGE_STRING];
++    * "n" is an optional count (defaults to 1 if missing)
++    * "X" is the time period
 +
-+/**
-+ * lock_mailbox - Try to lock a mailbox (exclusively)
-+ * @ctx:  Mailbox to lock
-+ * @fp:   File pointer to the mailbox file
-+ * @excl: Lock exclusively?
-+ *
-+ * Try to (exclusively) lock the mailbox.  If we succeed, then we mark the
-+ * mailbox as locked.  If we fail, but we didn't want exclusive rights, then
-+ * the mailbox will be marked readonly.
-+ *
-+ * Returns:
-+ *	 0: Success (locked or readonly)
-+ *	-1: Error (can't lock the file)
-+ */
-+static int
-+lock_mailbox (CONTEXT *ctx, FILE *fp, int excl)
-+{
-+	if (!ctx || !fp)
-+		return -1;
++    Date Formatting Codes
 +
-+	int r = mx_lock_file (ctx->realpath, fileno (fp), excl, 1, 1);
++    | Letter | Time Period |
++    |--------|-------------|
++    | y      | Years       |
++    | m      | Months      |
++    | w      | Weeks       |
++    | d      | Days        |
++    | H      | Hours       |
++    | M      | Minutes     |
 +
-+	if (r == 0) {
-+		ctx->locked = 1;
-+	} else if (excl == 0) {
-+		ctx->readonly = 1;
-+		return 0;
-+	}
++    Date Tests
 +
-+	return r;
-+}
++    | Test   | Meaning              |
++    |--------|----------------------|
++    | '%[y'  | This year            |
++    | '%[1y' | This year            |
++    | '%[6m' | In the last 6 months |
++    | '%[w'  | This week            |
++    | '%[d'  | Today                |
++    | '%[4H' | In the last 4 hours  |
 +
-+/**
-+ * restore_path - Put back the original mailbox name
-+ * @ctx: Mailbox to modify
-+ *
-+ * When we use a compressed mailbox, we change the CONTEXT to refer to the
-+ * uncompressed file.  We store the original name in ctx->realpath.
-+ *	ctx->path     = "/tmp/mailbox"
-+ *	ctx->realpath = "mailbox.gz"
-+ *
-+ * When we have finished with a compressed mailbox, we put back the original
-+ * name.
-+ *	ctx->path     = "mailbox.gz"
-+ *	ctx->realpath = NULL
-+ */
-+static void
-+restore_path (CONTEXT *ctx)
-+{
-+	if (!ctx)
-+		return;
++### Example 1
 +
-+	FREE(&ctx->path);
-+	ctx->path = ctx->realpath;
-+}
++    We start with a one-condition test.
 +
-+/**
-+ * remove_file - Delete the plaintext file
-+ * @ctx: Mailbox
-+ *
-+ * Delete the uncompressed file of a mailbox.
-+ * This only works for mbox or mmdf mailbox files.
-+ */
-+static void
-+remove_file (const CONTEXT *ctx)
-+{
-+	if (!ctx)
-+		return;
++    Example 1
 +
-+	if ((ctx->magic == M_MBOX) || (ctx->magic == M_MMDF)) {
-+		remove (ctx->path);
-+	}
-+}
++    | Test   | Date Range | Format String | Example    |
++    |--------|------------|---------------|------------|
++    | '%[1m' | This month | '%[%b %d]'    | Dec 10     |
++    |        | Older      | '%[%Y-%m-%d]' | 2015-04-23 |
 +
-+/**
-+ * unlock_mailbox - Unlock a mailbox
-+ * @ctx: Mailbox to unlock
-+ * @fp:  File pointer to mailbox file
-+ *
-+ * Unlock a mailbox previously locked by lock_mailbox().
-+ */
-+static void
-+unlock_mailbox (CONTEXT *ctx, FILE *fp)
-+{
-+	if (!ctx || !fp)
-+		return;
++    The $index_format string would contain:
 +
-+	if (ctx->locked) {
-+		fflush (fp);
++        %?[1m?%[%b %d]&%[%Y-%m-%d]?
 +
-+		mx_unlock_file (ctx->realpath, fileno (fp), 1);
-+		ctx->locked = 0;
-+	}
-+}
++    Reparsed a little, for clarity, you can see the test condition and the two
++    format strings.
 +
-+/**
-+ * file_exists - Does the file exist?
-+ * @path: Pathname to check
-+ *
-+ * Returns:
-+ *	1: File exists
-+ *	0: Non-existant file
-+ */
-+static int
-+file_exists (const char *path)
-+{
-+	if (!path)
-+		return 0;
++        %?[1m?        &           ?
++              %[%b %d] %[%Y-%m-%d]
 +
-+	return (access (path, W_OK) != 0 && errno == ENOENT) ? 1 : 0;
-+}
++### Example 2
 +
-+/**
-+ * find_hook - Find a hook to match a path
-+ * @type: Type of hook, e.g. M_CLOSEHOOK
-+ * @path: Filename to test
-+ *
-+ * Each hook has a type and a pattern.  Find a command that matches the type
-+ * and path supplied. e.g.
-+ *
-+ * User config:
-+ *	open-hook '\.gz$' "gzip -cd '%f' > '%t'"
-+ *
-+ * Call:
-+ *	find_hook (M_OPENHOOK, "myfile.gz");
-+ *
-+ * Returns:
-+ *	string: Matching hook command
-+ *	NULL:   No matches
-+ */
-+static const char *
-+find_hook (int type, const char *path)
-+{
-+	if (!path)
-+		return NULL;
++    This example contains three test conditions and four date formats.
 +
-+	const char *c = mutt_find_hook (type, path);
-+	return (!c || !*c) ? NULL : c;
-+}
++    Example 2
 +
-+/**
-+ * get_append_command - Get the command for appending to a file
-+ * @ctx:  Mailbox to append to
-+ * @path: Compressed file
-+ *
-+ * If the file exists, we can use the 'append-hook' command.
-+ * Otherwise, use the 'close-hook' command.
-+ *
-+ * Returns:
-+ *	string: Append command or Close command
-+ *	NULL:   On error
-+ */
-+static const char *
-+get_append_command (const CONTEXT *ctx, const char *path)
-+{
-+	if (!path || !ctx)
-+		return NULL;
++    | Test  | Date Range | Format String | Example |
++    |-------|------------|---------------|---------|
++    | '%[d' | Today      | '%[%H:%M ] '  | 12:34   |
++    | '%[m' | This month | '%[%a %d]'    | Thu 12  |
++    | '%[y' | This year  | '%[%b %d]'    | Dec 10  |
++    |       | Older      | '%[%m/%y ]'   | 06/15   |
 +
-+	COMPRESS_INFO *ci = (COMPRESS_INFO *) ctx->compress_info;
++    The $index_format string would contain:
 +
-+	return (file_exists (path)) ? ci->append : ci->close;
-+}
++        %<[y?%<[m?%<[d?%[%H:%M ]&%[%a %d]>&%[%b %d]>&%[%m/%y ]>
 +
-+/**
-+ * set_compress_info - Find the compress hooks for a mailbox
-+ * @ctx: Mailbox to examine
-+ *
-+ * When a mailbox is opened, we check if there are any matching hooks.
-+ *
-+ * Note: Caller must free the COMPRESS_INFO when done.
-+ *
-+ * Returns:
-+ *	COMPRESS_INFO: Hook info for the mailbox's path
-+ *	NULL:          On error
-+ */
-+static COMPRESS_INFO *
-+set_compress_info (CONTEXT *ctx)
-+{
-+	if (!ctx)
-+		return NULL;
++    Reparsed a little, for clarity, you can see the test conditions and the
++    four format strings.
 +
-+	COMPRESS_INFO *ci;
++        %<[y?                                       &%[%m/%y ]>  Older
++             %<[m?                        &%[%b %d]>             This year
++                  %<[d?         &%[%a %d]>                       This month
++                       %[%H:%M ]                                 Today
 +
-+	/* Now lets uncompress this thing */
-+	ci = safe_malloc (sizeof (COMPRESS_INFO));
-+	ctx->compress_info = (void*) ci;
-+	ci->append = find_hook (M_APPENDHOOK, ctx->path);
-+	ci->open   = find_hook (M_OPENHOOK, ctx->path);
-+	ci->close  = find_hook (M_CLOSEHOOK, ctx->path);
-+	return ci;
-+}
++    This a another view of the same example, with some whitespace for clarity.
 +
-+/**
-+ * setup_paths - Set the mailbox paths
-+ * @ctx: Mailbox to modify
-+ *
-+ * Save the compressed filename in ctx->realpath.
-+ * Create a temporary file and put its name in ctx->path.
-+ *
-+ * Note: ctx->path will be freed by restore_path()
-+ */
-+static void
-+setup_paths (CONTEXT *ctx)
-+{
-+	if (!ctx)
-+		return;
++        %<[y? %<[m? %<[d? AAA & BBB > & CCC > & DDD >
 +
-+	char tmppath[_POSIX_PATH_MAX];
++        AAA = %[%H:%M ]
++        BBB = %[%a %d]
++        CCC = %[%b %d]
++        DDD = %[%m/%y ]
 +
-+	/* Setup the right paths */
-+	ctx->realpath = ctx->path;
 +
-+	/* Uncompress to /tmp */
-+	mutt_mktemp (tmppath, sizeof(tmppath));
-+	ctx->path = safe_strdup (tmppath);
-+}
++Variables
++---------
 +
-+/**
-+ * get_size - Get the size of a file
-+ * @path: File to measure
-+ *
-+ * Returns:
-+ *	number: Size in bytes
-+ *	0: XXX -1 on error?
-+ */
-+static int
-+get_size (const char *path)
-+{
-+	if (!path)
-+		return 0;
++    The "cond-date" patch doesn't have any config of its own. It modifies the
++    behavior of the format strings.
 +
-+	struct stat sb;
-+	if (stat (path, &sb) != 0)
-+		return 0;
++See Also
++--------
 +
-+	return sb.st_size;
-+}
++    * NeoMutt project
++    * $index_format
++    * nested-if patch
++    * 'strftime(3)'
 +
-+/**
-+ * store_size - Save the size of the compressed file
-+ * @ctx: Mailbox
-+ *
-+ * Save the compressed file size in the compress_info struct.
-+ */
-+static void
-+store_size (const CONTEXT *ctx)
-+{
-+	if (!ctx)
-+		return;
++Known Bugs
++----------
 +
-+	COMPRESS_INFO *ci = (COMPRESS_INFO *) ctx->compress_info;
-+	ci->size = get_size (ctx->realpath);
-+}
++    Date parsing doesn't quite do what you expect. "1w" doesn't mean the "in
++    the last 7 days", but "*this* week". This doesn't match the normal Mutt
++    behaviour: for example '~d>1w' means emails dated in the last 7 days.
 +
-+/**
-+ * cb_format_str - Expand the filenames in the command string
-+ * @dest:        Buffer in which to save string
-+ * @destlen:     Buffer length
-+ * @col:         Starting column, UNUSED
-+ * @op:          printf-like operator, e.g. 't'
-+ * @src:         printf-like format string
-+ * @prefix:      Field formatting string, UNUSED
-+ * @ifstring:    If condition is met, display this string, UNUSED
-+ * @elsestring:  Otherwise, display this string, UNUSED
-+ * @data:        Pointer to our sidebar_entry
-+ * @flags:       Format flags, UNUSED
-+ *
-+ * cb_format_str is a callback function for mutt_FormatString.  It understands
-+ * two operators. '%f' : 'from' filename, '%t' : 'to' filename.
-+ *
-+ * Returns: src (unchanged)
-+ */
-+static const char *
-+cb_format_str (char *dest, size_t destlen, size_t col, char op, const char *src,
-+	const char *fmt, const char *ifstring, const char *elsestring,
-+	unsigned long data, format_flag flags)
-+{
-+	if (!fmt || !dest || (data == 0))
-+		return src;
++Credits
++-------
 +
-+	char tmp[SHORT_STRING];
++    * Aaron Schrab <aaron at schrab.com>
++    * Eric Davis <edavis at insanum.com>
++    * Richard Russon <rich at flatcap.org>
 +
-+	CONTEXT *ctx = (CONTEXT *) data;
+diff --git a/README.fmemopen b/README.fmemopen
+new file mode 100644
+index 0000000..9bd7de7
+--- /dev/null
++++ b/README.fmemopen
+@@ -0,0 +1,47 @@
++Fmemopen Patch
++==============
 +
-+	switch (op) {
-+		case 'f':
-+			/* Compressed file */
-+			snprintf (tmp, sizeof (tmp), "%%%ss", fmt);
-+			snprintf (dest, destlen, tmp, ctx->realpath);
-+			break;
-+		case 't':
-+			/* Plaintext, temporary file */
-+			snprintf (tmp, sizeof (tmp), "%%%ss", fmt);
-+			snprintf (dest, destlen, tmp, ctx->path);
-+			break;
-+	}
-+	return src;
-+}
++    Replace some temporary files with memory buffers
 +
-+/**
-+ * get_compression_cmd - Expand placeholders in command string
-+ * @ctx: Mailbox for paths
-+ * @cmd: Command string from config file
-+ *
-+ * This function takes a hook command and expands the filename placeholders
-+ * within it.  The function calls mutt_FormatString() to do the replacement
-+ * which calls our callback function cb_format_str(). e.g.
-+ *
-+ * Template command:
-+ *	gzip -cd '%f' > '%t'
-+ *
-+ * Result:
-+ *	gzip -dc '~/mail/abc.gz' > '/tmp/xyz'
-+ *
-+ * Note: Caller must free the returned string.
-+ *
-+ * Returns:
-+ *	string: Expanded command string
-+ *	NULL:   Error occurred
-+ */
-+static char *
-+get_compression_cmd (const CONTEXT *ctx, const char *cmd)
-+{
-+	if (!cmd || !ctx)
-+		return NULL;
++Patch
++-----
 +
-+	char expanded[_POSIX_PATH_MAX];
++    To check if Mutt supports "fmemopen", look for "patch-fmemopen" in the mutt
++    version.
 +
-+	mutt_FormatString (expanded, sizeof (expanded), 0, cmd, cb_format_str, (unsigned long) ctx, 0);
-+	return safe_strdup (expanded);
-+}
++    Dependencies
++    * mutt-1.6.2
++    * 'open_memstream()', 'fmemopen()' from glibc
 +
++Introduction
++------------
 +
-+/**
-+ * comp_can_read - Can we read from this file?
-+ * @path: Pathname of file to be tested
-+ *
-+ * Search for an 'open-hook' with a regex that matches the path.
-+ *
-+ * A match means it's our responsibility to open the file.
-+ *
-+ * Returns:
-+ *	1: Yes, we can read the file
-+ *	0: No, we cannot read the file
-+ */
-+int
-+comp_can_read (const char *path)
-+{
-+	if (!path)
-+		return 0;
++    The "fmemopen" patch speeds up some searches.
 +
-+	return find_hook (M_OPENHOOK, path) ? 1 : 0;
-+}
++    This patch changes a few places where Mutt creates temporary files. It
++    replaces them with in-memory buffers. This should improve the performance
++    when searching the header or body using the $thorough_search option.
 +
-+/**
-+ * comp_can_append - Can we append to this path?
-+ * @path: pathname of file to be tested
-+ *
-+ * To append to a file we can either use an 'append-hook' or a combination of
-+ * 'open-hook' and 'close-hook'.
-+ *
-+ * A match means it's our responsibility to append to the file.
-+ *
-+ * Returns:
-+ *	1: Yes, we can append to the file
-+ *	0: No, appending isn't possible
-+ */
-+int
-+comp_can_append (const char *path)
-+{
-+	if (!path)
-+		return 0;
++    There are no user-configurable parts.
 +
-+	int magic;
++    This patch depends on 'open_memstream()' and 'fmemopen()'. They are
++    provided by glibc. Without them, Mutt will simply create temporary files.
 +
-+	if (!file_exists (path)) {
-+		char *dir_path = safe_strdup(path);
-+		char *aux = strrchr(dir_path, '/');
-+		int dir_valid = 1;
-+		if (aux) {
-+			*aux='\0';
-+			if (access(dir_path, W_OK|X_OK))
-+				dir_valid = 0;
-+		}
-+		FREE(&dir_path);
-+		return dir_valid && (find_hook (M_CLOSEHOOK, path) ? 1 : 0);
-+	}
++See Also
++--------
 +
-+	magic = mx_get_magic (path);
++    * NeoMutt project
++    * Compile-Time Features
++    * 'fmemopen(3)'
 +
-+	if (magic != 0 && magic != M_COMPRESSED)
-+		return 0;
++Known Bugs
++----------
 +
-+	return (find_hook (M_APPENDHOOK, path)
-+			|| (find_hook (M_OPENHOOK, path)
-+			&& find_hook (M_CLOSEHOOK, path))) ? 1 : 0;
-+}
++    None
 +
-+/**
-+ * comp_valid_command - Is this command string allowed?
-+ * @cmd:  Command string
-+ *
-+ * A valid command string must have both "%f" (from file) and "%t" (to file).
-+ * We don't check if we can actually run the command.
-+ *
-+ * Returns:
-+ *	1: Valid command
-+ *	0: "%f" and/or "%t" is missing
-+ */
-+int
-+comp_valid_command (const char *cmd)
-+{
-+	if (!cmd)
-+		return 0;
++Credits
++-------
 +
-+	return (strstr (cmd, "%f") && strstr (cmd, "%t")) ? 1 : 0;
-+}
++    * Julius Plenz <plenz at cis.fu-berlin.de>
++    * Richard Russon <rich at flatcap.org>
 +
-+/**
-+ * comp_check_mailbox - Perform quick sanity check
-+ * @ctx: Mailbox
-+ *
-+ * Compare the stored size (in the CONTEXT) against the size in our
-+ * COMPRESS_INFO.
-+ *
-+ * The return codes are picked to match mx_check_mailbox().
-+ *
-+ * Returns:
-+ *	 0: Mailbox OK
-+ *	-1: Mailbox bad
-+ */
-+int
-+comp_check_mailbox (CONTEXT *ctx)
-+{
-+	if (!ctx)
-+		return -1;
+diff --git a/README.ifdef b/README.ifdef
+new file mode 100644
+index 0000000..f723216
+--- /dev/null
++++ b/README.ifdef
+@@ -0,0 +1,57 @@
++Ifdef Patch
++===========
 +
-+	COMPRESS_INFO *ci = (COMPRESS_INFO *) ctx->compress_info;
++    Conditional config options
 +
-+	if (get_size (ctx->realpath) != ci->size) {
-+		FREE(&ctx->compress_info);
-+		FREE(&ctx->realpath);
-+		mutt_error _("Mailbox was corrupted!");
-+		return -1;
-+	}
-+	return 0;
-+}
++Patch
++-----
 +
-+/**
-+ * comp_open_read - XXX
-+ * @ctx: Mailbox to open
-+ *
-+ * Returns:
-+ *	 0: Success
-+ *	-1: Failure
-+ */
-+int
-+comp_open_read (CONTEXT *ctx)
-+{
-+	if (!ctx)
-+		return 0;
++    To check if Mutt supports "ifdef", look for "patch-ifdef" in the mutt
++    version.
 +
-+	char *cmd;
-+	FILE *fp;
-+	int rc;
++    Dependencies
++    * mutt-1.6.2
 +
-+	COMPRESS_INFO *ci = set_compress_info (ctx);
-+	if (!ci->open) {
-+		ctx->magic = 0;
-+		FREE(&ctx->compress_info);
-+		return -1;
-+	}
++Introduction
++------------
 +
-+	if (!ci->close || access (ctx->path, W_OK) != 0)
-+		ctx->readonly = 1;
++    The "ifdef" patch introduces three new commands to Mutt and allow you to
++    share one config file between versions of Mutt that may have different
++    features compiled in.
 +
-+	setup_paths (ctx);
-+	store_size (ctx);
++        ifdef  symbol config-command [args...]  # If a symbol is defined
++        ifndef symbol config-command [args...]  # If a symbol is not defined
++        finish                                  # Finish reading the current file
 +
-+	if (!ctx->quiet)
-+		mutt_message (_("Decompressing %s..."), ctx->realpath);
++    Here a symbol can be a $variable, <function>, command or compile-time
++    symbol, such as "USE_IMAP".
 +
-+	cmd = get_compression_cmd (ctx, ci->open);
-+	if (!cmd) {
-+		return -1;
-+	}
-+	dprint (2, (debugfile, "DecompressCmd: '%s'\n", cmd));
++    'finish' is particularly useful when combined with 'ifndef'. e.g.
 +
-+	fp = fopen (ctx->realpath, "r");
-+	if (!fp) {
-+		mutt_perror (ctx->realpath);
-+		FREE(&cmd);
-+		return -1;
-+	}
++        # Sidebar config file
++        ifndef USE_SIDEBAR finish
 +
-+	mutt_block_signals();
-+	if (lock_mailbox (ctx, fp, 0) == -1) {
-+		fclose (fp);
-+		mutt_unblock_signals();
-+		mutt_error _("Unable to lock mailbox!");
-+		FREE(&cmd);
-+		return -1;
-+	}
++Commands
++--------
 +
-+	endwin();
-+	fflush (stdout);
-+	sprintf(echo_cmd,_("echo Decompressing %s..."),ctx->realpath);
-+	mutt_system(echo_cmd);
-+	rc = mutt_system (cmd);
-+	unlock_mailbox (ctx, fp);
-+	mutt_unblock_signals();
-+	fclose (fp);
++        ifdef  symbol "config-command [args]"
++        ifndef symbol "config-command [args]"
++        finish
 +
-+	if (rc != 0) {
-+		mutt_any_key_to_continue (NULL);
-+		ctx->magic = 0;
-+		FREE(&ctx->compress_info);
-+		mutt_error (_("Error executing: %s : unable to open the mailbox!\n"), cmd);
-+		/* remove the partial uncompressed file */
-+		remove_file (ctx);
-+		restore_path (ctx);
-+	}
-+	FREE(&cmd);
-+	if (rc != 0)
-+		return -1;
++See Also
++--------
 +
-+	if (comp_check_mailbox (ctx))
-+		return -1;
++    * NeoMutt project
 +
-+	ctx->magic = mx_get_magic (ctx->path);
++Known Bugs
++----------
 +
-+	return 0;
-+}
++    None
 +
-+/**
-+ * comp_open_append - XXX
-+ * @ctx: Mailbox to append to
-+ *
-+ * Returns:
-+ *	 0: Success
-+ *	-1: Failure
-+ */
-+int
-+comp_open_append (CONTEXT *ctx)
-+{
-+	if (!ctx)
-+		return 0;
++Credits
++-------
 +
-+	FILE *fh;
-+	COMPRESS_INFO *ci = set_compress_info (ctx);
++    * Cedric Duval <cedricduval at free.fr>
++    * Matteo F. Vescovi <mfvescovi at gmail.com>
++    * Richard Russon <rich at flatcap.org>
 +
-+	if (!get_append_command (ctx, ctx->path)) {
-+		if (ci->open && ci->close) {
-+			return (comp_open_read (ctx));
-+		}
+diff --git a/README.index-color b/README.index-color
+new file mode 100644
+index 0000000..fca7c18
+--- /dev/null
++++ b/README.index-color
+@@ -0,0 +1,82 @@
++Index Color Patch
++=================
 +
-+		ctx->magic = 0;
-+		FREE(&ctx->compress_info);
-+		return -1;
-+	}
++    Custom rules for theming the email index
 +
-+	setup_paths (ctx);
++Patch
++-----
 +
-+	ctx->magic = DefaultMagic;
++    To check if Mutt supports "Index Color", look for "patch-index-color" in
++    the mutt version.
 +
-+	if (file_exists (ctx->realpath)) {
-+		if (ctx->magic == M_MBOX || ctx->magic == M_MMDF) {
-+			if ((fh = safe_fopen (ctx->path, "w"))) {
-+				fclose (fh);
-+			}
-+		}
-+	}
-+	/* No error checking - the parent function will catch it */
++    Dependencies
++    * mutt-1.6.2
++    * status-color patch
 +
-+	return 0;
-+}
++Introduction
++------------
 +
-+/**
-+ * comp_sync - XXX
-+ * @ctx: Mailbox to sync
-+ *
-+ * Returns:
-+ *	 0: Success
-+ *	-1: Failure
-+ */
-+int
-+comp_sync (CONTEXT *ctx)
-+{
-+	if (!ctx)
-+		return 0;
++    The "index-color" patch allows you to specify colors for individual parts
++    of the email index. e.g. Subject, Author, Flags.
 +
-+	char *cmd;
-+	int rc = 0;
-+	FILE *fp;
-+	COMPRESS_INFO *ci = (COMPRESS_INFO *) ctx->compress_info;
++    First choose which part of the index you'd like to color. Then, if needed,
++    pick a pattern to match.
 +
-+	if (!ctx->quiet)
-+		mutt_message (_("Compressing %s..."), ctx->realpath);
++    Note: The pattern does not have to refer to the object you wish to color.
++    e.g.
 +
-+	cmd = get_compression_cmd (ctx, ci->close);
-+	if (!cmd)
-+		return -1;
++        color index_author red default "~smutt"
 +
-+	fp = fopen (ctx->realpath, "a");
-+	if (!fp) {
-+		mutt_perror (ctx->realpath);
-+		FREE(&cmd);
-+		return -1;
-+	}
++    The author appears red when the subject (~s) contains "mutt".
 +
-+	mutt_block_signals();
-+	if (lock_mailbox (ctx, fp, 1) == -1) {
-+		fclose (fp);
-+		mutt_unblock_signals();
-+		mutt_error _("Unable to lock mailbox!");
-+		store_size (ctx);
-+		FREE(&cmd);
-+		return -1;
-+	}
++Colors
++------
 +
-+	dprint (2, (debugfile, "CompressCommand: '%s'\n", cmd));
++    All the colors default to 'default', i.e. unset.
 +
-+	endwin();
-+	fflush (stdout);
-+	sprintf(echo_cmd,_("echo Compressing %s..."), ctx->realpath);
-+	mutt_system(echo_cmd);
-+	if (mutt_system (cmd) != 0) {
-+		mutt_any_key_to_continue (NULL);
-+		mutt_error (_("%s: Error compressing mailbox! Original mailbox deleted, uncompressed one kept!\n"), ctx->path);
-+		rc = -1;
-+	}
++    The index objects can be themed using the 'color' command. Some objects
++    require a pattern.
 +
-+	unlock_mailbox (ctx, fp);
-+	mutt_unblock_signals();
-+	fclose (fp);
++        color index-object foreground background
++        color index-object foreground background pattern
 +
-+	FREE(&cmd);
++    Index Colors
 +
-+	store_size (ctx);
++    | Object            | Pattern | Highlights                                   |
++    |-------------------|---------|----------------------------------------------|
++    | 'index'           | yes     | Entire index line                            |
++    | 'index_author'    | yes     | Author name, %A %a %F %L %n                  |
++    | 'index_collapsed' | no      | Number of messages in a collapsed thread, %M |
++    | 'index_date'      | no      | Date field                                   |
++    | 'index_flags'     | yes     | Message flags, %S %Z                         |
++    | 'index_label'     | no      | Message label, %y %Y                         |
++    | 'index_number'    | no      | Message number, %C                           |
++    | 'index_size'      | no      | Message size, %c %l                          |
++    | 'index_subject'   | yes     | Subject, %s                                  |
 +
-+	return rc;
-+}
++See Also
++--------
 +
-+/**
-+ * comp_fast_close - XXX
-+ * @ctx: Mailbox to close
-+ *
-+ * close a compressed mailbox
-+ */
-+void
-+comp_fast_close (CONTEXT *ctx)
-+{
-+	if (!ctx)
-+		return;
++    * NeoMutt project
++    * Regular Expressions
++    * Patterns
++    * $index_format
++    * Color command
++    * Status-Color patch
++    * Keywords patch
 +
-+	dprint (2, (debugfile, "comp_fast_close called on '%s'\n",
-+		ctx->path));
++Known Bugs
++----------
 +
-+	if (ctx->compress_info) {
-+		if (ctx->fp) {
-+			fclose (ctx->fp);
-+		}
-+		ctx->fp = NULL;
-+		/* if the folder was removed, remove the gzipped folder too */
-+		if ((ctx->magic > 0)
-+				&& (access (ctx->path, F_OK) != 0)
-+				&& ! option (OPTSAVEEMPTY))
-+			remove (ctx->realpath);
-+		else
-+			remove_file (ctx);
++    None
 +
-+		restore_path (ctx);
-+		FREE(&ctx->compress_info);
-+	}
-+}
++Credits
++-------
 +
-+/**
-+ * comp_slow_close - XXX
-+ * @ctx: Mailbox to close (slowly)
-+ *
-+ * Returns:
-+ *	 0: Success
-+ *	-1: Failure
-+ */
-+int
-+comp_slow_close (CONTEXT *ctx)
-+{
-+	if (!ctx)
-+		return -1;
++    * Christian Aichinger <Greek0 at gmx.net>
++    * Christoph "Myon" Berg <myon at debian.org>
++    * Elimar Riesebieter <riesebie at lxtec.de>
++    * Eric Davis <edavis at insanum.com>
++    * Vladimir Marek <Vladimir.Marek at oracle.com>
++    * Richard Russon <rich at flatcap.org>
 +
-+	FILE *fp;
-+	const char *append;
-+	char *cmd;
-+	COMPRESS_INFO *ci = (COMPRESS_INFO *) ctx->compress_info;
+diff --git a/README.initials b/README.initials
+new file mode 100644
+index 0000000..76b04ba
+--- /dev/null
++++ b/README.initials
+@@ -0,0 +1,48 @@
++Initials Expando Patch
++======================
 +
-+	dprint (2, (debugfile, "comp_slow_close called on '%s'\n", ctx->path));
++    Expando for author's initials
 +
-+	if (!(ctx->append
-+		&& ((append = get_append_command (ctx, ctx->realpath))
-+		|| (append = ci->close)))) {
-+		/* if we can not or should not append, we only have to remove the
-+		 * compressed info, because sync was already called */
-+		comp_fast_close (ctx);
-+		return 0;
-+	}
++Patch
++-----
 +
-+	if (ctx->fp) {
-+		fclose (ctx->fp);
-+		ctx->fp = NULL;
-+	}
++    To check if Mutt supports "Initials", look for "patch-initials" in the mutt
++    version.
 +
-+	if (!ctx->quiet) {
-+		if (append == ci->close) {
-+			mutt_message (_("Compressing %s..."), ctx->realpath);
-+		} else {
-+			mutt_message (_("Compressed-appending to %s..."), ctx->realpath);
-+		}
-+	}
++    Dependencies
++    * mutt-1.6.2
 +
-+	cmd = get_compression_cmd (ctx, append);
-+	if (!cmd)
-+		return -1;
++Introduction
++------------
 +
-+	fp = fopen (ctx->realpath, "a");
-+	if (!fp) {
-+		mutt_perror (ctx->realpath);
-+		FREE(&cmd);
-+		return -1;
-+	}
++    The "initials" patch adds an expando (%I) for an author's initials.
 +
-+	mutt_block_signals();
-+	if (lock_mailbox (ctx, fp, 1) == -1) {
-+		fclose (fp);
-+		mutt_unblock_signals();
-+		mutt_error _("Unable to lock mailbox!");
-+		FREE(&cmd);
-+		return -1;
-+	}
++    The index panel displays a list of emails. Its layout is controlled by the
++    $index_format variable. Using this expando saves space in the index panel.
++    This can be useful if you are regularly working with a small set of people.
 +
-+	dprint (2, (debugfile, "CompressCmd: '%s'\n", cmd));
++Variables
++---------
 +
-+	endwin();
-+	fflush (stdout);
++    This patch has no config of its own. It adds an expando which can be used
++    in the $index_format variable.
 +
-+	if (append == ci->close) {
-+		sprintf(echo_cmd,_("echo Compressing %s..."), ctx->realpath);
-+	} else {
-+		sprintf(echo_cmd,_("echo Compressed-appending to %s..."), ctx->realpath);
-+	}
-+	mutt_system(echo_cmd);
++See Also
++--------
 +
-+	if (mutt_system (cmd) != 0) {
-+		mutt_any_key_to_continue (NULL);
-+		mutt_error (_(" %s: Error compressing mailbox!  Uncompressed one kept!\n"),
-+			ctx->path);
-+		FREE(&cmd);
-+		unlock_mailbox (ctx, fp);
-+		mutt_unblock_signals();
-+		fclose (fp);
-+		return -1;
-+	}
++    * NeoMutt project
++    * $index_format
++    * index-color patch
++    * folder-hook
 +
-+	unlock_mailbox (ctx, fp);
-+	mutt_unblock_signals();
-+	fclose (fp);
-+	remove_file (ctx);
-+	restore_path (ctx);
-+	FREE(&cmd);
-+	FREE(&ctx->compress_info);
++Known Bugs
++----------
 +
-+	return 0;
-+}
++    None
 +
-diff -urN mutt-1.6.1/compress.h mutt-1.6.1-neomutt/compress.h
---- mutt-1.6.1/compress.h	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/compress.h	2016-06-12 18:43:00.677451879 +0100
-@@ -0,0 +1,32 @@
-+/* Copyright (C) 1997 Alain Penders <Alain at Finale-Dev.com>
-+ * Copyright (C) 2016 Richard Russon <rich at flatcap.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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-+ */
++Credits
++-------
 +
-+#ifndef _COMPRESS_H_
-+#define _COMPRESS_H_
++    * Vsevolod Volkov <vvv at mutt.org.ua>
++    * Richard Russon <rich at flatcap.org>
 +
-+int  comp_can_append    (const char *path);
-+int  comp_can_read      (const char *path);
-+int  comp_check_mailbox (CONTEXT *ctx);
-+void comp_fast_close    (CONTEXT *ctx);
-+int  comp_open_append   (CONTEXT *ctx);
-+int  comp_open_read     (CONTEXT *ctx);
-+int  comp_slow_close    (CONTEXT *ctx);
-+int  comp_sync          (CONTEXT *ctx);
-+int  comp_valid_command (const char *cmd);
+diff --git a/README.keywords b/README.keywords
+new file mode 100644
+index 0000000..a5c0dc6
+--- /dev/null
++++ b/README.keywords
+@@ -0,0 +1,107 @@
++Keywords Patch
++==============
 +
-+#endif /* _COMPRESS_H_ */
-diff -urN mutt-1.6.1/configure.ac mutt-1.6.1-neomutt/configure.ac
---- mutt-1.6.1/configure.ac	2016-06-12 18:43:00.398447528 +0100
-+++ mutt-1.6.1-neomutt/configure.ac	2016-06-12 18:43:00.677451879 +0100
-@@ -175,6 +175,47 @@
- 	SMIMEAUX_TARGET="smime_keys"
- fi
- 
-+AC_ARG_ENABLE(sidebar, AC_HELP_STRING([--enable-sidebar], [Enable Sidebar support]),
-+[       if test x$enableval = xyes ; then
-+		AC_DEFINE(USE_SIDEBAR, 1, [Define if you want support for the sidebar.])
-+		OPS="$OPS \$(srcdir)/OPS.SIDEBAR"
-+                MUTT_LIB_OBJECTS="$MUTT_LIB_OBJECTS sidebar.o"
-+        fi
-+])
++    Labels/Tagging for emails
 +
-+AC_ARG_ENABLE(notmuch, AC_HELP_STRING([--enable-notmuch], [Enable NOTMUCH support]),
-+[       if test x$enableval = xyes ; then
-+		AC_CHECK_LIB(notmuch, notmuch_database_open,,
-+			AC_MSG_ERROR([Unable to find Notmuch library]))
-+		AC_DEFINE(USE_NOTMUCH,1,[ Define if you want support for the notmuch. ])
-+		NOTMUCH_LIBS="-lnotmuch"
-+		OPS="$OPS \$(srcdir)/OPS.NOTMUCH"
-+		need_notmuch="yes"
++Patch
++-----
 +
-+		AC_MSG_CHECKING([for notmuch api version 3])
-+		AC_COMPILE_IFELSE( [AC_LANG_PROGRAM(
-+					[[#include <notmuch.h>]],
-+					[[notmuch_database_open("/path", NOTMUCH_DATABASE_MODE_READ_ONLY, (notmuch_database_t**)NULL);]]
-+					)],
-+		[notmuch_api_3=yes
-+			AC_DEFINE([NOTMUCH_API_3], 1, [Define to 1 if you have the notmuch api version 3.])
-+			],
-+		[notmuch_api_3=no]
-+		)
-+		AC_MSG_RESULT([$notmuch_api_3])
-+        fi
-+])
-+AM_CONDITIONAL(BUILD_NOTMUCH, test x$need_notmuch = xyes)
++    To check if Mutt supports "Keywords", look for "patch-keywords" in the mutt
++    version.
 +
++    Dependencies
++    * mutt-1.6.2
 +
-+AC_ARG_ENABLE(compressed, AC_HELP_STRING([--enable-compressed], [Enable compressed folders support]),
-+[       if test x$enableval = xyes ; then
-+                AC_DEFINE(USE_COMPRESSED, 1, [Define to enable compressed folders support.])
-+                MUTT_LIB_OBJECTS="$MUTT_LIB_OBJECTS compress.o"
-+        fi
-+])
-+AM_CONDITIONAL(BUILD_COMPRESS, test x$need_compress = xyes)
++Introduction
++------------
 +
- AC_ARG_WITH(mixmaster, AS_HELP_STRING([--with-mixmaster@<:@=PATH@:>@],[Include Mixmaster support]),
-   [if test "$withval" != no
-    then
-@@ -309,10 +350,11 @@
- AC_HEADER_STDC
- 
- AC_CHECK_HEADERS(stdarg.h sys/ioctl.h ioctl.h sysexits.h)
--AC_CHECK_HEADERS(sys/time.h sys/resource.h)
-+AC_CHECK_HEADERS(sys/time.h sys/resource.h sys/syscall.h)
- AC_CHECK_HEADERS(unix.h)
- 
- AC_CHECK_FUNCS(setrlimit getsid)
-+AC_CHECK_FUNCS(fgets_unlocked fgetc_unlocked)
- 
- AC_MSG_CHECKING(for sig_atomic_t in signal.h)
- AC_EGREP_HEADER(sig_atomic_t,signal.h,
-@@ -354,7 +396,7 @@
- 
- AC_CHECK_FUNCS(fgetpos memmove setegid srand48 strerror)
- 
--AC_REPLACE_FUNCS([setenv strcasecmp strdup strsep strtok_r wcscasecmp])
-+AC_REPLACE_FUNCS([setenv strcasecmp strdup strndup strnlen strsep strtok_r wcscasecmp])
- AC_REPLACE_FUNCS([strcasestr mkdtemp])
- 
- AC_CHECK_FUNC(getopt)
-@@ -600,6 +642,15 @@
- ])
- AM_CONDITIONAL(BUILD_IMAP, test x$need_imap = xyes)
- 
-+AC_ARG_ENABLE(nntp, AC_HELP_STRING([--enable-nntp],[Enable NNTP support]),
-+[	if test x$enableval = xyes ; then
-+		AC_DEFINE(USE_NNTP,1,[ Define if you want support for the NNTP protocol. ])
-+		MUTT_LIB_OBJECTS="$MUTT_LIB_OBJECTS nntp.o newsrc.o"
-+		need_nntp="yes"
-+		need_socket="yes"
-+	fi
-+])
++    Unify label/keyword handling.
 +
- AC_ARG_ENABLE(smtp, AS_HELP_STRING([--enable-smtp],[include internal SMTP relay support]),
- 	[if test $enableval = yes; then
- 		AC_DEFINE(USE_SMTP, 1, [Include internal SMTP relay support])
-@@ -607,7 +658,7 @@
- 		need_socket="yes"
- 	fi])
- 
--if test x"$need_imap" = xyes -o x"$need_pop" = xyes ; then
-+if test x"$need_imap" = xyes -o x"$need_pop" = xyes -o x"$need_nntp" = xyes ; then
-   MUTT_LIB_OBJECTS="$MUTT_LIB_OBJECTS bcache.o"
- fi
- 
-@@ -1065,6 +1116,7 @@
- AC_SUBST(MUTT_LIB_OBJECTS)
- AC_SUBST(LIBIMAP)
- AC_SUBST(LIBIMAPDEPS)
-+AC_SUBST(NOTMUCH_LIBS)
- 
- dnl -- iconv/gettext --
- 
-@@ -1076,6 +1128,13 @@
- 
- MUTT_AM_GNU_GETTEXT
- 
-+AC_ARG_ENABLE(quick_build, AC_HELP_STRING([--enable-quick-build], [Speed up the build (skip non-code)]),
-+[       if test x$enableval = xyes && test "$BUILD_INCLUDED_LIBINTL" = "no"; then
-+		need_quick_build="yes"
-+        fi
-+])
-+AM_CONDITIONAL(QUICK_BUILD, test x$need_quick_build = xyes)
++    Since x-labels were added to mutt in 2000, a number of other approaches to
++    what we now call "tagging" have also emerged. One of them was even made
++    standard in RFC 2822. This update unifies the handling of all these
++    strategies.
 +
- if test "$am_cv_func_iconv" != "yes"
- then
-   AC_MSG_WARN([Configuring without iconv support. See INSTALL for details])
-@@ -1308,6 +1367,8 @@
-   AC_DEFINE(HAVE_LANGINFO_YESEXPR,1,[ Define if you have <langinfo.h> and nl_langinfo(YESEXPR). ])
- fi
- 
-+AC_CHECK_FUNCS(fmemopen open_memstream)
++    We start by changing mutt's internal keyword storage from a single string
++    which may contain whitespace to a list of discrete keywords. This has
++    advantages for keyword completion as well as for portabilty among varying
++    "standards" for keyword storage. This may represent a significant change
++    for existing mutt users who have set x-labels containing spaces, and should
++    be regarded with suspicion. The advantages are significant, though.
 +
- dnl Documentation tools
- have_openjade="no"
- AC_PATH_PROG([OSPCAT], [ospcat], [none])
-diff -urN mutt-1.6.1/copy.c mutt-1.6.1-neomutt/copy.c
---- mutt-1.6.1/copy.c	2016-06-12 18:43:00.398447528 +0100
-+++ mutt-1.6.1-neomutt/copy.c	2016-06-12 18:43:00.683451972 +0100
-@@ -30,6 +30,10 @@
- #include "mutt_idna.h"
- #include "mutt_curses.h"
- 
-+#ifdef USE_NOTMUCH
-+#include "mutt_notmuch.h"
-+#endif
++    Next we allow mutt to parse keywords into this internal list from any of
++    the following headers: X-Label (freeform), X-Keywords (space-delimited),
++    X-Mozilla-Keys (space-delimited), and Keywords (RFC 2822,
++    comma-space-delimited). Mutt remembers which headers it sourced keywords
++    from, and can rewrite those headers when saving messages for compatibility
++    with the mailer of origin.
 +
- #include <string.h>
- #include <stdlib.h>
- #include <ctype.h>
-@@ -111,6 +115,15 @@
- 	ignore = 0;
-       }
- 
-+      if (flags & CH_UPDATE_LABEL)
-+      {
-+	if ((mutt_strncasecmp ("X-Label:", buf, 8) == 0) ||
-+	    (mutt_strncasecmp ("X-Keywords:", buf, 11) == 0) ||
-+	    (mutt_strncasecmp ("X-Mozilla-Keys:", buf, 15) == 0) ||
-+	    (mutt_strncasecmp ("Keywords:", buf, 9) == 0))
-+	  continue;
-+      }
++    (X-Label was specified as freeform text by mutt, its only known
++    implementation. X-Labels have been used both as a "tagging" device,
++    probably with space delimiting, and as a "memo" field, where
++    space-delimited parsing would ruin the semantics of the memo. By default
++    mutt will not split X-Labels at all. Set $xlabel_delimiter if your needs
++    vary.)
 +
-       if (!ignore && fputs (buf, out) == EOF)
- 	return (-1);
-     }
-@@ -288,7 +301,8 @@
-       if (flags & (CH_DECODE|CH_PREFIX))
-       {
- 	if (mutt_write_one_header (out, 0, headers[x], 
--				   flags & CH_PREFIX ? prefix : 0, mutt_term_width (Wrap), flags) == -1)
-+				   flags & CH_PREFIX ? prefix : 0,
-+                                   mutt_term_width (Wrap), flags) == -1)
- 	{
- 	  error = TRUE;
- 	  break;
-@@ -334,6 +348,7 @@
- 	CH_NOQFROM      ignore ">From " line
- 	CH_UPDATE_IRT	update the In-Reply-To: header
- 	CH_UPDATE_REFS	update the References: header
-+	CH_VIRTUAL      write virtual header lines too
- 
-    prefix
-    	string to use if CH_PREFIX is set
-@@ -347,7 +362,7 @@
-   if (h->env)
-     flags |= (h->env->irt_changed ? CH_UPDATE_IRT : 0)
-       | (h->env->refs_changed ? CH_UPDATE_REFS : 0);
--  
++    Finally we add two booleans: $keywords_legacy=true and
++    $keywords_standard=FALSE. When $keywords_legacy is true, mutt will always
++    save keyword to whatever original header it came from. When
++    $keywords_standard=true, mutt will save to the Keywords: header. If both
++    are true mutt saves to both; if neither is true, mutt saves only to legacy
++    headers to avoid complete loss of keywords.
 +
-   if (mutt_copy_hdr (in, out, h->offset, h->content->offset, flags, prefix) == -1)
-     return -1;
- 
-@@ -413,6 +428,70 @@
-       fprintf (out, "Lines: %d\n", h->lines);
-   }
- 
-+#ifdef USE_NOTMUCH
-+  if ((flags & CH_VIRTUAL) && nm_header_get_tags(h))
-+  {
-+    fputs ("Tags: ", out);
-+    fputs (nm_header_get_tags(h), out);
-+    fputc ('\n', out);
-+  }
-+#endif
++    Overall this represents convergence path for all competing
++    labelling/tagging/keywording systems toward one that is specified by RFC.
 +
-+  if (flags & CH_UPDATE_LABEL && h->label_changed)
-+  {
-+    h->label_changed = 0;
-+    if (h->env->labels != NULL)
-+    {
-+      char buf[HUGE_STRING];
-+      char *tmp = NULL;
-+      int fail = 0;
++    You can change or delete the X-Label: field within Mutt using the
++    edit-label command, bound to the y key by default. This works for tagged
++    messages, too.
 +
-+      if (fail == 0 &&
-+          ((h->env->kwtypes & M_X_LABEL) || (h->env->kwtypes == 0)) &&
-+          (option(OPTKEYWORDSLEGACY) || option(OPTKEYWORDSSTANDARD) == 0))
-+      {
-+        mutt_labels(buf, sizeof(buf), h->env, XlabelDelim);
-+        tmp = strdup(buf);
-+        rfc2047_encode_string(&tmp);
-+        fail = fprintf(out, "X-Label: %s\n", tmp) != 10 + strlen(tmp);
-+        FREE(&tmp);
-+      }
++Variables
++---------
 +
-+      if (fail == 0 && (h->env->kwtypes & M_X_KEYWORDS) &&
-+          (option(OPTKEYWORDSLEGACY) || option(OPTKEYWORDSSTANDARD) == 0))
-+      {
-+        mutt_labels(buf, sizeof(buf), h->env, " ");
-+        tmp = strdup(buf);
-+        rfc2047_encode_string(&tmp);
-+        fail = fprintf(out, "X-Keywords: %s\n", tmp) != 13 + strlen(tmp);
-+        FREE(&tmp);
-+      }
++    Keyword Variables
 +
-+      if (fail == 0 && (h->env->kwtypes & M_X_MOZILLA_KEYS) &&
-+          (option(OPTKEYWORDSLEGACY) || option(OPTKEYWORDSSTANDARD) == 0))
-+      {
-+        mutt_labels(buf, sizeof(buf), h->env, " ");
-+        tmp = strdup(buf);
-+        rfc2047_encode_string(&tmp);
-+        fail = fprintf(out, "X-Mozilla-Keys: %s\n", tmp) != 17 + strlen(tmp);
-+        FREE(&tmp);
-+      }
++    | Name                | Type    | Default |
++    |---------------------|---------|---------|
++    | 'keywords_legacy'   | boolean | 'yes'   |
++    | 'keywords_standard' | boolean | 'no'    |
++    | 'xlabel_delimiter'  | string  | (empty) |
 +
-+      if (fail == 0 && ((h->env->kwtypes & M_KEYWORDS) ||
-+                        option(OPTKEYWORDSSTANDARD)))
-+      {
-+        mutt_labels(buf, sizeof(buf), h->env, NULL);
-+        tmp = strdup(buf);
-+        rfc2047_encode_string(&tmp);
-+        fail = fprintf(out, "Keywords: %s\n", tmp) != 11 + strlen(tmp);
-+        FREE(&tmp);
-+      }
++Functions
++---------
 +
-+      if (fail)
-+        return -1;
-+    }
-+  }
++    Keyword Functions
 +
-   if ((flags & CH_NONEWLINE) == 0)
-   {
-     if (flags & CH_PREFIX)
-@@ -493,6 +572,9 @@
-       _mutt_make_string (prefix, sizeof (prefix), NONULL (Prefix), Context, hdr, 0);
-   }
- 
-+  if (hdr->label_changed)
-+    chflags |= CH_UPDATE_LABEL;
++    | Menus       | Default Key | Function       | Description                              |
++    |-------------|-------------|----------------|------------------------------------------|
++    | index,pager | y           | '<edit-label>' | add, change, or delete a message's label |
 +
-   if ((flags & M_CM_NOHEADER) == 0)
-   {
-     if (flags & M_CM_PREFIX)
-@@ -682,7 +764,7 @@
- {
-   MESSAGE *msg;
-   int r;
--  
++Sort
++----
 +
-   if ((msg = mx_open_message (src, hdr->msgno)) == NULL)
-     return -1;
-   if ((r = _mutt_copy_message (fpout, msg->fp, hdr, hdr->content, flags, chflags)) == 0 
-@@ -717,7 +799,7 @@
-   fseeko (fpin, hdr->offset, 0);
-   if (fgets (buf, sizeof (buf), fpin) == NULL)
-     return -1;
--  
++    Keywords Sort
 +
-   if ((msg = mx_open_new_message (dest, hdr, is_from (buf, NULL, 0, NULL) ? 0 : M_ADD_FROM)) == NULL)
-     return -1;
-   if (dest->magic == M_MBOX || dest->magic == M_MMDF)
-@@ -727,6 +809,11 @@
-   if (mx_commit_message (msg, dest) != 0)
-     r = -1;
- 
-+#ifdef USE_NOTMUCH
-+  if (hdr && msg->commited_path && dest->magic == M_MAILDIR && src->magic == M_NOTMUCH)
-+	  nm_update_filename(src, NULL, msg->commited_path, hdr);
-+#endif
++    | Sort    | Description   |
++    |---------|---------------|
++    | 'label' | Sort by label |
 +
-   mx_close_message (&msg);
-   return r;
- }
-diff -urN mutt-1.6.1/copy.h mutt-1.6.1-neomutt/copy.h
---- mutt-1.6.1/copy.h	2016-06-12 18:43:00.398447528 +0100
-+++ mutt-1.6.1-neomutt/copy.h	2016-06-12 18:43:00.683451972 +0100
-@@ -53,6 +53,8 @@
- #define CH_UPDATE_IRT     (1<<16) /* update In-Reply-To: */
- #define CH_UPDATE_REFS    (1<<17) /* update References: */
- #define CH_DISPLAY        (1<<18) /* display result to user */
-+#define CH_VIRTUAL	  (1<<19) /* write virtual header lines too */
-+#define CH_UPDATE_LABEL   (1<<20) /* update X-Label: from hdr->env->x_label? */
- 
- 
- int mutt_copy_hdr (FILE *, FILE *, LOFF_T, LOFF_T, int, const char *);
-diff -urN mutt-1.6.1/curs_lib.c mutt-1.6.1-neomutt/curs_lib.c
---- mutt-1.6.1/curs_lib.c	2016-06-12 18:43:00.399447544 +0100
-+++ mutt-1.6.1-neomutt/curs_lib.c	2016-06-12 18:43:00.686452019 +0100
-@@ -44,6 +44,10 @@
- #include <langinfo.h>
- #endif
- 
-+#ifdef USE_NOTMUCH
-+#include "mutt_notmuch.h"
-+#endif
++See Also
++--------
 +
- /* not possible to unget more than one char under some curses libs, and it
-  * is impossible to unget function keys in SLang, so roll our own input
-  * buffering routines.
-@@ -411,6 +415,53 @@
-   mutt_progress_update (progress, 0, 0);
- }
- 
-+/**
-+ * message_bar - XXX
-+ */
-+static void
-+message_bar (int percent, const char *fmt, ...)
-+{
-+	va_list ap;
-+	char buf[STRING], buf2[STRING];
-+	int w = percent * COLS / 100;
-+	size_t l;
++    * NeoMutt project
++    * $index_format
++    * index-color patch
++    * folder-hook
 +
-+	va_start (ap, fmt);
-+	vsnprintf (buf, sizeof (buf), fmt, ap);
-+	l = mutt_strwidth (buf);
-+	va_end (ap);
++Known Bugs
++----------
 +
-+	mutt_format_string (buf2, sizeof (buf2), 0, COLS-2, FMT_LEFT, 0, buf, sizeof (buf), 0);
++    None
 +
-+	move (LINES - 1, 0);
++Credits
++-------
 +
-+	if (l < w) {
-+		SETCOLOR(MT_COLOR_PROGRESS);
-+		addstr (buf2);
-+		w -= l;
-+		while (w--) {
-+			addch (' ');
-+		}
-+		SETCOLOR(MT_COLOR_NORMAL);
-+		clrtoeol();
-+		mutt_refresh();
-+	} else {
-+		size_t bw;
-+		char ch;
-+		int off = mutt_wstr_trunc (buf2, sizeof (buf2), w, &bw);
++    * David Champion <dgc at uchicago.edu>
++    * Richard Russon <rich at flatcap.org>
 +
-+		ch = buf2[off];
-+		buf2[off] = 0;
-+		SETCOLOR(MT_COLOR_PROGRESS);
-+		addstr (buf2);
-+		buf2[off] = ch;
-+		SETCOLOR(MT_COLOR_NORMAL);
-+		addstr (&buf2[off]);
-+		clrtoeol();
-+		mutt_refresh();
-+	}
-+}
+diff --git a/README.limit-current-thread b/README.limit-current-thread
+new file mode 100644
+index 0000000..6085ba9
+--- /dev/null
++++ b/README.limit-current-thread
+@@ -0,0 +1,45 @@
++Limit-Current-Thread Patch
++==========================
 +
- void mutt_progress_update (progress_t* progress, long pos, int percent)
- {
-   char posstr[SHORT_STRING];
-@@ -461,16 +512,16 @@
- 
-     if (progress->size > 0)
-     {
--      mutt_message ("%s %s/%s (%d%%)", progress->msg, posstr, progress->sizestr,
--		    percent > 0 ? percent :
--		   	(int) (100.0 * (double) progress->pos / progress->size));
-+      message_bar ((percent > 0) ? percent : (int) (100.0 * (double) progress->pos / progress->size),
-+        "%s %s/%s (%d%%)", progress->msg, posstr, progress->sizestr,
-+        (percent > 0) ? percent : (int) (100.0 * (double) progress->pos / progress->size));
-     }
-     else
-     {
-       if (percent > 0)
--	mutt_message ("%s %s (%d%%)", progress->msg, posstr, percent);
-+        message_bar (percent, "%s %s (%d%%)", progress->msg, posstr, percent);
-       else
--	mutt_message ("%s %s", progress->msg, posstr);
-+        mutt_message ("%s %s", progress->msg, posstr);
-     }
-   }
- 
-@@ -577,7 +628,9 @@
-   return rc;
- }
- 
--int _mutt_enter_fname (const char *prompt, char *buf, size_t blen, int *redraw, int buffy, int multiple, char ***files, int *numfiles)
-+int _mutt_enter_fname (const char *prompt, char *buf, size_t blen,
-+		int *redraw, int buffy, int multiple,
-+		char ***files, int *numfiles, int flags)
- {
-   event_t ch;
- 
-@@ -600,8 +653,10 @@
-   {
-     mutt_refresh ();
-     buf[0] = 0;
--    _mutt_select_file (buf, blen, M_SEL_FOLDER | (multiple ? M_SEL_MULTI : 0), 
--		       files, numfiles);
-+    if (!flags)
-+      flags = M_SEL_FOLDER | (multiple ? M_SEL_MULTI : 0);
++    Focus on one Email Thread
 +
-+    _mutt_select_file (buf, blen, flags, files, numfiles);
-     *redraw = REDRAW_FULL;
-   }
-   else
-@@ -615,6 +670,10 @@
-       buf[0] = 0;
-     MAYBE_REDRAW (*redraw);
-     FREE (&pc);
-+#ifdef USE_NOTMUCH
-+    if ((flags & M_SEL_VFOLDER) && buf[0] && strncmp(buf, "notmuch://", 10) != 0)
-+      nm_description_to_path(buf, buf, blen);
-+#endif
-   }
- 
-   return 0;
-@@ -779,6 +838,7 @@
-   size_t k, k2;
-   char scratch[MB_LEN_MAX];
-   mbstate_t mbstate1, mbstate2;
-+  int escaped = 0;
- 
-   memset(&mbstate1, 0, sizeof (mbstate1));
-   memset(&mbstate2, 0, sizeof (mbstate2));
-@@ -794,8 +854,15 @@
-       k = (k == (size_t)(-1)) ? 1 : n;
-       wc = replacement_char ();
-     }
--    if (arboreal && wc < M_TREE_MAX)
-+    if (escaped) {
-+      escaped = 0;
-+      w = 0;
-+    } else if (arboreal && wc == M_SPECIAL_INDEX) {
-+      escaped = 1;
-+      w = 0;
-+    } else if (arboreal && wc < M_TREE_MAX) {
-       w = 1; /* hack */
-+    }
-     else
-     {
- #ifdef HAVE_ISWBLANK
-@@ -1032,6 +1099,12 @@
-   memset (&mbstate, 0, sizeof (mbstate));
-   for (w=0; n && (k = mbrtowc (&wc, s, n, &mbstate)); s += k, n -= k)
-   {
-+    if (*s == M_SPECIAL_INDEX) {
-+      s += 2; /* skip the index coloring sequence */
-+      k = 0;
-+      continue;
-+    }
++Patch
++-----
 +
-     if (k == (size_t)(-1) || k == (size_t)(-2))
-     {
-       k = (k == (size_t)(-1)) ? 1 : n;
-diff -urN mutt-1.6.1/curs_main.c mutt-1.6.1-neomutt/curs_main.c
---- mutt-1.6.1/curs_main.c	2016-06-12 18:43:00.399447544 +0100
-+++ mutt-1.6.1-neomutt/curs_main.c	2016-06-12 18:43:00.686452019 +0100
-@@ -22,12 +22,18 @@
- 
- #include "mutt.h"
- #include "mutt_curses.h"
-+#include "mx.h"
- #include "mutt_menu.h"
- #include "mailbox.h"
- #include "mapping.h"
- #include "sort.h"
-+#include "buffy.h"
- #include "mx.h"
- 
-+#ifdef USE_SIDEBAR
-+#include "sidebar.h"
-+#endif
++    To check if Mutt supports "limit-current-thread", look for
++    "patch-limit-current-thread" in the mutt version.
 +
- #ifdef USE_POP
- #include "pop.h"
- #endif
-@@ -36,8 +42,16 @@
- #include "imap_private.h"
- #endif
- 
-+#ifdef USE_NOTMUCH
-+#include "mutt_notmuch.h"
-+#endif
++    Dependencies
++    * mutt-1.6.2
 +
- #include "mutt_crypt.h"
- 
-+#ifdef USE_NNTP
-+#include "nntp.h"
-+#endif
++Introduction
++------------
 +
- 
- #include <ctype.h>
- #include <stdlib.h>
-@@ -118,7 +132,9 @@
- {
-   char *term = getenv("TERM");
-   char *tcaps;
-+#ifdef HAVE_USE_EXTENDED_NAMES
-   int tcapi;
-+#endif
-   char **termp;
-   char *known[] = {
-     "color-xterm",
-@@ -477,6 +493,192 @@
-   menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
- }
- 
-+/**
-+ * mutt_draw_statusline - XXX
-+ */
-+void
-+mutt_draw_statusline (int cols, char *inbuf)
-+{
-+	int i          = 0;
-+	int cnt        = 0;
-+	int last_color = 0;
-+	int color      = 0;
-+	int offset     = 0;
-+	int found      = 0;
-+	int null_rx    = 0;
-+	char buf[2048];
-+
-+	struct line_t {
-+		short chunks;
-+		struct syntax_t {
-+			int color;
-+			int first;
-+			int last;
-+		} *syntax;
-+	} lineInfo = { 0, NULL };
-+
-+	mutt_format_string (buf, sizeof (buf), cols, cols, 0, ' ', inbuf, mutt_strlen (inbuf), 0);
-+
-+	lineInfo.syntax = safe_malloc (sizeof (struct syntax_t));
-+	lineInfo.syntax[0].first = -1;
-+	lineInfo.syntax[0].last  = -1;
-+	lineInfo.syntax[0].color = ColorDefs[MT_COLOR_STATUS];
-+	lineInfo.chunks = 1;
++    This patch adds a new way of using the Limit Command. The
++    '<limit-current-thread>' function restricts the view to just the current
++    thread. Setting the limit (the 'l' key) to "all" will restore the full
++    email list.
 +
-+	do {
-+		found = 0;
-+		null_rx = 0;
-+		COLOR_LINE *color_line = ColorStatusList;
++Functions
++---------
 +
-+		if (!buf[offset])
-+			break;
++    | Menus | Default Key | Function                 | Description                  |
++    |-------|-------------|--------------------------|------------------------------|
++    | index | '<Esc> L'   | '<limit-current-thread>' | Limit view to current thread |
 +
-+		while (color_line) {
-+			regmatch_t pmatch[color_line->match + 1];
++See Also
++--------
 +
-+			if (regexec (&color_line->rx, buf + offset, color_line->match + 1, pmatch, (offset ? REG_NOTBOL : 0)) == 0) {
-+				if (pmatch[color_line->match].rm_eo != pmatch[color_line->match].rm_so) {
-+					if (!found) {
-+						if (++(lineInfo.chunks) > 1) {
-+							safe_realloc (&(lineInfo.syntax), (lineInfo.chunks) * sizeof (struct syntax_t));
-+						}
-+					}
-+					i = lineInfo.chunks - 1;
-+					pmatch[color_line->match].rm_so += offset;
-+					pmatch[color_line->match].rm_eo += offset;
-+					if (!found ||
-+						(pmatch[color_line->match].rm_so < (lineInfo.syntax)[i].first) ||
-+						((pmatch[color_line->match].rm_so == (lineInfo.syntax)[i].first) &&
-+						(pmatch[color_line->match].rm_eo > (lineInfo.syntax)[i].last))) {
-+						(lineInfo.syntax)[i].color = color_line->pair;
-+						(lineInfo.syntax)[i].first = pmatch[color_line->match].rm_so;
-+						(lineInfo.syntax)[i].last = pmatch[color_line->match].rm_eo;
-+					}
-+					found = 1;
-+					null_rx = 0;
-+				} else {
-+					null_rx = 1; /* empty regexp; don't add it, but keep looking */
-+				}
-+			}
-+			color_line = color_line->next;
-+		}
++    * NeoMutt project
 +
-+		if (null_rx)
-+			offset++; /* avoid degenerate cases */
-+		else
-+			offset = (lineInfo.syntax)[i].last;
-+	} while (found || null_rx);
-+
-+	for (cnt = 0; cnt < mutt_strlen (buf); cnt++) {
-+		color = lineInfo.syntax[0].color;
-+		for (i = 0; i < lineInfo.chunks; i++) {
-+			/* we assume the chunks are sorted */
-+			if (cnt > (lineInfo.syntax)[i].last)
-+				continue;
-+			if (cnt < (lineInfo.syntax)[i].first)
-+				break;
-+			if (cnt != (lineInfo.syntax)[i].last) {
-+				color = (lineInfo.syntax)[i].color;
-+				break;
-+			}
-+			/* don't break here, as cnt might be in the next chunk as well */
-+		}
-+		if (color != last_color) {
-+			attrset (color);
-+			last_color = color;
-+		}
-+		/* XXX more than one char at a time? */
-+		addch ((unsigned char)buf[cnt]);
-+#if 0
-+		waddnstr (stdscr, tgbuf, 10);
-+		SETCOLOR (MT_COLOR_NORMAL);
-+		waddnstr (stdscr, tgbuf + 10, -1);
-+#endif
-+	}
++Known Bugs
++----------
 +
-+	safe_free (&lineInfo.syntax);
-+}
++    None
 +
-+static int main_change_folder(MUTTMENU *menu, int op, char *buf, size_t bufsz,
-+			  int *oldcount, int *index_hint, int flags)
-+{
-+#ifdef USE_NNTP
-+  if (option (OPTNEWS))
-+  {
-+    unset_option (OPTNEWS);
-+    nntp_expand_path (buf, bufsz, &CurrentNewsSrv->conn->account);
-+  }
-+  else
-+#endif
-+  mutt_expand_path (buf, bufsz);
-+#ifdef USE_SIDEBAR
-+  mutt_sb_set_open_buffy (buf);
-+#endif
-+  if (mx_get_magic (buf) <= 0)
-+  {
-+    mutt_error (_("%s is not a mailbox."), buf);
-+    return -1;
-+  }
-+  mutt_str_replace (&CurrentFolder, buf);
++Credits
++-------
 +
-+  /* keepalive failure in mutt_enter_fname may kill connection. #3028 */
-+  if (Context && !Context->path)
-+    FREE (&Context);
++    * David Sterba <dsterba at suse.cz>
++    * Richard Russon <rich at flatcap.org>
 +
-+  if (Context)
-+  {
-+    int check;
+diff --git a/README.lmdb b/README.lmdb
+new file mode 100644
+index 0000000..1e12926
+--- /dev/null
++++ b/README.lmdb
+@@ -0,0 +1,38 @@
++LMDB Patch
++==========
 +
-+#ifdef USE_COMPRESSED
-+	  if (Context->compress_info && Context->realpath)
-+	    mutt_str_replace (&LastFolder, Context->realpath);
-+	  else
-+#endif
-+    mutt_str_replace (&LastFolder, Context->path);
-+    *oldcount = Context ? Context->msgcount : 0;
++    LMDB backend for the header cache
 +
-+    if ((check = mx_close_mailbox (Context, index_hint)) != 0)
-+    {
-+      if (check == M_NEW_MAIL || check == M_REOPENED)
-+        update_index (menu, Context, check, *oldcount, *index_hint);
++Patch
++-----
 +
-+      set_option (OPTSEARCHINVALID);
-+      menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
-+      return 0;
-+    }
-+    FREE (&Context);
-+  }
++    To check if Mutt supports "lmdb", look for "patch-lmdb" in the mutt
++    version.
 +
-+  if (Labels)
-+    hash_destroy(&Labels, NULL);
++    Dependencies
++    * mutt-1.6.2
 +
-+  mutt_sleep (0);
++Introduction
++------------
 +
-+  /* Set CurrentMenu to MENU_MAIN before executing any folder
-+   * hooks so that all the index menu functions are available to
-+   * the exec command.
-+   */
++    This patch adds support for using LMDB as a storage backend for Mutt's
++    header cache (hcache). It is enabled at configure time with the
++    "--with-lmdb=<path>" switch.
 +
-+  CurrentMenu = MENU_MAIN;
-+  mutt_folder_hook (buf);
++See Also
++--------
 +
-+  if ((Context = mx_open_mailbox (buf, flags, NULL)) != NULL)
-+  {
-+    Labels = hash_create(131, 0);
-+    mutt_scan_labels(Context);
-+    menu->current = ci_first_message ();
-+  }
-+  else
-+    menu->current = 0;
++    * NeoMutt project
++    * Local Caching
 +
-+  mutt_clear_error ();
-+  mutt_buffy_check(1); /* force the buffy check after we have changed the folder */
-+  menu->redraw = REDRAW_FULL;
-+  set_option (OPTSEARCHINVALID);
++Known Bugs
++----------
 +
-+  return 0;
-+}
++    None
 +
- static const struct mapping_t IndexHelp[] = {
-   { N_("Quit"),  OP_QUIT },
-   { N_("Del"),   OP_DELETE },
-@@ -489,12 +691,27 @@
-   { NULL,	 0 }
- };
- 
-+#ifdef USE_NNTP
-+struct mapping_t IndexNewsHelp[] = {
-+  { N_("Quit"),     OP_QUIT },
-+  { N_("Del"),      OP_DELETE },
-+  { N_("Undel"),    OP_UNDELETE },
-+  { N_("Save"),     OP_SAVE },
-+  { N_("Post"),     OP_POST },
-+  { N_("Followup"), OP_FOLLOWUP },
-+  { N_("Catchup"),  OP_CATCHUP },
-+  { N_("Help"),     OP_HELP },
-+  { NULL,           0 }
-+};
-+#endif
++Credits
++-------
 +
- /* This function handles the message index window as well as commands returned
-  * from the pager (MENU_PAGER).
-  */
- int mutt_index_menu (void)
- {
-   char buf[LONG_STRING], helpstr[LONG_STRING];
-+  int flags;
-   int op = OP_NULL;
-   int done = 0;                /* controls when to exit the "event" loop */
-   int i = 0, j;
-@@ -515,7 +732,11 @@
-   menu->make_entry = index_make_entry;
-   menu->color = index_color;
-   menu->current = ci_first_message ();
--  menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_MAIN, IndexHelp);
-+  menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_MAIN,
-+#ifdef USE_NNTP
-+	(Context && (Context->magic == M_NNTP)) ? IndexNewsHelp :
-+#endif
-+	IndexHelp);
- 
-   if (!attach_msg)
-     mutt_buffy_check(1); /* force the buffy check after we enter the folder */
-@@ -595,21 +816,39 @@
-        menu->redraw |= REDRAW_STATUS;
-      if (do_buffy_notify)
-      {
--       if (mutt_buffy_notify () && option (OPTBEEPNEW))
-- 	beep ();
-+       if (mutt_buffy_notify())
-+       {
-+         menu->redraw |= REDRAW_STATUS;
-+         if (option (OPTBEEPNEW))
-+           beep();
-+       }
-      }
-      else
-        do_buffy_notify = 1;
-     }
- 
-+#ifdef USE_SIDEBAR
-+    if (option (OPTSIDEBAR))
-+        menu->redraw |= REDRAW_SIDEBAR;
-+#endif
++    * Pietro Cerutti <gahr at gahr.ch>
++    * Jan-Piet Mens <jp at mens.de>
 +
-     if (op != -1)
-       mutt_curs_set (0);
- 
-     if (menu->redraw & REDRAW_FULL)
-     {
-       menu_redraw_full (menu);
-+#ifdef USE_SIDEBAR
-+      mutt_sb_draw();
-+#endif
-       mutt_show_error ();
-     }
-+#ifdef USE_SIDEBAR
-+    else if (menu->redraw & REDRAW_SIDEBAR) {
-+      mutt_sb_draw();
-+      menu->redraw &= ~REDRAW_SIDEBAR;
-+    }
-+#endif
- 
-     if (menu->menu == MENU_MAIN)
-     {
-@@ -630,10 +869,21 @@
- 
-       if (menu->redraw & REDRAW_STATUS)
-       {
-+#ifdef USE_SIDEBAR
-+        /* Temporarily lie about the sidebar width */
-+	short sw = SidebarWidth;
-+	SidebarWidth = 0;
-+#endif
- 	menu_status_line (buf, sizeof (buf), menu, NONULL (Status));
-+#ifdef USE_SIDEBAR
-+        SidebarWidth = sw; /* Restore the sidebar width */
-+#endif
- 	move (option (OPTSTATUSONTOP) ? 0 : LINES-2, 0);
- 	SETCOLOR (MT_COLOR_STATUS);
--	mutt_paddstr (COLS, buf);
-+#ifdef USE_SIDEBAR
-+	mutt_sb_set_buffystats (Context);
-+#endif
-+	mutt_draw_statusline (COLS, buf);
- 	NORMAL_COLOR;
- 	menu->redraw &= ~REDRAW_STATUS;
- 	if (option(OPTTSENABLED) && TSSupported)
-@@ -652,7 +902,7 @@
- 	menu->oldcurrent = -1;
- 
-       if (option (OPTARROWCURSOR))
--	move (menu->current - menu->top + menu->offset, 2);
-+	move (menu->current - menu->top + menu->offset, SidebarWidth + 2);
-       else if (option (OPTBRAILLEFRIENDLY))
- 	move (menu->current - menu->top + menu->offset, 0);
-       else
-@@ -758,6 +1008,14 @@
-       mutt_curs_set (1);	/* fallback from the pager */
-     }
- 
-+#ifdef USE_NOTMUCH
-+    if (Context)
-+      nm_debug_check(Context);
-+#endif
+diff --git a/README.md b/README.md
+new file mode 120000
+index 0000000..716afb5
+--- /dev/null
++++ b/README.md
+@@ -0,0 +1 @@
++README.neomutt
+\ No newline at end of file
+diff --git a/README.neomutt b/README.neomutt
+new file mode 100644
+index 0000000..a8d6b3b
+--- /dev/null
++++ b/README.neomutt
+@@ -0,0 +1,83 @@
++# This is the NeoMutt Project
 +
-+#ifdef USE_NNTP
-+    unset_option (OPTNEWS);	/* for any case */
-+#endif
-     switch (op)
-     {
- 
-@@ -808,6 +1066,161 @@
- 	menu_current_bottom (menu);
- 	break;
- 
-+#ifdef USE_NNTP
-+      case OP_GET_PARENT:
-+	CHECK_MSGCOUNT;
-+	CHECK_VISIBLE;
++## What is NeoMutt?
 +
-+      case OP_GET_MESSAGE:
-+	CHECK_IN_MAILBOX;
-+	CHECK_READONLY;
-+	CHECK_ATTACH;
-+	if (Context->magic == M_NNTP)
-+	{
-+	  HEADER *hdr;
++* NeoMutt is a project of projects.
++* A place to gather all the patches against Mutt.
++* A place for all the developers to gather.
 +
-+	  if (op == OP_GET_MESSAGE)
-+	  {
-+	    buf[0] = 0;
-+	    if (mutt_get_field (_("Enter Message-Id: "),
-+		buf, sizeof (buf), 0) != 0 || !buf[0])
-+	      break;
-+	  }
-+	  else
-+	  {
-+	    LIST *ref = CURHDR->env->references;
-+	    if (!ref)
-+	    {
-+	      mutt_error _("Article has no parent reference.");
-+	      break;
-+	    }
-+	    strfcpy (buf, ref->data, sizeof (buf));
-+	  }
-+	  if (!Context->id_hash)
-+	    Context->id_hash = mutt_make_id_hash (Context);
-+	  hdr = hash_find (Context->id_hash, buf);
-+	  if (hdr)
-+	  {
-+	    if (hdr->virtual != -1)
-+	    {
-+	      menu->current = hdr->virtual;
-+	      menu->redraw = REDRAW_MOTION_RESYNCH;
-+	    }
-+	    else if (hdr->collapsed)
-+	    {
-+	      mutt_uncollapse_thread (Context, hdr);
-+	      mutt_set_virtual (Context);
-+	      menu->current = hdr->virtual;
-+	      menu->redraw = REDRAW_MOTION_RESYNCH;
-+	    }
-+	    else
-+	      mutt_error _("Message is not visible in limited view.");
-+	  }
-+	  else
-+	  {
-+	    int rc;
++Hopefully this will build the community and reduce duplicated effort.
 +
-+	    mutt_message (_("Fetching %s from server..."), buf);
-+	    rc = nntp_check_msgid (Context, buf);
-+	    if (rc == 0)
-+	    {
-+	      hdr = Context->hdrs[Context->msgcount - 1];
-+	      mutt_sort_headers (Context, 0);
-+	      menu->current = hdr->virtual;
-+	      menu->redraw = REDRAW_FULL;
-+	    }
-+	    else if (rc > 0)
-+	      mutt_error (_("Article %s not found on the server."), buf);
-+	  }
-+	}
-+	break;
++NeoMutt was created when Richard Russon (FlatCap) took all the old Mutt patches,
++sorted through them, fixed them up and documented them.
 +
-+      case OP_GET_CHILDREN:
-+      case OP_RECONSTRUCT_THREAD:
-+	CHECK_MSGCOUNT;
-+	CHECK_VISIBLE;
-+	CHECK_READONLY;
-+	CHECK_ATTACH;
-+	if (Context->magic == M_NNTP)
-+	{
-+	  int oldmsgcount = Context->msgcount;
-+	  int oldindex = CURHDR->index;
-+	  int rc = 0;
++## What Features does NeoMutt have?
 +
-+	  if (!CURHDR->env->message_id)
-+	  {
-+	    mutt_error _("No Message-Id. Unable to perform operation.");
-+	    break;
-+	  }
++| Name                 | Description
++|----------------------|-------------------------------------------------------
++| Compressed Folders   | Read from/write to compressed mailboxes
++| Conditional Dates    | Conditional Date Formatting
++| Fmemopen             | Use fmemopen(3) for speedier temporary files
++| Ifdef                | Conditional config options
++| Index Color          | Theming of the Index List
++| Initials Expando     | Expando for Author's Initials
++| Keywords             | Labels/Tagging for emails
++| Limit-Current-Thread | Limit Index View to Current Thread
++| LMDB                 | LMDB backend for the header cache
++| Nested If            | Allow deeply nested conditionals in format strings
++| New Mail Command     | Run a command when new mail arrives
++| NNTP                 | Talk to a Usenet news server
++| Notmuch              | Powerful email search engine
++| Progress Bar         | Colourful Progress Bar
++| Quasi-Delete         | Hide emails from view, but don't delete them
++| Sidebar              | Panel containing list of Mailboxes
++| Skip-Quoted          | Skip Quoted Text
++| SMIME Encrypt to Self| Save an self-encrypted copy of emails
++| Status Color         | Theming of the Status Bar
++| TLS-SNI              | Negotiate with a Server for a Certificate
++| Trash Folder         | Move 'deleted' emails to a trash folder
 +
-+	  mutt_message _("Fetching message headers...");
-+	  if (!Context->id_hash)
-+	    Context->id_hash = mutt_make_id_hash (Context);
-+	  strfcpy (buf, CURHDR->env->message_id, sizeof (buf));
++## Where is NeoMutt?
 +
-+	  /* trying to find msgid of the root message */
-+	  if (op == OP_RECONSTRUCT_THREAD)
-+	  {
-+	    LIST *ref = CURHDR->env->references;
-+	    while (ref)
-+	    {
-+	      if (hash_find (Context->id_hash, ref->data) == NULL)
-+	      {
-+		rc = nntp_check_msgid (Context, ref->data);
-+		if (rc < 0)
-+		  break;
-+	      }
++- Source Code:     https://github.com/neomutt/neomutt
++- Releases:        https://github.com/neomutt/neomutt/releases/latest
++- Questions/Bugs:  https://github.com/neomutt/neomutt/issues
++- Website:         http://www.neomutt.org/
++- IRC              irc://irc.freenode.net/neomutt
++- Development:     http://www.neomutt.org/devel/
 +
-+	      /* the last msgid in References is the root message */
-+	      if (!ref->next)
-+		strfcpy (buf, ref->data, sizeof (buf));
-+	      ref = ref->next;
-+	    }
-+	  }
++## NeoMutt Developers
 +
-+	  /* fetching all child messages */
-+	  if (rc >= 0)
-+	    rc = nntp_check_children (Context, buf);
++Here's a list of everyone who's helped NeoMutt:
 +
-+	  /* at least one message has been loaded */
-+	  if (Context->msgcount > oldmsgcount)
-+	  {
-+	    HEADER *hdr;
-+	    int i, quiet = Context->quiet;
++Alex Pearce, Antonio Radici, Christoph Berg, Chris Salzberg, David Sterba,
++Evgeni Golov, Fabian Groffen, Fabio Alessandro Locati, Faidon Liambotis,
++Karel Zak, Kurt Jaeger, Matteo Vescovi, Richard Hartmann, Richard Russon,
++Udo Schweigert, Werner Fink.
 +
-+	    if (rc < 0)
-+	      Context->quiet = 1;
-+	    mutt_sort_headers (Context, (op == OP_RECONSTRUCT_THREAD));
-+	    Context->quiet = quiet;
++## Original Patch Authors
 +
-+	    /* if the root message was retrieved, move to it */
-+	    hdr = hash_find (Context->id_hash, buf);
-+	    if (hdr)
-+	      menu->current = hdr->virtual;
++Without the original patch authors, there would be nothing.
++So, a Big Thank You to:
 +
-+	    /* try to restore old position */
-+	    else
-+	    {
-+	      for (i = 0; i < Context->msgcount; i++)
-+	      {
-+		if (Context->hdrs[i]->index == oldindex)
-+		{
-+		  menu->current = Context->hdrs[i]->virtual;
-+		  /* as an added courtesy, recenter the menu
-+		   * with the current entry at the middle of the screen */
-+		  menu_check_recenter (menu);
-+		  menu_current_middle (menu);
-+		}
-+	      }
-+	    }
-+	    menu->redraw = REDRAW_FULL;
-+	  }
-+	  else if (rc >= 0)
-+	    mutt_error _("No deleted messages found in the thread.");
-+	}
-+	break;
-+#endif
++Aaron Schrab, Alain Penders, Benjamin Kuperman, Cedric Duval, Chris Mason,
++Christian Aichinger, Christoph Berg, Christoph Rissner, David Champion,
++David Riebenbauer, David Sterba, David Wilson, Don Zickus, Elimar Riesebieter,
++Eric Davis, Evgeni Golov, Fabian Groffen, Felix von Leitner, Jan Synacek,
++Jason DeTiberus, Jeremiah Foster, Jeremy Katz, Josh Poimboeuf, Julius Plenz,
++Justin Hibbits, Karel Zak, Kirill Shutemov, Luke Macken, Mantas Mikulenas,
++Matteo Vescovi, Patrick Brisbin, Paul Miller, Phil Pennock,
++Philippe Le Brouster, Richard Russon, Rocco Rutte, Roland Rosenfeld, Sami Farin,
++Stefan Assmann, Stefan Kuhn, Steve Kemp, Terry Chan, Thomas Glanzmann,
++Thomer Gil, Tim Stoakes, Tyler Earnest, Victor Manuel Jaquez Leal,
++Vincent Lefevre, Vladimir Marek, Vsevolod Volkov.
 +
-       case OP_JUMP:
- 
- 	CHECK_MSGCOUNT;
-@@ -904,12 +1317,35 @@
- 	}
-         break;
- 
-+      case OP_LIMIT_CURRENT_THREAD:
-       case OP_MAIN_LIMIT:
-+      case OP_TOGGLE_READ:
- 
- 	CHECK_IN_MAILBOX;
- 	menu->oldcurrent = (Context->vcount && menu->current >= 0 && menu->current < Context->vcount) ?
- 		CURHDR->index : -1;
--	if (mutt_pattern_func (M_LIMIT, _("Limit to messages matching: ")) == 0)
-+	if (op == OP_TOGGLE_READ)
-+	{
-+	  char buf[LONG_STRING];
++## Original Mutt Authors
 +
-+	  if (!Context->pattern || strncmp (Context->pattern, "!~R!~D~s", 8) != 0)
-+	  {
-+	    snprintf (buf, sizeof (buf), "!~R!~D~s%s",
-+		      Context->pattern ? Context->pattern : ".*");
-+	    set_option (OPTHIDEREAD);
-+	  }
-+	  else
-+	  {
-+	    strfcpy (buf, Context->pattern + 8, sizeof(buf));
-+	    if (!*buf || strncmp (buf, ".*", 2) == 0)
-+	      snprintf (buf, sizeof(buf), "~A");
-+	    unset_option (OPTHIDEREAD);
-+	  }
-+	  FREE (&Context->pattern);
-+	  Context->pattern = safe_strdup (buf);
-+	}
-+	if (((op == OP_LIMIT_CURRENT_THREAD) && mutt_limit_current_thread(CURHDR))
-+	    || ((op == OP_MAIN_LIMIT) && (mutt_pattern_func (M_LIMIT, _("Limit to messages matching: ")) == 0)))
- 	{
- 	  if (menu->oldcurrent >= 0)
- 	  {
-@@ -1091,6 +1527,9 @@
- 	  break;
- 
- 	CHECK_MSGCOUNT;
-+#ifdef USE_SIDEBAR
-+	CHECK_VISIBLE;
-+#endif
- 	CHECK_READONLY;
- 	{
- 	  int oldvcount = Context->vcount;
-@@ -1150,19 +1589,172 @@
- 	  menu->redraw = REDRAW_FULL;
- 	break;
- 
--      case OP_MAIN_CHANGE_FOLDER:
--      case OP_MAIN_NEXT_UNREAD_MAILBOX:
-+      case OP_MAIN_QUASI_DELETE:
-+	if (tag) {
-+	  for (j = 0; j < Context->vcount; j++) {
-+	    if (Context->hdrs[Context->v2r[j]]->tagged) {
-+	      Context->hdrs[Context->v2r[j]]->quasi_deleted = TRUE;
-+	      Context->changed = TRUE;
-+	    }
-+	  }
-+	} else {
-+	  CURHDR->quasi_deleted = TRUE;
-+	  Context->changed = 1;
-+	}
-+	break;
- 
--	if (attach_msg)
--	  op = OP_MAIN_CHANGE_FOLDER_READONLY;
-+#ifdef USE_NOTMUCH
-+      case OP_MAIN_ENTIRE_THREAD:
-+      {
-+	int oldcount  = Context->msgcount;
-+	if (Context->magic != M_NOTMUCH) {
-+	  mutt_message _("No virtual folder, aborting.");
-+	  break;
-+	}
-+	CHECK_MSGCOUNT;
-+        CHECK_VISIBLE;
-+	if (nm_read_entire_thread(Context, CURHDR) < 0) {
-+	   mutt_message _("Failed to read thread, aborting.");
-+	   break;
-+	}
-+	if (oldcount < Context->msgcount) {
-+		HEADER *oldcur = CURHDR;
++And of course, we should thank the original Mutt authors, including the original
++author Michael Elkins and all the people that have contributed to Mutt during
++its long history, see the Acknowledgements section of the user manual for a
++detailed list.
 +
-+		if ((Sort & SORT_MASK) == SORT_THREADS)
-+			mutt_sort_headers (Context, 0);
-+		menu->current = oldcur->virtual;
-+		menu->redraw = REDRAW_STATUS | REDRAW_INDEX;
++http://www.neomutt.org/manual/miscellany.html#acknowledgements
 +
-+		if (oldcur->collapsed || Context->collapsed) {
-+			menu->current = mutt_uncollapse_thread(Context, CURHDR);
-+			mutt_set_virtual(Context);
-+		}
-+	}
-+	if (menu->menu == MENU_PAGER)
-+	{
-+	  op = OP_DISPLAY_MESSAGE;
-+	  continue;
-+	}
-+	break;
-+      }
- 
--	/* fallback to the readonly case */
-+      case OP_MAIN_MODIFY_LABELS:
-+      case OP_MAIN_MODIFY_LABELS_THEN_HIDE:
-+      {
-+	if (Context->magic != M_NOTMUCH) {
-+	  mutt_message _("No virtual folder, aborting.");
-+	  break;
-+	}
-+	CHECK_MSGCOUNT;
-+        CHECK_VISIBLE;
-+	*buf = '\0';
-+	if (mutt_get_field ("Add/remove labels: ", buf, sizeof (buf), M_NM_TAG) || !*buf)
-+	{
-+          mutt_message _("No label specified, aborting.");
-+          break;
+diff --git a/README.nested-if b/README.nested-if
+new file mode 100644
+index 0000000..20730e5
+--- /dev/null
++++ b/README.nested-if
+@@ -0,0 +1,122 @@
++Nested If Patch
++===============
++
++    Allow complex nested conditions in format strings
++
++Patch
++-----
++
++    To check if Mutt supports "Nested If", look for "patch-nested-if" in the
++    mutt version.
++
++    Dependencies
++    * mutt-1.6.2
++
++Introduction
++------------
++
++    Mutt's format strings can contain embedded if-then-else conditions. They
++    are of the form:
++
++        %?VAR?TRUE&FALSE?
++
++    If the variable "VAR" has a value greater than zero, print the "TRUE"
++    string, otherwise print the "FALSE" string.
++
++    e.g. '%?S?Size: %S&Empty?'
++
++    Which can be read as:
++
++        if (%S > 0) {
++            print "Size: %S"
++        } else {
++            print "Empty"
 +        }
-+	if (tag)
-+	{
-+	  char msgbuf[STRING];
-+	  progress_t progress;
-+	  int px;
 +
-+	  if (!Context->quiet) {
-+	    snprintf(msgbuf, sizeof (msgbuf), _("Update labels..."));
-+	    mutt_progress_init(&progress, msgbuf, M_PROGRESS_MSG,
-+				   1, Context->tagged);
-+	  }
-+	  nm_longrun_init(Context, TRUE);
-+	  for (px = 0, j = 0; j < Context->vcount; j++) {
-+	    if (Context->hdrs[Context->v2r[j]]->tagged) {
-+	      if (!Context->quiet)
-+		mutt_progress_update(&progress, ++px, -1);
-+	      nm_modify_message_tags(Context, Context->hdrs[Context->v2r[j]], buf);
-+	      if (op == OP_MAIN_MODIFY_LABELS_THEN_HIDE)
-+	      {
-+		Context->hdrs[Context->v2r[j]]->quasi_deleted = TRUE;
-+	        Context->changed = TRUE;
-+	      }
-+	    }
-+	  }
-+	  nm_longrun_done(Context);
-+	  menu->redraw = REDRAW_STATUS | REDRAW_INDEX;
-+	}
-+	else
-+	{
-+	  if (nm_modify_message_tags(Context, CURHDR, buf)) {
-+	    mutt_message _("Failed to modify labels, aborting.");
-+	    break;
-+	  }
-+	  if (op == OP_MAIN_MODIFY_LABELS_THEN_HIDE)
-+	  {
-+	    CURHDR->quasi_deleted = TRUE;
-+	    Context->changed = TRUE;
-+	  }
-+	  if (menu->menu == MENU_PAGER)
-+	  {
-+	    op = OP_DISPLAY_MESSAGE;
-+	    continue;
-+	  }
-+	  if (option (OPTRESOLVE))
-+	  {
-+	    if ((menu->current = ci_next_undeleted (menu->current)) == -1)
-+	    {
-+	      menu->current = menu->oldcurrent;
-+	      menu->redraw = REDRAW_CURRENT;
-+	    }
-+	    else
-+	      menu->redraw = REDRAW_MOTION_RESYNCH;
-+	  }
-+	  else
-+	    menu->redraw = REDRAW_CURRENT;
-+	}
-+	menu->redraw |= REDRAW_STATUS;
-+	break;
-+      }
 +
-+      case OP_MAIN_VFOLDER_FROM_QUERY:
-+	buf[0] = '\0';
-+        if (mutt_get_field ("Query: ", buf, sizeof (buf), M_NM_QUERY) != 0 || !buf[0])
-+        {
-+          mutt_message _("No query, aborting.");
-+          break;
++    These conditions are useful, but in Mutt they cannot be nested within one
++    another. This patch uses the notation '%<VAR?TRUE&FALSE>' and allows them
++    to be nested.
++
++    The '%<...>' notation was used to format the current local time. but that's
++    not really very useful since mutt has no means of refreshing the screen
++    periodically.
++
++    A simple nested condition might be: (Some whitespace has been introduced
++    for clarity)
++
++        %<x? %<y? XY & X > & %<y? Y & NONE > >  Conditions
++             %<y? XY & X >                      x>0
++                  XY                            x>0,y>0
++                       X                        x>0,y=0
++
++        %<x? %<y? XY & X > & %<y? Y & NONE > >  Conditions
++                             %<y? Y & NONE >    x=0
++                                  Y             x=0,y>0
++                                      NONE      x=0,y=0
++
++    Equivalent to:
++
++        if (x > 0) {
++            if (y > 0) {
++                print 'XY'
++            } else {
++                print 'X'
++            }
++        } else {
++            if (y > 0) {
++                print 'Y'
++            } else {
++                print 'NONE'
++            }
 +        }
-+	if (!nm_uri_from_query(Context, buf, sizeof (buf)))
-+	  mutt_message _("Failed to create query, aborting.");
-+	else
-+	  main_change_folder(menu, op, buf, sizeof (buf), &oldcount, &index_hint, 0);
-+	break;
- 
-+      case OP_MAIN_CHANGE_VFOLDER:
-+#endif
-+#ifdef USE_SIDEBAR
-+      case OP_SIDEBAR_OPEN:
-+#endif
-+      case OP_MAIN_CHANGE_FOLDER:
-+      case OP_MAIN_NEXT_UNREAD_MAILBOX:
-       case OP_MAIN_CHANGE_FOLDER_READONLY:
-+#ifdef USE_NNTP
-+      case OP_MAIN_CHANGE_GROUP:
-+      case OP_MAIN_CHANGE_GROUP_READONLY:
-+	unset_option (OPTNEWS);
-+#endif
-+	if (attach_msg || option (OPTREADONLY) ||
-+#ifdef USE_NNTP
-+	    op == OP_MAIN_CHANGE_GROUP_READONLY ||
-+#endif
-+	    op == OP_MAIN_CHANGE_FOLDER_READONLY)
-+	  flags = M_READONLY;
-+	else
-+	  flags = 0;
- 
--        if ((op == OP_MAIN_CHANGE_FOLDER_READONLY) || option (OPTREADONLY))
-+	if (flags)
-           cp = _("Open mailbox in read-only mode");
--        else
-+#ifdef USE_NOTMUCH
-+        else if (op == OP_MAIN_CHANGE_VFOLDER)
-+	  cp = _("Open virtual folder");
-+#endif
-+	else
-           cp = _("Open mailbox");
- 
- 	buf[0] = '\0';
-@@ -1177,10 +1769,48 @@
- 	    break;
- 	  }
- 	}
-+#ifdef USE_NOTMUCH
-+	else if (op == OP_MAIN_CHANGE_VFOLDER) {
-+	  if (Context->magic == M_NOTMUCH) {
-+		  strfcpy(buf, Context->path, sizeof (buf));
-+		  mutt_buffy_vfolder (buf, sizeof (buf));
-+	  }
-+	  mutt_enter_vfolder (cp, buf, sizeof (buf), &menu->redraw, 1);
-+	  if (!buf[0])
-+	  {
-+	    CLEARLINE (LINES-1);
-+	    break;
-+	  }
-+	}
-+#endif
- 	else
- 	{
-+#ifdef USE_NNTP
-+	  if (op == OP_MAIN_CHANGE_GROUP ||
-+	      op == OP_MAIN_CHANGE_GROUP_READONLY)
-+	  {
-+	    set_option (OPTNEWS);
-+	    CurrentNewsSrv = nntp_select_server (NewsServer, 0);
-+	    if (!CurrentNewsSrv)
-+	      break;
-+	    if (flags)
-+	      cp = _("Open newsgroup in read-only mode");
-+	    else
-+	      cp = _("Open newsgroup");
-+	    nntp_buffy (buf, sizeof (buf));
-+	  }
-+	  else
-+#endif
- 	  mutt_buffy (buf, sizeof (buf));
- 
-+#ifdef USE_SIDEBAR
-+	  if (op == OP_SIDEBAR_OPEN) {
-+	    const char *path = mutt_sb_get_highlight();
-+	    if (!path)
-+	      break;
-+	    strncpy (buf, path, sizeof (buf));
-+	  } else
-+#endif
- 	  if (mutt_enter_fname (cp, buf, sizeof (buf), &menu->redraw, 1) == -1)
- 	  {
- 	    if (menu->menu == MENU_PAGER)
-@@ -1198,61 +1828,16 @@
- 	  }
- 	}
- 
-+	main_change_folder(menu, op, buf, sizeof (buf), &oldcount, &index_hint, flags);
-+#ifdef USE_NNTP
-+	/* mutt_buffy_check() must be done with mail-reader mode! */
-+	menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_MAIN,
-+	  (Context && (Context->magic == M_NNTP)) ? IndexNewsHelp : IndexHelp);
-+#endif
- 	mutt_expand_path (buf, sizeof (buf));
--	if (mx_get_magic (buf) <= 0)
--	{
--	  mutt_error (_("%s is not a mailbox."), buf);
--	  break;
--	}
--	mutt_str_replace (&CurrentFolder, buf);
--
--	/* keepalive failure in mutt_enter_fname may kill connection. #3028 */
--	if (Context && !Context->path)
--	  FREE (&Context);
--
--        if (Context)
--        {
--	  int check;
--
--	  mutt_str_replace (&LastFolder, Context->path);
--	  oldcount = Context ? Context->msgcount : 0;
--
--	  if ((check = mx_close_mailbox (Context, &index_hint)) != 0)
--	  {
--	    if (check == M_NEW_MAIL || check == M_REOPENED)
--	      update_index (menu, Context, check, oldcount, index_hint);
--
--	    set_option (OPTSEARCHINVALID);
--	    menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
--	    break;
--	  }
--	  FREE (&Context);
--	}
--
--        mutt_sleep (0);
--
--	/* Set CurrentMenu to MENU_MAIN before executing any folder
--	 * hooks so that all the index menu functions are available to
--	 * the exec command.
--	 */
--
--	CurrentMenu = MENU_MAIN;
--	mutt_folder_hook (buf);
--
--	if ((Context = mx_open_mailbox (buf,
--					(option (OPTREADONLY) || op == OP_MAIN_CHANGE_FOLDER_READONLY) ?
--					M_READONLY : 0, NULL)) != NULL)
--	{
--	  menu->current = ci_first_message ();
--	}
--	else
--	  menu->current = 0;
--
--	mutt_clear_error ();
--	mutt_buffy_check(1); /* force the buffy check after we have changed
--			      the folder */
--	menu->redraw = REDRAW_FULL;
--	set_option (OPTSEARCHINVALID);
-+#ifdef USE_SIDEBAR
-+	mutt_sb_set_open_buffy (buf);
-+#endif
- 	break;
- 
-       case OP_DISPLAY_MESSAGE:
-@@ -1316,6 +1901,7 @@
- 	CHECK_MSGCOUNT;
-         CHECK_VISIBLE;
- 	CHECK_READONLY;
-+	CHECK_ACL(M_ACL_WRITE, _("Cannot break thread"));
- 
-         if ((Sort & SORT_MASK) != SORT_THREADS)
- 	  mutt_error _("Threading is not enabled.");
-@@ -1351,7 +1937,7 @@
-         CHECK_VISIBLE;
- 	CHECK_READONLY;
-         /* L10N: CHECK_ACL */
--	CHECK_ACL(M_ACL_DELETE, _("Cannot link threads"));
-+	CHECK_ACL(M_ACL_WRITE, _("Cannot link threads"));
- 
-         if ((Sort & SORT_MASK) != SORT_THREADS)
- 	  mutt_error _("Threading is not enabled.");
-@@ -1919,6 +2505,7 @@
- 	MAYBE_REDRAW (menu->redraw);
- 	break;
- 
-+      case OP_PURGE_MESSAGE:
-       case OP_DELETE:
- 
- 	CHECK_MSGCOUNT;
-@@ -1930,6 +2517,7 @@
- 	if (tag)
- 	{
- 	  mutt_tag_set_flag (M_DELETE, 1);
-+	  mutt_tag_set_flag (M_PURGED, (op != OP_PURGE_MESSAGE) ? 0 : 1);
- 	  if (option (OPTDELETEUNTAG))
- 	    mutt_tag_set_flag (M_TAG, 0);
- 	  menu->redraw = REDRAW_INDEX;
-@@ -1937,6 +2525,8 @@
- 	else
- 	{
- 	  mutt_set_flag (Context, CURHDR, M_DELETE, 1);
-+	  mutt_set_flag (Context, CURHDR, M_PURGED,
-+			 (op != OP_PURGE_MESSAGE) ? 0 : 1);
- 	  if (option (OPTDELETEUNTAG))
- 	    mutt_set_flag (Context, CURHDR, M_TAG, 0);
- 	  if (option (OPTRESOLVE))
-@@ -1984,6 +2574,20 @@
- 	}
- 	break;
- 
-+#ifdef USE_NNTP
-+      case OP_CATCHUP:
-+	CHECK_MSGCOUNT;
-+	CHECK_READONLY;
-+	CHECK_ATTACH
-+	if (Context && Context->magic == M_NNTP)
-+	{
-+	  NNTP_DATA *nntp_data = Context->data;
-+	  if (mutt_newsgroup_catchup (nntp_data->nserv, nntp_data->group))
-+	    menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
-+	}
-+	break;
-+#endif
 +
-       case OP_DISPLAY_ADDRESS:
- 
- 	CHECK_MSGCOUNT;
-@@ -2045,6 +2649,21 @@
- 	menu->redraw = REDRAW_FULL;
- 	break;
- 
-+      case OP_EDIT_LABEL:
 +
-+	CHECK_MSGCOUNT;
-+	CHECK_READONLY;
-+	rc = mutt_label_message(tag ? NULL : CURHDR);
-+	if (rc > 0) {
-+	  Context->changed = 1;
-+	  menu->redraw = REDRAW_FULL;
-+	  mutt_message ("%d label%s changed.", rc, rc == 1 ? "" : "s");
-+	}
-+	else {
-+	  mutt_message _("No labels changed.");
-+	}
-+	break;
++    Examples:
 +
-       case OP_LIST_REPLY:
- 
- 	CHECK_ATTACH;
-@@ -2190,6 +2809,39 @@
-         menu->redraw = REDRAW_FULL;
-         break;
- 
-+#ifdef USE_NNTP
-+      case OP_FOLLOWUP:
-+      case OP_FORWARD_TO_GROUP:
++        set index_format='%4C %Z %{%b %d} %-25.25n %s%> %<M?%M Msgs &%<l?%l Lines&%c Bytes>>'
 +
-+	CHECK_MSGCOUNT;
-+	CHECK_VISIBLE;
++        if a thread is folded
++            display the number of messages (%M)
++        else if we know how many lines in the message
++            display lines in message (%l)
++        else
++            display the size of the message in bytes (%c)
 +
-+      case OP_POST:
 +
-+	CHECK_ATTACH;
-+	if (op != OP_FOLLOWUP || !CURHDR->env->followup_to ||
-+	    mutt_strcasecmp (CURHDR->env->followup_to, "poster") ||
-+	    query_quadoption (OPT_FOLLOWUPTOPOSTER,
-+	    _("Reply by mail as poster prefers?")) != M_YES)
-+	{
-+	  if (Context && Context->magic == M_NNTP &&
-+	      !((NNTP_DATA *)Context->data)->allowed &&
-+	      query_quadoption (OPT_TOMODERATED,
-+	      _("Posting to this group not allowed, may be moderated. Continue?")) != M_YES)
-+	    break;
-+	  if (op == OP_POST)
-+	    ci_send_message (SENDNEWS, NULL, NULL, Context, NULL);
-+	  else
-+	  {
-+	    CHECK_MSGCOUNT;
-+	    ci_send_message ((op == OP_FOLLOWUP ? SENDREPLY : SENDFORWARD) |
-+			SENDNEWS, NULL, NULL, Context, tag ? NULL : CURHDR);
-+	  }
-+	  menu->redraw = REDRAW_FULL;
-+	  break;
-+	}
-+#endif
++        set index_format='%4C %Z %{%b %d} %-25.25n %<M?[%M] %s&%s%* %<l?%l&%c>>'
 +
-       case OP_REPLY:
- 
- 	CHECK_ATTACH;
-@@ -2242,11 +2894,13 @@
- 	if (tag)
- 	{
- 	  mutt_tag_set_flag (M_DELETE, 0);
-+	  mutt_tag_set_flag (M_PURGED, 0);
- 	  menu->redraw = REDRAW_INDEX;
- 	}
- 	else
- 	{
- 	  mutt_set_flag (Context, CURHDR, M_DELETE, 0);
-+	  mutt_set_flag (Context, CURHDR, M_PURGED, 0);
- 	  if (option (OPTRESOLVE) && menu->current < Context->vcount - 1)
- 	  {
- 	    menu->current++;
-@@ -2268,9 +2922,11 @@
- 	CHECK_ACL(M_ACL_DELETE, _("Cannot undelete message(s)"));
- 
- 	rc = mutt_thread_set_flag (CURHDR, M_DELETE, 0,
--				   op == OP_UNDELETE_THREAD ? 0 : 1);
-+				   op == OP_UNDELETE_THREAD ? 0 : 1)
-+	  + mutt_thread_set_flag (CURHDR, M_PURGED, 0,
-+				  (op == OP_UNDELETE_THREAD) ? 0 : 1);
- 
--	if (rc != -1)
-+	if (rc > -1)
- 	{
- 	  if (option (OPTRESOLVE))
- 	  {
-@@ -2310,11 +2966,35 @@
- 	mutt_what_key();
- 	break;
- 
-+#ifdef USE_SIDEBAR
-+      case OP_SIDEBAR_NEXT:
-+      case OP_SIDEBAR_NEXT_NEW:
-+      case OP_SIDEBAR_PAGE_DOWN:
-+      case OP_SIDEBAR_PAGE_UP:
-+      case OP_SIDEBAR_PREV:
-+      case OP_SIDEBAR_PREV_NEW:
-+        mutt_sb_change_mailbox (op);
-+        break;
++        if a thread is folded
++            display the number of messages (%M)
++            display the subject (%s)
++        else if we know how many lines in the message
++            display lines in message (%l)
++        else
++            display the size of the message in bytes (%c)
 +
-+      case OP_SIDEBAR_TOGGLE_VISIBLE:
-+	toggle_option (OPTSIDEBAR);
-+	menu->redraw = REDRAW_FULL;
-+	break;
 +
-+      case OP_SIDEBAR_TOGGLE_VIRTUAL:
-+	mutt_sb_toggle_virtual();
-+	break;
-+#endif
-       default:
- 	if (menu->menu == MENU_MAIN)
- 	  km_error_key (MENU_MAIN);
-     }
- 
-+#ifdef USE_NOTMUCH
-+    if (Context)
-+      nm_debug_check(Context);
-+#endif
-+
-     if (menu->menu == MENU_PAGER)
-     {
-       menu->menu = MENU_MAIN;
-diff -urN mutt-1.6.1/doc/gen-map-doc mutt-1.6.1-neomutt/doc/gen-map-doc
---- mutt-1.6.1/doc/gen-map-doc	2016-06-12 18:43:00.400447559 +0100
-+++ mutt-1.6.1-neomutt/doc/gen-map-doc	2016-06-12 18:43:00.688452050 +0100
-@@ -34,7 +34,8 @@
-     $binding =~ s/^\\(0\d+)$/'^'.chr(64+oct($1))/e;
-     $binding =~ s/^\\(0\d+)(.)/'^'.chr(64+oct($1)) ." $2"/e;
-     $binding =~ s/\\t/<Tab>/;
--    $binding =~ s/M_ENTER_S/<Return>/;
-+    $binding =~ s/\\r/<Return>/;
-+    $binding =~ s/\\n/<Enter>/;
-     $binding =~ s/NULL//;
-     die "unknown key $binding" if $binding =~ /\\[^\\]|<|>/;
-     die "unknown OP $op" unless $OPS{$op};
-diff -urN mutt-1.6.1/doc/Makefile.am mutt-1.6.1-neomutt/doc/Makefile.am
---- mutt-1.6.1/doc/Makefile.am	2016-06-12 18:43:00.399447544 +0100
-+++ mutt-1.6.1-neomutt/doc/Makefile.am	2016-06-12 18:43:00.687452035 +0100
-@@ -37,7 +37,8 @@
- 
- CHUNKED_DOCFILES = index.html intro.html gettingstarted.html \
- 	configuration.html mimesupport.html advancedusage.html \
--	optionalfeatures.html security.html tuning.html reference.html miscellany.html
-+	optionalfeatures.html security.html tuning.html reference.html miscellany.html \
-+	compressed-folders.html
- 
- HTML_DOCFILES = manual.html $(CHUNKED_DOCFILES)
- 
-@@ -189,8 +190,8 @@
- 
- stamp-doc-xml: makedoc$(EXEEXT) $(top_srcdir)/init.h \
-                manual.xml.head $(top_srcdir)/functions.h $(top_srcdir)/OPS* manual.xml.tail \
--               $(srcdir)/gen-map-doc $(top_srcdir)/VERSION $(top_srcdir)/ChangeLog
--	( date=`head -n 1 $(top_srcdir)/ChangeLog | LC_ALL=C cut -d ' ' -f 1` && \
-+               $(srcdir)/gen-map-doc $(top_srcdir)/VERSION $(top_srcdir)/ChangeLog.neomutt
-+	( date=`head -n 1 $(top_srcdir)/ChangeLog.neomutt | LC_ALL=C cut -b 1-10` && \
- 	  sed -e "s/@VERSION\@/`cat $(top_srcdir)/VERSION` ($$date)/" $(srcdir)/manual.xml.head && \
- 	  $(MAKEDOC_CPP) $(top_srcdir)/init.h | ./makedoc$(EXEEXT) -s && \
- 	  $(MAKEDOC_CPP) $(top_srcdir)/functions.h | \
-diff -urN mutt-1.6.1/doc/manual.xml.head mutt-1.6.1-neomutt/doc/manual.xml.head
---- mutt-1.6.1/doc/manual.xml.head	2016-06-12 18:43:00.402447590 +0100
-+++ mutt-1.6.1-neomutt/doc/manual.xml.head	2016-06-12 18:43:00.692452113 +0100
-@@ -405,6 +405,623 @@
- 
- </sect2>
- 
-+<sect2 id="intro-sidebar">
-+	<title>Sidebar</title>
-+	<para>
-+		The Sidebar shows a list of all your mailboxes.  The list can be
-+		turned on and off, it can be themed and the list style can be
-+		configured.
-+	</para>
-+	<para>
-+		This part of the manual is suitable for beginners.
-+		If you already know Mutt you could skip ahead to the main
-+		<link linkend="sidebar">Sidebar guide</link>.
-+		If you just want to get started, you could use the sample
-+		<link linkend="sidebar-muttrc">Sidebar muttrc</link>.
-+	</para>
-+	<para>
-+		This version of Sidebar is based on Terry Chan's
-+		<ulink url="http://www.lunar-linux.org/mutt-sidebar/">2015-11-11 release</ulink>.
-+		It contains many
-+		<emphasis role="bold"><link linkend="intro-sidebar-features">new features</link></emphasis>,
-+		lots of
-+		<emphasis role="bold"><link linkend="intro-sidebar-bugfixes">bugfixes</link></emphasis>
-+		and a generous helping of
-+		<emphasis role="bold">new documentation</emphasis> which you are already reading.
-+	</para>
-+	<para>
-+		To check if Mutt supports <quote>Sidebar</quote>, look for the string
-+		<literal>+USE_SIDEBAR</literal> in the mutt version.
-+	</para>
-+<screen>
-+mutt -v
-+</screen>
-+	<para>
-+		<emphasis role="bold">Let's turn on the Sidebar:</emphasis>
-+	</para>
-+	<screen>set sidebar_visible</screen>
-+	<para>
-+		You will see something like this.
-+		A list of mailboxes on the left.
-+		A list of emails, from the selected mailbox, on the right.
-+	</para>
-+<screen>
-+<emphasis role="indicator">Fruit [1]     3/8</emphasis>|  1    + Jan 24  Rhys Lee         (192)  Yew
-+Animals [1]   2/6|  2    + Feb 11  Grace Hall       (167)  Ilama
-+Cars            4|  3      Feb 23  Aimee Scott      (450)  Nectarine
-+Seas          1/7|  4    ! Feb 28  Summer Jackson   (264)  Lemon
-+                 |  5      Mar 07  Callum Harrison  (464)  Raspberry
-+                 |<emphasis role="indicator">  6 N  + Mar 24  Samuel Harris    (353)  Tangerine          </emphasis>
-+                 |  7 N  + Sep 05  Sofia Graham     (335)  Cherry
-+                 |  8 N    Sep 16  Ewan Brown       (105)  Ugli
-+                 |
-+                 |
-+</screen>
-+<para>
-+	This user has four mailboxes: <quote>Fruit</quote>,
-+	<quote>Cars</quote>, <quote>Animals</quote> and
-+	<quote>Seas</quote>.
-+</para>
-+<para>
-+	The current, open, mailbox is <quote>Fruit</quote>.  We can
-+	also see information about the other mailboxes.  For example:
-+	The <quote>Animals</quote> mailbox contains, 1 flagged email, 2
-+	new emails out of a total of 6 emails.
-+</para>
-+	<sect3 id="intro-sidebar-navigation">
-+		<title>Navigation</title>
-+		<para>
-+			The Sidebar adds some new <link linkend="sidebar-functions">functions</link>
-+			to Mutt.
-+		</para>
-+		<para>
-+			The user pressed the <quote>c</quote> key to
-+			<literal><change-folder></literal> to the
-+			<quote>Animals</quote> mailbox.  The Sidebar automatically
-+			updated the indicator to match.
-+		</para>
-+<screen>
-+Fruit [1]     3/8|  1      Jan 03  Tia Gibson       (362)  Caiman
-+<emphasis role="indicator">Animals [1]   2/6</emphasis>|  2    + Jan 22  Rhys Lee         ( 48)  Dolphin
-+Cars            4|  3    ! Aug 16  Ewan Brown       (333)  Hummingbird
-+Seas          1/7|  4      Sep 25  Grace Hall       ( 27)  Capybara
-+                 |<emphasis role="indicator">  5 N  + Nov 12  Evelyn Rogers    (453)  Tapir              </emphasis>
-+                 |  6 N  + Nov 16  Callum Harrison  (498)  Hedgehog
-+                 |
-+                 |
-+                 |
-+                 |
-+</screen>
-+		<para>
-+			Let's map some functions:
-+		</para>
-+<screen>
-+bind index,pager \CP sidebar-prev       <emphasis role="comment"># Ctrl-Shift-P - Previous Mailbox</emphasis>
-+bind index,pager \CN sidebar-next       <emphasis role="comment"># Ctrl-Shift-N - Next Mailbox</emphasis>
-+bind index,pager \CO sidebar-open       <emphasis role="comment"># Ctrl-Shift-O - Open Highlighted Mailbox</emphasis>
-+</screen>
-+		<para>
-+			Press <quote>Ctrl-Shift-N</quote> (Next mailbox) twice will
-+			move the Sidebar <emphasis role="bold">highlight</emphasis> to
-+			down to the <quote>Seas</quote> mailbox.
-+		</para>
-+<screen>
-+Fruit [1]     3/8|  1      Jan 03  Tia Gibson       (362)  Caiman
-+<emphasis role="indicator">Animals [1]   2/6</emphasis>|  2    + Jan 22  Rhys Lee         ( 48)  Dolphin
-+Cars            4|  3    ! Aug 16  Ewan Brown       (333)  Hummingbird
-+<emphasis role="highlight">Seas          1/7</emphasis>|  4      Sep 25  Grace Hall       ( 27)  Capybara
-+                 |<emphasis role="indicator">  5 N  + Nov 12  Evelyn Rogers    (453)  Tapir              </emphasis>
-+                 |  6 N  + Nov 16  Callum Harrison  (498)  Hedgehog
-+                 |
-+                 |
-+                 |
-+                 |
-+</screen>
-+		<note>
-+			Functions <literal><sidebar-next></literal> and
-+			<literal><sidebar-prev></literal> move the Sidebar
-+			<emphasis role="bold">highlight</emphasis>.
-+			They <emphasis role="bold">do not</emphasis> change the open
-+			mailbox.
-+		</note>
-+		<para>
-+			Press <quote>Ctrl-Shift-O</quote>
-+			(<literal><sidebar-open></literal>)
-+			to open the highlighted mailbox.
-+		</para>
-+<screen>
-+Fruit [1]     3/8|  1    ! Mar 07  Finley Jones     (139)  Molucca Sea
-+Animals [1]   2/6|  2    + Mar 24  Summer Jackson   ( 25)  Arafura Sea
-+Cars            4|  3    + Feb 28  Imogen Baker     (193)  Pechora Sea
-+<emphasis role="indicator">Seas          1/7</emphasis>|<emphasis role="indicator">  4 N  + Feb 23  Isla Hussain     (348)  Balearic Sea       </emphasis>
-+                 |
-+                 |
-+                 |
-+                 |
-+                 |
-+                 |
-+</screen>
-+	</sect3>
-+	<sect3 id="intro-sidebar-features">
-+		<title>Features</title>
-+		<para>
-+			The Sidebar shows a list of mailboxes in a panel.
-+		<para>
-+		</para>
-+			Everything about the Sidebar can be configured.
-+		</para>
-+		<itemizedlist>
-+		<title><link linkend="intro-sidebar-basics">State of the Sidebar</link></title>
-+			<listitem><para>Visibility</para></listitem>
-+			<listitem><para>Width</para></listitem>
-+		</itemizedlist>
-+		<itemizedlist>
-+		<title><link linkend="intro-sidebar-limit">Which mailboxes are displayed</link></title>
-+			<listitem><para>Display all</para></listitem>
-+			<listitem><para>Limit to mailboxes with new mail</para></listitem>
-+			<listitem><para>Whitelist mailboxes to display always</para></listitem>
-+		</itemizedlist>
-+		<itemizedlist>
-+		<title><link linkend="sidebar-sort">The order in which mailboxes are displayed</link></title>
-+		<title></title>
-+			<listitem><para>Unsorted (order of mailboxes commands)</para></listitem>
-+			<listitem><para>Sorted alphabetically</para></listitem>
-+			<listitem><para>Sorted by number of new mails</para></listitem>
-+		</itemizedlist>
-+		<itemizedlist>
-+		<title><link linkend="intro-sidebar-colors">Color</link></title>
-+			<listitem><para>Sidebar indicators and divider</para></listitem>
-+			<listitem><para>Mailboxes depending on their type</para></listitem>
-+			<listitem><para>Mailboxes depending on their contents</para></listitem>
-+		</itemizedlist>
-+		<itemizedlist>
-+		<title><link linkend="sidebar-functions">Key bindings</link></title>
-+			<listitem><para>Hide/Unhide the Sidebar</para></listitem>
-+			<listitem><para>Select previous/next mailbox</para></listitem>
-+			<listitem><para>Select previous/next mailbox with new mail</para></listitem>
-+			<listitem><para>Page up/down through a list of mailboxes</para></listitem>
-+		</itemizedlist>
-+		<itemizedlist>
-+		<title>Misc</title>
-+			<listitem><para><link linkend="intro-sidebar-format">Formatting string for mailbox</link></para></listitem>
-+			<listitem><para><link linkend="sidebar-next-new-wrap">Wraparound searching</link></para></listitem>
-+			<listitem><para><link linkend="intro-sidebar-abbrev">Flexible mailbox abbreviations</link></para></listitem>
-+			<listitem><para>Support for Unicode mailbox names (utf-8)</para></listitem>
-+		</itemizedlist>
-+	</sect3>
-+	<sect3 id="intro-sidebar-display">
-+		<title>Display</title>
-+		<para>
-+			Everything about the Sidebar can be configured.
-+		</para>
-+		<itemizedlist>
-+			<title>For a quick reference:</title>
-+			<listitem><para><link linkend="sidebar-variables">Sidebar variables to set</link> </para></listitem>
-+			<listitem><para><link linkend="sidebar-colors">Sidebar colors to apply</link></para></listitem>
-+			<listitem><para><link linkend="sidebar-sort">Sidebar sort methods</link></para></listitem>
-+		</itemizedlist>
-+		<sect4 id="intro-sidebar-basics">
-+			<title>Sidebar Basics</title>
-+			<para>
-+				The most important variable is <literal>$sidebar_visible</literal>.
-+				You can set this in your <quote>muttrc</quote>, or bind a key to the
-+				function <literal><sidebar-toggle-visible></literal>.
-+			</para>
-+<screen>
-+set sidebar_visible                         <emphasis role="comment"># Make the Sidebar visible by default</emphasis>
-+bind index,pager B sidebar-toggle-visible   <emphasis role="comment"># Use 'B' to switch the Sidebar on and off</emphasis>
-+</screen>
-+			<para>
-+				Next, decide how wide you want the Sidebar to be.  25
-+				characters might be enough for the mailbox name and some numbers.
-+		Remember, you can hide/show the Sidebar at the press of button.
-+		</para>
-+		<para>
-+		Finally, you might want to change the divider character.
-+		By default, Sidebar draws an ASCII line between it and the Index panel
-+				If your terminal supports it, you can use a Unicode line-drawing character.
-+			</para>
-+<screen>
-+set sidebar_width = 25                  <emphasis role="comment"># Plenty of space</emphasis>
-+set sidebar_divider_char = '│'          <emphasis role="comment"># Pretty line-drawing character</emphasis>
-+</screen>
-+		</sect4>
-+		<sect4 id="intro-sidebar-format">
-+			<title>Sidebar Format String</title>
-+			<para>
-+				<literal>$sidebar_format</literal> allows you to customize the Sidebar display.
-+				For an introduction, read <link linkend="index-format">format strings</link>
-+				including the section about <link linkend="formatstrings-conditionals">conditionals</link>.
-+			</para>
-+			<para>
-+				The default value is <literal>%B%?F? [%F]?%* %?N?%N/?%S</literal>
-+			</para>
-+			<itemizedlist>
-+				<title>Which breaks down as:</title>
-+				<listitem><para><literal>%B</literal> - Mailbox name</para></listitem>
-+				<listitem><para><literal>%?F? [%F]?</literal> - If flagged emails <literal>[%F]</literal>, otherwise nothing</para></listitem>
-+				<listitem><para><literal>%* </literal> - Pad with spaces</para></listitem>
-+				<listitem><para><literal>%?N?%N/?</literal> - If new emails <literal>%N/</literal>, otherwise nothing</para></listitem>
-+				<listitem><para><literal>%S</literal> - Total number of emails</para></listitem>
-+			</itemizedlist>
-+			<table>
-+				<title>sidebar_format</title>
-+				<tgroup cols="3">
-+					<thead>
-+						<row>
-+							<entry>Format</entry>
-+							<entry>Notes</entry>
-+							<entry>Description</entry>
-+						</row>
-+					</thead>
-+					<tbody>
-+						<row>
-+							<entry>%B</entry>
-+							<entry></entry>
-+							<entry>Name of the mailbox</entry>
-+						</row>
-+						<row>
-+							<entry>%S</entry>
-+							<entry>*</entry>
-+							<entry>Size of mailbox (total number of messages)</entry>
-+						</row>
-+						<row>
-+							<entry>%N</entry>
-+							<entry>*</entry>
-+							<entry>Number of New messages in the mailbox</entry>
-+						</row>
-+						<row>
-+							<entry>%F</entry>
-+							<entry>*</entry>
-+							<entry>Number of Flagged messages in the mailbox</entry>
-+						</row>
-+						<row>
-+							<entry>%!</entry>
-+							<entry></entry>
-+							<entry>
-+								<quote>!</quote>: one flagged message;
-+								<quote>!!</quote>: two flagged messages;
-+								<quote>n!</quote>: n flagged messages (for n > 2).
-+								Otherwise prints nothing.
-+							</entry>
-+						</row>
-+						<row>
-+							<entry>%d</entry>
-+							<entry>* ‡</entry>
-+							<entry>Number of deleted messages</entry>
-+						</row>
-+						<row>
-+							<entry>%L</entry>
-+							<entry>* ‡</entry>
-+							<entry>Number of messages after limiting</entry>
-+						</row>
-+						<row>
-+							<entry>%t</entry>
-+							<entry>* ‡</entry>
-+							<entry>Number of tagged messages</entry>
-+						</row>
-+						<row>
-+							<entry>%>X</entry>
-+							<entry></entry>
-+							<entry>Right justify the rest of the string and pad with <quote>X</quote></entry>
-+						</row>
-+						<row>
-+							<entry>%|X</entry>
-+							<entry></entry>
-+							<entry>Pad to the end of the line with
-+							<quote>X</quote></entry>
-+						</row>
-+						<row>
-+							<entry>%*X</entry>
-+							<entry></entry>
-+							<entry>Soft-fill with character <quote>X</quote>as pad</entry>
-+						</row>
-+					</tbody>
-+				</tgroup>
-+			</table>
-+			<para>
-+			* = Can be optionally printed if nonzero
-+			</para>
-+			<para>
-+			‡ = Only applicable to the current folder
-+			</para>
-+			<para>
-+				Here are some examples.
-+				They show the number of (F)lagged, (N)ew and (S)ize.
-+			</para>
-+			<table>
-+				<title>sidebar_format</title>
-+				<tgroup cols="2">
-+					<thead>
-+						<row>
-+							<entry>Format</entry>
-+							<entry>Example</entry>
-+						</row>
-+					</thead>
-+					<tbody>
-+						<row>
-+							<entry><literal>%B%?F? [%F]?%* %?N?%N/?%S</literal></entry>
-+							<entry><screen>mailbox [F]            N/S</screen></entry>
-+						</row>
-+						<row>
-+							<entry><literal>%B%* %F:%N:%S</literal></entry>
-+							<entry><screen>mailbox              F:N:S</screen></entry>
-+						</row>
-+						<row>
-+							<entry><literal>%B %?N?(%N)?%* %S</literal></entry>
-+							<entry><screen>mailbox (N)              S</screen></entry>
-+						</row>
-+						<row>
-+							<entry><literal>%B%* ?F?%F/?%N</literal></entry>
-+							<entry><screen>mailbox                F/S</screen></entry>
-+						</row>
-+					</tbody>
-+				</tgroup>
-+			</table>
-+		</sect4>
-+		<sect4 id="intro-sidebar-abbrev">
-+			<title>Abbreviating Mailbox Names</title>
-+			<para>
-+				<literal>$sidebar_delim_chars</literal> tells Sidebar
-+				how to split up mailbox paths.  For local directories
-+				use <quote>/</quote>; for IMAP folders use <quote>.</quote>
-+			</para>
-+			<sect5 id="intro-sidebar-abbrev-ex1">
-+				<title>Example 1</title>
-+				<para>
-+					This example works well if your mailboxes have unique names
-+					after the last separator.
-+				</para>
-+				<para>
-+					Add some mailboxes of diffent depths.
-+				</para>
-+<screen>
-+set folder="~/mail"
-+mailboxes =fruit/apple          =fruit/banana          =fruit/cherry
-+mailboxes =water/sea/sicily     =water/sea/archipelago =water/sea/sibuyan
-+mailboxes =water/ocean/atlantic =water/ocean/pacific   =water/ocean/arctic
-+</screen>
-+				<para>
-+					Shorten the names:
-+				</para>
-+<screen>
-+set sidebar_short_path                  <emphasis role="comment"># Shorten mailbox names</emphasis>
-+set sidebar_delim_chars="/"             <emphasis role="comment"># Delete everything up to the last / character</emphasis>
-+</screen>
-+				<para>
-+					The screenshot below shows what the Sidebar would look like
-+					before and after shortening.
-+				</para>
-+<screen>
-+|fruit/apple                            |apple
-+|fruit/banana                           |banana
-+|fruit/cherry                           |cherry
-+|water/sea/sicily                       |sicily
-+|water/sea/archipelago                  |archipelago
-+|water/sea/sibuyan                      |sibuyan
-+|water/ocean/atlantic                   |atlantic
-+|water/ocean/pacific                    |pacific
-+|water/ocean/arctic                     |arctic
-+</screen>
-+			</sect5>
-+			<sect5 id="intro-sidebar-abbrev-ex2">
-+				<title>Example 2</title>
-+				<para>
-+					This example works well if you have lots of mailboxes which are arranged
-+					in a tree.
-+				</para>
-+				<para>
-+					Add some mailboxes of diffent depths.
-+				</para>
-+<screen>
-+set folder="~/mail"
-+mailboxes =fruit
-+mailboxes =fruit/apple =fruit/banana =fruit/cherry
-+mailboxes =water
-+mailboxes =water/sea
-+mailboxes =water/sea/sicily =water/sea/archipelago =water/sea/sibuyan
-+mailboxes =water/ocean
-+mailboxes =water/ocean/atlantic =water/ocean/pacific =water/ocean/arctic
-+</screen>
-+				<para>
-+					Shorten the names:
-+				</para>
-+<screen>
-+set sidebar_short_path                  <emphasis role="comment"># Shorten mailbox names</emphasis>
-+set sidebar_delim_chars="/"             <emphasis role="comment"># Delete everything up to the last / character</emphasis>
-+set sidebar_folder_indent               <emphasis role="comment"># Indent folders whose names we've shortened</emphasis>
-+set sidebar_indent_string="  "          <emphasis role="comment"># Indent with two spaces</emphasis>
-+</screen>
-+				<para>
-+					The screenshot below shows what the Sidebar would look like
-+					before and after shortening.
-+				</para>
-+<screen>
-+|fruit                                  |fruit
-+|fruit/apple                            |  apple
-+|fruit/banana                           |  banana
-+|fruit/cherry                           |  cherry
-+|water                                  |water
-+|water/sea                              |  sea
-+|water/sea/sicily                       |    sicily
-+|water/sea/archipelago                  |    archipelago
-+|water/sea/sibuyan                      |    sibuyan
-+|water/ocean                            |  ocean
-+|water/ocean/atlantic                   |    atlantic
-+|water/ocean/pacific                    |    pacific
-+|water/ocean/arctic                     |    arctic
-+</screen>
-+				<para>
-+					Sometimes, it will be necessary to add mailboxes, that you
-+					don't use, to fill in part of the tree.	 This will trade
-+					vertical space for horizonal space (but it looks good).
-+				</para>
-+			</sect5>
-+		</sect4>
-+		<sect4 id="intro-sidebar-limit">
-+			<title>Limiting the Number of Mailboxes</title>
-+			<para>
-+				If you have a lot of mailboxes, sometimes it can be useful to hide
-+				the ones you aren't using.	<literal>$sidebar_new_mail_only</literal>
-+				tells Sidebar to only show mailboxes that contain new, or flagged, email.
-+			</para>
-+			<para>
-+				If you want some mailboxes to be always visible, then use the
-+				<literal>sidebar_whitelist</literal> command.  It takes a list of
-+				mailboxes as parameters.
-+			</para>
-+<screen>
-+set sidebar_new_mail_only               <emphasis role="comment"># Only mailboxes with new/flagged email</emphasis>
-+sidebar_whitelist fruit fruit/apple     <emphasis role="comment"># Always display these two mailboxes</emphasis>
-+</screen>
-+		</sect4>
-+	</sect3>
-+	<sect3 id="intro-sidebar-colors">
-+		<title>Colors</title>
-+		<para>
-+			Here is a sample color scheme:
-+		</para>
-+<screen>
-+color sidebar_indicator default color17         <emphasis role="comment"># Dark blue background</emphasis>
-+color sidebar_highlight white   color238        <emphasis role="comment"># Grey background</emphasis>
-+color sidebar_spoolfile yellow  default         <emphasis role="comment"># Yellow</emphasis>
-+color sidebar_new       green   default         <emphasis role="comment"># Green</emphasis>
-+color sidebar_flagged   red     default         <emphasis role="comment"># Red</emphasis>
-+color sidebar_divider   color8  default         <emphasis role="comment"># Dark grey</emphasis>
-+</screen>
-+		<para>
-+			There is a priority order when coloring Sidebar mailboxes.
-+			e.g.  If a mailbox has new mail it will have the
-+			<literal>sidebar_new</literal> color, even if it also contains
-+			flagged mails.
-+		</para>
-+		<table id="table-intro-sidebar-colors">
-+			<title>Sidebar Color Priority</title>
-+			<tgroup cols="3">
-+				<thead>
-+					<row>
-+						<entry>Priority</entry>
-+						<entry>Color</entry>
-+						<entry>Description</entry>
-+					</row>
-+				</thead>
-+				<tbody>
-+					<row>
-+						<entry>Highest</entry>
-+						<entry><literal>sidebar_indicator</literal></entry>
-+						<entry>Mailbox is open</entry>
-+					</row>
-+					<row>
-+						<entry></entry>
-+						<entry><literal>sidebar_highlight</literal></entry>
-+						<entry>Mailbox is highlighed</entry>
-+					</row>
-+					<row>
-+						<entry></entry>
-+						<entry><literal>sidebar_spoolfile</literal></entry>
-+						<entry>Mailbox is the spoolfile (receives incoming mail)</entry>
-+					</row>
-+					<row>
-+						<entry></entry>
-+						<entry><literal>sidebar_new</literal></entry>
-+						<entry>Mailbox contains new mail</entry>
-+					</row>
-+					<row>
-+						<entry></entry>
-+						<entry><literal>sidebar_flagged</literal></entry>
-+						<entry>Mailbox contains flagged mail</entry>
-+					</row>
-+					<row>
-+						<entry>Lowest</entry>
-+						<entry>(None)</entry>
-+						<entry>Mailbox does not match above</entry>
-+					</row>
-+				</tbody>
-+			</tgroup>
-+		</table>
-+	</sect3>
-+	<sect3 id="intro-sidebar-bugfixes">
-+		<title>Bug-fixes</title>
-+		<para>
-+			If you haven't used Sidebar before, you can ignore this section.
-+		</para>
-+		<para>
-+			These bugs have been fixed since the previous Sidebar release: 2015-11-11.
-+		</para>
-+		<itemizedlist>
-+			<listitem><para>Fix bug when starting in compose mode</para></listitem>
-+			<listitem><para>Fix bug with empty sidebar_divider_char string</para></listitem>
-+			<listitem><para>Fix bug with header wrapping</para></listitem>
-+			<listitem><para>Correctly handle utf8 character sequences</para></listitem>
-+			<listitem><para>Fix a bug in mh_buffy_update</para></listitem>
-+			<listitem><para>Fix refresh -- time overflowed short</para></listitem>
-+			<listitem><para>Protect against empty format strings</para></listitem>
-+			<listitem><para>Limit Sidebar width to COLS</para></listitem>
-+			<listitem><para>Handle unmailboxes * safely</para></listitem>
-+			<listitem><para>Refresh Sidebar after timeout</para></listitem>
-+		</itemizedlist>
-+	</sect3>
-+	<sect3 id="intro-sidebar-config-changes">
-+		<title>Config Changes</title>
-+		<para>
-+			If you haven't used Sidebar before, you can ignore this section.
-+		</para>
-+		<para>
-+			Some of the Sidebar config has been changed to make its meaning clearer.
-+			These changes have been made since the previous Sidebar release: 2015-11-11.
-+		</para>
-+		<table id="table-intro-sidebar-config-changes">
-+			<title>Config Changes</title>
-+			<tgroup cols="2">
-+				<thead>
-+					<row>
-+						<entry>Old Name</entry>
-+						<entry>New Name</entry>
-+					</row>
-+				</thead>
-+				<tbody>
-+					<row>
-+						<entry><literal>$sidebar_delim</literal></entry>
-+						<entry><literal>$sidebar_divider_char</literal></entry>
-+					</row>
-+					<row>
-+						<entry><literal>$sidebar_folderindent</literal></entry>
-+						<entry><literal>$sidebar_folder_indent</literal></entry>
-+					</row>
-+					<row>
-+						<entry><literal>$sidebar_indentstr</literal></entry>
-+						<entry><literal>$sidebar_indent_string</literal></entry>
-+					</row>
-+					<row>
-+						<entry><literal>$sidebar_newmail_only</literal></entry>
-+						<entry><literal>$sidebar_new_mail_only</literal></entry>
-+					</row>
-+					<row>
-+						<entry><literal>$sidebar_refresh</literal></entry>
-+						<entry><literal>$sidebar_refresh_time</literal></entry>
-+					</row>
-+					<row>
-+						<entry><literal>$sidebar_shortpath</literal></entry>
-+						<entry><literal>$sidebar_short_path</literal></entry>
-+					</row>
-+					<row>
-+						<entry><literal>$sidebar_sort</literal></entry>
-+						<entry><literal>$sidebar_sort_method</literal></entry>
-+					</row>
-+					<row>
-+						<entry><literal><sidebar-scroll-down></literal></entry>
-+						<entry><literal><sidebar-page-down></literal></entry>
-+					</row>
-+					<row>
-+						<entry><literal><sidebar-scroll-up></literal></entry>
-+						<entry><literal><sidebar-page-up></literal></entry>
-+					</row>
-+				</tbody>
-+			</tgroup>
-+		</table>
-+	</sect3>
-+</sect2>
++Variables
++---------
 +
- <sect2 id="intro-help">
- <title>Help</title>
- 
-@@ -539,7 +1156,7 @@
- <row><entry>^E or <End></entry><entry><literal><eol></literal></entry><entry>move to the end of the line</entry></row>
- <row><entry>^F or <Right></entry><entry><literal><forward-char></literal></entry><entry>move forward one char</entry></row>
- <row><entry>Esc F</entry><entry><literal><forward-word></literal></entry><entry>move forward one word</entry></row>
--<row><entry><Tab></entry><entry><literal><complete></literal></entry><entry>complete filename or alias</entry></row>
-+<row><entry><Tab></entry><entry><literal><complete></literal></entry><entry>complete filename, alias, or label</entry></row>
- <row><entry>^T</entry><entry><literal><complete-query></literal></entry><entry>complete address with query</entry></row>
- <row><entry>^K</entry><entry><literal><kill-eol></literal></entry><entry>delete to the end of the line</entry></row>
- <row><entry>Esc d</entry><entry><literal><kill-eow></literal></entry><entry>delete to the end of the word</entry></row>
-@@ -2642,7 +3259,7 @@
- 
- <command>color</command>
- <arg choice="plain">
--<option>index</option>
-+<option><emphasis>index-object</emphasis></option>
- </arg>
- <arg choice="plain">
- <replaceable class="parameter">foreground</replaceable>
-@@ -2657,7 +3274,7 @@
- <command>uncolor</command>
- <group choice="req">
- <arg choice="plain">
--<option>index</option>
-+<option><emphasis>index-object</emphasis></option>
- </arg>
- <arg choice="plain">
- <option>header</option>
-@@ -2687,8 +3304,8 @@
- <para>
- <emphasis>header</emphasis> and <emphasis>body</emphasis> match
- <emphasis>regexp</emphasis> in the header/body of a message,
--<emphasis>index</emphasis> matches <emphasis>pattern</emphasis> (see
--<xref linkend="patterns"/>) in the message index.  Note that IMAP
-+<emphasis>index-object</emphasis> can match <emphasis>pattern</emphasis>
-+(see <xref linkend="patterns"/>) in the message index. Note that IMAP
- server-side searches (=b, =B, =h) are not supported for color index
- patterns.
- </para>
-@@ -2702,10 +3319,19 @@
- <listitem><para>bold (highlighting bold patterns in the body of messages)</para></listitem>
- <listitem><para>error (error messages printed by Mutt)</para></listitem>
- <listitem><para>hdrdefault (default color of the message header in the pager)</para></listitem>
-+<listitem><para>index_author (color of the author name in the index, uses <emphasis>pattern</emphasis>)</para></listitem>
-+<listitem><para>index_collapsed (the number of messages in a collapsed thread in the index)</para></listitem>
-+<listitem><para>index_date (color of the date field in the index)</para></listitem>
-+<listitem><para>index_flags (color of the message flags in the index)</para></listitem>
-+<listitem><para>index_label (color of the message label in the index)</para></listitem>
-+<listitem><para>index_number (color of the message number in the index)</para></listitem>
-+<listitem><para>index_size (color of the message size and line number in the index)</para></listitem>
-+<listitem><para>index_subject (color of the subject in the index, uses <emphasis>pattern</emphasis>)</para></listitem>
- <listitem><para>indicator (arrow or bar used to indicate the current item in a menu)</para></listitem>
- <listitem><para>markers (the <quote>+</quote> markers at the beginning of wrapped lines in the pager)</para></listitem>
- <listitem><para>message (informational messages)</para></listitem>
- <listitem><para>normal</para></listitem>
-+<listitem><para><link linkend="progress">progress</link> (visual progress bar)</para></listitem>
- <listitem><para>prompt</para></listitem>
- <listitem><para>quoted (text matching <link linkend="quote-regexp">$quote_regexp</link> in the body of a message)</para></listitem>
- <listitem><para>quoted1, quoted2, ..., quoted<emphasis>N</emphasis> (higher levels of quoting)</para></listitem>
-@@ -2717,6 +3343,24 @@
- </itemizedlist>
- 
- <para>
-+<emphasis>index-object</emphasis> can be one of the following:
-+</para>
++    The "nested-if" patch doesn't have any config of its own. It modifies the
++    behavior of the format strings.
 +
-+<itemizedlist>
-+<listitem><para>index (default highlighting of the entire index line, uses <emphasis>pattern</emphasis>)</para></listitem>
-+<listitem><para>index_date (the date field)</para></listitem>
-+<listitem><para>index_flags (the message flags, %S %Z, uses <emphasis>pattern</emphasis>)</para></listitem>
-+<listitem><para>index_number (the message number, %C)</para></listitem>
-+<listitem><para>index_collapsed (the number of messages in a collapsed thread, %M)</para></listitem>
-+<listitem><para>index_author (the author name, %A %a %F %L %n, uses <emphasis>pattern</emphasis>)</para></listitem>
-+<listitem><para>index_subject (the subject, %s, uses <emphasis>pattern</emphasis>)</para></listitem>
-+<listitem><para>index_size (the message size, %c %l)</para></listitem>
-+<listitem><para>index_label (the message label, %y %Y)</para></listitem>
-+<listitem><para>index_tags (the transformed message tags, %g)</para></listitem>
-+<listitem><para>index_tag (an individual message tag, %G, uses <emphasis>pattern / tag name</emphasis>)</para></listitem>
-+</itemizedlist>
++See Also
++--------
 +
-+<para>
- <emphasis>foreground</emphasis> and <emphasis>background</emphasis> can
- be one of the following:
- </para>
-@@ -2833,7 +3477,7 @@
- <command>unmono</command>
- <group choice="req">
- <arg choice="plain">
--<option>index</option>
-+<option><emphasis>index-object</emphasis></option>
- </arg>
- <arg choice="plain">
- <option>header</option>
-@@ -4532,8 +5176,8 @@
- symbol (<literal>=</literal>) as a numeric prefix (like the minus
- above), it will force the string to be centered within its minimum space
- range. For example, <literal>%=14y</literal> will reserve 14 characters
--for the %y expansion — that's the X-Label: header, in <link
--linkend="index-format">$index_format</link>. If the expansion results in
-+for the %y expansion — that's the set of message keywords (formerly
-+X-Label).  If the expansion results in
- a string less than 14 characters, it will be centered in a 14-character
- space.  If the X-Label for a message were <quote>test</quote>, that
- expansion would look like
-@@ -4595,6 +5239,18 @@
- <emphasis>else_string</emphasis> will be expanded.
- </para>
- 
-+<para>
-+The conditional sequences can also be nested by using the %< and >
-+operators. The %? notation can still be used but requires quoting. For example:
-+</para>
++    * NeoMutt project
++    * cond-date patch
++    * $index_format
++    * $status_format
 +
-+<screen>
-+%<x?true&false>
-+%<x?%<y?%<z?xyz&xy>&x>&none>
-+</screen>
++Known Bugs
++----------
 +
-+<para>For more examples, see <xref linkend="nested-if"/></para>
++    Patch overwrites $<fmt> handler in $index_format
 +
- </sect2>
- 
- <sect2 id="formatstrings-filters">
-@@ -4701,6 +5357,27 @@
- 
- </sect2>
- 
-+<sect2 id="formatstrings-conditional-dates">
-+<title>Conditional Dates</title>
-+<para>
-+This patch allows the format of dates in the index to vary based on how recent
-+the message is. This is especially useful in combination with David Champion's
-+patch to allow if-else sequences to be nested.
-+</para>
++Credits
++-------
 +
-+<para>
-+For example, using
-+<literal>%<[y?%<[d?%[%H:%M]&%[%m/%d]>&%[%y.%m]></literal>
-+for the date in the <literal>$index_format</literal> will produce a display like:
-+</para>
++    * David Champion <dgc at uchicago.edu>
++    * Richard Russon <rich at flatcap.org>
 +
-+<screen>
-+   1   + 14.12 Grace Hall      (   13) Gulliver's Travels
-+   2   + 10/02 Callum Harrison (   48) Huckleberry Finn
-+   3     12:17 Rhys Lee        (   42) The Lord Of The Rings
-+</screen>
-+</sect2>
+diff --git a/README.new-mail b/README.new-mail
+new file mode 100644
+index 0000000..07dc80e
+--- /dev/null
++++ b/README.new-mail
+@@ -0,0 +1,62 @@
++new-mail Patch
++==============
 +
- </sect1>
- 
- <sect1 id="mailto-allow">
-@@ -5126,7 +5803,7 @@
- <row><entry>~V</entry><entry>cryptographically verified messages</entry></row>
- <row><entry>~x <emphasis>EXPR</emphasis></entry><entry>messages which contain <emphasis>EXPR</emphasis> in the <quote>References</quote> or <quote>In-Reply-To</quote> field</entry></row>
- <row><entry>~X [<emphasis>MIN</emphasis>]-[<emphasis>MAX</emphasis>]</entry><entry>messages with <emphasis>MIN</emphasis> to <emphasis>MAX</emphasis> attachments *)</entry></row>
--<row><entry>~y <emphasis>EXPR</emphasis></entry><entry>messages which contain <emphasis>EXPR</emphasis> in the <quote>X-Label</quote> field</entry></row>
-+<row><entry>~y <emphasis>EXPR</emphasis></entry><entry>messages which contain <emphasis>EXPR</emphasis> in their keywords</entry></row>
- <row><entry>~z [<emphasis>MIN</emphasis>]-[<emphasis>MAX</emphasis>]</entry><entry>messages with a size in the range <emphasis>MIN</emphasis> to <emphasis>MAX</emphasis> *) **)</entry></row>
- <row><entry>~=</entry><entry>duplicated messages (see <link linkend="duplicate-threads">$duplicate_threads</link>)</entry></row>
- <row><entry>~$</entry><entry>unreferenced messages (requires threaded view)</entry></row>
-@@ -5521,12 +6198,24 @@
- 
- <listitem>
- <para>
-+<link linkend="append-hook"><command>append-hook</command></link>
-+</para>
-+</listitem>
++    Execute a command upon the receipt of new mail.
 +
-+<listitem>
-+<para>
- <link linkend="charset-hook"><command>charset-hook</command></link>
- </para>
- </listitem>
- 
- <listitem>
- <para>
-+<link linkend="close-hook"><command>close-hook</command></link>
-+</para>
-+</listitem>
++Patch
++-----
 +
-+<listitem>
-+<para>
- <link linkend="crypt-hook"><command>crypt-hook</command></link>
- </para>
- </listitem>
-@@ -5569,6 +6258,12 @@
- 
- <listitem>
- <para>
-+<link linkend="open-hook"><command>open-hook</command></link>
-+</para>
-+</listitem>
++    To check if Mutt supports "new-mail", look for "patch-new-mail" in the mutt
++    version.
 +
-+<listitem>
-+<para>
- <link linkend="reply-hook"><command>reply-hook</command></link>
- </para>
- </listitem>
-@@ -5978,18 +6673,6 @@
- </para>
- 
- <para>
--The <quote>X-Label:</quote> header field can be used to further identify
--mailing lists or list subject matter (or just to annotate messages
--individually).  The <link linkend="index-format">$index_format</link>
--variable's <quote>%y</quote> and <quote>%Y</quote> expandos can be used
--to expand <quote>X-Label:</quote> fields in the index, and Mutt's
--pattern-matcher can match regular expressions to <quote>X-Label:</quote>
--fields with the <quote>~y</quote> selector.  <quote>X-Label:</quote> is
--not a standard message header field, but it can easily be inserted by
--procmail and other mail filtering agents.
--</para>
--
--<para>
- Lastly, Mutt has the ability to <link linkend="sort">sort</link> the
- mailbox into <link linkend="threads">threads</link>.  A thread is a
- group of messages which all relate to the same subject.  This is usually
-@@ -6002,6 +6685,121 @@
- 
- </sect1>
- 
-+<sect1 id="using-keywords">
-+<title>Keyword Management</title>
++    Dependencies
++    * mutt-1.6.2
 +
-+<para>
-+Mutt has supported textual labels (usually known as X-Labels after
-+the header that we use to store them) for many years.  Since we
-+initially added support for X-Lanels, however, the larger community
-+has evolved more common ways of using and managing such labels, often
-+known as <quote>keywords</quote> or <quote>tags</quote>.
-+</para>
++Introduction
++------------
 +
-+<para>
-+If you are new to Mutt or to using keywords in Mutt, you only need
-+to know that the <edit-label> binding (<literal>y</literal> by
-+default) will edit keywords, and that you can search for keywords
-+using the <literal>~y</literal> pattern, and use the <literal>%y</literal>
-+expando to display it in your <literal>$index_format</literal>.  You also
-+can sort by keyword.  Keywords that you set will be stored to the
-+<literal>X-Label:</literal> header by default.
-+</para>
++    This patch enables the new_mail_command setting, which can be used to
++    execute a custom script (e.g., a notification handler) upon receiving a new
++    mail.
 +
-+<para>
-+If you've been using X-Labels for a while, things have grown slightly.
-+Mutt still supports X-Labels much as it has since 2000, but the scope
-+of this support has expanded to support three additional header-based
-+techniques for storing keyword metadata on messages:
-+</para>
++    The command string can contain expandos, such as '%f' for the folder name.
++    For a complete list, see: $status_format.
 +
-+<variablelist>
++    For example in Linux you can use (most distributions already provide
++    notify-send):
 +
-+<varlistentry>
-+<term>X-Keywords</term>
-+<listitem>
-+<para>
-+Informal design; space-delimited keywords
-+</para>
-+</listitem>
-+</varlistentry>
++        set new_mail_command="notify-send --icon='/home/santiago/Pictures/mutt.png' 'New Email in %f' '%n new messages, %u unread.' &"
 +
-+<varlistentry>
-+<term>X-Mozilla-Keys</term>
-+<listitem>
-+<para>
-+Informal design used by Mozilla-based agents; space-delimited keywords
-+</para>
-+</listitem>
-+</varlistentry>
++    And in OS X you will need to install a command line interface for
++    Notification Center, for example: terminal-notifier https://github.com/julienXX/terminal-notifier
 +
-+<varlistentry>
-+<term>Keywords</term>
-+<listitem>
-+<para>
-+Standardized in RFC2822 (2001); comma-space-delimited keywords
-+</para>
-+</listitem>
-+</varlistentry>
++        set new_mail_command="terminal-notifier -title '%v' -subtitle 'New Mail in %f' -message '%n new messages, %u unread.' -activate 'com.apple.Terminal'"
 +
-+<varlistentry>
-+<term>X-Label</term>
-+<listitem>
-+<para>
-+Mutt-specific design; freeform text (but see <link linkend="xlabel-delimiter">$xlabel_delimiter</link>)
-+</para>
-+</listitem>
-+</varlistentry>
++Variables
++---------
 +
-+</variablelist>
++    | Name               | Type   | Default |
++    |--------------------|--------|---------|
++    | 'new_mail_command' | string | (empty) |
 +
-+<para>
-+With X-Label, mutt's only notion of a message keyword was the literal
-+string value of the X-Label header.  Under the new, integrated support,
-+each message may have a list of distinct message keywords.  When reading
-+keywords from one of the headers in the list above, the header value is
-+split on the indicated delimiter (space or comma-space) for X-Keywords:,
-+X-Mozilla-Keys:, and Keywords:.  By default, X-Label: is parsed as a
-+single keyword.  By setting $xlabel_delimiter, you can force splitting
-+of X-Label: as well.
-+</para>
++See Also
++--------
 +
-+<para>
-+Two boolean variables control how keywords are saved when writing
-+messages to a mailbox.  The default settings preserve backward
-+compatibility within mutt completely, but by changing these
-+values you can transition to more standard keyword storage. <link
-+linkend="keywords-legacy">$keywords_legacy</link>, if set, will tell
-+mutt to use only "legacy" headers -- i.e., <literal>X-Keywords:</literal>,
-+<literal>X-Mozilla-Keys</literal>, <literal>Keywords</literal>, or
-+<literal>X-Label:</literal>.  Keywords will be saved to whichever
-+header was in use by the message the keyword was read from.  If
-+<link linkend="keywords-standard">$keywords_standard</link> is
-+set, keywords will be saved without exception to the standard
-+<literal>Keywords:</literal> header.  (If both are set, both will be used;
-+if both are unset, legacy headers are used.)  Additionally, <link
-+linkend="xlabel-delimiter">$xlabel_delimiter</link> is used to format
-+the X-Label: header on saves.
-+</para>
++    * NeoMutt project
++    * folder-hook
 +
-+<para>
-+To migrate completely to the new standard,
-+unset <literal>$keywords_legacy</literal> and set
-+<literal>$keywords_standard</literal>, and set
-+<literal>$xlabel_delimiter</literal> either to what you currently use to
-+delimit keywords in X-Labels, or to <quote>, </quote> (comma
-+space).
-+</para>
++Known Bugs
++----------
 +
-+<para>
-+Note that it is common practice to insert <literal>X-Label:</literal> or
-+other keyword headers from proxmail or other mail filters.  This is
-+a useful trick for categorizing messages en masse as they are delivered
-+to your inbox, and it is fully compatible with the new keywords code.
-+</para>
++    * Notifies about spurious new email when an email is saved, see Issue #20
++          https://github.com/neomutt/neomutt/issues/20
++    * Will not notify about new e-mail if the pager is open, see Issue #19
++          https://github.com/neomutt/neomutt/issues/19
 +
-+</sect1>
++Credits
++-------
 +
- <sect1 id="new-mail">
- <title>New Mail Detection</title>
- 
-@@ -6773,6 +7571,17 @@
- </para>
- 
- <para>
-+Mutt will set the <literal>COLUMNS</literal> environment variable to
-+the width of the pager.  Some programs make use of this environment
-+variable automatically.  Others provide a command line argument that
-+can use this to set the output width:
-+</para>
++    * Yoshiki Vazquez-Baeza <yoshiki at ucsd.edu>
++    * Santiago Torres-Arias <santiago at nyu.edu>
++    * Richard Russon <rich at flatcap.org>
 +
-+<screen>
-+text/html; lynx -dump -width ${COLUMNS:-80} %s; copiousoutput
-+</screen>
+diff --git a/README.nntp b/README.nntp
+new file mode 100644
+index 0000000..7664b84
+--- /dev/null
++++ b/README.nntp
+@@ -0,0 +1,111 @@
++NNTP Patch
++==========
 +
-+<para>
- Note that when using the built-in pager, <emphasis>only</emphasis>
- entries with this flag will be considered a handler for a MIME type
- — all other entries will be ignored.
-@@ -7467,6 +8276,16 @@
- 
- </sect2>
- 
-+<sect2 id="mutt-patches">
-+<title>Mutt Patches</title>
-+<para>
-+Mutt may also be <quote>patched</quote> to support smaller features.
-+These patches should add a free-form string to the end Mutt's version string.
-+Running <literal>mutt -v</literal> might show:
-+<screen>patch-1.6.1.sidebar.20160502</screen>
-+</para>
-+</sect2>
++    Talk to a Usenet news server
 +
- <sect2 id="url-syntax">
- <title>URL Syntax</title>
- 
-@@ -8081,6 +8900,3640 @@
- 
- </sect1>
- 
-+<sect1 id="quasi-delete">
-+	<title>Quasi-Delete Patch</title>
-+	<subtitle>Mark emails that should be hidden, but not deleted</subtitle>
++Patch
++-----
 +
-+	<sect2 id="quasi-delete-patch">
-+		<title>Patch</title>
++    To check if Mutt supports "NNTP", look for "+USE_NNTP" in the mutt version.
 +
-+		<para>
-+			To check if Mutt supports <quote>Quasi-Delete</quote>, look for
-+			<quote>patch-quasi-delete</quote> in the mutt version.
-+			See: <xref linkend="mutt-patches"/>.
-+		</para>
++    Dependencies
++    * mutt-1.6.2
 +
-+		<itemizedlist>
-+			<title>Dependencies:</title>
-+			<listitem><para>mutt-1.6.1</para></listitem>
-+		</itemizedlist>
++Introduction
++------------
 +
-+		<para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
-+	</sect2>
++    Reading news via NNTP
 +
-+	<sect2 id="quasi-delete-intro">
-+		<title>Introduction</title>
++    If compiled with *--enable-nntp* option, Mutt can read news from news
++    server via NNTP. You can open a newsgroup with function
++    ''change-newsgroup'' (default: ''i''). Default news server can be obtained
++    from '$NNTPSERVER' environment variable or from '/etc/nntpserver' file.
++    Like other news readers, info about subscribed newsgroups is saved in file
++    by $newsrc variable. The variable $news_cache_dir can be used to point to a
++    directory. Mutt will create a hierarchy of subdirectories named like the
++    account and newsgroup the cache is for. Also the hierarchy is used to store
++    header cache if Mutt was compiled with header cache support.
 +
-+        <para>
-+		The <quote>quasi-delete</quote> function marks an email that should be
-+		hidden from the index, but NOT deleted.
-+        </para>
++Variables
++---------
 +
-+        <para>
-+		On its own, this patch isn't very useful.  It forms a useful part of
-+		the notmuch plugin.
-+        </para>
-+	</sect2>
++    NNTP Variables
 +
-+<!--
-+	<sect2 id="quasi-delete-variables">
-+		<title>Variables</title>
-+		<para>None</para>
-+	</sect2>
-+-->
++    | Name                    | Type    | Default                     |
++    |-------------------------|---------|-----------------------------|
++    | 'ask_follow_up'         | boolean | 'no'                        |
++    | 'ask_x_comment_to'      | boolean | 'no'                        |
++    | 'catchup_newsgroup'     | quad    | 'ask-yes'                   |
++    | 'followup_to_poster'    | quad    | 'ask-yes'                   |
++    | 'group_index_format'    | string  | '%4C %M%N %5s  %-45.45f %d' |
++    | 'inews'                 | string  | (empty)                     |
++    | 'mime_subject'          | boolean | 'yes'                       |
++    | 'newsgroups_charset'    | string  | 'utf-8'                     |
++    | 'newsrc'                | string  | '~/.newsrc'                 |
++    | 'news_cache_dir'        | string  | '~/.mutt'                   |
++    | 'news_server'           | string  | (empty)                     |
++    | 'nntp_authenticators'   | string  | (empty)                     |
++    | 'nntp_context'          | number  | '1000'                      |
++    | 'nntp_listgroup'        | boolean | 'yes'                       |
++    | 'nntp_load_description' | boolean | 'yes'                       |
++    | 'nntp_pass'             | string  | (empty)                     |
++    | 'nntp_poll'             | number  | '60'                        |
++    | 'nntp_user'             | string  | (empty)                     |
++    | 'post_moderated'        | quad    | 'ask-yes'                   |
++    | 'save_unsubscribed'     | boolean | 'no'                        |
++    | 'show_new_news'         | boolean | 'yes'                       |
++    | 'show_only_unread'      | boolean | 'no'                        |
++    | 'x_comment_to'          | boolean | 'no'                        |
 +
-+	<sect2 id="quasi-delete-functions">
-+		<title>Functions</title>
-+		<table id="table-quasi-delete-functions">
-+			<title>Quasi-Delete Functions</title>
-+			<tgroup cols="4">
-+				<thead>
-+					<row>
-+						<entry>Menus</entry>
-+						<entry>Default Key</entry>
-+						<entry>Function</entry>
-+						<entry>Description</entry>
-+					</row>
-+				</thead>
-+				<tbody>
-+					<row>
-+						<entry>index,pager</entry>
-+						<entry>(none)</entry>
-+						<entry><literal><quasi-delete></literal></entry>
-+						<entry>delete from mutt, don't touch on disk</entry>
-+					</row>
-+				</tbody>
-+			</tgroup>
-+		</table>
-+	</sect2>
++Functions
++---------
 +
-+<!--
-+	<sect2 id="quasi-delete-commands">
-+		<title>Commands</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="quasi-delete-colors">
-+		<title>Colors</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="quasi-delete-sort">
-+		<title>Sort</title>
-+		<para>None</para>
-+	</sect2>
-+-->
++    NNTP Functions
 +
-+	<sect2 id="quasi-delete-muttrc">
-+		<title>Muttrc</title>
-+<screen>
-+<emphasis role="comment"># Example Mutt config file for the 'quasi-delete' feature.
-+ 
-+# The 'quasi-delete' function marks an email that should be hidden
-+# from the index, but NOT deleted.</emphasis>
-+bind index,pager Q quasi-delete
-+ 
-+<emphasis role="comment"># vim: syntax=muttrc</emphasis>
-+</screen>
-+	</sect2>
-+
-+	<sect2 id="quasi-delete-see-also">
-+		<title>See Also</title>
-+
-+		<itemizedlist>
-+			<listitem><para><ulink url="http://www.neomutt.org/">NeoMutt Project</ulink></para></listitem>
-+			<listitem><para><link linkend="notmuch">notmuch patch</link></para></listitem>
-+		</itemizedlist>
-+	</sect2>
-+
-+	<sect2 id="quasi-delete-known-bugs">
-+		<title>Known Bugs</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="quasi-delete-credits">
-+		<title>Credits</title>
-+		<itemizedlist>
-+		<listitem><para>Karel Zak <email>kzak at redhat.com</email></para></listitem>
-+		<listitem><para>Richard Russon <email>rich at flatcap.org</email></para></listitem>
-+		</itemizedlist>
-+	</sect2>
-+</sect1>
++    | Menus                  | Default Key | Function                      | Description                                    |
++    |------------------------|-------------|-------------------------------|------------------------------------------------|
++    | browser,index          | y           | '<catchup>'                   | mark all articles in newsgroup as read         |
++    | index,pager            | i           | '<change-newsgroup>'          | open a different newsgroup                     |
++    | pager                  | X           | '<change-vfolder>'            | open a different virtual folder                |
++    | compose                | o           | '<edit-followup-to>'          | edit the Followup-To field                     |
++    | compose                | N           | '<edit-newsgroups>'           | edit the newsgroups list                       |
++    | compose                | x           | '<edit-x-comment-to>'         | edit the X-Comment-To field                    |
++    | pager                  | +           | '<entire-thread>'             | read entire thread of the current message      |
++    | attachment,index,pager | F           | '<followup-message>'          | followup to newsgroup                          |
++    | pager                  | `           | '<modify-labels>'             | modify (notmuch) tags                          |
++    | index,pager            | P           | '<post-message>'              | post message to newsgroup                      |
++    | browser                | g           | '<reload-active>'             | load list of all newsgroups from NNTP server   |
++    | browser                | s           | '<subscribe>'                 | subscribe to current mbox (IMAP/NNTP only)     |
++    | browser                | S           | '<subscribe-pattern>'         | subscribe to newsgroups matching a pattern     |
++    | browser                | Y           | '<uncatchup>'                 | mark all articles in newsgroup as unread       |
++    | browser                | u           | '<unsubscribe>'               | unsubscribe from current mbox (IMAP/NNTP only) |
++    | browser                | U           | '<unsubscribe-pattern>'       | unsubscribe from newsgroups matching a pattern |
++    | index,pager            | Alt-i       | '<change-newsgroup-readonly>' | open a different newsgroup in read only mode   |
++    | attachment,index,pager | Alt-F       | '<forward-to-group>'          | forward to newsgroup                           |
++    | index                  | (none)      | '<get-children>'              | get all children of the current message        |
++    | index                  | Alt-G       | '<get-parent>'                | get parent of the current message              |
++    | index,pager            | (none)      | '<imap-fetch-mail>'           | force retrieval of mail from IMAP server       |
++    | index,pager            | (none)      | '<imap-logout-all>'           | logout from all IMAP servers                   |
++    | pager                  | (none)      | '<modify-labels-then-hide>'   | modify labeld and then hide message            |
++    | index                  | (none)      | '<reconstruct-thread>'        | reconstruct thread containing current message  |
++    | pager                  | Alt-X       | '<vfolder-from-query>'        | generate virtual folder from query             |
++    | index                  | Ctrl-G      | '<get-message>'               | get message with Message-Id                    |
 +
-+<sect1 id="progress">
-+	<title>Progress Bar Patch</title>
-+	<subtitle>Show a visual progress bar on slow operations</subtitle>
++See Also
++--------
 +
-+	<sect2 id="progress-patch">
-+		<title>Patch</title>
++    * NeoMutt project
++    * Compile-Time Features
 +
-+		<para>
-+			To check if Mutt supports <quote>Progress Bar</quote>, look for
-+			<quote>patch-progress</quote> in the mutt version.
-+			See: <xref linkend="mutt-patches"/>.
-+		</para>
++Known Bugs
++----------
 +
-+		<itemizedlist>
-+			<title>Dependencies:</title>
-+			<listitem><para>mutt-1.6.1</para></listitem>
-+		</itemizedlist>
++    None
 +
-+		<para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
-+	</sect2>
++Credits
++-------
 +
-+	<sect2 id="progress-intro">
-+		<title>Introduction</title>
++    * Vsevolod Volkov <vvv at mutt.org.ua>
++    * Felix von Leitner <leitner at fefe.de>
++    * Richard Russon <rich at flatcap.org>
 +
-+        <para>
-+		The <quote>progress</quote> patch shows a visual progress bar on slow
-+		tasks, such as indexing a large folder over the net.
-+        </para>
-+	</sect2>
+diff --git a/README.notmuch b/README.notmuch
+new file mode 100644
+index 0000000..e7ec564
+--- /dev/null
++++ b/README.notmuch
+@@ -0,0 +1,115 @@
++Notmuch Patch
++=============
 +
-+<!--
-+	<sect2 id="progress-variables">
-+		<title>Variables</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="progress-functions">
-+		<title>Functions</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="progress-commands">
-+		<title>Commands</title>
-+		<para>None</para>
-+	</sect2>
-+-->
++    Email search engine
 +
-+	<sect2 id="progress-colors">
-+		<title>Colors</title>
-+		<table id="table-progress-colors">
-+			<title>Progress Colors</title>
-+			<tgroup cols="3">
-+				<thead>
-+					<row>
-+						<entry>Name</entry>
-+						<entry>Default Color</entry>
-+						<entry>Description</entry>
-+					</row>
-+				</thead>
-+				<tbody>
-+					<row>
-+						<entry><literal>progress</literal></entry>
-+						<entry>default</entry>
-+						<entry>Visual progress bar</entry>
-+					</row>
-+				</tbody>
-+			</tgroup>
-+		</table>
-+	</sect2>
++Patch
++-----
 +
-+<!--
-+	<sect2 id="progress-sort">
-+		<title>Sort</title>
-+		<para>None</para>
-+	</sect2>
-+-->
++    To check if Mutt supports "Notmuch", look for "+USE_NOTMUCH" in the mutt
++    version.
 +
-+	<sect2 id="progress-muttrc">
-+		<title>Muttrc</title>
-+<screen>
-+<emphasis role="comment"># Example Mutt config file for the 'progress' patch.
-+ 
-+# The 'progress' patch provides clear visual feedback for
-+# slow tasks, such as indexing a large folder over the net.
-+ 
-+# Set the color of the progress bar
-+# White text on a red background</emphasis>
-+color progress white red
-+ 
-+<emphasis role="comment"># vim: syntax=muttrc</emphasis>
-+</screen>
-+	</sect2>
-+
-+	<sect2 id="progress-see-also">
-+		<title>See Also</title>
-+
-+		<itemizedlist>
-+			<listitem><para><ulink url="http://www.neomutt.org/">NeoMutt Project</ulink></para></listitem>
-+			<listitem><para><link linkend="color">Color command</link></para></listitem>
-+		</itemizedlist>
-+	</sect2>
-+
-+	<sect2 id="progress-known-bugs">
-+		<title>Known Bugs</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="progress-credits">
-+		<title>Credits</title>
-+		<itemizedlist>
-+		<listitem><para>Rocco Rutte <email>pdmef at gmx.net</email></para></listitem>
-+		<listitem><para>Vincent Lefevre <email>vincent at vinc17.org</email></para></listitem>
-+		<listitem><para>Stefan Kuhn <email>wuodan at hispeed.ch</email></para></listitem>
-+		<listitem><para>Karel Zak <email>kzak at redhat.com</email></para></listitem>
-+		<listitem><para>Richard Russon <email>rich at flatcap.org</email></para></listitem>
-+		</itemizedlist>
-+	</sect2>
-+</sect1>
++    Dependencies
++    * mutt-1.6.2
++    * sidebar patch
++    * quasi-delete patch
++    * index-color patch
++    * Notmuch libraries
 +
-+<sect1 id="status-color">
-+	<title>Status Color Patch</title>
-+	<subtitle>Custom rules for theming the status bar</subtitle>
++Introduction
++------------
 +
-+	<sect2 id="status-color-patch">
-+		<title>Patch</title>
++Variables
++---------
 +
-+		<para>
-+			To check if Mutt supports <quote>Status Color</quote>, look for
-+			<quote>patch-status-color</quote> in the mutt version.
-+			See: <xref linkend="mutt-patches"/>.
-+		</para>
++    Notmuch Variables
++
++    | Name                | Type    | Default                                                           |
++    |---------------------|---------|-------------------------------------------------------------------|
++    | 'nm_db_limit'       | number  | '0'                                                               |
++    | 'nm_default_uri'    | string  | (empty)                                                           |
++    | 'nm_exclude_tags'   | string  | (empty)                                                           |
++    | 'nm_hidden_tags'    | string  | 'unread,draft,flagged,passed,replied,attachment,signed,encrypted' |
++    | 'nm_open_timeout'   | number  | '5'                                                               |
++    | 'nm_query_type'     | string  | 'messages'                                                        |
++    | 'nm_record'         | boolean | 'no'                                                              |
++    | 'nm_record_tags'    | string  | (empty)                                                           |
++    | 'nm_unread_tag'     | string  | 'unread'                                                          |
++    | 'vfolder_format'    | string  | '%6n(%6N) %f'                                                     |
++    | 'virtual_spoolfile' | boolean | 'no'                                                              |
 +
-+		<itemizedlist>
-+			<title>Dependencies:</title>
-+			<listitem><para>mutt-1.6.1</para></listitem>
-+		</itemizedlist>
++Functions
++---------
 +
-+		<para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
-+	</sect2>
++    Notmuch Functions
 +
-+	<sect2 id="status-color-intro">
-+		<title>Introduction</title>
++    | Menus       | Default Key | Function                    | Description                                    |
++    |-------------|-------------|-----------------------------|------------------------------------------------|
++    | index,pager | X           | '<change-vfolder>'          | open a different virtual folder                |
++    | index,pager | +           | '<entire-thread>'           | read entire thread of the current message      |
++    | index,pager | `           | '<modify-labels>'           | modify (notmuch) tags                          |
++    | index,pager | (none)      | '<modify-labels-then-hide>' | modify labels and then hide message            |
++    | index,pager | (none)      | '<sidebar-toggle-virtual>'  | toggle between mailboxes and virtual mailboxes |
++    | index,pager | Alt-X       | '<vfolder-from-query>'      | generate virtual folder from query             |
 +
-+        <para>
-+		The <quote>status-color</quote> patch allows you to theme different
-+		parts of the status bar (also when it's used by the index).
-+        </para>
++Commands
++--------
 +
-+        <para>
-+		Unlike normal color commands, <literal>color status</literal> can now
-+		take up to 2 extra parameters (regex, num).
-+        </para>
-+	</sect2>
++    Notmuch Commands
 +
-+<!--
-+	<sect2 id="status-color-variables">
-+		<title>Variables</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="status-color-functions">
-+		<title>Functions</title>
-+		<para>None</para>
-+	</sect2>
-+-->
++        virtual-mailboxes description notmuch-URI { description notmuch-URI ...}
++        tag-transforms tag transformed-string { tag transformed-string ...}
++        tag-formats tag format-string { tag format-string ...}
 +
-+	<sect2 id="status-color-commands">
-+		<title>Commands</title>
-+		<cmdsynopsis>
-+			<command>color</command>
-+			<arg choice="plain">
-+				<option>status</option>
-+			</arg>
-+			<arg choice="plain">
-+				<replaceable class="parameter">foreground</replaceable>
-+			</arg>
-+			<arg choice="plain">
-+				<replaceable class="parameter">background</replaceable>
-+			</arg>
-+			<group choice="opt">
-+				<arg choice="plain">
-+					<replaceable class="parameter">regex</replaceable>
-+				</arg>
-+				<group choice="opt">
-+					<arg choice="plain">
-+						<replaceable class="parameter">num</replaceable>
-+					</arg>
-+				</group>
-+			</group>
-+		</cmdsynopsis>
-+
-+		<para>
-+			With zero parameters, Mutt will set the default color for the entire
-+			status bar.
-+		</para>
-+
-+		<para>
-+			With one parameter, Mutt will only color the parts matching the
-+			regex.
-+		</para>
-+
-+		<para>
-+			With two parameters, Mutt will only color the num'th sub-match of
-+			the regex.
-+		</para>
-+	</sect2>
-+
-+	<sect2 id="status-color-colors">
-+		<title>Colors</title>
-+
-+		<table id="table-status-color-colors">
-+			<title>Status Colors</title>
-+			<tgroup cols="3">
-+				<thead>
-+					<row>
-+						<entry>Name</entry>
-+						<entry>Default Color</entry>
-+						<entry>Description</entry>
-+					</row>
-+				</thead>
-+				<tbody>
-+					<row>
-+						<entry>status</entry>
-+						<entry><literal>reverse</literal></entry>
-+						<entry>Status bar</entry>
-+					</row>
-+				</tbody>
-+			</tgroup>
-+		</table>
-+	</sect2>
++Colors
++------
 +
-+<!--
-+	<sect2 id="status-color-sort">
-+		<title>Sort</title>
-+		<para>None</para>
-+	</sect2>
-+-->
++    Adds these to index-color patch:
 +
-+	<sect2 id="status-color-muttrc">
-+		<title>Muttrc</title>
-+<screen>
-+<emphasis role="comment"># Example Mutt config file for the 'status-color' patch.
-+ 
-+# The 'status-color' patch allows you to theme different parts of
-+# the status bar (also when it's used by the index).
-+ 
-+# For the examples below, set some defaults</emphasis>
-+set status_format='-%r-Mutt: %f [Msgs:%?M?%M/?%m%?n? New:%n?%?o? Old:%o?%?d? Del:%d?%?F? Flag:%F?%?t? Tag:%t?%?p? Post:%p?%?b? Inc:%b?%?l? %l?]---(%s/%S)-%>-(%P)---'
-+set index_format='%4C %Z %{%b %d} %-15.15L (%?l?%4l&%4c?) %s'
-+set sort=threads
-+set sort_aux=last-date-received
-+ 
-+<emphasis role="comment"># 'status color' can take up to 2 extra parameters
-+ 
-+# color status foreground background [ regex [ num ]]
-+ 
-+# 0 extra parameters
-+# Set the default color for the entire status line</emphasis>
-+color status blue white
-+ 
-+<emphasis role="comment"># 1 extra parameter
-+# Set the color for a matching pattern
-+# color status foreground background regexp
-+ 
-+# Highlight New, Deleted, or Flagged emails</emphasis>
-+color status brightred white '(New|Del|Flag):[0-9]+'
-+ 
-+<emphasis role="comment"># Highlight mailbox ordering if it's different from the default
-+# First, highlight anything (*/*)</emphasis>
-+color status brightred default '\([^)]+/[^)]+\)'
-+ 
-+<emphasis role="comment"># Then override the color for one specific case</emphasis>
-+color status default   default '\(threads/last-date-received\)'
-+ 
-+<emphasis role="comment"># 2 extra parameters
-+# Set the color for the nth submatch of a pattern
-+# color status foreground background regexp num
-+ 
-+# Highlight the contents of the []s but not the [] themselves</emphasis>
-+color status red default '\[([^]]+)\]' 1
-+ 
-+<emphasis role="comment"># The '1' refers to the first regex submatch, which is the inner
-+# part in ()s
-+ 
-+# Highlight the mailbox</emphasis>
-+color status brightwhite default 'Mutt: ([^ ]+)' 1
-+ 
-+<emphasis role="comment"># Search for 'Mutt: ' but only highlight what comes after it
-+ 
-+# vim: syntax=muttrc</emphasis>
-+</screen>
-+	</sect2>
-+
-+	<sect2 id="status-color-see-also">
-+		<title>See Also</title>
-+
-+		<itemizedlist>
-+			<listitem><para><ulink url="http://www.neomutt.org/">NeoMutt Project</ulink></para></listitem>
-+			<listitem><para><link linkend="compile-time-features">Compile-Time Features</link></para></listitem>
-+			<listitem><para><link linkend="regexp">Regular Expressions</link></para></listitem>
-+			<listitem><para><link linkend="patterns">Patterns</link></para></listitem>
-+			<listitem><para><link linkend="index-color">index-color patch</link></para></listitem>
-+			<listitem><para><link linkend="color">Color command</link></para></listitem>
-+		</itemizedlist>
-+	</sect2>
-+
-+	<sect2 id="status-color-known-bugs">
-+		<title>Known Bugs</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="status-color-credits">
-+		<title>Credits</title>
-+		<itemizedlist>
-+		<listitem><para>David Sterba <email>dsterba at suse.cz</email></para></listitem>
-+		<listitem><para>Thomas Glanzmann <email>thomas at glanzmann.de</email></para></listitem>
-+		<listitem><para>Kirill A. Shutemov <email>kirill at shutemov.name</email></para></listitem>
-+		<listitem><para>Richard Russon <email>rich at flatcap.org</email></para></listitem>
-+		</itemizedlist>
-+	</sect2>
-+</sect1>
++    Index Colors
 +
-+<sect1 id="index-color">
-+	<title>Index Color Patch</title>
-+	<subtitle>Custom rules for theming the email index</subtitle>
++    | Object       | Pattern | Highlights                                   |
++    |--------------|---------|----------------------------------------------|
++    | 'index_tag'  | yes     | an individual message tag, %G, uses tag name |
++    | 'index_tags' | no      | the transformed message tags, %g             |
 +
-+	<sect2 id="index-color-patch">
-+		<title>Patch</title>
 +
-+		<para>
-+			To check if Mutt supports <quote>Index Color</quote>, look for
-+			<quote>patch-index-color</quote> in the mutt version.
-+			See: <xref linkend="mutt-patches"/>.
-+		</para>
++See Also
++--------
 +
-+		<itemizedlist>
-+			<title>Dependencies:</title>
-+			<listitem><para>mutt-1.6.1</para></listitem>
-+			<listitem><para><link linkend="status-color">status-color patch</link></para></listitem>
-+		</itemizedlist>
++    * NeoMutt project
++    * Compile-Time Features
 +
-+		<para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
-+	</sect2>
++Known Bugs
++----------
 +
-+	<sect2 id="index-color-intro">
-+		<title>Introduction</title>
++    None
 +
-+        <para>
-+		The <quote>index-color</quote> patch allows you to specify colors for
-+		individual parts of the email index. e.g. Subject, Author, Flags.
-+        </para>
++Credits
++-------
 +
-+        <para>
-+		First choose which part of the index you'd like to color.
-+		Then, if needed, pick a pattern to match.
-+        </para>
++    * Karel Zak <kzak at redhat.com>
++    * Chris Mason <clm at fb.com>
++    * Christoph Rissner <cri at visotech.at>
++    * David Riebenbauer <davrieb at liegesta.at>
++    * David Sterba <dsterba at suse.cz>
++    * David Wilson <dw at botanicus.net>
++    * Don Zickus <dzickus at redhat.com>
++    * Eric Davis <edavis at insanum.com>
++    * Jan Synacek <jsynacek at redhat.com>
++    * Jeremiah C. Foster <jeremiah at jeremiahfoster.com>
++    * Josh Poimboeuf <jpoimboe at redhat.com>
++    * Kirill A. Shutemov <kirill at shutemov.name>
++    * Luke Macken <lmacken at redhat.com>
++    * Mantas Mikulėnas <grawity at gmail.com>
++    * Patrick Brisbin <pbrisbin at gmail.com>
++    * Philippe Le Brouster <plb at nebkha.net>
++    * Raghavendra D Prabhu <rprabhu at wnohang.net>
++    * Sami Farin <hvtaifwkbgefbaei at gmail.com>
++    * Stefan Assmann <sassmann at kpanic.de>
++    * Stefan Kuhn <p_regius at gmx.ch>
++    * Tim Stoakes <tim at stoakes.net>
++    * Vladimir Marek <Vladimir.Marek at oracle.com>
++    * Víctor Manuel Jáquez Leal <vjaquez at igalia.com>
++    * Richard Russon <rich at flatcap.org>
 +
-+		<para>
-+		Note: The pattern does not have to refer to the object you wish to
-+		color.  e.g.
-+		</para>
+diff --git a/README.progress b/README.progress
+new file mode 100644
+index 0000000..ff12be2
+--- /dev/null
++++ b/README.progress
+@@ -0,0 +1,49 @@
++Progress Bar Patch
++==================
 +
-+<screen>
-+color index_author red default "~smutt"
-+</screen>
++    Show a visual progress bar on slow operations
 +
-+        <para>
-+		The author appears red when the subject (~s) contains <quote>mutt</quote>.
-+        </para>
-+	</sect2>
++Patch
++-----
 +
-+<!--
-+	<sect2 id="index-color-variables">
-+		<title>Variables</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="index-color-functions">
-+		<title>Functions</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="index-color-commands">
-+		<title>Commands</title>
-+		<para>None</para>
-+	</sect2>
-+-->
++    To check if Mutt supports "Progress Bar", look for "patch-progress" in the
++    mutt version.
 +
-+	<sect2 id="index-color-colors">
-+		<title>Colors</title>
++    Dependencies
++    * mutt-1.6.2
 +
-+        <para>
-+		All the colors default to <literal>default</literal>, i.e. unset.
-+        </para>
++Introduction
++------------
 +
-+        <para>
-+		The index objects can be themed using the <literal>color</literal> command.
-+		Some objects require a pattern.
-+        </para>
++    The "progress" patch shows a visual progress bar on slow tasks, such as
++    indexing a large folder over the net.
 +
-+<screen>
-+color index-object foreground background
-+color index-object foreground background pattern
-+</screen>
++Colors
++------
 +
-+		<table id="table-index-color-colors">
-+			<title>Index Colors</title>
-+			<tgroup cols="3">
-+				<thead>
-+					<row>
-+						<entry>Object</entry>
-+						<entry>Pattern</entry>
-+						<entry>Highlights</entry>
-+					</row>
-+				</thead>
-+				<tbody>
-+					<row>
-+						<entry><literal>index</literal></entry>
-+						<entry>yes</entry>
-+						<entry>Entire index line</entry>
-+					</row>
-+					<row>
-+						<entry><literal>index_author</literal></entry>
-+						<entry>yes</entry>
-+						<entry>Author name, %A %a %F %L %n</entry>
-+					</row>
-+					<row>
-+						<entry><literal>index_collapsed</literal></entry>
-+						<entry>no</entry>
-+						<entry>Number of messages in a collapsed thread, %M</entry>
-+					</row>
-+					<row>
-+						<entry><literal>index_date</literal></entry>
-+						<entry>no</entry>
-+						<entry>Date field</entry>
-+					</row>
-+					<row>
-+						<entry><literal>index_flags</literal></entry>
-+						<entry>yes</entry>
-+						<entry>Message flags, %S %Z</entry>
-+					</row>
-+					<row>
-+						<entry><literal>index_label</literal></entry>
-+						<entry>no</entry>
-+						<entry>Message label, %y %Y</entry>
-+					</row>
-+					<row>
-+						<entry><literal>index_number</literal></entry>
-+						<entry>no</entry>
-+						<entry>Message number, %C</entry>
-+					</row>
-+					<row>
-+						<entry><literal>index_size</literal></entry>
-+						<entry>no</entry>
-+						<entry>Message size, %c %l</entry>
-+					</row>
-+					<row>
-+						<entry><literal>index_subject</literal></entry>
-+						<entry>yes</entry>
-+						<entry>Subject, %s</entry>
-+					</row>
-+				</tbody>
-+			</tgroup>
-+		</table>
-+	</sect2>
++    Progress Colors
 +
-+<!--
-+	<sect2 id="index-color-sort">
-+		<title>Sort</title>
-+		<para>None</para>
-+	</sect2>
-+-->
++    | Name       | Default Color | Description         |
++    |------------|---------------|---------------------|
++    | 'progress' | default       | Visual progress bar |
 +
-+	<sect2 id="index-color-muttrc">
-+		<title>Muttrc</title>
-+<screen>
-+<emphasis role="comment"># Example Mutt config file for the 'index-color' feature.
-+ 
-+# Entire index line</emphasis>
-+color index white black '.*'
-+ 
-+<emphasis role="comment"># Author name, %A %a %F %L %n
-+ 
-+# Give the author column a dark grey background</emphasis>
-+color index_author default color234 '.*'
-+ 
-+<emphasis role="comment"># Highlight a particular from (~f)</emphasis>
-+color index_author brightyellow color234 '~fRay Charles'
-+ 
-+<emphasis role="comment"># Message flags, %S %Z
-+# Highlight the flags for flagged (~F) emails</emphasis>
-+color index_flags default red '~F'
-+ 
-+<emphasis role="comment"># Subject, %s
-+# Look for a particular subject (~s)</emphasis>
-+color index_subject brightcyan default '~s\(closes #[0-9]+\)'
-+ 
-+<emphasis role="comment"># Number of messages in a collapsed thread, %M</emphasis>
-+color index_collapsed default brightblue
-+ 
-+<emphasis role="comment"># Date field</emphasis>
-+color index_date green default
-+ 
-+<emphasis role="comment"># Message label, %y %Y</emphasis>
-+color index_label default brightgreen
-+ 
-+<emphasis role="comment"># Message number, %C</emphasis>
-+color index_number red default
-+ 
-+<emphasis role="comment"># Message size, %c %l</emphasis>
-+color index_size cyan default
-+ 
-+<emphasis role="comment"># vim: syntax=muttrc</emphasis>
-+</screen>
-+	</sect2>
-+
-+	<sect2 id="index-color-see-also">
-+		<title>See Also</title>
-+
-+		<itemizedlist>
-+			<listitem><para><ulink url="http://www.neomutt.org/">NeoMutt Project</ulink></para></listitem>
-+			<listitem><para><link linkend="regexp">Regular Expressions</link></para></listitem>
-+			<listitem><para><link linkend="patterns">Patterns</link></para></listitem>
-+			<listitem><para><link linkend="index-format">$index_format</link></para></listitem>
-+			<listitem><para><link linkend="color">Color command</link></para></listitem>
-+			<listitem><para><link linkend="status-color">Status-Color patch</link></para></listitem>
-+			<listitem><para><link linkend="keywords">Keywords patch</link></para></listitem>
-+		</itemizedlist>
-+	</sect2>
-+
-+	<sect2 id="index-color-known-bugs">
-+		<title>Known Bugs</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="index-color-credits">
-+		<title>Credits</title>
-+		<itemizedlist>
-+		<listitem><para>Christian Aichinger <email>Greek0 at gmx.net</email></para></listitem>
-+		<listitem><para>Christoph <quote>Myon</quote> Berg <email>myon at debian.org</email></para></listitem>
-+		<listitem><para>Elimar Riesebieter <email>riesebie at lxtec.de</email></para></listitem>
-+		<listitem><para>Eric Davis <email>edavis at insanum.com</email></para></listitem>
-+		<listitem><para>Vladimir Marek <email>Vladimir.Marek at oracle.com</email></para></listitem>
-+		<listitem><para>Richard Russon <email>rich at flatcap.org</email></para></listitem>
-+		</itemizedlist>
-+	</sect2>
-+</sect1>
++See Also
++--------
 +
-+<sect1 id="nested-if">
-+	<title>Nested If Patch</title>
-+	<subtitle>Allow complex nested conditions in format strings</subtitle>
++    * NeoMutt project
++    * Color command
 +
-+	<sect2 id="nested-if-patch">
-+		<title>Patch</title>
++Known Bugs
++----------
 +
-+		<para>
-+			To check if Mutt supports <quote>Nested If</quote>, look for
-+			<quote>patch-nested-if</quote> in the mutt version.
-+			See: <xref linkend="mutt-patches"/>.
-+		</para>
++    None
 +
-+		<itemizedlist>
-+			<title>Dependencies:</title>
-+			<listitem><para>mutt-1.6.1</para></listitem>
-+		</itemizedlist>
++Credits
++-------
 +
-+		<para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
-+	</sect2>
++    * Rocco Rutte <pdmef at gmx.net>
++    * Vincent Lefevre <vincent at vinc17.org>
++    * Stefan Kuhn <wuodan at hispeed.ch>
++    * Karel Zak <kzak at redhat.com>
++    * Richard Russon <rich at flatcap.org>
 +
-+	<sect2 id="nested-if-intro">
-+		<title>Introduction</title>
+diff --git a/README.quasi-delete b/README.quasi-delete
+new file mode 100644
+index 0000000..42a42b2
+--- /dev/null
++++ b/README.quasi-delete
+@@ -0,0 +1,49 @@
++Quasi-Delete Patch
++==================
 +
-+		<para>
-+			Mutt's format strings can contain embedded if-then-else conditions.
-+			They are of the form:
-+		</para>
++    Mark emails that should be hidden, but not deleted
 +
-+<screen>
-+%?VAR?TRUE&FALSE?
-+</screen>
++Patch
++-----
 +
-+		<para>
-+			If the variable <quote>VAR</quote> has a value greater than zero,
-+			print the <quote>TRUE</quote> string, otherwise print the
-+			<quote>FALSE</quote> string.
-+		</para>
-+
-+		<para>
-+			e.g.  <literal>%?S?Size: %S&Empty?</literal>
-+		</para>
-+
-+		<para>Which can be read as:</para>
-+
-+		<literallayout>
-+		    if (%S > 0) {
-+		        print "Size: %S"
-+		    } else {
-+		        print "Empty"
-+		    }
-+		</literallayout>
-+
-+		<para>
-+			These conditions are useful, but in Mutt they cannot be nested
-+			within one another.  This patch uses the notation
-+			<literal>%<VAR?TRUE&FALSE></literal> and allows them to be nested.
-+		</para>
-+
-+		<para>
-+			The <literal>%<...></literal> notation was used to format the
-+			current local time.  but that's not really very useful since mutt
-+			has no means of refreshing the screen periodically.
-+		</para>
-+
-+		<para>
-+			A simple nested condition might be:
-+			(Some whitespace has been introduced for clarity)
-+		</para>
-+
-+		<literallayout>
-+		    %<x? %<y? XY & X > & %<y? Y & NONE > >  Conditions
-+		         %<y? XY & X >                      x>0
-+		              XY                            x>0,y>0
-+		                   X                        x>0,y=0
-+		</literallayout>
-+
-+		<literallayout>
-+		    %<x? %<y? XY & X > & %<y? Y & NONE > >  Conditions
-+		                         %<y? Y & NONE >    x=0
-+		                              Y             x=0,y>0
-+		                                  NONE      x=0,y=0
-+		</literallayout>
-+
-+		<para>Equivalent to:</para>
-+
-+		<literallayout>
-+		    if (x > 0) {
-+		        if (y > 0) {
-+		            print 'XY'
-+		        } else {
-+		            print 'X'
-+		        }
-+		    } else {
-+		        if (y > 0) {
-+		            print 'Y'
-+		        } else {
-+		            print 'NONE'
-+		        }
-+		    }
-+		</literallayout>
-+
-+		<para>Examples:</para>
++    To check if Mutt supports "Quasi-Delete", look for "patch-quasi-delete" in
++    the mutt version.
 +
-+<screen>
-+set index_format='%4C %Z %{%b %d} %-25.25n %s%> %<M?%M Msgs &%<l?%l Lines&%c Bytes>>'
-+</screen>
++    Dependencies
++    * mutt-1.6.2
 +
-+		<literallayout>
-+		    if a thread is folded
-+		        display the number of messages (%M)
-+		    else if we know how many lines in the message
-+		        display lines in message (%l)
-+		    else
-+		        display the size of the message in bytes (%c)
-+		</literallayout>
++Introduction
++------------
 +
-+<screen>
-+set index_format='%4C %Z %{%b %d} %-25.25n %<M?[%M] %s&%s%* %<l?%l&%c>>'
-+</screen>
++    The "quasi-delete" function marks an email that should be hidden from the
++    index, but NOT deleted.
 +
-+		<literallayout>
-+		    if a thread is folded
-+		        display the number of messages (%M)
-+		        display the subject (%s)
-+		    else if we know how many lines in the message
-+		        display lines in message (%l)
-+		    else
-+		        display the size of the message in bytes (%c)
-+		</literallayout>
++    On its own, this patch isn't very useful. It forms a useful part of the
++    notmuch plugin.
 +
-+	</sect2>
++Functions
++---------
 +
-+	<sect2 id="nested-if-variables">
-+		<title>Variables</title>
-+		The <quote>nested-if</quote> patch doesn't have any config of its own.
-+		It modifies the behavior of the format strings.
-+	</sect2>
++    Quasi-Delete Functions
 +
-+<!--
-+	<sect2 id="nested-if-functions">
-+		<title>Functions</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="nested-if-commands">
-+		<title>Commands</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="nested-if-colors">
-+		<title>Colors</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="nested-if-sort">
-+		<title>Sort</title>
-+		<para>None</para>
-+	</sect2>
-+-->
++    | Menus       | Default Key | Function         | Description                           |
++    |-------------|-------------|------------------|---------------------------------------|
++    | index,pager | (none)      | '<quasi-delete>' | delete from mutt, don't touch on disk |
 +
-+	<sect2 id="nested-if-muttrc">
-+		<title>Muttrc</title>
-+<screen>
-+<emphasis role="comment"># Example Mutt config file for the 'nested-if' feature.
-+ 
-+# This patch uses the format: '%<VAR?TRUE&FALSE>' for conditional
-+# format strings that can be nested.
-+ 
-+# Example 1
-+# if a thread is folded
-+#       display the number of messages (%M)
-+# else if we know how many lines in the message
-+#       display lines in message (%l)
-+# else display the size of the message in bytes (%c)</emphasis>
-+set index_format='%4C %Z %{%b %d} %-25.25n %s%> %<M?%M Msgs &%<l?%l Lines&%c Bytes>>'
-+ 
-+<emphasis role="comment"># Example 2
-+# if a thread is folded
-+#       display the number of messages (%M)
-+#       display the subject (%s)
-+# else if we know how many lines in the message
-+#       display lines in message (%l)
-+# else
-+#       display the size of the message in bytes (%c)</emphasis>
-+set index_format='%4C %Z %{%b %d} %-25.25n %<M?[%M] %s&%s%* %<l?%l&%c>>'
-+ 
-+<emphasis role="comment"># vim: syntax=muttrc</emphasis>
-+</screen>
-+	</sect2>
-+
-+	<sect2 id="nested-if-see-also">
-+		<title>See Also</title>
-+
-+		<itemizedlist>
-+			<listitem><para><ulink url="http://www.neomutt.org/">NeoMutt Project</ulink></para></listitem>
-+			<listitem><para><link linkend="cond-date">cond-date patch</link></para></listitem>
-+			<listitem><para><link linkend="index-format">$index_format</link></para></listitem>
-+			<listitem><para><link linkend="status-format">$status_format</link></para></listitem>
-+		</itemizedlist>
-+	</sect2>
-+
-+	<sect2 id="nested-if-known-bugs">
-+		<title>Known Bugs</title>
-+		Patch overwrites $<fmt> handler in <literal>$index_format</literal>
-+	</sect2>
-+
-+	<sect2 id="nested-if-credits">
-+		<title>Credits</title>
-+		<itemizedlist>
-+		<listitem><para>David Champion <email>dgc at uchicago.edu</email></para></listitem>
-+		<listitem><para>Richard Russon <email>rich at flatcap.org</email></para></listitem>
-+		</itemizedlist>
-+	</sect2>
-+</sect1>
++See Also
++--------
 +
-+<sect1 id="cond-date">
-+	<title>Conditional Dates Patch</title>
-+	<subtitle>Use rules to choose date format</subtitle>
-+
-+	<sect2 id="cond-date-patch">
-+		<title>Patch</title>
-+
-+		<para>
-+			To check if Mutt supports <quote>Conditional Dates</quote>, look for
-+			<quote>patch-cond-date</quote> in the mutt version.
-+			See: <xref linkend="mutt-patches"/>.
-+		</para>
-+
-+		<itemizedlist>
-+			<title>Dependencies:</title>
-+			<listitem><para>mutt-1.6.1</para></listitem>
-+			<listitem><para><link linkend="nested-if">nested-if patch</link></para></listitem>
-+		</itemizedlist>
-+
-+		<para>
-+			This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.
-+		</para>
-+	</sect2>
-+
-+	<sect2 id="cond-date-intro">
-+		<title>Introduction</title>
-+
-+		<para>
-+		The <quote>cond-date</quote> patch allows you to construct
-+		<link linkend="index-format">$index_format</link> expressions based on the age of the email.
-+		</para>
-+
-+		<para>
-+		Mutt's default <literal>$index_format</literal> displays email dates in the
-+		form: abbreviated-month day-of-month — <quote>Jan 14</quote>.
-+		</para>
-+
-+		<para>
-+		The format is configurable but only per-mailbox.  This patch allows you
-+		to configure the display depending on the age of the email.
-+		</para>
-+
-+		<table id="table-cond-date-scheme">
-+			<title>Potential Formatting Scheme</title>
-+			<tgroup cols="3">
-+				<thead>
-+					<row>
-+						<entry>Email Sent</entry>
-+						<entry>Format</entry>
-+						<entry>Example</entry>
-+					</row>
-+				</thead>
-+				<tbody>
-+					<row>
-+						<entry>Today</entry>
-+						<entry><literal>%H:%M</literal></entry>
-+						<entry>13:23</entry>
-+					</row>
-+					<row>
-+						<entry>This Month</entry>
-+						<entry><literal>%a %d</literal></entry>
-+						<entry>Thu 17</entry>
-+					</row>
-+					<row>
-+						<entry>This Year</entry>
-+						<entry><literal>%b %d</literal></entry>
-+						<entry>Dec 10</entry>
-+					</row>
-+					<row>
-+						<entry>Older than 1 Year</entry>
-+						<entry><literal>%m/%y</literal></entry>
-+						<entry>06/14</entry>
-+					</row>
-+				</tbody>
-+			</tgroup>
-+		</table>
-+
-+		<para>
-+        For an explanation of the date formatting strings, see
-+        <literal>strftime(3).</literal>
-+		</para>
++    * NeoMutt project
++    * notmuch patch
 +
-+		<para>
-+        By carefully picking your formats, the dates can remain
-+        unambiguous and compact.
-+		</para>
-+
-+		<para>
-+		Mutt's conditional format strings have the form:
-+		(whitespace introduced for clarity)
-+		</para>
-+
-+		<screen>%? TEST ? TRUE & FALSE ?</screen>
-+
-+		<para>
-+		The examples below use the test <quote>%[</quote> — the date
-+		of the message in the local timezone.  They will also work with
-+		<quote>%(</quote> — the local time that the message arrived.
-+		</para>
-+
-+		<para>
-+		The date tests are of the form:
-+		</para>
-+
-+		<screen>%[nX? TRUE & FALSE ?</screen>
-+
-+		<itemizedlist>
-+		<listitem><para><quote>n</quote> is an optional count (defaults to 1 if missing)</para></listitem>
-+		<listitem><para><quote>X</quote> is the time period</para></listitem>
-+		</itemizedlist>
-+
-+		<table id="table-cond-date-format-codes">
-+			<title>Date Formatting Codes</title>
-+			<tgroup cols="2">
-+				<thead>
-+					<row>
-+						<entry>Letter</entry>
-+						<entry>Time Period</entry>
-+					</row>
-+				</thead>
-+				<tbody>
-+					<row>
-+						<entry>y</entry>
-+						<entry>Years</entry>
-+					</row>
-+					<row>
-+						<entry>m</entry>
-+						<entry>Months</entry>
-+					</row>
-+					<row>
-+						<entry>w</entry>
-+						<entry>Weeks</entry>
-+					</row>
-+					<row>
-+						<entry>d</entry>
-+						<entry>Days</entry>
-+					</row>
-+					<row>
-+						<entry>H</entry>
-+						<entry>Hours</entry>
-+					</row>
-+					<row>
-+						<entry>M</entry>
-+						<entry>Minutes</entry>
-+					</row>
-+				</tbody>
-+			</tgroup>
-+		</table>
-+
-+		<table id="table-cond-date-example-tests">
-+			<title>Example Date Tests</title>
-+			<tgroup cols="2">
-+				<thead>
-+					<row>
-+						<entry>Test</entry>
-+						<entry>Meaning</entry>
-+					</row>
-+				</thead>
-+				<tbody>
-+					<row>
-+						<entry><literal>%[y</literal></entry>
-+						<entry>This year</entry>
-+					</row>
-+					<row>
-+						<entry><literal>%[1y</literal></entry>
-+						<entry>This year</entry>
-+					</row>
-+					<row>
-+						<entry><literal>%[6m</literal></entry>
-+						<entry>In the last 6 months</entry>
-+					</row>
-+					<row>
-+						<entry><literal>%[w</literal></entry>
-+						<entry>This week</entry>
-+					</row>
-+					<row>
-+						<entry><literal>%[d</literal></entry>
-+						<entry>Today</entry>
-+					</row>
-+					<row>
-+						<entry><literal>%[4H</literal></entry>
-+						<entry>In the last 4 hours</entry>
-+					</row>
-+				</tbody>
-+			</tgroup>
-+		</table>
-+
-+		<sect3 id="cond-date-example1">
-+			<title>Example 1</title>
-+
-+			<para>We start with a one-condition test.</para>
-+
-+			<table id="table-cond-date-example1">
-+				<title>Example 1</title>
-+				<tgroup cols="4">
-+					<thead>
-+						<row>
-+							<entry>Test</entry>
-+							<entry>Date Range</entry>
-+							<entry>Format String</entry>
-+							<entry>Example</entry>
-+						</row>
-+					</thead>
-+					<tbody>
-+						<row>
-+							<entry><literal>%[1m</literal></entry>
-+							<entry>This month</entry>
-+							<entry><literal>%[%b %d]</literal></entry>
-+							<entry>Dec 10</entry>
-+						</row>
-+						<row>
-+							<entry></entry>
-+							<entry>Older</entry>
-+							<entry><literal>%[%Y-%m-%d]</literal></entry>
-+							<entry>2015-04-23</entry>
-+						</row>
-+					</tbody>
-+				</tgroup>
-+			</table>
-+
-+			<para>The $index_format string would contain:</para>
-+<screen>
-+%?[1m?%[%b %d]&%[%Y-%m-%d]?
-+</screen>
-+ 
-+			<para>
-+				Reparsed a little, for clarity, you can see the
-+				test condition and the two format strings.
-+			</para>
++Known Bugs
++----------
 +
-+<screen>
-+%?[1m?        &           ?
-+      %[%b %d] %[%Y-%m-%d]
-+</screen>
++    None
 +
-+		</sect3>
-+
-+		<sect3 id="cond-date-example2">
-+			<title>Example 2</title>
-+
-+			<para>
-+			This example contains three test conditions and four date formats.
-+			</para>
-+
-+			<table id="table-cond-date-example2">
-+				<title>Example 2</title>
-+				<tgroup cols="4">
-+					<thead>
-+						<row>
-+							<entry>Test</entry>
-+							<entry>Date Range</entry>
-+							<entry>Format String</entry>
-+							<entry>Example</entry>
-+						</row>
-+					</thead>
-+					<tbody>
-+						<row>
-+							<entry><literal>%[d</literal></entry>
-+							<entry>Today</entry>
-+							<entry><literal>%[%H:%M ] </literal></entry>
-+							<entry>12:34</entry>
-+						</row>
-+						<row>
-+							<entry><literal>%[m</literal></entry>
-+							<entry>This month</entry>
-+							<entry><literal>%[%a %d]</literal></entry>
-+							<entry>Thu 12</entry>
-+						</row>
-+						<row>
-+							<entry><literal>%[y</literal></entry>
-+							<entry>This year</entry>
-+							<entry><literal>%[%b %d]</literal></entry>
-+							<entry>Dec 10</entry>
-+						</row>
-+						<row>
-+							<entry></entry>
-+							<entry>Older</entry>
-+							<entry><literal>%[%m/%y ]</literal></entry>
-+							<entry>06/15</entry>
-+						</row>
-+					</tbody>
-+				</tgroup>
-+			</table>
-+
-+			<para>The $index_format string would contain:</para>
-+ 
-+<screen>
-+%<[y?%<[m?%<[d?%[%H:%M ]&%[%a %d]>&%[%b %d]>&%[%m/%y ]>
-+</screen>
++Credits
++-------
 +
-+			<para>
-+				Reparsed a little, for clarity, you can see the
-+				test conditions and the four format strings.
-+			</para>
++    * Karel Zak <kzak at redhat.com>
++    * Richard Russon <rich at flatcap.org>
 +
-+<screen>
-+%<[y?                                       &%[%m/%y ]>  Older
-+     %<[m?                        &%[%b %d]>             This year
-+          %<[d?         &%[%a %d]>                       This month
-+               %[%H:%M ]                                 Today
-+</screen>
+diff --git a/README.sidebar b/README.sidebar
+new file mode 100644
+index 0000000..6ee820b
+--- /dev/null
++++ b/README.sidebar
+@@ -0,0 +1,143 @@
++Sidebar Patch
++=============
 +
-+			<para>
-+			This a another view of the same example, with some whitespace
-+			for clarity.
-+			</para>
++    Overview of mailboxes
 +
-+<screen>
-+%<[y? %<[m? %<[d? AAA & BBB > & CCC > & DDD >
-+</screen>
++    NOTES:
 +
-+			<literallayout>
-+AAA = %[%H:%M ]
-+BBB = %[%a %d]
-+CCC = %[%b %d]
-+DDD = %[%m/%y ]
-+			</literallayout>
-+		</sect3>
-+	</sect2>
++    If you haven't used the sidebar before, you might like to read the
++    Sidebar Introduction:
 +
-+	<sect2 id="cond-date-variables">
-+		<title>Variables</title>
++        http://www.neomutt.org/sidebar-intro.html
 +
-+        <para>
-+		The <quote>cond-date</quote> patch doesn't have any config of its own.
-+		It modifies the behavior of the format strings.
-+        </para>
-+	</sect2>
++    If you have used an older version of the Sidebar, please note that some
++    of the configuration has changed.
 +
-+<!--
-+	<sect2 id="cond-date-functions">
-+		<title>Functions</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="cond-date-commands">
-+		<title>Commands</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="cond-date-colors">
-+		<title>Colors</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="cond-date-sort">
-+		<title>Sort</title>
-+		<para>None</para>
-+	</sect2>
-+-->
++        http://www.neomutt.org/sidebar-intro.html#intro-sidebar-config-changes
 +
-+	<sect2 id="cond-date-muttrc">
-+		<title>Muttrc</title>
-+<screen>
-+<emphasis role="comment"># Example Mutt config file for the 'index-color' feature.
-+#
-+# The default index_format is:
-+#       '%4C %Z %{%b %d} %-15.15L (%?l?%4l&%4c?) %s'
-+#
-+# We replace the date field '%{%b %d}', giving:</emphasis>
-+set index_format='%4C %Z %<[y?%<[m?%<[d?%[%H:%M ]&%[%a %d]>&%[%b %d]>&%[%m/%y ]> %-15.15L (%?l?%4l&%4c?) %s'
-+ 
-+<emphasis role="comment"># Test  Date Range  Format String  Example
-+# --------------------------------------------
-+# %[d   Today       %[%H:%M ]      12:34
-+# %[m   This month  %[%a %d]       Thu 12
-+# %[y   This year   %[%b %d]       Dec 10
-+# -     Older       %[%m/%y ]      06/15
-+ 
-+# vim: syntax=muttrc</emphasis>
-+</screen>
-+	</sect2>
-+
-+	<sect2 id="cond-date-see-also">
-+		<title>See Also</title>
-+
-+		<itemizedlist>
-+			<listitem><para><ulink url="http://www.neomutt.org/">NeoMutt Project</ulink></para></listitem>
-+			<listitem><para><link linkend="index-format">$index_format</link></para></listitem>
-+			<listitem><para><link linkend="nested-if">nested-if patch</link></para></listitem>
-+			<listitem><para><literal>strftime(3)</literal></para></listitem>
-+		</itemizedlist>
-+	</sect2>
-+
-+	<sect2 id="cond-date-known-bugs">
-+		<title>Known Bugs</title>
-+
-+		<para>
-+			Date parsing doesn't quite do what you expect.
-+			<quote>1w</quote> doesn't mean the <quote>in the last 7 days</quote>, but
-+			<quote><emphasis>this</emphasis> week</quote>.  This doesn't match
-+			the normal Mutt behaviour: for example <literal>~d>1w</literal>
-+			means emails dated in the last 7 days.
-+		</para>
-+
-+	</sect2>
-+
-+	<sect2 id="cond-date-credits">
-+		<title>Credits</title>
-+		<itemizedlist>
-+		<listitem><para>Aaron Schrab <email>aaron at schrab.com</email></para></listitem>
-+		<listitem><para>Eric Davis <email>edavis at insanum.com</email></para></listitem>
-+		<listitem><para>Richard Russon <email>rich at flatcap.org</email></para></listitem>
-+		</itemizedlist>
-+	</sect2>
-+</sect1>
++Patch
++-----
 +
-+<sect1 id="tls-sni">
-+	<title>TLS-SNI Patch</title>
-+	<subtitle>Negotiate with a server for a TSL/SSL certificate</subtitle>
-+
-+	<sect2 id="tls-sni-patch">
-+		<title>Patch</title>
-+
-+		<para>
-+			To check if Mutt supports <quote>TLS-SNI</quote>, look for
-+			<quote>patch-tls-sni</quote> in the mutt version.
-+			See: <xref linkend="mutt-patches"/>.
-+		</para>
-+
-+		<itemizedlist>
-+			<title>Dependencies:</title>
-+			<listitem><para>mutt-1.6.1</para></listitem>
-+			<listitem><para>OpenSSL</para></listitem>
-+		</itemizedlist>
-+
-+		<para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
-+	</sect2>
-+
-+	<sect2 id="tls-sni-intro">
-+		<title>Introduction</title>
-+
-+		<para>
-+		The <quote>TLS-SNI</quote> patch adds support for TLS virtual hosting.
-+		If your mail server doesn't support this everything will still work
-+		normally.
-+		</para>
-+
-+		<para>
-+		TLS supports sending the expected server hostname during the
-+		handshake, via the SNI extension.  This can be used to select a
-+		server certificate to issue to the client, permitting
-+		virtual-hosting without requiring multiple IP addresses.
-+		</para>
-+
-+		<para>
-+		This has been tested against Exim 4.80, which optionally logs SNI
-+		and can perform vhosting.
-+		</para>
++    To check if Mutt supports "Sidebar", look for "+USE_SIDEBAR" in the mutt
++    version.
 +
-+        <para>
-+		To verify TLS SNI support by a server, you can use:
-+        </para>
++    Dependencies
++    * mutt-1.6.2
 +
-+<screen>
-+openssl s_client -host <imap server> -port <port> -tls1 -servername <imap server>
-+</screen>
-+	</sect2>
++Introduction
++------------
 +
-+<!--
-+	<sect2 id="tls-sni-variables">
-+		<title>Variables</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="tls-sni-functions">
-+		<title>Functions</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="tls-sni-commands">
-+		<title>Commands</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="tls-sni-colors">
-+		<title>Colors</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="tls-sni-sort">
-+		<title>Sort</title>
-+		<para>None</para>
-+	</sect2>
-+-->
++    The Sidebar shows a list of all your mailboxes. The list can be turned on
++    and off, it can be themed and the list style can be configured.
 +
-+	<sect2 id="tls-sni-muttrc">
-+		<title>Muttrc</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="tls-sni-see-also">
-+		<title>See Also</title>
-+
-+		<itemizedlist>
-+			<listitem><para><ulink url="http://www.neomutt.org/">NeoMutt Project</ulink></para></listitem>
-+		</itemizedlist>
-+	</sect2>
-+
-+	<sect2 id="tls-sni-known-bugs">
-+		<title>Known Bugs</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="tls-sni-credits">
-+		<title>Credits</title>
-+		<itemizedlist>
-+		<listitem><para>Jeremy Katz <email>katzj at linuxpower.org</email></para></listitem>
-+		<listitem><para>Phil Pennock <email>mutt-dev at spodhuis.demon.nl</email></para></listitem>
-+		<listitem><para>Richard Russon <email>rich at flatcap.org</email></para></listitem>
-+		</itemizedlist>
-+	</sect2>
-+</sect1>
++    This part of the manual is a reference guide. If you want a simple
++    introduction with examples see the Sidebar Howto. If you just want to get
++    started, you could use the sample Sidebar muttrc.
 +
-+<sect1 id="sidebar">
-+	<title>Sidebar Patch</title>
-+	<subtitle>Overview of mailboxes</subtitle>
-+
-+	<sect2 id="sidebar-patch">
-+		<title>Patch</title>
-+
-+		<para>
-+			To check if Mutt supports <quote>Sidebar</quote>, look for
-+			<quote>+USE_SIDEBAR</quote> in the mutt version.
-+			See: <xref linkend="compile-time-features"/>.
-+		</para>
-+
-+		<itemizedlist>
-+			<title>Dependencies:</title>
-+			<listitem><para>mutt-1.6.1</para></listitem>
-+		</itemizedlist>
-+
-+		<para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
-+	</sect2>
-+
-+	<sect2 id="sidebar-intro">
-+		<title>Introduction</title>
-+
-+		<para>
-+			The Sidebar shows a list of all your mailboxes.  The list can be
-+			turned on and off, it can be themed and the list style can be
-+			configured.
-+		</para>
-+
-+		<para>
-+			This part of the manual is a reference guide.
-+			If you want a simple introduction with examples see the
-+			<link linkend="intro-sidebar">Sidebar Howto</link>.
-+			If you just want to get started, you could use the sample
-+			<link linkend="sidebar-muttrc">Sidebar muttrc</link>.
-+		</para>
-+
-+		<para>
-+			This version of Sidebar is based on Terry Chan's
-+			<ulink url="http://www.lunar-linux.org/mutt-sidebar/">2015-11-11 release</ulink>.
-+			It contains many
-+			<emphasis role="bold"><link linkend="intro-sidebar-features">new features</link></emphasis>,
-+			lots of
-+			<emphasis role="bold"><link linkend="intro-sidebar-bugfixes">bugfixes</link></emphasis>.
-+		</para>
-+	</sect2>
-+
-+	<sect2 id="sidebar-variables">
-+		<title>Variables</title>
-+
-+		<table id="table-sidebar-variables">
-+			<title>Sidebar Variables</title>
-+			<tgroup cols="3">
-+				<thead>
-+					<row>
-+						<entry>Name</entry>
-+						<entry>Type</entry>
-+						<entry>Default</entry>
-+					</row>
-+				</thead>
-+				<tbody>
-+					<row>
-+						<entry><literal>sidebar_delim_chars</literal></entry>
-+						<entry>string</entry>
-+						<entry><literal>/.</literal></entry>
-+					</row>
-+					<row>
-+						<entry><literal>sidebar_divider_char</literal></entry>
-+						<entry>string</entry>
-+						<entry><literal>|</literal></entry>
-+					</row>
-+					<row>
-+						<entry><literal>sidebar_folder_indent</literal></entry>
-+						<entry>boolean</entry>
-+						<entry><literal>no</literal></entry>
-+					</row>
-+					<row>
-+						<entry><literal>sidebar_format</literal></entry>
-+						<entry>string</entry>
-+						<entry><literal>%B%?F? [%F]?%* %?N?%N/?%S</literal></entry>
-+					</row>
-+					<row>
-+						<entry><literal>sidebar_indent_string</literal></entry>
-+						<entry>string</entry>
-+						<entry><literal>  </literal> (two spaces)</entry>
-+					</row>
-+					<row>
-+						<entry><literal>sidebar_new_mail_only</literal></entry>
-+						<entry>boolean</entry>
-+						<entry><literal>no</literal></entry>
-+					</row>
-+					<row>
-+						<entry><literal>sidebar_next_new_wrap</literal></entry>
-+						<entry>boolean</entry>
-+						<entry><literal>no</literal></entry>
-+					</row>
-+					<row>
-+						<entry><literal>sidebar_refresh_time</literal></entry>
-+						<entry>number</entry>
-+						<entry><literal>60</literal></entry>
-+					</row>
-+					<row>
-+						<entry><literal>sidebar_short_path</literal></entry>
-+						<entry>boolean</entry>
-+						<entry><literal>no</literal></entry>
-+					</row>
-+					<row>
-+						<entry><literal>sidebar_sort_method</literal></entry>
-+						<entry>enum</entry>
-+						<entry><literal>SORT_ORDER</literal></entry>
-+					</row>
-+					<row>
-+						<entry><literal>sidebar_visible</literal></entry>
-+						<entry>boolean</entry>
-+						<entry><literal>no</literal></entry>
-+					</row>
-+					<row>
-+						<entry><literal>sidebar_whitelist</literal></entry>
-+						<entry>list</entry>
-+						<entry>(empty)</entry>
-+					</row>
-+					<row>
-+						<entry><literal>sidebar_width</literal></entry>
-+						<entry>number</entry>
-+						<entry><literal>20</literal></entry>
-+					</row>
-+				</tbody>
-+			</tgroup>
-+		</table>
-+	</sect2>
-+
-+	<sect2 id="sidebar-functions">
-+		<title>Functions</title>
-+
-+		<para>
-+			Sidebar adds the following functions to Mutt.
-+			By default, none of them are bound to keys.
-+		</para>
-+
-+		<table id="table-sidebar-functions">
-+			<title>Sidebar Functions</title>
-+			<tgroup cols="3">
-+				<thead>
-+					<row>
-+						<entry>Menus</entry>
-+						<entry>Function</entry>
-+						<entry>Description</entry>
-+					</row>
-+				</thead>
-+				<tbody>
-+					<row>
-+						<entry>index,pager</entry>
-+						<entry><literal><sidebar-next></literal></entry>
-+						<entry>Move the highlight to next mailbox</entry>
-+					</row>
-+					<row>
-+						<entry>index,pager</entry>
-+						<entry><literal><sidebar-next-new></literal></entry>
-+						<entry>Move the highlight to next mailbox with new mail</entry>
-+					</row>
-+					<row>
-+						<entry>index,pager</entry>
-+						<entry><literal><sidebar-open></literal></entry>
-+						<entry>Open highlighted mailbox</entry>
-+					</row>
-+					<row>
-+						<entry>index,pager</entry>
-+						<entry><literal><sidebar-page-down></literal></entry>
-+						<entry>Scroll the Sidebar down 1 page</entry>
-+					</row>
-+					<row>
-+						<entry>index,pager</entry>
-+						<entry><literal><sidebar-page-up></literal></entry>
-+						<entry>Scroll the Sidebar up 1 page</entry>
-+					</row>
-+					<row>
-+						<entry>index,pager</entry>
-+						<entry><literal><sidebar-prev></literal></entry>
-+						<entry>Move the highlight to previous mailbox</entry>
-+					</row>
-+					<row>
-+						<entry>index,pager</entry>
-+						<entry><literal><sidebar-prev-new></literal></entry>
-+						<entry>Move the highlight to previous mailbox with new mail</entry>
-+					</row>
-+					<row>
-+						<entry>index,pager</entry>
-+						<entry><literal><sidebar-toggle-visible></literal></entry>
-+						<entry>Make the Sidebar (in)visible</entry>
-+					</row>
-+				</tbody>
-+			</tgroup>
-+		</table>
-+	</sect2>
-+
-+	<sect2 id="sidebar-commands">
-+		<title>Commands</title>
-+		<cmdsynopsis>
-+			<command>sidebar_whitelist</command>
-+			<arg choice="plain">
-+				<replaceable class="parameter">mailbox</replaceable>
-+			</arg>
-+			<arg choice="opt" rep="repeat">
-+				<replaceable class="parameter">mailbox</replaceable>
-+			</arg>
-+		</cmdsynopsis>
-+	</sect2>
-+
-+	<sect2 id="sidebar-colors">
-+		<title>Colors</title>
-+
-+		<table id="table-sidebar-colors">
-+			<title>Sidebar Colors</title>
-+			<tgroup cols="3">
-+				<thead>
-+					<row>
-+						<entry>Name</entry>
-+						<entry>Default Color</entry>
-+						<entry>Description</entry>
-+					</row>
-+				</thead>
-+				<tbody>
-+					<row>
-+						<entry><literal>sidebar_divider</literal></entry>
-+						<entry>default</entry>
-+						<entry>The dividing line between the Sidebar and the Index/Pager panels</entry>
-+					</row>
-+					<row>
-+						<entry><literal>sidebar_flagged</literal></entry>
-+						<entry>default</entry>
-+						<entry>Mailboxes containing flagged mail</entry>
-+					</row>
-+					<row>
-+						<entry><literal>sidebar_highlight</literal></entry>
-+						<entry>underline</entry>
-+						<entry>Cursor to select a mailbox</entry>
-+					</row>
-+					<row>
-+						<entry><literal>sidebar_indicator</literal></entry>
-+						<entry>mutt <literal>indicator</literal></entry>
-+						<entry>The mailbox open in the Index panel</entry>
-+					</row>
-+					<row>
-+						<entry><literal>sidebar_new</literal></entry>
-+						<entry>default</entry>
-+						<entry>Mailboxes containing new mail</entry>
-+					</row>
-+					<row>
-+						<entry><literal>sidebar_spoolfile</literal></entry>
-+						<entry>default</entry>
-+						<entry>Mailbox that receives incoming mail</entry>
-+					</row>
-+				</tbody>
-+			</tgroup>
-+		</table>
-+
-+		If the <literal>sidebar_indicator</literal> color isn't set, then the default Mutt
-+		indicator color will be used (the color used in the index panel).
-+	</sect2>
-+
-+	<sect2 id="sidebar-sort">
-+		<title>Sort</title>
-+
-+		<table id="table-sidebar-sort">
-+			<title>Sidebar Sort</title>
-+			<tgroup cols="2">
-+				<thead>
-+					<row>
-+						<entry>Sort</entry>
-+						<entry>Description</entry>
-+					</row>
-+				</thead>
-+				<tbody>
-+					<row>
-+						<entry><literal>alpha</literal></entry>
-+						<entry>Alphabetically by path</entry>
-+					</row>
-+					<row>
-+						<entry><literal>count</literal></entry>
-+						<entry>Total number of messages</entry>
-+					</row>
-+					<row>
-+						<entry><literal>flagged</literal></entry>
-+						<entry>Number of flagged messages</entry>
-+					</row>
-+					<row>
-+						<entry><literal>name</literal></entry>
-+						<entry>Alphabetically by path</entry>
-+					</row>
-+					<row>
-+						<entry><literal>new</literal></entry>
-+						<entry>Number of new messages</entry>
-+					</row>
-+					<row>
-+						<entry><literal>path</literal></entry>
-+						<entry>Alphabetically by path</entry>
-+					</row>
-+					<row>
-+						<entry><literal>unsorted</literal></entry>
-+						<entry>Do not resort the paths</entry>
-+					</row>
-+				</tbody>
-+			</tgroup>
-+		</table>
-+	</sect2>
-+
-+	<sect2 id="sidebar-muttrc">
-+		<title>Muttrc</title>
-+<screen>
-+<emphasis role="comment"># This is a complete list of sidebar-related configuration.
-+ 
-+# --------------------------------------------------------------------------
-+# VARIABLES - shown with their default values
-+# --------------------------------------------------------------------------
-+ 
-+# Should the Sidebar be shown?</emphasis>
-+set sidebar_visible = no
-+ 
-+<emphasis role="comment"># How wide should the Sidebar be in screen columns?
-+# Note: Some characters, e.g. Chinese, take up two columns each.</emphasis>
-+set sidebar_width = 20
-+ 
-+<emphasis role="comment"># Should the mailbox paths be abbreviated?</emphasis>
-+set sidebar_short_path = no
-+ 
-+<emphasis role="comment"># When abbreviating mailbox path names, use any of these characters as path
-+# separators.  Only the part after the last separators will be shown.
-+# For file folders '/' is good.  For IMAP folders, often '.' is useful.</emphasis>
-+set sidebar_delim_chars = '/.'
-+ 
-+<emphasis role="comment"># If the mailbox path is abbreviated, should it be indented?</emphasis>
-+set sidebar_folder_indent = no
-+ 
-+<emphasis role="comment"># Indent mailbox paths with this string.</emphasis>
-+set sidebar_indent_string = '  '
-+ 
-+<emphasis role="comment"># Make the Sidebar only display mailboxes that contain new, or flagged,
-+# mail.</emphasis>
-+set sidebar_new_mail_only = no
-+ 
-+<emphasis role="comment"># Any mailboxes that are whitelisted will always be visible, even if the
-+# sidebar_new_mail_only option is enabled.</emphasis>
-+sidebar_whitelist '/home/user/mailbox1'
-+sidebar_whitelist '/home/user/mailbox2'
-+ 
-+<emphasis role="comment"># When searching for mailboxes containing new mail, should the search wrap
-+# around when it reaches the end of the list?</emphasis>
-+set sidebar_next_new_wrap = no
-+ 
-+<emphasis role="comment"># The character to use as the divider between the Sidebar and the other Mutt
-+# panels.
-+# Note: Only the first character of this string is used.</emphasis>
-+set sidebar_divider_char = '|'
-+ 
-+<emphasis role="comment"># Display the Sidebar mailboxes using this format string.</emphasis>
-+set sidebar_format = '%B%?F? [%F]?%* %?N?%N/?%S'
-+ 
-+<emphasis role="comment"># Sidebar will not refresh its list of mailboxes any more frequently than
-+# this number of seconds.  This will help reduce disk/network traffic.</emphasis>
-+set sidebar_refresh_time = 60
-+ 
-+<emphasis role="comment"># Sort the mailboxes in the Sidebar using this method:
-+#       count    - total number of messages
-+#       flagged  - number of flagged messages
-+#       new      - number of new messages
-+#       path     - mailbox path
-+#       unsorted - do not sort the mailboxes</emphasis>
-+set sidebar_sort_method = 'unsorted'
-+ 
-+<emphasis role="comment"># --------------------------------------------------------------------------
-+# FUNCTIONS - shown with an example mapping
-+# --------------------------------------------------------------------------
-+ 
-+# Move the highlight to the previous mailbox</emphasis>
-+bind index,pager \Cp sidebar-prev
-+ 
-+<emphasis role="comment"># Move the highlight to the next mailbox</emphasis>
-+bind index,pager \Cn sidebar-next
-+ 
-+<emphasis role="comment"># Open the highlighted mailbox</emphasis>
-+bind index,pager \Co sidebar-open
-+ 
-+<emphasis role="comment"># Move the highlight to the previous page
-+# This is useful if you have a LOT of mailboxes.</emphasis>
-+bind index,pager <F3> sidebar-page-up
-+ 
-+<emphasis role="comment"># Move the highlight to the next page
-+# This is useful if you have a LOT of mailboxes.</emphasis>
-+bind index,pager <F4> sidebar-page-down
-+ 
-+<emphasis role="comment"># Move the highlight to the previous mailbox containing new, or flagged,
-+# mail.</emphasis>
-+bind index,pager <F5> sidebar-prev-new
-+ 
-+<emphasis role="comment"># Move the highlight to the next mailbox containing new, or flagged, mail.</emphasis>
-+bind index,pager <F6> sidebar-next-new
-+ 
-+<emphasis role="comment"># Toggle the visibility of the Sidebar.</emphasis>
-+bind index,pager B sidebar-toggle-visible
-+ 
-+<emphasis role="comment"># --------------------------------------------------------------------------
-+# COLORS - some unpleasant examples are given
-+# --------------------------------------------------------------------------
-+# Note: All color operations are of the form:
-+#       color OBJECT FOREGROUND BACKGROUND
-+ 
-+# Color of the current, open, mailbox
-+# Note: This is a general Mutt option which colors all selected items.</emphasis>
-+color indicator cyan black
-+ 
-+<emphasis role="comment"># Color of the highlighted, but not open, mailbox.</emphasis>
-+color sidebar_highlight black color8
-+ 
-+<emphasis role="comment"># Color of the divider separating the Sidebar from Mutt panels</emphasis>
-+color sidebar_divider color8 black
-+ 
-+<emphasis role="comment"># Color to give mailboxes containing flagged mail</emphasis>
-+color sidebar_flagged red black
-+ 
-+<emphasis role="comment"># Color to give mailboxes containing new mail</emphasis>
-+color sidebar_new green black
-+ 
-+<emphasis role="comment"># --------------------------------------------------------------------------
-+ 
-+# vim: syntax=muttrc</emphasis>
-+</screen>
-+	</sect2>
-+
-+	<sect2 id="sidebar-see-also">
-+		<title>See Also</title>
-+
-+		<itemizedlist>
-+			<listitem><para><link linkend="regexp">Regular Expressions</link></para></listitem>
-+			<listitem><para><link linkend="patterns">Patterns</link></para></listitem>
-+			<listitem><para><link linkend="color">Color command</link></para></listitem>
-+			<listitem><para><link linkend="notmuch">notmuch patch</link></para></listitem>
-+		</itemizedlist>
-+	</sect2>
-+
-+	<sect2 id="sidebar-known-bugs">
-+		<title>Known Bugs</title>
-+		Unsorted isn't
-+	</sect2>
-+
-+	<sect2 id="sidebar-credits">
-+		<title>Credits</title>
-+		<itemizedlist>
-+		<listitem><para>Justin Hibbits <email>jrh29 at po.cwru.edu</email></para></listitem>
-+		<listitem><para>Thomer M. Gil <email>mutt at thomer.com</email></para></listitem>
-+		<listitem><para>David Sterba <email>dsterba at suse.cz</email></para></listitem>
-+		<listitem><para>Evgeni Golov <email>evgeni at debian.org</email></para></listitem>
-+		<listitem><para>Fabian Groffen <email>grobian at gentoo.org</email></para></listitem>
-+		<listitem><para>Jason DeTiberus <email>jdetiber at redhat.com</email></para></listitem>
-+		<listitem><para>Stefan Assmann <email>sassmann at kpanic.de</email></para></listitem>
-+		<listitem><para>Steve Kemp <email>steve at steve.org.uk</email></para></listitem>
-+		<listitem><para>Terry Chan <email>tchan at lunar-linux.org</email></para></listitem>
-+		<listitem><para>Tyler Earnest <email>tylere at rne.st</email></para></listitem>
-+		<listitem><para>Richard Russon <email>rich at flatcap.org</email></para></listitem>
-+		</itemizedlist>
-+	</sect2>
-+</sect1>
++Variables
++---------
 +
-+<sect1 id="ifdef">
-+	<title>Ifdef Patch</title>
-+	<subtitle>Conditional config options</subtitle>
++    Sidebar Variables
 +
-+	<sect2 id="ifdef-patch">
-+		<title>Patch</title>
++    | Name                    | Type    | Default           |
++    |-------------------------|---------|-------------------|
++    | 'sidebar_delim_chars'   | string  | '/.'              |
++    | 'sidebar_divider_char'  | string  | '|'               |
++    | 'sidebar_folder_indent' | boolean | 'no'              |
++    | 'sidebar_format'        | string  | '%B%*  %n'        |
++    | 'sidebar_indent_string' | string  | '  ' (two spaces) |
++    | 'sidebar_new_mail_only' | boolean | 'no'              |
++    | 'sidebar_next_new_wrap' | boolean | 'no'              |
++    | 'sidebar_short_path'    | boolean | 'no'              |
++    | 'sidebar_sort_method'   | enum    | 'unsorted'        |
++    | 'sidebar_visible'       | boolean | 'no'              |
++    | 'sidebar_whitelist'     | list    | (empty)           |
++    | 'sidebar_width'         | number  | '20'              |
++
++    For more details, and examples, about the '$sidebar_format', see the
++    Sidebar Intro.
 +
-+		<para>
-+			To check if Mutt supports <quote>ifdef</quote>, look for
-+			<quote>patch-ifdef</quote> in the mutt version.
-+			See: <xref linkend="mutt-patches"/>.
-+		</para>
++Functions
++---------
 +
-+		<itemizedlist>
-+			<title>Dependencies:</title>
-+			<listitem><para>mutt-1.6.1</para></listitem>
-+		</itemizedlist>
++    Sidebar Functions
 +
-+		<para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
-+	</sect2>
++    Sidebar adds the following functions to Mutt. By default, none of them are
++    bound to keys.
 +
-+	<sect2 id="ifdef-intro">
-+		<title>Introduction</title>
++    | Menus       | Function                   | Description                                          |
++    |-------------|----------------------------|------------------------------------------------------|
++    | index,pager | '<sidebar-next>'           | Move the highlight to next mailbox                   |
++    | index,pager | '<sidebar-next-new>'       | Move the highlight to next mailbox with new mail     |
++    | index,pager | '<sidebar-open>'           | Open highlighted mailbox                             |
++    | index,pager | '<sidebar-page-down>'      | Scroll the Sidebar down 1 page                       |
++    | index,pager | '<sidebar-page-up>'        | Scroll the Sidebar up 1 page                         |
++    | index,pager | '<sidebar-prev>'           | Move the highlight to previous mailbox               |
++    | index,pager | '<sidebar-prev-new>'       | Move the highlight to previous mailbox with new mail |
++    | index,pager | '<sidebar-toggle-visible>' | Make the Sidebar (in)visible                         |
 +
-+		<para>
-+			The <quote>ifdef</quote> patch introduces three new commands to
-+			Mutt and allow you to share one config file between versions of Mutt
-+			that may have different features compiled in.
-+		</para>
++Commands
++--------
 +
-+<screen>
-+ifdef  symbol config-command [args...]  <emphasis role="comment"># If a symbol is defined</emphasis>
-+ifndef symbol config-command [args...]  <emphasis role="comment"># If a symbol is not defined</emphasis>
-+finish                                  <emphasis role="comment"># Finish reading the current file</emphasis>
-+</screen>
++        sidebar_whitelist mailbox [ mailbox... ]
 +
-+		<para>
-+			Here a symbol can be a <link linkend="variables">$variable</link>,
-+			<link linkend="functions"><function></link>,
-+			<link linkend="commands">command</link> or compile-time symbol, such
-+			as <quote>USE_IMAP</quote>.
-+		</para>
++Colors
++------
 +
-+        <para>
-+            <literal>finish</literal> is particularly useful when combined with
-+            <literal>ifndef</literal>. e.g.
-+        </para>
++    Sidebar Colors
 +
-+<screen>
-+<emphasis role="comment"># Sidebar config file</emphasis>
-+ifndef USE_SIDEBAR finish
-+</screen>
++    | Name                | Default Color    | Description                                                      |
++    |---------------------|------------------|------------------------------------------------------------------|
++    | 'sidebar_divider'   | default          | The dividing line between the Sidebar and the Index/Pager panels |
++    | 'sidebar_flagged'   | default          | Mailboxes containing flagged mail                                |
++    | 'sidebar_highlight' | underline        | Cursor to select a mailbox                                       |
++    | 'sidebar_indicator' | mutt 'indicator' | The mailbox open in the Index panel                              |
++    | 'sidebar_new'       | default          | Mailboxes containing new mail                                    |
++    | 'sidebar_spoolfile' | default          | Mailbox that receives incoming mail                              |
 +
-+	</sect2>
++    If the 'sidebar_indicator' color isn't set, then the default Mutt indicator
++    color will be used (the color used in the index panel).
 +
-+<!--
-+	<sect2 id="ifdef-variables">
-+		<title>Variables</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="ifdef-functions">
-+		<title>Functions</title>
-+		<para>None</para>
-+	</sect2>
-+-->
++Sort
++----
 +
-+	<sect2 id="ifdef-commands">
-+		<title>Commands</title>
-+		<cmdsynopsis>
-+			<command>ifdef</command>
-+			<arg choice="plain">
-+				<replaceable class="parameter">symbol</replaceable>
-+			</arg>
-+			<arg choice="plain">
-+				<replaceable class="parameter">"config-command [args]"</replaceable>
-+			</arg>
-+			<command>ifndef</command>
-+			<arg choice="plain">
-+				<replaceable class="parameter">symbol</replaceable>
-+			</arg>
-+			<arg choice="plain">
-+				<replaceable class="parameter">"config-command [args]"</replaceable>
-+			</arg>
-+			<command>finish</command>
-+		</cmdsynopsis>
-+	</sect2>
++    Sidebar Sort
 +
-+<!--
-+	<sect2 id="ifdef-colors">
-+		<title>Colors</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="ifdef-sort">
-+		<title>Sort</title>
-+		<para>None</para>
-+	</sect2>
-+-->
++    | Sort       | Description                      |
++    |------------|----------------------------------|
++    | 'alpha'    | Alphabetically by path           |
++    | 'count'    | Total number of messages         |
++    | 'flagged'  | Number of flagged messages       |
++    | 'name'     | Alphabetically by path           |
++    | 'new'      | Number of new messages           |
++    | 'path'     | Alphabetically by path           |
++    | 'unsorted' | Order of the 'mailboxes' command |
 +
-+	<sect2 id="ifdef-muttrc">
-+		<title>Muttrc</title>
-+<screen>
-+<emphasis role="comment"># Example Mutt config file for the 'ifdef' feature.
-+ 
-+# This feature introduces three useful commands which allow you to share
-+# one config file between versions of Mutt that may have different
-+# features compiled in.
-+ 
-+#	ifdef  symbol config-command [args...]
-+#	ifndef symbol config-command [args...]
-+#	finish                                
-+ 
-+# The 'ifdef' command tests whether Mutt understands the name of
-+# a variable, function, command or compile-time symbol.
-+# If it does, then it executes a config command.
-+ 
-+# The 'ifndef' command tests whether a symbol does NOT exist.
-+ 
-+# The 'finish' command tells Mutt to stop reading current config file.
-+ 
-+# If the 'trash' variable exists, set it.</emphasis>
-+ifdef trash 'set trash=~/Mail/trash'
-+ 
-+<emphasis role="comment"># If the 'tag-pattern' function exists, bind a key to it.</emphasis>
-+ifdef tag-pattern 'bind index <F6> tag-pattern'
-+ 
-+<emphasis role="comment"># If the 'imap-fetch-mail' command exists, read my IMAP config.</emphasis>
-+ifdef imap-fetch-mail 'source ~/.mutt/imap.rc'
-+ 
-+<emphasis role="comment"># If the compile-time symbol 'USE_SIDEBAR' does not exist, then
-+# stop reading the current config file.</emphasis>
-+ifndef USE_SIDEBAR finish
-+ 
-+<emphasis role="comment"># vim: syntax=muttrc</emphasis>
-+</screen>
-+	</sect2>
-+
-+	<sect2 id="ifdef-see-also">
-+		<title>See Also</title>
-+
-+		<itemizedlist>
-+			<listitem><para><ulink url="http://www.neomutt.org/">NeoMutt Project</ulink></para></listitem>
-+		</itemizedlist>
-+	</sect2>
-+
-+	<sect2 id="ifdef-known-bugs">
-+		<title>Known Bugs</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="ifdef-credits">
-+		<title>Credits</title>
-+		<itemizedlist>
-+		<listitem><para>Cedric Duval <email>cedricduval at free.fr</email></para></listitem>
-+		<listitem><para>Matteo F. Vescovi <email>mfvescovi at gmail.com</email></para></listitem>
-+		<listitem><para>Richard Russon <email>rich at flatcap.org</email></para></listitem>
-+		</itemizedlist>
-+	</sect2>
-+</sect1>
++See Also
++--------
 +
-+<sect1 id="fmemopen">
-+	<title>Fmemopen Patch</title>
-+	<subtitle>Replace some temporary files with memory buffers</subtitle>
++    * Regular Expressions
++    * Patterns
++    * Color command
++    * notmuch patch
 +
-+	<sect2 id="fmemopen-patch">
-+		<title>Patch</title>
++Known Bugs
++----------
 +
-+		<para>
-+			To check if Mutt supports <quote>fmemopen</quote>, look for
-+			<quote>patch-fmemopen</quote> in the mutt version.
-+			See: <xref linkend="mutt-patches"/>.
-+		</para>
++    None
 +
-+		<itemizedlist>
-+			<title>Dependencies:</title>
-+			<listitem><para>mutt-1.6.1</para></listitem>
-+			<listitem><para><literal>open_memstream()</literal>, <literal>fmemopen()</literal> from glibc</para></listitem>
-+		</itemizedlist>
++Credits
++-------
 +
-+		<para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
-+	</sect2>
++    * Justin Hibbits <jrh29 at po.cwru.edu>
++    * Thomer M. Gil <mutt at thomer.com>
++    * David Sterba <dsterba at suse.cz>
++    * Evgeni Golov <evgeni at debian.org>
++    * Fabian Groffen <grobian at gentoo.org>
++    * Jason DeTiberus <jdetiber at redhat.com>
++    * Stefan Assmann <sassmann at kpanic.de>
++    * Steve Kemp <steve at steve.org.uk>
++    * Terry Chan <tchan at lunar-linux.org>
++    * Tyler Earnest <tylere at rne.st>
++    * Richard Russon <rich at flatcap.org>
 +
-+	<sect2 id="fmemopen-intro">
-+		<title>Introduction</title>
+diff --git a/README.skip-quoted b/README.skip-quoted
+new file mode 100644
+index 0000000..fe611d1
+--- /dev/null
++++ b/README.skip-quoted
+@@ -0,0 +1,47 @@
++Skip-Quoted Patch
++=================
 +
-+        <para>
-+		The <quote>fmemopen</quote> patch speeds up some searches.
-+        </para>
++    Leave some context visible
 +
-+        <para>
-+		This patch changes a few places where Mutt creates temporary files.
-+		It replaces them with in-memory buffers.  This should improve the
-+		performance when searching the header or body using the
-+		<link linkend="thorough-search">$thorough_search</link> option.
-+        </para>
++Patch
++-----
 +
-+        <para>
-+		There are no user-configurable parts.
-+        </para>
++    To check if Mutt supports "skip-quoted", look for "patch-skip-quoted" in
++    the mutt version.
 +
-+        <para>
-+		This patch depends on <literal>open_memstream()</literal> and
-+		<literal>fmemopen()</literal>.  They are provided by glibc.  Without
-+		them, Mutt will simply create temporary files.
-+        </para>
-+	</sect2>
++    Dependencies
++    * mutt-1.6.2
 +
-+<!--
-+	<sect2 id="fmemopen-variables">
-+		<title>Variables</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="fmemopen-functions">
-+		<title>Functions</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="fmemopen-commands">
-+		<title>Commands</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="fmemopen-colors">
-+		<title>Colors</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="fmemopen-sort">
-+		<title>Sort</title>
-+		<para>None</para>
-+	</sect2>
-+-->
++Introduction
++------------
 +
-+	<sect2 id="fmemopen-muttrc">
-+		<title>Muttrc</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="fmemopen-see-also">
-+		<title>See Also</title>
-+
-+		<itemizedlist>
-+			<listitem><para><ulink url="http://www.neomutt.org/">NeoMutt Project</ulink></para></listitem>
-+			<listitem><para><link linkend="compile-time-features">Compile-Time Features</link></para></listitem>
-+			<listitem><para><literal>fmemopen(3)</literal></para></listitem>
-+		</itemizedlist>
-+	</sect2>
-+
-+	<sect2 id="fmemopen-known-bugs">
-+		<title>Known Bugs</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="fmemopen-credits">
-+		<title>Credits</title>
-+		<itemizedlist>
-+		<listitem><para>Julius Plenz <email>plenz at cis.fu-berlin.de</email></para></listitem>
-+		<listitem><para>Richard Russon <email>rich at flatcap.org</email></para></listitem>
-+		</itemizedlist>
-+	</sect2>
-+</sect1>
++    When viewing an email, the '<skip-to-quoted>' function (by default the 'S'
++    key) will scroll past any quoted text. Sometimes, a little context is
++    useful.
 +
-+<sect1 id="initials">
-+	<title>Initials Expando Patch</title>
-+	<subtitle>Expando for author's initials</subtitle>
++    By setting the '$skip_quoted_offset' variable, you can select how much of
++    the quoted text is left visible.
 +
-+	<sect2 id="initials-patch">
-+		<title>Patch</title>
++Variables
++---------
 +
-+		<para>
-+			To check if Mutt supports <quote>Initials</quote>, look for
-+			<quote>patch-initials</quote> in the mutt version.
-+			See: <xref linkend="mutt-patches"/>.
-+		</para>
++    | Name                 | Type   | Default |
++    |----------------------|--------|---------|
++    | 'skip_quoted_offset' | number | 0       |
 +
-+		<itemizedlist>
-+			<title>Dependencies:</title>
-+			<listitem><para>mutt-1.6.1</para></listitem>
-+		</itemizedlist>
++See Also
++--------
 +
-+		<para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
-+	</sect2>
++    * NeoMutt project
 +
-+	<sect2 id="initials-intro">
-+		<title>Introduction</title>
++Known Bugs
++----------
 +
-+        <para>
-+		The <quote>initials</quote> patch adds an expando (%I) for an author's
-+		initials.
-+        </para>
++    None
 +
-+		<para>
-+		The index panel displays a list of emails.  Its layout is controlled by
-+		the <link linkend="index-format">$index_format</link> variable.  Using
-+		this expando saves space in the index panel.  This can be useful if you
-+		are regularly working with a small set of people.
-+		</para>
-+	</sect2>
++Credits
++-------
 +
-+	<sect2 id="initials-variables">
-+		<title>Variables</title>
++    * David Sterba <dsterba at suse.cz>
++    * Richard Russon <rich at flatcap.org>
 +
-+        <para>
-+        This patch has no config of its own.  It adds an expando which can be
-+		used in the <link linkend="index-format">$index_format</link> variable.
-+        </para>
-+	</sect2>
+diff --git a/README.smime-encrypt-self b/README.smime-encrypt-self
+new file mode 100644
+index 0000000..8cd9267
+--- /dev/null
++++ b/README.smime-encrypt-self
+@@ -0,0 +1,50 @@
++smime-encrypt-self Patch
++========================
 +
-+<!--
-+	<sect2 id="initials-functions">
-+		<title>Functions</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="initials-commands">
-+		<title>Commands</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="initials-colors">
-+		<title>Colors</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="initials-sort">
-+		<title>Sort</title>
-+		<para>None</para>
-+	</sect2>
-+-->
++    Save an self-encrypted copy of emails
 +
-+	<sect2 id="initials-muttrc">
-+		<title>Muttrc</title>
-+<screen>
-+<emphasis role="comment"># Example Mutt config file for the 'initials' patch.
-+ 
-+# The 'initials' patch has no config of its own.
-+# It adds an expando for an author's initials,
-+# which can be used in the 'index_format' variable.
-+ 
-+# The default 'index_format' is:</emphasis>
-+set index_format='%4C %Z %{%b %d} %-15.15L (%?l?%4l&%4c?) %s'
-+ 
-+<emphasis role="comment"># Where %L represents the author/recipient
-+ 
-+# This might look like:
-+#       1   + Nov 17 David Bowie   Changesbowie    ( 689)
-+#       2   ! Nov 17 Stevie Nicks  Rumours         ( 555)
-+#       3   + Nov 16 Jimi Hendrix  Voodoo Child    ( 263)
-+#       4   + Nov 16 Debbie Harry  Parallel Lines  ( 540)
-+ 
-+# Using the %I expando:</emphasis>
-+set index_format='%4C %Z %{%b %d} %I (%?l?%4l&%4c?) %s'
-+ 
-+<emphasis role="comment"># This might look like:
-+#       1   + Nov 17 DB Changesbowie    ( 689)
-+#       2   ! Nov 17 SN Rumours         ( 555)
-+#       3   + Nov 16 JH Voodoo Child    ( 263)
-+#       4   + Nov 16 DH Parallel Lines  ( 540)
-+ 
-+# vim: syntax=muttrc</emphasis>
-+</screen>
-+	</sect2>
-+
-+	<sect2 id="initials-see-also">
-+		<title>See Also</title>
-+
-+		<itemizedlist>
-+			<listitem><para><ulink url="http://www.neomutt.org/">NeoMutt Project</ulink></para></listitem>
-+			<listitem><para><link linkend="index-format">$index_format</link></para></listitem>
-+			<listitem><para><link linkend="index-color">index-color patch</link></para></listitem>
-+			<listitem><para><link linkend="folder-hook">folder-hook</link></para></listitem>
-+		</itemizedlist>
-+	</sect2>
-+
-+	<sect2 id="initials-known-bugs">
-+		<title>Known Bugs</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="initials-credits">
-+		<title>Credits</title>
-+		<itemizedlist>
-+		<listitem><para>Vsevolod Volkov <email>vvv at mutt.org.ua</email></para></listitem>
-+		<listitem><para>Richard Russon <email>rich at flatcap.org</email></para></listitem>
-+		</itemizedlist>
-+	</sect2>
-+</sect1>
++Patch
++-----
 +
-+<sect1 id="trash-folder">
-+	<title>Trash Folder Patch</title>
-+	<subtitle>Automatically move "deleted" emails to a trash bin</subtitle>
-+
-+	<sect2 id="trash-folder-patch">
-+		<title>Patch</title>
-+
-+		<para>
-+			To check if Mutt supports <quote>Trash Folder</quote>, look for
-+			<quote>patch-trash</quote> in the mutt version.
-+			See: <xref linkend="mutt-patches"/>.
-+		</para>
-+
-+		If IMAP is enabled, this patch will use it
-+
-+		<itemizedlist>
-+			<title>Dependencies:</title>
-+			<listitem><para>mutt-1.6.1</para></listitem>
-+			<listitem><para>IMAP support</para></listitem>
-+		</itemizedlist>
-+
-+		<para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
-+	</sect2>
-+
-+	<sect2 id="trash-folder-intro">
-+		<title>Introduction</title>
-+
-+		<para>
-+		In Mutt, when you <quote>delete</quote> an email it is first marked
-+		deleted.  The email isn't really gone until
-+		<link linkend="index-map"><sync-mailbox></link> is called.
-+		This happens when the user leaves the folder, or the function is called
-+		manually.
-+		</para>
-+
-+		<para>
-+		After <literal><sync-mailbox></literal> has been called the email is gone forever.
-+		</para>
-+
-+		<para>
-+		The <link linkend="trash">$trash</link> variable defines a folder in
-+		which to keep old emails.  As before, first you mark emails for
-+		deletion.  When <sync-mailbox> is called the emails are moved to
-+		the trash folder.
-+		</para>
-+
-+		<para>
-+		The <literal>$trash</literal> path can be either a full directory,
-+		or be relative to the <link linkend="folder">$folder</link>
-+		variable, like the <literal>mailboxes</literal> command.
-+		</para>
-+
-+		<note>
-+		Emails deleted from the trash folder are gone forever.
-+		</note>
-+	</sect2>
-+
-+	<sect2 id="trash-folder-variables">
-+		<title>Variables</title>
-+		<table id="table-trash-variables">
-+			<title>Trash Variables</title>
-+			<tgroup cols="3">
-+				<thead>
-+					<row>
-+						<entry>Name</entry>
-+						<entry>Type</entry>
-+						<entry>Default</entry>
-+					</row>
-+				</thead>
-+				<tbody>
-+					<row>
-+						<entry>trash</entry>
-+						<entry>string</entry>
-+						<entry>(none)</entry>
-+					</row>
-+				</tbody>
-+			</tgroup>
-+		</table>
-+	</sect2>
-+
-+	<sect2 id="trash-folder-functions">
-+		<title>Functions</title>
-+		<table id="table-trash-functions">
-+			<title>Trash Functions</title>
-+			<tgroup cols="4">
-+				<thead>
-+					<row>
-+						<entry>Menus</entry>
-+						<entry>Default Key</entry>
-+						<entry>Function</entry>
-+						<entry>Description</entry>
-+					</row>
-+				</thead>
-+				<tbody>
-+					<row>
-+						<entry>index,pager</entry>
-+						<entry>(none)</entry>
-+						<entry><literal><purge-message></literal></entry>
-+						<entry>really delete the current entry, bypassing the trash folder</entry>
-+					</row>
-+				</tbody>
-+			</tgroup>
-+		</table>
-+	</sect2>
++    To check if Mutt supports "smime-encrypt-self", look for
++    "patch-smime-encrypt-self" in the mutt version.
 +
-+<!--
-+	<sect2 id="trash-folder-commands">
-+		<title>Commands</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="trash-folder-colors">
-+		<title>Colors</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="trash-folder-sort">
-+		<title>Sort</title>
-+		<para>None</para>
-+	</sect2>
-+-->
++    Dependencies
++    * mutt-1.6.2
 +
-+	<sect2 id="trash-folder-muttrc">
-+		<title>Muttrc</title>
-+<screen>
-+<emphasis role="comment"># Example Mutt config file for the 'trash' feature.
-+ 
-+# This feature defines a new 'trash' folder.
-+# When mail is deleted it will be moved to this folder.
-+ 
-+# Folder in which to put deleted emails</emphasis>
-+set trash='+Trash'
-+set trash='/home/flatcap/Mail/Trash'
-+ 
-+<emphasis role="comment"># The default delete key 'd' will move an email to the 'trash' folder
-+# Bind 'D' to REALLY delete an email</emphasis>
-+bind index D purge-message
-+ 
-+<emphasis role="comment"># Note: Deleting emails from the 'trash' folder will REALLY delete them.
-+ 
-+# vim: syntax=muttrc</emphasis>
-+</screen>
-+	</sect2>
-+
-+	<sect2 id="trash-folder-see-also">
-+		<title>See Also</title>
-+
-+		<itemizedlist>
-+			<listitem><para><ulink url="http://www.neomutt.org/">NeoMutt Project</ulink></para></listitem>
-+			<listitem><para><link linkend="folder-hook">folder-hook</link></para></listitem>
-+		</itemizedlist>
-+	</sect2>
-+
-+	<sect2 id="trash-folder-known-bugs">
-+		<title>Known Bugs</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="trash-folder-credits">
-+		<title>Credits</title>
-+		<itemizedlist>
-+		<listitem><para>Cedric Duval <email>cedricduval at free.fr</email></para></listitem>
-+		<listitem><para>Benjamin Kuperman <email>kuperman at acm.org</email></para></listitem>
-+		<listitem><para>Paul Miller <email>paul at voltar.org</email></para></listitem>
-+		<listitem><para>Richard Russon <email>rich at flatcap.org</email></para></listitem>
-+		</itemizedlist>
-+	</sect2>
-+</sect1>
++Introduction
++------------
 +
-+<sect1 id="limit-current-thread">
-+	<title>Limit-Current-Thread Patch</title>
-+	<subtitle>Focus on one Email Thread</subtitle>
++    Once you encrypt an email to someone you cannot read it. This is good for
++    security, but bad for record-keeping. If you wanted to keep a copy of an
++    encrypted email you could set $fcc_clear.
 +
-+	<sect2 id="limit-current-thread-patch">
-+		<title>Patch</title>
++    A better option is to enable $smime_encrypt_self, then set
++    $smime_default_key to your personal S/MIME key id.
 +
-+		<para>
-+			To check if Mutt supports <quote>limit-current-thread</quote>, look for
-+			<quote>patch-limit-current-thread</quote> in the mutt version.
-+			See: <xref linkend="mutt-patches"/>.
-+		</para>
++        set smime_encrypt_self = yes
++        set smime_default_key  = bb345e23.0
 +
-+		<itemizedlist>
-+			<title>Dependencies:</title>
-+			<listitem><para>mutt-1.6.1</para></listitem>
-+		</itemizedlist>
++Variables
++---------
 +
-+		<para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
-+	</sect2>
++    | Name                 | Type | Default |
++    |----------------------|------|---------|
++    | 'smime_encrypt_self' | quad | No      |
 +
-+	<sect2 id="limit-current-thread-intro">
-+		<title>Introduction</title>
++See Also
++--------
 +
-+		<para>
-+			This patch adds a new way of using the
-+			<link linkend="tuning-search">Limit Command</link>.
-+                        The <literal><limit-current-thread></literal>
-+                        function restricts the view to just the current thread.
-+                        Setting the limit (the <literal>l</literal> key) to
-+                        <quote>all</quote> will restore the full email list.
-+		</para>
++    * NeoMutt Project
 +
-+	</sect2>
++Known Bugs
++----------
 +
-+<!--
-+	<sect2 id="limit-current-thread-variables">
-+		<title>Variables</title>
-+		<para>None</para>
-+	</sect2>
-+-->
-+	<sect2 id="limit-current-thread-functions">
-+		<title>Functions</title>
-+
-+		<table id="table-limit-current-thread-functions">
-+			<title>Limit-Current-Thread Functions</title>
-+			<tgroup cols="4">
-+				<thead>
-+					<row>
-+						<entry>Menus</entry>
-+						<entry>Default Key</entry>
-+						<entry>Function</entry>
-+						<entry>Description</entry>
-+					</row>
-+				</thead>
-+				<tbody>
-+					<row>
-+						<entry>index</entry>
-+                                                <entry><literal><Esc> L</literal></entry>
-+						<entry><literal><limit-current-thread></literal></entry>
-+						<entry>Limit view to current thread</entry>
-+					</row>
-+				</tbody>
-+			</tgroup>
-+		</table>
-+
-+	</sect2>
-+<!--
-+	<sect2 id="limit-current-thread-commands">
-+		<title>Commands</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="limit-current-thread-colors">
-+		<title>Colors</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="limit-current-thread-sort">
-+		<title>Sort</title>
-+		<para>None</para>
-+	</sect2>
-+-->
++    None
 +
-+	<sect2 id="limit-current-thread-muttrc">
-+		<title>Muttrc</title>
++Credits
++-------
 +
-+<screen>
-+<emphasis role="comment"># Example Mutt config file for the 'limit-current-thread' patch.
-+ 
-+# Limit view to current thread</emphasis>
-+bind index <esc>L limit-current-thread
-+ 
-+<emphasis role="comment"># vim: syntax=muttrc</emphasis>
-+</screen>
-+	</sect2>
-+
-+	<sect2 id="limit-current-thread-see-also">
-+		<title>See Also</title>
-+
-+		<itemizedlist>
-+			<listitem><para><ulink url="http://www.neomutt.org/">NeoMutt Project</ulink></para></listitem>
-+		</itemizedlist>
-+	</sect2>
-+
-+	<sect2 id="limit-current-thread-known-bugs">
-+		<title>Known Bugs</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="limit-current-thread-credits">
-+		<title>Credits</title>
-+		<itemizedlist>
-+		<listitem><para>David Sterba <email>dsterba at suse.cz</email></para></listitem>
-+		<listitem><para>Richard Russon <email>rich at flatcap.org</email></para></listitem>
-+		</itemizedlist>
-+	</sect2>
-+</sect1>
++    * Omen Wild <omen at mandarb.com>
++    * Richard Russon <rich at flatcap.org>
 +
-+<sect1 id="skip-quoted-patch">
-+	<title>Skip-Quoted Patch</title>
-+	<subtitle>Leave some context visible</subtitle>
-+
-+	<sect2 id="skip-quoted-patch2">
-+		<title>Patch</title>
-+
-+		<para>
-+			To check if Mutt supports <quote>skip-quoted</quote>, look for
-+			<quote>patch-skip-quoted</quote> in the mutt version.
-+			See: <xref linkend="mutt-patches"/>.
-+		</para>
-+
-+		<itemizedlist>
-+			<title>Dependencies:</title>
-+			<listitem><para>mutt-1.6.1</para></listitem>
-+		</itemizedlist>
-+
-+		<para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
-+	</sect2>
-+
-+	<sect2 id="skip-quoted-intro">
-+		<title>Introduction</title>
-+
-+		<para>
-+			When viewing an email, the
-+			<literal><skip-to-quoted></literal> function (by default the
-+			<literal>S</literal> key) will scroll past any quoted text.
-+			Sometimes, a little context is useful.
-+		</para>
-+
-+		<para>
-+			By setting the <literal>$skip_quoted_offset</literal> variable, you
-+			can select how much of the quoted text is left visible.
-+		</para>
-+	</sect2>
-+
-+	<sect2 id="skip-quoted-variables">
-+		<title>Variables</title>
-+		<table id="table-skip-quoted-variables">
-+			<title>Skip-Quoted Variables</title>
-+			<tgroup cols="3">
-+				<thead>
-+					<row>
-+						<entry>Name</entry>
-+						<entry>Type</entry>
-+						<entry>Default</entry>
-+					</row>
-+				</thead>
-+				<tbody>
-+					<row>
-+						<entry><literal>skip_quoted_offset</literal></entry>
-+						<entry>number</entry>
-+						<entry>0</entry>
-+					</row>
-+				</tbody>
-+			</tgroup>
-+		</table>
-+	</sect2>
+diff --git a/README.status-color b/README.status-color
+new file mode 100644
+index 0000000..03a7fb4
+--- /dev/null
++++ b/README.status-color
+@@ -0,0 +1,67 @@
++Status Color Patch
++==================
 +
-+<!--
-+	<sect2 id="skip-quoted-functions">
-+		<title>Functions</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="skip-quoted-commands">
-+		<title>Commands</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="skip-quoted-colors">
-+		<title>Colors</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="skip-quoted-sort">
-+		<title>Sort</title>
-+		<para>None</para>
-+	</sect2>
-+-->
++    Custom rules for theming the status bar
 +
-+	<sect2 id="skip-quoted-muttrc">
-+		<title>Muttrc</title>
++Patch
++-----
 +
-+<screen>
-+<emphasis role="comment"># Example Mutt config file for the 'skip-quoted' patch.
-+ 
-+# The 'S' (skip-quoted) command scrolls the pager past the quoted text (usually
-+# indented with '> '.  Setting 'skip_quoted_offset' leaves some lines of quoted
-+# text on screen for context.
-+ 
-+# Show three quoted lines before the reply</emphasis>
-+set skip_quoted_offset = 3
-+ 
-+<emphasis role="comment"># vim: syntax=muttrc</emphasis>
-+</screen>
-+	</sect2>
-+
-+	<sect2 id="skip-quoted-see-also">
-+		<title>See Also</title>
-+
-+		<itemizedlist>
-+			<listitem><para><ulink url="http://www.neomutt.org/">NeoMutt Project</ulink></para></listitem>
-+		</itemizedlist>
-+	</sect2>
-+
-+	<sect2 id="skip-quoted-known-bugs">
-+		<title>Known Bugs</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="skip-quoted-credits">
-+		<title>Credits</title>
-+		<itemizedlist>
-+		<listitem><para>David Sterba <email>dsterba at suse.cz</email></para></listitem>
-+		<listitem><para>Richard Russon <email>rich at flatcap.org</email></para></listitem>
-+		</itemizedlist>
-+	</sect2>
-+</sect1>
++    To check if Mutt supports "Status Color", look for "patch-status-color" in
++    the mutt version.
 +
-+<sect1 id="compress">
-+	<title>Compressed Folders Patch</title>
-+	<subtitle>Read from/write to compressed mailboxes</subtitle>
-+
-+	<sect2 id="compress-patch">
-+		<title>Patch</title>
-+
-+		<para>
-+			To check if Mutt supports <quote>Compress Folders</quote>, look for
-+			<quote>+USE_COMPRESSED</quote> in the mutt version.
-+			See: <xref linkend="compile-time-features"/>.
-+		</para>
-+
-+		<itemizedlist>
-+			<title>Dependencies:</title>
-+			<listitem><para>mutt-1.6.1</para></listitem>
-+		</itemizedlist>
-+
-+		<para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
-+	</sect2>
-+
-+	<sect2 id="compress-intro">
-+		<title>Introduction</title>
-+
-+		<para>
-+			The Compressed Folder patch allows Mutt to read mailbox files that are
-+			compressed.  But it isn't limited to compressed files.  It works well
-+			with encrypted files, too.  In fact, if you can create a program/script
-+			to convert to and from your format, then Mutt can read it.
-+		</para>
-+
-+		<para>
-+			The patch adds three hooks to Mutt: <literal>open-hook</literal>,
-+			<literal>close-hook</literal> and <literal>append-hook</literal>.  They
-+			define commands to: uncompress a file; compress a file; append
-+			messages to an already compressed file.
-+		</para>
-+
-+		<para>
-+			There are some examples of both compressed and encrypted files,
-+			later.  For now, the documentation will just concentrate on
-+			compressed files.
-+		</para>
-+
-+	</sect2>
++    Dependencies
++    * mutt-1.6.2
 +
-+<!--
-+	<sect2 id="compress-variables">
-+		<title>Variables</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="compress-functions">
-+		<title>Functions</title>
-+		<para>None</para>
-+	</sect2>
-+-->
++Introduction
++------------
 +
-+	<sect2 id="compress-commands">
-+		<title>Commands</title>
-+		<cmdsynopsis>
-+			<command>open-hook</command>
-+			<arg choice="plain">
-+				<replaceable class="parameter">pattern</replaceable>
-+			</arg>
-+			<arg choice="plain">
-+				<replaceable class="parameter">shell-command</replaceable>
-+			</arg>
-+			<command>close-hook</command>
-+			<arg choice="plain">
-+				<replaceable class="parameter">pattern</replaceable>
-+			</arg>
-+			<arg choice="plain">
-+				<replaceable class="parameter">shell-command</replaceable>
-+			</arg>
-+			<command>append-hook</command>
-+			<arg choice="plain">
-+				<replaceable class="parameter">pattern</replaceable>
-+			</arg>
-+			<arg choice="plain">
-+				<replaceable class="parameter">shell-command</replaceable>
-+			</arg>
-+		</cmdsynopsis>
-+
-+		<para>
-+			The shell-command must contain two placeholders for filenames:
-+			<literal>%f</literal> and <literal>%t</literal>.  These represent
-+			<quote>from</quote> and <quote>to</quote> filenames.  It's a good idea to
-+			put quotes around these placeholders.
-+		</para>
-+
-+		<para>
-+			If you need the exact string <quote>%f</quote> or <quote>%t</quote> in your
-+			command, simply double up the <quote>%</quote> character, e.g.
-+			<quote>%%f</quote> or <quote>%%t</quote>.
-+		</para>
-+
-+		<table id="table-compress-optional">
-+			<title>Not all Hooks are Required</title>
-+			<tgroup cols="5">
-+				<thead>
-+					<row>
-+						<entry>Open</entry>
-+						<entry>Close</entry>
-+						<entry>Append</entry>
-+						<entry>Effect</entry>
-+						<entry>Useful if</entry>
-+					</row>
-+				</thead>
-+				<tbody>
-+					<row>
-+						<entry>Open</entry>
-+						<entry>-</entry>
-+						<entry>-</entry>
-+						<entry>Folder is readonly</entry>
-+						<entry>The folder is just a backup</entry>
-+					</row>
-+					<row>
-+						<entry>Open</entry>
-+						<entry>Close</entry>
-+						<entry>-</entry>
-+						<entry>Folder is read/write, but the entire folder must be
-+							written if anything is changed</entry>
-+						<entry>Your compression format doesn't support appending</entry>
-+					</row>
-+					<row>
-+						<entry>Open</entry>
-+						<entry>Close</entry>
-+						<entry>Append</entry>
-+						<entry>Folder is read/write and emails can be efficiently added
-+							to the end</entry>
-+						<entry>Your compression format supports appending</entry>
-+					</row>
-+					<row>
-+						<entry>Open</entry>
-+						<entry>-</entry>
-+						<entry>Append</entry>
-+						<entry>Folder is readonly, but can be appended to</entry>
-+						<entry>You want to store emails, but never change them</entry>
-+					</row>
-+				</tbody>
-+			</tgroup>
-+		</table>
-+
-+		<note>
-+			The command:
-+			<itemizedlist>
-+				<listitem><para>should return a non-zero exit status on failure</para></listitem>
-+				<listitem><para>should not delete any files</para></listitem>
-+			</itemizedlist>
-+		</note>
-+
-+		<sect3 id="open-hook">
-+			<title>Read from compressed mailbox</title>
-+
-+			<screen>open-hook regexp shell-command</screen>
-+
-+			<para>
-+				If Mutt is unable to open a file, it then looks for
-+				<literal>open-hook</literal> that matches the filename.
-+			</para>
-+
-+			<para>
-+				If your compression program doesn't have a well-defined extension,
-+				then you can use <literal>.</literal> as the regexp.
-+			</para>
-+
-+			<sect4 id="compress-open-hook-example">
-+				<title>Example of open-hook</title>
-+
-+				<screen>open-hook '\.gz$' "gzip -cd '%f' > '%t'"</screen>
-+
-+				<itemizedlist>
-+					<listitem><para>Mutt finds a file, <quote>example.gz</quote>,
-+							that it can't read</para></listitem>
-+					<listitem><para>Mutt has an <literal>open-hook</literal>
-+							whose regexp matches the filename:
-+							<literal>\.gz$</literal></para></listitem>
-+					<listitem><para>Mutt uses the command <literal>gzip -cd</literal>
-+							to create a temporary file that it <emphasis>can</emphasis>
-+							read</para></listitem>
-+				</itemizedlist>
-+			</sect4>
-+		</sect3>
-+
-+		<sect3 id="close-hook">
-+			<title>Write to a compressed mailbox</title>
-+
-+			<screen>close-hook regexp shell-command</screen>
-+
-+			<para>
-+				When Mutt has finished with a compressed mail folder, it will look
-+				for a matching <literal>close-hook</literal> to recompress the file.
-+				This hook is <link linkend="table-compress-optional">optional</link>.
-+			</para>
-+
-+			<note>
-+				If the folder has not been modifed, the
-+				<literal>close-hook</literal> will not be called.
-+			</note>
-+
-+			<sect4 id="compress-close-hook-example">
-+				<title>Example of close-hook</title>
-+
-+				<screen>close-hook '\.gz$' "gzip -c '%t' > '%f'"</screen>
-+
-+				<itemizedlist>
-+					<listitem><para>Mutt has finished with a folder, <quote>example.gz</quote>,
-+							that it opened with <literal>open-hook</literal></para></listitem>
-+					<listitem><para>The folder has been modified</para></listitem>
-+					<listitem><para>Mutt has a <literal>close-hook</literal> whose regexp
-+							matches the filename: <literal>\.gz$</literal></para></listitem>
-+					<listitem><para>Mutt uses the command <literal>gzip -c</literal>
-+							to create a new compressed file</para></listitem>
-+				</itemizedlist>
-+			</sect4>
-+		</sect3>
-+
-+		<sect3 id="append-hook">
-+			<title>Append to a compressed mailbox</title>
-+
-+			<screen>append-hook regexp shell-command</screen>
-+
-+			<para>
-+				When Mutt wants to append an email to a compressed mail folder, it
-+				will look for a matching <literal>append-hook</literal>.
-+				This hook is <link linkend="table-compress-optional">optional</link>.
-+			</para>
-+
-+			<para>
-+				Using the <literal>append-hook</literal> will save time, but
-+				Mutt won't be able to determine the type of the mail folder
-+				inside the compressed file.
-+			</para>
-+
-+			<para>
-+				Mutt will <emphasis>assume</emphasis> the type to be that of
-+				the <literal>$mbox_type</literal> variable.  Mutt also uses
-+				this type for temporary files.
-+			</para>
-+
-+			<para>
-+				Mutt will only use the <literal>append-hook</literal> for existing files.
-+				The <literal>close-hook</literal> will be used for empty, or missing files.
-+			</para>
-+
-+			<sect4 id="compress-append-hook-example">
-+				<title>Example of append-hook</title>
-+
-+				<screen>append-hook '\.gz$' "gzip -c '%t' >> '%f'"</screen>
-+
-+				<itemizedlist>
-+					<listitem><para>Mutt wants to append an email to a folder, <quote>example.gz</quote>,
-+							that it opened with <literal>open-hook</literal></para></listitem>
-+					<listitem><para>Mutt has an <literal>append-hook</literal> whose regexp matches
-+							the filename: <literal>\.gz$</literal></para></listitem>
-+					<listitem><para>Mutt knows the mailbox type from the <literal>$mbox</literal>
-+							variable</para></listitem>
-+					<listitem><para>Mutt uses the command <literal>gzip -c</literal>
-+							to append to an existing compressed file</para></listitem>
-+				</itemizedlist>
-+			</sect4>
-+
-+		</sect3>
-+
-+		<sect3 id="compress-empty">
-+			<title>Empty Files</title>
-+
-+			<para>
-+				Mutt assumes that an empty file is not compressed.  In this
-+				situation, unset <link linkend="save-empty">$save_empty</link>, so
-+				that the compressed file will be removed if you delete all of the
-+				messages.
-+			</para>
-+		</sect3>
-+
-+		<sect3 id="compress-security">
-+			<title>Security</title>
-+
-+			<para>
-+				Encrypted files are decrypted into temporary files which are
-+				stored in the <link linkend="tmpdir">$tmpdir</link> directory.
-+				This could be a security risk.
-+			</para>
-+		</sect3>
-+	</sect2>
++    The "status-color" patch allows you to theme different parts of the status
++    bar (also when it's used by the index).
 +
-+<!--
-+	<sect2 id="compress-colors">
-+		<title>Colors</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="compress-sort">
-+		<title>Sort</title>
-+		<para>None</para>
-+	</sect2>
-+-->
++    Unlike normal color commands, 'color status' can now take up to 2 extra
++    parameters (regex, num).
 +
-+	<sect2 id="compress-muttrc">
-+		<title>Muttrc</title>
-+<screen>
-+<emphasis role="comment"># Example Mutt config file for the 'compressed folders' feature.
-+ 
-+# This feature adds three hooks to Mutt which allow it to
-+# work with compressed, or encrypted, mailboxes.
-+ 
-+# The hooks are of the form:
-+#       open-hook   regexp "shell-command"
-+#       close-hook  regexp "shell-command"
-+#       append-hook regexp "shell-command"
-+ 
-+# The 'append-hook' is optional.
-+ 
-+# Hander for gzip compressed mailboxes</emphasis>
-+open-hook   '\.gz$'  "gzip -cd  '%f' >  '%t'"
-+close-hook  '\.gz$'  "gzip -c   '%t' >  '%f'"
-+append-hook '\.gz$'  "gzip -c   '%t' >> '%f'"
-+ 
-+<emphasis role="comment"># Hander for bzip2 compressed mailboxes</emphasis>
-+open-hook   '\.bz2$' "bzip2 -cd '%f' >  '%t'"
-+close-hook  '\.bz2$' "bzip2 -c  '%t' >  '%f'"
-+append-hook '\.bz2$' "bzip2 -c  '%t' >> '%f'"
-+ 
-+<emphasis role="comment"># Hander for xz compressed mailboxes</emphasis>
-+open-hook   '\.xz$'  "xz    -cd '%f' >  '%t'"
-+close-hook  '\.xz$'  "xz    -c  '%t' >  '%f'"
-+append-hook '\.xz$'  "xz    -c  '%t' >> '%f'"
-+ 
-+<emphasis role="comment"># Hander for pgp encrypted mailboxes
-+# PGP does not support appending to an encrypted file</emphasis>
-+open-hook   '\.pgp$' "pgp -f < '%f' > '%t'"
-+close-hook  '\.pgp$' "pgp -fe YourPgpUserIdOrKeyId < '%t' > '%f'"
-+ 
-+<emphasis role="comment"># Hander for gpg encrypted mailboxes
-+# gpg does not support appending to an encrypted file</emphasis>
-+open-hook   '\.gpg$' "gpg --decrypt < '%f' > '%t'"
-+close-hook  '\.gpg$' "gpg --encrypt --recipient YourGpgUserIdOrKeyId < '%t' > '%f'"
-+ 
-+<emphasis role="comment"># vim: syntax=muttrc</emphasis>
-+</screen>
-+	</sect2>
-+
-+	<sect2 id="compress-see-also">
-+		<title>See Also</title>
-+
-+		<itemizedlist>
-+			<listitem><para><ulink url="https://github.com/neomutt/neomutt/wiki">NeoMutt Project</ulink></para></listitem>
-+			<listitem><para><link linkend="compile-time-features">Compile-Time Features</link></para></listitem>
-+			<listitem><para><link linkend="regexp">Regular Expressions</link></para></listitem>
-+			<listitem><para><link linkend="tmpdir">$tmpdir</link></para></listitem>
-+			<listitem><para><link linkend="mbox-type">$mbox_type</link></para></listitem>
-+			<listitem><para><link linkend="save-empty">$save_empty</link></para></listitem>
-+			<listitem><para><link linkend="folder-hook">folder-hook</link></para></listitem>
-+		</itemizedlist>
-+	</sect2>
-+
-+	<sect2 id="compress-known-bugs">
-+		<title>Known Bugs</title>
-+
-+		<itemizedlist>
-+			<listitem><para>The Compressed Folder hooks cannot deal with filenames that contains quotes/apostrophes.</para></listitem>
-+		</itemizedlist>
-+	</sect2>
-+
-+	<sect2 id="compress-credits">
-+		<title>Credits</title>
-+		<itemizedlist>
-+		<listitem><para>Roland Rosenfeld <email>roland at spinnaker.de</email></para></listitem>
-+		<listitem><para>Alain Penders <email>Alain at Finale-Dev.com</email></para></listitem>
-+		<listitem><para>Christoph <quote>Myon</quote> Berg <email>myon at debian.org</email></para></listitem>
-+		<listitem><para>Evgeni Golov <email>evgeni at debian.org</email></para></listitem>
-+		<listitem><para>Richard Russon <email>rich at flatcap.org</email></para></listitem>
-+		</itemizedlist>
-+	</sect2>
-+</sect1>
++Commands
++--------
 +
-+<sect1 id="keywords">
-+	<title>Keywords Patch</title>
-+	<subtitle>Labels/Tagging for emails</subtitle>
-+
-+	<sect2 id="keywords-patch">
-+		<title>Patch</title>
-+
-+		<para>
-+			To check if Mutt supports <quote>Keywords</quote>, look for
-+			<quote>patch-keywords</quote> in the mutt version.
-+			See: <xref linkend="mutt-patches"/>.
-+		</para>
-+
-+		<itemizedlist>
-+			<title>Dependencies:</title>
-+			<listitem><para>mutt-1.6.1</para></listitem>
-+		</itemizedlist>
-+
-+		<para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
-+	</sect2>
-+
-+	<sect2 id="keywords-intro">
-+		<title>Introduction</title>
-+
-+		<para>
-+		Unify label/keyword handling.
-+		</para>
-+
-+		<para>
-+		Since x-labels were added to mutt in 2000, a number of other approaches
-+		to what we now call <quote>tagging</quote> have also emerged.
-+		One of them was even made standard in RFC 2822.
-+		This update unifies the handling of all these strategies.
-+		</para>
-+
-+		<para>
-+		We start by changing mutt's internal keyword storage from a single
-+		string which may contain whitespace to a list of discrete keywords.
-+		This has advantages for keyword completion as well as for portabilty
-+		among varying "standards" for keyword storage.  This may represent
-+		a significant change for existing mutt users who have set x-labels
-+		containing spaces, and should be regarded with suspicion.  The
-+		advantages are significant, though.
-+		</para>
-+
-+		<para>
-+		Next we allow mutt to parse keywords into this internal list from
-+		any of the following headers: X-Label (freeform), X-Keywords
-+		(space-delimited), X-Mozilla-Keys (space-delimited), and Keywords (RFC
-+		2822, comma-space-delimited).  Mutt remembers which headers it sourced
-+		keywords from, and can rewrite those headers when saving messages for
-+		compatibility with the mailer of origin.
-+		</para>
-+
-+		<para>
-+		(X-Label was specified as freeform text by mutt, its only known
-+		implementation.  X-Labels have been used both as a
-+		<quote>tagging</quote> device, probably with space delimiting, and as a
-+		<quote>memo</quote> field, where space-delimited parsing would ruin the
-+		semantics of the memo.  By default mutt will not split X-Labels at all.
-+		Set $xlabel_delimiter if your needs vary.)
-+		</para>
-+
-+		<para>
-+		Finally we add two booleans: $keywords_legacy=true and
-+		$keywords_standard=FALSE.  When $keywords_legacy is true, mutt will
-+		always save keyword to whatever original header it came from.  When
-+		$keywords_standard=true, mutt will save to the Keywords: header.  If
-+		both are true mutt saves to both; if neither is true, mutt saves only
-+		to legacy headers to avoid complete loss of keywords.
-+		</para>
-+
-+		<para>
-+		Overall this represents convergence path for all competing
-+		labelling/tagging/keywording systems toward one that is specified by
-+		RFC.
-+		</para>
-+
-+		<para>
-+		You can change or delete the X-Label: field within
-+		Mutt using the edit-label command, bound to the
-+		y key by default.  This works for tagged messages, too.
-+		</para>
-+	</sect2>
-+
-+	<sect2 id="keywords-variables">
-+		<title>Variables</title>
-+
-+		<table id="table-keywords-variables">
-+			<title>Keywords Variables</title>
-+			<tgroup cols="3">
-+				<thead>
-+					<row>
-+						<entry>Name</entry>
-+						<entry>Type</entry>
-+						<entry>Default</entry>
-+					</row>
-+				</thead>
-+				<tbody>
-+					<row>
-+						<entry><literal>keywords_legacy</literal></entry>
-+						<entry>boolean</entry>
-+						<entry><literal>yes</literal></entry>
-+					</row>
-+					<row>
-+						<entry><literal>keywords_standard</literal></entry>
-+						<entry>boolean</entry>
-+						<entry><literal>no</literal></entry>
-+					</row>
-+					<row>
-+						<entry><literal>xlabel_delimiter</literal></entry>
-+						<entry>string</entry>
-+						<entry>(empty)</entry>
-+					</row>
-+				</tbody>
-+			</tgroup>
-+		</table>
-+	</sect2>
-+
-+	<sect2 id="keywords-functions">
-+		<title>Functions</title>
-+
-+		<table id="table-keywords-funcions">
-+			<title>Keyword Functions</title>
-+			<tgroup cols="4">
-+				<thead>
-+					<row>
-+						<entry>Menus</entry>
-+						<entry>Default Key</entry>
-+						<entry>Function</entry>
-+						<entry>Description</entry>
-+					</row>
-+				</thead>
-+				<tbody>
-+					<row>
-+						<entry>index,pager</entry>
-+						<entry>y</entry>
-+						<entry><literal><edit-label></literal></entry>
-+						<entry>add, change, or delete a message's label</entry>
-+					</row>
-+				</tbody>
-+			</tgroup>
-+		</table>
-+	</sect2>
++        color status foreground background [ regex [ num ]]
 +
-+<!--
-+	<sect2 id="keywords-commands">
-+		<title>Commands</title>
-+	</sect2>
-+
-+	<sect2 id="keywords-colors">
-+		<title>Colors</title>
-+		<para>None</para>
-+	</sect2>
-+-->
++    With zero parameters, Mutt will set the default color for the entire status
++    bar.
 +
-+	<sect2 id="keywords-sort">
-+		<title>Sort</title>
-+		<table id="table-keywords-sort">
-+			<title>Keywords Sort</title>
-+			<tgroup cols="2">
-+				<thead>
-+					<row>
-+						<entry>Sort</entry>
-+						<entry>Description</entry>
-+					</row>
-+				</thead>
-+				<tbody>
-+					<row>
-+						<entry><literal>label</literal></entry>
-+						<entry>Sort by label</entry>
-+					</row>
-+				</tbody>
-+			</tgroup>
-+		</table>
-+	</sect2>
-+
-+	<sect2 id="keywords-muttrc">
-+		<title>Muttrc</title>
-+	</sect2>
-+
-+	<sect2 id="keywords-see-also">
-+		<title>See Also</title>
-+
-+		<itemizedlist>
-+			<listitem><para><ulink url="https://github.com/neomutt/neomutt/wiki">NeoMutt Project</ulink></para></listitem>
-+			<listitem><para><link linkend="index-format">$index_format</link></para></listitem>
-+			<listitem><para><link linkend="index-color">index-color patch</link></para></listitem>
-+			<listitem><para><link linkend="folder-hook">folder-hook</link></para></listitem>
-+		</itemizedlist>
-+	</sect2>
-+
-+	<sect2 id="keywords-known-bugs">
-+		<title>Known Bugs</title>
-+	</sect2>
-+
-+	<sect2 id="keywords-credits">
-+		<title>Credits</title>
-+		<itemizedlist>
-+		<listitem><para>David Champion <email>dgc at uchicago.edu</email></para></listitem>
-+		<listitem><para>Richard Russon <email>rich at flatcap.org</email></para></listitem>
-+		</itemizedlist>
-+	</sect2>
-+</sect1>
++    With one parameter, Mutt will only color the parts matching the regex.
 +
-+<sect1 id="nntp">
-+	<title>NNTP Patch</title>
-+	<subtitle>Talk to a Usenet news server</subtitle>
-+
-+	<sect2 id="nntp-patch">
-+		<title>Patch</title>
-+
-+		<para>
-+			To check if Mutt supports <quote>NNTP</quote>, look for
-+			<quote>+USE_NNTP</quote> in the mutt version.
-+			See: <xref linkend="compile-time-features"/>.
-+		</para>
-+
-+		<itemizedlist>
-+			<title>Dependencies:</title>
-+			<listitem><para>mutt-1.6.1</para></listitem>
-+		</itemizedlist>
-+
-+		<para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
-+	</sect2>
-+
-+	<sect2 id="nntp-intro">
-+		<title>Introduction</title>
-+
-+		<para>Reading news via NNTP</para>
-+		<para>
-+		If compiled with <emphasis>--enable-nntp</emphasis> option, Mutt can
-+		read news from news server via NNTP.  You can open a newsgroup with
-+		function ``change-newsgroup'' (default: ``i'').  Default news server
-+		can be obtained from <literal>$NNTPSERVER</literal> environment
-+		variable or from <literal>/etc/nntpserver</literal> file.  Like other
-+		news readers, info about subscribed newsgroups is saved in file by
-+		<link linkend="newsrc">$newsrc</link> variable.  The variable <link
-+		linkend="news-cache-dir">$news_cache_dir</link> can be used to point
-+		to a directory.  Mutt will create a hierarchy of subdirectories named
-+		like the account and newsgroup the cache is for.  Also the hierarchy
-+		is used to store header cache if Mutt was compiled with <link
-+		linkend="header-caching">header cache</link> support.
-+		</para>
-+	</sect2>
-+
-+	<sect2 id="nntp-variables">
-+		<title>Variables</title>
-+
-+		<table id="table-nntp-variables">
-+			<title>NNTP Variables</title>
-+			<tgroup cols="3">
-+				<thead>
-+					<row>
-+						<entry>Name</entry>
-+						<entry>Type</entry>
-+						<entry>Default</entry>
-+					</row>
-+				</thead>
-+				<tbody>
-+					<row>
-+						<entry><literal>ask_follow_up</literal></entry>
-+						<entry>boolean</entry>
-+						<entry><literal>no</literal></entry>
-+					</row>
-+					<row>
-+						<entry><literal>ask_x_comment_to</literal></entry>
-+						<entry>boolean</entry>
-+						<entry><literal>no</literal></entry>
-+					</row>
-+					<row>
-+						<entry><literal>catchup_newsgroup</literal></entry>
-+						<entry>quad</entry>
-+						<entry><literal>ask-yes</literal></entry>
-+					</row>
-+					<row>
-+						<entry><literal>followup_to_poster</literal></entry>
-+						<entry>quad</entry>
-+						<entry><literal>ask-yes</literal></entry>
-+					</row>
-+					<row>
-+						<entry><literal>group_index_format</literal></entry>
-+						<entry>string</entry>
-+						<entry><literal>%4C %M%N %5s  %-45.45f %d</literal></entry>
-+					</row>
-+					<row>
-+						<entry><literal>inews</literal></entry>
-+						<entry>string</entry>
-+						<entry>(empty)</entry>
-+					</row>
-+					<row>
-+						<entry><literal>mime_subject</literal></entry>
-+						<entry>boolean</entry>
-+						<entry><literal>yes</literal></entry>
-+					</row>
-+					<row>
-+						<entry><literal>newsgroups_charset</literal></entry>
-+						<entry>string</entry>
-+						<entry><literal>utf-8</literal></entry>
-+					</row>
-+					<row>
-+						<entry><literal>newsrc</literal></entry>
-+						<entry>string</entry>
-+						<entry><literal>~/.newsrc</literal></entry>
-+					</row>
-+					<row>
-+						<entry><literal>news_cache_dir</literal></entry>
-+						<entry>string</entry>
-+						<entry><literal>~/.mutt</literal></entry>
-+					</row>
-+					<row>
-+						<entry><literal>news_server</literal></entry>
-+						<entry>string</entry>
-+						<entry>(empty)</entry>
-+					</row>
-+					<row>
-+						<entry><literal>nntp_authenticators</literal></entry>
-+						<entry>string</entry>
-+						<entry>(empty)</entry>
-+					</row>
-+					<row>
-+						<entry><literal>nntp_context</literal></entry>
-+						<entry>number</entry>
-+						<entry><literal>1000</literal></entry>
-+					</row>
-+					<row>
-+						<entry><literal>nntp_listgroup</literal></entry>
-+						<entry>boolean</entry>
-+						<entry><literal>yes</literal></entry>
-+					</row>
-+					<row>
-+						<entry><literal>nntp_load_description</literal></entry>
-+						<entry>boolean</entry>
-+						<entry><literal>yes</literal></entry>
-+					</row>
-+					<row>
-+						<entry><literal>nntp_pass</literal></entry>
-+						<entry>string</entry>
-+						<entry>(empty)</entry>
-+					</row>
-+					<row>
-+						<entry><literal>nntp_poll</literal></entry>
-+						<entry>number</entry>
-+						<entry><literal>60</literal></entry>
-+					</row>
-+					<row>
-+						<entry><literal>nntp_user</literal></entry>
-+						<entry>string</entry>
-+						<entry>(empty)</entry>
-+					</row>
-+					<row>
-+						<entry><literal>post_moderated</literal></entry>
-+						<entry>quad</entry>
-+						<entry><literal>ask-yes</literal></entry>
-+					</row>
-+					<row>
-+						<entry><literal>save_unsubscribed</literal></entry>
-+						<entry>boolean</entry>
-+						<entry><literal>no</literal></entry>
-+					</row>
-+					<row>
-+						<entry><literal>show_new_news</literal></entry>
-+						<entry>boolean</entry>
-+						<entry><literal>yes</literal></entry>
-+					</row>
-+					<row>
-+						<entry><literal>show_only_unread</literal></entry>
-+						<entry>boolean</entry>
-+						<entry><literal>no</literal></entry>
-+					</row>
-+					<row>
-+						<entry><literal>x_comment_to</literal></entry>
-+						<entry>boolean</entry>
-+						<entry><literal>no</literal></entry>
-+					</row>
-+				</tbody>
-+			</tgroup>
-+		</table>
-+	</sect2>
-+
-+	<sect2 id="nntp-functions">
-+		<title>Functions</title>
-+
-+		<table id="table-nntp-functions">
-+			<title>NNTP Functions</title>
-+			<tgroup cols="4">
-+				<thead>
-+					<row>
-+						<entry>Menus</entry>
-+						<entry>Default Key</entry>
-+						<entry>Function</entry>
-+						<entry>Description</entry>
-+					</row>
-+				</thead>
-+				<tbody>
-+					<row>
-+						<entry>browser,index</entry>
-+						<entry>y</entry>
-+						<entry><literal><catchup></literal></entry>
-+						<entry>mark all articles in newsgroup as read</entry>
-+					</row>
-+					<row>
-+						<entry>index,pager</entry>
-+						<entry>i</entry>
-+						<entry><literal><change-newsgroup></literal></entry>
-+						<entry>open a different newsgroup</entry>
-+					</row>
-+					<row>
-+						<entry>pager</entry>
-+						<entry>X</entry>
-+						<entry><literal><change-vfolder></literal></entry>
-+						<entry>open a different virtual folder</entry>
-+					</row>
-+					<row>
-+						<entry>compose</entry>
-+						<entry>o</entry>
-+						<entry><literal><edit-followup-to></literal></entry>
-+						<entry>edit the Followup-To field</entry>
-+					</row>
-+					<row>
-+						<entry>compose</entry>
-+						<entry>N</entry>
-+						<entry><literal><edit-newsgroups></literal></entry>
-+						<entry>edit the newsgroups list</entry>
-+					</row>
-+					<row>
-+						<entry>compose</entry>
-+						<entry>x</entry>
-+						<entry><literal><edit-x-comment-to></literal></entry>
-+						<entry>edit the X-Comment-To field</entry>
-+					</row>
-+					<row>
-+						<entry>pager</entry>
-+						<entry>+</entry>
-+						<entry><literal><entire-thread></literal></entry>
-+						<entry>read entire thread of the current message</entry>
-+					</row>
-+					<row>
-+						<entry>attachment,index,pager</entry>
-+						<entry>F</entry>
-+						<entry><literal><followup-message></literal></entry>
-+						<entry>followup to newsgroup</entry>
-+					</row>
-+					<row>
-+						<entry>pager</entry>
-+						<entry>`</entry>
-+						<entry><literal><modify-labels></literal></entry>
-+						<entry>modify (notmuch) tags</entry>
-+					</row>
-+					<row>
-+						<entry>index,pager</entry>
-+						<entry>P</entry>
-+						<entry><literal><post-message></literal></entry>
-+						<entry>post message to newsgroup</entry>
-+					</row>
-+					<row>
-+						<entry>browser</entry>
-+						<entry>g</entry>
-+						<entry><literal><reload-active></literal></entry>
-+						<entry>load list of all newsgroups from NNTP server</entry>
-+					</row>
-+					<row>
-+						<entry>browser</entry>
-+						<entry>s</entry>
-+						<entry><literal><subscribe></literal></entry>
-+						<entry>subscribe to current mbox (IMAP/NNTP only)</entry>
-+					</row>
-+					<row>
-+						<entry>browser</entry>
-+						<entry>S</entry>
-+						<entry><literal><subscribe-pattern></literal></entry>
-+						<entry>subscribe to newsgroups matching a pattern</entry>
-+					</row>
-+					<row>
-+						<entry>browser</entry>
-+						<entry>Y</entry>
-+						<entry><literal><uncatchup></literal></entry>
-+						<entry>mark all articles in newsgroup as unread</entry>
-+					</row>
-+					<row>
-+						<entry>browser</entry>
-+						<entry>u</entry>
-+						<entry><literal><unsubscribe></literal></entry>
-+						<entry>unsubscribe from current mbox (IMAP/NNTP only)</entry>
-+					</row>
-+					<row>
-+						<entry>browser</entry>
-+						<entry>U</entry>
-+						<entry><literal><unsubscribe-pattern></literal></entry>
-+						<entry>unsubscribe from newsgroups matching a pattern</entry>
-+					</row>
-+					<row>
-+						<entry>index,pager</entry>
-+						<entry>Alt-i</entry>
-+						<entry><literal><change-newsgroup-readonly></literal></entry>
-+						<entry>open a different newsgroup in read only mode</entry>
-+					</row>
-+					<row>
-+						<entry>attachment,index,pager</entry>
-+						<entry>Alt-F</entry>
-+						<entry><literal><forward-to-group></literal></entry>
-+						<entry>forward to newsgroup</entry>
-+					</row>
-+					<row>
-+						<entry>index</entry>
-+						<entry>(none)</entry>
-+						<entry><literal><get-children></literal></entry>
-+						<entry>get all children of the current message</entry>
-+					</row>
-+					<row>
-+						<entry>index</entry>
-+						<entry>Alt-G</entry>
-+						<entry><literal><get-parent></literal></entry>
-+						<entry>get parent of the current message</entry>
-+					</row>
-+					<row>
-+						<entry>index,pager</entry>
-+						<entry>(none)</entry>
-+						<entry><literal><imap-fetch-mail></literal></entry>
-+						<entry>force retrieval of mail from IMAP server</entry>
-+					</row>
-+					<row>
-+						<entry>index,pager</entry>
-+						<entry>(none)</entry>
-+						<entry><literal><imap-logout-all></literal></entry>
-+						<entry>logout from all IMAP servers</entry>
-+					</row>
-+					<row>
-+						<entry>pager</entry>
-+						<entry>(none)</entry>
-+						<entry><literal><modify-labels-then-hide></literal></entry>
-+						<entry>modify labeld and then hide message</entry>
-+					</row>
-+					<row>
-+						<entry>index</entry>
-+						<entry>(none)</entry>
-+						<entry><literal><reconstruct-thread></literal></entry>
-+						<entry>reconstruct thread containing current message</entry>
-+					</row>
-+					<row>
-+						<entry>pager</entry>
-+						<entry>Alt-X</entry>
-+						<entry><literal><vfolder-from-query></literal></entry>
-+						<entry>generate virtual folder from query</entry>
-+					</row>
-+					<row>
-+						<entry>index</entry>
-+						<entry>Ctrl-G</entry>
-+						<entry><literal><get-message></literal></entry>
-+						<entry>get message with Message-Id</entry>
-+					</row>
-+				</tbody>
-+			</tgroup>
-+		</table>
-+	</sect2>
-+
-+	<sect2 id="nntp-commands">
-+		<title>Commands</title>
-+	</sect2>
-+
-+	<sect2 id="nntp-colors">
-+		<title>Colors</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="nntp-sort">
-+		<title>Sort</title>
-+		<para>None</para>
-+	</sect2>
-+
-+	<sect2 id="nntp-muttrc">
-+		<title>Muttrc</title>
-+	</sect2>
-+
-+	<sect2 id="nntp-see-also">
-+		<title>See Also</title>
-+
-+		<itemizedlist>
-+			<listitem><para><ulink url="https://github.com/neomutt/neomutt/wiki">NeoMutt Project</ulink></para></listitem>
-+			<listitem><para><link linkend="compile-time-features">Compile-Time Features</link></para></listitem>
-+		</itemizedlist>
-+	</sect2>
-+
-+	<sect2 id="nntp-known-bugs">
-+		<title>Known Bugs</title>
-+	</sect2>
-+
-+	<sect2 id="nntp-credits">
-+		<title>Credits</title>
-+		<itemizedlist>
-+		<listitem><para>Vsevolod Volkov <email>vvv at mutt.org.ua</email></para></listitem>
-+		<listitem><para>Felix von Leitner <email>leitner at fefe.de</email></para></listitem>
-+		<listitem><para>Richard Russon <email>rich at flatcap.org</email></para></listitem>
-+		</itemizedlist>
-+	</sect2>
-+</sect1>
++    With two parameters, Mutt will only color the num'th sub-match of the regex.
 +
- </chapter>
- 
- <chapter id="security">
-@@ -8623,6 +13076,18 @@
- 
- <listitem>
- <cmdsynopsis>
-+<command><link linkend="append-hook">append-hook</link></command>
-+<arg choice="plain">
-+<replaceable class="parameter">pattern</replaceable>
-+</arg>
-+<arg choice="plain">
-+<replaceable class="parameter">shell-command</replaceable>
-+</arg>
-+</cmdsynopsis>
-+</listitem>
++Colors
++------
 +
-+<listitem>
-+<cmdsynopsis>
- <command><link linkend="auto-view">auto_view</link></command>
- <arg choice="plain">
- <replaceable>mimetype</replaceable>
-@@ -8684,6 +13149,18 @@
- 
- <listitem>
- <cmdsynopsis>
-+<command><link linkend="close-hook">close-hook</link></command>
-+<arg choice="plain">
-+<replaceable class="parameter">pattern</replaceable>
-+</arg>
-+<arg choice="plain">
-+<replaceable class="parameter">shell-command</replaceable>
-+</arg>
-+</cmdsynopsis>
-+</listitem>
++    Status Colors
 +
-+<listitem>
-+<cmdsynopsis>
- <command><link linkend="color">color</link></command>
- <arg choice="plain">
- <replaceable class="parameter">object</replaceable>
-@@ -8753,6 +13230,18 @@
- 
- <listitem>
- <cmdsynopsis>
-+<command><link linkend="open-hook">open-hook</link></command>
-+<arg choice="plain">
-+<replaceable class="parameter">pattern</replaceable>
-+</arg>
-+<arg choice="plain">
-+<replaceable class="parameter">shell-command</replaceable>
-+</arg>
-+</cmdsynopsis>
-+</listitem>
++    | Name   | Default Color | Description |
++    |--------|---------------|-------------|
++    | status | 'reverse'     | Status bar  |
 +
-+<listitem>
-+<cmdsynopsis>
- <command><link linkend="crypt-hook">crypt-hook</link></command>
- <arg choice="plain">
- <replaceable class="parameter">regexp</replaceable>
-@@ -8874,6 +13363,18 @@
- 
- <listitem>
- <cmdsynopsis>
-+<command>ifdef</command>
-+<arg choice="plain">
-+<replaceable class="parameter">item</replaceable>
-+</arg>
-+<arg choice="plain">
-+<replaceable class="parameter">"config-command [args]"</replaceable>
-+</arg>
-+</cmdsynopsis>
-+</listitem>
++See Also
++--------
 +
-+<listitem>
-+<cmdsynopsis>
- <command><link linkend="ignore">ignore</link></command>
- <arg choice="plain">
- <replaceable class="parameter">pattern</replaceable>
-@@ -9237,6 +13738,17 @@
- 
- <listitem>
- <cmdsynopsis>
-+<command><link linkend="sidebar-whitelist">sidebar_whitelist</link></command>
-+<arg choice="plain">
-+<replaceable class="parameter">item</replaceable>
-+</arg>
-+<arg choice="plain">
-+<replaceable class="parameter">command</replaceable>
-+</arg>
-+</cmdsynopsis>
-+</listitem>
-+<listitem>
-+<cmdsynopsis>
- <command><link linkend="source">source</link></command>
- <arg choice="plain">
- <replaceable class="parameter">filename</replaceable>
-diff -urN mutt-1.6.1/doc/mutt.css mutt-1.6.1-neomutt/doc/mutt.css
---- mutt-1.6.1/doc/mutt.css	2016-06-12 18:43:00.402447590 +0100
-+++ mutt-1.6.1-neomutt/doc/mutt.css	2016-06-12 18:43:00.692452113 +0100
-@@ -9,17 +9,24 @@
- div.table-contents table th, div.informaltable table th {
-     font-family:sans-serif;
-     background:#d0d0d0;
--    font-weight:normal;
-+    font-weight:bold;
-     vertical-align:top;
- }
--div.cmdsynopsis { border-left:1px solid #707070; padding-left:5px; }
-+div.cmdsynopsis { border-left:1px solid #707070; padding-left: 1em; }
- li div.cmdsynopsis { border-left:none; padding-left:0px; }
--pre.screen, div.note { background:#f0f0f0; border:1px solid #c0c0c0; padding:5px; margin-left:2%; margin-right:2%; }
-+li p { margin: 0; }
-+pre.screen, div.note { border:1px solid #c0c0c0; margin-left:2%; margin-right:2%; }
-+pre.screen { color: #ffffff; background:#000000; padding: 0.5em; }
-+div.note { background:#ffff80; padding: 0.5em; }
- div.example p.title { margin-left:2%; }
- div.note h3 { font-size:small; font-style:italic; font-variant: small-caps; }
- div.note h3:after { content: ":" }
- div.note { margin-bottom: 5px; }
--.command { font-family: monospace; font-weight: normal; }
-+div.literallayout, .command { font-family: monospace; font-weight: normal; }
- .command strong { font-weight: normal; }
- tr { vertical-align: top; }
--.comment { color:#707070; }
-+.comment { color:#00c000; }
-+code.literal { background: #f0f0f0; color: #000000; }
-+span.indicator { background: #000060; color: #ffffff; }
-+span.highlight { background: #404040; color: #ffffff; }
-+span.reverse { background: #ffffff; color: #000000; }
-diff -urN mutt-1.6.1/doc/mutt.man mutt-1.6.1-neomutt/doc/mutt.man
---- mutt-1.6.1/doc/mutt.man	2016-06-12 18:43:00.403447606 +0100
-+++ mutt-1.6.1-neomutt/doc/mutt.man	2016-06-12 18:43:00.692452113 +0100
-@@ -23,8 +23,8 @@
- .SH SYNOPSIS
- .PP
- .B mutt
--[\-nRyzZ]
--[\-e \fIcmd\fP] [\-F \fIfile\fP] [\-m \fItype\fP] [\-f \fIfile\fP]
-+[\-GnRyzZ]
-+[\-e \fIcmd\fP] [\-F \fIfile\fP] [\-g \fIserver\fP] [\-m \fItype\fP] [\-f \fIfile\fP]
- .PP
- .B mutt 
- [\-Enx] 
-@@ -104,6 +104,10 @@
- Specify which mailbox to load.
- .IP "-F \fImuttrc\fP"
- Specify an initialization file to read instead of ~/.muttrc
-+.IP "-g \fIserver\fP"
-+Start Mutt with a listing of subscribed newsgroups at specified news server.
-+.IP "-G"
-+Start Mutt with a listing of subscribed newsgroups.
- .IP "-h"
- Display help.
- .IP "-H \fIdraft\fP"
-diff -urN mutt-1.6.1/doc/muttrc.compress mutt-1.6.1-neomutt/doc/muttrc.compress
---- mutt-1.6.1/doc/muttrc.compress	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/doc/muttrc.compress	2016-06-12 18:43:00.697452191 +0100
-@@ -0,0 +1,38 @@
-+# Example Mutt config file for the 'compressed folders' feature.
++    * NeoMutt project
++    * Compile-Time Features
++    * Regular Expressions
++    * Patterns
++    * index-color patch
++    * Color command
 +
-+# This feature adds three hooks to Mutt which allow it to
-+# work with compressed, or encrypted, mailboxes.
++Known Bugs
++----------
 +
-+# The hooks are of the form:
-+#       open-hook   regexp "shell-command"
-+#       close-hook  regexp "shell-command"
-+#       append-hook regexp "shell-command"
++    None
 +
-+# The 'append-hook' is optional.
++Credits
++-------
 +
-+# Hander for gzip compressed mailboxes
-+open-hook   '\.gz$'  "gzip -cd  '%f' >  '%t'"
-+close-hook  '\.gz$'  "gzip -c   '%t' >  '%f'"
-+append-hook '\.gz$'  "gzip -c   '%t' >> '%f'"
++    * David Sterba <dsterba at suse.cz>
++    * Thomas Glanzmann <thomas at glanzmann.de>
++    * Kirill A. Shutemov <kirill at shutemov.name>
++    * Richard Russon <rich at flatcap.org>
 +
-+# Hander for bzip2 compressed mailboxes
-+open-hook   '\.bz2$' "bzip2 -cd '%f' >  '%t'"
-+close-hook  '\.bz2$' "bzip2 -c  '%t' >  '%f'"
-+append-hook '\.bz2$' "bzip2 -c  '%t' >> '%f'"
+diff --git a/README.tls-sni b/README.tls-sni
+new file mode 100644
+index 0000000..76d5052
+--- /dev/null
++++ b/README.tls-sni
+@@ -0,0 +1,51 @@
++TLS-SNI Patch
++=============
 +
-+# Hander for xz compressed mailboxes
-+open-hook   '\.xz$'  "xz    -cd '%f' >  '%t'"
-+close-hook  '\.xz$'  "xz    -c  '%t' >  '%f'"
-+append-hook '\.xz$'  "xz    -c  '%t' >> '%f'"
++    Negotiate with a server for a TSL/SSL certificate
 +
-+# Hander for pgp encrypted mailboxes
-+# PGP does not support appending to an encrypted file
-+open-hook   '\.pgp$' "pgp -f < '%f' > '%t'"
-+close-hook  '\.pgp$' "pgp -fe YourPgpUserIdOrKeyId < '%t' > '%f'"
++Patch
++-----
 +
-+# Hander for gpg encrypted mailboxes
-+# gpg does not support appending to an encrypted file
-+open-hook   '\.gpg$' "gpg --decrypt < '%f' > '%t'"
-+close-hook  '\.gpg$' "gpg --encrypt --recipient YourGpgUserIdOrKeyId < '%t' > '%f'"
++    To check if Mutt supports "TLS-SNI", look for "patch-tls-sni" in the mutt
++    version.
 +
-+# vim: syntax=muttrc
-diff -urN mutt-1.6.1/doc/muttrc.cond-date mutt-1.6.1-neomutt/doc/muttrc.cond-date
---- mutt-1.6.1/doc/muttrc.cond-date	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/doc/muttrc.cond-date	2016-06-12 18:43:00.697452191 +0100
-@@ -0,0 +1,16 @@
-+# Example Mutt config file for the 'index-color' feature.
-+#
-+# The default index_format is:
-+#       '%4C %Z %{%b %d} %-15.15L (%?l?%4l&%4c?) %s'
-+#
-+# We replace the date field '%{%b %d}', giving:
-+set index_format='%4C %Z %<[y?%<[m?%<[d?%[%H:%M ]&%[%a %d]>&%[%b %d]>&%[%m/%y ]> %-15.15L (%?l?%4l&%4c?) %s'
++    Dependencies
++    * mutt-1.6.2
++    * OpenSSL
 +
-+# Test  Date Range  Format String  Example
-+# --------------------------------------------
-+# %[d   Today       %[%H:%M ]      12:34
-+# %[m   This month  %[%a %d]       Thu 12
-+# %[y   This year   %[%b %d]       Dec 10
-+# -     Older       %[%m/%y ]      06/15
++Introduction
++------------
 +
-+# vim: syntax=muttrc
-diff -urN mutt-1.6.1/doc/Muttrc.head mutt-1.6.1-neomutt/doc/Muttrc.head
---- mutt-1.6.1/doc/Muttrc.head	2016-06-12 18:43:00.400447559 +0100
-+++ mutt-1.6.1-neomutt/doc/Muttrc.head	2016-06-12 18:43:00.687452035 +0100
-@@ -29,6 +29,11 @@
- macro index,pager y "<change-folder>?<toggle-mailboxes>" "show incoming mailboxes list"
- bind browser y exit
- 
-+# Use folders which match on \\.gz$ as gzipped folders:
-+# open-hook \\.gz$ "gzip -cd %f > %t"
-+# close-hook \\.gz$ "gzip -c %t > %f"
-+# append-hook \\.gz$ "gzip -c %t >> %f"
++    The "TLS-SNI" patch adds support for TLS virtual hosting. If your mail
++    server doesn't support this everything will still work normally.
 +
- # If Mutt is unable to determine your site's domain name correctly, you can
- # set the default here.
- #
-diff -urN mutt-1.6.1/doc/muttrc.ifdef mutt-1.6.1-neomutt/doc/muttrc.ifdef
---- mutt-1.6.1/doc/muttrc.ifdef	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/doc/muttrc.ifdef	2016-06-12 18:43:00.697452191 +0100
-@@ -0,0 +1,32 @@
-+# Example Mutt config file for the 'ifdef' feature.
++    TLS supports sending the expected server hostname during the handshake, via
++    the SNI extension. This can be used to select a server certificate to issue
++    to the client, permitting virtual-hosting without requiring multiple IP
++    addresses.
 +
-+# This feature introduces three useful commands which allow you to share
-+# one config file between versions of Mutt that may have different
-+# features compiled in.
++    This has been tested against Exim 4.80, which optionally logs SNI and can
++    perform vhosting.
 +
-+#	ifdef  symbol config-command [args...]
-+#	ifndef symbol config-command [args...]
-+#	finish                                
++    To verify TLS SNI support by a server, you can use:
 +
-+# The 'ifdef' command tests whether Mutt understands the name of
-+# a variable, function, command or compile-time symbol.
-+# If it does, then it executes a config command.
++        openssl s_client -host <imap server> -port <port> -tls1 -servername
++    <imap server>
 +
-+# The 'ifndef' command tests whether a symbol does NOT exist.
++See Also
++--------
 +
-+# The 'finish' command tells Mutt to stop reading current config file.
++    * NeoMutt project
 +
-+# If the 'trash' variable exists, set it.
-+ifdef trash 'set trash=~/Mail/trash'
++Known Bugs
++----------
 +
-+# If the 'tag-pattern' function exists, bind a key to it.
-+ifdef tag-pattern 'bind index <F6> tag-pattern'
++    None
 +
-+# If the 'imap-fetch-mail' command exists, read my IMAP config.
-+ifdef imap-fetch-mail 'source ~/.mutt/imap.rc'
++Credits
++-------
 +
-+# If the compile-time symbol 'USE_SIDEBAR' does not exist, then
-+# stop reading the current config file.
-+ifndef USE_SIDEBAR finish
++    * Jeremy Katz <katzj at linuxpower.org>
++    * Phil Pennock <mutt-dev at spodhuis.demon.nl>
++    * Richard Russon <rich at flatcap.org>
 +
-+# vim: syntax=muttrc
-diff -urN mutt-1.6.1/doc/muttrc.index-color mutt-1.6.1-neomutt/doc/muttrc.index-color
---- mutt-1.6.1/doc/muttrc.index-color	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/doc/muttrc.index-color	2016-06-12 18:43:00.697452191 +0100
-@@ -0,0 +1,37 @@
-+# Example Mutt config file for the 'index-color' feature.
+diff --git a/README.trash b/README.trash
+new file mode 100644
+index 0000000..70e7402
+--- /dev/null
++++ b/README.trash
+@@ -0,0 +1,74 @@
++Trash Folder Patch
++==================
 +
-+# Entire index line
-+color index white black '.*'
++    Automatically move "deleted" emails to a trash bin
 +
-+# Author name, %A %a %F %L %n
++Patch
++-----
 +
-+# Give the author column a dark grey background
-+color index_author default color234 '.*'
++    To check if Mutt supports "Trash Folder", look for "patch-trash" in the
++    mutt version.
 +
-+# Highlight a particular from (~f)
-+color index_author brightyellow color234 '~fRay Charles'
++    If IMAP is enabled, this patch will use it
 +
-+# Message flags, %S %Z
-+# Highlight the flags for flagged (~F) emails
-+color index_flags default red '~F'
++    Dependencies
++    * mutt-1.6.2
++    * IMAP support
 +
-+# Subject, %s
-+# Look for a particular subject (~s)
-+color index_subject brightcyan default '~s\(closes #[0-9]+\)'
++Introduction
++------------
 +
-+# Number of messages in a collapsed thread, %M
-+color index_collapsed default brightblue
++    In Mutt, when you "delete" an email it is first marked deleted. The email
++    isn't really gone until <sync-mailbox> is called. This happens when the
++    user leaves the folder, or the function is called manually.
 +
-+# Date field
-+color index_date green default
++    After '<sync-mailbox>' has been called the email is gone forever.
 +
-+# Message label, %y %Y
-+color index_label default brightgreen
++    The $trash variable defines a folder in which to keep old emails. As
++    before, first you mark emails for deletion. When <sync-mailbox> is called
++    the emails are moved to the trash folder.
 +
-+# Message number, %C
-+color index_number red default
++    The '$trash' path can be either a full directory, or be relative to the
++    $folder variable, like the 'mailboxes' command.
 +
-+# Message size, %c %l
-+color index_size cyan default
++    > Note
++    >
++    > Emails deleted from the trash folder are gone forever.
 +
-+# vim: syntax=muttrc
-diff -urN mutt-1.6.1/doc/muttrc.initials mutt-1.6.1-neomutt/doc/muttrc.initials
---- mutt-1.6.1/doc/muttrc.initials	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/doc/muttrc.initials	2016-06-12 18:43:00.697452191 +0100
-@@ -0,0 +1,27 @@
-+# Example Mutt config file for the 'initials' patch.
-+
-+# The 'initials' patch has no config of its own.
-+# It adds an expando for an author's initials,
-+# which can be used in the 'index_format' variable.
-+
-+# The default 'index_format' is:
-+set index_format='%4C %Z %{%b %d} %-15.15L (%?l?%4l&%4c?) %s'
-+
-+# Where %L represents the author/recipient
-+
-+# This might look like:
-+#       1   + Nov 17 David Bowie   Changesbowie    ( 689)
-+#       2   ! Nov 17 Stevie Nicks  Rumours         ( 555)
-+#       3   + Nov 16 Jimi Hendrix  Voodoo Child    ( 263)
-+#       4   + Nov 16 Debbie Harry  Parallel Lines  ( 540)
-+
-+# Using the %I expando:
-+set index_format='%4C %Z %{%b %d} %I (%?l?%4l&%4c?) %s'
-+
-+# This might look like:
-+#       1   + Nov 17 DB Changesbowie    ( 689)
-+#       2   ! Nov 17 SN Rumours         ( 555)
-+#       3   + Nov 16 JH Voodoo Child    ( 263)
-+#       4   + Nov 16 DH Parallel Lines  ( 540)
-+
-+# vim: syntax=muttrc
-diff -urN mutt-1.6.1/doc/muttrc.limit-current-thread mutt-1.6.1-neomutt/doc/muttrc.limit-current-thread
---- mutt-1.6.1/doc/muttrc.limit-current-thread	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/doc/muttrc.limit-current-thread	2016-06-12 18:43:00.697452191 +0100
-@@ -0,0 +1,6 @@
-+# Example Mutt config file for the 'limit-current-thread' patch.
-+ 
-+# Limit view to current thread
-+bind index <esc>L limit-current-thread
-+ 
-+# vim: syntax=muttrc
-diff -urN mutt-1.6.1/doc/muttrc.man.head mutt-1.6.1-neomutt/doc/muttrc.man.head
---- mutt-1.6.1/doc/muttrc.man.head	2016-06-12 18:43:00.403447606 +0100
-+++ mutt-1.6.1-neomutt/doc/muttrc.man.head	2016-06-12 18:43:00.698452206 +0100
-@@ -358,7 +358,24 @@
- \fBcrypt-hook\fPs with the same \fIregexp\fP; multiple matching
- \fBcrypt-hook\fPs result in the use of multiple \fIkey-id\fPs for
- a recipient.
--
-+.PP
-+.nf
-+\fBopen-hook\fP \fIregexp\fP "\fIcommand\fP"
-+\fBclose-hook\fP \fIregexp\fP "\fIcommand\fP"
-+\fBappend-hook\fP \fIregexp\fP "\fIcommand\fP"
-+.fi
-+.IP
-+These commands provide a way to handle compressed folders. The given
-+\fBregexp\fP specifies which folders are taken as compressed (e.g.
-+"\fI\\\\.gz$\fP"). The commands tell Mutt how to uncompress a folder
-+(\fBopen-hook\fP), compress a folder (\fBclose-hook\fP) or append a
-+compressed mail to a compressed folder (\fBappend-hook\fP). The
-+\fIcommand\fP string is the
-+.BR printf (3)
-+like format string, and it should accept two parameters: \fB%f\fP,
-+which is replaced with the (compressed) folder name, and \fB%t\fP
-+which is replaced with the name of the temporary folder to which to
-+write.
- .TP
- \fBpush\fP \fIstring\fP
- This command adds the named \fIstring\fP to the keyboard buffer.
-diff -urN mutt-1.6.1/doc/muttrc.nested-if mutt-1.6.1-neomutt/doc/muttrc.nested-if
---- mutt-1.6.1/doc/muttrc.nested-if	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/doc/muttrc.nested-if	2016-06-12 18:43:00.698452206 +0100
-@@ -0,0 +1,24 @@
-+# Example Mutt config file for the 'nested-if' feature.
++Variables
++---------
 +
-+# This patch uses the format: '%<VAR?TRUE&FALSE>' for conditional
-+# format strings that can be nested.
++    Trash Variables
 +
-+# Example 1
-+# if a thread is folded
-+#       display the number of messages (%M)
-+# else if we know how many lines in the message
-+#       display lines in message (%l)
-+# else display the size of the message in bytes (%c)
-+set index_format='%4C %Z %{%b %d} %-25.25n %s%> %<M?%M Msgs &%<l?%l Lines&%c Bytes>>'
++    | Name  | Type   | Default |
++    |-------|--------|---------|
++    | trash | string | (none)  |
 +
-+# Example 2
-+# if a thread is folded
-+#       display the number of messages (%M)
-+#       display the subject (%s)
-+# else if we know how many lines in the message
-+#       display lines in message (%l)
-+# else
-+#       display the size of the message in bytes (%c)
-+set index_format='%4C %Z %{%b %d} %-25.25n %<M?[%M] %s&%s%* %<l?%l&%c>>'
++Functions
++---------
 +
-+# vim: syntax=muttrc
-diff -urN mutt-1.6.1/doc/muttrc.progress mutt-1.6.1-neomutt/doc/muttrc.progress
---- mutt-1.6.1/doc/muttrc.progress	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/doc/muttrc.progress	2016-06-12 18:43:00.698452206 +0100
-@@ -0,0 +1,10 @@
-+# Example Mutt config file for the 'progress' patch.
++    Trash Functions
 +
-+# The 'progress' patch provides clear visual feedback for
-+# slow tasks, such as indexing a large folder over the net.
++    | Menus       | Default Key | Function          | Description                                                 |
++    |-------------|-------------|-------------------|-------------------------------------------------------------|
++    | index,pager | (none)      | '<purge-message>' | really delete the current entry, bypassing the trash folder |
 +
-+# Set the color of the progress bar
-+# White text on a red background
-+color progress white red
++See Also
++--------
 +
-+# vim: syntax=muttrc
-diff -urN mutt-1.6.1/doc/muttrc.quasi-delete mutt-1.6.1-neomutt/doc/muttrc.quasi-delete
---- mutt-1.6.1/doc/muttrc.quasi-delete	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/doc/muttrc.quasi-delete	2016-06-12 18:43:00.698452206 +0100
-@@ -0,0 +1,7 @@
-+# Example Mutt config file for the 'quasi-delete' feature.
++    * NeoMutt project
++    * folder-hook
 +
-+# The 'quasi-delete' function marks an email that should be hidden
-+# from the index, but NOT deleted.
-+bind index,pager Q quasi-delete
++Known Bugs
++----------
 +
-+# vim: syntax=muttrc
-diff -urN mutt-1.6.1/doc/muttrc.sidebar mutt-1.6.1-neomutt/doc/muttrc.sidebar
---- mutt-1.6.1/doc/muttrc.sidebar	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/doc/muttrc.sidebar	2016-06-12 18:43:00.698452206 +0100
-@@ -0,0 +1,116 @@
-+# This is a complete list of sidebar-related configuration.
++    None
 +
-+# --------------------------------------------------------------------------
-+# VARIABLES - shown with their default values
-+# --------------------------------------------------------------------------
++Credits
++-------
 +
-+# Should the Sidebar be shown?
-+set sidebar_visible = no
++    * Cedric Duval <cedricduval at free.fr>
++    * Benjamin Kuperman <kuperman at acm.org>
++    * Paul Miller <paul at voltar.org>
++    * Richard Russon <rich at flatcap.org>
 +
-+# How wide should the Sidebar be in screen columns?
-+# Note: Some characters, e.g. Chinese, take up two columns each.
-+set sidebar_width = 20
+diff --git a/UPDATING.kz b/UPDATING.kz
+new file mode 100644
+index 0000000..1df36c0
+--- /dev/null
++++ b/UPDATING.kz
+@@ -0,0 +1,68 @@
++1.6.0.1:
 +
-+# Should the mailbox paths be abbreviated?
-+set sidebar_short_path = no
+++ rebase to mutt upstream 1.6.0
+++ update to the new sidebar implementation. Note that all .muttrc options 
++  are prefixed by "sidebar_" now.
 +
-+# When abbreviating mailbox path names, use any of these characters as path
-+# separators.  Only the part after the last separators will be shown.
-+# For file folders '/' is good.  For IMAP folders, often '.' is useful.
-+set sidebar_delim_chars = '/.'
+++ rebase is based on neomutt project (see https://github.com/neomutt) where are
++  maintained all non-upstream mutt changes, so it's easy to merge another
++  features like "trash", "ifdef", ... to mutt-kz.
 +
-+# If the mailbox path is abbreviated, should it be indented?
-+set sidebar_folder_indent = no
+++ the stable mutt-kz releases and tags are maintained in stable/v<version> branches, 
++  the master branch is going to be *rebased*. This development model help us to be 
++  up to date with mutt upstream.
 +
-+# Indent mailbox paths with this string.
-+set sidebar_indent_string = '  '
 +
-+# Make the Sidebar only display mailboxes that contain new, or flagged,
-+# mail.
-+set sidebar_new_mail_only = no
++1.5.23.1:
 +
-+# Any mailboxes that are whitelisted will always be visible, even if the
-+# sidebar_new_mail_only option is enabled.
-+sidebar_whitelist '/home/user/mailbox1'
-+sidebar_whitelist '/home/user/mailbox2'
+++ integrated color status patch (original from Thomas Glanzmann)
++  https://thomas.glanzmann.de//mutt/#cstatus
+++ integrated TLS Server Name Indication support patch (original from Phil Pennock)
+++ improved sidebar functionality to optinaly show only folders with new emails
++  (sidebar-new, sitebar-next, ...)
 +
-+# When searching for mailboxes containing new mail, should the search wrap
-+# around when it reaches the end of the list?
-+set sidebar_next_new_wrap = no
+++ fix notmuch DB usage
+++ use unlocked libc IO in improve performance
+++ security bug fix from original mutt
 +
-+# The character to use as the divider between the Sidebar and the other Mutt
-+# panels.
-+# Note: Only the first character of this string is used.
-+set sidebar_divider_char = '|'
+++ sync with the original mutt upstream
+++ add sidebar_whitelist option
+++ oppenc & pgp upstream sync and improvements
 +
-+# Display the Sidebar mailboxes using this format string.
-+set sidebar_format = '%B%?F? [%F]?%* %?N?%N/?%S'
 +
-+# Sidebar will not refresh its list of mailboxes any more frequently than
-+# this number of seconds.  This will help reduce disk/network traffic.
-+set sidebar_refresh_time = 60
++1.5.22.1:
 +
-+# Sort the mailboxes in the Sidebar using this method:
-+#       count    - total number of messages
-+#       flagged  - number of flagged messages
-+#       new      - number of new messages
-+#       path     - mailbox path
-+#       unsorted - do not sort the mailboxes
-+set sidebar_sort_method = 'unsorted'
+++ use git and github rather than hg to maintain source code
 +
-+# --------------------------------------------------------------------------
-+# FUNCTIONS - shown with an example mapping
-+# --------------------------------------------------------------------------
+++ virtual folders based on notmuch queries
+++ merge sidebar patch
+++ merge index-color patch
 +
-+# Move the highlight to the previous mailbox
-+bind index,pager \Cp sidebar-prev
+++ <change-vfolder> command
+++ <vfolder-from-query> command
+++ <modify-labels> command to set/unset notmuch tags
+++ <modify-labels-then-hide> command to set/unset notmuch tags and hide email
++  from the current view
+++ <quasi-delete> command to delete message from mutt, but don't touch message
++  on the disk
+++ <entire-thread> command to add to the current list of the messages all
++  messages that belongs to the same thread as the current message
+++ ~Y EXPR  pattern modifier for notmuch labels for limit, tag-pattern,
++  delete-pattern, color etc.
+++ virtual-mailboxes <desc> <uri> [...]  to specify list of the virtual mailboxes
+++ virtual_spoolfile = <boolean> to use the first virtual mailbox as a spoolfile
+++ tag-transforms <tag> <transform> to transform tag name to another name
+++ tag-formats <tag> <format sequence> [ ...] to define tag specific formatting
++  sequence for $index_format
+++ nm_record = <boolean> to add sent emails (mutt record) to notmuch DB
+++ nm_record_tags = <comma delimited list> to specify tags for nm_record
+++ nm_open_timeout = <seconds> to specify timeout for notmuch database
+++ nm_default_uri = <uri>  the default URI to connect notmuch
+++ nm_hidden_tags = <comma delimited list> to make some tags invisible for mutt user
+++ nm_exclude_tags = <comma delimited list> - messages tagged with these tags
++  are excluded and not loaded from notmuch DB to mutt unless specified explicitly
+++ nm_unread_tag = <name> to specify unread messages
+++ nm_db_limit = <num> to specify notmuch query limit
+++ nm_query_type = <threads|messages> to specify what to load from DB
+++ vfolder_format = <string> to specify vfolders browser entry format
+++ %g and %Gx index_format and pager_format formatting sequences
+diff --git a/VERSION.neo b/VERSION.neo
+new file mode 100644
+index 0000000..9fcb455
+--- /dev/null
++++ b/VERSION.neo
+@@ -0,0 +1 @@
++-neo
+diff --git a/account.c b/account.c
+index 235ff10..57eba36 100644
+--- a/account.c
++++ b/account.c
+@@ -51,8 +51,17 @@ int mutt_account_match (const ACCOUNT* a1, const ACCOUNT* a2)
+     user = PopUser;
+ #endif
+   
++#ifdef USE_NNTP
++  if (a1->type == M_ACCT_TYPE_NNTP && NntpUser)
++    user = NntpUser;
++#endif
 +
-+# Move the highlight to the next mailbox
-+bind index,pager \Cn sidebar-next
+   if (a1->flags & a2->flags & M_ACCT_USER)
+     return (!strcmp (a1->user, a2->user));
++#ifdef USE_NNTP
++  if (a1->type == M_ACCT_TYPE_NNTP)
++    return a1->flags & M_ACCT_USER && a1->user[0] ? 0 : 1;
++#endif
+   if (a1->flags & M_ACCT_USER)
+     return (!strcmp (a1->user, user));
+   if (a2->flags & M_ACCT_USER)
+@@ -130,6 +139,16 @@ void mutt_account_tourl (ACCOUNT* account, ciss_url_t* url)
+   }
+ #endif
+ 
++#ifdef USE_NNTP
++  if (account->type == M_ACCT_TYPE_NNTP)
++  {
++    if (account->flags & M_ACCT_SSL)
++      url->scheme = U_NNTPS;
++    else
++      url->scheme = U_NNTP;
++  }
++#endif
 +
-+# Open the highlighted mailbox
-+bind index,pager \Co sidebar-open
-+
-+# Move the highlight to the previous page
-+# This is useful if you have a LOT of mailboxes.
-+bind index,pager <F3> sidebar-page-up
-+
-+# Move the highlight to the next page
-+# This is useful if you have a LOT of mailboxes.
-+bind index,pager <F4> sidebar-page-down
+   url->host = account->host;
+   if (account->flags & M_ACCT_PORT)
+     url->port = account->port;
+@@ -155,6 +174,10 @@ int mutt_account_getuser (ACCOUNT* account)
+   else if ((account->type == M_ACCT_TYPE_POP) && PopUser)
+     strfcpy (account->user, PopUser, sizeof (account->user));
+ #endif
++#ifdef USE_NNTP
++  else if ((account->type == M_ACCT_TYPE_NNTP) && NntpUser)
++    strfcpy (account->user, NntpUser, sizeof (account->user));
++#endif
+   else if (option (OPTNOCURSES))
+     return -1;
+   /* prompt (defaults to unix username), copy into account->user */
+@@ -217,6 +240,10 @@ int mutt_account_getpass (ACCOUNT* account)
+   else if ((account->type == M_ACCT_TYPE_SMTP) && SmtpPass)
+     strfcpy (account->pass, SmtpPass, sizeof (account->pass));
+ #endif
++#ifdef USE_NNTP
++  else if ((account->type == M_ACCT_TYPE_NNTP) && NntpPass)
++    strfcpy (account->pass, NntpPass, sizeof (account->pass));
++#endif
+   else if (option (OPTNOCURSES))
+     return -1;
+   else
+diff --git a/account.h b/account.h
+index 774fbfc..d968c1c 100644
+--- a/account.h
++++ b/account.h
+@@ -29,7 +29,8 @@ enum
+   M_ACCT_TYPE_NONE = 0,
+   M_ACCT_TYPE_IMAP,
+   M_ACCT_TYPE_POP,
+-  M_ACCT_TYPE_SMTP
++  M_ACCT_TYPE_SMTP,
++  M_ACCT_TYPE_NNTP
+ };
+ 
+ /* account flags */
+diff --git a/addrbook.c b/addrbook.c
+index 8767a00..345fe87 100644
+--- a/addrbook.c
++++ b/addrbook.c
+@@ -24,6 +24,7 @@
+ #include "mutt_menu.h"
+ #include "mapping.h"
+ #include "sort.h"
++#include "mutt_curses.h"
+ 
+ #include "mutt_idna.h"
+ 
+@@ -43,7 +44,7 @@ static const struct mapping_t AliasHelp[] = {
+ };
+ 
+ static const char *
+-alias_format_str (char *dest, size_t destlen, size_t col, char op, const char *src,
++alias_format_str (char *dest, size_t destlen, size_t col, int cols, char op, const char *src,
+ 		  const char *fmt, const char *ifstring, const char *elsestring,
+ 		  unsigned long data, format_flag flags)
+ {
+@@ -80,7 +81,7 @@ alias_format_str (char *dest, size_t destlen, size_t col, char op, const char *s
+ 
+ static void alias_entry (char *s, size_t slen, MUTTMENU *m, int num)
+ {
+-  mutt_FormatString (s, slen, 0, NONULL (AliasFmt), alias_format_str, (unsigned long) ((ALIAS **) m->data)[num], M_FORMAT_ARROWCURSOR);
++  mutt_FormatString (s, slen, 0, COLS - SidebarWidth, NONULL (AliasFmt), alias_format_str, (unsigned long) ((ALIAS **) m->data)[num], M_FORMAT_ARROWCURSOR);
+ }
+ 
+ static int alias_tag (MUTTMENU *menu, int n, int m)
+diff --git a/alias.c b/alias.c
+index cb653fd..cfc35c4 100644
+--- a/alias.c
++++ b/alias.c
+@@ -27,6 +27,7 @@
+ 
+ #include <string.h>
+ #include <ctype.h>
++#include <errno.h>
+ 
+ ADDRESS *mutt_lookup_alias (const char *s)
+ {
+@@ -379,8 +380,10 @@ retry_name:
+     recode_buf (buf, sizeof (buf));
+     write_safe_address (rc, buf);
+     fputc ('\n', rc);
+-    safe_fclose (&rc);
+-    mutt_message _("Alias added.");
++    if (safe_fsync_close(&rc) != 0)
++      mutt_message ("Trouble adding alias: %s.", strerror(errno));
++    else
++      mutt_message _("Alias added.");
+   }
+   else
+     mutt_perror (buf);
+diff --git a/attach.c b/attach.c
+index 7f0e478..7a77a53 100644
+--- a/attach.c
++++ b/attach.c
+@@ -765,7 +765,7 @@ int mutt_save_attachment (FILE *fp, BODY *m, char *path, int flags, HEADER *hdr)
+       fseeko ((s.fpin = fp), m->offset, 0);
+       mutt_decode_attachment (m, &s);
+       
+-      if (fclose (s.fpout) != 0)
++      if (safe_fsync_close (&s.fpout) != 0)
+       {
+ 	mutt_perror ("fclose");
+ 	mutt_sleep (2);
+@@ -800,7 +800,10 @@ int mutt_save_attachment (FILE *fp, BODY *m, char *path, int flags, HEADER *hdr)
+       return (-1);
+     }
+     safe_fclose (&ofp);
+-    safe_fclose (&nfp);
++    if (safe_fsync_close (&nfp) != 0) {
++      mutt_error _("Write fault!");
++      return (-1);
++    }
+   }
+ 
+   return 0;
+@@ -814,6 +817,7 @@ int mutt_decode_save_attachment (FILE *fp, BODY *m, char *path,
+   unsigned int saved_encoding = 0;
+   BODY *saved_parts = NULL;
+   HEADER *saved_hdr = NULL;
++  int ret = 0;
+ 
+   memset (&s, 0, sizeof (s));
+   s.flags = displaying;
+@@ -871,7 +875,10 @@ int mutt_decode_save_attachment (FILE *fp, BODY *m, char *path,
+ 
+   mutt_body_handler (m, &s);
+ 
+-  safe_fclose (&s.fpout);
++  if (safe_fsync_close (&s.fpout) != 0) {
++    mutt_perror("fclose");
++    ret = -1;
++  }
+   if (fp == NULL)
+   {
+     m->length = 0;
+@@ -885,7 +892,7 @@ int mutt_decode_save_attachment (FILE *fp, BODY *m, char *path,
+     safe_fclose (&s.fpin);
+   }
+ 
+-  return (0);
++  return ret;
+ }
+ 
+ /* Ok, the difference between send and receive:
+diff --git a/attach.h b/attach.h
+index 928408a..071f22c 100644
+--- a/attach.h
++++ b/attach.h
+@@ -50,7 +50,7 @@ void mutt_print_attachment_list (FILE *fp, int tag, BODY *top);
+ 
+ void mutt_attach_bounce (FILE *, HEADER *, ATTACHPTR **, short, BODY *);
+ void mutt_attach_resend (FILE *, HEADER *, ATTACHPTR **, short, BODY *);
+-void mutt_attach_forward (FILE *, HEADER *, ATTACHPTR **, short, BODY *);
++void mutt_attach_forward (FILE *, HEADER *, ATTACHPTR **, short, BODY *, int);
+ void mutt_attach_reply (FILE *, HEADER *, ATTACHPTR **, short, BODY *, int);
+ 
+ #endif /* _ATTACH_H_ */
+diff --git a/browser.c b/browser.c
+index 46919a0..875101b 100644
+--- a/browser.c
++++ b/browser.c
+@@ -29,9 +29,16 @@
+ #include "sort.h"
+ #include "mailbox.h"
+ #include "browser.h"
++#include "mx.h"
+ #ifdef USE_IMAP
+ #include "imap.h"
+ #endif
++#ifdef USE_NOTMUCH
++#include "mutt_notmuch.h"
++#endif
++#ifdef USE_NNTP
++#include "nntp.h"
++#endif
+ 
+ #include <stdlib.h>
+ #include <dirent.h>
+@@ -50,6 +57,19 @@ static const struct mapping_t FolderHelp[] = {
+   { NULL,	 0 }
+ };
+ 
++#ifdef USE_NNTP
++static struct mapping_t FolderNewsHelp[] = {
++  { N_("Exit"),        OP_EXIT },
++  { N_("List"),        OP_TOGGLE_MAILBOXES },
++  { N_("Subscribe"),   OP_BROWSER_SUBSCRIBE },
++  { N_("Unsubscribe"), OP_BROWSER_UNSUBSCRIBE },
++  { N_("Catchup"),     OP_CATCHUP },
++  { N_("Mask"),        OP_ENTER_MASK },
++  { N_("Help"),        OP_HELP },
++  { NULL,              0 }
++};
++#endif
 +
-+# Move the highlight to the previous mailbox containing new, or flagged,
-+# mail.
-+bind index,pager <F5> sidebar-prev-new
+ typedef struct folder_t
+ {
+   struct folder_file *ff;
+@@ -86,6 +106,16 @@ static int browser_compare_subject (const void *a, const void *b)
+   return ((BrowserSort & SORT_REVERSE) ? -r : r);
+ }
+ 
++static int browser_compare_desc (const void *a, const void *b)
++{
++  struct folder_file *pa = (struct folder_file *) a;
++  struct folder_file *pb = (struct folder_file *) b;
 +
-+# Move the highlight to the next mailbox containing new, or flagged, mail.
-+bind index,pager <F6> sidebar-next-new
++  int r = mutt_strcoll (pa->desc, pb->desc);
 +
-+# Toggle the visibility of the Sidebar.
-+bind index,pager B sidebar-toggle-visible
++  return ((BrowserSort & SORT_REVERSE) ? -r : r);
++}
 +
-+# --------------------------------------------------------------------------
-+# COLORS - some unpleasant examples are given
-+# --------------------------------------------------------------------------
-+# Note: All color operations are of the form:
-+#       color OBJECT FOREGROUND BACKGROUND
+ static int browser_compare_date (const void *a, const void *b)
+ {
+   struct folder_file *pa = (struct folder_file *) a;
+@@ -106,6 +136,26 @@ static int browser_compare_size (const void *a, const void *b)
+   return ((BrowserSort & SORT_REVERSE) ? -r : r);
+ }
+ 
++static int browser_compare_count (const void *a, const void *b)
++{
++  struct folder_file *pa = (struct folder_file *) a;
++  struct folder_file *pb = (struct folder_file *) b;
 +
-+# Color of the current, open, mailbox
-+# Note: This is a general Mutt option which colors all selected items.
-+color indicator cyan black
++  int r = pa->all - pb->all;
 +
-+# Color of the highlighted, but not open, mailbox.
-+color sidebar_highlight black color8
++  return ((BrowserSort & SORT_REVERSE) ? -r : r);
++}
 +
-+# Color of the divider separating the Sidebar from Mutt panels
-+color sidebar_divider color8 black
++static int browser_compare_count_new (const void *a, const void *b)
++{
++  struct folder_file *pa = (struct folder_file *) a;
++  struct folder_file *pb = (struct folder_file *) b;
 +
-+# Color to give mailboxes containing flagged mail
-+color sidebar_flagged red black
++  int r = pa->new - pb->new;
 +
-+# Color to give mailboxes containing new mail
-+color sidebar_new green black
++  return ((BrowserSort & SORT_REVERSE) ? -r : r);
++}
 +
-+# --------------------------------------------------------------------------
+ static void browser_sort (struct browser_state *state)
+ {
+   int (*f) (const void *, const void *);
+@@ -115,11 +165,28 @@ static void browser_sort (struct browser_state *state)
+     case SORT_ORDER:
+       return;
+     case SORT_DATE:
++#ifdef USE_NNTP
++      if (option (OPTNEWS))
++	return;
++#endif
+       f = browser_compare_date;
+       break;
+     case SORT_SIZE:
++#ifdef USE_NNTP
++      if (option (OPTNEWS))
++	return;
++#endif
+       f = browser_compare_size;
+       break;
++    case SORT_DESC:
++      f = browser_compare_desc;
++      break;
++    case SORT_COUNT:
++      f = browser_compare_count;
++      break;
++    case SORT_COUNT_NEW:
++      f = browser_compare_count_new;
++      break;
+     case SORT_SUBJECT:
+     default:
+       f = browser_compare_subject;
+@@ -142,7 +209,7 @@ static int link_is_dir (const char *folder, const char *path)
+ }
+ 
+ static const char *
+-folder_format_str (char *dest, size_t destlen, size_t col, char op, const char *src,
++folder_format_str (char *dest, size_t destlen, size_t col, int cols, char op, const char *src,
+ 		   const char *fmt, const char *ifstring, const char *elsestring,
+ 		   unsigned long data, format_flag flags)
+ {
+@@ -192,6 +259,12 @@ folder_format_str (char *dest, size_t destlen, size_t col, char op, const char *
+     case 'f':
+     {
+       char *s;
 +
-+# vim: syntax=muttrc
-diff -urN mutt-1.6.1/doc/muttrc.skip-quoted mutt-1.6.1-neomutt/doc/muttrc.skip-quoted
---- mutt-1.6.1/doc/muttrc.skip-quoted	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/doc/muttrc.skip-quoted	2016-06-12 18:43:00.698452206 +0100
-@@ -0,0 +1,10 @@
-+# Example Mutt config file for the 'skip-quoted' patch.
-+ 
-+# The 'S' (skip-quoted) command scrolls the pager past the quoted text (usually
-+# indented with '> '.  Setting 'skip_quoted_offset' leaves some lines of quoted
-+# text on screen for context.
-+ 
-+# Show three quoted lines before the reply
-+set skip_quoted_offset = 3
-+ 
-+# vim: syntax=muttrc
-diff -urN mutt-1.6.1/doc/muttrc.status-color mutt-1.6.1-neomutt/doc/muttrc.status-color
---- mutt-1.6.1/doc/muttrc.status-color	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/doc/muttrc.status-color	2016-06-12 18:43:00.698452206 +0100
-@@ -0,0 +1,49 @@
-+# Example Mutt config file for the 'status-color' patch.
-+
-+# The 'status-color' patch allows you to theme different parts of
-+# the status bar (also when it's used by the index).
++#ifdef USE_NOTMUCH
++      if (mx_is_notmuch(folder->ff->name))
++        s = NONULL (folder->ff->desc);
++      else
++#endif
+ #ifdef USE_IMAP
+       if (folder->ff->imap)
+ 	s = NONULL (folder->ff->desc);
+@@ -260,7 +333,16 @@ folder_format_str (char *dest, size_t destlen, size_t col, char op, const char *
+       else
+ 	mutt_format_s (dest, destlen, fmt, "");
+       break;
+-      
 +
-+# For the examples below, set some defaults
-+set status_format='-%r-Mutt: %f [Msgs:%?M?%M/?%m%?n? New:%n?%?o? Old:%o?%?d? Del:%d?%?F? Flag:%F?%?t? Tag:%t?%?p? Post:%p?%?b? Inc:%b?%?l? %l?]---(%s/%S)-%>-(%P)---'
-+set index_format='%4C %Z %{%b %d} %-15.15L (%?l?%4l&%4c?) %s'
-+set sort=threads
-+set sort_aux=last-date-received
++    case 'n':
++      if (!optional) {
++	snprintf (tmp, sizeof (tmp), "%%%sd", fmt);
++	snprintf (dest, destlen, tmp, folder->ff->all);
++      } else if (!folder->ff->all) {
++	optional = 0;
++      }
++      break;
 +
-+# 'status color' can take up to 2 extra parameters
+     case 'N':
+ #ifdef USE_IMAP
+       if (mx_is_imap (folder->ff->desc))
+@@ -275,6 +357,18 @@ folder_format_str (char *dest, size_t destlen, size_t col, char op, const char *
+ 	break;
+       }
+ #endif
++#ifdef USE_NOTMUCH
++      if (mx_is_notmuch (folder->ff->name))
++      {
++	if (!optional)
++	{
++	  snprintf (tmp, sizeof (tmp), "%%%sd", fmt);
++	  snprintf (dest, destlen, tmp, folder->ff->new);
++	} else if (!folder->ff->new)
++	  optional = 0;
++	break;
++      }
++#endif
+       snprintf (tmp, sizeof (tmp), "%%%sc", fmt);
+       snprintf (dest, destlen, tmp, folder->ff->new ? 'N' : ' ');
+       break;
+@@ -317,15 +411,119 @@ folder_format_str (char *dest, size_t destlen, size_t col, char op, const char *
+   }
+ 
+   if (optional)
+-    mutt_FormatString (dest, destlen, col, ifstring, folder_format_str, data, 0);
++    mutt_FormatString (dest, destlen, col, cols, ifstring, folder_format_str, data, 0);
+   else if (flags & M_FORMAT_OPTIONAL)
+-    mutt_FormatString (dest, destlen, col, elsestring, folder_format_str, data, 0);
++    mutt_FormatString (dest, destlen, col, cols, elsestring, folder_format_str, data, 0);
 +
-+# color status foreground background [ regex [ num ]]
++  return (src);
++}
 +
-+# 0 extra parameters
-+# Set the default color for the entire status line
-+color status blue white
++#ifdef USE_NNTP
++static const char *
++newsgroup_format_str (char *dest, size_t destlen, size_t col, int cols, char op, const char *src,
++		      const char *fmt, const char *ifstring, const char *elsestring,
++		      unsigned long data, format_flag flags)
++{
++  char fn[SHORT_STRING], tmp[SHORT_STRING];
++  FOLDER *folder = (FOLDER *) data;
 +
-+# 1 extra parameter
-+# Set the color for a matching pattern
-+# color status foreground background regexp
++  switch (op)
++  {
++    case 'C':
++      snprintf (tmp, sizeof (tmp), "%%%sd", fmt);
++      snprintf (dest, destlen, tmp, folder->num + 1);
++      break;
 +
-+# Highlight New, Deleted, or Flagged emails
-+color status brightred white '(New|Del|Flag):[0-9]+'
++    case 'f':
++      strncpy (fn, folder->ff->name, sizeof(fn) - 1);
++      snprintf (tmp, sizeof (tmp), "%%%ss", fmt);
++      snprintf (dest, destlen, tmp, fn);
++      break;
 +
-+# Highlight mailbox ordering if it's different from the default
-+# First, highlight anything (*/*)
-+color status brightred default '\([^)]+/[^)]+\)'
++    case 'N':
++      snprintf (tmp, sizeof (tmp), "%%%sc", fmt);
++      if (folder->ff->nd->subscribed)
++	snprintf (dest, destlen, tmp, ' ');
++      else
++	snprintf (dest, destlen, tmp, folder->ff->new ? 'N' : 'u');
++      break;
 +
-+# Then override the color for one specific case
-+color status default   default '\(threads/last-date-received\)'
++    case 'M':
++      snprintf (tmp, sizeof (tmp), "%%%sc", fmt);
++      if (folder->ff->nd->deleted)
++	snprintf (dest, destlen, tmp, 'D');
++      else
++	snprintf (dest, destlen, tmp, folder->ff->nd->allowed ? ' ' : '-');
++      break;
+ 
++    case 's':
++      if (flags & M_FORMAT_OPTIONAL)
++      {
++	if (folder->ff->nd->unread != 0)
++	  mutt_FormatString (dest, destlen, col, cols, ifstring, newsgroup_format_str,
++		data, flags);
++	else
++	  mutt_FormatString (dest, destlen, col, cols, elsestring, newsgroup_format_str,
++		data, flags);
++      }
++      else if (Context && Context->data == folder->ff->nd)
++      {
++	snprintf (tmp, sizeof (tmp), "%%%sd", fmt);
++	snprintf (dest, destlen, tmp, Context->unread);
++      }
++      else
++      {
++	snprintf (tmp, sizeof (tmp), "%%%sd", fmt);
++	snprintf (dest, destlen, tmp, folder->ff->nd->unread);
++      }
++      break;
 +
-+# 2 extra parameters
-+# Set the color for the nth submatch of a pattern
-+# color status foreground background regexp num
++    case 'n':
++      if (Context && Context->data == folder->ff->nd)
++      {
++	snprintf (tmp, sizeof (tmp), "%%%sd", fmt);
++	snprintf (dest, destlen, tmp, Context->new);
++      }
++      else if (option (OPTMARKOLD) &&
++		folder->ff->nd->lastCached >= folder->ff->nd->firstMessage &&
++		folder->ff->nd->lastCached <= folder->ff->nd->lastMessage)
++      {
++	snprintf (tmp, sizeof (tmp), "%%%sd", fmt);
++	snprintf (dest, destlen, tmp, folder->ff->nd->lastMessage - folder->ff->nd->lastCached);
++      }
++      else
++      {
++	snprintf (tmp, sizeof (tmp), "%%%sd", fmt);
++	snprintf (dest, destlen, tmp, folder->ff->nd->unread);
++      }
++      break;
 +
-+# Highlight the contents of the []s but not the [] themselves
-+color status red default '\[([^]]+)\]' 1
++    case 'd':
++      if (folder->ff->nd->desc != NULL)
++      {
++	char *buf = safe_strdup (folder->ff->nd->desc);
++	if (NewsgroupsCharset && *NewsgroupsCharset)
++	  mutt_convert_string (&buf, NewsgroupsCharset, Charset, M_ICONV_HOOK_FROM);
++	mutt_filter_unprintable (&buf);
 +
-+# The '1' refers to the first regex submatch, which is the inner
-+# part in ()s
++	snprintf (tmp, sizeof (tmp), "%%%ss", fmt);
++	snprintf (dest, destlen, tmp, buf);
++	FREE (&buf);
++      }
++      else
++      {
++	snprintf (tmp, sizeof (tmp), "%%%ss", fmt);
++	snprintf (dest, destlen, tmp, "");
++      }
++      break;
++  }
+   return (src);
+ }
++#endif /* USE_NNTP */
+ 
+ static void add_folder (MUTTMENU *m, struct browser_state *state,
+-			const char *name, const struct stat *s, unsigned int new)
++		const char *name, const char *desc, const struct stat *s,
++		unsigned int new, unsigned int all, void *data)
+ {
+   if (state->entrylen == state->entrymax)
+   {
+@@ -349,11 +547,16 @@ static void add_folder (MUTTMENU *m, struct browser_state *state,
+   }
+ 
+   (state->entry)[state->entrylen].new = new;
++  (state->entry)[state->entrylen].all = all;
+   (state->entry)[state->entrylen].name = safe_strdup (name);
+-  (state->entry)[state->entrylen].desc = safe_strdup (name);
++  (state->entry)[state->entrylen].desc = safe_strdup(desc ? desc : name);
+ #ifdef USE_IMAP
+   (state->entry)[state->entrylen].imap = 0;
+ #endif
++#ifdef USE_NNTP
++  if (option (OPTNEWS))
++    (state->entry)[state->entrylen].nd = (NNTP_DATA *)data;
++#endif
+   (state->entrylen)++;
+ }
+ 
+@@ -369,9 +572,35 @@ static void init_state (struct browser_state *state, MUTTMENU *menu)
+     menu->data = state->entry;
+ }
+ 
++/* get list of all files/newsgroups with mask */
+ static int examine_directory (MUTTMENU *menu, struct browser_state *state,
+ 			      char *d, const char *prefix)
+ {
++#ifdef USE_NNTP
++  if (option (OPTNEWS))
++  {
++    NNTP_SERVER *nserv = CurrentNewsSrv;
++    unsigned int i;
 +
-+# Highlight the mailbox
-+color status brightwhite default 'Mutt: ([^ ]+)' 1
++/*  mutt_buffy_check (0); */
++    init_state (state, menu);
 +
-+# Search for 'Mutt: ' but only highlight what comes after it
++    for (i = 0; i < nserv->groups_num; i++)
++    {
++      NNTP_DATA *nntp_data = nserv->groups_list[i];
++      if (!nntp_data)
++	continue;
++      if (prefix && *prefix &&
++	  strncmp (prefix, nntp_data->group, strlen (prefix)))
++	continue;
++      if (!((regexec (Mask.rx, nntp_data->group, 0, NULL, 0) == 0) ^ Mask.not))
++	continue;
++      add_folder (menu, state, nntp_data->group, NULL, NULL, nntp_data->new, nntp_data->newsrc_len, nntp_data);
++    }
++  }
++  else
++#endif /* USE_NNTP */
++  {
+   struct stat s;
+   DIR *dp;
+   struct dirent *de;
+@@ -432,17 +661,66 @@ static int examine_directory (MUTTMENU *menu, struct browser_state *state,
+     tmp = Incoming;
+     while (tmp && mutt_strcmp (buffer, tmp->path))
+       tmp = tmp->next;
+-    add_folder (menu, state, de->d_name, &s, (tmp) ? tmp->new : 0);
++    add_folder (menu, state, de->d_name, NULL, &s, (tmp) ? tmp->new : 0, (tmp) ? tmp->msg_count : 0, NULL);
+   }
+   closedir (dp);  
++  }
+   browser_sort (state);
+   return 0;
+ }
+ 
++#ifdef USE_NOTMUCH
++static int examine_vfolders (MUTTMENU *menu, struct browser_state *state)
++{
++  BUFFY *tmp = VirtIncoming;
 +
-+# vim: syntax=muttrc
-diff -urN mutt-1.6.1/doc/muttrc.trash mutt-1.6.1-neomutt/doc/muttrc.trash
---- mutt-1.6.1/doc/muttrc.trash	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/doc/muttrc.trash	2016-06-12 18:43:00.698452206 +0100
-@@ -0,0 +1,16 @@
-+# Example Mutt config file for the 'trash' feature.
-+
-+# This feature defines a new 'trash' folder.
-+# When mail is deleted it will be moved to this folder.
-+
-+# Folder in which to put deleted emails
-+set trash='+Trash'
-+set trash='/home/flatcap/Mail/Trash'
-+
-+# The default delete key 'd' will move an email to the 'trash' folder
-+# Bind 'D' to REALLY delete an email
-+bind index D purge-message
-+
-+# Note: Deleting emails from the 'trash' folder will REALLY delete them.
-+
-+# vim: syntax=muttrc
-diff -urN mutt-1.6.1/doc/vimrc-compress mutt-1.6.1-neomutt/doc/vimrc-compress
---- mutt-1.6.1/doc/vimrc-compress	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/doc/vimrc-compress	2016-06-12 18:43:00.699452222 +0100
-@@ -0,0 +1,7 @@
-+" Vim syntax file for the mutt compress patch
-+
-+syntax keyword muttrcCommand    append-hook
-+syntax keyword muttrcCommand    close-hook
-+syntax keyword muttrcCommand    open-hook
-+
-+" vim: syntax=vim
-diff -urN mutt-1.6.1/doc/vimrc.ifdef mutt-1.6.1-neomutt/doc/vimrc.ifdef
---- mutt-1.6.1/doc/vimrc.ifdef	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/doc/vimrc.ifdef	2016-06-12 18:43:00.699452222 +0100
-@@ -0,0 +1,7 @@
-+" Vim syntax file for the mutt ifdef patch
++  if (!VirtIncoming)
++    return (-1);
++  mutt_buffy_check (0);
 +
-+syntax keyword muttrcCommand    ifdef
-+syntax keyword muttrcCommand    ifndef
-+syntax keyword muttrcCommand    finish
++  init_state (state, menu);
 +
-+" vim: syntax=vim
-diff -urN mutt-1.6.1/doc/vimrc.index-color mutt-1.6.1-neomutt/doc/vimrc.index-color
---- mutt-1.6.1/doc/vimrc.index-color	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/doc/vimrc.index-color	2016-06-12 18:43:00.699452222 +0100
-@@ -0,0 +1,13 @@
-+" Vim syntax file for the mutt index-color patch
++  do
++  {
++    if (mx_is_notmuch (tmp->path))
++    {
++      nm_nonctx_get_count(tmp->path, &tmp->msg_count, &tmp->msg_unread);
++      add_folder (menu, state, tmp->path, tmp->desc, NULL, tmp->msg_unread, tmp->msg_count, NULL);
++      continue;
++    }
++  }
++  while ((tmp = tmp->next));
++  browser_sort (state);
++  return 0;
++}
++#endif
 +
-+syntax keyword muttrcColorField contained index
-+syntax keyword muttrcColorField contained index_author
-+syntax keyword muttrcColorField contained index_collapsed
-+syntax keyword muttrcColorField contained index_date
-+syntax keyword muttrcColorField contained index_flags
-+syntax keyword muttrcColorField contained index_label
-+syntax keyword muttrcColorField contained index_number
-+syntax keyword muttrcColorField contained index_size
-+syntax keyword muttrcColorField contained index_subject
++/* get list of mailboxes/subscribed newsgroups */
+ static int examine_mailboxes (MUTTMENU *menu, struct browser_state *state)
+ {
+   struct stat s;
+   char buffer[LONG_STRING];
 +
-+" vim: syntax=vim
-diff -urN mutt-1.6.1/doc/vimrc-keywords mutt-1.6.1-neomutt/doc/vimrc-keywords
---- mutt-1.6.1/doc/vimrc-keywords	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/doc/vimrc-keywords	2016-06-12 18:43:00.699452222 +0100
-@@ -0,0 +1,10 @@
-+" Vim syntax file for the mutt keywords patch
++#ifdef USE_NNTP
++  if (option (OPTNEWS))
++  {
++    NNTP_SERVER *nserv = CurrentNewsSrv;
++    unsigned int i;
 +
-+syntax keyword muttrcVarBool    skipwhite contained keywords_legacy       nextgroup=muttrcSetBoolAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-+syntax keyword muttrcVarBool    skipwhite contained keywords_standard     nextgroup=muttrcSetBoolAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
++/*  mutt_buffy_check (0); */
++    init_state (state, menu);
 +
-+syntax keyword muttrcVarStr     contained skipwhite xlabel_delimiter      nextgroup=muttrcVarEqualsIdxFmt
++    for (i = 0; i < nserv->groups_num; i++)
++    {
++      NNTP_DATA *nntp_data = nserv->groups_list[i];
++      if (nntp_data && (nntp_data->new || (nntp_data->subscribed &&
++	 (nntp_data->unread || !option (OPTSHOWONLYUNREAD)))))
++	add_folder (menu, state, nntp_data->group, NULL, NULL, nntp_data->new, nntp_data->newsrc_len, nntp_data);
++    }
++  }
++  else
++#endif
++  {
+   BUFFY *tmp = Incoming;
+ #ifdef USE_IMAP
+   struct mailbox_state mbox;
+@@ -460,14 +738,21 @@ static int examine_mailboxes (MUTTMENU *menu, struct browser_state *state)
+     if (mx_is_imap (tmp->path))
+     {
+       imap_mailbox_state (tmp->path, &mbox);
+-      add_folder (menu, state, tmp->path, NULL, mbox.new);
++      add_folder (menu, state, tmp->path, NULL, NULL, mbox.new, mbox.messages, NULL);
+       continue;
+     }
+ #endif
+ #ifdef USE_POP
+     if (mx_is_pop (tmp->path))
+     {
+-      add_folder (menu, state, tmp->path, NULL, tmp->new);
++      add_folder (menu, state, tmp->path, NULL, NULL, tmp->new, tmp->msg_count, NULL);
++      continue;
++    }
++#endif
++#ifdef USE_NNTP
++    if (mx_is_nntp (tmp->path))
++    {
++      add_folder (menu, state, tmp->path, NULL, NULL, tmp->new, tmp->msg_count, NULL);
+       continue;
+     }
+ #endif
+@@ -496,18 +781,30 @@ static int examine_mailboxes (MUTTMENU *menu, struct browser_state *state)
+     strfcpy (buffer, NONULL(tmp->path), sizeof (buffer));
+     mutt_pretty_mailbox (buffer, sizeof (buffer));
+ 
+-    add_folder (menu, state, buffer, &s, tmp->new);
++    add_folder (menu, state, buffer, NULL, &s, tmp->new, tmp->msg_count, NULL);
+   }
+   while ((tmp = tmp->next));
++  }
+   browser_sort (state);
+   return 0;
+ }
+ 
+ static int select_file_search (MUTTMENU *menu, regex_t *re, int n)
+ {
++#ifdef USE_NNTP
++  if (option (OPTNEWS))
++    return (regexec (re, ((struct folder_file *) menu->data)[n].desc, 0, NULL, 0));
++#endif
+   return (regexec (re, ((struct folder_file *) menu->data)[n].name, 0, NULL, 0));
+ }
+ 
++#ifdef USE_NOTMUCH
++static int select_vfolder_search (MUTTMENU *menu, regex_t *re, int n)
++{
++  return (regexec (re, ((struct folder_file *) menu->data)[n].desc, 0, NULL, 0));
++}
++#endif
 +
-+syntax match muttrcFunction     contained "\<edit-label\>"
+ static void folder_entry (char *s, size_t slen, MUTTMENU *menu, int num)
+ {
+   FOLDER folder;
+@@ -515,10 +812,29 @@ static void folder_entry (char *s, size_t slen, MUTTMENU *menu, int num)
+   folder.ff = &((struct folder_file *) menu->data)[num];
+   folder.num = num;
+   
+-  mutt_FormatString (s, slen, 0, NONULL(FolderFormat), folder_format_str, 
++#ifdef USE_NNTP
++  if (option (OPTNEWS))
++    mutt_FormatString (s, slen, 0, COLS - SidebarWidth, NONULL(GroupFormat), newsgroup_format_str, 
++      (unsigned long) &folder, M_FORMAT_ARROWCURSOR);
++  else
++#endif
++  mutt_FormatString (s, slen, 0, COLS - SidebarWidth, NONULL(FolderFormat), folder_format_str, 
+       (unsigned long) &folder, M_FORMAT_ARROWCURSOR);
+ }
+ 
++#ifdef USE_NOTMUCH
++static void vfolder_entry (char *s, size_t slen, MUTTMENU *menu, int num)
++{
++  FOLDER folder;
 +
-+" vim: syntax=vim
-diff -urN mutt-1.6.1/doc/vimrc-nntp mutt-1.6.1-neomutt/doc/vimrc-nntp
---- mutt-1.6.1/doc/vimrc-nntp	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/doc/vimrc-nntp	2016-06-12 18:43:00.699452222 +0100
-@@ -0,0 +1,50 @@
-+" Vim syntax file for the mutt nntp patch
++  folder.ff = &((struct folder_file *) menu->data)[num];
++  folder.num = num;
 +
-+syntax keyword muttrcVarBool    skipwhite contained ask_follow_up         nextgroup=muttrcSetBoolAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-+syntax keyword muttrcVarBool    skipwhite contained ask_x_comment_to      nextgroup=muttrcSetBoolAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-+syntax keyword muttrcVarBool    skipwhite contained mime_subject          nextgroup=muttrcSetBoolAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-+syntax keyword muttrcVarBool    skipwhite contained nntp_listgroup        nextgroup=muttrcSetBoolAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-+syntax keyword muttrcVarBool    skipwhite contained nntp_load_description nextgroup=muttrcSetBoolAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-+syntax keyword muttrcVarBool    skipwhite contained save_unsubscribed     nextgroup=muttrcSetBoolAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-+syntax keyword muttrcVarBool    skipwhite contained show_new_news         nextgroup=muttrcSetBoolAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-+syntax keyword muttrcVarBool    skipwhite contained show_only_unread      nextgroup=muttrcSetBoolAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-+syntax keyword muttrcVarBool    skipwhite contained x_comment_to          nextgroup=muttrcSetBoolAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
++  mutt_FormatString (s, slen, 0, COLS - SidebarWidth, NONULL(VirtFolderFormat), folder_format_str,
++      (unsigned long) &folder, M_FORMAT_ARROWCURSOR);
++}
++#endif
 +
-+syntax keyword muttrcVarNum     skipwhite contained nntp_context          nextgroup=muttrcSetNumAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-+syntax keyword muttrcVarNum     skipwhite contained nntp_poll             nextgroup=muttrcSetNumAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
+ static void init_menu (struct browser_state *state, MUTTMENU *menu, char *title,
+ 		       size_t titlelen, int buffy)
+ {
+@@ -535,6 +851,17 @@ static void init_menu (struct browser_state *state, MUTTMENU *menu, char *title,
+ 
+   menu->tagged = 0;
+   
++#ifdef USE_NNTP
++  if (option (OPTNEWS))
++  {
++    if (buffy)
++      snprintf (title, titlelen, _("Subscribed newsgroups"));
++    else
++      snprintf (title, titlelen, _("Newsgroups on server [%s]"),
++		CurrentNewsSrv->conn->account.host);
++  }
++  else
++#endif
+   if (buffy)
+     snprintf (title, titlelen, _("Mailboxes [%d]"), mutt_buffy_check (0));
+   else
+@@ -584,12 +911,37 @@ void _mutt_select_file (char *f, size_t flen, int flags, char ***files, int *num
+   int buffy    = (flags & M_SEL_BUFFY)  ? 1 : 0;
+ 
+   buffy = buffy && folder;
+-  
 +
-+syn keyword muttrcVarQuad	skipwhite contained catchup_newsgroup     nextgroup=muttrcSetQuadAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-+syn keyword muttrcVarQuad	skipwhite contained followup_to_poster    nextgroup=muttrcSetQuadAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-+syn keyword muttrcVarQuad	skipwhite contained post_moderated        nextgroup=muttrcSetQuadAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
+   memset (&state, 0, sizeof (struct browser_state));
+ 
+   if (!folder)
+     strfcpy (LastDirBackup, LastDir, sizeof (LastDirBackup));
+ 
++#ifdef USE_NNTP
++  if (option (OPTNEWS))
++  {
++    if (*f)
++      strfcpy (prefix, f, sizeof (prefix));
++    else
++    {
++      NNTP_SERVER *nserv = CurrentNewsSrv;
++      unsigned int i;
 +
-+syntax keyword muttrcVarStr     contained skipwhite group_index_format    nextgroup=muttrcVarEqualsIdxFmt
-+syntax keyword muttrcVarStr     contained skipwhite inews                 nextgroup=muttrcVarEqualsIdxFmt
-+syntax keyword muttrcVarStr     contained skipwhite newsgroups_charset    nextgroup=muttrcVarEqualsIdxFmt
-+syntax keyword muttrcVarStr     contained skipwhite newsrc                nextgroup=muttrcVarEqualsIdxFmt
-+syntax keyword muttrcVarStr     contained skipwhite news_cache_dir        nextgroup=muttrcVarEqualsIdxFmt
-+syntax keyword muttrcVarStr     contained skipwhite news_server           nextgroup=muttrcVarEqualsIdxFmt
-+syntax keyword muttrcVarStr     contained skipwhite nntp_authenticators   nextgroup=muttrcVarEqualsIdxFmt
-+syntax keyword muttrcVarStr     contained skipwhite nntp_pass             nextgroup=muttrcVarEqualsIdxFmt
-+syntax keyword muttrcVarStr     contained skipwhite nntp_user             nextgroup=muttrcVarEqualsIdxFmt
++      /* default state for news reader mode is browse subscribed newsgroups */
++      buffy = 0;
++      for (i = 0; i < nserv->groups_num; i++)
++      {
++	NNTP_DATA *nntp_data = nserv->groups_list[i];
++	if (nntp_data && nntp_data->subscribed)
++	{
++	  buffy = 1;
++	  break;
++	}
++      }
++    }
++  }
++  else
++#endif
+   if (*f)
+   {
+     mutt_expand_path (f, flen);
+@@ -637,13 +989,17 @@ void _mutt_select_file (char *f, size_t flen, int flags, char ***files, int *num
+     }
+ #endif
+   }
+-  else 
++#ifdef USE_NOTMUCH
++  else if (!(flags & M_SEL_VFOLDER))
++#else
++  else
++#endif
+   {
+     if (!folder)
+       getcwd (LastDir, sizeof (LastDir));
+     else if (!LastDir[0])
+       strfcpy (LastDir, NONULL(Maildir), sizeof (LastDir));
+-    
 +
-+syntax match muttrcFunction     contained "\<attach-news-message>"
-+syntax match muttrcFunction     contained "\<catchup>"
-+syntax match muttrcFunction     contained "\<change-newsgroup-readonly>"
-+syntax match muttrcFunction     contained "\<change-newsgroup>"
-+syntax match muttrcFunction     contained "\<edit-followup-to>"
-+syntax match muttrcFunction     contained "\<edit-newsgroups>"
-+syntax match muttrcFunction     contained "\<edit-x-comment-to>"
-+syntax match muttrcFunction     contained "\<followup-message>"
-+syntax match muttrcFunction     contained "\<forward-to-group>"
-+syntax match muttrcFunction     contained "\<get-children>"
-+syntax match muttrcFunction     contained "\<get-message>"
-+syntax match muttrcFunction     contained "\<get-parent>"
-+syntax match muttrcFunction     contained "\<post-message>"
-+syntax match muttrcFunction     contained "\<reconstruct-thread>"
-+syntax match muttrcFunction     contained "\<reload-active>"
-+syntax match muttrcFunction     contained "\<subscribe-pattern>"
-+syntax match muttrcFunction     contained "\<toggle-read>"
-+syntax match muttrcFunction     contained "\<uncatchup>"
-+syntax match muttrcFunction     contained "\<unsubscribe-pattern>"
-+
-+" vim: syntax=vim
-diff -urN mutt-1.6.1/doc/vimrc.progress mutt-1.6.1-neomutt/doc/vimrc.progress
---- mutt-1.6.1/doc/vimrc.progress	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/doc/vimrc.progress	2016-06-12 18:43:00.699452222 +0100
-@@ -0,0 +1,5 @@
-+" Vim syntax file for the mutt progress patch
+ #ifdef USE_IMAP
+     if (!buffy && mx_is_imap (LastDir))
+     {
+@@ -665,6 +1021,12 @@ void _mutt_select_file (char *f, size_t flen, int flags, char ***files, int *num
+ 
+   *f = 0;
+ 
++#ifdef USE_NOTMUCH
++  if (flags & M_SEL_VFOLDER) {
++    if (examine_vfolders (NULL, &state) == -1)
++      goto bail;
++  } else
++#endif
+   if (buffy)
+   {
+     if (examine_mailboxes (NULL, &state) == -1)
+@@ -674,18 +1036,29 @@ void _mutt_select_file (char *f, size_t flen, int flags, char ***files, int *num
+ #ifdef USE_IMAP
+   if (!state.imap_browse)
+ #endif
++  {
+   if (examine_directory (NULL, &state, LastDir, prefix) == -1)
+     goto bail;
+-
++  }
+   menu = mutt_new_menu (MENU_FOLDER);
+-  menu->make_entry = folder_entry;
+   menu->search = select_file_search;
+   menu->title = title;
+   menu->data = state.entry;
+   if (multiple)
+     menu->tag = file_tag;
+ 
++#ifdef USE_NOTMUCH
++  if (flags & M_SEL_VFOLDER) {
++    menu->make_entry = vfolder_entry;
++    menu->search = select_vfolder_search;
++  } else
++#endif
++    menu->make_entry = folder_entry;
 +
-+syntax keyword muttrcColorField contained progress
+   menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_FOLDER,
++#ifdef USE_NNTP
++    option (OPTNEWS) ? FolderNewsHelp :
++#endif
+     FolderHelp);
+ 
+   init_menu (&state, menu, title, sizeof (title), buffy);
+@@ -824,7 +1197,11 @@ void _mutt_select_file (char *f, size_t flen, int flags, char ***files, int *num
+ 	  }
+ 	}
+ 
++#ifdef USE_NNTP
++	if (buffy || option (OPTNEWS))
++#else
+ 	if (buffy)
++#endif
+ 	{
+ 	  strfcpy (f, state.entry[menu->current].name, flen);
+ 	  mutt_expand_path (f, flen);
+@@ -833,6 +1210,10 @@ void _mutt_select_file (char *f, size_t flen, int flags, char ***files, int *num
+ 	else if (state.imap_browse)
+           strfcpy (f, state.entry[menu->current].name, flen);
+ #endif
++#ifdef USE_NOTMUCH
++	else if (mx_is_notmuch(state.entry[menu->current].name))
++	  strfcpy (f, state.entry[menu->current].name, flen);
++#endif
+ 	else
+ 	  mutt_concat_path (f, LastDir, state.entry[menu->current].name, flen);
+ 
+@@ -882,14 +1263,6 @@ void _mutt_select_file (char *f, size_t flen, int flags, char ***files, int *num
+         break;
+ 
+ #ifdef USE_IMAP
+-      case OP_BROWSER_SUBSCRIBE:
+-	imap_subscribe (state.entry[menu->current].name, 1);
+-	break;
+-
+-      case OP_BROWSER_UNSUBSCRIBE:
+-	imap_subscribe (state.entry[menu->current].name, 0);
+-	break;
+-
+       case OP_BROWSER_TOGGLE_LSUB:
+ 	if (option (OPTIMAPLSUB))
+ 	  unset_option (OPTIMAPLSUB);
+@@ -987,9 +1360,14 @@ void _mutt_select_file (char *f, size_t flen, int flags, char ***files, int *num
+         }
+         break;
+ #endif
+-      
 +
-+" vim: syntax=vim
-diff -urN mutt-1.6.1/doc/vimrc.quasi-delete mutt-1.6.1-neomutt/doc/vimrc.quasi-delete
---- mutt-1.6.1/doc/vimrc.quasi-delete	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/doc/vimrc.quasi-delete	2016-06-12 18:43:00.699452222 +0100
-@@ -0,0 +1,5 @@
-+" Vim syntax file for the mutt quasi-delete patch
+       case OP_CHANGE_DIRECTORY:
+ 
++#ifdef USE_NNTP
++	if (option (OPTNEWS))
++	  break;
++#endif
 +
-+syntax match muttrcFunction     contained "\<quasi-delete\>"
+ 	strfcpy (buf, LastDir, sizeof (buf));
+ #ifdef USE_IMAP
+ 	if (!state.imap_browse)
+@@ -1136,9 +1514,9 @@ void _mutt_select_file (char *f, size_t flen, int flags, char ***files, int *num
+ 	  int reverse = (i == OP_SORT_REVERSE);
+ 	  
+ 	  switch (mutt_multi_choice ((reverse) ?
+-	      _("Reverse sort by (d)ate, (a)lpha, si(z)e or do(n)'t sort? ") :
+-	      _("Sort by (d)ate, (a)lpha, si(z)e or do(n)'t sort? "),
+-	      _("dazn")))
++	      _("Reverse sort by (d)ate, (a)lpha, si(z)e, d(e)scription, (c)ount, ne(w) count, or do(n)'t sort? ") :
++	      _("Sort by (d)ate, (a)lpha, si(z)e, d(e)scription, (c)ount, ne(w) count, or do(n)'t sort? "),
++	      _("dazecwn")))
+ 	  {
+ 	    case -1: /* abort */
+ 	      resort = 0;
+@@ -1156,7 +1534,19 @@ void _mutt_select_file (char *f, size_t flen, int flags, char ***files, int *num
+ 	      BrowserSort = SORT_SIZE;
+ 	      break;
+ 
+-            case 4: /* do(n)'t sort */
++            case 4: /* d(e)scription */
++	      BrowserSort = SORT_DESC;
++	      break;
 +
-+" vim: syntax=vim
-diff -urN mutt-1.6.1/doc/vimrc.sidebar mutt-1.6.1-neomutt/doc/vimrc.sidebar
---- mutt-1.6.1/doc/vimrc.sidebar	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/doc/vimrc.sidebar	2016-06-12 18:43:00.699452222 +0100
-@@ -0,0 +1,35 @@
-+" Vim syntax file for the mutt sidebar patch
++            case 5: /* (c)ount */
++	      BrowserSort = SORT_COUNT;
++	      break;
 +
-+syntax keyword muttrcVarBool    skipwhite contained sidebar_folder_indent nextgroup=muttrcSetBoolAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-+syntax keyword muttrcVarBool    skipwhite contained sidebar_new_mail_only nextgroup=muttrcSetBoolAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-+syntax keyword muttrcVarBool    skipwhite contained sidebar_next_new_wrap nextgroup=muttrcSetBoolAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-+syntax keyword muttrcVarBool    skipwhite contained sidebar_short_path    nextgroup=muttrcSetBoolAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-+syntax keyword muttrcVarBool    skipwhite contained sidebar_visible       nextgroup=muttrcSetBoolAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
++            case 6: /* ne(w) count */
++	      BrowserSort = SORT_COUNT_NEW;
++	      break;
 +
-+syntax keyword muttrcVarNum     skipwhite contained sidebar_refresh_time  nextgroup=muttrcSetNumAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
-+syntax keyword muttrcVarNum     skipwhite contained sidebar_width         nextgroup=muttrcSetNumAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
++            case 7: /* do(n)'t sort */
+ 	      BrowserSort = SORT_ORDER;
+ 	      resort = 0;
+ 	      break;
+@@ -1255,6 +1645,209 @@ void _mutt_select_file (char *f, size_t flen, int flags, char ***files, int *num
+ 	  else
+ 	    mutt_error _("Error trying to view file");
+ 	}
++	break;
 +
-+syntax keyword muttrcVarStr     contained skipwhite sidebar_divider_char  nextgroup=muttrcVarEqualsIdxFmt
-+syntax keyword muttrcVarStr     contained skipwhite sidebar_delim_chars   nextgroup=muttrcVarEqualsIdxFmt
-+syntax keyword muttrcVarStr     contained skipwhite sidebar_format        nextgroup=muttrcVarEqualsIdxFmt
-+syntax keyword muttrcVarStr     contained skipwhite sidebar_indent_string nextgroup=muttrcVarEqualsIdxFmt
-+syntax keyword muttrcVarStr     contained skipwhite sidebar_sort_method   nextgroup=muttrcVarEqualsIdxFmt
++#ifdef USE_NNTP
++      case OP_CATCHUP:
++      case OP_UNCATCHUP:
++	if (option (OPTNEWS))
++	{
++	  struct folder_file *f = &state.entry[menu->current];
++	  int rc;
++	  NNTP_DATA *nntp_data;
 +
-+syntax keyword muttrcCommand    sidebar_whitelist
++	  rc = nntp_newsrc_parse (CurrentNewsSrv);
++	  if (rc < 0)
++	    break;
 +
-+syntax match muttrcFunction     contained "\<sidebar-next\>"
-+syntax match muttrcFunction     contained "\<sidebar-next-new\>"
-+syntax match muttrcFunction     contained "\<sidebar-open\>"
-+syntax match muttrcFunction     contained "\<sidebar-page-down\>"
-+syntax match muttrcFunction     contained "\<sidebar-page-up\>"
-+syntax match muttrcFunction     contained "\<sidebar-prev\>"
-+syntax match muttrcFunction     contained "\<sidebar-prev-new\>"
-+syntax match muttrcFunction     contained "\<sidebar-toggle-visible\>"
++	  if (i == OP_CATCHUP)
++	    nntp_data = mutt_newsgroup_catchup (CurrentNewsSrv, f->name);
++	  else
++	    nntp_data = mutt_newsgroup_uncatchup (CurrentNewsSrv, f->name);
 +
-+syntax keyword muttrcColorField contained sidebar_divider
-+syntax keyword muttrcColorField contained sidebar_flagged
-+syntax keyword muttrcColorField contained sidebar_highlight
-+syntax keyword muttrcColorField contained sidebar_indicator
-+syntax keyword muttrcColorField contained sidebar_new
++	  if (nntp_data)
++	  {
++/*	    FOLDER folder;
++	    struct folder_file ff;
++	    char buffer[_POSIX_PATH_MAX + SHORT_STRING];
 +
-+" vim: syntax=vim
-diff -urN mutt-1.6.1/doc/vimrc.trash mutt-1.6.1-neomutt/doc/vimrc.trash
---- mutt-1.6.1/doc/vimrc.trash	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/doc/vimrc.trash	2016-06-12 18:43:00.699452222 +0100
-@@ -0,0 +1,7 @@
-+" Vim syntax file for the mutt trash patch
++	    folder.ff = &ff;
++	    folder.ff->name = f->name;
++	    folder.ff->st = NULL;
++	    folder.ff->is_new = nntp_data->new;
++	    folder.ff->nntp_data = nntp_data;
++	    FREE (&f->desc);
++	    mutt_FormatString (buffer, sizeof (buffer), 0, NONULL(GroupFormat),
++		  newsgroup_format_str, (unsigned long) &folder,
++		  M_FORMAT_ARROWCURSOR);
++	    f->desc = safe_strdup (buffer); */
++	    nntp_newsrc_update (CurrentNewsSrv);
++	    if (menu->current + 1 < menu->max)
++	      menu->current++;
++	    menu->redraw = REDRAW_MOTION_RESYNCH;
++	  }
++	  if (rc)
++	    menu->redraw = REDRAW_INDEX;
++	  nntp_newsrc_close (CurrentNewsSrv);
++	}
++	break;
 +
-+syntax keyword muttrcVarStr     contained skipwhite trash                 nextgroup=muttrcVarEqualsIdxFmt
++      case OP_LOAD_ACTIVE:
++	if (option (OPTNEWS))
++	{
++	  NNTP_SERVER *nserv = CurrentNewsSrv;
++	  unsigned int i;
 +
-+syntax match muttrcFunction     contained "\<purge-message\>"
++	  if (nntp_newsrc_parse (nserv) < 0)
++	    break;
 +
-+" vim: syntax=vim
-diff -urN mutt-1.6.1/enter.c mutt-1.6.1-neomutt/enter.c
---- mutt-1.6.1/enter.c	2016-06-12 18:43:00.403447606 +0100
-+++ mutt-1.6.1-neomutt/enter.c	2016-06-12 18:43:00.700452238 +0100
-@@ -565,6 +565,49 @@
- 	    }
- 	    break;
- 	  }
-+	  else if (flags & M_LABEL && ch == OP_EDITOR_COMPLETE)
++	  for (i = 0; i < nserv->groups_num; i++)
 +	  {
-+	    for (i = state->curpos; i && state->wbuf[i-1] != ',' && 
-+		 state->wbuf[i-1] != ':'; i--)
-+	      ;
-+	    for (; i < state->lastchar && state->wbuf[i] == ' '; i++)
-+	      ;
-+	    my_wcstombs (buf, buflen, state->wbuf + i, state->curpos - i);
-+	    r = mutt_label_complete (buf, buflen, i, state->tabs);
-+	    replace_part (state, i, buf);
-+	    if (!r)
-+	    {
-+	      rv = 1;
-+	      goto bye;
-+	    }
-+	    break;
++	    NNTP_DATA *nntp_data = nserv->groups_list[i];
++	    if (nntp_data)
++	      nntp_data->deleted = 1;
 +	  }
-+	  else if (flags & M_PATTERN && ch == OP_EDITOR_COMPLETE)
-+	  {
-+        char *p;
-+	    for (i = state->curpos; i && state->wbuf[i-1] != ',' && 
-+		 state->wbuf[i-1] != ':'; i--)
-+	      ;
-+	    for (; i < state->lastchar && state->wbuf[i] == ' '; i++)
-+	      ;
-+	    my_wcstombs (buf, buflen, state->wbuf + i, state->curpos - i);
-+        p = &buf[i];
-+        while (p > buf && *(p-1) != '~')
-+          p--;
-+        if (*p == '~' && *(p+1) == 'y')
-+        {
-+	      r = mutt_label_complete (buf, buflen, i, state->tabs);
-+	      replace_part (state, i, buf);
-+	      if (!r)
-+	      {
-+	        rv = 1;
-+	        goto bye;
-+	      }
-+        }
-+        else
-+          goto self_insert;
++	  nntp_active_fetch (nserv);
++	  nntp_newsrc_update (nserv);
++	  nntp_newsrc_close (nserv);
++
++	  destroy_state (&state);
++	  if (buffy)
++	    examine_mailboxes (menu, &state);
++	  else
++	    examine_directory (menu, &state, NULL, NULL);
++	  init_menu (&state, menu, title, sizeof (title), buffy);
++	}
++	break;
++#endif /* USE_NNTP */
++
++#if defined USE_IMAP || defined USE_NNTP
++      case OP_BROWSER_SUBSCRIBE:
++      case OP_BROWSER_UNSUBSCRIBE:
++#endif
++#ifdef USE_NNTP
++      case OP_SUBSCRIBE_PATTERN:
++      case OP_UNSUBSCRIBE_PATTERN:
++	if (option (OPTNEWS))
++	{
++	  NNTP_SERVER *nserv = CurrentNewsSrv;
++	  NNTP_DATA *nntp_data;
++	  regex_t *rx = (regex_t *) safe_malloc (sizeof (regex_t));
++	  char *s = buf;
++	  int rc, j = menu->current;
++
++	  if (i == OP_SUBSCRIBE_PATTERN || i == OP_UNSUBSCRIBE_PATTERN)
++	  {
++	    char tmp[STRING];
++	    int err;
++
++	    buf[0] = 0;
++	    if (i == OP_SUBSCRIBE_PATTERN)
++	      snprintf (tmp, sizeof (tmp), _("Subscribe pattern: "));
++	    else
++	      snprintf (tmp, sizeof (tmp), _("Unsubscribe pattern: "));
++	    if (mutt_get_field (tmp, buf, sizeof (buf), 0) != 0 || !buf[0])
++	    {
++	      FREE (&rx);
++	      break;
++	    }
++
++	    err = REGCOMP (rx, s, REG_NOSUB);
++	    if (err)
++	    {
++	      regerror (err, rx, buf, sizeof (buf));
++	      regfree (rx);
++	      FREE (&rx);
++	      mutt_error ("%s", buf);
++	      break;
++	    }
++	    menu->redraw = REDRAW_FULL;
++	    j = 0;
++	  }
++	  else if (!state.entrylen)
++	  {
++	    mutt_error _("No newsgroups match the mask");
 +	    break;
 +	  }
- 	  else if (flags & M_ALIAS && ch == OP_EDITOR_COMPLETE_QUERY)
- 	  {
- 	    /* invoke the query-menu to get more addresses */
-@@ -630,6 +673,27 @@
- 	      BEEP (); /* let the user know that nothing matched */
- 	    replace_part (state, 0, buf);
- 	  }
-+#if USE_NOTMUCH
-+	  else if (flags & M_NM_QUERY)
++
++	  rc = nntp_newsrc_parse (nserv);
++	  if (rc < 0)
++	    break;
++
++	  for ( ; j < state.entrylen; j++)
 +	  {
-+	    my_wcstombs (buf, buflen, state->wbuf, state->curpos);
-+	    i = strlen (buf);
-+	    if (!mutt_nm_query_complete(buf, buflen, i, state->tabs))
-+	      BEEP ();
++	    struct folder_file *f = &state.entry[j];
 +
-+	    replace_part (state, 0, buf);
++	    if (i == OP_BROWSER_SUBSCRIBE || i == OP_BROWSER_UNSUBSCRIBE ||
++		  regexec (rx, f->name, 0, NULL, 0) == 0)
++	    {
++	      if (i == OP_BROWSER_SUBSCRIBE || i == OP_SUBSCRIBE_PATTERN)
++		nntp_data = mutt_newsgroup_subscribe (nserv, f->name);
++	      else
++		nntp_data = mutt_newsgroup_unsubscribe (nserv, f->name);
++/*	      if (nntp_data)
++	      {
++		FOLDER folder;
++		char buffer[_POSIX_PATH_MAX + SHORT_STRING];
++
++		folder.name = f->name;
++		folder.f = NULL;
++		folder.new = nntp_data->new;
++		folder.nd = nntp_data;
++		FREE (&f->desc);
++		mutt_FormatString (buffer, sizeof (buffer), 0, NONULL(GroupFormat),
++			newsgroup_format_str, (unsigned long) &folder,
++			M_FORMAT_ARROWCURSOR);
++		f->desc = safe_strdup (buffer);
++	      } */
++	    }
++	    if (i == OP_BROWSER_SUBSCRIBE || i == OP_BROWSER_UNSUBSCRIBE)
++	    {
++	      if (menu->current + 1 < menu->max)
++		menu->current++;
++	      menu->redraw = REDRAW_MOTION_RESYNCH;
++	      break;
++	    }
 +	  }
-+	  else if (flags & M_NM_TAG)
++	  if (i == OP_SUBSCRIBE_PATTERN)
 +	  {
-+	    my_wcstombs (buf, buflen, state->wbuf, state->curpos);
-+	    i = strlen (buf);
-+	    if (!mutt_nm_tag_complete(buf, buflen, i, state->tabs))
-+	      BEEP ();
++	    unsigned int i;
 +
-+	    replace_part (state, 0, buf);
++	    for (i = 0; nserv && i < nserv->groups_num; i++)
++	    {
++	      nntp_data = nserv->groups_list[i];
++	      if (nntp_data && nntp_data->group && !nntp_data->subscribed)
++	      {
++		if (regexec (rx, nntp_data->group, 0, NULL, 0) == 0)
++		{
++		  mutt_newsgroup_subscribe (nserv, nntp_data->group);
++		  add_folder (menu, &state, nntp_data->group, NULL, NULL, nntp_data->new, nntp_data->newsrc_len, nntp_data);
++		}
++	      }
++	    }
++	    init_menu (&state, menu, title, sizeof (title), buffy);
 +	  }
-+
++	  if (rc > 0)
++	    menu->redraw = REDRAW_FULL;
++	  nntp_newsrc_update (nserv);
++	  nntp_clear_cache (nserv);
++	  nntp_newsrc_close (nserv);
++	  if (i != OP_BROWSER_SUBSCRIBE && i != OP_BROWSER_UNSUBSCRIBE)
++	    regfree (rx);
++	  FREE (&rx);
++	}
++#ifdef USE_IMAP
++	else
++#endif /* USE_IMAP && USE_NNTP */
++#endif /* USE_NNTP */
++#ifdef USE_IMAP
++	{
++	  if (i == OP_BROWSER_SUBSCRIBE)
++	    imap_subscribe (state.entry[menu->current].name, 1);
++	  else
++	    imap_subscribe (state.entry[menu->current].name, 0);
++	}
++#endif /* USE_IMAP */
+     }
+   }
+   
+diff --git a/browser.h b/browser.h
+index 515d69f..a41e0d5 100644
+--- a/browser.h
++++ b/browser.h
+@@ -19,6 +19,10 @@
+ #ifndef _BROWSER_H
+ #define _BROWSER_H 1
+ 
++#ifdef USE_NNTP
++#include "nntp.h"
 +#endif
- 	  else
- 	    goto self_insert;
- 	  break;
-@@ -677,12 +741,6 @@
-       /* use the raw keypress */
-       ch = LastKey;
++
+ struct folder_file
+ {
+   mode_t mode;
+@@ -30,6 +34,8 @@ struct folder_file
+   char *desc;
  
--#ifdef KEY_ENTER
--      /* treat ENTER the same as RETURN */
--      if (ch == KEY_ENTER)
--	ch = '\r';
--#endif
--
-       /* quietly ignore all other function keys */
-       if (ch & ~0xff)
- 	continue;
-diff -urN mutt-1.6.1/filter.c mutt-1.6.1-neomutt/filter.c
---- mutt-1.6.1/filter.c	2016-06-12 18:43:00.403447606 +0100
-+++ mutt-1.6.1-neomutt/filter.c	2016-06-12 18:43:00.700452238 +0100
-@@ -21,6 +21,7 @@
+   unsigned int new;
++  unsigned int all;
++
+ #ifdef USE_IMAP
+   char delim;
+   
+@@ -37,6 +43,9 @@ struct folder_file
+   unsigned selectable : 1;
+   unsigned inferiors : 1;
  #endif
++#ifdef USE_NNTP
++  NNTP_DATA *nd;
++#endif
+   unsigned tagged : 1;
+ };
  
- #include "mutt.h"
-+#include "mutt_curses.h"
- 
- #include <unistd.h>
- #include <stdlib.h>
-@@ -34,6 +35,7 @@
- 		       int fdin, int fdout, int fderr)
- {
-   int pin[2], pout[2], perr[2], thepid;
-+  char columns[11];
- 
-   if (in)
-   {
-@@ -117,6 +119,9 @@
-       close (fderr);
-     }
+diff --git a/buffy.c b/buffy.c
+index c713d16..7d90ca4 100644
+--- a/buffy.c
++++ b/buffy.c
+@@ -27,10 +27,18 @@
  
-+    snprintf (columns, sizeof (columns), "%d", COLS - SidebarWidth);
-+    setenv ("COLUMNS", columns, 1);
-+
-     execl (EXECSHELL, "sh", "-c", cmd, NULL);
-     _exit (127);
-   }
-diff -urN mutt-1.6.1/flags.c mutt-1.6.1-neomutt/flags.c
---- mutt-1.6.1/flags.c	2016-06-12 18:43:00.403447606 +0100
-+++ mutt-1.6.1-neomutt/flags.c	2016-06-12 18:43:00.700452238 +0100
-@@ -25,6 +25,10 @@
- #include "sort.h"
- #include "mx.h"
+ #include "mutt_curses.h"
  
 +#ifdef USE_SIDEBAR
 +#include "sidebar.h"
 +#endif
 +
- void _mutt_set_flag (CONTEXT *ctx, HEADER *h, int flag, int bf, int upd_ctx)
- {
-   int changed = h->changed;
-@@ -65,7 +69,13 @@
-       {
- 	h->deleted = 0;
-         update = 1;
--	if (upd_ctx) ctx->deleted--;
-+        if (upd_ctx) {
-+          ctx->deleted--;
-+          if (h->appended) {
-+            ctx->appended--;
-+	  }
-+        }
-+        h->appended = 0; /* when undeleting, also reset the appended flag */
  #ifdef USE_IMAP
-         /* see my comment above */
- 	if (ctx->magic == M_IMAP) 
-@@ -87,6 +97,27 @@
-       }
-       break;
+ #include "imap.h"
+ #endif
  
-+    case M_APPENDED:
-+      if (bf) {
-+        if (!h->appended) {
-+          h->appended = 1;
-+          if (upd_ctx) {
-+            ctx->appended++;
-+          }
-+        }
-+      }
-+      break;
-+
-+    case M_PURGED:
-+      if (bf) {
-+        if (!h->purged) {
-+          h->purged = 1;
-+        }
-+      } else if (h->purged) {
-+        h->purged = 0;
-+      }
-+      break;
++#ifdef USE_NOTMUCH
++#include "mutt_notmuch.h"
++#endif
 +
-     case M_NEW:
+ #include <string.h>
+ #include <sys/stat.h>
+ #include <dirent.h>
+@@ -41,6 +49,7 @@
+ #include <stdio.h>
+ 
+ static time_t BuffyTime = 0;	/* last time we started checking for mail */
++static time_t BuffyStatsTime = 0; /* last time we check performed mail_check_stats */
+ time_t BuffyDoneTime = 0;	/* last time we knew for sure how much mail there was. */
+ static short BuffyCount = 0;	/* how many boxes with new mail */
+ static short BuffyNotify = 0;	/* # of unnotified new boxes */
+@@ -196,9 +205,13 @@ void mutt_update_mailbox (BUFFY * b)
+ static BUFFY *buffy_new (const char *path)
+ {
+   BUFFY* buffy;
++  char rp[PATH_MAX] = "";
++  char *r = NULL;
  
-       if (!mutt_bit_isset(ctx->rights,M_ACL_SEEN))
-@@ -263,6 +294,9 @@
-    */
-   if (h->searched && (changed != h->changed || deleted != ctx->deleted || tagged != ctx->tagged || flagged != ctx->flagged))
-     h->searched = 0;
-+#ifdef USE_SIDEBAR
-+  mutt_sb_draw();
-+#endif
- }
+   buffy = (BUFFY *) safe_calloc (1, sizeof (BUFFY));
+   strfcpy (buffy->path, path, sizeof (buffy->path));
++  r = realpath (path, rp);
++  strfcpy (buffy->realpath, r ? rp : path, sizeof (buffy->realpath));
+   buffy->next = NULL;
+   buffy->magic = 0;
  
- void mutt_tag_set_flag (int flag, int bf)
-diff -urN mutt-1.6.1/functions.h mutt-1.6.1-neomutt/functions.h
---- mutt-1.6.1/functions.h	2016-06-12 18:43:00.403447606 +0100
-+++ mutt-1.6.1-neomutt/functions.h	2016-06-12 18:43:00.701452253 +0100
-@@ -22,9 +22,6 @@
-  *
-  * Notes:
-  *
-- * - If you want to bind \n or \r, use M_ENTER_S so that it will work
-- * correctly under both ncurses and S-Lang
-- *
-  * - If you need to bind a control char, use the octal value because the \cX
-  * construct does not work at this level.
-  *
-@@ -70,7 +67,8 @@
-   { "tag-prefix-cond",	OP_TAG_PREFIX_COND,	NULL },
-   { "end-cond",		OP_END_COND,		NULL },
-   { "shell-escape",	OP_SHELL_ESCAPE,	"!" },
--  { "select-entry",	OP_GENERIC_SELECT_ENTRY,M_ENTER_S },
-+  { "select-entry",	OP_GENERIC_SELECT_ENTRY,"\n" },
-+  { "select-entry",	OP_GENERIC_SELECT_ENTRY,"\r" },
-   { "search",		OP_SEARCH,		"/" },
-   { "search-reverse",	OP_SEARCH_REVERSE,	"\033/" },
-   { "search-opposite",	OP_SEARCH_OPPOSITE,	NULL },
-@@ -88,6 +86,10 @@
-   { "break-thread",		OP_MAIN_BREAK_THREAD,		"#" },
-   { "change-folder",		OP_MAIN_CHANGE_FOLDER,		"c" },
-   { "change-folder-readonly",	OP_MAIN_CHANGE_FOLDER_READONLY,	"\033c" },
-+#ifdef USE_NNTP
-+  { "change-newsgroup",		OP_MAIN_CHANGE_GROUP,		"i" },
-+  { "change-newsgroup-readonly",OP_MAIN_CHANGE_GROUP_READONLY,	"\033i" },
-+#endif
-   { "next-unread-mailbox",	OP_MAIN_NEXT_UNREAD_MAILBOX,    NULL },
-   { "collapse-thread",		OP_MAIN_COLLAPSE_THREAD,	"\033v" },
-   { "collapse-all",		OP_MAIN_COLLAPSE_ALL,		"\033V" },
-@@ -99,9 +101,18 @@
-   { "delete-thread",		OP_DELETE_THREAD,		"\004" },
-   { "delete-subthread",		OP_DELETE_SUBTHREAD,		"\033d" },
-   { "edit",			OP_EDIT_MESSAGE,		"e" },
-+  { "edit-label",		OP_EDIT_LABEL,			"y" },
-   { "edit-type",		OP_EDIT_TYPE,			"\005" },
-   { "forward-message",		OP_FORWARD_MESSAGE,		"f" },
--  { "flag-message",		OP_FLAG_MESSAGE,		"F" },
-+#ifdef USE_NNTP
-+  { "forward-to-group",		OP_FORWARD_TO_GROUP,		"\033F" },
-+  { "followup-message",		OP_FOLLOWUP,			"F" },
-+  { "get-children",		OP_GET_CHILDREN,		NULL },
-+  { "get-message",		OP_GET_MESSAGE,			"\007" },
-+  { "get-parent",		OP_GET_PARENT,			"\033G" },
-+  { "reconstruct-thread",	OP_RECONSTRUCT_THREAD,		NULL },
-+#endif
-+  { "flag-message",		OP_FLAG_MESSAGE,		"\033f" },
-   { "group-reply",		OP_GROUP_REPLY,			"g" },
- #ifdef USE_POP
-   { "fetch-mail",		OP_MAIN_FETCH_MAIL,		"G" },
-@@ -114,6 +125,7 @@
-   { "next-undeleted",		OP_MAIN_NEXT_UNDELETED,		"j" },
-   { "previous-undeleted",	OP_MAIN_PREV_UNDELETED,		"k" },
-   { "limit",			OP_MAIN_LIMIT,			"l" },
-+  { "limit-current-thread",	OP_LIMIT_CURRENT_THREAD,	"\033L" },
-   { "link-threads",		OP_MAIN_LINK_THREADS,		"&" },
-   { "list-reply",		OP_LIST_REPLY,			"L" },
-   { "mail",			OP_MAIL,			"m" },
-@@ -121,6 +133,7 @@
-   { "toggle-write",		OP_TOGGLE_WRITE,		"%" },
-   { "next-thread",		OP_MAIN_NEXT_THREAD,		"\016" },
-   { "next-subthread",		OP_MAIN_NEXT_SUBTHREAD,		"\033n" },
-+  { "purge-message",		OP_PURGE_MESSAGE,		NULL },
-   { "query",			OP_QUERY,			"Q" },
-   { "quit",			OP_QUIT,			"q" },
-   { "reply",			OP_REPLY,			"r" },
-@@ -128,6 +141,9 @@
-   { "sort-mailbox",		OP_SORT,			"o" },
-   { "sort-reverse",		OP_SORT_REVERSE,		"O" },
-   { "print-message",		OP_PRINT,			"p" },
-+#ifdef USE_NNTP
-+  { "post-message",		OP_POST,			"P" },
-+#endif
-   { "previous-thread",		OP_MAIN_PREV_THREAD,		"\020" },
-   { "previous-subthread",	OP_MAIN_PREV_SUBTHREAD,		"\033p" },
-   { "recall-message",		OP_RECALL_MESSAGE,		"R" },
-@@ -147,7 +163,12 @@
-   { "show-version",		OP_VERSION,			"V" },
-   { "set-flag",			OP_MAIN_SET_FLAG,		"w" },
-   { "clear-flag",		OP_MAIN_CLEAR_FLAG,		"W" },
--  { "display-message",		OP_DISPLAY_MESSAGE,		M_ENTER_S },
-+  { "toggle-read",		OP_TOGGLE_READ,			"X" },
-+#ifdef USE_NNTP
-+  { "catchup",			OP_CATCHUP,			"y" },
-+#endif
-+  { "display-message",		OP_DISPLAY_MESSAGE,		"\n" },
-+  { "display-message",		OP_DISPLAY_MESSAGE,		"\r" },
-   { "buffy-list",		OP_BUFFY_LIST,			"." },
-   { "sync-mailbox",		OP_MAIN_SYNC_FOLDER,		"$" },
-   { "display-address",		OP_DISPLAY_ADDRESS,		"@" },
-@@ -158,7 +179,7 @@
-   { "previous-new-then-unread",	OP_MAIN_PREV_NEW_THEN_UNREAD,	"\033\t" },
-   { "next-unread",		OP_MAIN_NEXT_UNREAD,		NULL },
-   { "previous-unread",		OP_MAIN_PREV_UNREAD,		NULL },
--  { "parent-message",		OP_MAIN_PARENT_MESSAGE,		"P" },
-+  { "parent-message",		OP_MAIN_PARENT_MESSAGE,		NULL },
+@@ -207,6 +220,8 @@ static BUFFY *buffy_new (const char *path)
  
+ static void buffy_free (BUFFY **mailbox)
+ {
++  if (mailbox && *mailbox)
++    FREE (&(*mailbox)->desc);
+   FREE (mailbox); /* __FREE_CHECKED__ */
+ }
  
-   { "extract-keys",		OP_EXTRACT_KEYS,		"\013" },
-@@ -167,8 +188,27 @@
-   { "mail-key",			OP_MAIL_KEY,			"\033k" },
-   { "decrypt-copy",		OP_DECRYPT_COPY,		NULL },
-   { "decrypt-save",		OP_DECRYPT_SAVE,		NULL },
-+  { "quasi-delete",		OP_MAIN_QUASI_DELETE,		NULL },
+@@ -215,8 +230,8 @@ int mutt_parse_mailboxes (BUFFER *path, BUFFER *s, unsigned long data, BUFFER *e
+   BUFFY **tmp,*tmp1;
+   char buf[_POSIX_PATH_MAX];
+   struct stat sb;
+-  char f1[PATH_MAX], f2[PATH_MAX];
+-  char *p, *q;
++  char f1[PATH_MAX];
++  char *p;
  
+   while (MoreArgs (s))
+   {
+@@ -228,6 +243,9 @@ int mutt_parse_mailboxes (BUFFER *path, BUFFER *s, unsigned long data, BUFFER *e
+       for (tmp = &Incoming; *tmp;)
+       {
+         tmp1=(*tmp)->next;
 +#ifdef USE_SIDEBAR
-+  { "sidebar-next",		OP_SIDEBAR_NEXT,		NULL },
-+  { "sidebar-next-new",		OP_SIDEBAR_NEXT_NEW,		NULL },
-+  { "sidebar-open",		OP_SIDEBAR_OPEN,		NULL },
-+  { "sidebar-page-down",	OP_SIDEBAR_PAGE_DOWN,		NULL },
-+  { "sidebar-page-up",		OP_SIDEBAR_PAGE_UP,		NULL },
-+  { "sidebar-prev",		OP_SIDEBAR_PREV,		NULL },
-+  { "sidebar-prev-new",		OP_SIDEBAR_PREV_NEW,		NULL },
-+  { "sidebar-toggle-virtual",	OP_SIDEBAR_TOGGLE_VIRTUAL,	NULL },
-+  { "sidebar-toggle-visible",	OP_SIDEBAR_TOGGLE_VISIBLE,	NULL },
++	mutt_sb_notify_mailbox (*tmp, 0);
 +#endif
- 
-+#ifdef USE_NOTMUCH
-+  { "change-vfolder",		OP_MAIN_CHANGE_VFOLDER,         "X" },
-+  { "vfolder-from-query",	OP_MAIN_VFOLDER_FROM_QUERY,     "\033X" },
-+  { "modify-labels",		OP_MAIN_MODIFY_LABELS,		"`" },
-+  { "modify-labels-then-hide",	OP_MAIN_MODIFY_LABELS_THEN_HIDE, NULL },
-+  { "entire-thread",		OP_MAIN_ENTIRE_THREAD,          "+" },
+         buffy_free (tmp);
+         *tmp=tmp1;
+       }
+@@ -243,8 +261,7 @@ int mutt_parse_mailboxes (BUFFER *path, BUFFER *s, unsigned long data, BUFFER *e
+     p = realpath (buf, f1);
+     for (tmp = &Incoming; *tmp; tmp = &((*tmp)->next))
+     {
+-      q = realpath ((*tmp)->path, f2);
+-      if (mutt_strcmp (p ? p : buf, q ? q : (*tmp)->path) == 0)
++      if (mutt_strcmp (p ? p : buf, (*tmp)->realpath) == 0)
+       {
+ 	dprint(3,(debugfile,"mailbox '%s' already registered as '%s'\n", buf, (*tmp)->path));
+ 	break;
+@@ -256,14 +273,21 @@ int mutt_parse_mailboxes (BUFFER *path, BUFFER *s, unsigned long data, BUFFER *e
+       if(*tmp)
+       {
+         tmp1=(*tmp)->next;
++#ifdef USE_SIDEBAR
++	mutt_sb_notify_mailbox (*tmp, 0);
 +#endif
-   { NULL,			0,				NULL }
- };
+         buffy_free (tmp);
+         *tmp=tmp1;
+       }
+       continue;
+     }
  
-@@ -178,6 +218,10 @@
-   { "bounce-message",	OP_BOUNCE_MESSAGE,		"b" },
-   { "change-folder",	OP_MAIN_CHANGE_FOLDER,		"c" },
-   { "change-folder-readonly",	OP_MAIN_CHANGE_FOLDER_READONLY,	"\033c" },
-+#ifdef USE_NNTP
-+  { "change-newsgroup",		OP_MAIN_CHANGE_GROUP,		"i" },
-+  { "change-newsgroup-readonly",OP_MAIN_CHANGE_GROUP_READONLY,	"\033i" },
-+#endif
-   { "next-unread-mailbox",	OP_MAIN_NEXT_UNREAD_MAILBOX, NULL },
-   { "copy-message",	OP_COPY_MESSAGE,		"C" },
-   { "decode-copy",	OP_DECODE_COPY,			"\033C" },
-@@ -187,9 +231,14 @@
-   { "set-flag",  	OP_MAIN_SET_FLAG,		"w" },
-   { "clear-flag",       OP_MAIN_CLEAR_FLAG,		"W" },
-   { "edit",		OP_EDIT_MESSAGE,		"e" },
-+  { "edit-label",	OP_EDIT_LABEL,			"y" },
-   { "edit-type",	OP_EDIT_TYPE,			"\005" },
-+#ifdef USE_NNTP
-+  { "followup-message",	OP_FOLLOWUP,			"F" },
-+  { "forward-to-group",	OP_FORWARD_TO_GROUP,		"\033F" },
-+#endif
-   { "forward-message",	OP_FORWARD_MESSAGE,		"f" },
--  { "flag-message",	OP_FLAG_MESSAGE,		"F" },
-+  { "flag-message",	OP_FLAG_MESSAGE,		"\033f" },
-   { "group-reply",	OP_GROUP_REPLY,			"g" },
- #ifdef USE_IMAP
-   { "imap-fetch-mail",  OP_MAIN_IMAP_FETCH,		NULL },
-@@ -211,8 +260,12 @@
-   { "sort-mailbox",	OP_SORT,			"o" },
-   { "sort-reverse",	OP_SORT_REVERSE,		"O" },
-   { "print-message",	OP_PRINT,			"p" },
-+#ifdef USE_NNTP
-+  { "post-message",	OP_POST,			"P" },
+-    if (!*tmp)
++    if (!*tmp) {
+       *tmp = buffy_new (buf);
++#ifdef USE_SIDEBAR
++      mutt_sb_notify_mailbox (*tmp, 1);
 +#endif
-   { "previous-thread",	OP_MAIN_PREV_THREAD,		"\020" },
-   { "previous-subthread",OP_MAIN_PREV_SUBTHREAD,	"\033p" },
-+  { "purge-message",	OP_PURGE_MESSAGE,		NULL },
-   { "quit",		OP_QUIT,			"Q" },
-   { "exit",		OP_EXIT,			"q" },
-   { "reply",		OP_REPLY,			"r" },
-@@ -247,7 +300,8 @@
-   { "search",		OP_SEARCH,			"/" },
-   { "search-reverse",	OP_SEARCH_REVERSE,		"\033/" },
-   { "search-opposite",	OP_SEARCH_OPPOSITE,		NULL },
--  { "next-line",	OP_NEXT_LINE,			M_ENTER_S },
-+  { "next-line",	OP_NEXT_LINE,			"\n" },
-+  { "next-line",	OP_NEXT_LINE,			"\r" },
-   { "jump",		OP_JUMP,			NULL },
-   { "next-unread",	OP_MAIN_NEXT_UNREAD,		NULL },
-   { "previous-new",	OP_MAIN_PREV_NEW,		NULL },
-@@ -258,7 +312,7 @@
-   { "half-down",	OP_HALF_DOWN,			NULL },
-   { "previous-line",	OP_PREV_LINE,			NULL },
-   { "bottom",		OP_PAGER_BOTTOM,		NULL },
--  { "parent-message",	OP_MAIN_PARENT_MESSAGE,		"P" },
-+  { "parent-message",	OP_MAIN_PARENT_MESSAGE,		NULL },
- 
++    }
  
+     (*tmp)->new = 0;
+     (*tmp)->notified = 1;
+@@ -285,10 +309,16 @@ int mutt_parse_mailboxes (BUFFER *path, BUFFER *s, unsigned long data, BUFFER *e
+   return 0;
+ }
  
-@@ -271,6 +325,27 @@
-   { "decrypt-save",    	OP_DECRYPT_SAVE,		NULL },
+-/* returns 1 if the specified dir (cur or new) has new mail */
+-static int buffy_maildir_dir_hasnew(BUFFY* mailbox, const char *dir_name)
++/* Checks the specified maildir subdir (cur or new) for new mail or mail counts.
++ * check_new:   if true, check for new mail.
++ * check_stats: if true, count total, new, and flagged mesages.
++ * Returns 1 if the dir has new mail.
++ */
++static int buffy_maildir_check_dir (BUFFY* mailbox, const char *dir_name, int check_new,
++                                    int check_stats)
+ {
+   char path[_POSIX_PATH_MAX];
++  char msgpath[_POSIX_PATH_MAX];
+   DIR *dirp;
+   struct dirent *de;
+   char *p;
+@@ -300,12 +330,18 @@ static int buffy_maildir_dir_hasnew(BUFFY* mailbox, const char *dir_name)
+   /* when $mail_check_recent is set, if the new/ directory hasn't been modified since
+    * the user last exited the mailbox, then we know there is no recent mail.
+    */
+-  if (option(OPTMAILCHECKRECENT))
++  if (check_new && option(OPTMAILCHECKRECENT))
+   {
+     if (stat(path, &sb) == 0 && sb.st_mtime < mailbox->last_visited)
+-      return 0;
++    {
++      rc = 0;
++      check_new = 0;
++    }
+   }
  
-   { "what-key",		OP_WHAT_KEY,		NULL },
-+  { "quasi-delete",	OP_MAIN_QUASI_DELETE,		NULL },
-+
-+#ifdef USE_SIDEBAR
-+  { "sidebar-next",		OP_SIDEBAR_NEXT,		NULL },
-+  { "sidebar-next-new",		OP_SIDEBAR_NEXT_NEW,		NULL },
-+  { "sidebar-open",		OP_SIDEBAR_OPEN,		NULL },
-+  { "sidebar-page-down",	OP_SIDEBAR_PAGE_DOWN,		NULL },
-+  { "sidebar-page-up",		OP_SIDEBAR_PAGE_UP,		NULL },
-+  { "sidebar-prev",		OP_SIDEBAR_PREV,		NULL },
-+  { "sidebar-prev-new",		OP_SIDEBAR_PREV_NEW,		NULL },
-+  { "sidebar-toggle-virtual",	OP_SIDEBAR_TOGGLE_VIRTUAL,	NULL },
-+  { "sidebar-toggle-visible",	OP_SIDEBAR_TOGGLE_VISIBLE,	NULL },
-+#endif
++  if (! (check_new || check_stats))
++    return rc;
 +
-+#ifdef USE_NOTMUCH
-+  { "change-vfolder",		OP_MAIN_CHANGE_VFOLDER,		"X" },
-+  { "vfolder-from-query",	OP_MAIN_VFOLDER_FROM_QUERY,	"\033X" },
-+  { "modify-labels",		OP_MAIN_MODIFY_LABELS,		"`" },
-+  { "modify-labels-then-hide",	OP_MAIN_MODIFY_LABELS_THEN_HIDE, NULL },
-+  { "entire-thread",		OP_MAIN_ENTIRE_THREAD,          "+" },
-+#endif
- 
-   { NULL,		0,				NULL }
- };
-@@ -279,6 +354,10 @@
-   { "bounce-message",	OP_BOUNCE_MESSAGE,		"b" },
-   { "display-toggle-weed",	OP_DISPLAY_HEADERS,	"h" },
-   { "edit-type",	OP_EDIT_TYPE,			"\005" },
-+#ifdef USE_NNTP
-+  { "followup-message",	OP_FOLLOWUP,			"F" },
-+  { "forward-to-group",	OP_FORWARD_TO_GROUP,		"\033F" },
-+#endif
-   { "print-entry",	OP_PRINT,			"p" },
-   { "save-entry",	OP_SAVE,			"s" },
-   { "pipe-entry",	OP_PIPE,			"|" },
-@@ -289,7 +368,8 @@
-   { "list-reply",	OP_LIST_REPLY,			"L" },
-   { "forward-message",	OP_FORWARD_MESSAGE,		"f" },
-   { "view-text",	OP_ATTACH_VIEW_TEXT,		"T" },
--  { "view-attach",	OP_VIEW_ATTACH,			M_ENTER_S },
-+  { "view-attach",	OP_VIEW_ATTACH,			"\n" },
-+  { "view-attach",	OP_VIEW_ATTACH,			"\r" },
-   { "delete-entry",	OP_DELETE,			"d" },
-   { "undelete-entry",	OP_UNDELETE,			"u" },
-   { "collapse-parts",	OP_ATTACH_COLLAPSE,		"v" },
-@@ -304,6 +384,7 @@
- const struct binding_t OpCompose[] = { /* map: compose */
-   { "attach-file",	OP_COMPOSE_ATTACH_FILE,		"a" },
-   { "attach-message",	OP_COMPOSE_ATTACH_MESSAGE,	"A" },
-+  { "attach-news-message",OP_COMPOSE_ATTACH_NEWS_MESSAGE,"\033a" },
-   { "edit-bcc",		OP_COMPOSE_EDIT_BCC,		"b" },
-   { "edit-cc",		OP_COMPOSE_EDIT_CC,		"c" },
-   { "copy-file",	OP_SAVE,			"C" },
-@@ -323,6 +404,11 @@
-   { "print-entry",	OP_PRINT,			"l" },
-   { "edit-mime",	OP_COMPOSE_EDIT_MIME,		"m" },
-   { "new-mime",		OP_COMPOSE_NEW_MIME,		"n" },
-+#ifdef USE_NNTP
-+  { "edit-newsgroups",	OP_COMPOSE_EDIT_NEWSGROUPS,	"N" },
-+  { "edit-followup-to",	OP_COMPOSE_EDIT_FOLLOWUP_TO,	"o" },
-+  { "edit-x-comment-to",OP_COMPOSE_EDIT_X_COMMENT_TO,	"x" },
-+#endif
-   { "postpone-message",	OP_COMPOSE_POSTPONE_MESSAGE,	"P" },
-   { "edit-reply-to",	OP_COMPOSE_EDIT_REPLY_TO,	"r" },
-   { "rename-file",	OP_COMPOSE_RENAME_FILE,		"R" },
-@@ -333,7 +419,8 @@
-   { "toggle-unlink",	OP_COMPOSE_TOGGLE_UNLINK,	"u" },
-   { "toggle-recode",    OP_COMPOSE_TOGGLE_RECODE,	NULL },
-   { "update-encoding",	OP_COMPOSE_UPDATE_ENCODING,	"U" },
--  { "view-attach",	OP_VIEW_ATTACH,			M_ENTER_S },
-+  { "view-attach",	OP_VIEW_ATTACH,			"\n" },
-+  { "view-attach",	OP_VIEW_ATTACH,			"\r" },
-   { "send-message",	OP_COMPOSE_SEND_MESSAGE,	"y" },
-   { "pipe-entry",	OP_PIPE,			"|" },
- 
-@@ -374,14 +461,25 @@
-   { "select-new",	OP_BROWSER_NEW_FILE,	"N" },
-   { "check-new",	OP_CHECK_NEW,		NULL },
-   { "toggle-mailboxes", OP_TOGGLE_MAILBOXES, 	"\t" },
-+#ifdef USE_NNTP
-+  { "reload-active",	OP_LOAD_ACTIVE,		"g" },
-+  { "subscribe-pattern", OP_SUBSCRIBE_PATTERN,	"S" },
-+  { "unsubscribe-pattern", OP_UNSUBSCRIBE_PATTERN, "U" },
-+  { "catchup",		OP_CATCHUP,		"y" },
-+  { "uncatchup",	OP_UNCATCHUP,		"Y" },
-+#endif
-   { "view-file",	OP_BROWSER_VIEW_FILE,	" " },
-   { "buffy-list",	OP_BUFFY_LIST,		"." },
- #ifdef USE_IMAP
-   { "create-mailbox",   OP_CREATE_MAILBOX,      "C" },
-   { "delete-mailbox",   OP_DELETE_MAILBOX,      "d" },
-   { "rename-mailbox",   OP_RENAME_MAILBOX,      "r" },
-+#endif
-+#if defined USE_IMAP || defined USE_NNTP
-   { "subscribe",	OP_BROWSER_SUBSCRIBE,	"s" },
-   { "unsubscribe",	OP_BROWSER_UNSUBSCRIBE,	"u" },
-+#endif
-+#ifdef USE_IMAP
-   { "toggle-subscribed", OP_BROWSER_TOGGLE_LSUB, "T" },
- #endif
-   { NULL,		0,			NULL }
-@@ -446,7 +544,8 @@
+   if ((dirp = opendir (path)) == NULL)
+   {
+     mailbox->magic = 0;
+@@ -317,21 +353,35 @@ static int buffy_maildir_dir_hasnew(BUFFY* mailbox, const char *dir_name)
+     if (*de->d_name == '.')
+       continue;
  
- #ifdef MIXMASTER
- const struct binding_t OpMix[] = { /* map: mixmaster */
--  { "accept",		OP_MIX_USE,	M_ENTER_S },
-+  { "accept",		OP_MIX_USE,	"\n" },
-+  { "accept",		OP_MIX_USE,	"\r" },
-   { "append",		OP_MIX_APPEND,	"a"       },
-   { "insert",		OP_MIX_INSERT,	"i"       },
-   { "delete",		OP_MIX_DELETE,  "d"	  },
-diff -urN mutt-1.6.1/globals.h mutt-1.6.1-neomutt/globals.h
---- mutt-1.6.1/globals.h	2016-06-12 18:43:00.403447606 +0100
-+++ mutt-1.6.1-neomutt/globals.h	2016-06-12 18:43:00.701452253 +0100
-@@ -66,10 +66,11 @@
- #endif
- WHERE char *Inbox;
- WHERE char *Ispell;
-+WHERE char *KeywordsSave;
- WHERE char *Locale;
- WHERE char *MailcapPath;
- WHERE char *Maildir;
--#if defined(USE_IMAP) || defined(USE_POP)
-+#if defined(USE_IMAP) || defined(USE_POP) || defined(USE_NNTP)
- WHERE char *MessageCachedir;
- #endif
- #if USE_HCACHE
-@@ -95,6 +96,17 @@
- #endif
+-    if (!(p = strstr (de->d_name, ":2,")) || !(strchr (p + 3, 'T') || strchr(p + 3, 'S')))
++    p = strstr (de->d_name, ":2,");
++    if (p && strchr (p + 3, 'T'))
++      continue;
++
++    if (check_stats)
++    {
++      mailbox->msg_count++;
++      if (p && strchr (p + 3, 'F'))
++        mailbox->msg_flagged++;
++    }
++    if (!p || !strchr (p + 3, 'S'))
+     {
+-      if (option(OPTMAILCHECKRECENT))
++      if (check_stats)
++        mailbox->msg_unread++;
++      if (check_new)
+       {
+-	char msgpath[_POSIX_PATH_MAX];
+-
+-	snprintf(msgpath, sizeof(msgpath), "%s/%s", path, de->d_name);
+-	/* ensure this message was received since leaving this mailbox */
+-	if (stat(msgpath, &sb) == 0 && (sb.st_ctime <= mailbox->last_visited))
+-	  continue;
++        if (option(OPTMAILCHECKRECENT))
++        {
++          snprintf(msgpath, sizeof(msgpath), "%s/%s", path, de->d_name);
++          /* ensure this message was received since leaving this mailbox */
++          if (stat(msgpath, &sb) == 0 && (sb.st_ctime <= mailbox->last_visited))
++            continue;
++        }
++        mailbox->new = 1;
++        rc = 1;
++        check_new = 0;
++        if (!check_stats)
++          break;
+       }
+-      /* one new and undeleted message is enough */
+-      mailbox->new = 1;
+-      rc = 1;
+-      break;
+     }
+   }
  
- WHERE char *Muttrc INITVAL (NULL);
-+#ifdef USE_NNTP
-+WHERE char *GroupFormat;
-+WHERE char *Inews;
-+WHERE char *NewsCacheDir;
-+WHERE char *NewsServer;
-+WHERE char *NewsgroupsCharset;
-+WHERE char *NewsRc;
-+WHERE char *NntpAuthenticators;
-+WHERE char *NntpUser;
-+WHERE char *NntpPass;
-+#endif
- WHERE char *Outbox;
- WHERE char *Pager;
- WHERE char *PagerFmt;
-@@ -118,6 +130,12 @@
- WHERE char *SendCharset;
- WHERE char *Sendmail;
- WHERE char *Shell;
-+#ifdef USE_SIDEBAR
-+WHERE char *SidebarDelimChars;
-+WHERE char *SidebarDividerChar;
-+WHERE char *SidebarFormat;
-+WHERE char *SidebarIndentString;
-+#endif
- WHERE char *Signature;
- WHERE char *SimpleSearch;
- #if USE_SMTP
-@@ -141,11 +159,13 @@
- WHERE char *Status;
- WHERE char *Tempdir;
- WHERE char *Tochars;
-+WHERE char *TrashPath;
- WHERE char *TSStatusFormat;
- WHERE char *TSIconFormat;
- WHERE short TSSupported;
- WHERE char *Username;
- WHERE char *Visual;
-+WHERE char *XlabelDelim;
+@@ -340,35 +390,48 @@ static int buffy_maildir_dir_hasnew(BUFFY* mailbox, const char *dir_name)
+   return rc;
+ }
  
- WHERE char *CurrentFolder;
- WHERE char *LastFolder;
-@@ -154,7 +174,12 @@
- WHERE const char *ReleaseDate;
+-/* returns 1 if maildir has new mail */
+-static int buffy_maildir_hasnew (BUFFY* mailbox)
++/* Checks new mail for a maildir mailbox.
++ * check_stats: if true, also count total, new, and flagged mesages.
++ * Returns 1 if the mailbox has new mail.
++ */
++static int buffy_maildir_check (BUFFY* mailbox, int check_stats)
+ {
+-  if (buffy_maildir_dir_hasnew(mailbox, "new")) {
+-      return 1;
+-  }
++  int rc, check_new = 1;
  
- WHERE HASH *Groups;
-+WHERE HASH *Labels;
- WHERE HASH *ReverseAlias;
-+#ifdef USE_NOTMUCH
-+WHERE HASH *TagTransforms;
-+WHERE HASH *TagFormats;
-+#endif
+-  if (!option(OPTMAILDIRCHECKCUR)) {
+-      return 0;
++  if (check_stats)
++  {
++    mailbox->msg_count   = 0;
++    mailbox->msg_unread  = 0;
++    mailbox->msg_flagged = 0;
+   }
  
- WHERE LIST *AutoViewList INITVAL(0);
- WHERE LIST *AlternativeOrderList INITVAL(0);
-@@ -194,6 +219,11 @@
+-  if (buffy_maildir_dir_hasnew(mailbox, "cur")) {
+-      return 1;
+-  }
++  rc = buffy_maildir_check_dir (mailbox, "new", check_new, check_stats);
  
- WHERE unsigned short Counter INITVAL (0);
+-  return 0;
++  check_new = !rc && option (OPTMAILDIRCHECKCUR);
++  if (check_new || check_stats)
++    if (buffy_maildir_check_dir (mailbox, "cur", check_new, check_stats))
++      rc = 1;
++
++  return rc;
+ }
+-/* returns 1 if mailbox has new mail */ 
+-static int buffy_mbox_hasnew (BUFFY* mailbox, struct stat *sb)
++
++/* Checks new mail for an mbox mailbox
++ * check_stats: if true, also count total, new, and flagged mesages.
++ * Returns 1 if the mailbox has new mail.
++ */
++static int buffy_mbox_check (BUFFY* mailbox, struct stat *sb, int check_stats)
+ {
+   int rc = 0;
+-  int statcheck;
++  int new_or_changed;
++  CONTEXT *ctx = NULL;
  
-+#ifdef USE_NNTP
-+WHERE short NewsPollTimeout;
-+WHERE short NntpContext;
-+#endif
+   if (option (OPTCHECKMBOXSIZE))
+-    statcheck = sb->st_size > mailbox->size;
++    new_or_changed = sb->st_size > mailbox->size;
+   else
+-    statcheck = sb->st_mtime > sb->st_atime
++    new_or_changed = sb->st_mtime > sb->st_atime
+       || (mailbox->newly_created && sb->st_ctime == sb->st_mtime && sb->st_ctime == sb->st_atime);
+-  if (statcheck)
 +
- WHERE short ConnectTimeout;
- WHERE short HistSize;
- WHERE short MenuContext;
-@@ -204,6 +234,7 @@
- WHERE short SaveHist;
- WHERE short SendmailWait;
- WHERE short SleepTime INITVAL (1);
-+WHERE short SkipQuotedOffset;
- WHERE short TimeInc;
- WHERE short Timeout;
- WHERE short Wrap;
-@@ -214,6 +245,14 @@
- WHERE short ScoreThresholdRead;
- WHERE short ScoreThresholdFlag;
++  if (new_or_changed)
+   {
+     if (!option(OPTMAILCHECKRECENT) || sb->st_mtime > mailbox->last_visited)
+     {
+@@ -381,55 +444,97 @@ static int buffy_mbox_hasnew (BUFFY* mailbox, struct stat *sb)
+     /* some other program has deleted mail from the folder */
+     mailbox->size = (off_t) sb->st_size;
+   }
++
+   if (mailbox->newly_created &&
+       (sb->st_ctime != sb->st_mtime || sb->st_ctime != sb->st_atime))
+     mailbox->newly_created = 0;
  
-+/* This isn't excluded from the build because it's too entwined in the code.
-+ * For now. */
-+WHERE short SidebarWidth;
-+#ifdef USE_SIDEBAR
-+WHERE short SidebarRefreshTime;
-+WHERE LIST *SidebarWhitelist INITVAL(0);
-+#endif
++  if (check_stats &&
++      (mailbox->stats_last_checked < sb->st_mtime))
++  {
++    if ((ctx = mx_open_mailbox (mailbox->path,
++                                M_READONLY | M_QUIET | M_NOSORT | M_PEEK,
++                                NULL)) != NULL)
++    {
++      mailbox->msg_count       = ctx->msgcount;
++      mailbox->msg_unread      = ctx->unread;
++      mailbox->msg_flagged     = ctx->flagged;
++      mailbox->stats_last_checked = ctx->mtime;
++      mx_close_mailbox (ctx, 0);
++    }
++  }
 +
- #ifdef USE_IMAP
- WHERE short ImapKeepalive;
- WHERE short ImapPipelineDepth;
-@@ -269,6 +308,17 @@
- WHERE char *SmimeImportCertCommand;
- WHERE char *SmimeGetCertEmailCommand;
+   return rc;
+ }
  
+-int mutt_buffy_check (int force)
 +#ifdef USE_NOTMUCH
-+WHERE int NotmuchOpenTimeout;
-+WHERE char *NotmuchDefaultUri;
-+WHERE char *NotmuchExcludeTags;
-+WHERE char *NotmuchUnreadTag;
-+WHERE char *NotmuchHiddenTags;
-+WHERE char *VirtFolderFormat;
-+WHERE int NotmuchDBLimit;
-+WHERE char *NotmuchQueryType;
-+WHERE char *NotmuchRecordTags;
-+#endif
- 
- 
- 
-diff -urN mutt-1.6.1/GPL mutt-1.6.1-neomutt/GPL
---- mutt-1.6.1/GPL	2016-06-12 18:43:00.389447388 +0100
-+++ mutt-1.6.1-neomutt/GPL	2016-06-12 18:43:00.663451660 +0100
-@@ -1,73 +1,74 @@
--		    GNU GENERAL PUBLIC LICENSE
--		       Version 2, June 1991
-+GNU General Public License
-+==========================
- 
-- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
--                 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
-- Everyone is permitted to copy and distribute verbatim copies
-- of this license document, but changing it is not allowed.
-+_Version 2, June 1991_  
-+_Copyright © 1989, 1991 Free Software Foundation, Inc.,_  
-+_51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA_
++int mutt_parse_virtual_mailboxes (BUFFER *path, BUFFER *s, unsigned long data, BUFFER *err)
+ {
+-  BUFFY *tmp;
+-  struct stat sb;
+-  struct stat contex_sb;
+-  time_t t;
++  BUFFY **tmp;
++  char buf[_POSIX_PATH_MAX + LONG_STRING + 32];   /* path to DB + query + URI "decoration" */
  
--			    Preamble
-+Everyone is permitted to copy and distribute verbatim copies
-+of this license document, but changing it is not allowed.
+-  sb.st_size=0;
+-  contex_sb.st_dev=0;
+-  contex_sb.st_ino=0;
++  while (MoreArgs (s))
++  {
++    char *desc;
  
--  The licenses for most software are designed to take away your
-+### Preamble
+-#ifdef USE_IMAP
+-  /* update postponed count as well, on force */
+-  if (force)
+-    mutt_update_num_postponed ();
++    mutt_extract_token (path, s, 0);
++    if (path->data && *path->data)
++      desc = safe_strdup( path->data);
++    else
++      continue;
 +
-+The licenses for most software are designed to take away your
- freedom to share and change it.  By contrast, the GNU General Public
- License is intended to guarantee your freedom to share and change free
- software--to make sure the software is free for all its users.  This
- General Public License applies to most of the Free Software
- Foundation's software and to any other program whose authors commit to
- using it.  (Some other Free Software Foundation software is covered by
--the GNU Library General Public License instead.)  You can apply it to
-+the GNU Lesser General Public License instead.)  You can apply it to
- your programs, too.
- 
--  When we speak of free software, we are referring to freedom, not
-+When we speak of free software, we are referring to freedom, not
- price.  Our General Public Licenses are designed to make sure that you
- have the freedom to distribute copies of free software (and charge for
- this service if you wish), that you receive source code or can get it
- if you want it, that you can change the software or use pieces of it
- in new free programs; and that you know you can do these things.
- 
--  To protect your rights, we need to make restrictions that forbid
-+To protect your rights, we need to make restrictions that forbid
- anyone to deny you these rights or to ask you to surrender the rights.
- These restrictions translate to certain responsibilities for you if you
- distribute copies of the software, or if you modify it.
++    mutt_extract_token (path, s, 0);
++    strfcpy (buf, path->data, sizeof (buf));
++
++    /* Skip empty tokens. */
++    if(!*buf) {
++	    FREE(&desc);
++	    continue;
++    }
++
++    /* avoid duplicates */
++    for (tmp = &VirtIncoming; *tmp; tmp = &((*tmp)->next))
++    {
++      if (mutt_strcmp (buf, (*tmp)->path) == 0)
++      {
++	dprint(3,(debugfile,"virtual mailbox '%s' already registered as '%s'\n", buf, (*tmp)->path));
++	break;
++      }
++    }
++
++    if (!*tmp)
++      *tmp = buffy_new (buf);
++
++    (*tmp)->new = 0;
++    (*tmp)->notified = 1;
++    (*tmp)->newly_created = 0;
++    (*tmp)->size = 0;
++    (*tmp)->desc = desc;
++#ifdef USE_SIDEBAR
++    mutt_sb_notify_mailbox (*tmp, 1);
++#endif
++  }
++  return 0;
++}
+ #endif
  
--  For example, if you distribute copies of such a program, whether
-+For example, if you distribute copies of such a program, whether
- gratis or for a fee, you must give the recipients all the rights that
- you have.  You must make sure that they, too, receive or can get the
- source code.  And you must show them these terms so they know their
- rights.
+-  /* fastest return if there are no mailboxes */
+-  if (!Incoming)
+-    return 0;
+-  t = time (NULL);
+-  if (!force && (t - BuffyTime < BuffyTimeout))
+-    return BuffyCount;
+- 
+-  BuffyTime = t;
+-  BuffyCount = 0;
+-  BuffyNotify = 0;
++static void buffy_check (BUFFY *tmp, struct stat *contex_sb, int check_stats)
++{
++    struct stat sb;
++#ifdef USE_SIDEBAR
++    short orig_new;
++    int orig_count, orig_unread, orig_flagged;
++#endif
  
--  We protect your rights with two steps: (1) copyright the software, and
--(2) offer you this license which gives you legal permission to copy,
-+We protect your rights with two steps: **(1)** copyright the software, and
-+**(2)** offer you this license which gives you legal permission to copy,
- distribute and/or modify the software.
+-#ifdef USE_IMAP
+-  BuffyCount += imap_buffy_check (force);
++    sb.st_size=0;
++
++#ifdef USE_SIDEBAR
++    orig_new = tmp->new;
++    orig_count = tmp->msg_count;
++    orig_unread = tmp->msg_unread;
++    orig_flagged = tmp->msg_flagged;
+ #endif
  
--  Also, for each author's protection and ours, we want to make certain
-+Also, for each author's protection and ours, we want to make certain
- that everyone understands that there is no warranty for this free
- software.  If the software is modified by someone else and passed on, we
- want its recipients to know that what they have is not the original, so
- that any problems introduced by others will not reflect on the original
- authors' reputations.
+-  /* check device ID and serial number instead of comparing paths */
+-  if (!Context || Context->magic == M_IMAP || Context->magic == M_POP
+-      || stat (Context->path, &contex_sb) != 0)
+-  {
+-    contex_sb.st_dev=0;
+-    contex_sb.st_ino=0;
+-  }
+-  
+-  for (tmp = Incoming; tmp; tmp = tmp->next)
+-  {
+     if (tmp->magic != M_IMAP)
+     {
+       tmp->new = 0;
+@@ -438,6 +543,16 @@ int mutt_buffy_check (int force)
+ 	tmp->magic = M_POP;
+       else
+ #endif
++#ifdef USE_NOTMUCH
++      if (mx_is_notmuch (tmp->path))
++	tmp->magic = M_NOTMUCH;
++      else
++#endif
++#ifdef USE_NNTP
++      if ((tmp->magic == M_NNTP) || mx_is_nntp (tmp->path))
++	tmp->magic = M_NNTP;
++      else
++#endif
+       if (stat (tmp->path, &sb) != 0 || (S_ISREG(sb.st_mode) && sb.st_size == 0) ||
+ 	  (!tmp->magic && (tmp->magic = mx_get_magic (tmp->path)) <= 0))
+       {
+@@ -446,46 +561,133 @@ int mutt_buffy_check (int force)
+ 	tmp->newly_created = 1;
+ 	tmp->magic = 0;
+ 	tmp->size = 0;
+-	continue;
++	return;
+       }
+     }
  
--  Finally, any free program is threatened constantly by software
-+Finally, any free program is threatened constantly by software
- patents.  We wish to avoid the danger that redistributors of a free
- program will individually obtain patent licenses, in effect making the
- program proprietary.  To prevent this, we have made it clear that any
- patent must be licensed for everyone's free use or not licensed at all.
+     /* check to see if the folder is the currently selected folder
+      * before polling */
+     if (!Context || !Context->path ||
+-	(( tmp->magic == M_IMAP || tmp->magic == M_POP )
++#ifdef USE_NNTP
++	(( tmp->magic == M_IMAP || tmp->magic == M_POP || tmp->magic == M_NNTP )
++#else
++	(( tmp->magic == M_IMAP || tmp->magic == M_POP || tmp->magic == M_NOTMUCH)
++#endif
+ 	    ? mutt_strcmp (tmp->path, Context->path) :
+-	      (sb.st_dev != contex_sb.st_dev || sb.st_ino != contex_sb.st_ino)))
++	      (sb.st_dev != contex_sb->st_dev || sb.st_ino != contex_sb->st_ino)))
+     {
+       switch (tmp->magic)
+       {
+-      case M_MBOX:
+-      case M_MMDF:
+-	if (buffy_mbox_hasnew (tmp, &sb) > 0)
+-	  BuffyCount++;
+-	break;
+-
+-      case M_MAILDIR:
+-	if (buffy_maildir_hasnew (tmp) > 0)
+-	  BuffyCount++;
+-	break;
+-
+-      case M_MH:
+-	mh_buffy(tmp);
+-	if (tmp->new)
+-	  BuffyCount++;
+-	break;
++        case M_MBOX:
++        case M_MMDF:
++          if (buffy_mbox_check (tmp, &sb, check_stats) > 0)
++            BuffyCount++;
++          break;
++
++        case M_MAILDIR:
++          if (buffy_maildir_check (tmp, check_stats) > 0)
++            BuffyCount++;
++          break;
++
++        case M_MH:
++          if (mh_buffy (tmp, check_stats) > 0)
++            BuffyCount++;
++          break;
++#ifdef USE_NOTMUCH
++        case M_NOTMUCH:
++          tmp->msg_count = 0;
++          tmp->msg_unread = 0;
++          tmp->msg_flagged = 0;
++          nm_nonctx_get_count(tmp->path, &tmp->msg_count, &tmp->msg_unread);
++          if (tmp->msg_unread > 0) {
++            BuffyCount++;
++            tmp->new = 1;
++          }
++          break;
++#endif
+       }
+     }
+     else if (option(OPTCHECKMBOXSIZE) && Context && Context->path)
+       tmp->size = (off_t) sb.st_size;	/* update the size of current folder */
  
--  The precise terms and conditions for copying, distribution and
-+The precise terms and conditions for copying, distribution and
- modification follow.
--

--		    GNU GENERAL PUBLIC LICENSE
--   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
++#ifdef USE_SIDEBAR
++    if ((orig_new != tmp->new) ||
++        (orig_count != tmp->msg_count) ||
++        (orig_unread != tmp->msg_unread) ||
++        (orig_flagged != tmp->msg_flagged))
++      SidebarNeedsRedraw = 1;
++#endif
++
+     if (!tmp->new)
+       tmp->notified = 0;
+     else if (!tmp->notified)
+       BuffyNotify++;
++}
++
++/* Check all Incoming for new mail and total/new/flagged messages
++ * force: if true, ignore BuffyTimeout and check for new mail anyway
++ */
++int mutt_buffy_check (int force)
++{
++  BUFFY *tmp;
++  struct stat contex_sb;
++  time_t t;
++  int check_stats = 0;
++  contex_sb.st_dev=0;
++  contex_sb.st_ino=0;
++
++#ifdef USE_IMAP
++  /* update postponed count as well, on force */
++  if (force)
++    mutt_update_num_postponed ();
++#endif
++
++  /* fastest return if there are no mailboxes */
++#ifdef USE_NOTMUCH
++  if (!Incoming && !VirtIncoming)
++    return 0;
++#else
++  if (!Incoming)
++    return 0;
++#endif
++  t = time (NULL);
++  if (!force && (t - BuffyTime < BuffyTimeout))
++    return BuffyCount;
++
++  if (option (OPTMAILCHECKSTATS) &&
++      (t - BuffyStatsTime >= BuffyCheckStatsInterval))
++  {
++    check_stats = 1;
++    BuffyStatsTime = t;
+   }
  
--  0. This License applies to any program or other work which contains
-+### TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
++  BuffyTime = t;
++  BuffyCount = 0;
++  BuffyNotify = 0;
 +
-+**0.** This License applies to any program or other work which contains
- a notice placed by the copyright holder saying it may be distributed
--under the terms of this General Public License.  The "Program", below,
--refers to any such program or work, and a "work based on the Program"
-+under the terms of this General Public License.  The “Program”, below,
-+refers to any such program or work, and a “work based on the Program”
- means either the Program or any derivative work under copyright law:
- that is to say, a work containing the Program or a portion of it,
- either verbatim or with modifications and/or translated into another
- language.  (Hereinafter, translation is included without limitation in
--the term "modification".)  Each licensee is addressed as "you".
-+the term “modification”.)  Each licensee is addressed as “you”.
- 
- Activities other than copying, distribution and modification are not
- covered by this License; they are outside its scope.  The act of
-@@ -76,7 +77,7 @@
- Program (independent of having been made by running the Program).
- Whether that is true depends on what the Program does.
- 
--  1. You may copy and distribute verbatim copies of the Program's
-+**1.** You may copy and distribute verbatim copies of the Program's
- source code as you receive it, in any medium, provided that you
- conspicuously and appropriately publish on each copy an appropriate
- copyright notice and disclaimer of warranty; keep intact all the
-@@ -87,30 +88,28 @@
- You may charge a fee for the physical act of transferring a copy, and
- you may at your option offer warranty protection in exchange for a fee.
- 
--  2. You may modify your copy or copies of the Program or any portion
-+**2.** You may modify your copy or copies of the Program or any portion
- of it, thus forming a work based on the Program, and copy and
- distribute such modifications or work under the terms of Section 1
- above, provided that you also meet all of these conditions:
- 
--    a) You must cause the modified files to carry prominent notices
--    stating that you changed the files and the date of any change.
-+* **a)** You must cause the modified files to carry prominent notices
-+stating that you changed the files and the date of any change.
-+* **b)** You must cause any work that you distribute or publish, that in
-+whole or in part contains or is derived from the Program or any
-+part thereof, to be licensed as a whole at no charge to all third
-+parties under the terms of this License.
-+* **c)** If the modified program normally reads commands interactively
-+when run, you must cause it, when started running for such
-+interactive use in the most ordinary way, to print or display an
-+announcement including an appropriate copyright notice and a
-+notice that there is no warranty (or else, saying that you provide
-+a warranty) and that users may redistribute the program under
-+these conditions, and telling the user how to view a copy of this
-+License.  (Exception: if the Program itself is interactive but
-+does not normally print such an announcement, your work based on
-+the Program is not required to print an announcement.)
- 
--    b) You must cause any work that you distribute or publish, that in
--    whole or in part contains or is derived from the Program or any
--    part thereof, to be licensed as a whole at no charge to all third
--    parties under the terms of this License.
--
--    c) If the modified program normally reads commands interactively
--    when run, you must cause it, when started running for such
--    interactive use in the most ordinary way, to print or display an
--    announcement including an appropriate copyright notice and a
--    notice that there is no warranty (or else, saying that you provide
--    a warranty) and that users may redistribute the program under
--    these conditions, and telling the user how to view a copy of this
--    License.  (Exception: if the Program itself is interactive but
--    does not normally print such an announcement, your work based on
--    the Program is not required to print an announcement.)
--

- These requirements apply to the modified work as a whole.  If
- identifiable sections of that work are not derived from the Program,
- and can be reasonably considered independent and separate works in
-@@ -131,26 +130,24 @@
- a storage or distribution medium does not bring the other work under
- the scope of this License.
- 
--  3. You may copy and distribute the Program (or a work based on it,
-+**3.** You may copy and distribute the Program (or a work based on it,
- under Section 2) in object code or executable form under the terms of
- Sections 1 and 2 above provided that you also do one of the following:
++#ifdef USE_IMAP
++  BuffyCount += imap_buffy_check (force, check_stats);
++#endif
++
++  /* check device ID and serial number instead of comparing paths */
++  if (!Context || Context->magic == M_IMAP || Context->magic == M_POP
++#ifdef USE_NNTP
++      || Context->magic == M_NNTP
++#endif
++      || stat (Context->path, &contex_sb) != 0)
++  {
++    contex_sb.st_dev=0;
++    contex_sb.st_ino=0;
++  }
++
++  for (tmp = Incoming; tmp; tmp = tmp->next)
++    buffy_check(tmp, &contex_sb, check_stats);
++
++#ifdef USE_NOTMUCH
++  for (tmp = VirtIncoming; tmp; tmp = tmp->next)
++    buffy_check(tmp, &contex_sb, check_stats);
++#endif
++
+   BuffyDoneTime = BuffyTime;
+   return (BuffyCount);
+ }
+@@ -600,6 +802,35 @@ void mutt_buffy (char *s, size_t slen)
+   *s = '\0';
+ }
  
--    a) Accompany it with the complete corresponding machine-readable
--    source code, which must be distributed under the terms of Sections
--    1 and 2 above on a medium customarily used for software interchange; or,
--
--    b) Accompany it with a written offer, valid for at least three
--    years, to give any third party, for a charge no more than your
--    cost of physically performing source distribution, a complete
--    machine-readable copy of the corresponding source code, to be
--    distributed under the terms of Sections 1 and 2 above on a medium
--    customarily used for software interchange; or,
--
--    c) Accompany it with the information you received as to the offer
--    to distribute corresponding source code.  (This alternative is
--    allowed only for noncommercial distribution and only if you
--    received the program in object code or executable form with such
--    an offer, in accord with Subsection b above.)
-+* **a)** Accompany it with the complete corresponding machine-readable
-+source code, which must be distributed under the terms of Sections
-+1 and 2 above on a medium customarily used for software interchange; or,
-+* **b)** Accompany it with a written offer, valid for at least three
-+years, to give any third party, for a charge no more than your
-+cost of physically performing source distribution, a complete
-+machine-readable copy of the corresponding source code, to be
-+distributed under the terms of Sections 1 and 2 above on a medium
-+customarily used for software interchange; or,
-+* **c)** Accompany it with the information you received as to the offer
-+to distribute corresponding source code.  (This alternative is
-+allowed only for noncommercial distribution and only if you
-+received the program in object code or executable form with such
-+an offer, in accord with Subsection b above.)
++#ifdef USE_NOTMUCH
++void mutt_buffy_vfolder (char *s, size_t slen)
++{
++  BUFFY *tmp;
++  int pass, found = 0;
++
++  if (mutt_buffy_check (0))
++  {
++    for (pass = 0; pass < 2; pass++) {
++      for (tmp = VirtIncoming; tmp; tmp = tmp->next)
++      {
++	if ((found || pass) && tmp->new)
++	{
++	  strfcpy (s, tmp->desc, slen);
++	  return;
++	}
++	if (mutt_strcmp (s, tmp->path) == 0)
++	  found = 1;
++      }
++    }
++
++    mutt_buffy_check (1); /* buffy was wrong - resync things */
++  }
++
++  /* no folders with new mail */
++  *s = '\0';
++}
++#endif
++
+ /* fetch buffy object for given path, if present */
+ static BUFFY* buffy_get (const char *path)
+ {
+diff --git a/buffy.h b/buffy.h
+index 9aa8e51..f77bda2 100644
+--- a/buffy.h
++++ b/buffy.h
+@@ -16,6 +16,9 @@
+  *     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+  */
  
- The source code for a work means the preferred form of the work for
- making modifications to it.  For an executable work, complete source
-@@ -168,8 +165,8 @@
- access to copy the source code from the same place counts as
- distribution of the source code, even though third parties are not
- compelled to copy the source along with the object code.
--

--  4. You may not copy, modify, sublicense, or distribute the Program
++#ifndef _BUFFY_H
++#define _BUFFY_H
 +
-+**4.** You may not copy, modify, sublicense, or distribute the Program
- except as expressly provided under this License.  Any attempt
- otherwise to copy, modify, sublicense or distribute the Program is
- void, and will automatically terminate your rights under this License.
-@@ -177,7 +174,7 @@
- this License will not have their licenses terminated so long as such
- parties remain in full compliance.
+ /*parameter to mutt_parse_mailboxes*/
+ #define M_MAILBOXES   1
+ #define M_UNMAILBOXES 2 
+@@ -23,18 +26,34 @@
+ typedef struct buffy_t
+ {
+   char path[_POSIX_PATH_MAX];
++  char realpath[_POSIX_PATH_MAX]; /* used for duplicate detection, context comparison,
++                                     and the sidebar */
++  char *desc;
+   off_t size;
+   struct buffy_t *next;
+   short new;			/* mailbox has new mail */
++
++  /* These next three are only set when OPTMAILCHECKSTATS is set */
++  int msg_count;		/* total number of messages */
++  int msg_unread;		/* number of unread messages */
++  int msg_flagged;		/* number of flagged messages */
++
+   short notified;		/* user has been notified */
+   short magic;			/* mailbox type */
+   short newly_created;		/* mbox or mmdf just popped into existence */
+   time_t last_visited;		/* time of last exit from this mailbox */
++  time_t stats_last_checked;	/* mtime of mailbox the last time stats where checked. */
+ }
+ BUFFY;
  
--  5. You are not required to accept this License, since you have not
-+**5.** You are not required to accept this License, since you have not
- signed it.  However, nothing else grants you permission to modify or
- distribute the Program or its derivative works.  These actions are
- prohibited by law if you do not accept this License.  Therefore, by
-@@ -186,7 +183,7 @@
- all its terms and conditions for copying, distributing or modifying
- the Program or works based on it.
+ WHERE BUFFY *Incoming INITVAL (0);
+ WHERE short BuffyTimeout INITVAL (3);
++WHERE short BuffyCheckStatsInterval INITVAL (60);
++
++#ifdef USE_NOTMUCH
++WHERE BUFFY *VirtIncoming INITVAL (0);
++void mutt_buffy_vfolder (char *s, size_t slen);
++#endif
  
--  6. Each time you redistribute the Program (or any work based on the
-+**6.** Each time you redistribute the Program (or any work based on the
- Program), the recipient automatically receives a license from the
- original licensor to copy, distribute or modify the Program subject to
- these terms and conditions.  You may not impose any further
-@@ -194,7 +191,7 @@
- You are not responsible for enforcing compliance by third parties to
- this License.
+ extern time_t BuffyDoneTime;	/* last time we knew for sure how much mail there was */
  
--  7. If, as a consequence of a court judgment or allegation of patent
-+**7.** If, as a consequence of a court judgment or allegation of patent
- infringement or for any other reason (not limited to patent issues),
- conditions are imposed on you (whether by court order, agreement or
- otherwise) that contradict the conditions of this License, they do not
-@@ -225,8 +222,8 @@
+@@ -48,4 +67,6 @@ void mutt_buffy_cleanup (const char *buf, struct stat *st);
+ /* mark mailbox just left as already notified */
+ void mutt_buffy_setnotified (const char *path);
  
- This section is intended to make thoroughly clear what is believed to
- be a consequence of the rest of this License.
--

--  8. If the distribution and/or use of the Program is restricted in
+-void mh_buffy (BUFFY *);
++int mh_buffy (BUFFY *, int);
 +
-+**8.** If the distribution and/or use of the Program is restricted in
- certain countries either by patents or by copyrighted interfaces, the
- original copyright holder who places the Program under this License
- may add an explicit geographical distribution limitation excluding
-@@ -234,20 +231,20 @@
- countries not thus excluded.  In such case, this License incorporates
- the limitation as if written in the body of this License.
++#endif /* _BUFFY_H */
+diff --git a/color.c b/color.c
+index 6e29603..172bc59 100644
+--- a/color.c
++++ b/color.c
+@@ -34,7 +34,14 @@ int ColorQuoteUsed;
+ int ColorDefs[MT_COLOR_MAX];
+ COLOR_LINE *ColorHdrList = NULL;
+ COLOR_LINE *ColorBodyList = NULL;
++COLOR_LINE *ColorStatusList = NULL;
+ COLOR_LINE *ColorIndexList = NULL;
++COLOR_LINE *ColorIndexAuthorList = NULL;
++COLOR_LINE *ColorIndexFlagsList = NULL;
++COLOR_LINE *ColorIndexSubjectList = NULL;
++#ifdef USE_NOTMUCH
++COLOR_LINE *ColorIndexTagList = NULL;
++#endif
  
--  9. The Free Software Foundation may publish revised and/or new versions
-+**9.** The Free Software Foundation may publish revised and/or new versions
- of the General Public License from time to time.  Such new versions will
- be similar in spirit to the present version, but may differ in detail to
- address new problems or concerns.
- 
- Each version is given a distinguishing version number.  If the Program
--specifies a version number of this License which applies to it and "any
--later version", you have the option of following the terms and conditions
-+specifies a version number of this License which applies to it and “any
-+later version”, you have the option of following the terms and conditions
- either of that version or of any later version published by the Free
- Software Foundation.  If the Program does not specify a version number of
- this License, you may choose any version ever published by the Free Software
- Foundation.
+ /* local to this file */
+ static int ColorQuoteSize;
+@@ -93,7 +100,28 @@ static const struct mapping_t Fields[] =
+   { "bold",		MT_COLOR_BOLD },
+   { "underline",	MT_COLOR_UNDERLINE },
+   { "index",		MT_COLOR_INDEX },
++  { "progress",		MT_COLOR_PROGRESS },
++  { "index_author",	MT_COLOR_INDEX_AUTHOR },
++  { "index_collapsed",	MT_COLOR_INDEX_COLLAPSED },
++  { "index_date",	MT_COLOR_INDEX_DATE },
++  { "index_flags",	MT_COLOR_INDEX_FLAGS },
++  { "index_label",	MT_COLOR_INDEX_LABEL },
++  { "index_number",	MT_COLOR_INDEX_NUMBER },
++  { "index_size",	MT_COLOR_INDEX_SIZE },
++  { "index_subject",	MT_COLOR_INDEX_SUBJECT },
++#ifdef USE_NOTMUCH
++  { "index_tag",	MT_COLOR_INDEX_TAG },
++  { "index_tags",	MT_COLOR_INDEX_TAGS },
++#endif
+   { "prompt",		MT_COLOR_PROMPT },
++#ifdef USE_SIDEBAR
++  { "sidebar_divider",	MT_COLOR_DIVIDER },
++  { "sidebar_flagged",	MT_COLOR_FLAGGED },
++  { "sidebar_highlight",MT_COLOR_HIGHLIGHT },
++  { "sidebar_indicator",MT_COLOR_SB_INDICATOR },
++  { "sidebar_new",	MT_COLOR_NEW },
++  { "sidebar_spoolfile",MT_COLOR_SB_SPOOLFILE },
++#endif
+   { NULL,		0 }
+ };
  
--  10. If you wish to incorporate parts of the Program into other free
-+**10.** If you wish to incorporate parts of the Program into other free
- programs whose distribution conditions are different, write to the author
- to ask for permission.  For software which is copyrighted by the Free
- Software Foundation, write to the Free Software Foundation; we sometimes
-@@ -255,19 +252,19 @@
- of preserving the free status of all derivatives of our free software and
- of promoting the sharing and reuse of software generally.
+@@ -146,6 +174,9 @@ void ci_start_color (void)
+   ColorDefs[MT_COLOR_INDICATOR] = A_REVERSE;
+   ColorDefs[MT_COLOR_SEARCH] = A_REVERSE;
+   ColorDefs[MT_COLOR_MARKERS] = A_REVERSE;
++#ifdef USE_SIDEBAR
++  ColorDefs[MT_COLOR_HIGHLIGHT] = A_UNDERLINE;
++#endif
+   /* special meaning: toggle the relevant attribute */
+   ColorDefs[MT_COLOR_BOLD] = 0;
+   ColorDefs[MT_COLOR_UNDERLINE] = 0;
+@@ -384,12 +415,52 @@ int mutt_parse_unmono (BUFFER *buf, BUFFER *s, unsigned long data,
+   return _mutt_parse_uncolor(buf, s, data, err, 0);
+ }
  
--			    NO WARRANTY
-+### NO WARRANTY
++/**
++ * mutt_do_uncolor - XXX
++ */
++static void
++mutt_do_uncolor (BUFFER *buf, BUFFER *s, COLOR_LINE **ColorList,
++                 int *do_cache, int parse_uncolor)
++{
++	COLOR_LINE *tmp, *last = NULL;
++
++	do {
++		mutt_extract_token (buf, s, 0);
++		if (mutt_strcmp ("*", buf->data) == 0) {
++			for (tmp = *ColorList; tmp; ) {
++				if (!*do_cache) {
++					*do_cache = 1;
++				}
++				last = tmp;
++				tmp = tmp->next;
++				mutt_free_color_line (&last, parse_uncolor);
++			}
++			*ColorList = NULL;
++		} else {
++			for (last = NULL, tmp = *ColorList; tmp; last = tmp, tmp = tmp->next) {
++				if (mutt_strcmp (buf->data, tmp->pattern) == 0) {
++					if (!*do_cache) {
++						*do_cache = 1;
++					}
++					dprint (1, (debugfile,"Freeing pattern \"%s\" from ColorList\n",
++															 tmp->pattern));
++					if (last) {
++						last->next = tmp->next;
++					} else {
++						*ColorList = tmp->next;
++					}
++					mutt_free_color_line (&tmp, parse_uncolor);
++					break;
++				}
++			}
++		}
++	} while (MoreArgs (s));
++}
++
+ static int _mutt_parse_uncolor (BUFFER *buf, BUFFER *s, unsigned long data,
+ 				BUFFER *err, short parse_uncolor)
+ {
+   int object = 0, do_cache = 0;
+-  COLOR_LINE *tmp, *last = NULL;
+-  COLOR_LINE **list;
  
--  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-+**11.** BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
- FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
- OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
--PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-+PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
- OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
- TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
- PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
- REPAIR OR CORRECTION.
+   mutt_extract_token (buf, s, 0);
  
--  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-+**12.** IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
- WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
- REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
- INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-@@ -277,36 +274,35 @@
- PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
- POSSIBILITY OF SUCH DAMAGES.
+@@ -399,13 +470,15 @@ static int _mutt_parse_uncolor (BUFFER *buf, BUFFER *s, unsigned long data,
+     return (-1);
+   }
  
--		     END OF TERMS AND CONDITIONS
--

--	    How to Apply These Terms to Your New Programs
-+END OF TERMS AND CONDITIONS
+-  if (mutt_strncmp (buf->data, "index", 5) == 0)
+-    list = &ColorIndexList;
+-  else if (mutt_strncmp (buf->data, "body", 4) == 0)
+-    list = &ColorBodyList;
+-  else if (mutt_strncmp (buf->data, "header", 7) == 0)
+-    list = &ColorHdrList;
+-  else
++  if (object > MT_COLOR_INDEX_SUBJECT) { /* uncolor index column */
++    ColorDefs[object] = 0;
++    set_option (OPTFORCEREDRAWINDEX);
++    return 0;
++  }
 +
-+### How to Apply These Terms to Your New Programs
- 
--  If you develop a new program, and you want it to be of the greatest
-+If you develop a new program, and you want it to be of the greatest
- possible use to the public, the best way to achieve this is to make it
- free software which everyone can redistribute and change under these terms.
- 
--  To do so, attach the following notices to the program.  It is safest
-+To do so, attach the following notices to the program.  It is safest
- to attach them to the start of each source file to most effectively
- convey the exclusion of warranty; and each file should have at least
--the "copyright" line and a pointer to where the full notice is found.
-+the “copyright” line and a pointer to where the full notice is found.
++  if ((mutt_strncmp (buf->data, "body",   4) != 0) &&
++      (mutt_strncmp (buf->data, "header", 6) != 0) &&
++      (mutt_strncmp (buf->data, "index",  5) != 0))
+   {
+     snprintf (err->data, err->dsize,
+ 	      _("%s: command valid only for index, body, header objects"),
+@@ -442,43 +515,22 @@ static int _mutt_parse_uncolor (BUFFER *buf, BUFFER *s, unsigned long data,
+     return 0;
+   }
  
-     <one line to give the program's name and a brief idea of what it does.>
-     Copyright (C) <year>  <name of author>
--
-+    
-     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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+-  do
+-  {
+-    mutt_extract_token (buf, s, 0);
+-    if (!mutt_strcmp ("*", buf->data))
+-    {
+-      for (tmp = *list; tmp; )
+-      {
+-        if (!do_cache)
+-	  do_cache = 1;
+-	last = tmp;
+-	tmp = tmp->next;
+-	mutt_free_color_line(&last, parse_uncolor);
+-      }
+-      *list = NULL;
+-    }
+-    else
+-    {
+-      for (last = NULL, tmp = *list; tmp; last = tmp, tmp = tmp->next)
+-      {
+-	if (!mutt_strcmp (buf->data, tmp->pattern))
+-	{
+-          if (!do_cache)
+-	    do_cache = 1;
+-	  dprint(1,(debugfile,"Freeing pattern \"%s\" from color list\n",
+-	                       tmp->pattern));
+-	  if (last)
+-	    last->next = tmp->next;
+-	  else
+-	    *list = tmp->next;
+-	  mutt_free_color_line(&tmp, parse_uncolor);
+-	  break;
+-	}
+-      }
+-    }
+-  }
+-  while (MoreArgs (s));
 -
-+    
-+    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.,
-+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- 
- Also add information on how to contact you by electronic and paper mail.
++  if (object == MT_COLOR_BODY)
++    mutt_do_uncolor (buf, s, &ColorBodyList, &do_cache, parse_uncolor);
++  else if (object == MT_COLOR_HEADER)
++    mutt_do_uncolor (buf, s, &ColorHdrList, &do_cache, parse_uncolor);
++  else if (object == MT_COLOR_INDEX)
++    mutt_do_uncolor (buf, s, &ColorIndexList, &do_cache, parse_uncolor);
++  else if (object == MT_COLOR_INDEX_AUTHOR)
++    mutt_do_uncolor (buf, s, &ColorIndexAuthorList, &do_cache, parse_uncolor);
++  else if (object == MT_COLOR_INDEX_FLAGS)
++    mutt_do_uncolor (buf, s, &ColorIndexFlagsList, &do_cache, parse_uncolor);
++  else if (object == MT_COLOR_INDEX_SUBJECT)
++    mutt_do_uncolor (buf, s, &ColorIndexSubjectList, &do_cache, parse_uncolor);
++#ifdef USE_NOTMUCH
++  else if (object == MT_COLOR_INDEX_TAG)
++    mutt_do_uncolor(buf, s, &ColorIndexTagList, &do_cache, parse_uncolor);
++#endif
  
-@@ -318,23 +314,23 @@
-     This is free software, and you are welcome to redistribute it
-     under certain conditions; type `show c' for details.
+   if (do_cache && !option (OPTNOCURSES))
+   {
+@@ -495,7 +547,7 @@ static int _mutt_parse_uncolor (BUFFER *buf, BUFFER *s, unsigned long data,
+ static int 
+ add_pattern (COLOR_LINE **top, const char *s, int sensitive,
+ 	     int fg, int bg, int attr, BUFFER *err,
+-	     int is_index)
++	     int is_index, int match)
+ {
  
--The hypothetical commands `show w' and `show c' should show the appropriate
-+The hypothetical commands `show w` and `show c` should show the appropriate
- parts of the General Public License.  Of course, the commands you use may
--be called something other than `show w' and `show c'; they could even be
-+be called something other than `show w` and `show c`; they could even be
- mouse-clicks or menu items--whatever suits your program.
- 
- You should also get your employer (if you work as a programmer) or your
--school, if any, to sign a "copyright disclaimer" for the program, if
-+school, if any, to sign a “copyright disclaimer” for the program, if
- necessary.  Here is a sample; alter the names:
- 
--  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
--  `Gnomovision' (which makes passes at compilers) written by James Hacker.
--
--  <signature of Ty Coon>, 1 April 1989
--  Ty Coon, President of Vice
-+    Yoyodyne, Inc., hereby disclaims all copyright interest in the program
-+    `Gnomovision' (which makes passes at compilers) written by James Hacker.
-+    
-+    <signature of Ty Coon>, 1 April 1989
-+    Ty Coon, President of Vice
- 
- This General Public License does not permit incorporating your program into
- proprietary programs.  If your program is a subroutine library, you may
- consider it more useful to permit linking proprietary applications with the
--library.  If this is what you want to do, use the GNU Library General
-+library.  If this is what you want to do, use the GNU Lesser General
- Public License instead of this License.
-diff -urN mutt-1.6.1/handler.c mutt-1.6.1-neomutt/handler.c
---- mutt-1.6.1/handler.c	2016-06-12 18:43:00.404447621 +0100
-+++ mutt-1.6.1-neomutt/handler.c	2016-06-12 18:43:00.701452253 +0100
-@@ -1595,7 +1595,9 @@
-   int origType;
-   char *savePrefix = NULL;
-   FILE *fp = NULL;
-+#ifndef HAVE_FMEMOPEN
-   char tempfile[_POSIX_PATH_MAX];
-+#endif
-   size_t tmplength = 0;
-   LOFF_T tmpoffset = 0;
-   int decode = 0;
-@@ -1603,6 +1605,11 @@
+   /* is_index used to store compiled pattern
+@@ -566,6 +618,7 @@ add_pattern (COLOR_LINE **top, const char *s, int sensitive,
+     }
+     tmp->next = *top;
+     tmp->pattern = safe_strdup (s);
++    tmp->match = match;
+ #ifdef HAVE_COLOR
+     if(fg != -1 && bg != -1)
+     {
+@@ -708,7 +761,7 @@ _mutt_parse_color (BUFFER *buf, BUFFER *s, BUFFER *err,
+ 		   parser_callback_t callback, short dry_run)
+ {
+   int object = 0, attr = 0, fg = 0, bg = 0, q_level = 0;
+-  int r = 0;
++  int r = 0, match = 0;
  
-   fseeko (s->fpin, b->offset, 0);
+   if(parse_object(buf, s, &object, &q_level, err) == -1)
+     return -1;
+@@ -718,18 +771,25 @@ _mutt_parse_color (BUFFER *buf, BUFFER *s, BUFFER *err,
  
-+#ifdef HAVE_FMEMOPEN
-+  char *temp;
-+  size_t tempsize;
-+#endif
-+
-   /* see if we need to decode this part before processing it */
-   if (b->encoding == ENCBASE64 || b->encoding == ENCQUOTEDPRINTABLE ||
-       b->encoding == ENCUUENCODED || plaintext ||
-@@ -1618,6 +1625,14 @@
-     {
-       /* decode to a tempfile, saving the original destination */
-       fp = s->fpout;
-+#ifdef HAVE_FMEMOPEN
-+     s->fpout = open_memstream (&temp, &tempsize);
-+     if (!s->fpout) {
-+       mutt_error _("Unable to open memory stream!");
-+       dprint (1, (debugfile, "Can't open memory stream.\n"));
-+       return -1;
-+     }
-+#else
-       mutt_mktemp (tempfile, sizeof (tempfile));
-       if ((s->fpout = safe_fopen (tempfile, "w")) == NULL)
-       {
-@@ -1625,6 +1640,7 @@
-         dprint (1, (debugfile, "Can't open %s.\n", tempfile));
-         return -1;
-       }
-+#endif
-       /* decoding the attachment changes the size and offset, so save a copy
-         * of the "real" values now, and restore them after processing
-         */
-@@ -1653,9 +1669,20 @@
-       /* restore final destination and substitute the tempfile for input */
-       s->fpout = fp;
-       fp = s->fpin;
-+#ifdef HAVE_FMEMOPEN
-+      if (tempsize) {
-+        s->fpin = fmemopen (temp, tempsize, "r");
-+      } else { /* fmemopen cannot handle zero-length buffers */
-+        s->fpin = safe_fopen ("/dev/null", "r");
-+      }
-+      if (!s->fpin) {
-+        mutt_perror ("failed to re-open memstream!");
-+        return -1;
-+      }
-+#else
-       s->fpin = fopen (tempfile, "r");
-       unlink (tempfile);
--
+   /* extract a regular expression if needed */
+   
+-  if (object == MT_COLOR_HEADER || object == MT_COLOR_BODY || object == MT_COLOR_INDEX)
+-  {
+-    if (!MoreArgs (s))
+-    {
++  if ((object == MT_COLOR_BODY) ||
++      (object == MT_COLOR_HEADER) ||
++      (object == MT_COLOR_INDEX) ||
++      (object == MT_COLOR_INDEX_AUTHOR) ||
++      (object == MT_COLOR_INDEX_FLAGS) ||
++      (object == MT_COLOR_INDEX_SUBJECT)
++#ifdef USE_NOTMUCH
++      || (object == MT_COLOR_INDEX_TAG)
 +#endif
-       /* restore the prefix */
-       s->prefix = savePrefix;
++      ) {
++    if (!MoreArgs (s)) {
+       strfcpy (err->data, _("too few arguments"), err->dsize);
+-      return (-1);
++      return -1;
      }
-@@ -1680,6 +1707,10 @@
  
-       /* restore the original source stream */
-       safe_fclose (&s->fpin);
-+#ifdef HAVE_FMEMOPEN
-+      if (tempsize)
-+        FREE(&temp);
-+#endif
-       s->fpin = fp;
-     }
+     mutt_extract_token (buf, s, 0);
    }
-diff -urN mutt-1.6.1/hash.c mutt-1.6.1-neomutt/hash.c
---- mutt-1.6.1/hash.c	2016-06-12 18:43:00.404447621 +0100
-+++ mutt-1.6.1-neomutt/hash.c	2016-06-12 18:43:00.702452269 +0100
-@@ -57,6 +57,7 @@
-   if (nelem == 0)
-     nelem = 2;
-   table->nelem = nelem;
-+  table->curnelem = 0;
-   table->table = safe_calloc (nelem, sizeof (struct hash_elem *));
-   if (lower)
+    
+-  if (MoreArgs (s))
++  if (MoreArgs (s) && (object != MT_COLOR_STATUS))
    {
-@@ -71,6 +72,29 @@
-   return table;
- }
- 
-+HASH *hash_resize (HASH *ptr, int nelem, int lower)
-+{
-+  HASH *table;
-+  struct hash_elem *elem, *tmp;
-+  int i;
+     strfcpy (err->data, _("too many arguments"), err->dsize);
+     return (-1);
+@@ -754,14 +814,59 @@ _mutt_parse_color (BUFFER *buf, BUFFER *s, BUFFER *err,
+ #endif
+   
+   if (object == MT_COLOR_HEADER)
+-    r = add_pattern (&ColorHdrList, buf->data, 0, fg, bg, attr, err,0);
++    r = add_pattern (&ColorHdrList, buf->data, 0, fg, bg, attr, err, 0, match);
+   else if (object == MT_COLOR_BODY)
+-    r = add_pattern (&ColorBodyList, buf->data, 1, fg, bg, attr, err, 0);
++    r = add_pattern (&ColorBodyList, buf->data, 1, fg, bg, attr, err, 0, match);
++  else if ((object == MT_COLOR_STATUS) && MoreArgs (s)) {
++    /* 'color status fg bg' can have up to 2 arguments:
++     * 0 arguments: sets the default status color (handled below by else part)
++     * 1 argument : colorize pattern on match
++     * 2 arguments: colorize nth submatch of pattern
++     */
++    mutt_extract_token (buf, s, 0);
 +
-+  table = hash_create (nelem, lower);
++    if (MoreArgs (s)) {
++      BUFFER temporary;
++      memset (&temporary, 0, sizeof (BUFFER));
++      mutt_extract_token (&temporary, s, 0);
++      match = atoi (temporary.data);
++      FREE(&temporary.data);
++    }
 +
-+  for (i = 0; i < ptr->nelem; i++)
-+  {
-+    for (elem = ptr->table[i]; elem; )
-+    {
-+      tmp = elem;
-+      elem = elem->next;
-+      hash_insert (table, tmp->key, tmp->data, 1);
-+      FREE (&tmp);
++    if (MoreArgs (s)) {
++      strfcpy (err->data, _("too many arguments"), err->dsize);
++      return -1;
 +    }
-+  }
-+  FREE (&ptr->table);
-+  FREE (&ptr);
-+  return table;
-+}
 +
- /* table        hash table to update
-  * key          key to hash on
-  * data         data to associate with `key'
-@@ -90,6 +114,7 @@
++    r = add_pattern (&ColorStatusList, buf->data, 1,
++		    fg, bg, attr, err, 0, match);
++  }
+   else if (object == MT_COLOR_INDEX)
    {
-     ptr->next = table->table[h];
-     table->table[h] = ptr;
-+    table->curnelem++;
+-    r = add_pattern (&ColorIndexList, buf->data, 1, fg, bg, attr, err, 1);
++    r = add_pattern (&ColorIndexList, buf->data, 1,
++		    fg, bg, attr, err, 1, match);
++    set_option (OPTFORCEREDRAWINDEX);
++  } else if (object == MT_COLOR_INDEX_AUTHOR) {
++    r = add_pattern (&ColorIndexAuthorList, buf->data, 1,
++		    fg, bg, attr, err, 1, match);
++    set_option (OPTFORCEREDRAWINDEX);
++  } else if (object == MT_COLOR_INDEX_FLAGS) {
++    r = add_pattern (&ColorIndexFlagsList, buf->data, 1,
++		    fg, bg, attr, err, 1, match);
++    set_option (OPTFORCEREDRAWINDEX);
++  } else if (object == MT_COLOR_INDEX_SUBJECT) {
++    r = add_pattern (&ColorIndexSubjectList, buf->data, 1,
++		    fg, bg, attr, err, 1, match);
++    set_option (OPTFORCEREDRAWINDEX);
++  }
++#ifdef USE_NOTMUCH
++  else if (object == MT_COLOR_INDEX_TAG)
++  {
++    r = add_pattern (&ColorIndexTagList, buf->data, 1,
++		    fg, bg, attr, err, 1, match);
+     set_option (OPTFORCEREDRAWINDEX);
    }
-   else
++#endif
+   else if (object == MT_COLOR_QUOTED)
    {
-@@ -112,6 +137,7 @@
-     else
-       table->table[h] = ptr;
-     ptr->next = tmp;
-+    table->curnelem++;
+     if (q_level >= ColorQuoteSize)
+@@ -787,7 +892,11 @@ _mutt_parse_color (BUFFER *buf, BUFFER *s, BUFFER *err,
+       ColorQuote[q_level] = fgbgattr_to_color(fg, bg, attr);
    }
-   return h;
- }
-@@ -142,6 +168,7 @@
-       if (destroy)
- 	destroy (ptr->data);
-       FREE (&ptr);
-+      table->curnelem--;
-       
-       ptr = *last;
-     }
-@@ -176,3 +203,30 @@
-   FREE (&pptr->table);
-   FREE (ptr);		/* __FREE_CHECKED__ */
- }
-+
-+struct hash_elem *hash_walk(const HASH *table, struct hash_walk_state *state)
-+{
-+  if (state->last && state->last->next)
+   else
 +  {
-+    state->last = state->last->next;
-+    return state->last;
+     ColorDefs[object] = fgbgattr_to_color(fg, bg, attr);
++    if (object > MT_COLOR_INDEX_AUTHOR)
++      set_option (OPTFORCEREDRAWINDEX);
 +  }
-+
-+  if (state->last)
-+    state->index++;
-+
-+  while (state->index < table->nelem)
-+  {
-+    if (table->table[state->index])
-+    {
-+      state->last = table->table[state->index];
-+      return state->last;
-+    }
-+    state->index++;
-+  } 
-+
-+  state->index = 0;
-+  state->last = NULL;
-+  return NULL;
-+}
-+
-diff -urN mutt-1.6.1/hash.h mutt-1.6.1-neomutt/hash.h
---- mutt-1.6.1/hash.h	2016-06-12 18:43:00.404447621 +0100
-+++ mutt-1.6.1-neomutt/hash.h	2016-06-12 18:43:00.702452269 +0100
-@@ -28,7 +28,7 @@
- 
- typedef struct
- {
--  int nelem;
-+  int nelem, curnelem;
-   struct hash_elem **table;
-   unsigned int (*hash_string)(const unsigned char *, unsigned int);
-   int (*cmp_string)(const char *, const char *);
-@@ -41,9 +41,17 @@
  
- HASH *hash_create (int nelem, int lower);
- int hash_insert (HASH * table, const char *key, void *data, int allow_dup);
-+HASH *hash_resize (HASH * table, int nelem, int lower);
- void *hash_find_hash (const HASH * table, int hash, const char *key);
- void hash_delete_hash (HASH * table, int hash, const char *key, const void *data,
- 		       void (*destroy) (void *));
- void hash_destroy (HASH ** hash, void (*destroy) (void *));
+   return (r);
+ }
+diff --git a/commands.c b/commands.c
+index 2a0cdc9..1af59f4 100644
+--- a/commands.c
++++ b/commands.c
+@@ -40,6 +40,10 @@
+ #include "imap.h"
+ #endif
  
-+struct hash_walk_state {
-+  int index;
-+  struct hash_elem *last;
-+};
-+
-+struct hash_elem *hash_walk(const HASH *table, struct hash_walk_state *state);
++#ifdef USE_NOTMUCH
++#include "mutt_notmuch.h"
++#endif
 +
- #endif
-diff -urN mutt-1.6.1/hcache.c mutt-1.6.1-neomutt/hcache.c
---- mutt-1.6.1/hcache.c	2016-06-12 18:43:00.404447621 +0100
-+++ mutt-1.6.1-neomutt/hcache.c	2016-06-12 18:43:00.702452269 +0100
-@@ -439,13 +439,19 @@
-   d = dump_char(e->message_id, d, off, 0);
-   d = dump_char(e->supersedes, d, off, 0);
-   d = dump_char(e->date, d, off, 0);
--  d = dump_char(e->x_label, d, off, convert);
+ #include "buffy.h"
  
-   d = dump_buffer(e->spam, d, off, convert);
+ #include <errno.h>
+@@ -61,6 +65,7 @@ int mutt_display_message (HEADER *cur)
+   char tempfile[_POSIX_PATH_MAX], buf[LONG_STRING];
+   int rc = 0, builtin = 0;
+   int cmflags = M_CM_DECODE | M_CM_DISPLAY | M_CM_CHARCONV;
++  int chflags;
+   FILE *fpout = NULL;
+   FILE *fpfilterout = NULL;
+   pid_t filterpid = -1;
+@@ -145,8 +150,14 @@ int mutt_display_message (HEADER *cur)
+     fputs ("\n\n", fpout);
+   }
  
-   d = dump_list(e->references, d, off, 0);
-   d = dump_list(e->in_reply_to, d, off, 0);
-   d = dump_list(e->userhdrs, d, off, convert);
-+  d = dump_list(e->labels, d, off, convert);
-+
-+#ifdef USE_NNTP
-+  d = dump_char(e->xref, d, off, 0);
-+  d = dump_char(e->followup_to, d, off, 0);
-+  d = dump_char(e->x_comment_to, d, off, convert);
+-  res = mutt_copy_message (fpout, Context, cur, cmflags,
+-       	(option (OPTWEED) ? (CH_WEED | CH_REORDER) : 0) | CH_DECODE | CH_FROM | CH_DISPLAY);
++  chflags = (option (OPTWEED) ? (CH_WEED | CH_REORDER) : 0)
++           | CH_DECODE | CH_FROM | CH_DISPLAY;
++#ifdef USE_NOTMUCH
++  if (Context->magic == M_NOTMUCH)
++    chflags |= CH_VIRTUAL;
 +#endif
++  res = mutt_copy_message (fpout, Context, cur, cmflags, chflags);
++
+   if ((safe_fclose (&fpout) != 0 && errno != EPIPE) || res < 0)
+   {
+     mutt_error (_("Could not copy message"));
+@@ -533,9 +544,9 @@ int mutt_select_sort (int reverse)
+   int method = Sort; /* save the current method in case of abort */
  
-   return d;
+   switch (mutt_multi_choice (reverse ?
+-			     _("Rev-Sort (d)ate/(f)rm/(r)ecv/(s)ubj/t(o)/(t)hread/(u)nsort/si(z)e/s(c)ore/s(p)am?: ") :
+-			     _("Sort (d)ate/(f)rm/(r)ecv/(s)ubj/t(o)/(t)hread/(u)nsort/si(z)e/s(c)ore/s(p)am?: "),
+-			     _("dfrsotuzcp")))
++			     _("Rev-Sort Date/Frm/Recv/Subj/tO/Thread/Unsort/siZe/sCore/sPam/Label?: ") :
++			     _("Sort Date/Frm/Recv/Subj/tO/Thread/Unsort/siZe/sCore/sPam/Label?: "),
++			     _("dfrsotuzcpl")))
+   {
+   case -1: /* abort - don't resort */
+     return -1;
+@@ -579,6 +590,10 @@ int mutt_select_sort (int reverse)
+   case 10: /* s(p)am */
+     Sort = SORT_SPAM;
+     break;
++
++  case 11: /* (l)abel */
++    Sort = SORT_LABEL;
++    break;
+   }
+   if (reverse)
+     Sort |= SORT_REVERSE;
+@@ -720,6 +735,7 @@ int _mutt_save_message (HEADER *h, CONTEXT *ctx, int delete, int decode, int dec
+     if (option (OPTDELETEUNTAG))
+       mutt_set_flag (Context, h, M_TAG, 0);
+   }
++  mutt_set_flag (Context, h, M_APPENDED, 1);
+   
+   return 0;
  }
-@@ -476,13 +482,19 @@
-   restore_char(&e->message_id, d, off, 0);
-   restore_char(&e->supersedes, d, off, 0);
-   restore_char(&e->date, d, off, 0);
--  restore_char(&e->x_label, d, off, convert);
- 
-   restore_buffer(&e->spam, d, off, convert);
- 
-   restore_list(&e->references, d, off, 0);
-   restore_list(&e->in_reply_to, d, off, 0);
-   restore_list(&e->userhdrs, d, off, convert);
-+  restore_list(&e->labels, d, off, convert);
+@@ -846,19 +862,30 @@ int mutt_save_message (HEADER *h, int delete,
+     }
+     else
+     {
++      int rc = 0;
 +
-+#ifdef USE_NNTP
-+  restore_char(&e->xref, d, off, 0);
-+  restore_char(&e->followup_to, d, off, 0);
-+  restore_char(&e->x_comment_to, d, off, convert);
++#ifdef USE_NOTMUCH
++      if (Context->magic == M_NOTMUCH)
++        nm_longrun_init(Context, TRUE);
 +#endif
- }
+       for (i = 0; i < Context->vcount; i++)
+       {
+ 	if (Context->hdrs[Context->v2r[i]]->tagged)
+ 	{
+ 	  mutt_message_hook (Context, Context->hdrs[Context->v2r[i]], M_MESSAGEHOOK);
+-	  if (_mutt_save_message(Context->hdrs[Context->v2r[i]],
+-			     &ctx, delete, decode, decrypt) != 0)
+-          {
+-            mx_close_mailbox (&ctx, NULL);
+-            return -1;
+-          }
++	  if ((rc = _mutt_save_message(Context->hdrs[Context->v2r[i]],
++			     &ctx, delete, decode, decrypt) != 0))
++	    break;
+ 	}
+       }
++#ifdef USE_NOTMUCH
++      if (Context->magic == M_NOTMUCH)
++        nm_longrun_done(Context);
++#endif
++      if (rc != 0) {
++	mx_close_mailbox (&ctx, NULL);
++	return -1;
++      }
+     }
  
- static int
-diff -urN mutt-1.6.1/hdrline.c mutt-1.6.1-neomutt/hdrline.c
---- mutt-1.6.1/hdrline.c	2016-06-12 18:43:00.404447621 +0100
-+++ mutt-1.6.1-neomutt/hdrline.c	2016-06-12 18:43:00.702452269 +0100
-@@ -36,6 +36,10 @@
- #include <alloca.h>
+     need_buffy_cleanup = (ctx.magic == M_MBOX || ctx.magic == M_MMDF);
+diff --git a/complete.c b/complete.c
+index d0ee4af..8dc48cd 100644
+--- a/complete.c
++++ b/complete.c
+@@ -25,6 +25,9 @@
+ #include "mailbox.h"
+ #include "imap.h"
  #endif
++#ifdef USE_NNTP
++#include "nntp.h"
++#endif
  
-+#ifdef USE_NOTMUCH
-+#include "mutt_notmuch.h"
+ #include <dirent.h>
+ #include <string.h>
+@@ -48,9 +51,70 @@ int mutt_complete (char *s, size_t slen)
+   char filepart[_POSIX_PATH_MAX];
+ #ifdef USE_IMAP
+   char imap_path[LONG_STRING];
 +#endif
-+
- int mutt_is_mail_list (ADDRESS *addr)
- {
-   if (!mutt_match_rx_list (addr->mailbox, UnMailLists))
-@@ -103,6 +107,38 @@
-   return 0;
- }
  
-+/**
-+ * add_index_color - XXX
-+ *
-+ * Takes the color to embed, the buffer to manipulate and the buffer length as
-+ * arguments.
-+ * Returns the number of chars written.
-+ */
-+static size_t
-+add_index_color (char *buf, size_t buflen, format_flag flags, char color)
-+{
-+	int len;
+   dprint (2, (debugfile, "mutt_complete: completing %s\n", s));
+ 
++#ifdef USE_NNTP
++  if (option (OPTNEWS))
++  {
++    NNTP_SERVER *nserv = CurrentNewsSrv;
++    unsigned int n = 0;
 +
-+	/* only add color markers if we are operating on main index entries. */
-+	if (!(flags & M_FORMAT_INDEX))
-+		return 0;
++    strfcpy (filepart, s, sizeof (filepart));
 +
-+	if (color == MT_COLOR_INDEX) { /* buf might be uninitialized other cases */
-+		len = mutt_strlen (buf);
-+		buf += len;
-+		buflen -= len;
++    /* special case to handle when there is no filepart yet
++     * find the first subscribed newsgroup */
++    len = mutt_strlen (filepart);
++    if (len == 0)
++    {
++      for (; n < nserv->groups_num; n++)
++      {
++	NNTP_DATA *nntp_data = nserv->groups_list[n];
++
++	if (nntp_data && nntp_data->subscribed)
++	{
++	  strfcpy (filepart, nntp_data->group, sizeof (filepart));
++	  init = 1;
++	  n++;
++	  break;
 +	}
++      }
++    }
 +
-+	if (buflen < 2)
-+		return 0;
++    for (; n < nserv->groups_num; n++)
++    {
++      NNTP_DATA *nntp_data = nserv->groups_list[n];
 +
-+	buf[0] = M_SPECIAL_INDEX;
-+	buf[1] = color;
-+	buf[2] = '\0';
++      if (nntp_data && nntp_data->subscribed &&
++	  mutt_strncmp (nntp_data->group, filepart, len) == 0)
++      {
++	if (init)
++	{
++	  for (i = 0; filepart[i] && nntp_data->group[i]; i++)
++	  {
++	    if (filepart[i] != nntp_data->group[i])
++	    {
++	      filepart[i] = 0;
++	      break;
++	    }
++	  }
++	  filepart[i] = 0;
++	}
++	else
++	{
++	  strfcpy (filepart, nntp_data->group, sizeof (filepart));
++	  init = 1;
++	}
++      }
++    }
 +
-+	return 2;
-+}
++    strcpy (s, filepart);
++    return (init ? 0 : -1);
++  }
++#endif
 +
- static void make_from (ENVELOPE *hdr, char *buf, size_t len, int do_lists)
- {
-   int me;
-@@ -211,7 +247,10 @@
-  * %E = number of messages in current thread
-  * %f = entire from line
-  * %F = like %n, unless from self
-+ * %g = message labels (e.g. notmuch tags)
-+ * %g = newsgroup name (if compiled with NNTP support)
-  * %i = message-id
-+ * %I = initials of author
-  * %l = number of lines in the message
-  * %L = like %F, except `lists' are displayed first
-  * %m = number of messages in the mailbox
-@@ -227,6 +266,8 @@
-  * %T = $to_chars
-  * %u = user (login) name of author
-  * %v = first name of author, unless from self
-+ * %W = where user is (organization)
-+ * %x = `x-comment-to:' field (if present and compiled with NNTP support)
-  * %X = number of MIME attachments
-  * %y = `x-label:' field (if present)
-  * %Y = `x-label:' field (if present, tree unfolded, and != parent's x-label)
-@@ -255,6 +296,7 @@
- #define THREAD_NEW (threads && hdr->collapsed && hdr->num_hidden > 1 && mutt_thread_contains_unread (ctx, hdr) == 1)
- #define THREAD_OLD (threads && hdr->collapsed && hdr->num_hidden > 1 && mutt_thread_contains_unread (ctx, hdr) == 2)
-   size_t len;
-+  size_t colorlen;
- 
-   hdr = hfi->hdr;
-   ctx = hfi->ctx;
-@@ -265,7 +307,9 @@
-     case 'A':
-       if(hdr->env->reply_to && hdr->env->reply_to->mailbox)
-       {
--	mutt_format_s (dest, destlen, prefix, mutt_addr_for_display (hdr->env->reply_to));
-+        colorlen = add_index_color (dest, destlen, flags, MT_COLOR_INDEX_AUTHOR);
-+        mutt_format_s (dest + colorlen, destlen - colorlen, prefix, mutt_addr_for_display (hdr->env->reply_to));
-+        add_index_color (dest + colorlen, destlen - colorlen, flags, MT_COLOR_INDEX);
- 	break;
-       }
-       /* fall through if 'A' returns nothing */
-@@ -273,7 +317,9 @@
-     case 'a':
-       if(hdr->env->from && hdr->env->from->mailbox)
-       {
--	mutt_format_s (dest, destlen, prefix, mutt_addr_for_display (hdr->env->from));
-+        colorlen = add_index_color (dest, destlen, flags, MT_COLOR_INDEX_AUTHOR);
-+        mutt_format_s (dest + colorlen, destlen - colorlen, prefix, mutt_addr_for_display (hdr->env->from));
-+        add_index_color (dest + colorlen, destlen - colorlen, flags, MT_COLOR_INDEX);
-       }
-       else
-         dest[0] = '\0';
-@@ -306,12 +352,16 @@
-       break;
-     
-     case 'c':
-+      colorlen = add_index_color (dest, destlen, flags, MT_COLOR_INDEX_SIZE);
-       mutt_pretty_size (buf2, sizeof (buf2), (long) hdr->content->length);
--      mutt_format_s (dest, destlen, prefix, buf2);
-+      mutt_format_s (dest + colorlen, destlen - colorlen, prefix, buf2);
-+      add_index_color (dest + colorlen, destlen - colorlen, flags, MT_COLOR_INDEX);
-       break;
++#ifdef USE_IMAP
+   /* we can use '/' as a delimiter, imap_complete rewrites it */
+   if (*s == '=' || *s == '+' || *s == '!')
+   {
+diff --git a/compose.c b/compose.c
+index 6af817f..d555d92 100644
+--- a/compose.c
++++ b/compose.c
+@@ -32,11 +32,19 @@
+ #include "mailbox.h"
+ #include "sort.h"
+ #include "charset.h"
++#ifdef USE_SIDEBAR
++#include "sidebar.h"
++#endif
++#include "mx.h"
  
-     case 'C':
--      snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
-+      colorlen = add_index_color (fmt, sizeof (fmt), flags, MT_COLOR_INDEX_NUMBER);
-+      snprintf (fmt + colorlen, sizeof (fmt) - colorlen, "%%%sd", prefix);
-+      add_index_color (fmt + colorlen, sizeof (fmt) - colorlen, flags, MT_COLOR_INDEX);
-       snprintf (dest, destlen, fmt, hdr->msgno + 1);
-       break;
+ #ifdef MIXMASTER
+ #include "remailer.h"
+ #endif
  
-@@ -327,6 +377,98 @@
- 	const char *cp;
- 	struct tm *tm; 
- 	time_t T;
-+	int i = 0, invert = 0;
-+
-+	if (optional && ((op == '[') || (op == '('))) {
-+	  char *is;
-+	  T = time (NULL);
-+	  tm = localtime (&T);
-+	  T -= (op == '(') ? hdr->received : hdr->date_sent;
-+
-+	  is = (char *) prefix;
-+	  if (*is == '>') {
-+	    invert = 1;
-+	    is++;
-+	  }
-+
-+	  while (*is && (*is != '?')) {
-+	    int t = strtol (is, &is, 10);
-+	    /* semi-broken (assuming 30 days in all months) */
-+	    switch (*(is++)) {
-+	      case 'y':
-+		if (t > 1) {
-+		  t--;
-+		  t *= (60 * 60 * 24 * 365);
-+		}
-+		t += ((tm->tm_mon  * 60 * 60 * 24 * 30) +
-+		      (tm->tm_mday * 60 * 60 * 24) +
-+		      (tm->tm_hour * 60 * 60) +
-+		      (tm->tm_min  * 60) +
-+		       tm->tm_sec);
-+		break;
-+
-+	      case 'm':
-+		if (t > 1) {
-+		  t--;
-+		  t *= (60 * 60 * 24 * 30);
-+		}
-+		t += ((tm->tm_mday * 60 * 60 * 24) +
-+		      (tm->tm_hour * 60 * 60) +
-+		      (tm->tm_min  * 60) +
-+		      tm->tm_sec);
-+		break;
-+
-+	      case 'w':
-+		if (t > 1) {
-+		  t--;
-+		  t *= (60 * 60 * 24 * 7);
-+		}
-+		t += ((tm->tm_wday * 60 * 60 * 24) +
-+		      (tm->tm_hour * 60 * 60) +
-+		      (tm->tm_min  * 60) +
-+		       tm->tm_sec);
-+		break;
-+
-+	      case 'd':
-+		if (t > 1) {
-+		  t--;
-+		  t *= (60 * 60 * 24);
-+		}
-+		t += ((tm->tm_hour * 60 * 60) +
-+		      (tm->tm_min  * 60) +
-+		       tm->tm_sec);
-+		break;
-+
-+	      case 'H':
-+		if (t > 1) {
-+		  t--;
-+		  t *= (60 * 60);
-+		}
-+		t += ((tm->tm_min * 60) +
-+		       tm->tm_sec);
-+		break;
-+
-+	      case 'M':
-+		if (t > 1) {
-+		  t--;
-+		  t *= (60);
-+		}
-+		t += (tm->tm_sec);
-+		break;
-+
-+	      default:
-+		break;
-+	    }
-+	    i += t;
-+	  }
-+
-+	  if (i < 0)
-+	    i *= -1;
++#ifdef USE_NNTP
++#include "nntp.h"
++#endif
 +
-+	  if (((T > i) || (T < (-1*i))) ^ invert)
-+	    optional = 0;
-+	  break;
-+	}
- 
- 	p = dest;
- 
-@@ -410,7 +552,10 @@
- 	if (do_locales)
- 	  setlocale (LC_TIME, "C");
+ #include <errno.h>
+ #include <string.h>
+ #include <sys/stat.h>
+@@ -67,12 +75,18 @@ enum
+   HDR_CRYPT,
+   HDR_CRYPTINFO,
  
--	mutt_format_s (dest, destlen, prefix, buf2);
-+	colorlen = add_index_color (dest, destlen, flags, MT_COLOR_INDEX_DATE);
-+	mutt_format_s (dest + colorlen, destlen - colorlen, prefix, buf2);
-+	add_index_color (dest + colorlen, destlen - colorlen, flags, MT_COLOR_INDEX);
++#ifdef USE_NNTP
++  HDR_NEWSGROUPS,
++  HDR_FOLLOWUPTO,
++  HDR_XCOMMENTTO,
++#endif
 +
- 	if (len > 0 && op != 'd' && op != 'D') /* Skip ending op */
- 	  src = cp + 1;
-       }
-@@ -440,13 +585,28 @@
-     case 'F':
-       if (!optional)
-       {
-+        colorlen = add_index_color (dest, destlen, flags, MT_COLOR_INDEX_AUTHOR);
-         make_from (hdr->env, buf2, sizeof (buf2), 0);
--	mutt_format_s (dest, destlen, prefix, buf2);
-+        mutt_format_s (dest + colorlen, destlen - colorlen, prefix, buf2);
-+        add_index_color (dest + colorlen, destlen - colorlen, flags, MT_COLOR_INDEX);
-       }
-       else if (mutt_addr_is_user (hdr->env->from))
-         optional = 0;
-       break;
+   HDR_ATTACH  = (HDR_FCC + 5) /* where to start printing the attachments */
+ };
  
-+#ifdef USE_NOTMUCH
-+    case 'g':
-+      if (!optional)
-+      {
-+        colorlen = add_index_color(dest, destlen, flags, MT_COLOR_INDEX_TAGS);
-+        mutt_format_s (dest+colorlen, destlen-colorlen, prefix, nm_header_get_tags_transformed(hdr));
-+        add_index_color(dest+colorlen, destlen-colorlen, flags, MT_COLOR_INDEX);
-+      }
-+      else if (!nm_header_get_tags_transformed(hdr))
-+        optional = 0;
-+      break;
+-#define HDR_XOFFSET 10
+-#define TITLE_FMT "%10s" /* Used for Prompts, which are ASCII */
+-#define W (COLS - HDR_XOFFSET)
++#define HDR_XOFFSET 14
++#define TITLE_FMT "%14s" /* Used for Prompts, which are ASCII */
++#define W (COLS - HDR_XOFFSET - SidebarWidth)
+ 
+ static const char * const Prompts[] =
+ {
+@@ -83,6 +97,16 @@ static const char * const Prompts[] =
+   "Subject: ",
+   "Reply-To: ",
+   "Fcc: "
++#ifdef USE_NNTP
++#ifdef MIXMASTER
++  ,""
 +#endif
-+
-     case 'H':
-       /* (Hormel) spam score */
-       if (optional)
-@@ -459,15 +619,45 @@
++  ,""
++  ,""
++  ,"Newsgroups: "
++  ,"Followup-To: "
++  ,"X-Comment-To: "
++#endif
+ };
  
-       break;
+ static const struct mapping_t ComposeHelp[] = {
+@@ -97,9 +121,22 @@ static const struct mapping_t ComposeHelp[] = {
+   { NULL,	0 }
+ };
  
 +#ifdef USE_NNTP
-+    case 'q':
-+      mutt_format_s (dest, destlen, prefix, hdr->env->newsgroups ? hdr->env->newsgroups : "");
-+      break;
++static struct mapping_t ComposeNewsHelp[] = {
++  { N_("Send"),		OP_COMPOSE_SEND_MESSAGE },
++  { N_("Abort"),	OP_EXIT },
++  { "Newsgroups",	OP_COMPOSE_EDIT_NEWSGROUPS },
++  { "Subj",		OP_COMPOSE_EDIT_SUBJECT },
++  { N_("Attach file"),	OP_COMPOSE_ATTACH_FILE },
++  { N_("Descrip"),	OP_COMPOSE_EDIT_DESCRIPTION },
++  { N_("Help"),		OP_HELP },
++  { NULL,		0 }
++};
 +#endif
 +
-     case 'i':
-       mutt_format_s (dest, destlen, prefix, hdr->env->message_id ? hdr->env->message_id : "<no.id>");
-       break;
- 
-+    case 'I':
-+      {
-+	int iflag = FALSE;
-+	int j = 0;
-+
-+	for (i = 0; hdr->env->from && hdr->env->from->personal &&
-+		    hdr->env->from->personal[i] && (j < (SHORT_STRING - 1)); i++) {
-+	  if (isalpha ((int) hdr->env->from->personal[i])) {
-+	    if (!iflag) {
-+	      buf2[j++] = hdr->env->from->personal[i];
-+	      iflag = TRUE;
-+	    }
-+	  } else {
-+	    iflag = FALSE;
-+	  }
-+	}
-+
-+	buf2[j] = '\0';
-+      }
-+      mutt_format_s (dest, destlen, prefix, buf2);
-+      break;
-+
-     case 'l':
-       if (!optional)
-       {
- 	snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
--	snprintf (dest, destlen, fmt, (int) hdr->lines);
-+	colorlen = add_index_color (dest, destlen, flags, MT_COLOR_INDEX_SIZE);
-+	snprintf (dest + colorlen, destlen - colorlen, fmt, (int) hdr->lines);
-+	add_index_color (dest + colorlen, destlen - colorlen, flags, MT_COLOR_INDEX);
-       }
-       else if (hdr->lines <= 0)
-         optional = 0;
-@@ -476,8 +666,10 @@
-     case 'L':
-       if (!optional)
-       {
-+	colorlen = add_index_color (dest, destlen, flags, MT_COLOR_INDEX_AUTHOR);
- 	make_from (hdr->env, buf2, sizeof (buf2), 1);
--	mutt_format_s (dest, destlen, prefix, buf2);
-+	mutt_format_s (dest + colorlen, destlen - colorlen, prefix, buf2);
-+	add_index_color (dest + colorlen, destlen - colorlen, flags, MT_COLOR_INDEX);
-       }
-       else if (!check_for_mailing_list (hdr->env->to, NULL, NULL, 0) &&
- 	       !check_for_mailing_list (hdr->env->cc, NULL, NULL, 0))
-@@ -497,7 +689,9 @@
-       break;
+ static void snd_entry (char *b, size_t blen, MUTTMENU *menu, int num)
+ {
+-    mutt_FormatString (b, blen, 0, NONULL (AttachFormat), mutt_attach_fmt,
++  mutt_FormatString (b, blen, 0, COLS - SidebarWidth, NONULL (AttachFormat), mutt_attach_fmt,
+ 	    (unsigned long)(((ATTACHPTR **) menu->data)[num]),
+ 	    M_FORMAT_STAT_FILE | M_FORMAT_ARROWCURSOR);
+ }
+@@ -110,7 +147,7 @@ static void snd_entry (char *b, size_t blen, MUTTMENU *menu, int num)
  
-     case 'n':
--      mutt_format_s (dest, destlen, prefix, mutt_get_name (hdr->env->from));
-+      colorlen = add_index_color (dest, destlen, flags, MT_COLOR_INDEX_AUTHOR);
-+      mutt_format_s (dest + colorlen, destlen - colorlen, prefix, mutt_get_name (hdr->env->from));
-+      add_index_color (dest + colorlen, destlen - colorlen, flags, MT_COLOR_INDEX);
-       break;
+ static void redraw_crypt_lines (HEADER *msg)
+ {
+-  mvaddstr (HDR_CRYPT, 0, "Security: ");
++  mvprintw (HDR_CRYPT, SidebarWidth, TITLE_FMT, "Security: ");
  
-     case 'N':
-@@ -532,10 +726,15 @@
-       snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
-       if (!optional)
-       {
--	if (threads && is_index && hdr->collapsed && hdr->num_hidden > 1)
--	  snprintf (dest, destlen, fmt, hdr->num_hidden);
--	else if (is_index && threads)
--	  mutt_format_s (dest, destlen, prefix, " ");
-+	colorlen = add_index_color (dest, destlen, flags,
-+				   MT_COLOR_INDEX_COLLAPSED);
-+	if (threads && is_index && hdr->collapsed && hdr->num_hidden > 1) {
-+	  snprintf (dest + colorlen, destlen - colorlen, fmt, hdr->num_hidden);
-+	  add_index_color (dest, destlen - colorlen, flags, MT_COLOR_INDEX);
-+	} else if (is_index && threads) {
-+	  mutt_format_s (dest + colorlen, destlen - colorlen, prefix, " ");
-+	  add_index_color (dest, destlen - colorlen, flags, MT_COLOR_INDEX);
-+	}
- 	else
- 	  *dest = '\0';
-       }
-@@ -572,15 +771,20 @@
-       {
- 	if (flags & M_FORMAT_FORCESUBJ)
- 	{
--	  mutt_format_s (dest, destlen, "", NONULL (hdr->env->subject));
-+	  colorlen = add_index_color (dest, destlen, flags, MT_COLOR_INDEX_SUBJECT);
-+	  mutt_format_s (dest + colorlen, destlen - colorlen, "", NONULL (hdr->env->subject));
-+	  add_index_color (dest + colorlen, destlen - colorlen, flags, MT_COLOR_INDEX);
- 	  snprintf (buf2, sizeof (buf2), "%s%s", hdr->tree, dest);
- 	  mutt_format_s_tree (dest, destlen, prefix, buf2);
- 	}
- 	else
- 	  mutt_format_s_tree (dest, destlen, prefix, hdr->tree);
-       }
--      else
--	mutt_format_s (dest, destlen, prefix, NONULL (hdr->env->subject));
-+      else {
-+	colorlen = add_index_color (dest, destlen, flags, MT_COLOR_INDEX_SUBJECT);
-+	mutt_format_s (dest + colorlen, destlen - colorlen, prefix, NONULL (hdr->env->subject));
-+	add_index_color (dest + colorlen, destlen - colorlen, flags, MT_COLOR_INDEX);
-+      }
-       break;
+   if ((WithCrypto & (APPLICATION_PGP | APPLICATION_SMIME)) == 0)
+   {
+@@ -145,16 +182,24 @@ static void redraw_crypt_lines (HEADER *msg)
+       addstr (_(" (OppEnc mode)"));
  
-     case 'S':
-@@ -603,8 +807,11 @@
+   clrtoeol ();
+-  move (HDR_CRYPTINFO, 0);
++  move (HDR_CRYPTINFO, SidebarWidth);
+   clrtoeol ();
  
-       /* FOO - this is probably unsafe, but we are not likely to have such
- 	 a short string passed into this routine */
--      *dest = ch;
--      *(dest + 1) = 0;
-+      buf2[0] = ch;
-+      buf2[1] = 0;
-+      colorlen = add_index_color (dest, destlen, flags, MT_COLOR_INDEX_FLAGS);
-+      mutt_format_s (dest + colorlen, destlen - colorlen, prefix, buf2);
-+      add_index_color (dest + colorlen, destlen - colorlen, flags, MT_COLOR_INDEX);
-       break;
+   if ((WithCrypto & APPLICATION_PGP)
+       && (msg->security & APPLICATION_PGP) && (msg->security & SIGN))
+-    printw ("%s%s", _(" sign as: "), PgpSignAs ? PgpSignAs : _("<default>"));
++  {
++    char *s = _(" sign as: ");
++    int offset = HDR_XOFFSET + SidebarWidth - mbstowcs (NULL, s, 0);
++    mvprintw (HDR_CRYPTINFO, offset < 0 ? 0 : offset, "%s%s", s,
++	      PgpSignAs ? PgpSignAs : _("<default>"));
++  }
  
-     case 't':
-@@ -655,6 +862,22 @@
-       mutt_format_s (dest, destlen, prefix, buf2);
+   if ((WithCrypto & APPLICATION_SMIME)
+       && (msg->security & APPLICATION_SMIME) && (msg->security & SIGN)) {
+-      printw ("%s%s", _(" sign as: "), SmimeDefaultKey ? SmimeDefaultKey : _("<default>"));
++    char *s = _(" sign as: ");
++    int offset = HDR_XOFFSET + SidebarWidth - mbstowcs (NULL, s, 0);
++    mvprintw (HDR_CRYPTINFO, offset < 0 ? 0 : offset, "%s%s", s,
++	      SmimeDefaultKey ? SmimeDefaultKey : _("<default>"));
+   }
+ 
+   if ((WithCrypto & APPLICATION_SMIME)
+@@ -162,7 +207,7 @@ static void redraw_crypt_lines (HEADER *msg)
+       && (msg->security & ENCRYPT)
+       && SmimeCryptAlg
+       && *SmimeCryptAlg) {
+-      mvprintw (HDR_CRYPTINFO, 40, "%s%s", _("Encrypt with: "),
++      mvprintw (HDR_CRYPTINFO, SidebarWidth + 40, "%s%s", _("Encrypt with: "),
+ 		NONULL(SmimeCryptAlg));
+   }
+ }
+@@ -175,7 +220,8 @@ static void redraw_mix_line (LIST *chain)
+   int c;
+   char *t;
+ 
+-  mvaddstr (HDR_MIX, 0,     "     Mix: ");
++  /* L10N: "Mix" refers to the MixMaster chain for anonymous email */
++  mvprintw (HDR_MIX, SidebarWidth, TITLE_FMT, _("Mix: "));
+ 
+   if (!chain)
+   {
+@@ -190,7 +236,7 @@ static void redraw_mix_line (LIST *chain)
+     if (t && t[0] == '0' && t[1] == '\0')
+       t = "<random>";
+     
+-    if (c + mutt_strlen (t) + 2 >= COLS)
++    if (c + mutt_strlen (t) + 2 >= COLS - SidebarWidth)
        break;
  
-+    case 'W':
-+      if (!optional)
-+	mutt_format_s (dest, destlen, prefix, hdr->env->organization ? hdr->env->organization : "");
-+      else if (!hdr->env->organization)
-+	optional = 0;
-+      break;
-+
+     addstr (NONULL(t));
+@@ -242,20 +288,42 @@ static void draw_envelope_addr (int line, ADDRESS *addr)
+ 
+   buf[0] = 0;
+   rfc822_write_address (buf, sizeof (buf), addr, 1);
+-  mvprintw (line, 0, TITLE_FMT, Prompts[line - 1]);
++  mvprintw (line, SidebarWidth, TITLE_FMT, Prompts[line - 1]);
+   mutt_paddstr (W, buf);
+ }
+ 
+ static void draw_envelope (HEADER *msg, char *fcc)
+ {
++#ifdef USE_SIDEBAR
++  mutt_sb_draw();
++#endif
+   draw_envelope_addr (HDR_FROM, msg->env->from);
 +#ifdef USE_NNTP
-+    case 'x':
-+      if (!optional)
-+	mutt_format_s (dest, destlen, prefix, hdr->env->x_comment_to ? hdr->env->x_comment_to : "");
-+      else if (!hdr->env->x_comment_to)
-+	optional = 0;
-+      break;
++  if (!option (OPTNEWSSEND))
++  {
 +#endif
-+
-     case 'Z':
-     
-       ch = ' ';
-@@ -676,7 +899,9 @@
- 		hdr->tagged ? '*' :
- 		(hdr->flagged ? '!' :
- 		 (Tochars && ((i = mutt_user_is_recipient (hdr)) < mutt_strlen (Tochars)) ? Tochars[i] : ' ')));
--      mutt_format_s (dest, destlen, prefix, buf2);
-+      colorlen = add_index_color (dest, destlen, flags, MT_COLOR_INDEX_FLAGS);
-+      mutt_format_s (dest + colorlen, destlen - colorlen, prefix, buf2);
-+      add_index_color (dest + colorlen, destlen - colorlen, flags, MT_COLOR_INDEX);
-       break;
+   draw_envelope_addr (HDR_TO, msg->env->to);
+   draw_envelope_addr (HDR_CC, msg->env->cc);
+   draw_envelope_addr (HDR_BCC, msg->env->bcc);
+-  mvprintw (HDR_SUBJECT, 0, TITLE_FMT, Prompts[HDR_SUBJECT - 1]);
++#ifdef USE_NNTP
++  }
++  else
++  {
++    mvprintw (HDR_TO, 0, TITLE_FMT , Prompts[HDR_NEWSGROUPS - 1]);
++    mutt_paddstr (W, NONULL (msg->env->newsgroups));
++    mvprintw (HDR_CC, 0, TITLE_FMT , Prompts[HDR_FOLLOWUPTO - 1]);
++    mutt_paddstr (W, NONULL (msg->env->followup_to));
++    if (option (OPTXCOMMENTTO))
++    {
++      mvprintw (HDR_BCC, 0, TITLE_FMT , Prompts[HDR_XCOMMENTTO - 1]);
++      mutt_paddstr (W, NONULL (msg->env->x_comment_to));
++    }
++  }
++#endif
++  mvprintw (HDR_SUBJECT, SidebarWidth, TITLE_FMT, Prompts[HDR_SUBJECT - 1]);
+   mutt_paddstr (W, NONULL (msg->env->subject));
+   draw_envelope_addr (HDR_REPLYTO, msg->env->reply_to);
+-  mvprintw (HDR_FCC, 0, TITLE_FMT, Prompts[HDR_FCC - 1]);
++  mvprintw (HDR_FCC, SidebarWidth, TITLE_FMT, Prompts[HDR_FCC - 1]);
+   mutt_paddstr (W, fcc);
  
-     case 'X':
-@@ -694,40 +919,100 @@
+   if (WithCrypto)
+@@ -266,7 +334,7 @@ static void draw_envelope (HEADER *msg, char *fcc)
+ #endif
  
-      case 'y':
-        if (optional)
--	 optional = hdr->env->x_label ? 1 : 0;
-+	 optional = hdr->env->labels ? 1 : 0;
+   SETCOLOR (MT_COLOR_STATUS);
+-  mvaddstr (HDR_ATTACH - 1, 0, _("-- Attachments"));
++  mvaddstr (HDR_ATTACH - 1, SidebarWidth, _("-- Attachments"));
+   clrtoeol ();
  
--       mutt_format_s (dest, destlen, prefix, NONULL (hdr->env->x_label));
-+       colorlen = add_index_color (dest, destlen, flags, MT_COLOR_INDEX_LABEL);
-+       mutt_format_s (dest + colorlen, destlen - colorlen, prefix, mutt_labels(NULL, 0, hdr->env, NULL));
-+       add_index_color (dest + colorlen, destlen - colorlen, flags, MT_COLOR_INDEX);
-        break;
-- 
-+
-     case 'Y':
--      if (hdr->env->x_label)
-+      if (hdr->env->labels == NULL)
-       {
--	i = 1;	/* reduce reuse recycle */
--	htmp = NULL;
--	if (flags & M_FORMAT_TREE
--	    && (hdr->thread->prev && hdr->thread->prev->message
--		&& hdr->thread->prev->message->env->x_label))
--	  htmp = hdr->thread->prev->message;
--	else if (flags & M_FORMAT_TREE
--		 && (hdr->thread->parent && hdr->thread->parent->message
--		     && hdr->thread->parent->message->env->x_label))
--	  htmp = hdr->thread->parent->message;
--	if (htmp && mutt_strcasecmp (hdr->env->x_label,
--				     htmp->env->x_label) == 0)
--	  i = 0;
-+        if (optional)
-+          optional = 0;
-+        mutt_format_s(dest, destlen, prefix, "");
-+        break;
-       }
-       else
--	i = 0;
-+      {
-+        char labels[HUGE_STRING];
-+        char labelstmp[HUGE_STRING];
-+
-+        i = 1;  /* reduce reuse recycle */
-+        htmp = NULL;
-+        if ((flags & M_FORMAT_TREE) &&
-+            hdr->thread->prev &&
-+            hdr->thread->prev->message &&
-+            hdr->thread->prev->message->env->labels)
-+          htmp = hdr->thread->prev->message;
-+        else if ((flags & M_FORMAT_TREE) &&
-+                 hdr->thread->parent &&
-+                 hdr->thread->parent->message &&
-+                 hdr->thread->parent->message->env->labels)
-+          htmp = hdr->thread->parent->message;
-+
-+        mutt_labels(labels, sizeof(labels), hdr->env, NULL);
-+        if (htmp)
-+        {
-+          mutt_labels(labelstmp, sizeof(labelstmp), htmp->env, NULL);
-+          if (htmp && mutt_strcasecmp (labels, labelstmp) == 0)
-+            i = 0;
-+        }
-+
-+        if (optional)
-+	  optional = i;
-+
-+        colorlen = add_index_color (dest, destlen, flags, MT_COLOR_INDEX_LABEL);
-+        if (i)
-+	  mutt_format_s (dest + colorlen, destlen - colorlen, prefix, labels);
-+        else
-+          mutt_format_s (dest + colorlen, destlen - colorlen, prefix, "");
-+        add_index_color (dest + colorlen, destlen - colorlen, flags, MT_COLOR_INDEX);
-+      }
-+      break;
- 
--      if (optional)
--	optional = i;
-+#ifdef USE_NOTMUCH
-+    case 'G':
-+    {
-+      char *tag_transformed;
-+      char format[3];
-+      char *tag;
+   NORMAL_COLOR;
+@@ -302,7 +370,7 @@ static int edit_address_list (int line, ADDRESS **addr)
+   /* redraw the expanded list so the user can see the result */
+   buf[0] = 0;
+   rfc822_write_address (buf, sizeof (buf), *addr, 1);
+-  move (line, HDR_XOFFSET);
++  move (line, HDR_XOFFSET + SidebarWidth);
+   mutt_paddstr (W, buf);
+   
+   return 0;
+@@ -402,7 +470,7 @@ static unsigned long cum_attachs_size (MUTTMENU *menu)
+ }
  
--      if (i)
--        mutt_format_s (dest, destlen, prefix, NONULL (hdr->env->x_label));
-+      if (!optional)
-+      {
-+        format[0] = op;
-+        format[1] = *src;
-+        format[2] = 0;
-+
-+        tag = hash_find(TagFormats, format);
-+        if (tag != NULL)
-+        {
-+            tag_transformed = nm_header_get_tag_transformed(tag, hdr);
-+
-+            colorlen = add_index_color(dest, destlen, flags, MT_COLOR_INDEX_TAG);
-+            mutt_format_s (dest+colorlen, destlen-colorlen, prefix,
-+                           (tag_transformed) ? tag_transformed : "");
-+            add_index_color(dest+colorlen, destlen-colorlen, flags, MT_COLOR_INDEX);
-+        }
-+
-+        src++;
-+      }
-       else
--        mutt_format_s (dest, destlen, prefix, "");
-+      {
-+        format[0] = op;
-+        format[1] = *prefix;
-+        format[2] = 0;
-+
-+        tag = hash_find(TagFormats, format);
-+        if (tag != NULL)
-+          if (nm_header_get_tag_transformed(tag, hdr) == NULL)
-+            optional = 0;
-+      }
+ /* prototype for use below */
+-static void compose_status_line (char *buf, size_t buflen, size_t col, MUTTMENU *menu, 
++static void compose_status_line (char *buf, size_t buflen, size_t col, int cols, MUTTMENU *menu, 
+       const char *p);
  
-       break;
-+    }
-+#endif
+ /*
+@@ -418,7 +486,7 @@ static void compose_status_line (char *buf, size_t buflen, size_t col, MUTTMENU
+  */
  
-     default:
-       snprintf (dest, destlen, "%%%s%c", prefix, op);
-diff -urN mutt-1.6.1/headers.c mutt-1.6.1-neomutt/headers.c
---- mutt-1.6.1/headers.c	2016-06-12 18:43:00.405447637 +0100
-+++ mutt-1.6.1-neomutt/headers.c	2016-06-12 18:43:00.702452269 +0100
-@@ -114,6 +114,9 @@
-      $edit_headers set, we remove References: as they're likely invalid;
-      we can simply compare strings as we don't generate References for
-      multiple Message-Ids in IRT anyways */
-+#ifdef USE_NNTP
-+  if (!option (OPTNEWSSEND))
-+#endif
-   if (msg->env->in_reply_to &&
-       (!n->in_reply_to || mutt_strcmp (n->in_reply_to->data,
- 				       msg->env->in_reply_to->data) != 0))
-@@ -211,3 +214,199 @@
-     }
+ static const char *
+-compose_format_str (char *buf, size_t buflen, size_t col, char op, const char *src,
++compose_format_str (char *buf, size_t buflen, size_t col, int cols, char op, const char *src,
+ 		   const char *prefix, const char *ifstring,
+ 		   const char *elsestring,
+ 		   unsigned long data, format_flag flags)
+@@ -461,17 +529,17 @@ compose_format_str (char *buf, size_t buflen, size_t col, char op, const char *s
    }
+ 
+   if (optional)
+-    compose_status_line (buf, buflen, col, menu, ifstring);
++    compose_status_line (buf, buflen, col, cols, menu, ifstring);
+   else if (flags & M_FORMAT_OPTIONAL)
+-    compose_status_line (buf, buflen, col, menu, elsestring);
++    compose_status_line (buf, buflen, col, cols, menu, elsestring);
+ 
+   return (src);
  }
+ 
+-static void compose_status_line (char *buf, size_t buflen, size_t col, MUTTMENU *menu, 
+-      const char *p)
++static void compose_status_line (char *buf, size_t buflen, size_t col, int cols,
++                                 MUTTMENU *menu, const char *p)
+ {
+-  mutt_FormatString (buf, buflen, col, p, compose_format_str, 
++  mutt_FormatString (buf, buflen, col, cols, p, compose_format_str, 
+         (unsigned long) menu, 0);
+ }
+ 
+@@ -504,6 +572,12 @@ int mutt_compose_menu (HEADER *msg,   /* structure for new message */
+   /* Sort, SortAux could be changed in mutt_index_menu() */
+   int oldSort, oldSortAux;
+   struct stat st;
++#ifdef USE_NNTP
++  int news = 0;		/* is it a news article ? */
 +
-+void mutt_label_ref_dec(ENVELOPE *env)
-+{
-+  uintptr_t count;
-+  LIST *label;
-+
-+  if (!env || !env->labels || !Labels)
-+    return;
-+
-+  for (label = env->labels; label; label = label->next)
-+  {
-+    if (label->data == NULL)
-+      continue;
-+    count = (uintptr_t)hash_find(Labels, label->data);
-+    if (count)
-+    {
-+      hash_delete(Labels, label->data, NULL, NULL);
-+      count--;
-+      if (count > 0)
-+        hash_insert(Labels, label->data, (void *)count, 0);
-+    }
-+    dprint(1, (debugfile, "--label %s: %d\n", label->data, count));
-+  }
-+}
-+
-+void mutt_label_ref_inc(ENVELOPE *env)
-+{
-+  uintptr_t count;
-+  LIST *label;
-+
-+  if (!env || !env->labels || !Labels)
-+    return;
-+
-+  for (label = env->labels; label; label = label->next)
-+  {
-+    if (label->data == NULL)
-+      continue;
-+    count = (uintptr_t)hash_find(Labels, label->data);
-+    if (count)
-+      hash_delete(Labels, label->data, NULL, NULL);
-+    count++;  /* was zero if not found */
-+    hash_insert(Labels, label->data, (void *)count, 0);
-+    dprint(1, (debugfile, "++label %s: %d\n", label->data, count));
-+  }
-+}
-+
-+/*
-+ * set labels on a message
-+ */
-+static int label_message(HEADER *hdr, char *new)
-+{
-+  if (hdr == NULL)
-+    return 0;
-+  if (hdr->env->labels == NULL && new == NULL)
-+    return 0;
-+  if (hdr->env->labels != NULL && new != NULL)
-+  {
-+    char old[HUGE_STRING];
-+    mutt_labels(old, sizeof(old), hdr->env, NULL);
-+    if (!strcmp(old, new))
-+      return 0;
-+  }
-+
-+  if (hdr->env->labels != NULL)
-+  {
-+    mutt_label_ref_dec(hdr->env);
-+    mutt_free_list(&hdr->env->labels);
-+  }
-+
-+  if (new == NULL)
-+    hdr->env->labels = NULL;
++  if (option (OPTNEWSSEND))
++    news++;
++#endif
+ 
+   mutt_attach_init (msg->content);
+   idx = mutt_gen_attach_list (msg->content, -1, idx, &idxlen, &idxmax, 0, 1);
+@@ -514,10 +588,18 @@ int mutt_compose_menu (HEADER *msg,   /* structure for new message */
+   menu->make_entry = snd_entry;
+   menu->tag = mutt_tag_attach;
+   menu->data = idx;
++#ifdef USE_NNTP
++  if (news)
++    menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_COMPOSE, ComposeNewsHelp);
 +  else
-+  {
-+    char *last, *label;
-+
-+    for (label = strtok_r(new, ",", &last); label;
-+         label = strtok_r(NULL, ",", &last)) 
-+    {
-+      SKIPWS(label);
-+      if (mutt_find_list(hdr->env->labels, label))
-+        continue;
-+      if (hdr->env->labels == NULL)
-+      {
-+        hdr->env->labels = mutt_new_list();
-+        hdr->env->labels->data = safe_strdup(label);
-+      }
-+      else
-+        mutt_add_list(hdr->env->labels, label);
-+    }
-+    mutt_label_ref_inc(hdr->env);
-+  }
-+  return hdr->changed = hdr->label_changed = 1;
-+}
-+
-+int mutt_label_message(HEADER *hdr)
-+{
-+  char buf[LONG_STRING], *new;
-+  int i;
-+  int changed;
-+
-+  *buf = '\0';
-+  if (hdr != NULL && hdr->env->labels != NULL)
-+    mutt_labels(buf, sizeof(buf)-2, hdr->env, NULL);
-+
-+  /* add a comma-space so that new typing is a new keyword */
-+  if (buf[0])
-+    strcat(buf, ", ");    /* __STRCAT_CHECKED__ */
-+
-+  if (mutt_get_field("Label: ", buf, sizeof(buf), M_LABEL /* | M_CLEAR */) != 0)
-+    return 0;
++#endif
+   menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_COMPOSE, ComposeHelp);
+-  
 +
-+  new = buf;
-+  SKIPWS(new);
-+  if (new && *new)
-+  {
-+    char *p;
-+    int len = strlen(new);
-+    p = &new[len]; /* '\0' */
-+    while (p > new)
-+    {
-+      if (!isspace((unsigned char)*(p-1)) && *(p-1) != ',')
-+        break;
-+      p--;
-+    }
-+    *p = '\0';
-+  }
-+  if (*new == '\0')
-+    new = NULL;
-+
-+  changed = 0;
-+  if (hdr != NULL) {
-+    changed += label_message(hdr, new);
-+  } else {
-+#define HDR_OF(index) Context->hdrs[Context->v2r[(index)]]
-+    for (i = 0; i < Context->vcount; ++i) {
-+      if (HDR_OF(i)->tagged)
-+        if (label_message(HDR_OF(i), new)) {
-+          ++changed;
-+          mutt_set_flag(Context, HDR_OF(i),
-+            M_TAG, 0);
-+        }
-+    }
-+  }
-+
-+  return changed;
-+}
-+
-+/* scan a context (mailbox) and hash all labels we find */
-+void mutt_scan_labels(CONTEXT *ctx)
-+{
-+  int i;
-+
-+  if (!ctx)
-+    return;
-+
-+  for (i = 0; i < ctx->msgcount; i++)
-+    if (ctx->hdrs[i]->env->labels)
-+      mutt_label_ref_inc(ctx->hdrs[i]->env);
-+}
-+
-+
-+char *mutt_labels(char *dst, int sz, ENVELOPE *env, char *sep)
-+{
-+  static char sbuf[HUGE_STRING];
-+  int off = 0;
-+  int len;
-+  LIST *label;
-+
-+  if (sep == NULL)
-+    sep = ", ";
-+
-+  if (dst == NULL)
-+  {
-+    dst = sbuf;
-+    sz = sizeof(sbuf);
-+  }
-+
-+  *dst = '\0';
-+
-+  for (label = env->labels; label; label = label->next)
-+  {
-+    if (label->data == NULL)
-+      continue;
-+    len = MIN(mutt_strlen(label->data), sz-off);
-+    strfcpy(&dst[off], label->data, len+1);
-+    off += len;
-+    if (label->next)
-+    {
-+      len = MIN(mutt_strlen(sep), sz-off);
-+      strfcpy(&dst[off], sep, len+1);
-+      off += len;
-+    }
-+  }
-+
-+  return dst;
-+}
-diff -urN mutt-1.6.1/hook.c mutt-1.6.1-neomutt/hook.c
---- mutt-1.6.1/hook.c	2016-06-12 18:43:00.405447637 +0100
-+++ mutt-1.6.1-neomutt/hook.c	2016-06-12 18:43:00.703452284 +0100
-@@ -24,6 +24,10 @@
- #include "mailbox.h"
- #include "mutt_crypt.h"
- 
-+#ifdef USE_COMPRESSED
-+#include "compress.h"
+   while (loop)
+   {
++#ifdef USE_NNTP
++    unset_option (OPTNEWS);	/* for any case */
 +#endif
-+
- #include <limits.h>
- #include <string.h>
- #include <stdlib.h>
-@@ -109,6 +113,14 @@
-     memset (&pattern, 0, sizeof (pattern));
-     pattern.data = safe_strdup (path);
-   }
-+#ifdef USE_COMPRESSED
-+  else if (data & (M_APPENDHOOK | M_OPENHOOK | M_CLOSEHOOK)) {
-+    if (comp_valid_command (command.data) == 0) {
-+      strfcpy (err->data, _("badly formatted command string"), err->dsize);
-+      return -1;
-+    }
-+  }
+     switch (op = mutt_menuLoop (menu))
+     {
+       case OP_REDRAW:
+@@ -530,6 +612,10 @@ int mutt_compose_menu (HEADER *msg,   /* structure for new message */
+         mutt_message_hook (NULL, msg, M_SEND2HOOK);
+ 	break;
+       case OP_COMPOSE_EDIT_TO:
++#ifdef USE_NNTP
++	if (news)
++	  break;
 +#endif
-   else if (DefaultHook && !(data & (M_CHARSETHOOK | M_ICONVHOOK | M_ACCOUNTHOOK))
-            && (!WithCrypto || !(data & M_CRYPTHOOK))
-       )
-@@ -362,7 +374,7 @@
- 
-     if (hook->type & type)
-       if ((mutt_pattern_exec (hook->pattern, 0, ctx, hdr) > 0) ^ hook->rx.not)
--	if (mutt_parse_rc_line (hook->command, &token, &err) != 0)
-+	if (mutt_parse_rc_line (hook->command, &token, &err) == -1)
+ 	menu->redraw = edit_address_list (HDR_TO, &msg->env->to);
+ 	if (option (OPTCRYPTOPPORTUNISTICENCRYPT))
  	{
- 	  FREE (&token.data);
- 	  mutt_error ("%s", err.data);
-diff -urN mutt-1.6.1/imap/command.c mutt-1.6.1-neomutt/imap/command.c
---- mutt-1.6.1/imap/command.c	2016-06-12 18:43:00.405447637 +0100
-+++ mutt-1.6.1-neomutt/imap/command.c	2016-06-12 18:43:00.705452315 +0100
-@@ -1016,6 +1016,14 @@
- 	     opened */
- 	  status->uidnext = oldun;
- 
-+#ifdef USE_SIDEBAR
-+	/* Make the sidebar show the correct numbers */
-+	if (status->messages) {
-+	  inc->msg_count  = status->messages;
-+	  inc->msg_unread = status->unseen;
-+	}
+@@ -539,6 +625,10 @@ int mutt_compose_menu (HEADER *msg,   /* structure for new message */
+         mutt_message_hook (NULL, msg, M_SEND2HOOK);
+         break;
+       case OP_COMPOSE_EDIT_BCC:
++#ifdef USE_NNTP
++	if (news)
++	  break;
 +#endif
-+
-         FREE (&value);
-         return;
-       }
-diff -urN mutt-1.6.1/imap/imap.c mutt-1.6.1-neomutt/imap/imap.c
---- mutt-1.6.1/imap/imap.c	2016-06-12 18:43:00.405447637 +0100
-+++ mutt-1.6.1-neomutt/imap/imap.c	2016-06-12 18:43:00.705452315 +0100
-@@ -888,6 +888,12 @@
-           if (hdrs[n]->deleted != HEADER_DATA(hdrs[n])->deleted)
-             match = invert ^ hdrs[n]->deleted;
- 	  break;
-+        case M_EXPIRED: /* imap_fast_trash version of M_DELETED */
-+	  if (hdrs[n]->purged)
-+	    break;
-+          if (hdrs[n]->deleted != HEADER_DATA(hdrs[n])->deleted)
-+            match = invert ^ (hdrs[n]->deleted && !hdrs[n]->appended);
+ 	menu->redraw = edit_address_list (HDR_BCC, &msg->env->bcc);
+ 	if (option (OPTCRYPTOPPORTUNISTICENCRYPT))
+ 	{
+@@ -548,6 +638,10 @@ int mutt_compose_menu (HEADER *msg,   /* structure for new message */
+         mutt_message_hook (NULL, msg, M_SEND2HOOK);
+ 	break;
+       case OP_COMPOSE_EDIT_CC:
++#ifdef USE_NNTP
++	if (news)
 +	  break;
-         case M_FLAG:
-           if (hdrs[n]->flagged != HEADER_DATA(hdrs[n])->flagged)
-             match = invert ^ hdrs[n]->flagged;
-@@ -1222,7 +1228,7 @@
-        * we delete the message and reupload it.
-        * This works better if we're expunging, of course. */
-       if ((h->env && (h->env->refs_changed || h->env->irt_changed)) ||
--	  h->attach_del)
-+	  h->attach_del || h->label_changed)
-       {
-         mutt_message (_("Saving changed messages... [%d/%d]"), n+1,
-                       ctx->msgcount);
-@@ -1232,6 +1238,7 @@
- 	  dprint (1, (debugfile, "imap_sync_mailbox: Error opening mailbox in append mode\n"));
- 	else
- 	  _mutt_save_message (h, appendctx, 1, 0, 0);
-+	h->label_changed = 0;
-       }
-     }
-   }
-@@ -1535,7 +1542,11 @@
- 
-     imap_munge_mbox_name (idata, munged, sizeof (munged), name);
-     snprintf (command, sizeof (command),
-+#ifdef USE_SIDEBAR
-+	      "STATUS %s (UIDNEXT UIDVALIDITY UNSEEN RECENT MESSAGES)", munged);
-+#else
- 	      "STATUS %s (UIDNEXT UIDVALIDITY UNSEEN RECENT)", munged);
 +#endif
- 
-     if (imap_exec (idata, command, IMAP_CMD_QUEUE) < 0)
-     {
-@@ -2038,3 +2049,53 @@
- 
-   return -1;
- }
-+
-+/**
-+ * imap_fast_trash - XXX
-+ */
-+int
-+imap_fast_trash (void)
-+{
-+	if ((Context->magic == M_IMAP) && mx_is_imap (TrashPath)) {
-+		IMAP_MBOX mx;
-+		IMAP_DATA *idata = (IMAP_DATA *) Context->data;
-+		char mbox[LONG_STRING];
-+		char mmbox[LONG_STRING];
-+		int rc;
-+		dprint (1, (debugfile, "[itf] trashcan seems to be on imap.\n"));
-+
-+		if (imap_parse_path (TrashPath, &mx) == 0) {
-+			if (mutt_account_match (&(idata->conn->account), &(mx.account))) {
-+				dprint (1, (debugfile, "[itf] trashcan seems to be on the same account.\n"));
-+
-+				imap_fix_path (idata, mx.mbox, mbox, sizeof (mbox));
-+				if (!*mbox)
-+					strfcpy (mbox, "INBOX", sizeof (mbox));
-+				imap_munge_mbox_name (idata, mmbox, sizeof (mmbox), mbox);
-+
-+				rc = imap_exec_msgset (idata, "UID COPY", mmbox, M_EXPIRED, 0, 0);
-+				if (rc == 0) {
-+					dprint (1, (debugfile, "imap_copy_messages: No messages del-tagged\n"));
-+					rc = -1;
-+					goto old_way;
-+				} else if (rc < 0) {
-+					dprint (1, (debugfile, "could not queue copy\n"));
-+					goto old_way;
-+				} else {
-+					mutt_message (_("Copying %d messages to %s..."), rc, mbox);
-+					return 0;
-+				}
-+			} else {
-+				dprint (1, (debugfile, "[itf] trashcan seems to be on a different account.\n"));
-+			}
-+old_way:
-+			FREE(&mx.mbox); /* we probably only need to free this when the parse works */
-+		} else {
-+			dprint (1, (debugfile, "[itf] failed to parse TrashPath.\n"));
-+		}
-+
-+		dprint (1, (debugfile, "[itf] giving up and trying old fasioned way.\n"));
+ 	menu->redraw = edit_address_list (HDR_CC, &msg->env->cc);
+ 	if (option (OPTCRYPTOPPORTUNISTICENCRYPT))
+ 	{
+@@ -556,6 +650,62 @@ int mutt_compose_menu (HEADER *msg,   /* structure for new message */
+ 	}
+         mutt_message_hook (NULL, msg, M_SEND2HOOK);	
+         break;
++#ifdef USE_NNTP
++      case OP_COMPOSE_EDIT_NEWSGROUPS:
++	if (news)
++	{
++	  if (msg->env->newsgroups)
++	    strfcpy (buf, msg->env->newsgroups, sizeof (buf));
++	  else
++	    buf[0] = 0;
++	  if (mutt_get_field ("Newsgroups: ", buf, sizeof (buf), 0) == 0)
++	  {
++	    mutt_str_replace (&msg->env->newsgroups, buf);
++	    move (HDR_TO, HDR_XOFFSET);
++	    if (msg->env->newsgroups)
++	      mutt_paddstr (W, msg->env->newsgroups);
++	    else
++	      clrtoeol ();
++	  }
 +	}
-+
-+	return 1;
-+}
-diff -urN mutt-1.6.1/imap/imap.h mutt-1.6.1-neomutt/imap/imap.h
---- mutt-1.6.1/imap/imap.h	2016-06-12 18:43:00.405447637 +0100
-+++ mutt-1.6.1-neomutt/imap/imap.h	2016-06-12 18:43:00.705452315 +0100
-@@ -72,4 +72,7 @@
++	break;
++      case OP_COMPOSE_EDIT_FOLLOWUP_TO:
++	if (news)
++	{
++	  if (msg->env->followup_to)
++	    strfcpy (buf, msg->env->followup_to, sizeof (buf));
++	  else
++	    buf[0] = 0;
++	  if (mutt_get_field ("Followup-To: ", buf, sizeof (buf), 0) == 0)
++	  {
++	    mutt_str_replace (&msg->env->followup_to, buf);
++	    move (HDR_CC, HDR_XOFFSET);
++	    if (msg->env->followup_to)
++	      mutt_paddstr (W, msg->env->followup_to);
++	    else
++	      clrtoeol ();
++	  }
++	}
++	break;
++      case OP_COMPOSE_EDIT_X_COMMENT_TO:
++	if (news && option (OPTXCOMMENTTO))
++	{
++	  if (msg->env->x_comment_to)
++	    strfcpy (buf, msg->env->x_comment_to, sizeof (buf));
++	  else
++	    buf[0] = 0;
++	  if (mutt_get_field ("X-Comment-To: ", buf, sizeof (buf), 0) == 0)
++	  {
++	    mutt_str_replace (&msg->env->x_comment_to, buf);
++	    move (HDR_BCC, HDR_XOFFSET);
++	    if (msg->env->x_comment_to)
++	      mutt_paddstr (W, msg->env->x_comment_to);
++	    else
++	      clrtoeol ();
++	  }
++	}
++	break;
++#endif
+       case OP_COMPOSE_EDIT_SUBJECT:
+ 	if (msg->env->subject)
+ 	  strfcpy (buf, msg->env->subject, sizeof (buf));
+@@ -564,7 +714,7 @@ int mutt_compose_menu (HEADER *msg,   /* structure for new message */
+ 	if (mutt_get_field ("Subject: ", buf, sizeof (buf), 0) == 0)
+ 	{
+ 	  mutt_str_replace (&msg->env->subject, buf);
+-	  move (HDR_SUBJECT, HDR_XOFFSET);
++	  move (HDR_SUBJECT, HDR_XOFFSET + SidebarWidth);
+ 	  if (msg->env->subject)
+ 	    mutt_paddstr (W, msg->env->subject);
+ 	  else
+@@ -582,7 +732,7 @@ int mutt_compose_menu (HEADER *msg,   /* structure for new message */
+ 	{
+ 	  strfcpy (fcc, buf, fcclen);
+ 	  mutt_pretty_mailbox (fcc, fcclen);
+-	  move (HDR_FCC, HDR_XOFFSET);
++	  move (HDR_FCC, HDR_XOFFSET + SidebarWidth);
+ 	  mutt_paddstr (W, fcc);
+ 	  fccSet = 1;
+ 	}
+@@ -686,7 +836,8 @@ int mutt_compose_menu (HEADER *msg,   /* structure for new message */
+ 	  numfiles = 0;
+ 	  files = NULL;
  
- int imap_account_match (const ACCOUNT* a1, const ACCOUNT* a2);
+-	  if (_mutt_enter_fname (prompt, fname, sizeof (fname), &menu->redraw, 0, 1, &files, &numfiles) == -1 ||
++	  if (_mutt_enter_fname (prompt, fname, sizeof (fname),
++			&menu->redraw, 0, 1, &files, &numfiles, 0) == -1 ||
+ 	      *fname == '\0')
+ 	    break;
  
-+/* trash */
-+int imap_fast_trash (void);
-+
- #endif
-diff -urN mutt-1.6.1/imap/message.c mutt-1.6.1-neomutt/imap/message.c
---- mutt-1.6.1/imap/message.c	2016-06-12 18:43:00.406447652 +0100
-+++ mutt-1.6.1-neomutt/imap/message.c	2016-06-12 18:43:00.705452315 +0100
-@@ -69,7 +69,7 @@
-   int rc, mfhrc, oldmsgcount;
-   int fetchlast = 0;
-   int maxuid = 0;
--  static const char * const want_headers = "DATE FROM SUBJECT TO CC MESSAGE-ID REFERENCES CONTENT-TYPE CONTENT-DESCRIPTION IN-REPLY-TO REPLY-TO LINES LIST-POST X-LABEL";
-+  static const char * const want_headers = "DATE FROM SUBJECT TO CC MESSAGE-ID REFERENCES CONTENT-TYPE CONTENT-DESCRIPTION IN-REPLY-TO REPLY-TO LINES LIST-POST X-LABEL X-KEYWORDS X-MOZILLA-KEYS KEYWORDS";
-   progress_t progress;
-   int retval = -1;
+@@ -724,6 +875,9 @@ int mutt_compose_menu (HEADER *msg,   /* structure for new message */
+         break;
  
-@@ -406,6 +406,7 @@
-   IMAP_CACHE *cache;
-   int read;
-   int rc;
+       case OP_COMPOSE_ATTACH_MESSAGE:
++#ifdef USE_NNTP
++      case OP_COMPOSE_ATTACH_NEWS_MESSAGE:
++#endif
+ 	{
+ 	  char *prompt;
+ 	  HEADER *h;
+@@ -731,7 +885,22 @@ int mutt_compose_menu (HEADER *msg,   /* structure for new message */
+ 	  fname[0] = 0;
+ 	  prompt = _("Open mailbox to attach message from");
+ 
++#ifdef USE_NNTP
++	  unset_option (OPTNEWS);
++	  if (op == OP_COMPOSE_ATTACH_NEWS_MESSAGE)
++	  {
++	    if (!(CurrentNewsSrv = nntp_select_server (NewsServer, 0)))
++	      break;
 +
-   /* Sam's weird courier server returns an OK response even when FETCH
-    * fails. Thanks Sam. */
-   short fetched = 0;
-@@ -886,6 +887,7 @@
-         if (ctx->hdrs[n]->tagged)
-         {
-           mutt_set_flag (ctx, ctx->hdrs[n], M_DELETE, 1);
-+          mutt_set_flag (ctx, ctx->hdrs[n], M_APPENDED, 1);
-           if (option (OPTDELETEUNTAG))
-             mutt_set_flag (ctx, ctx->hdrs[n], M_TAG, 0);
-         }
-@@ -893,6 +895,7 @@
-     else
-     {
-       mutt_set_flag (ctx, h, M_DELETE, 1);
-+      mutt_set_flag (ctx, h, M_APPENDED, 1);
-       if (option (OPTDELETEUNTAG))
-         mutt_set_flag (ctx, h, M_TAG, 0);
-     }
-diff -urN mutt-1.6.1/init.c mutt-1.6.1-neomutt/init.c
---- mutt-1.6.1/init.c	2016-06-12 18:43:00.406447652 +0100
-+++ mutt-1.6.1-neomutt/init.c	2016-06-12 18:43:00.707452347 +0100
-@@ -32,12 +32,15 @@
- #include "mutt_crypt.h"
- #include "mutt_idna.h"
- #include "group.h"
-+#include "version.h"
++	    prompt = _("Open newsgroup to attach message from");
++	    set_option (OPTNEWS);
++	  }
++#endif
++
+ 	  if (Context)
++#ifdef USE_NNTP
++	  if ((op == OP_COMPOSE_ATTACH_MESSAGE) ^ (Context->magic == M_NNTP))
++#endif
+ 	  {
+ 	    strfcpy (fname, NONULL (Context->path), sizeof (fname));
+ 	    mutt_pretty_mailbox (fname, sizeof (fname));
+@@ -740,6 +909,11 @@ int mutt_compose_menu (HEADER *msg,   /* structure for new message */
+ 	  if (mutt_enter_fname (prompt, fname, sizeof (fname), &menu->redraw, 1) == -1 || !fname[0])
+ 	    break;
  
- #if defined(USE_SSL)
- #include "mutt_ssl.h"
++#ifdef USE_NNTP
++	  if (option (OPTNEWS))
++	    nntp_expand_path (fname, sizeof (fname), &CurrentNewsSrv->conn->account);
++	  else
++#endif
+ 	  mutt_expand_path (fname, sizeof (fname));
+ #ifdef USE_IMAP
+           if (!mx_is_imap (fname))
+@@ -747,6 +921,9 @@ int mutt_compose_menu (HEADER *msg,   /* structure for new message */
+ #ifdef USE_POP
+           if (!mx_is_pop (fname))
  #endif
- 
--
-+#if USE_NOTMUCH
-+#include "mutt_notmuch.h"
++#ifdef USE_NNTP
++	  if (!mx_is_nntp (fname) && !option (OPTNEWS))
 +#endif
+ 	  /* check to make sure the file exists and is readable */
+ 	  if (access (fname, R_OK) == -1)
+ 	  {
+@@ -1231,7 +1408,7 @@ int mutt_compose_menu (HEADER *msg,   /* structure for new message */
+          if (msg->content->next)
+            msg->content = mutt_make_multipart (msg->content);
  
- #include "mx.h"
- #include "init.h"
-@@ -76,6 +79,12 @@
- static const char* myvar_get (const char* var);
- static void myvar_del (const char* var);
- 
-+#if USE_NOTMUCH
-+/* List of tags found in last call to mutt_nm_query_complete(). */
-+static char **nm_tags;
+-         if (mutt_write_fcc (fname, msg, NULL, 0, NULL) < 0)
++         if (mutt_write_fcc (fname, msg, NULL, 0, NULL, NULL) < 0)
+            msg->content = mutt_remove_multipart (msg->content);
+          else
+            mutt_message _("Message written.");
+@@ -1313,7 +1490,7 @@ int mutt_compose_menu (HEADER *msg,   /* structure for new message */
+     /* Draw formatted compose status line */
+     if (menu->redraw & REDRAW_STATUS) 
+     {
+-	compose_status_line (buf, sizeof (buf), 0, menu, NONULL(ComposeFormat));
++	compose_status_line (buf, sizeof (buf), 0, COLS - SidebarWidth, menu, NONULL(ComposeFormat));
+ 	move(option (OPTSTATUSONTOP) ? 0 : LINES-2, 0);
+ 	SETCOLOR (MT_COLOR_STATUS);
+ 	mutt_paddstr (COLS, buf);
+diff --git a/compress.c b/compress.c
+new file mode 100644
+index 0000000..3eb02a7
+--- /dev/null
++++ b/compress.c
+@@ -0,0 +1,826 @@
++/* Copyright (C) 1997 Alain Penders <Alain at Finale-Dev.com>
++ * Copyright (C) 2016 Richard Russon <rich at flatcap.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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ */
++
++#if HAVE_CONFIG_H
++#include "config.h"
 +#endif
 +
++#include <errno.h>
++#include <string.h>
++#include <sys/stat.h>
++#include <unistd.h>
++
++#include "mutt.h"
++#include "mailbox.h"
++#include "mutt_curses.h"
++#include "mx.h"
++
++/* Notes:
++ * Any references to compressed files also apply to encrypted files.
++ * ctx->path     == plaintext file
++ * ctx->realpath == compressed file
++ */
 +
- static void toggle_quadoption (int opt)
- {
-   int n = opt/4;
-@@ -601,6 +610,113 @@
-   }
- }
- 
 +/**
-+ * finish_source - 'finish' command: stop processing current config file
-+ * @tmp:  Temporary space shared by all command handlers
-+ * @s:    Current line of the config file
-+ * @data: data field from init.h:struct command_t
-+ * @err:  Buffer for any error message
-+ *
-+ * If the 'finish' command is found, we should stop reading the current file.
++ * struct COMPRESS_INFO - Private data for compress
 + *
-+ * Returns:
-+ *	 1 Stop processing the current file
-+ *	-1 Failed
++ * This object gets attached to the mailbox's CONTEXT.
 + */
-+static int finish_source (BUFFER *tmp, BUFFER *s, unsigned long data, BUFFER *err)
++typedef struct
 +{
-+	if (MoreArgs (s)) {
-+		snprintf (err->data, err->dsize, _("finish: too many arguments"));
-+		return -1;
-+	}
++	const char *append;   /* append-hook command */
++	const char *close;    /* close-hook  command */
++	const char *open;     /* open-hook   command */
++	off_t size;           /* size of the compressed file */
++} COMPRESS_INFO;
 +
-+	return 1;
-+}
++char echo_cmd[HUGE_STRING];
 +
 +/**
-+ * parse_ifdef - 'ifdef' command: conditional config
-+ * @tmp:  Temporary space shared by all command handlers
-+ * @s:    Current line of the config file
-+ * @data: data field from init.h:struct command_t
-+ * @err:  Buffer for any error message
++ * lock_mailbox - Try to lock a mailbox (exclusively)
++ * @ctx:  Mailbox to lock
++ * @fp:   File pointer to the mailbox file
++ * @excl: Lock exclusively?
 + *
-+ * The 'ifdef' command allows conditional elements in the config file.
-+ * If a given variable, function, command or compile-time symbol exists, then
-+ * read the rest of the line of config commands.
-+ * e.g.
-+ *	ifdef USE_SIDEBAR source ~/.mutt/sidebar.rc
-+ *
-+ * If (data == 1) then it means use the 'ifndef' (if-not-defined) command.
-+ * e.g.
-+ *	ifndef USE_IMAP finish
++ * Try to (exclusively) lock the mailbox.  If we succeed, then we mark the
++ * mailbox as locked.  If we fail, but we didn't want exclusive rights, then
++ * the mailbox will be marked readonly.
 + *
 + * Returns:
-+ *	 0 Success
-+ *	-1 Failed
++ *	 0: Success (locked or readonly)
++ *	-1: Error (can't lock the file)
 + */
-+static int parse_ifdef (BUFFER *tmp, BUFFER *s, unsigned long data, BUFFER *err)
++static int
++lock_mailbox (CONTEXT *ctx, FILE *fp, int excl)
 +{
-+	int i, j, res = 0;
-+	BUFFER token;
-+
-+	memset (&token, 0, sizeof (token));
-+	mutt_extract_token (tmp, s, 0);
++	if (!ctx || !fp)
++		return -1;
 +
-+	/* is the item defined as a variable? */
-+	res = (mutt_option_index (tmp->data) != -1);
++	int r = mx_lock_file (ctx->realpath, fileno (fp), excl, 1, 1);
 +
-+	/* is the item a compiled-in feature? */
-+	if (!res) {
-+		res = feature_enabled (tmp->data);
++	if (r == 0) {
++		ctx->locked = 1;
++	} else if (excl == 0) {
++		ctx->readonly = 1;
++		return 0;
 +	}
 +
-+	/* or a function? */
-+	if (!res) {
-+		for (i = 0; !res && (i < MENU_MAX); i++) {
-+			const struct binding_t *b = km_get_table (Menus[i].value);
-+			if (!b)
-+				continue;
++	return r;
++}
 +
-+			for (j = 0; b[j].name; j++) {
-+				if (mutt_strcmp (tmp->data, b[j].name) == 0) {
-+					res = 1;
-+					break;
-+				}
-+			}
-+		}
-+	}
++/**
++ * restore_path - Put back the original mailbox name
++ * @ctx: Mailbox to modify
++ *
++ * When we use a compressed mailbox, we change the CONTEXT to refer to the
++ * uncompressed file.  We store the original name in ctx->realpath.
++ *	ctx->path     = "/tmp/mailbox"
++ *	ctx->realpath = "mailbox.gz"
++ *
++ * When we have finished with a compressed mailbox, we put back the original
++ * name.
++ *	ctx->path     = "mailbox.gz"
++ *	ctx->realpath = NULL
++ */
++static void
++restore_path (CONTEXT *ctx)
++{
++	if (!ctx)
++		return;
 +
-+	/* or a command? */
-+	if (!res) {
-+		for (i = 0; Commands[i].name; i++) {
-+			if (mutt_strcmp (tmp->data, Commands[i].name) == 0) {
-+				res = 1;
-+				break;
-+			}
-+		}
-+	}
++	FREE(&ctx->path);
++	ctx->path = ctx->realpath;
++}
 +
-+	if (!MoreArgs (s)) {
-+		snprintf (err->data, err->dsize, _("%s: too few arguments"),
-+			(data ? "ifndef" : "ifdef"));
-+		return -1;
-+	}
-+	mutt_extract_token (tmp, s, M_TOKEN_SPACE);
++/**
++ * remove_file - Delete the plaintext file
++ * @ctx: Mailbox
++ *
++ * Delete the uncompressed file of a mailbox.
++ * This only works for mbox or mmdf mailbox files.
++ */
++static void
++remove_file (const CONTEXT *ctx)
++{
++	if (!ctx)
++		return;
 +
-+        /* ifdef KNOWN_SYMBOL or ifndef UNKNOWN_SYMBOL */
-+	if ((res && (data == 0)) || (!res && (data == 1))) {
-+                int rc = mutt_parse_rc_line (tmp->data, &token, err);
-+		if (rc == -1) {
-+			mutt_error ("Error: %s", err->data);
-+			FREE(&token.data);
-+			return -1;
-+		}
-+		FREE(&token.data);
-+                return rc;
++	if ((ctx->magic == M_MBOX) || (ctx->magic == M_MMDF)) {
++		remove (ctx->path);
 +	}
-+	return 0;
 +}
 +
- static int parse_unignore (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
- {
-   do
-@@ -2173,6 +2289,9 @@
- 	case DT_SORT_AUX:
- 	  map = SortAuxMethods;
- 	  break;
-+	case DT_SORT_SIDEBAR:
-+	  map = SortSidebarMethods;
-+	  break;
- 	default:
- 	  map = SortMethods;
- 	  break;
-@@ -2238,7 +2357,7 @@
- static int source_rc (const char *rcfile, BUFFER *err)
- {
-   FILE *f;
--  int line = 0, rc = 0, conv = 0;
-+  int line = 0, rc = 0, conv = 0, line_rc;
-   BUFFER token;
-   char *linebuf = NULL;
-   char *currentline = NULL;
-@@ -2267,17 +2386,17 @@
-     else 
-       currentline=linebuf;
- 
--    if (mutt_parse_rc_line (currentline, &token, err) == -1)
--    {
-+    line_rc = mutt_parse_rc_line (currentline, &token, err);
-+    if (line_rc == -1) {
-       mutt_error (_("Error in %s, line %d: %s"), rcfile, line, err->data);
-       if (--rc < -MAXERRS) 
-       {
-         if (conv) FREE(&currentline);
-         break;
-       }
--    }
--    else
--    {
-+    } else if (line_rc == 1) {
-+      break;	/* Found "finish" command */
-+    } else {
-       if (rc < 0)
-         rc = -1;
-     }
-@@ -2332,7 +2451,7 @@
-    err		where to write error messages */
- int mutt_parse_rc_line (/* const */ char *line, BUFFER *token, BUFFER *err)
- {
--  int i, r = -1;
-+  int i, r = 0;
-   BUFFER expn;
- 
-   if (!line || !*line)
-@@ -2359,22 +2478,24 @@
-     {
-       if (!mutt_strcmp (token->data, Commands[i].name))
-       {
--	if (Commands[i].func (token, &expn, Commands[i].data, err) != 0)
--	  goto finish;
--        break;
-+        r = Commands[i].func (token, &expn, Commands[i].data, err);
-+        if (r != 0) {   /* -1 Error, +1 Finish */
-+          goto finish;  /* Propagate return code */
-+        }
-+        break;          /* Continue with next command */
-       }
-     }
-     if (!Commands[i].name)
-     {
-       snprintf (err->data, err->dsize, _("%s: unknown command"), NONULL (token->data));
--      goto finish;
-+      r = -1;
-+      break;            /* Ignore the rest of the line */
-     }
-   }
--  r = 0;
- finish:
-   if (expn.destroy)
-     FREE (&expn.data);
--  return (r);
-+  return r;
- }
- 
- 
-@@ -2633,6 +2754,182 @@
-   return 0;
- }
- 
-+#if USE_NOTMUCH
-+
-+/* Fetch a list of all notmuch tags and insert them into the completion
-+ * machinery.
++/**
++ * unlock_mailbox - Unlock a mailbox
++ * @ctx: Mailbox to unlock
++ * @fp:  File pointer to mailbox file
++ *
++ * Unlock a mailbox previously locked by lock_mailbox().
 + */
-+static int complete_all_nm_tags (const char *pt)
++static void
++unlock_mailbox (CONTEXT *ctx, FILE *fp)
 +{
-+  int num;
-+  int tag_count_1 = 0;
-+  int tag_count_2 = 0;
-+
-+  Num_matched = 0;
-+  strfcpy (User_typed, pt, sizeof (User_typed));
-+  memset (Matches, 0, Matches_listsize);
-+  memset (Completed, 0, sizeof (Completed));
++	if (!ctx || !fp)
++		return;
 +
-+  nm_longrun_init(Context, FALSE);
++	if (ctx->locked) {
++		fflush (fp);
 +
-+  /* Work out how many tags there are. */
-+  if (nm_get_all_tags(Context, NULL, &tag_count_1) || tag_count_1 == 0)
-+    goto done;
++		mx_unlock_file (ctx->realpath, fileno (fp), 1);
++		ctx->locked = 0;
++	}
++}
 +
-+  /* Free the old list, if any. */
-+  if (nm_tags != NULL) {
-+    int i;
-+    for (i = 0; nm_tags[i] != NULL; i++)
-+      FREE (&nm_tags[i]);
-+    FREE (&nm_tags);
-+  }
-+  /* Allocate a new list, with sentinel. */
-+  nm_tags = safe_malloc((tag_count_1 + 1) * sizeof (char *));
-+  nm_tags[tag_count_1] = NULL;
++/**
++ * file_exists - Does the file exist?
++ * @path: Pathname to check
++ *
++ * Returns:
++ *	1: File exists
++ *	0: Non-existant file
++ */
++static int
++file_exists (const char *path)
++{
++	if (!path)
++		return 0;
 +
-+  /* Get all the tags. */
-+  if (nm_get_all_tags(Context, nm_tags, &tag_count_2) ||
-+      tag_count_1 != tag_count_2) {
-+    FREE (&nm_tags);
-+    nm_tags = NULL;
-+    nm_longrun_done(Context);
-+    return -1;
-+  }
++	return (access (path, W_OK) != 0 && errno == ENOENT) ? 1 : 0;
++}
 +
-+  /* Put them into the completion machinery. */
-+  for (num = 0; num < tag_count_1; num++) {
-+    candidate (Completed, User_typed, nm_tags[num], sizeof (Completed));
-+  }
-+
-+  matches_ensure_morespace (Num_matched);
-+  Matches[Num_matched++] = User_typed;
++/**
++ * find_hook - Find a hook to match a path
++ * @type: Type of hook, e.g. M_CLOSEHOOK
++ * @path: Filename to test
++ *
++ * Each hook has a type and a pattern.  Find a command that matches the type
++ * and path supplied. e.g.
++ *
++ * User config:
++ *	open-hook '\.gz$' "gzip -cd '%f' > '%t'"
++ *
++ * Call:
++ *	find_hook (M_OPENHOOK, "myfile.gz");
++ *
++ * Returns:
++ *	string: Matching hook command
++ *	NULL:   No matches
++ */
++static const char *
++find_hook (int type, const char *path)
++{
++	if (!path)
++		return NULL;
 +
-+done:
-+  nm_longrun_done(Context);
-+  return 0;
++	const char *c = mutt_find_hook (type, path);
++	return (!c || !*c) ? NULL : c;
 +}
 +
-+/* Return the last instance of needle in the haystack, or NULL.
-+ * Like strstr(), only backwards, and for a limited haystack length.
++/**
++ * get_append_command - Get the command for appending to a file
++ * @ctx:  Mailbox to append to
++ * @path: Compressed file
++ *
++ * If the file exists, we can use the 'append-hook' command.
++ * Otherwise, use the 'close-hook' command.
++ *
++ * Returns:
++ *	string: Append command or Close command
++ *	NULL:   On error
 + */
-+static const char* rstrnstr(const char* haystack,
-+                            size_t haystack_length,
-+                            const char* needle)
++static const char *
++get_append_command (const CONTEXT *ctx, const char *path)
 +{
-+  int needle_length = strlen(needle);
-+  const char* haystack_end = haystack + haystack_length - needle_length;
-+  const char* p;
++	if (!path || !ctx)
++		return NULL;
 +
-+  for (p = haystack_end; p >= haystack; --p)
-+  {
-+    size_t i;
-+    for (i = 0; i < needle_length; ++i) {
-+      if (p[i] != needle[i])
-+        goto next;
-+    }
-+    return p;
++	COMPRESS_INFO *ci = (COMPRESS_INFO *) ctx->compress_info;
 +
-+    next:;
-+  }
-+  return NULL;
++	return (file_exists (path)) ? ci->append : ci->close;
 +}
 +
-+/* Complete the nearest "tag:"-prefixed string previous to pos. */
-+int mutt_nm_query_complete (char *buffer, size_t len, int pos, int numtabs)
++/**
++ * set_compress_info - Find the compress hooks for a mailbox
++ * @ctx: Mailbox to examine
++ *
++ * When a mailbox is opened, we check if there are any matching hooks.
++ *
++ * Note: Caller must free the COMPRESS_INFO when done.
++ *
++ * Returns:
++ *	COMPRESS_INFO: Hook info for the mailbox's path
++ *	NULL:          On error
++ */
++static COMPRESS_INFO *
++set_compress_info (CONTEXT *ctx)
 +{
-+  char *pt = buffer;
-+  int spaces;
-+
-+  SKIPWS (buffer);
-+  spaces = buffer - pt;
++	if (!ctx)
++		return NULL;
 +
-+  pt = (char *)rstrnstr((char *)buffer, pos, "tag:");
-+  if (pt != NULL) {
-+    pt += 4;
-+    if (numtabs == 1) {
-+      /* First TAB. Collect all the matches */
-+      complete_all_nm_tags(pt);
++	COMPRESS_INFO *ci;
 +
-+      /* All matches are stored. Longest non-ambiguous string is ""
-+       * i.e. don't change 'buffer'. Fake successful return this time.
-+       */
-+      if (User_typed[0] == 0)
-+	return 1;
-+    }
++	/* Now lets uncompress this thing */
++	ci = safe_malloc (sizeof (COMPRESS_INFO));
++	ctx->compress_info = (void*) ci;
++	ci->append = find_hook (M_APPENDHOOK, ctx->path);
++	ci->open   = find_hook (M_OPENHOOK, ctx->path);
++	ci->close  = find_hook (M_CLOSEHOOK, ctx->path);
++	return ci;
++}
 +
-+    if (Completed[0] == 0 && User_typed[0])
-+      return 0;
++/**
++ * setup_paths - Set the mailbox paths
++ * @ctx: Mailbox to modify
++ *
++ * Save the compressed filename in ctx->realpath.
++ * Create a temporary file and put its name in ctx->path.
++ *
++ * Note: ctx->path will be freed by restore_path()
++ */
++static void
++setup_paths (CONTEXT *ctx)
++{
++	if (!ctx)
++		return;
 +
-+    /* Num_matched will _always_ be atleast 1 since the initial
-+     * user-typed string is always stored */
-+    if (numtabs == 1 && Num_matched == 2)
-+      snprintf(Completed, sizeof(Completed),"%s", Matches[0]);
-+    else if (numtabs > 1 && Num_matched > 2)
-+      /* cycle thru all the matches */
-+      snprintf(Completed, sizeof(Completed), "%s",
-+	       Matches[(numtabs - 2) % Num_matched]);
++	char tmppath[_POSIX_PATH_MAX];
 +
-+    /* return the completed query */
-+    strncpy (pt, Completed, buffer + len - pt - spaces);
-+  }
-+  else
-+    return 0;
++	/* Setup the right paths */
++	ctx->realpath = ctx->path;
 +
-+  return 1;
++	/* Uncompress to /tmp */
++	mutt_mktemp (tmppath, sizeof(tmppath));
++	ctx->path = safe_strdup (tmppath);
 +}
 +
-+/* Complete the nearest "+" or "-" -prefixed string previous to pos. */
-+int mutt_nm_tag_complete (char *buffer, size_t len, int pos, int numtabs)
++/**
++ * get_size - Get the size of a file
++ * @path: File to measure
++ *
++ * Returns:
++ *	number: Size in bytes
++ *	0: XXX -1 on error?
++ */
++static int
++get_size (const char *path)
 +{
-+  char *pt = buffer;
-+  int spaces;
-+  const char *first_plus = NULL;
-+  const char *first_minus = NULL;
-+
-+  SKIPWS (buffer);
-+  spaces = buffer - pt;
-+
-+  first_plus = rstrnstr((char *)buffer, pos, "+");
-+  first_minus = rstrnstr((char *)buffer, pos, "-");
-+  pt = (char *)MAX(first_plus, first_minus);
++	if (!path)
++		return 0;
 +
-+  if (pt != NULL) {
-+    pt++;
++	struct stat sb;
++	if (stat (path, &sb) != 0)
++		return 0;
 +
-+    if (numtabs == 1)
-+    {
-+      /* First TAB. Collect all the matches */
-+      complete_all_nm_tags(pt);
++	return sb.st_size;
++}
 +
-+      /* All matches are stored. Longest non-ambiguous string is ""
-+       * i.e. don't change 'buffer'. Fake successful return this time.
-+       */
-+      if (User_typed[0] == 0)
-+	return 1;
-+    }
++/**
++ * store_size - Save the size of the compressed file
++ * @ctx: Mailbox
++ *
++ * Save the compressed file size in the compress_info struct.
++ */
++static void
++store_size (const CONTEXT *ctx)
++{
++	if (!ctx)
++		return;
 +
-+    if (Completed[0] == 0 && User_typed[0])
-+      return 0;
++	COMPRESS_INFO *ci = (COMPRESS_INFO *) ctx->compress_info;
++	ci->size = get_size (ctx->realpath);
++}
 +
-+    /* Num_matched will _always_ be atleast 1 since the initial
-+     * user-typed string is always stored */
-+    if (numtabs == 1 && Num_matched == 2)
-+      snprintf(Completed, sizeof(Completed),"%s", Matches[0]);
-+    else if (numtabs > 1 && Num_matched > 2)
-+      /* cycle thru all the matches */
-+      snprintf(Completed, sizeof(Completed), "%s",
-+	       Matches[(numtabs - 2) % Num_matched]);
++/**
++ * cb_format_str - Expand the filenames in the command string
++ * @dest:        Buffer in which to save string
++ * @destlen:     Buffer length
++ * @col:         Starting column, UNUSED
++ * @op:          printf-like operator, e.g. 't'
++ * @src:         printf-like format string
++ * @prefix:      Field formatting string, UNUSED
++ * @ifstring:    If condition is met, display this string, UNUSED
++ * @elsestring:  Otherwise, display this string, UNUSED
++ * @data:        Pointer to our sidebar_entry
++ * @flags:       Format flags, UNUSED
++ *
++ * cb_format_str is a callback function for mutt_FormatString.  It understands
++ * two operators. '%f' : 'from' filename, '%t' : 'to' filename.
++ *
++ * Returns: src (unchanged)
++ */
++static const char *
++cb_format_str (char *dest, size_t destlen, size_t col, int cols, char op, const char *src,
++	const char *fmt, const char *ifstring, const char *elsestring,
++	unsigned long data, format_flag flags)
++{
++	if (!fmt || !dest || (data == 0))
++		return src;
 +
-+    /* return the completed query */
-+    strncpy (pt, Completed, buffer + len - pt - spaces);
-+  }
-+  else
-+    return 0;
++	char tmp[SHORT_STRING];
 +
-+  return 1;
-+}
-+#endif
++	CONTEXT *ctx = (CONTEXT *) data;
 +
- static int var_to_string (int idx, char* val, size_t len)
- {
-   char tmp[LONG_STRING];
-@@ -2852,7 +3149,7 @@
-   mutt_buffer_init (&token);
-   for (; p; p = p->next)
-   {
--    if (mutt_parse_rc_line (p->data, &token, &err) != 0)
-+    if (mutt_parse_rc_line (p->data, &token, &err) == -1)
-     {
-       fprintf (stderr, _("Error in command line: %s\n"), err.data);
-       FREE (&token.data);
-@@ -2867,23 +3164,6 @@
-   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;
-@@ -2900,15 +3180,15 @@
- 
-   Groups = hash_create (1031, 0);
-   ReverseAlias = hash_create (1031, 1);
--  
-+#ifdef USE_NOTMUCH
-+  TagTransforms = hash_create (64, 1);
-+  TagFormats = hash_create (64, 0);
-+#endif
-+
-   mutt_menu_init ();
--  mutt_srandom ();
- 
--  /* 
--   * XXX - use something even more difficult to predict?
--   */
-   snprintf (AttachmentMarker, sizeof (AttachmentMarker),
--	    "\033]9;%ld\a", (long) time (NULL));
-+	    "\033]9;%" PRIu64 "\a", mutt_rand64());
-   
-   /* on one of the systems I use, getcwd() does not return the same prefix
-      as is listed in the passwd file */
-@@ -3002,6 +3282,28 @@
-     Fqdn = safe_strdup(utsname.nodename);
- 
- 
-+#ifdef USE_NNTP
-+  {
-+    FILE *f;
-+    char *i;
-+
-+    if ((f = safe_fopen (SYSCONFDIR "/nntpserver", "r")))
-+    {
-+      buffer[0] = '\0';
-+      fgets (buffer, sizeof (buffer), f);
-+      p = buffer;
-+      SKIPWS (p);
-+      i = p;
-+      while (*i && (*i != ' ') && (*i != '\t') && (*i != '\r') && (*i != '\n')) i++;
-+      *i = '\0';
-+      NewsServer = safe_strdup (p);
-+      fclose (f);
-+    }
-+  }
-+  if ((p = getenv ("NNTPSERVER")))
-+    NewsServer = safe_strdup (p);
-+#endif
-+
-   if ((p = getenv ("MAIL")))
-     Spoolfile = safe_strdup (p);
-   else if ((p = getenv ("MAILDIR")))
-@@ -3188,6 +3490,11 @@
- 
-   mutt_read_histfile ();
- 
-+#ifdef USE_NOTMUCH
-+  if (option (OPTVIRTSPOOLFILE) && VirtIncoming)
-+    mutt_str_replace(&Spoolfile, VirtIncoming->path);
-+#endif
++	switch (op) {
++		case 'f':
++			/* Compressed file */
++			snprintf (tmp, sizeof (tmp), "%%%ss", fmt);
++			snprintf (dest, destlen, tmp, ctx->realpath);
++			break;
++		case 't':
++			/* Plaintext, temporary file */
++			snprintf (tmp, sizeof (tmp), "%%%ss", fmt);
++			snprintf (dest, destlen, tmp, ctx->path);
++			break;
++	}
++	return src;
++}
 +
- #if 0
-   set_option (OPTWEED); /* turn weeding on by default */
- #endif
-@@ -3235,6 +3542,70 @@
-   return -1;
- }
- 
-+#ifdef USE_NOTMUCH
-+int parse_tag_transforms (BUFFER *b, BUFFER *s, unsigned long data, BUFFER *err)
++/**
++ * get_compression_cmd - Expand placeholders in command string
++ * @ctx: Mailbox for paths
++ * @cmd: Command string from config file
++ *
++ * This function takes a hook command and expands the filename placeholders
++ * within it.  The function calls mutt_FormatString() to do the replacement
++ * which calls our callback function cb_format_str(). e.g.
++ *
++ * Template command:
++ *	gzip -cd '%f' > '%t'
++ *
++ * Result:
++ *	gzip -dc '~/mail/abc.gz' > '/tmp/xyz'
++ *
++ * Note: Caller must free the returned string.
++ *
++ * Returns:
++ *	string: Expanded command string
++ *	NULL:   Error occurred
++ */
++static char *
++get_compression_cmd (const CONTEXT *ctx, const char *cmd)
 +{
-+  char *tmp;
++	if (!cmd || !ctx)
++		return NULL;
 +
-+  while (MoreArgs (s))
-+  {
-+    char *tag, *transform;
++	char expanded[_POSIX_PATH_MAX];
 +
-+    mutt_extract_token (b, s, 0);
-+    if (b->data && *b->data)
-+      tag = safe_strdup (b->data);
-+    else
-+      continue;
++	mutt_FormatString (expanded, sizeof (expanded), 0, COLS - SidebarWidth, cmd, cb_format_str, (unsigned long) ctx, 0);
++	return safe_strdup (expanded);
++}
 +
-+    mutt_extract_token (b, s, 0);
-+    transform = safe_strdup (b->data);
 +
-+    /* avoid duplicates */
-+    tmp = hash_find(TagTransforms, tag);
-+    if (tmp) {
-+      dprint(3,(debugfile,"tag transform '%s' already registered as '%s'\n", tag, tmp));
-+      FREE(&tag);
-+      FREE(&transform);
-+      continue;
-+    }
++/**
++ * comp_can_read - Can we read from this file?
++ * @path: Pathname of file to be tested
++ *
++ * Search for an 'open-hook' with a regex that matches the path.
++ *
++ * A match means it's our responsibility to open the file.
++ *
++ * Returns:
++ *	1: Yes, we can read the file
++ *	0: No, we cannot read the file
++ */
++int
++comp_can_read (const char *path)
++{
++	if (!path)
++		return 0;
 +
-+    hash_insert(TagTransforms, tag, transform, 0);
-+  }
-+  return 0;
++	return find_hook (M_OPENHOOK, path) ? 1 : 0;
 +}
 +
-+int parse_tag_formats (BUFFER *b, BUFFER *s, unsigned long data, BUFFER *err)
++/**
++ * comp_can_append - Can we append to this path?
++ * @path: pathname of file to be tested
++ *
++ * To append to a file we can either use an 'append-hook' or a combination of
++ * 'open-hook' and 'close-hook'.
++ *
++ * A match means it's our responsibility to append to the file.
++ *
++ * Returns:
++ *	1: Yes, we can append to the file
++ *	0: No, appending isn't possible
++ */
++int
++comp_can_append (const char *path)
 +{
-+  char *tmp;
++	if (!path)
++		return 0;
 +
-+  while (MoreArgs (s))
-+  {
-+    char *tag, *format;
++	int magic;
 +
-+    mutt_extract_token (b, s, 0);
-+    if (b->data && *b->data)
-+      tag = safe_strdup (b->data);
-+    else
-+      continue;
++	if (!file_exists (path)) {
++		char *dir_path = safe_strdup(path);
++		char *aux = strrchr(dir_path, '/');
++		int dir_valid = 1;
++		if (aux) {
++			*aux='\0';
++			if (access(dir_path, W_OK|X_OK))
++				dir_valid = 0;
++		}
++		FREE(&dir_path);
++		return dir_valid && (find_hook (M_CLOSEHOOK, path) ? 1 : 0);
++	}
 +
-+    mutt_extract_token (b, s, 0);
-+    format = safe_strdup (b->data);
++	magic = mx_get_magic (path);
 +
-+    /* avoid duplicates */
-+    tmp = hash_find(TagFormats, format);
-+    if (tmp) {
-+      dprint(3,(debugfile,"tag format '%s' already registered as '%s'\n", format, tmp));
-+      FREE(&tag);
-+      FREE(&format);
-+      continue;
-+    }
++	if (magic != 0 && magic != M_COMPRESSED)
++		return 0;
 +
-+    hash_insert(TagFormats, format, tag, 0);
-+  }
-+  return 0;
++	return (find_hook (M_APPENDHOOK, path)
++			|| (find_hook (M_OPENHOOK, path)
++			&& find_hook (M_CLOSEHOOK, path))) ? 1 : 0;
 +}
-+#endif
-+
- static void myvar_set (const char* var, const char* val)
- {
-   myvar_t** cur;
-@@ -3282,3 +3653,58 @@
- 
-   return NULL;
- }
 +
-+int mutt_label_complete (char *buffer, size_t len, int pos, int numtabs)
++/**
++ * comp_valid_command - Is this command string allowed?
++ * @cmd:  Command string
++ *
++ * A valid command string must have both "%f" (from file) and "%t" (to file).
++ * We don't check if we can actually run the command.
++ *
++ * Returns:
++ *	1: Valid command
++ *	0: "%f" and/or "%t" is missing
++ */
++int
++comp_valid_command (const char *cmd)
 +{
-+  char *pt = buffer;
-+  int spaces; /* keep track of the number of leading spaces on the line */
-+  int prefix;
++	if (!cmd)
++		return 0;
 +
-+  SKIPWS (buffer);
-+  spaces = buffer - pt;
++	return (strstr (cmd, "%f") && strstr (cmd, "%t")) ? 1 : 0;
++}
 +
-+  for (pt = buffer; pt && *pt && *(pt+1); pt++);
-+  for (; pt > buffer && !isspace(*(pt-1)); pt--);
-+  prefix = pt - buffer;
++/**
++ * comp_check_mailbox - Perform quick sanity check
++ * @ctx: Mailbox
++ *
++ * Compare the stored size (in the CONTEXT) against the size in our
++ * COMPRESS_INFO.
++ *
++ * The return codes are picked to match mx_check_mailbox().
++ *
++ * Returns:
++ *	 0: Mailbox OK
++ *	-1: Mailbox bad
++ */
++int
++comp_check_mailbox (CONTEXT *ctx)
++{
++	if (!ctx)
++		return -1;
 +
-+  /* first TAB. Collect all the matches */
-+  if (numtabs == 1)
-+  {
-+    struct hash_elem *entry;
-+    struct hash_walk_state state;
++	COMPRESS_INFO *ci = (COMPRESS_INFO *) ctx->compress_info;
 +
-+    Num_matched = 0;
-+    strfcpy (User_typed, pt, sizeof (User_typed));
-+    memset (Matches, 0, Matches_listsize);
-+    memset (Completed, 0, sizeof (Completed));
-+    memset (&state, 0, sizeof(state));
-+    while ((entry = hash_walk(Labels, &state)))
-+      candidate (Completed, User_typed, entry->key, sizeof (Completed));
-+    matches_ensure_morespace (Num_matched);
-+    qsort(Matches, Num_matched, sizeof(char *), (sort_t *) mutt_strcasecmp);
-+    Matches[Num_matched++] = User_typed;
++	if (get_size (ctx->realpath) != ci->size) {
++		FREE(&ctx->compress_info);
++		FREE(&ctx->realpath);
++		mutt_error _("Mailbox was corrupted!");
++		return -1;
++	}
++	return 0;
++}
 +
-+    /* All matches are stored. Longest non-ambiguous string is ""
-+     * i.e. dont change 'buffer'. Fake successful return this time */
-+    if (User_typed[0] == 0)
-+      return 1;
-+  }
++/**
++ * comp_open_read - XXX
++ * @ctx: Mailbox to open
++ *
++ * Returns:
++ *	 0: Success
++ *	-1: Failure
++ */
++int
++comp_open_read (CONTEXT *ctx)
++{
++	if (!ctx)
++		return 0;
 +
-+  if (Completed[0] == 0 && User_typed[0])
-+    return 0;
++	char *cmd;
++	FILE *fp;
++	int rc;
 +
-+   /* Num_matched will _always_ be atleast 1 since the initial
-+    * user-typed string is always stored */
-+  if (numtabs == 1 && Num_matched == 2)
-+    snprintf(Completed, sizeof(Completed), "%s", Matches[0]);
-+  else if (numtabs > 1 && Num_matched > 2)
-+    /* cycle thru all the matches */
-+    snprintf(Completed, sizeof(Completed), "%s", 
-+             Matches[(numtabs - 2) % Num_matched]);
++	COMPRESS_INFO *ci = set_compress_info (ctx);
++	if (!ci->open) {
++		ctx->magic = 0;
++		FREE(&ctx->compress_info);
++		return -1;
++	}
 +
-+  /* return the completed label */
-+  strncpy (&buffer[prefix], Completed, len - spaces);
++	if (!ci->close || access (ctx->path, W_OK) != 0)
++		ctx->readonly = 1;
 +
-+  return 1;
++	setup_paths (ctx);
++	store_size (ctx);
++
++	if (!ctx->quiet)
++		mutt_message (_("Decompressing %s..."), ctx->realpath);
++
++	cmd = get_compression_cmd (ctx, ci->open);
++	if (!cmd) {
++		return -1;
++	}
++	dprint (2, (debugfile, "DecompressCmd: '%s'\n", cmd));
++
++	fp = fopen (ctx->realpath, "r");
++	if (!fp) {
++		mutt_perror (ctx->realpath);
++		FREE(&cmd);
++		return -1;
++	}
++
++	mutt_block_signals();
++	if (lock_mailbox (ctx, fp, 0) == -1) {
++		fclose (fp);
++		mutt_unblock_signals();
++		mutt_error _("Unable to lock mailbox!");
++		FREE(&cmd);
++		return -1;
++	}
++
++	endwin();
++	fflush (stdout);
++	sprintf(echo_cmd,_("echo Decompressing %s..."),ctx->realpath);
++	mutt_system(echo_cmd);
++	rc = mutt_system (cmd);
++	unlock_mailbox (ctx, fp);
++	mutt_unblock_signals();
++	fclose (fp);
++
++	if (rc != 0) {
++		mutt_any_key_to_continue (NULL);
++		ctx->magic = 0;
++		FREE(&ctx->compress_info);
++		mutt_error (_("Error executing: %s : unable to open the mailbox!\n"), cmd);
++		/* remove the partial uncompressed file */
++		remove_file (ctx);
++		restore_path (ctx);
++	}
++	FREE(&cmd);
++	if (rc != 0)
++		return -1;
++
++	if (comp_check_mailbox (ctx))
++		return -1;
++
++	ctx->magic = mx_get_magic (ctx->path);
++
++	return 0;
 +}
 +
-diff -urN mutt-1.6.1/init.h mutt-1.6.1-neomutt/init.h
---- mutt-1.6.1/init.h	2016-06-12 18:43:00.408447684 +0100
-+++ mutt-1.6.1-neomutt/init.h	2016-06-12 18:43:00.708452362 +0100
-@@ -42,11 +42,12 @@
- #define DTYPE(x) ((x) & DT_MASK)
- 
- /* subtypes */
--#define DT_SUBTYPE_MASK	0xf0
-+#define DT_SUBTYPE_MASK	0xff0
- #define DT_SORT_ALIAS	0x10
- #define DT_SORT_BROWSER 0x20
- #define DT_SORT_KEYS	0x40
- #define DT_SORT_AUX	0x80
-+#define DT_SORT_SIDEBAR	0x100
- 
- /* flags to parse_set() */
- #define M_SET_INV	(1<<0)	/* default is to invert all vars */
-@@ -176,6 +177,20 @@
-   ** If \fIset\fP, Mutt will prompt you for carbon-copy (Cc) recipients before
-   ** editing the body of an outgoing message.
-   */
-+#ifdef USE_NNTP
-+  { "ask_follow_up",	DT_BOOL, R_NONE, OPTASKFOLLOWUP, 0 },
-+  /*
-+  ** .pp
-+  ** If set, Mutt will prompt you for follow-up groups before editing
-+  ** the body of an outgoing message.
-+  */
-+  { "ask_x_comment_to",	DT_BOOL, R_NONE, OPTASKXCOMMENTTO, 0 },
-+  /*
-+  ** .pp
-+  ** If set, Mutt will prompt you for x-comment-to field before editing
-+  ** the body of an outgoing message.
-+  */
-+#endif
-   { "assumed_charset", DT_STR, R_NONE, UL &AssumedCharset, UL 0},
-   /*
-   ** .pp
-@@ -322,6 +337,14 @@
-   ** follow these menus.  The option is \fIunset\fP by default because many
-   ** visual terminals don't permit making the cursor invisible.
-   */
-+#ifdef USE_NNTP
-+  { "catchup_newsgroup", DT_QUAD, R_NONE, OPT_CATCHUP, M_ASKYES },
-+  /*
-+  ** .pp
-+  ** If this variable is \fIset\fP, Mutt will mark all articles in newsgroup
-+  ** as read when you quit the newsgroup (catchup newsgroup).
-+  */
-+#endif
- #if defined(USE_SSL)
-   { "certificate_file",	DT_PATH, R_NONE, UL &SslCertFile, UL "~/.mutt_certificates" },
-   /*
-@@ -841,6 +864,16 @@
-   ** sent to both the list and your address, resulting in two copies
-   ** of the same email for you.
-   */
-+#ifdef USE_NNTP
-+  { "followup_to_poster", DT_QUAD, R_NONE, OPT_FOLLOWUPTOPOSTER, M_ASKYES },
-+  /*
-+  ** .pp
-+  ** If this variable is \fIset\fP and the keyword "poster" is present in
-+  ** \fIFollowup-To\fP header, follow-up to newsgroup function is not
-+  ** permitted.  The message will be mailed to the submitter of the
-+  ** message via mail.
-+  */
-+#endif
-   { "force_name",	DT_BOOL, R_NONE, OPTFORCENAME, 0 },
-   /*
-   ** .pp
-@@ -923,6 +956,26 @@
-   ** a regular expression that will match the whole name so mutt will expand
-   ** ``Franklin'' to ``Franklin, Steve''.
-   */
-+#ifdef USE_NNTP
-+  { "group_index_format", DT_STR, R_BOTH, UL &GroupFormat, UL "%4C %M%N %5s  %-45.45f %d" },
-+  /*
-+  ** .pp
-+  ** This variable allows you to customize the newsgroup browser display to
-+  ** your personal taste.  This string is similar to ``$index_format'', but
-+  ** has its own set of printf()-like sequences:
-+  ** .dl
-+  ** .dt %C  .dd current newsgroup number
-+  ** .dt %d  .dd description of newsgroup (becomes from server)
-+  ** .dt %f  .dd newsgroup name
-+  ** .dt %M  .dd - if newsgroup not allowed for direct post (moderated for example)
-+  ** .dt %N  .dd N if newsgroup is new, u if unsubscribed, blank otherwise
-+  ** .dt %n  .dd number of new articles in newsgroup
-+  ** .dt %s  .dd number of unread articles in newsgroup
-+  ** .dt %>X .dd right justify the rest of the string and pad with character "X"
-+  ** .dt %|X .dd pad to the end of the line with character "X"
-+  ** .de
-+  */
-+#endif
-   { "hdr_format",	DT_SYN,  R_NONE, UL "index_format", 0 },
-   /*
-   */
-@@ -1315,6 +1368,8 @@
-   ** .dt %E .dd number of messages in current thread
-   ** .dt %f .dd sender (address + real name), either From: or Return-Path:
-   ** .dt %F .dd author name, or recipient name if the message is from you
-+  ** .dt %g .dd message labels (e.g. notmuch tags)
-+  ** .dt %g .dd newsgroup name (if compiled with NNTP support)
-   ** .dt %H .dd spam attribute(s) of this message
-   ** .dt %i .dd message-id of the current message
-   ** .dt %l .dd number of lines in the message (does not work with maildir,
-@@ -1338,6 +1393,8 @@
-   ** .dt %T .dd the appropriate character from the $$to_chars string
-   ** .dt %u .dd user (login) name of the author
-   ** .dt %v .dd first name of the author, or the recipient if the message is from you
-+  ** .dt %W .dd name of organization of author (``Organization:'' field)
-+  ** .dt %x .dd ``X-Comment-To:'' field (if present and compiled with NNTP support)
-   ** .dt %X .dd number of attachments
-   **            (please see the ``$attachments'' section for possible speed effects)
-   ** .dt %y .dd ``X-Label:'' field, if present
-@@ -1361,6 +1418,10 @@
-   ** .dt %*X    .dd soft-fill with character ``X'' as pad
-   ** .de
-   ** .pp
-+  ** Date format expressions can be constructed based on relative dates. Using
-+  ** the date formatting operators along with nested conditionals, the date
-+  ** format can be modified based on how old a message is.  See the section on
-+  ** ``Conditional Dates'' for an explanation and examples
-   ** ``Soft-fill'' deserves some explanation: Normal right-justification
-   ** will print everything to the left of the ``%>'', displaying padding and
-   ** whatever lies to the right only if there's room. By contrast,
-@@ -1372,6 +1433,25 @@
-   ** Note that these expandos are supported in
-   ** ``$save-hook'', ``$fcc-hook'' and ``$fcc-save-hook'', too.
-   */
-+#ifdef USE_NNTP
-+  { "inews",		DT_PATH, R_NONE, UL &Inews, UL "" },
-+  /*
-+  ** .pp
-+  ** If set, specifies the program and arguments used to deliver news posted
-+  ** by Mutt.  Otherwise, mutt posts article using current connection to
-+  ** news server.  The following printf-style sequence is understood:
-+  ** .dl
-+  ** .dt %a .dd account url
-+  ** .dt %p .dd port
-+  ** .dt %P .dd port if specified
-+  ** .dt %s .dd news server name
-+  ** .dt %S .dd url schema
-+  ** .dt %u .dd username
-+  ** .de
-+  ** .pp
-+  ** Example: set inews="/usr/local/bin/inews -hS"
-+  */
-+#endif
-   { "ispell",		DT_PATH, R_NONE, UL &Ispell, UL ISPELL },
-   /*
-   ** .pp
-@@ -1384,6 +1464,28 @@
-   ** from your spool mailbox to your $$mbox mailbox, or as a result of
-   ** a ``$mbox-hook'' command.
-   */
-+  { "keywords_legacy", DT_BOOL, R_NONE, OPTKEYWORDSLEGACY, 1 },
-+  /*
-+  ** .pp
-+  ** If \fIset\fP, keywords/labels/tags will be written to whatever
-+  ** legacy, nonstandard headers (X-Label, X-Keywords, X-Mozilla-Keys)
-+  ** they were sourced from.
-+  ** .pp
-+  ** If both ``$$keywords_legacy'' and
-+  ** ``$$keywords_standard'' are \fCfalse\fP, mutt will save keywords
-+  ** to legacy headers to ensure that it does not lose your labels.
-+  */
-+  { "keywords_standard", DT_BOOL, R_NONE, OPTKEYWORDSSTANDARD, 0 },
-+  /*
-+  ** .pp
-+  ** If \fIset\fP, keywords/labels/tags will be written to the
-+  ** RFC2822-standard Keywords: header; this may imply a conversion from
-+  ** legacy headers.
-+  ** .pp
-+  ** If both ``$$keywords_legacy'' and
-+  ** ``$$keywords_standard'' are \fCfalse\fP, mutt will save keywords
-+  ** to legacy headers to ensure that it does not lose your labels.
-+  */
-   { "locale",		DT_STR,  R_BOTH, UL &Locale, UL "C" },
-   /*
-   ** .pp
-@@ -1616,6 +1718,15 @@
-   ** menu, attachments which cannot be decoded in a reasonable manner will
-   ** be attached to the newly composed message if this option is \fIset\fP.
-   */
-+#ifdef USE_NNTP
-+  { "mime_subject",	DT_BOOL, R_NONE, OPTMIMESUBJECT, 1 },
-+  /*
-+  ** .pp
-+  ** If \fIunset\fP, 8-bit ``subject:'' line in article header will not be
-+  ** encoded according to RFC2047 to base64.  This is useful when message
-+  ** is Usenet article, because MIME for news is nonstandard feature.
-+  */
-+#endif
- #ifdef MIXMASTER
-   { "mix_entry_format", DT_STR,  R_NONE, UL &MixEntryFormat, UL "%4n %c %-16s %a" },
-   /*
-@@ -1663,6 +1774,160 @@
-    ** See also $$read_inc, $$write_inc and $$net_inc.
-    */
- #endif
-+#ifdef USE_NNTP
-+  { "news_cache_dir",	DT_PATH, R_NONE, UL &NewsCacheDir, UL "~/.mutt" },
-+  /*
-+  ** .pp
-+  ** This variable pointing to directory where Mutt will save cached news
-+  ** articles and headers in. If \fIunset\fP, articles and headers will not be
-+  ** saved at all and will be reloaded from the server each time.
-+  */
-+  { "news_server",	DT_STR, R_NONE, UL &NewsServer, 0 },
-+  /*
-+  ** .pp
-+  ** This variable specifies domain name or address of NNTP server. It
-+  ** defaults to the news server specified in the environment variable
-+  ** $$$NNTPSERVER or contained in the file /etc/nntpserver.  You can also
-+  ** specify username and an alternative port for each news server, ie:
-+  ** .pp
-+  ** [[s]news://][username[:password]@]server[:port]
-+  */
-+  { "newsgroups_charset", DT_STR, R_NONE, UL &NewsgroupsCharset, UL "utf-8" },
-+  /*
-+  ** .pp
-+  ** Character set of newsgroups descriptions.
-+  */
-+  { "newsrc",		DT_PATH, R_NONE, UL &NewsRc, UL "~/.newsrc" },
-+  /*
-+  ** .pp
-+  ** The file, containing info about subscribed newsgroups - names and
-+  ** indexes of read articles.  The following printf-style sequence
-+  ** is understood:
-+  ** .dl
-+  ** .dt %a .dd account url
-+  ** .dt %p .dd port
-+  ** .dt %P .dd port if specified
-+  ** .dt %s .dd news server name
-+  ** .dt %S .dd url schema
-+  ** .dt %u .dd username
-+  ** .de
-+  */
-+  { "nntp_authenticators", DT_STR, R_NONE, UL &NntpAuthenticators, UL 0 },
-+  /*
-+  ** .pp
-+  ** This is a colon-delimited list of authentication methods mutt may
-+  ** attempt to use to log in to a news server, in the order mutt should
-+  ** try them.  Authentication methods are either ``user'' or any
-+  ** SASL mechanism, e.g. ``digest-md5'', ``gssapi'' or ``cram-md5''.
-+  ** This option is case-insensitive.  If it's \fIunset\fP (the default)
-+  ** mutt will try all available methods, in order from most-secure to
-+  ** least-secure.
-+  ** .pp
-+  ** Example:
-+  ** .ts
-+  ** set nntp_authenticators="digest-md5:user"
-+  ** .te
-+  ** .pp
-+  ** \fBNote:\fP Mutt will only fall back to other authentication methods if
-+  ** the previous methods are unavailable. If a method is available but
-+  ** authentication fails, mutt will not connect to the IMAP server.
-+  */
-+  { "nntp_context",	DT_NUM, R_NONE, UL &NntpContext, 1000 },
-+  /*
-+  ** .pp
-+  ** This variable defines number of articles which will be in index when
-+  ** newsgroup entered.  If active newsgroup have more articles than this
-+  ** number, oldest articles will be ignored.  Also controls how many
-+  ** articles headers will be saved in cache when you quit newsgroup.
-+  */
-+  { "nntp_listgroup",	DT_BOOL, R_NONE, OPTLISTGROUP, 1 },
-+  /*
-+  ** .pp
-+  ** This variable controls whether or not existence of each article is
-+  ** checked when newsgroup is entered.
-+  */
-+  { "nntp_load_description", DT_BOOL, R_NONE, OPTLOADDESC, 1 },
-+  /*
-+  ** .pp
-+  ** This variable controls whether or not descriptions for each newsgroup
-+  ** must be loaded when newsgroup is added to list (first time list
-+  ** loading or new newsgroup adding).
-+  */
-+  { "nntp_user",	DT_STR, R_NONE, UL &NntpUser, UL "" },
-+  /*
-+  ** .pp
-+  ** Your login name on the NNTP server.  If \fIunset\fP and NNTP server requires
-+  ** authentication, Mutt will prompt you for your account name when you
-+  ** connect to news server.
-+  */
-+  { "nntp_pass",	DT_STR, R_NONE, UL &NntpPass, UL "" },
-+  /*
-+  ** .pp
-+  ** Your password for NNTP account.
-+  */
-+  { "nntp_poll",	DT_NUM, R_NONE, UL &NewsPollTimeout, 60 },
-+  /*
-+  ** .pp
-+  ** The time in seconds until any operations on newsgroup except post new
-+  ** article will cause recheck for new news.  If set to 0, Mutt will
-+  ** recheck newsgroup on each operation in index (stepping, read article,
-+  ** etc.).
-+  */
-+#endif
-+#ifdef USE_NOTMUCH
-+  { "nm_open_timeout", DT_NUM, R_NONE, UL &NotmuchOpenTimeout, 5 },
-+  /*
-+   ** .pp
-+   ** This variable specifies the timeout for database open in seconds.
-+   */
++/**
++ * comp_open_append - XXX
++ * @ctx: Mailbox to append to
++ *
++ * Returns:
++ *	 0: Success
++ *	-1: Failure
++ */
++int
++comp_open_append (CONTEXT *ctx)
++{
++	if (!ctx)
++		return 0;
 +
-+  { "nm_default_uri", DT_STR, R_NONE, UL &NotmuchDefaultUri, 0 },
-+  /*
-+   ** .pp
-+   ** This variable specifies the default Notmuch database in format
-+   ** notmuch://<absolute path>.
-+   */
++	FILE *fh;
++	COMPRESS_INFO *ci = set_compress_info (ctx);
 +
-+  { "nm_hidden_tags", DT_STR, R_NONE, UL &NotmuchHiddenTags, UL "unread,draft,flagged,passed,replied,attachment,signed,encrypted" },
-+  /*
-+   ** .pp
-+   ** This variable specifies private notmuch tags which should not be printed
-+   ** on screen.
-+   */
-+  { "nm_exclude_tags", DT_STR,  R_NONE, UL &NotmuchExcludeTags, 0 },
-+  /*
-+   ** .pp
-+   ** The messages tagged with these tags are excluded and not loaded
-+   ** from notmuch DB to mutt unless specified explicitly.
-+   */
-+  { "nm_unread_tag", DT_STR, R_NONE, UL &NotmuchUnreadTag, UL "unread" },
-+  /*
-+   ** .pp
-+   ** This variable specifies notmuch tag which is used for unread messages. The
-+   ** variable is used to count unread messages in DB only. All other mutt commands
-+   ** use standard (e.g. maildir) flags.
-+   */
-+  { "nm_db_limit", DT_NUM, R_NONE, UL &NotmuchDBLimit, 0 },
-+  /*
-+   ** .pp
-+   ** This variable specifies the default limit used in notmuch queries.
-+   */
-+  { "nm_query_type", DT_STR, R_NONE, UL &NotmuchQueryType, UL "messages" },
-+  /*
-+   ** .pp
-+   ** This variable specifies the default query type (threads or messages) used in notmuch queries.
-+   */
-+  { "nm_record", DT_BOOL, R_NONE, OPTNOTMUCHRECORD, 0 },
-+  /*
-+   ** .pp
-+   ** This variable specifies if the mutt record should indexed by notmuch.
-+   */
-+  { "nm_record_tags", DT_STR, R_NONE, UL &NotmuchRecordTags, 0 },
-+  /*
-+   ** .pp
-+   ** This variable specifies the default tags applied to messages stored to the mutt record.
-+   */
-+#endif
-   { "pager",		DT_PATH, R_NONE, UL &Pager, UL "builtin" },
-   /*
-   ** .pp
-@@ -2189,6 +2454,16 @@
-   { "post_indent_str",  DT_SYN,  R_NONE, UL "post_indent_string", 0 },
-   /*
-   */
-+#ifdef USE_NNTP
-+  { "post_moderated",	DT_QUAD, R_NONE, OPT_TOMODERATED, M_ASKYES },
-+  /*
-+  ** .pp
-+  ** If set to \fIyes\fP, Mutt will post article to newsgroup that have
-+  ** not permissions to posting (e.g. moderated).  \fBNote:\fP if news server
-+  ** does not support posting to that newsgroup or totally read-only, that
-+  ** posting will not have an effect.
-+  */
-+#endif
-   { "postpone",		DT_QUAD, R_NONE, OPT_POSTPONE, M_ASKYES },
-   /*
-   ** .pp
-@@ -2665,6 +2940,169 @@
-   ** Command to use when spawning a subshell.  By default, the user's login
-   ** shell from \fC/etc/passwd\fP is used.
-   */
-+#ifdef USE_NNTP
-+  { "save_unsubscribed", DT_BOOL, R_NONE, OPTSAVEUNSUB, 0 },
-+  /*
-+  ** .pp
-+  ** When \fIset\fP, info about unsubscribed newsgroups will be saved into
-+  ** ``newsrc'' file and into cache.
-+  */
-+  { "show_new_news",	DT_BOOL, R_NONE, OPTSHOWNEWNEWS, 1 },
-+  /*
-+  ** .pp
-+  ** If \fIset\fP, news server will be asked for new newsgroups on entering
-+  ** the browser.  Otherwise, it will be done only once for a news server.
-+  ** Also controls whether or not number of new articles of subscribed
-+  ** newsgroups will be then checked.
-+  */
-+  { "show_only_unread",	DT_BOOL, R_NONE, OPTSHOWONLYUNREAD, 0 },
-+  /*
-+  ** .pp
-+  ** If \fIset\fP, only subscribed newsgroups that contain unread articles
-+  ** will be displayed in browser.
-+  */
-+#endif
-+#ifdef USE_SIDEBAR
-+  { "sidebar_divider_char", DT_STR, R_BOTH, UL &SidebarDividerChar, UL "|" },
-+  /*
-+  ** .pp
-+  ** This specifies the characters to be drawn between the sidebar (when
-+  ** visible) and the other Mutt panels. ASCII and Unicode line-drawing
-+  ** characters are supported.
-+  */
-+  { "sidebar_delim_chars", DT_STR, R_NONE, UL &SidebarDelimChars, UL "/." },
-+  /*
-+  ** .pp
-+  ** This contains the list of characters which you would like to treat
-+  ** as folder separators for displaying paths in the sidebar.
-+  ** .pp
-+  ** Local mail is often arranged in directories: `dir1/dir2/mailbox'.
-+  ** .ts
-+  ** set sidebar_delim_chars='/'
-+  ** .te
-+  ** .pp
-+  ** IMAP mailboxes are often named: `folder1.folder2.mailbox'.
-+  ** .ts
-+  ** set sidebar_delim_chars='.'
-+  ** .te
-+  ** .pp
-+  ** \fBSee also:\fP $$sidebar_short_path, $$sidebar_folder_indent, $$sidebar_indent_string.
-+  */
-+  { "sidebar_folder_indent", DT_BOOL, R_BOTH, OPTSIDEBARFOLDERINDENT, 0 },
-+  /*
-+  ** .pp
-+  ** Set this to indent mailboxes in the sidebar.
-+  ** .pp
-+  ** \fBSee also:\fP $$sidebar_short_path, $$sidebar_indent_string, $$sidebar_delim_chars.
-+  */
-+  { "sidebar_format", DT_STR, R_NONE, UL &SidebarFormat, UL "%B%?F? [%F]?%* %?N?%N/?%S" },
-+  /*
-+  ** .pp
-+  ** This variable allows you to customize the sidebar display. This string is
-+  ** similar to $$index_format, but has its own set of \fCprintf(3)\fP-like
-+  ** sequences:
-+  ** .dl
-+  ** .dt %B  .dd Name of the mailbox
-+  ** .dt %S  .dd * Size of mailbox (total number of messages)
-+  ** .dt %N  .dd * Number of New messages in the mailbox
-+  ** .dt %F  .dd * Number of Flagged messages in the mailbox
-+  ** .dt %!  .dd ``!'' : one flagged message;
-+  **             ``!!'' : two flagged messages;
-+  **             ``n!'' : n flagged messages (for n > 2).
-+  **             Otherwise prints nothing.
-+  ** .dt %d  .dd * @ Number of deleted messages
-+  ** .dt %L  .dd * @ Number of messages after limiting
-+  ** .dt %t  .dd * @ Number of tagged messages
-+  ** .dt %>X .dd right justify the rest of the string and pad with ``X''
-+  ** .dt %|X .dd pad to the end of the line with ``X''
-+  ** .dt %*X .dd soft-fill with character ``X'' as pad
-+  ** .de
-+  ** .pp
-+  ** * = Can be optionally printed if nonzero
-+  ** @ = Only applicable to the current folder
-+  */
-+  { "sidebar_indent_string", DT_STR, R_BOTH, UL &SidebarIndentString, UL "  " },
-+  /*
-+  ** .pp
-+  ** This specifies the string that is used to indent mailboxes in the sidebar.
-+  ** It defaults to two spaces.
-+  ** .pp
-+  ** \fBSee also:\fP $$sidebar_short_path, $$sidebar_folder_indent, $$sidebar_delim_chars.
-+  */
-+  { "sidebar_new_mail_only", DT_BOOL, R_BOTH, OPTSIDEBARNEWMAILONLY, 0 },
-+  /*
-+  ** .pp
-+  ** When set, the sidebar will only display mailboxes containing new, or
-+  ** flagged, mail.
-+  ** .pp
-+  ** \fBSee also:\fP $sidebar_whitelist.
-+  */
-+  { "sidebar_next_new_wrap", DT_BOOL, R_BOTH, UL OPTSIDEBARNEXTNEWWRAP, 0 },
-+  /*
-+  ** .pp
-+  ** When set, the \fC<sidebar-next-new>\fP command will not stop and the end of
-+  ** the list of mailboxes, but wrap around to the beginning. The
-+  ** \fC<sidebar-prev-new>\fP command is similarly affected, wrapping around to
-+  ** the end of the list.
-+  */
-+  { "sidebar_refresh_time", DT_NUM, R_BOTH, UL &SidebarRefreshTime, 60 },
-+  /*
-+  ** .pp
-+  ** Set sidebar_refresh_time to the minimum number of seconds between refreshes.
-+  ** This will reduce network traffic.
-+  ** .pp
-+  ** \fBNote:\fP Set to 0 to disable refreshing.
-+  */
-+  { "sidebar_short_path", DT_BOOL, R_BOTH, OPTSIDEBARSHORTPATH, 0 },
-+  /*
-+  ** .pp
-+  ** By default the sidebar will show the mailbox's path, relative to the
-+  ** $$folder variable. Setting \fCsidebar_shortpath=yes\fP will shorten the
-+  ** names relative to the previous name. Here's an example:
-+  ** .dl
-+  ** .dt \fBshortpath=no\fP .dd \fBshortpath=yes\fP .dd \fBshortpath=yes, folderindent=yes, indentstr=".."\fP
-+  ** .dt \fCfruit\fP        .dd \fCfruit\fP         .dd \fCfruit\fP
-+  ** .dt \fCfruit.apple\fP  .dd \fCapple\fP         .dd \fC..apple\fP
-+  ** .dt \fCfruit.banana\fP .dd \fCbanana\fP        .dd \fC..banana\fP
-+  ** .dt \fCfruit.cherry\fP .dd \fCcherry\fP        .dd \fC..cherry\fP
-+  ** .de
-+  ** .pp
-+  ** \fBSee also:\fP $$sidebar_delim_chars, $$sidebar_folder_indent, $$sidebar_indent_string.
-+  */
-+  { "sidebar_sort_method", DT_SORT|DT_SORT_SIDEBAR, R_NONE, UL &SidebarSortMethod, SORT_ORDER },
-+  /*
-+  ** .pp
-+  ** Specifies how to sort entries in the file browser.  By default, the
-+  ** entries are sorted alphabetically.  Valid values:
-+  ** .il
-+  ** .dd alpha (alphabetically)
-+  ** .dd count (all message count)
-+  ** .dd date
-+  ** .dd desc (description)
-+  ** .dd new (new message count)
-+  ** .dd size
-+  ** .dd unsorted
-+  ** .ie
-+  ** .pp
-+  ** You may optionally use the ``reverse-'' prefix to specify reverse sorting
-+  ** order (example: ``\fCset sort_browser=reverse-date\fP'').
-+  */
-+  { "sidebar_visible", DT_BOOL, R_BOTH, OPTSIDEBAR, 0 },
-+  /*
-+  ** .pp
-+  ** This specifies whether or not to show sidebar. The sidebar shows a list of
-+  ** all your mailboxes.
-+  ** .pp
-+  ** \fBSee also:\fP $$sidebar_format, $$sidebar_width
-+  */
-+  { "sidebar_width", DT_NUM, R_BOTH, UL &SidebarWidth, 0 },
-+  /*
-+  ** .pp
-+  ** This controls the width of the sidebar.  It is measured in screen columns.
-+  ** For example: sidebar_width=20 could display 20 ASCII characters, or 10
-+  ** Chinese characters.
-+  */
-+#endif
-   { "sig_dashes",	DT_BOOL, R_NONE, OPTSIGDASHES, 1 },
-   /*
-   ** .pp
-@@ -2703,6 +3141,12 @@
-   ** replacing ``%s'' with the supplied string.
-   ** For the default value, ``joe'' would be expanded to: ``~f joe | ~s joe''.
-   */
-+  { "skip_quoted_offset", DT_NUM, R_NONE, UL &SkipQuotedOffset, 0 },
-+  /*
-+  ** .pp
-+  ** Lines of quoted text that are displayed before the unquoted text after
-+  ** "skip to quoted" command (S)
-+  */
-   { "sleep_time",	DT_NUM, R_NONE, UL &SleepTime, 1 },
-   /*
-   ** .pp
-@@ -3046,7 +3490,10 @@
-   ** entries are sorted alphabetically.  Valid values:
-   ** .il
-   ** .dd alpha (alphabetically)
-+  ** .dd count (all message count)
-   ** .dd date
-+  ** .dd desc (description)
-+  ** .dd new (new message count)
-   ** .dd size
-   ** .dd unsorted
-   ** .ie
-@@ -3057,14 +3504,15 @@
-   { "sort_re",		DT_BOOL, R_INDEX|R_RESORT|R_RESORT_INIT, OPTSORTRE, 1 },
-   /*
-   ** .pp
--  ** This variable is only useful when sorting by threads with
--  ** $$strict_threads \fIunset\fP.  In that case, it changes the heuristic
--  ** mutt uses to thread messages by subject.  With $$sort_re \fIset\fP, mutt will
--  ** only attach a message as the child of another message by subject if
--  ** the subject of the child message starts with a substring matching the
--  ** setting of $$reply_regexp.  With $$sort_re \fIunset\fP, mutt will attach
--  ** the message whether or not this is the case, as long as the
--  ** non-$$reply_regexp parts of both messages are identical.
-+  ** This variable is only useful when sorting by mailboxes in sidebar. By default,
-+  ** entries are unsorted.  Valid values:
-+  ** .il
-+  ** .dd count (all message count)
-+  ** .dd desc  (virtual mailbox description)
-+  ** .dd new (new message count)
-+  ** .dd path
-+  ** .dd unsorted
-+  ** .ie
-   */
-   { "spam_separator",   DT_STR, R_NONE, UL &SpamSep, UL "," },
-   /*
-@@ -3419,6 +3867,16 @@
-   ** provided that ``$$ts_enabled'' has been set. This string is identical in
-   ** formatting to the one used by ``$$status_format''.
-   */
-+  { "trash",            DT_PATH, R_NONE, UL &TrashPath, 0 },
-+  /*
-+  ** .pp
-+  ** If set, this variable specifies the path of the trash folder where the
-+  ** mails marked for deletion will be moved, instead of being irremediably
-+  ** purged.
-+  ** .pp
-+  ** NOTE: When you delete a message in the trash folder, it is really
-+  ** deleted, so that you have a way to clean the trash.
-+  */
- #ifdef USE_SOCKET
-   { "tunnel",            DT_STR, R_NONE, UL &Tunnel, UL 0 },
-   /*
-@@ -3507,6 +3965,31 @@
-   ** Specifies the visual editor to invoke when the ``\fC~v\fP'' command is
-   ** given in the built-in editor.
-   */
-+#ifdef USE_NOTMUCH
-+  { "vfolder_format",	DT_STR,	 R_INDEX, UL &VirtFolderFormat, UL " %6n(%6N) %f " },
-+  /*
-+  ** .pp
-+  ** This variable allows you to customize the file browser display for virtual
-+  ** folders to your ** personal taste.  This string is similar to $$index_format,
-+  ** but has its own set of \fCprintf(3)\fP-like sequences:
-+  ** .dl
-+  ** .dt %f  .dd folder name (description)
-+  ** .dt %n  .dd number of all messages
-+  ** .dt %N  .dd number of new messages
-+  ** .dt %>X .dd right justify the rest of the string and pad with character ``X''
-+  ** .dt %|X .dd pad to the end of the line with character ``X''
-+  ** .dt %*X .dd soft-fill with character ``X'' as pad
-+  ** .de
-+  ** .pp
-+  ** For an explanation of ``soft-fill'', see the $$index_format documentation.
-+  */
-+  { "virtual_spoolfile", DT_BOOL, R_NONE, OPTVIRTSPOOLFILE, 0 },
-+  /*
-+  ** .pp
-+  ** When \fset\fP, mutt will use the first defined virtual mailbox (see
-+  ** virtual-mailboxes) as a spool file.
-+  */
-+#endif
-   { "wait_key",		DT_BOOL, R_NONE, OPTWAITKEY, 1 },
-   /*
-   ** .pp
-@@ -3590,6 +4073,28 @@
-   {"xterm_set_titles",	DT_SYN,  R_NONE, UL "ts_enabled", 0 },
-   /*
-   */
-+  { "xlabel_delimiter", DT_STR, R_NONE, UL &XlabelDelim, UL "" },
-+  /*
-+  ** .pp
-+  ** The character used to delimit distinct keywords in X-Label headers.
-+  ** X-Label is primarily a Mutt artifact, and the semantics of the field
-+  ** were never defined: it is free-form text.  However interaction with
-+  ** X-Keywords:, X-Mozilla-Keys:, and Keywords: requires that we adopt
-+  ** some means of identifying separate keywords within the field.  Set
-+  ** this to your personal convention.
-+  ** .pp
-+  ** This affect both parsing existing X-Label headers and writing new
-+  ** X-Label headers.  You can modify this variable in runtime to accomplish
-+  ** various kinds of conversion.
-+  */
-+#ifdef USE_NNTP
-+  { "x_comment_to",	DT_BOOL, R_NONE, OPTXCOMMENTTO, 0 },
-+  /*
-+  ** .pp
-+  ** If \fIset\fP, Mutt will add ``X-Comment-To:'' field (that contains full
-+  ** name of original article author) to article that followuped to newsgroup.
-+  */
-+#endif
-   /*--*/
-   { NULL, 0, 0, 0, 0 }
- };
-@@ -3606,6 +4111,7 @@
-   { "to",		SORT_TO },
-   { "score",		SORT_SCORE },
-   { "spam",		SORT_SPAM },
-+  { "label",		SORT_LABEL },
-   { NULL,               0 }
- };
- 
-@@ -3625,13 +4131,17 @@
-   { "to",		SORT_TO },
-   { "score",		SORT_SCORE },
-   { "spam",		SORT_SPAM },
-+  { "label",		SORT_LABEL },
-   { NULL,               0 }
- };
- 
- 
- const struct mapping_t SortBrowserMethods[] = {
-   { "alpha",	SORT_SUBJECT },
-+  { "count",	SORT_COUNT },
-   { "date",	SORT_DATE },
-+  { "desc",	SORT_DESC },
-+  { "new",	SORT_COUNT_NEW },
-   { "size",	SORT_SIZE },
-   { "unsorted",	SORT_ORDER },
-   { NULL,       0 }
-@@ -3652,6 +4162,19 @@
-   { NULL,       0 }
- };
- 
-+const struct mapping_t SortSidebarMethods[] = {
-+  { "alpha",		SORT_PATH },
-+  { "count",		SORT_COUNT },
-+  { "desc",		SORT_DESC },
-+  { "flagged",		SORT_FLAGGED },
-+  { "mailbox-order",	SORT_ORDER },
-+  { "name",		SORT_PATH },
-+  { "new",		SORT_COUNT_NEW },
-+  { "path",		SORT_PATH },
-+  { "unsorted",		SORT_ORDER },
-+  { NULL,		0 }
-+};
-+
- 
- /* functions used to parse commands in a rc file */
- 
-@@ -3665,6 +4188,8 @@
- static int parse_unlists (BUFFER *, BUFFER *, unsigned long, BUFFER *);
- static int parse_alias (BUFFER *, BUFFER *, unsigned long, BUFFER *);
- static int parse_unalias (BUFFER *, BUFFER *, unsigned long, BUFFER *);
-+static int finish_source (BUFFER *, BUFFER *, unsigned long, BUFFER *);
-+static int parse_ifdef (BUFFER *, BUFFER *, unsigned long, BUFFER *);
- static int parse_ignore (BUFFER *, BUFFER *, unsigned long, BUFFER *);
- static int parse_unignore (BUFFER *, BUFFER *, unsigned long, BUFFER *);
- static int parse_source (BUFFER *, BUFFER *, unsigned long, BUFFER *);
-@@ -3676,13 +4201,16 @@
- static int parse_attachments (BUFFER *, BUFFER *, unsigned long, BUFFER *);
- static int parse_unattachments (BUFFER *, BUFFER *, unsigned long, BUFFER *);
- 
--
- static int parse_alternates (BUFFER *, BUFFER *, unsigned long, BUFFER *);
- static int parse_unalternates (BUFFER *, BUFFER *, unsigned long, BUFFER *);
- 
- /* Parse -group arguments */
- static int parse_group_context (group_context_t **ctx, BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err);
- 
-+#ifdef USE_NOTMUCH
-+static int parse_tag_transforms (BUFFER *, BUFFER *, unsigned long, BUFFER *);
-+static int parse_tag_formats (BUFFER *, BUFFER *, unsigned long, BUFFER *);
-+#endif
- 
- struct command_t
- {
-@@ -3712,9 +4240,17 @@
-   { "fcc-hook",		mutt_parse_hook,	M_FCCHOOK },
-   { "fcc-save-hook",	mutt_parse_hook,	M_FCCHOOK | M_SAVEHOOK },
-   { "folder-hook",	mutt_parse_hook,	M_FOLDERHOOK },
-+#ifdef USE_COMPRESSED
-+  { "open-hook",	mutt_parse_hook,	M_OPENHOOK },
-+  { "close-hook",	mutt_parse_hook,	M_CLOSEHOOK },
-+  { "append-hook",	mutt_parse_hook,	M_APPENDHOOK },
-+#endif
-   { "group",		parse_group,		M_GROUP },
-   { "ungroup",		parse_group,		M_UNGROUP },
-   { "hdr_order",	parse_list,		UL &HeaderOrderList },
-+  { "ifdef",		parse_ifdef,		0 },
-+  { "ifndef",		parse_ifdef,		1 },
-+  { "finish",		finish_source,		0 },
- #ifdef HAVE_ICONV
-   { "iconv-hook",	mutt_parse_hook,	M_ICONVHOOK },
- #endif
-@@ -3723,6 +4259,11 @@
-   { "macro",		mutt_parse_macro,	0 },
-   { "mailboxes",	mutt_parse_mailboxes,	M_MAILBOXES },
-   { "unmailboxes",	mutt_parse_mailboxes,	M_UNMAILBOXES },
-+#ifdef USE_NOTMUCH
-+  { "virtual-mailboxes",mutt_parse_virtual_mailboxes, 0 },
-+  { "tag-transforms",	parse_tag_transforms,	0 },
-+  { "tag-formats",	parse_tag_formats,	0 },
-+#endif
-   { "mailto_allow",	parse_list,		UL &MailtoAllow },
-   { "unmailto_allow",	parse_unlist,		UL &MailtoAllow },
-   { "message-hook",	mutt_parse_hook,	M_MESSAGEHOOK },
-@@ -3741,6 +4282,9 @@
-   { "send-hook",	mutt_parse_hook,	M_SENDHOOK },
-   { "send2-hook",	mutt_parse_hook,	M_SEND2HOOK },
-   { "set",		parse_set,		0 },
-+#ifdef USE_SIDEBAR
-+  { "sidebar_whitelist",parse_list,		UL &SidebarWhitelist },
-+#endif
-   { "source",		parse_source,		0 },
-   { "spam",		parse_spam_list,	M_SPAM },
-   { "nospam",		parse_spam_list,	M_NOSPAM },
-diff -urN mutt-1.6.1/keymap.c mutt-1.6.1-neomutt/keymap.c
---- mutt-1.6.1/keymap.c	2016-06-12 18:43:00.408447684 +0100
-+++ mutt-1.6.1-neomutt/keymap.c	2016-06-12 18:43:00.712452424 +0100
-@@ -76,10 +76,8 @@
-   { "<Insert>",	KEY_IC },
-   { "<Home>",	KEY_HOME },
-   { "<End>",	KEY_END },
--#ifdef KEY_ENTER
--  { "<Enter>",	KEY_ENTER },
--#endif
--  { "<Return>",	M_ENTER_C },
-+  { "<Enter>",	'\n' },
-+  { "<Return>",	'\r' },
-   { "<Esc>",	'\033' },
-   { "<Tab>",	'\t' },
-   { "<Space>",	' ' },
-@@ -453,6 +451,9 @@
-     }
- #endif
- 
-+    /* update sidebar stats */
-+    mutt_buffy_check(0);
-+
-     timeout (i * 1000);
-     tmp = mutt_getch();
-     timeout (-1);
-@@ -781,6 +782,7 @@
-   km_bindkey ("8", MENU_GENERIC, OP_JUMP);
-   km_bindkey ("9", MENU_GENERIC, OP_JUMP);
- 
-+  km_bindkey ("<return>", MENU_GENERIC, OP_GENERIC_SELECT_ENTRY);
-   km_bindkey ("<enter>", MENU_GENERIC, OP_GENERIC_SELECT_ENTRY);
- 
-   /* Miscellaneous extra bindings */
-@@ -792,10 +794,10 @@
-   km_bindkey ("K", MENU_MAIN, OP_PREV_ENTRY);
-   km_bindkey ("x", MENU_MAIN, OP_EXIT);
- 
-+  km_bindkey ("<return>", MENU_MAIN, OP_DISPLAY_MESSAGE);
-   km_bindkey ("<enter>", MENU_MAIN, OP_DISPLAY_MESSAGE);
- 
-   km_bindkey ("x", MENU_PAGER, OP_EXIT);
--  km_bindkey ("i", MENU_PAGER, OP_EXIT);
-   km_bindkey ("<backspace>", MENU_PAGER, OP_PREV_LINE);
-   km_bindkey ("<pagedown>", MENU_PAGER, OP_NEXT_PAGE);
-   km_bindkey ("<pageup>", MENU_PAGER, OP_PREV_PAGE);
-@@ -815,13 +817,16 @@
-   km_bindkey ("8", MENU_PAGER, OP_JUMP);
-   km_bindkey ("9", MENU_PAGER, OP_JUMP);
- 
-+  km_bindkey ("<return>", MENU_PAGER, OP_NEXT_LINE);
-   km_bindkey ("<enter>", MENU_PAGER, OP_NEXT_LINE);
-   
-   km_bindkey ("<return>", MENU_ALIAS, OP_GENERIC_SELECT_ENTRY);
-   km_bindkey ("<enter>",  MENU_ALIAS, OP_GENERIC_SELECT_ENTRY);
-   km_bindkey ("<space>", MENU_ALIAS, OP_TAG);
- 
-+  km_bindkey ("<return>", MENU_ATTACH, OP_VIEW_ATTACH);
-   km_bindkey ("<enter>", MENU_ATTACH, OP_VIEW_ATTACH);
-+  km_bindkey ("<return>", MENU_COMPOSE, OP_VIEW_ATTACH);
-   km_bindkey ("<enter>", MENU_COMPOSE, OP_VIEW_ATTACH);
- 
-   /* edit-to (default "t") hides generic tag-entry in Compose menu
-diff -urN mutt-1.6.1/lib.c mutt-1.6.1-neomutt/lib.c
---- mutt-1.6.1/lib.c	2016-06-12 18:43:00.408447684 +0100
-+++ mutt-1.6.1-neomutt/lib.c	2016-06-12 18:43:00.712452424 +0100
-@@ -219,8 +219,10 @@
-   {
-     if (fflush (*f) || fsync (fileno (*f)))
-     {
-+      int save_errno = errno;
-       r = -1;
-       safe_fclose (f);
-+      errno = save_errno;
-     }
-     else
-       r = safe_fclose (f);
-@@ -367,6 +369,7 @@
-     size -= chunk;
-   }
- 
-+  if (fflush(out) != 0) return -1;
-   return 0;
- }
- 
-@@ -381,6 +384,7 @@
-       return (-1);
-   }
- 
-+  if (fflush(fout) != 0) return -1;
-   return 0;
- }
- 
-diff -urN mutt-1.6.1/LICENSE.md mutt-1.6.1-neomutt/LICENSE.md
---- mutt-1.6.1/LICENSE.md	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/LICENSE.md	2016-06-12 18:43:00.663451660 +0100
-@@ -0,0 +1,336 @@
-+GNU General Public License
-+==========================
++	if (!get_append_command (ctx, ctx->path)) {
++		if (ci->open && ci->close) {
++			return (comp_open_read (ctx));
++		}
 +
-+_Version 2, June 1991_  
-+_Copyright © 1989, 1991 Free Software Foundation, Inc.,_  
-+_51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA_
++		ctx->magic = 0;
++		FREE(&ctx->compress_info);
++		return -1;
++	}
 +
-+Everyone is permitted to copy and distribute verbatim copies
-+of this license document, but changing it is not allowed.
++	setup_paths (ctx);
 +
-+### Preamble
++	ctx->magic = DefaultMagic;
 +
-+The licenses for most software are designed to take away your
-+freedom to share and change it.  By contrast, the GNU General Public
-+License is intended to guarantee your freedom to share and change free
-+software--to make sure the software is free for all its users.  This
-+General Public License applies to most of the Free Software
-+Foundation's software and to any other program whose authors commit to
-+using it.  (Some other Free Software Foundation software is covered by
-+the GNU Lesser General Public License instead.)  You can apply it to
-+your programs, too.
++	if (file_exists (ctx->realpath)) {
++		if (ctx->magic == M_MBOX || ctx->magic == M_MMDF) {
++			if ((fh = safe_fopen (ctx->path, "w"))) {
++				fclose (fh);
++			}
++		}
++	}
++	/* No error checking - the parent function will catch it */
 +
-+When we speak of free software, we are referring to freedom, not
-+price.  Our General Public Licenses are designed to make sure that you
-+have the freedom to distribute copies of free software (and charge for
-+this service if you wish), that you receive source code or can get it
-+if you want it, that you can change the software or use pieces of it
-+in new free programs; and that you know you can do these things.
++	return 0;
++}
 +
-+To protect your rights, we need to make restrictions that forbid
-+anyone to deny you these rights or to ask you to surrender the rights.
-+These restrictions translate to certain responsibilities for you if you
-+distribute copies of the software, or if you modify it.
++/**
++ * comp_sync - XXX
++ * @ctx: Mailbox to sync
++ *
++ * Returns:
++ *	 0: Success
++ *	-1: Failure
++ */
++int
++comp_sync (CONTEXT *ctx)
++{
++	if (!ctx)
++		return 0;
 +
-+For example, if you distribute copies of such a program, whether
-+gratis or for a fee, you must give the recipients all the rights that
-+you have.  You must make sure that they, too, receive or can get the
-+source code.  And you must show them these terms so they know their
-+rights.
++	char *cmd;
++	int rc = 0;
++	FILE *fp;
++	COMPRESS_INFO *ci = (COMPRESS_INFO *) ctx->compress_info;
 +
-+We protect your rights with two steps: **(1)** copyright the software, and
-+**(2)** offer you this license which gives you legal permission to copy,
-+distribute and/or modify the software.
++	if (!ctx->quiet)
++		mutt_message (_("Compressing %s..."), ctx->realpath);
 +
-+Also, for each author's protection and ours, we want to make certain
-+that everyone understands that there is no warranty for this free
-+software.  If the software is modified by someone else and passed on, we
-+want its recipients to know that what they have is not the original, so
-+that any problems introduced by others will not reflect on the original
-+authors' reputations.
++	cmd = get_compression_cmd (ctx, ci->close);
++	if (!cmd)
++		return -1;
 +
-+Finally, any free program is threatened constantly by software
-+patents.  We wish to avoid the danger that redistributors of a free
-+program will individually obtain patent licenses, in effect making the
-+program proprietary.  To prevent this, we have made it clear that any
-+patent must be licensed for everyone's free use or not licensed at all.
++	fp = fopen (ctx->realpath, "a");
++	if (!fp) {
++		mutt_perror (ctx->realpath);
++		FREE(&cmd);
++		return -1;
++	}
 +
-+The precise terms and conditions for copying, distribution and
-+modification follow.
++	mutt_block_signals();
++	if (lock_mailbox (ctx, fp, 1) == -1) {
++		fclose (fp);
++		mutt_unblock_signals();
++		mutt_error _("Unable to lock mailbox!");
++		store_size (ctx);
++		FREE(&cmd);
++		return -1;
++	}
 +
-+### TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
++	dprint (2, (debugfile, "CompressCommand: '%s'\n", cmd));
 +
-+**0.** This License applies to any program or other work which contains
-+a notice placed by the copyright holder saying it may be distributed
-+under the terms of this General Public License.  The “Program”, below,
-+refers to any such program or work, and a “work based on the Program”
-+means either the Program or any derivative work under copyright law:
-+that is to say, a work containing the Program or a portion of it,
-+either verbatim or with modifications and/or translated into another
-+language.  (Hereinafter, translation is included without limitation in
-+the term “modification”.)  Each licensee is addressed as “you”.
++	endwin();
++	fflush (stdout);
++	sprintf(echo_cmd,_("echo Compressing %s..."), ctx->realpath);
++	mutt_system(echo_cmd);
++	if (mutt_system (cmd) != 0) {
++		mutt_any_key_to_continue (NULL);
++		mutt_error (_("%s: Error compressing mailbox! Original mailbox deleted, uncompressed one kept!\n"), ctx->path);
++		rc = -1;
++	}
 +
-+Activities other than copying, distribution and modification are not
-+covered by this License; they are outside its scope.  The act of
-+running the Program is not restricted, and the output from the Program
-+is covered only if its contents constitute a work based on the
-+Program (independent of having been made by running the Program).
-+Whether that is true depends on what the Program does.
++	unlock_mailbox (ctx, fp);
++	mutt_unblock_signals();
++	fclose (fp);
 +
-+**1.** You may copy and distribute verbatim copies of the Program's
-+source code as you receive it, in any medium, provided that you
-+conspicuously and appropriately publish on each copy an appropriate
-+copyright notice and disclaimer of warranty; keep intact all the
-+notices that refer to this License and to the absence of any warranty;
-+and give any other recipients of the Program a copy of this License
-+along with the Program.
++	FREE(&cmd);
 +
-+You may charge a fee for the physical act of transferring a copy, and
-+you may at your option offer warranty protection in exchange for a fee.
++	store_size (ctx);
 +
-+**2.** You may modify your copy or copies of the Program or any portion
-+of it, thus forming a work based on the Program, and copy and
-+distribute such modifications or work under the terms of Section 1
-+above, provided that you also meet all of these conditions:
++	return rc;
++}
 +
-+* **a)** You must cause the modified files to carry prominent notices
-+stating that you changed the files and the date of any change.
-+* **b)** You must cause any work that you distribute or publish, that in
-+whole or in part contains or is derived from the Program or any
-+part thereof, to be licensed as a whole at no charge to all third
-+parties under the terms of this License.
-+* **c)** If the modified program normally reads commands interactively
-+when run, you must cause it, when started running for such
-+interactive use in the most ordinary way, to print or display an
-+announcement including an appropriate copyright notice and a
-+notice that there is no warranty (or else, saying that you provide
-+a warranty) and that users may redistribute the program under
-+these conditions, and telling the user how to view a copy of this
-+License.  (Exception: if the Program itself is interactive but
-+does not normally print such an announcement, your work based on
-+the Program is not required to print an announcement.)
++/**
++ * comp_fast_close - XXX
++ * @ctx: Mailbox to close
++ *
++ * close a compressed mailbox
++ */
++void
++comp_fast_close (CONTEXT *ctx)
++{
++	if (!ctx)
++		return;
 +
-+These requirements apply to the modified work as a whole.  If
-+identifiable sections of that work are not derived from the Program,
-+and can be reasonably considered independent and separate works in
-+themselves, then this License, and its terms, do not apply to those
-+sections when you distribute them as separate works.  But when you
-+distribute the same sections as part of a whole which is a work based
-+on the Program, the distribution of the whole must be on the terms of
-+this License, whose permissions for other licensees extend to the
-+entire whole, and thus to each and every part regardless of who wrote it.
-+
-+Thus, it is not the intent of this section to claim rights or contest
-+your rights to work written entirely by you; rather, the intent is to
-+exercise the right to control the distribution of derivative or
-+collective works based on the Program.
-+
-+In addition, mere aggregation of another work not based on the Program
-+with the Program (or with a work based on the Program) on a volume of
-+a storage or distribution medium does not bring the other work under
-+the scope of this License.
++	dprint (2, (debugfile, "comp_fast_close called on '%s'\n",
++		ctx->path));
 +
-+**3.** You may copy and distribute the Program (or a work based on it,
-+under Section 2) in object code or executable form under the terms of
-+Sections 1 and 2 above provided that you also do one of the following:
++	if (ctx->compress_info) {
++		if (ctx->fp) {
++			fclose (ctx->fp);
++		}
++		ctx->fp = NULL;
++		/* if the folder was removed, remove the gzipped folder too */
++		if ((ctx->magic > 0)
++				&& (access (ctx->path, F_OK) != 0)
++				&& ! option (OPTSAVEEMPTY))
++			remove (ctx->realpath);
++		else
++			remove_file (ctx);
 +
-+* **a)** Accompany it with the complete corresponding machine-readable
-+source code, which must be distributed under the terms of Sections
-+1 and 2 above on a medium customarily used for software interchange; or,
-+* **b)** Accompany it with a written offer, valid for at least three
-+years, to give any third party, for a charge no more than your
-+cost of physically performing source distribution, a complete
-+machine-readable copy of the corresponding source code, to be
-+distributed under the terms of Sections 1 and 2 above on a medium
-+customarily used for software interchange; or,
-+* **c)** Accompany it with the information you received as to the offer
-+to distribute corresponding source code.  (This alternative is
-+allowed only for noncommercial distribution and only if you
-+received the program in object code or executable form with such
-+an offer, in accord with Subsection b above.)
++		restore_path (ctx);
++		FREE(&ctx->compress_info);
++	}
++}
 +
-+The source code for a work means the preferred form of the work for
-+making modifications to it.  For an executable work, complete source
-+code means all the source code for all modules it contains, plus any
-+associated interface definition files, plus the scripts used to
-+control compilation and installation of the executable.  However, as a
-+special exception, the source code distributed need not include
-+anything that is normally distributed (in either source or binary
-+form) with the major components (compiler, kernel, and so on) of the
-+operating system on which the executable runs, unless that component
-+itself accompanies the executable.
-+
-+If distribution of executable or object code is made by offering
-+access to copy from a designated place, then offering equivalent
-+access to copy the source code from the same place counts as
-+distribution of the source code, even though third parties are not
-+compelled to copy the source along with the object code.
++/**
++ * comp_slow_close - XXX
++ * @ctx: Mailbox to close (slowly)
++ *
++ * Returns:
++ *	 0: Success
++ *	-1: Failure
++ */
++int
++comp_slow_close (CONTEXT *ctx)
++{
++	if (!ctx)
++		return -1;
 +
-+**4.** You may not copy, modify, sublicense, or distribute the Program
-+except as expressly provided under this License.  Any attempt
-+otherwise to copy, modify, sublicense or distribute the Program is
-+void, and will automatically terminate your rights under this License.
-+However, parties who have received copies, or rights, from you under
-+this License will not have their licenses terminated so long as such
-+parties remain in full compliance.
++	FILE *fp;
++	const char *append;
++	char *cmd;
++	COMPRESS_INFO *ci = (COMPRESS_INFO *) ctx->compress_info;
 +
-+**5.** You are not required to accept this License, since you have not
-+signed it.  However, nothing else grants you permission to modify or
-+distribute the Program or its derivative works.  These actions are
-+prohibited by law if you do not accept this License.  Therefore, by
-+modifying or distributing the Program (or any work based on the
-+Program), you indicate your acceptance of this License to do so, and
-+all its terms and conditions for copying, distributing or modifying
-+the Program or works based on it.
++	dprint (2, (debugfile, "comp_slow_close called on '%s'\n", ctx->path));
 +
-+**6.** Each time you redistribute the Program (or any work based on the
-+Program), the recipient automatically receives a license from the
-+original licensor to copy, distribute or modify the Program subject to
-+these terms and conditions.  You may not impose any further
-+restrictions on the recipients' exercise of the rights granted herein.
-+You are not responsible for enforcing compliance by third parties to
-+this License.
++	if (!(ctx->append
++		&& ((append = get_append_command (ctx, ctx->realpath))
++		|| (append = ci->close)))) {
++		/* if we can not or should not append, we only have to remove the
++		 * compressed info, because sync was already called */
++		comp_fast_close (ctx);
++		return 0;
++	}
 +
-+**7.** If, as a consequence of a court judgment or allegation of patent
-+infringement or for any other reason (not limited to patent issues),
-+conditions are imposed on you (whether by court order, agreement or
-+otherwise) that contradict the conditions of this License, they do not
-+excuse you from the conditions of this License.  If you cannot
-+distribute so as to satisfy simultaneously your obligations under this
-+License and any other pertinent obligations, then as a consequence you
-+may not distribute the Program at all.  For example, if a patent
-+license would not permit royalty-free redistribution of the Program by
-+all those who receive copies directly or indirectly through you, then
-+the only way you could satisfy both it and this License would be to
-+refrain entirely from distribution of the Program.
-+
-+If any portion of this section is held invalid or unenforceable under
-+any particular circumstance, the balance of the section is intended to
-+apply and the section as a whole is intended to apply in other
-+circumstances.
-+
-+It is not the purpose of this section to induce you to infringe any
-+patents or other property right claims or to contest validity of any
-+such claims; this section has the sole purpose of protecting the
-+integrity of the free software distribution system, which is
-+implemented by public license practices.  Many people have made
-+generous contributions to the wide range of software distributed
-+through that system in reliance on consistent application of that
-+system; it is up to the author/donor to decide if he or she is willing
-+to distribute software through any other system and a licensee cannot
-+impose that choice.
-+
-+This section is intended to make thoroughly clear what is believed to
-+be a consequence of the rest of this License.
++	if (ctx->fp) {
++		fclose (ctx->fp);
++		ctx->fp = NULL;
++	}
 +
-+**8.** If the distribution and/or use of the Program is restricted in
-+certain countries either by patents or by copyrighted interfaces, the
-+original copyright holder who places the Program under this License
-+may add an explicit geographical distribution limitation excluding
-+those countries, so that distribution is permitted only in or among
-+countries not thus excluded.  In such case, this License incorporates
-+the limitation as if written in the body of this License.
++	if (!ctx->quiet) {
++		if (append == ci->close) {
++			mutt_message (_("Compressing %s..."), ctx->realpath);
++		} else {
++			mutt_message (_("Compressed-appending to %s..."), ctx->realpath);
++		}
++	}
 +
-+**9.** The Free Software Foundation may publish revised and/or new versions
-+of the General Public License from time to time.  Such new versions will
-+be similar in spirit to the present version, but may differ in detail to
-+address new problems or concerns.
++	cmd = get_compression_cmd (ctx, append);
++	if (!cmd)
++		return -1;
 +
-+Each version is given a distinguishing version number.  If the Program
-+specifies a version number of this License which applies to it and “any
-+later version”, you have the option of following the terms and conditions
-+either of that version or of any later version published by the Free
-+Software Foundation.  If the Program does not specify a version number of
-+this License, you may choose any version ever published by the Free Software
-+Foundation.
++	fp = fopen (ctx->realpath, "a");
++	if (!fp) {
++		mutt_perror (ctx->realpath);
++		FREE(&cmd);
++		return -1;
++	}
 +
-+**10.** If you wish to incorporate parts of the Program into other free
-+programs whose distribution conditions are different, write to the author
-+to ask for permission.  For software which is copyrighted by the Free
-+Software Foundation, write to the Free Software Foundation; we sometimes
-+make exceptions for this.  Our decision will be guided by the two goals
-+of preserving the free status of all derivatives of our free software and
-+of promoting the sharing and reuse of software generally.
++	mutt_block_signals();
++	if (lock_mailbox (ctx, fp, 1) == -1) {
++		fclose (fp);
++		mutt_unblock_signals();
++		mutt_error _("Unable to lock mailbox!");
++		FREE(&cmd);
++		return -1;
++	}
 +
-+### NO WARRANTY
++	dprint (2, (debugfile, "CompressCmd: '%s'\n", cmd));
 +
-+**11.** BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
-+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-+PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
-+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
-+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-+REPAIR OR CORRECTION.
++	endwin();
++	fflush (stdout);
 +
-+**12.** IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-+POSSIBILITY OF SUCH DAMAGES.
++	if (append == ci->close) {
++		sprintf(echo_cmd,_("echo Compressing %s..."), ctx->realpath);
++	} else {
++		sprintf(echo_cmd,_("echo Compressed-appending to %s..."), ctx->realpath);
++	}
++	mutt_system(echo_cmd);
 +
-+END OF TERMS AND CONDITIONS
++	if (mutt_system (cmd) != 0) {
++		mutt_any_key_to_continue (NULL);
++		mutt_error (_(" %s: Error compressing mailbox!  Uncompressed one kept!\n"),
++			ctx->path);
++		FREE(&cmd);
++		unlock_mailbox (ctx, fp);
++		mutt_unblock_signals();
++		fclose (fp);
++		return -1;
++	}
 +
-+### How to Apply These Terms to Your New Programs
++	unlock_mailbox (ctx, fp);
++	mutt_unblock_signals();
++	fclose (fp);
++	remove_file (ctx);
++	restore_path (ctx);
++	FREE(&cmd);
++	FREE(&ctx->compress_info);
 +
-+If you develop a new program, and you want it to be of the greatest
-+possible use to the public, the best way to achieve this is to make it
-+free software which everyone can redistribute and change under these terms.
++	return 0;
++}
 +
-+To do so, attach the following notices to the program.  It is safest
-+to attach them to the start of each source file to most effectively
-+convey the exclusion of warranty; and each file should have at least
-+the “copyright” line and a pointer to where the full notice is found.
+diff --git a/compress.h b/compress.h
+new file mode 100644
+index 0000000..adf6a3e
+--- /dev/null
++++ b/compress.h
+@@ -0,0 +1,32 @@
++/* Copyright (C) 1997 Alain Penders <Alain at Finale-Dev.com>
++ * Copyright (C) 2016 Richard Russon <rich at flatcap.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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ */
 +
-+    <one line to give the program's name and a brief idea of what it does.>
-+    Copyright (C) <year>  <name of author>
-+    
-+    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.,
-+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++#ifndef _COMPRESS_H_
++#define _COMPRESS_H_
 +
-+Also add information on how to contact you by electronic and paper mail.
++int  comp_can_append    (const char *path);
++int  comp_can_read      (const char *path);
++int  comp_check_mailbox (CONTEXT *ctx);
++void comp_fast_close    (CONTEXT *ctx);
++int  comp_open_append   (CONTEXT *ctx);
++int  comp_open_read     (CONTEXT *ctx);
++int  comp_slow_close    (CONTEXT *ctx);
++int  comp_sync          (CONTEXT *ctx);
++int  comp_valid_command (const char *cmd);
 +
-+If the program is interactive, make it output a short notice like this
-+when it starts in an interactive mode:
++#endif /* _COMPRESS_H_ */
+diff --git a/configure.ac b/configure.ac
+index 6096dbb..c839b29 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -175,6 +175,47 @@ if test x$have_smime != xno ; then
+ 	SMIMEAUX_TARGET="smime_keys"
+ fi
+ 
++AC_ARG_ENABLE(sidebar, AC_HELP_STRING([--enable-sidebar], [Enable Sidebar support]),
++[       if test x$enableval = xyes ; then
++		AC_DEFINE(USE_SIDEBAR, 1, [Define if you want support for the sidebar.])
++		OPS="$OPS \$(srcdir)/OPS.SIDEBAR"
++                MUTT_LIB_OBJECTS="$MUTT_LIB_OBJECTS sidebar.o"
++        fi
++])
 +
-+    Gnomovision version 69, Copyright (C) year name of author
-+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
-+    This is free software, and you are welcome to redistribute it
-+    under certain conditions; type `show c' for details.
++AC_ARG_ENABLE(notmuch, AC_HELP_STRING([--enable-notmuch], [Enable NOTMUCH support]),
++[       if test x$enableval = xyes ; then
++		AC_CHECK_LIB(notmuch, notmuch_database_open,,
++			AC_MSG_ERROR([Unable to find Notmuch library]))
++		AC_DEFINE(USE_NOTMUCH,1,[ Define if you want support for the notmuch. ])
++		NOTMUCH_LIBS="-lnotmuch"
++		OPS="$OPS \$(srcdir)/OPS.NOTMUCH"
++		need_notmuch="yes"
 +
-+The hypothetical commands `show w` and `show c` should show the appropriate
-+parts of the General Public License.  Of course, the commands you use may
-+be called something other than `show w` and `show c`; they could even be
-+mouse-clicks or menu items--whatever suits your program.
++		AC_MSG_CHECKING([for notmuch api version 3])
++		AC_COMPILE_IFELSE( [AC_LANG_PROGRAM(
++					[[#include <notmuch.h>]],
++					[[notmuch_database_open("/path", NOTMUCH_DATABASE_MODE_READ_ONLY, (notmuch_database_t**)NULL);]]
++					)],
++		[notmuch_api_3=yes
++			AC_DEFINE([NOTMUCH_API_3], 1, [Define to 1 if you have the notmuch api version 3.])
++			],
++		[notmuch_api_3=no]
++		)
++		AC_MSG_RESULT([$notmuch_api_3])
++        fi
++])
++AM_CONDITIONAL(BUILD_NOTMUCH, test x$need_notmuch = xyes)
 +
-+You should also get your employer (if you work as a programmer) or your
-+school, if any, to sign a “copyright disclaimer” for the program, if
-+necessary.  Here is a sample; alter the names:
 +
-+    Yoyodyne, Inc., hereby disclaims all copyright interest in the program
-+    `Gnomovision' (which makes passes at compilers) written by James Hacker.
-+    
-+    <signature of Ty Coon>, 1 April 1989
-+    Ty Coon, President of Vice
++AC_ARG_ENABLE(compressed, AC_HELP_STRING([--enable-compressed], [Enable compressed folders support]),
++[       if test x$enableval = xyes ; then
++                AC_DEFINE(USE_COMPRESSED, 1, [Define to enable compressed folders support.])
++                MUTT_LIB_OBJECTS="$MUTT_LIB_OBJECTS compress.o"
++        fi
++])
++AM_CONDITIONAL(BUILD_COMPRESS, test x$need_compress = xyes)
 +
-+This General Public License does not permit incorporating your program into
-+proprietary programs.  If your program is a subroutine library, you may
-+consider it more useful to permit linking proprietary applications with the
-+library.  If this is what you want to do, use the GNU Lesser General
-+Public License instead of this License.
-diff -urN mutt-1.6.1/mailbox.h mutt-1.6.1-neomutt/mailbox.h
---- mutt-1.6.1/mailbox.h	2016-06-12 18:43:00.408447684 +0100
-+++ mutt-1.6.1-neomutt/mailbox.h	2016-06-12 18:43:00.714452456 +0100
-@@ -27,6 +27,9 @@
- #define M_NEWFOLDER	(1<<4) /* create a new folder - same as M_APPEND, but uses
- 				* safe_fopen() for mbox-style folders.
- 				*/
-+#ifdef USE_SIDEBAR
-+#define M_PEEK		(1<<5) /* revert atime back after taking a look (if applicable) */
-+#endif
+ AC_ARG_WITH(mixmaster, AS_HELP_STRING([--with-mixmaster@<:@=PATH@:>@],[Include Mixmaster support]),
+   [if test "$withval" != no
+    then
+@@ -281,7 +322,9 @@ main ()
+ 	done
+         AC_CHECK_LIB($cf_ncurses, initscr,
+                 [MUTTLIBS="$MUTTLIBS -l$cf_ncurses"
+-		
++
++                AC_CHECK_LIB(tinfo, tgetent, [MUTTLIBS="$MUTTLIBS -ltinfo"])
++
+                 if test "$cf_ncurses" = ncursesw; then
+ 			AC_CHECK_HEADERS(ncursesw/ncurses.h,[cf_cv_ncurses_header="ncursesw/ncurses.h"])
+ 		else
+@@ -309,10 +352,11 @@ main ()
+ AC_HEADER_STDC
  
- /* mx_open_new_message() */
- #define M_ADD_FROM	(1<<0)	/* add a From_ line */
-@@ -45,6 +48,7 @@
- {
-   FILE *fp;	/* pointer to the message data */
-   char *path;	/* path to temp file */
-+  char *commited_path; /* the final path generated by mx_commit_message() */
-   short magic;	/* type of mailbox this message belongs to */
-   short write;	/* nonzero if message is open for writing */
-   struct {
-@@ -76,6 +80,9 @@
- #ifdef USE_POP
- int mx_is_pop (const char *);
- #endif
-+#ifdef USE_NNTP
-+int mx_is_nntp (const char *);
-+#endif
+ AC_CHECK_HEADERS(stdarg.h sys/ioctl.h ioctl.h sysexits.h)
+-AC_CHECK_HEADERS(sys/time.h sys/resource.h)
++AC_CHECK_HEADERS(sys/time.h sys/resource.h sys/syscall.h)
+ AC_CHECK_HEADERS(unix.h)
  
- int mx_access (const char*, int);
- int mx_check_empty (const char *);
-diff -urN mutt-1.6.1/main.c mutt-1.6.1-neomutt/main.c
---- mutt-1.6.1/main.c	2016-06-12 18:43:00.409447699 +0100
-+++ mutt-1.6.1-neomutt/main.c	2016-06-12 18:43:00.714452456 +0100
-@@ -31,6 +31,10 @@
- #include "url.h"
- #include "mutt_crypt.h"
- #include "mutt_idna.h"
-+#ifdef USE_SIDEBAR
-+#include "sidebar.h"
-+#endif
-+#include "version.h"
+ AC_CHECK_FUNCS(setrlimit getsid)
++AC_CHECK_FUNCS(fgets_unlocked fgetc_unlocked)
  
- #ifdef USE_SASL
- #include "mutt_sasl.h"
-@@ -62,45 +66,9 @@
- #include <idn/stringprep.h>
- #endif
+ AC_MSG_CHECKING(for sig_atomic_t in signal.h)
+ AC_EGREP_HEADER(sig_atomic_t,signal.h,
+@@ -354,7 +398,7 @@ AC_CHECK_TYPE(ssize_t, int)
  
--static const char *ReachingUs = N_("\
--To contact the developers, please mail to <mutt-dev at mutt.org>.\n\
--To report a bug, please visit http://bugs.mutt.org/.\n");
--
--static const char *Notice = N_("\
--Copyright (C) 1996-2016 Michael R. Elkins and others.\n\
--Mutt comes with ABSOLUTELY NO WARRANTY; for details type `mutt -vv'.\n\
--Mutt is free software, and you are welcome to redistribute it\n\
--under certain conditions; type `mutt -vv' for details.\n");
--
--static const char *Copyright = N_("\
--Copyright (C) 1996-2014 Michael R. Elkins <me at mutt.org>\n\
--Copyright (C) 1996-2002 Brandon Long <blong at fiction.net>\n\
--Copyright (C) 1997-2009 Thomas Roessler <roessler at does-not-exist.org>\n\
--Copyright (C) 1998-2005 Werner Koch <wk at isil.d.shuttle.de>\n\
--Copyright (C) 1999-2014 Brendan Cully <brendan at kublai.com>\n\
--Copyright (C) 1999-2002 Tommi Komulainen <Tommi.Komulainen at iki.fi>\n\
--Copyright (C) 2000-2004 Edmund Grimley Evans <edmundo at rano.org>\n\
--Copyright (C) 2006-2009 Rocco Rutte <pdmef at gmx.net>\n\
--Copyright (C) 2014-2015 Kevin J. McCarthy <kevin at 8t8.us>\n\
--\n\
--Many others not mentioned here contributed code, fixes,\n\
--and suggestions.\n");
--
--static const char *Licence = N_("\
--    This program is free software; you can redistribute it and/or modify\n\
--    it under the terms of the GNU General Public License as published by\n\
--    the Free Software Foundation; either version 2 of the License, or\n\
--    (at your option) any later version.\n\
--\n\
--    This program is distributed in the hope that it will be useful,\n\
--    but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
--    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n\
--    GNU General Public License for more details.\n");
--static const char *Obtaining = N_("\
--    You should have received a copy of the GNU General Public License\n\
--    along with this program; if not, write to the Free Software\n\
--    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\n\
--");
-+#ifdef USE_NNTP
-+#include "nntp.h"
-+#endif
+ AC_CHECK_FUNCS(fgetpos memmove setegid srand48 strerror)
+ 
+-AC_REPLACE_FUNCS([setenv strcasecmp strdup strsep strtok_r wcscasecmp])
++AC_REPLACE_FUNCS([setenv strcasecmp strdup strndup strnlen strsep strtok_r wcscasecmp])
+ AC_REPLACE_FUNCS([strcasestr mkdtemp])
+ 
+ AC_CHECK_FUNC(getopt)
+@@ -600,6 +644,15 @@ AC_ARG_ENABLE(imap, AS_HELP_STRING([--enable-imap],[Enable IMAP support]),
+ ])
+ AM_CONDITIONAL(BUILD_IMAP, test x$need_imap = xyes)
+ 
++AC_ARG_ENABLE(nntp, AC_HELP_STRING([--enable-nntp],[Enable NNTP support]),
++[	if test x$enableval = xyes ; then
++		AC_DEFINE(USE_NNTP,1,[ Define if you want support for the NNTP protocol. ])
++		MUTT_LIB_OBJECTS="$MUTT_LIB_OBJECTS nntp.o newsrc.o"
++		need_nntp="yes"
++		need_socket="yes"
++	fi
++])
++
+ AC_ARG_ENABLE(smtp, AS_HELP_STRING([--enable-smtp],[include internal SMTP relay support]),
+ 	[if test $enableval = yes; then
+ 		AC_DEFINE(USE_SMTP, 1, [Include internal SMTP relay support])
+@@ -607,7 +660,7 @@ AC_ARG_ENABLE(smtp, AS_HELP_STRING([--enable-smtp],[include internal SMTP relay
+ 		need_socket="yes"
+ 	fi])
+ 
+-if test x"$need_imap" = xyes -o x"$need_pop" = xyes ; then
++if test x"$need_imap" = xyes -o x"$need_pop" = xyes -o x"$need_nntp" = xyes ; then
+   MUTT_LIB_OBJECTS="$MUTT_LIB_OBJECTS bcache.o"
+ fi
  
- void mutt_exit (int code)
- {
-@@ -138,6 +106,8 @@
-   -e <command>\tspecify a command to be executed after initialization\n\
-   -f <file>\tspecify which mailbox to read\n\
-   -F <file>\tspecify an alternate muttrc file\n\
-+  -g <server>\tspecify a news server (if compiled with NNTP)\n\
-+  -G\t\tselect a newsgroup (if compiled with NNTP)\n\
-   -H <file>\tspecify a draft file to read header and body from\n\
-   -i <file>\tspecify a file which Mutt should include in the body\n\
-   -m <type>\tspecify a default mailbox type\n\
-@@ -158,359 +128,6 @@
-   exit (0);
- }
+@@ -855,6 +908,7 @@ AC_ARG_WITH(tokyocabinet, AS_HELP_STRING([--without-tokyocabinet],[Don't use tok
+ AC_ARG_WITH(qdbm, AS_HELP_STRING([--without-qdbm],[Don't use qdbm even if it is available]))
+ AC_ARG_WITH(gdbm, AS_HELP_STRING([--without-gdbm],[Don't use gdbm even if it is available]))
+ AC_ARG_WITH(bdb, AS_HELP_STRING([--with-bdb@<:@=DIR@:>@],[Use BerkeleyDB4 if gdbm is not available]))
++AC_ARG_WITH(lmdb, AS_HELP_STRING([--with-lmdb@<:@=DIR@:>@],[Use LMDB if gdbm is not available]))
+ 
+ db_found=no
+ if test x$enable_hcache = xyes
+@@ -899,6 +953,15 @@ then
+         db_requested=bdb
+       fi
+     fi
++    if test -n "$with_lmdb" && test "$with_lmdb" != "no"
++    then
++      if test "$db_requested" != "auto"
++      then
++        AC_MSG_ERROR([more than one header cache engine requested.])
++      else
++        db_requested=lmdb
++      fi
++    fi
+     
+     dnl -- Tokyo Cabinet --
+     if test "$with_tokyocabinet" != "no" \
+@@ -1042,6 +1105,34 @@ then
+         fi
+     fi
+ 
++    dnl -- LMDB --
++    if test x$with_lmdb != xno && test $db_found = no \
++	    && test "$db_requested" = auto -o "$db_requested" = lmdb
++    then
++        if test "$with_lmdb" != "yes"
++        then
++          CPPFLAGS="$CPPFLAGS -I$with_lmdb/include"
++          LDFLAGS="$LDFLAGS -L$with_lmdb/lib"
++        fi
++        saved_LIBS="$LIBS"
++        LIBS="$LIBS -llmdb"
++        AC_CACHE_CHECK(for mdb_env_create, ac_cv_mdbenvcreate,[
++            ac_cv_mdbenvcreate=no
++            AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <lmdb.h>]], [[mdb_env_create(0);]])],[ac_cv_mdbenvcreate=yes],[])
++        ])
++        LIBS="$saved_LIBS"
++        if test "$ac_cv_mdbenvcreate" = yes
++        then
++          AC_DEFINE(HAVE_LMDB, 1, [LMDB Support])
++          MUTTLIBS="$MUTTLIBS -llmdb"
++          db_found=lmdb
++        fi
++        if test "$db_requested" != auto && test "$db_found" != "$db_requested"
++        then
++          AC_MSG_ERROR([LMDB could not be used. Check config.log for details.])
++        fi
++    fi
++
+     if test $db_found = no
+     then
+         AC_MSG_ERROR([You need Tokyo Cabinet, QDBM, GDBM or Berkeley DB4 for hcache])
+@@ -1065,6 +1156,7 @@ AC_SUBST(MUTTLIBS)
+ AC_SUBST(MUTT_LIB_OBJECTS)
+ AC_SUBST(LIBIMAP)
+ AC_SUBST(LIBIMAPDEPS)
++AC_SUBST(NOTMUCH_LIBS)
  
--extern const char cc_version[];
--extern const char cc_cflags[];
--extern const char configure_options[];
--
--static char *
--rstrip_in_place(char *s)
--{
--  char *p;
--
--  p = &s[strlen(s)];
--  if (p == s)
--    return s;
--  p--;
--  while (p >= s && (*p == '\n' || *p == '\r'))
--    *p-- = '\0';
--  return s;
--}
--
--static void show_version (void)
--{
--  struct utsname uts;
--
--  puts (mutt_make_version());
--  puts (_(Notice));
--
--  uname (&uts);
--
--#ifdef _AIX
--  printf ("System: %s %s.%s", uts.sysname, uts.version, uts.release);
--#elif defined (SCO)
--  printf ("System: SCO %s", uts.release);
--#else
--  printf ("System: %s %s", uts.sysname, uts.release);
--#endif
--
--  printf (" (%s)", uts.machine);
--
--#ifdef NCURSES_VERSION
--  printf ("\nncurses: %s (compiled with %s)", curses_version(), NCURSES_VERSION);
--#elif defined(USE_SLANG_CURSES)
--  printf ("\nslang: %d", SLANG_VERSION);
--#endif
--
--#ifdef _LIBICONV_VERSION
--  printf ("\nlibiconv: %d.%d", _LIBICONV_VERSION >> 8,
--	  _LIBICONV_VERSION & 0xff);
--#endif
--
--#ifdef HAVE_LIBIDN
--  printf ("\nlibidn: %s (compiled with %s)", stringprep_check_version (NULL), 
--	  STRINGPREP_VERSION);
--#endif
--
--#ifdef USE_HCACHE
--  printf ("\nhcache backend: %s", mutt_hcache_backend ());
--#endif
--
--  puts ("\n\nCompiler:");
--  rstrip_in_place((char *)cc_version);
--  puts (cc_version);
--
--  rstrip_in_place((char *)configure_options);
--  printf ("\nConfigure options: %s\n", configure_options);
--
--  rstrip_in_place((char *)cc_cflags);
--  printf ("\nCompilation CFLAGS: %s\n", cc_cflags);
--
--  puts (_("\nCompile options:"));
--
--#ifdef DOMAIN
--  printf ("DOMAIN=\"%s\"\n", DOMAIN);
--#else
--  puts ("-DOMAIN");
--#endif
--
--#ifdef DEBUG
--  puts ("+DEBUG");
--#else
--  puts ("-DEBUG");
--#endif
--  
--
--  
--  puts (
--
--#ifdef HOMESPOOL
--	"+HOMESPOOL  "
--#else
--	"-HOMESPOOL  "
--#endif
--
--#ifdef USE_SETGID
--	"+USE_SETGID  "
--#else
--	"-USE_SETGID  "
--#endif
--
--#ifdef USE_DOTLOCK
--	"+USE_DOTLOCK  "
--#else
--	"-USE_DOTLOCK  "
--#endif
--
--#ifdef DL_STANDALONE
--	"+DL_STANDALONE  "
--#else
--	"-DL_STANDALONE  "
--#endif
--
--#ifdef USE_FCNTL
--	"+USE_FCNTL  "
--#else
--	"-USE_FCNTL  "
--#endif
--
--#ifdef USE_FLOCK
--	"+USE_FLOCK   "
--#else
--	"-USE_FLOCK   "
--#endif
--    );
--  puts (
--#ifdef USE_POP
--	"+USE_POP  "
--#else
--	"-USE_POP  "
--#endif
--
--#ifdef USE_IMAP
--        "+USE_IMAP  "
--#else
--        "-USE_IMAP  "
--#endif
--
--#ifdef USE_SMTP
--	"+USE_SMTP  "
--#else
--	"-USE_SMTP  "
--#endif
--	"\n"
--	
--#ifdef USE_SSL_OPENSSL
--	"+USE_SSL_OPENSSL  "
--#else
--	"-USE_SSL_OPENSSL  "
--#endif
--
--#ifdef USE_SSL_GNUTLS
--	"+USE_SSL_GNUTLS  "
--#else
--	"-USE_SSL_GNUTLS  "
--#endif
--
--#ifdef USE_SASL
--	"+USE_SASL  "
--#else
--	"-USE_SASL  "
--#endif
--#ifdef USE_GSS
--	"+USE_GSS  "
--#else
--	"-USE_GSS  "
--#endif
--
--#if HAVE_GETADDRINFO
--	"+HAVE_GETADDRINFO  "
--#else
--	"-HAVE_GETADDRINFO  "
--#endif
--        );
--  	
--  puts (
--#ifdef HAVE_REGCOMP
--	"+HAVE_REGCOMP  "
--#else
--	"-HAVE_REGCOMP  "
--#endif
--
--#ifdef USE_GNU_REGEX
--	"+USE_GNU_REGEX  "
--#else
--	"-USE_GNU_REGEX  "
--#endif
--
--	"\n"
--	
--#ifdef HAVE_COLOR
--	"+HAVE_COLOR  "
--#else
--	"-HAVE_COLOR  "
--#endif
--	
--#ifdef HAVE_START_COLOR
--	"+HAVE_START_COLOR  "
--#else
--	"-HAVE_START_COLOR  "
--#endif
--	
--#ifdef HAVE_TYPEAHEAD
--	"+HAVE_TYPEAHEAD  "
--#else
--	"-HAVE_TYPEAHEAD  "
--#endif
--	
--#ifdef HAVE_BKGDSET
--	"+HAVE_BKGDSET  "
--#else
--	"-HAVE_BKGDSET  "
--#endif
--
--	"\n"
--	
--#ifdef HAVE_CURS_SET
--	"+HAVE_CURS_SET  "
--#else
--	"-HAVE_CURS_SET  "
--#endif
--	
--#ifdef HAVE_META
--	"+HAVE_META  "
--#else
--	"-HAVE_META  "
--#endif
--	
--#ifdef HAVE_RESIZETERM
--	"+HAVE_RESIZETERM  "
--#else
--	"-HAVE_RESIZETERM  "
--#endif
--        );	
+ dnl -- iconv/gettext --
+ 
+@@ -1076,6 +1168,13 @@ AC_ARG_ENABLE(iconv, AS_HELP_STRING([--disable-iconv],[Disable iconv support]),
+ 
+ MUTT_AM_GNU_GETTEXT
+ 
++AC_ARG_ENABLE(quick_build, AC_HELP_STRING([--enable-quick-build], [Speed up the build (skip non-code)]),
++[       if test x$enableval = xyes && test "$BUILD_INCLUDED_LIBINTL" = "no"; then
++		need_quick_build="yes"
++        fi
++])
++AM_CONDITIONAL(QUICK_BUILD, test x$need_quick_build = xyes)
++
+ if test "$am_cv_func_iconv" != "yes"
+ then
+   AC_MSG_WARN([Configuring without iconv support. See INSTALL for details])
+@@ -1308,6 +1407,8 @@ if test $mutt_cv_langinfo_yesexpr = yes; then
+   AC_DEFINE(HAVE_LANGINFO_YESEXPR,1,[ Define if you have <langinfo.h> and nl_langinfo(YESEXPR). ])
+ fi
+ 
++AC_CHECK_FUNCS(fmemopen open_memstream)
++
+ dnl Documentation tools
+ have_openjade="no"
+ AC_PATH_PROG([OSPCAT], [ospcat], [none])
+diff --git a/contrib/vim-keybindings/README.md b/contrib/vim-keybindings/README.md
+new file mode 100644
+index 0000000..2beeb08
+--- /dev/null
++++ b/contrib/vim-keybindings/README.md
+@@ -0,0 +1,13 @@
++# Vim Keybindings
++
++This Mutt config file sets up some keyboard mappings that make Mutt more
++friendly for Vim users.  For example:
++
++- gg  Move to top of Index
++- G   Move to bottom of Index
++- dd  Delete email from Index
++
++## Credits
++
++- Ivan Tham <pickfire at riseup.net>
++
+diff --git a/contrib/vim-keybindings/vim-keybindings.rc b/contrib/vim-keybindings/vim-keybindings.rc
+new file mode 100644
+index 0000000..cb64889
+--- /dev/null
++++ b/contrib/vim-keybindings/vim-keybindings.rc
+@@ -0,0 +1,35 @@
++#------------------------------------------------------------
++# Vi Key Bindings
++#------------------------------------------------------------
++
++# Moving around
++bind attach,browser,index       gg  first-entry
++bind attach,browser,index       G   last-entry
++bind pager                      gg  top
++bind pager                      G   bottom
++bind pager                      k   previous-line
++bind pager                      j   next-line
++
++# Scrolling
++bind attach,browser,pager,index \CF next-page
++bind attach,browser,pager,index \CB previous-page
++bind attach,browser,pager,index \Cu half-up
++bind attach,browser,pager,index \Cd half-down
++bind browser,pager              \Ce next-line
++bind browser,pager              \Cy previous-line
++bind index                      \Ce next-line
++bind index                      \Cy previous-line
++
++bind pager,index                dd  delete-message
++
++# Mail & Reply
++bind index                      \Cm list-reply # Doesn't work currently
++
++# Threads
++bind browser,pager,index        N   search-opposite
++bind pager,index                dT  delete-thread
++bind pager,index                dt  delete-subthread
++bind pager,index                gt  next-thread
++bind pager,index                gT  previous-thread
++bind index                      za  collapse-thread
++bind index                      zA  collapse-all # Missing :folddisable/foldenable
+diff --git a/copy.c b/copy.c
+index 360c1a4..4167411 100644
+--- a/copy.c
++++ b/copy.c
+@@ -30,6 +30,10 @@
+ #include "mutt_idna.h"
+ #include "mutt_curses.h"
+ 
++#ifdef USE_NOTMUCH
++#include "mutt_notmuch.h"
++#endif
++
+ #include <string.h>
+ #include <stdlib.h>
+ #include <ctype.h>
+@@ -111,6 +115,15 @@ mutt_copy_hdr (FILE *in, FILE *out, LOFF_T off_start, LOFF_T off_end, int flags,
+ 	ignore = 0;
+       }
+ 
++      if (flags & CH_UPDATE_LABEL)
++      {
++	if ((mutt_strncasecmp ("X-Label:", buf, 8) == 0) ||
++	    (mutt_strncasecmp ("X-Keywords:", buf, 11) == 0) ||
++	    (mutt_strncasecmp ("X-Mozilla-Keys:", buf, 15) == 0) ||
++	    (mutt_strncasecmp ("Keywords:", buf, 9) == 0))
++	  continue;
++      }
++
+       if (!ignore && fputs (buf, out) == EOF)
+ 	return (-1);
+     }
+@@ -288,7 +301,8 @@ mutt_copy_hdr (FILE *in, FILE *out, LOFF_T off_start, LOFF_T off_end, int flags,
+       if (flags & (CH_DECODE|CH_PREFIX))
+       {
+ 	if (mutt_write_one_header (out, 0, headers[x], 
+-				   flags & CH_PREFIX ? prefix : 0, mutt_term_width (Wrap), flags) == -1)
++				   flags & CH_PREFIX ? prefix : 0,
++                                   mutt_term_width (Wrap), flags) == -1)
+ 	{
+ 	  error = TRUE;
+ 	  break;
+@@ -334,6 +348,7 @@ mutt_copy_hdr (FILE *in, FILE *out, LOFF_T off_start, LOFF_T off_end, int flags,
+ 	CH_NOQFROM      ignore ">From " line
+ 	CH_UPDATE_IRT	update the In-Reply-To: header
+ 	CH_UPDATE_REFS	update the References: header
++	CH_VIRTUAL      write virtual header lines too
+ 
+    prefix
+    	string to use if CH_PREFIX is set
+@@ -347,7 +362,7 @@ mutt_copy_header (FILE *in, HEADER *h, FILE *out, int flags, const char *prefix)
+   if (h->env)
+     flags |= (h->env->irt_changed ? CH_UPDATE_IRT : 0)
+       | (h->env->refs_changed ? CH_UPDATE_REFS : 0);
 -  
--  puts (
--#ifdef CRYPT_BACKEND_CLASSIC_PGP
--        "+CRYPT_BACKEND_CLASSIC_PGP  "
--#else
--        "-CRYPT_BACKEND_CLASSIC_PGP  "
--#endif
--#ifdef CRYPT_BACKEND_CLASSIC_SMIME
--        "+CRYPT_BACKEND_CLASSIC_SMIME  "
--#else
--        "-CRYPT_BACKEND_CLASSIC_SMIME  "
--#endif
--#ifdef CRYPT_BACKEND_GPGME
--        "+CRYPT_BACKEND_GPGME  "
--#else
--        "-CRYPT_BACKEND_GPGME  "
--#endif
--        );
++
+   if (mutt_copy_hdr (in, out, h->offset, h->content->offset, flags, prefix) == -1)
+     return -1;
+ 
+@@ -413,6 +428,70 @@ mutt_copy_header (FILE *in, HEADER *h, FILE *out, int flags, const char *prefix)
+       fprintf (out, "Lines: %d\n", h->lines);
+   }
+ 
++#ifdef USE_NOTMUCH
++  if ((flags & CH_VIRTUAL) && nm_header_get_tags(h))
++  {
++    fputs ("Tags: ", out);
++    fputs (nm_header_get_tags(h), out);
++    fputc ('\n', out);
++  }
++#endif
++
++  if (flags & CH_UPDATE_LABEL && h->label_changed)
++  {
++    h->label_changed = 0;
++    if (h->env->labels != NULL)
++    {
++      char buf[HUGE_STRING];
++      char *tmp = NULL;
++      int fail = 0;
++
++      if (fail == 0 &&
++          ((h->env->kwtypes & M_X_LABEL) || (h->env->kwtypes == 0)) &&
++          (option(OPTKEYWORDSLEGACY) || option(OPTKEYWORDSSTANDARD) == 0))
++      {
++        mutt_labels(buf, sizeof(buf), h->env, XlabelDelim);
++        tmp = strdup(buf);
++        rfc2047_encode_string(&tmp);
++        fail = fprintf(out, "X-Label: %s\n", tmp) != 10 + strlen(tmp);
++        FREE(&tmp);
++      }
++
++      if (fail == 0 && (h->env->kwtypes & M_X_KEYWORDS) &&
++          (option(OPTKEYWORDSLEGACY) || option(OPTKEYWORDSSTANDARD) == 0))
++      {
++        mutt_labels(buf, sizeof(buf), h->env, " ");
++        tmp = strdup(buf);
++        rfc2047_encode_string(&tmp);
++        fail = fprintf(out, "X-Keywords: %s\n", tmp) != 13 + strlen(tmp);
++        FREE(&tmp);
++      }
++
++      if (fail == 0 && (h->env->kwtypes & M_X_MOZILLA_KEYS) &&
++          (option(OPTKEYWORDSLEGACY) || option(OPTKEYWORDSSTANDARD) == 0))
++      {
++        mutt_labels(buf, sizeof(buf), h->env, " ");
++        tmp = strdup(buf);
++        rfc2047_encode_string(&tmp);
++        fail = fprintf(out, "X-Mozilla-Keys: %s\n", tmp) != 17 + strlen(tmp);
++        FREE(&tmp);
++      }
++
++      if (fail == 0 && ((h->env->kwtypes & M_KEYWORDS) ||
++                        option(OPTKEYWORDSSTANDARD)))
++      {
++        mutt_labels(buf, sizeof(buf), h->env, NULL);
++        tmp = strdup(buf);
++        rfc2047_encode_string(&tmp);
++        fail = fprintf(out, "Keywords: %s\n", tmp) != 11 + strlen(tmp);
++        FREE(&tmp);
++      }
++
++      if (fail)
++        return -1;
++    }
++  }
++
+   if ((flags & CH_NONEWLINE) == 0)
+   {
+     if (flags & CH_PREFIX)
+@@ -493,6 +572,9 @@ _mutt_copy_message (FILE *fpout, FILE *fpin, HEADER *hdr, BODY *body,
+       _mutt_make_string (prefix, sizeof (prefix), NONULL (Prefix), Context, hdr, 0);
+   }
+ 
++  if (hdr->label_changed)
++    chflags |= CH_UPDATE_LABEL;
++
+   if ((flags & M_CM_NOHEADER) == 0)
+   {
+     if (flags & M_CM_PREFIX)
+@@ -682,7 +764,7 @@ mutt_copy_message (FILE *fpout, CONTEXT *src, HEADER *hdr, int flags,
+ {
+   MESSAGE *msg;
+   int r;
 -  
--  puts (
--#ifdef EXACT_ADDRESS
--	"+EXACT_ADDRESS  "
--#else
--	"-EXACT_ADDRESS  "
--#endif
--
--#ifdef SUN_ATTACHMENT
--	"+SUN_ATTACHMENT  "
--#else
--	"-SUN_ATTACHMENT  "
--#endif
--
--	"\n"
--	
--#ifdef ENABLE_NLS
--	"+ENABLE_NLS  "
--#else
--	"-ENABLE_NLS  "
--#endif
--
--#ifdef LOCALES_HACK
--	"+LOCALES_HACK  "
--#else
--	"-LOCALES_HACK  "
--#endif
--	      
--#ifdef HAVE_WC_FUNCS
--	"+HAVE_WC_FUNCS  "
--#else
--	"-HAVE_WC_FUNCS  "
--#endif
--	
--#ifdef HAVE_LANGINFO_CODESET
--	"+HAVE_LANGINFO_CODESET  "
--#else
--	"-HAVE_LANGINFO_CODESET  "
--#endif
--
--	
--#ifdef HAVE_LANGINFO_YESEXPR
-- 	"+HAVE_LANGINFO_YESEXPR  "
--#else
-- 	"-HAVE_LANGINFO_YESEXPR  "
--#endif
--	
--	"\n"
++
+   if ((msg = mx_open_message (src, hdr->msgno)) == NULL)
+     return -1;
+   if ((r = _mutt_copy_message (fpout, msg->fp, hdr, hdr->content, flags, chflags)) == 0 
+@@ -717,7 +799,7 @@ _mutt_append_message (CONTEXT *dest, FILE *fpin, CONTEXT *src, HEADER *hdr,
+   fseeko (fpin, hdr->offset, 0);
+   if (fgets (buf, sizeof (buf), fpin) == NULL)
+     return -1;
+-  
++
+   if ((msg = mx_open_new_message (dest, hdr, is_from (buf, NULL, 0, NULL) ? 0 : M_ADD_FROM)) == NULL)
+     return -1;
+   if (dest->magic == M_MBOX || dest->magic == M_MMDF)
+@@ -727,6 +809,11 @@ _mutt_append_message (CONTEXT *dest, FILE *fpin, CONTEXT *src, HEADER *hdr,
+   if (mx_commit_message (msg, dest) != 0)
+     r = -1;
+ 
++#ifdef USE_NOTMUCH
++  if (hdr && msg->commited_path && dest->magic == M_MAILDIR && src->magic == M_NOTMUCH)
++	  nm_update_filename(src, NULL, msg->commited_path, hdr);
++#endif
++
+   mx_close_message (&msg);
+   return r;
+ }
+diff --git a/copy.h b/copy.h
+index 5f12a3c..4dcec52 100644
+--- a/copy.h
++++ b/copy.h
+@@ -53,6 +53,8 @@
+ #define CH_UPDATE_IRT     (1<<16) /* update In-Reply-To: */
+ #define CH_UPDATE_REFS    (1<<17) /* update References: */
+ #define CH_DISPLAY        (1<<18) /* display result to user */
++#define CH_VIRTUAL	  (1<<19) /* write virtual header lines too */
++#define CH_UPDATE_LABEL   (1<<20) /* update X-Label: from hdr->env->x_label? */
+ 
+ 
+ int mutt_copy_hdr (FILE *, FILE *, LOFF_T, LOFF_T, int, const char *);
+diff --git a/crypt-gpgme.c b/crypt-gpgme.c
+index 479b58a..d7bf305 100644
+--- a/crypt-gpgme.c
++++ b/crypt-gpgme.c
+@@ -2744,6 +2744,7 @@ int smime_gpgme_application_handler (BODY *a, STATE *s)
+ static const char *crypt_entry_fmt (char *dest,
+                                     size_t destlen,
+ 				    size_t col,
++                                    int cols,
+                                     char op,
+                                     const char *src,
+                                     const char *prefix,
+@@ -2941,9 +2942,9 @@ static const char *crypt_entry_fmt (char *dest,
+   }
+ 
+   if (optional)
+-    mutt_FormatString (dest, destlen, col, ifstring, mutt_attach_fmt, data, 0);
++    mutt_FormatString (dest, destlen, col, cols, ifstring, mutt_attach_fmt, data, 0);
+   else if (flags & M_FORMAT_OPTIONAL)
+-    mutt_FormatString (dest, destlen, col, elsestring, mutt_attach_fmt, data, 0);
++    mutt_FormatString (dest, destlen, col, cols, elsestring, mutt_attach_fmt, data, 0);
+   return (src);
+ }
+       
+@@ -2956,7 +2957,7 @@ static void crypt_entry (char *s, size_t l, MUTTMENU * menu, int num)
+   entry.key = key_table[num];
+   entry.num = num + 1;
+ 
+-  mutt_FormatString (s, l, 0, NONULL (PgpEntryFormat), crypt_entry_fmt, 
++  mutt_FormatString (s, l, 0, COLS - SidebarWidth, NONULL (PgpEntryFormat), crypt_entry_fmt, 
+ 		     (unsigned long) &entry, M_FORMAT_ARROWCURSOR);
+ }
+ 
+diff --git a/crypt.c b/crypt.c
+index 570cc36..f6fae83 100644
+--- a/crypt.c
++++ b/crypt.c
+@@ -231,8 +231,21 @@ int mutt_protect (HEADER *msg, char *keylist)
+     if ((WithCrypto & APPLICATION_SMIME)
+         && (msg->security & APPLICATION_SMIME))
+     {
+-      if (!(tmp_pbody = crypt_smime_build_smime_entity (tmp_smime_pbody,
+-                                                        keylist)))
++			  char *new_keylist = keylist;
++ 
++			  if (SmimeDefaultKey && query_quadoption(OPT_SMIMEENCRYPTSELF, _("Encrypt message to S/MIME Default Key also?")) == M_YES)
++				  {
++					  /* +1 for NULL, +1 for \n */
++					  int size = mutt_strlen(keylist) + mutt_strlen(SmimeDefaultKey) + 2;
++					  new_keylist = safe_malloc(size);
++					  snprintf(new_keylist, size, "%s%s\n", keylist, SmimeDefaultKey);
++				  }
++ 		 
++			  tmp_pbody = crypt_smime_build_smime_entity (tmp_smime_pbody, new_keylist);
++			  if (new_keylist != keylist)
++				  safe_free((void **)&new_keylist);
++			  
++			  if (!tmp_pbody)
+       {
+ 	/* signed ? free it! */
+ 	return (-1);
+diff --git a/curs_lib.c b/curs_lib.c
+index 3178f22..2145946 100644
+--- a/curs_lib.c
++++ b/curs_lib.c
+@@ -44,6 +44,10 @@
+ #include <langinfo.h>
+ #endif
+ 
++#ifdef USE_NOTMUCH
++#include "mutt_notmuch.h"
++#endif
++
+ /* not possible to unget more than one char under some curses libs, and it
+  * is impossible to unget function keys in SLang, so roll our own input
+  * buffering routines.
+@@ -411,6 +415,53 @@ void mutt_progress_init (progress_t* progress, const char *msg,
+   mutt_progress_update (progress, 0, 0);
+ }
+ 
++/**
++ * message_bar - XXX
++ */
++static void
++message_bar (int percent, const char *fmt, ...)
++{
++	va_list ap;
++	char buf[STRING], buf2[STRING];
++	int w = percent * COLS / 100;
++	size_t l;
++
++	va_start (ap, fmt);
++	vsnprintf (buf, sizeof (buf), fmt, ap);
++	l = mutt_strwidth (buf);
++	va_end (ap);
++
++	mutt_format_string (buf2, sizeof (buf2), 0, COLS-2, FMT_LEFT, 0, buf, sizeof (buf), 0);
++
++	move (LINES - 1, 0);
++
++	if (l < w) {
++		SETCOLOR(MT_COLOR_PROGRESS);
++		addstr (buf2);
++		w -= l;
++		while (w--) {
++			addch (' ');
++		}
++		SETCOLOR(MT_COLOR_NORMAL);
++		clrtoeol();
++		mutt_refresh();
++	} else {
++		size_t bw;
++		char ch;
++		int off = mutt_wstr_trunc (buf2, sizeof (buf2), w, &bw);
++
++		ch = buf2[off];
++		buf2[off] = 0;
++		SETCOLOR(MT_COLOR_PROGRESS);
++		addstr (buf2);
++		buf2[off] = ch;
++		SETCOLOR(MT_COLOR_NORMAL);
++		addstr (&buf2[off]);
++		clrtoeol();
++		mutt_refresh();
++	}
++}
++
+ void mutt_progress_update (progress_t* progress, long pos, int percent)
+ {
+   char posstr[SHORT_STRING];
+@@ -461,16 +512,16 @@ void mutt_progress_update (progress_t* progress, long pos, int percent)
+ 
+     if (progress->size > 0)
+     {
+-      mutt_message ("%s %s/%s (%d%%)", progress->msg, posstr, progress->sizestr,
+-		    percent > 0 ? percent :
+-		   	(int) (100.0 * (double) progress->pos / progress->size));
++      message_bar ((percent > 0) ? percent : (int) (100.0 * (double) progress->pos / progress->size),
++        "%s %s/%s (%d%%)", progress->msg, posstr, progress->sizestr,
++        (percent > 0) ? percent : (int) (100.0 * (double) progress->pos / progress->size));
+     }
+     else
+     {
+       if (percent > 0)
+-	mutt_message ("%s %s (%d%%)", progress->msg, posstr, percent);
++        message_bar (percent, "%s %s (%d%%)", progress->msg, posstr, percent);
+       else
+-	mutt_message ("%s %s", progress->msg, posstr);
++        mutt_message ("%s %s", progress->msg, posstr);
+     }
+   }
+ 
+@@ -577,7 +628,9 @@ int mutt_do_pager (const char *banner,
+   return rc;
+ }
+ 
+-int _mutt_enter_fname (const char *prompt, char *buf, size_t blen, int *redraw, int buffy, int multiple, char ***files, int *numfiles)
++int _mutt_enter_fname (const char *prompt, char *buf, size_t blen,
++		int *redraw, int buffy, int multiple,
++		char ***files, int *numfiles, int flags)
+ {
+   event_t ch;
+ 
+@@ -600,8 +653,10 @@ int _mutt_enter_fname (const char *prompt, char *buf, size_t blen, int *redraw,
+   {
+     mutt_refresh ();
+     buf[0] = 0;
+-    _mutt_select_file (buf, blen, M_SEL_FOLDER | (multiple ? M_SEL_MULTI : 0), 
+-		       files, numfiles);
++    if (!flags)
++      flags = M_SEL_FOLDER | (multiple ? M_SEL_MULTI : 0);
++
++    _mutt_select_file (buf, blen, flags, files, numfiles);
+     *redraw = REDRAW_FULL;
+   }
+   else
+@@ -615,6 +670,10 @@ int _mutt_enter_fname (const char *prompt, char *buf, size_t blen, int *redraw,
+       buf[0] = 0;
+     MAYBE_REDRAW (*redraw);
+     FREE (&pc);
++#ifdef USE_NOTMUCH
++    if ((flags & M_SEL_VFOLDER) && buf[0] && strncmp(buf, "notmuch://", 10) != 0)
++      nm_description_to_path(buf, buf, blen);
++#endif
+   }
+ 
+   return 0;
+@@ -779,6 +838,7 @@ void mutt_format_string (char *dest, size_t destlen,
+   size_t k, k2;
+   char scratch[MB_LEN_MAX];
+   mbstate_t mbstate1, mbstate2;
++  int escaped = 0;
+ 
+   memset(&mbstate1, 0, sizeof (mbstate1));
+   memset(&mbstate2, 0, sizeof (mbstate2));
+@@ -794,8 +854,15 @@ void mutt_format_string (char *dest, size_t destlen,
+       k = (k == (size_t)(-1)) ? 1 : n;
+       wc = replacement_char ();
+     }
+-    if (arboreal && wc < M_TREE_MAX)
++    if (escaped) {
++      escaped = 0;
++      w = 0;
++    } else if (arboreal && wc == M_SPECIAL_INDEX) {
++      escaped = 1;
++      w = 0;
++    } else if (arboreal && wc < M_TREE_MAX) {
+       w = 1; /* hack */
++    }
+     else
+     {
+ #ifdef HAVE_ISWBLANK
+@@ -974,7 +1041,12 @@ size_t mutt_wstr_trunc (const char *src, size_t maxlen, size_t maxwid, size_t *w
+     cw = wcwidth (wc);
+     /* hack because M_TREE symbols aren't turned into characters
+      * until rendered by print_enriched_string (#3364) */
+-    if (cw < 0 && cl == 1 && src[0] && src[0] < M_TREE_MAX)
++    if ((cw < 0) && (src[0] == M_SPECIAL_INDEX))
++    {
++      cl = 2; /* skip the index coloring sequence */
++      cw = 0;
++    }
++    else if (cw < 0 && cl == 1 && src[0] && src[0] < M_TREE_MAX)
+       cw = 1;
+     else if (cw < 0)
+       cw = 0;			/* unprintable wchar */
+@@ -1032,6 +1104,12 @@ int mutt_strwidth (const char *s)
+   memset (&mbstate, 0, sizeof (mbstate));
+   for (w=0; n && (k = mbrtowc (&wc, s, n, &mbstate)); s += k, n -= k)
+   {
++    if (*s == M_SPECIAL_INDEX) {
++      s += 2; /* skip the index coloring sequence */
++      k = 0;
++      continue;
++    }
++
+     if (k == (size_t)(-1) || k == (size_t)(-2))
+     {
+       k = (k == (size_t)(-1)) ? 1 : n;
+diff --git a/curs_main.c b/curs_main.c
+index a76aac9..54c61d9 100644
+--- a/curs_main.c
++++ b/curs_main.c
+@@ -22,12 +22,18 @@
+ 
+ #include "mutt.h"
+ #include "mutt_curses.h"
++#include "mx.h"
+ #include "mutt_menu.h"
+ #include "mailbox.h"
+ #include "mapping.h"
+ #include "sort.h"
++#include "buffy.h"
+ #include "mx.h"
+ 
++#ifdef USE_SIDEBAR
++#include "sidebar.h"
++#endif
++
+ #ifdef USE_POP
+ #include "pop.h"
+ #endif
+@@ -36,8 +42,16 @@
+ #include "imap_private.h"
+ #endif
+ 
++#ifdef USE_NOTMUCH
++#include "mutt_notmuch.h"
++#endif
++
+ #include "mutt_crypt.h"
+ 
++#ifdef USE_NNTP
++#include "nntp.h"
++#endif
++
+ 
+ #include <ctype.h>
+ #include <stdlib.h>
+@@ -118,7 +132,9 @@ short mutt_ts_capability(void)
+ {
+   char *term = getenv("TERM");
+   char *tcaps;
++#ifdef HAVE_USE_EXTENDED_NAMES
+   int tcapi;
++#endif
+   char **termp;
+   char *known[] = {
+     "color-xterm",
+@@ -477,6 +493,208 @@ static void resort_index (MUTTMENU *menu)
+   menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
+ }
+ 
++/**
++ * mutt_draw_statusline - Draw a highlighted status bar
++ * @cols:  Maximum number of screen columns
++ * @buf:   Message to be displayed
++ *
++ * Users configure the highlighting of the status bar, e.g.
++ *     color status red default "[0-9][0-9]:[0-9][0-9]"
++ *
++ * Where regexes overlap, the one nearest the start will be used.
++ * If two regexes start at the same place, the longer match will be used.
++ */
++void
++mutt_draw_statusline (int cols, const char *buf, int buflen)
++{
++	int i      = 0;
++	int offset = 0;
++	int found  = 0;
++	int chunks = 0;
++	int len    = 0;
++
++	struct syntax_t {
++		int color;
++		int first;
++		int last;
++	} *syntax = NULL;
++
++	if (!buf)
++		return;
++
++	do {
++		COLOR_LINE *cl;
++		found = 0;
++
++		if (!buf[offset])
++			break;
++
++		/* loop through each "color status regex" */
++		for (cl = ColorStatusList; cl; cl = cl->next) {
++			regmatch_t pmatch[cl->match + 1];
++
++			if (regexec (&cl->rx, buf + offset, cl->match + 1, pmatch, 0) != 0)
++				continue;	/* regex doesn't match the status bar */
++
++			int first = pmatch[cl->match].rm_so + offset;
++			int last  = pmatch[cl->match].rm_eo + offset;
++
++			if (first == last)
++				continue;	/* ignore an empty regex */
++
++			if (!found) {
++				chunks++;
++				safe_realloc (&syntax, chunks * sizeof (struct syntax_t));
++			}
++
++			i = chunks - 1;
++			if (!found || (first < syntax[i].first) || ((first == syntax[i].first) && (last > syntax[i].last))) {
++				syntax[i].color = cl->pair;
++				syntax[i].first = first;
++				syntax[i].last  = last;
++			}
++			found = 1;
++		}
++
++		if (syntax) {
++			offset = syntax[i].last;
++		}
++	} while (found);
++
++	/* Only 'len' bytes will fit into 'cols' screen columns */
++	len = mutt_wstr_trunc (buf, buflen, cols, NULL);
++
++	offset = 0;
++
++	if ((chunks > 0) && (syntax[0].first > 0)) {
++		/* Text before the first highlight */
++		addnstr (buf, MIN(len, syntax[0].first));
++		attrset (ColorDefs[MT_COLOR_STATUS]);
++		if (len <= syntax[0].first)
++			goto dsl_finish;	/* no more room */
++
++		offset = syntax[0].first;
++	}
++
++	for (i = 0; i < chunks; i++) {
++		/* Highlighted text */
++		attrset (syntax[i].color);
++		addnstr (buf + offset, MIN(len, syntax[i].last) - offset);
++		if (len <= syntax[i].last)
++			goto dsl_finish;	/* no more room */
++
++		int next;
++		if ((i + 1) == chunks) {
++			next = len;
++		} else {
++			next = MIN (len, syntax[i+1].first);
++		}
++
++		attrset (ColorDefs[MT_COLOR_STATUS]);
++		offset = syntax[i].last;
++		addnstr (buf + offset, next - offset);
++
++		offset = next;
++		if (offset >= len)
++			goto dsl_finish;	/* no more room */
++	}
++
++	attrset (ColorDefs[MT_COLOR_STATUS]);
++	if (offset < len) {
++		/* Text after the last highlight */
++		addnstr (buf + offset, len - offset);
++	}
++
++	int width = mutt_strwidth (buf);
++	if (width < cols) {
++		/* Pad the rest of the line with whitespace */
++		mutt_paddstr (cols - width, "");
++	}
++dsl_finish:
++	safe_free (&syntax);
++}
++
++static int main_change_folder(MUTTMENU *menu, int op, char *buf, size_t bufsz,
++			  int *oldcount, int *index_hint, int flags)
++{
++#ifdef USE_NNTP
++  if (option (OPTNEWS))
++  {
++    unset_option (OPTNEWS);
++    nntp_expand_path (buf, bufsz, &CurrentNewsSrv->conn->account);
++  }
++  else
++#endif
++  mutt_expand_path (buf, bufsz);
++  if (mx_get_magic (buf) <= 0)
++  {
++    mutt_error (_("%s is not a mailbox."), buf);
++    return -1;
++  }
++  mutt_str_replace (&CurrentFolder, buf);
++
++  /* keepalive failure in mutt_enter_fname may kill connection. #3028 */
++  if (Context && !Context->path)
++    FREE (&Context);
++
++  if (Context)
++  {
++    int check;
++
++#ifdef USE_COMPRESSED
++	  if (Context->compress_info && Context->realpath)
++	    mutt_str_replace (&LastFolder, Context->realpath);
++	  else
++#endif
++    mutt_str_replace (&LastFolder, Context->path);
++    *oldcount = Context ? Context->msgcount : 0;
++
++    if ((check = mx_close_mailbox (Context, index_hint)) != 0)
++    {
++      if (check == M_NEW_MAIL || check == M_REOPENED)
++        update_index (menu, Context, check, *oldcount, *index_hint);
++
++      set_option (OPTSEARCHINVALID);
++      menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
++      return 0;
++    }
++    FREE (&Context);
++  }
++
++  if (Labels)
++    hash_destroy(&Labels, NULL);
++
++  mutt_sleep (0);
++
++  /* Set CurrentMenu to MENU_MAIN before executing any folder
++   * hooks so that all the index menu functions are available to
++   * the exec command.
++   */
++
++  CurrentMenu = MENU_MAIN;
++  mutt_folder_hook (buf);
++
++  if ((Context = mx_open_mailbox (buf, flags, NULL)) != NULL)
++  {
++    Labels = hash_create(131, 0);
++    mutt_scan_labels(Context);
++    menu->current = ci_first_message ();
++  }
++  else
++    menu->current = 0;
++
++#ifdef USE_SIDEBAR
++        mutt_sb_set_open_buffy ();
++#endif
++
++  mutt_clear_error ();
++  mutt_buffy_check(1); /* force the buffy check after we have changed the folder */
++  menu->redraw = REDRAW_FULL;
++  set_option (OPTSEARCHINVALID);
++
++  return 0;
++}
++
+ static const struct mapping_t IndexHelp[] = {
+   { N_("Quit"),  OP_QUIT },
+   { N_("Del"),   OP_DELETE },
+@@ -489,12 +707,27 @@ static const struct mapping_t IndexHelp[] = {
+   { NULL,	 0 }
+ };
+ 
++#ifdef USE_NNTP
++struct mapping_t IndexNewsHelp[] = {
++  { N_("Quit"),     OP_QUIT },
++  { N_("Del"),      OP_DELETE },
++  { N_("Undel"),    OP_UNDELETE },
++  { N_("Save"),     OP_SAVE },
++  { N_("Post"),     OP_POST },
++  { N_("Followup"), OP_FOLLOWUP },
++  { N_("Catchup"),  OP_CATCHUP },
++  { N_("Help"),     OP_HELP },
++  { NULL,           0 }
++};
++#endif
++
+ /* This function handles the message index window as well as commands returned
+  * from the pager (MENU_PAGER).
+  */
+ int mutt_index_menu (void)
+ {
+   char buf[LONG_STRING], helpstr[LONG_STRING];
++  int flags;
+   int op = OP_NULL;
+   int done = 0;                /* controls when to exit the "event" loop */
+   int i = 0, j;
+@@ -515,7 +748,11 @@ int mutt_index_menu (void)
+   menu->make_entry = index_make_entry;
+   menu->color = index_color;
+   menu->current = ci_first_message ();
+-  menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_MAIN, IndexHelp);
++  menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_MAIN,
++#ifdef USE_NNTP
++	(Context && (Context->magic == M_NNTP)) ? IndexNewsHelp :
++#endif
++	IndexHelp);
+ 
+   if (!attach_msg)
+     mutt_buffy_check(1); /* force the buffy check after we enter the folder */
+@@ -574,6 +811,12 @@ int mutt_index_menu (void)
+ 	  mutt_message _("New mail in this mailbox.");
+ 	  if (option (OPTBEEPNEW))
+ 	    beep ();
++	  if (NewMailCmd)
++	  {
++	    char cmd[LONG_STRING];
++	    menu_status_line(cmd, sizeof(cmd), menu, NONULL(NewMailCmd));
++	    mutt_system(cmd);
++	  }
+ 	} else if (check == M_FLAGS)
+ 	  mutt_message _("Mailbox was externally modified.");
+ 
+@@ -595,8 +838,18 @@ int mutt_index_menu (void)
+        menu->redraw |= REDRAW_STATUS;
+      if (do_buffy_notify)
+      {
+-       if (mutt_buffy_notify () && option (OPTBEEPNEW))
+- 	beep ();
++       if (mutt_buffy_notify())
++       {
++         menu->redraw |= REDRAW_STATUS;
++         if (option (OPTBEEPNEW))
++           beep();
++         if (NewMailCmd)
++         {
++           char cmd[LONG_STRING];
++           menu_status_line(cmd, sizeof(cmd), menu, NONULL(NewMailCmd));
++           mutt_system(cmd);
++         }
++       }
+      }
+      else
+        do_buffy_notify = 1;
+@@ -613,6 +866,13 @@ int mutt_index_menu (void)
+ 
+     if (menu->menu == MENU_MAIN)
+     {
++#ifdef USE_SIDEBAR
++      if (menu->redraw & REDRAW_SIDEBAR || SidebarNeedsRedraw)
++      {
++        mutt_sb_set_buffystats (Context);
++        menu_redraw_sidebar (menu);
++      }
++#endif
+       if (Context && Context->hdrs && !(menu->current >= Context->vcount))
+       {
+ 	menu_check_recenter (menu);
+@@ -630,10 +890,18 @@ int mutt_index_menu (void)
+ 
+       if (menu->redraw & REDRAW_STATUS)
+       {
++#ifdef USE_SIDEBAR
++        /* Temporarily lie about the sidebar width */
++	short sw = SidebarWidth;
++	SidebarWidth = 0;
++#endif
+ 	menu_status_line (buf, sizeof (buf), menu, NONULL (Status));
++#ifdef USE_SIDEBAR
++        SidebarWidth = sw; /* Restore the sidebar width */
++#endif
+ 	move (option (OPTSTATUSONTOP) ? 0 : LINES-2, 0);
+ 	SETCOLOR (MT_COLOR_STATUS);
+-	mutt_paddstr (COLS, buf);
++	mutt_draw_statusline (COLS, buf, sizeof (buf));
+ 	NORMAL_COLOR;
+ 	menu->redraw &= ~REDRAW_STATUS;
+ 	if (option(OPTTSENABLED) && TSSupported)
+@@ -652,7 +920,7 @@ int mutt_index_menu (void)
+ 	menu->oldcurrent = -1;
+ 
+       if (option (OPTARROWCURSOR))
+-	move (menu->current - menu->top + menu->offset, 2);
++	move (menu->current - menu->top + menu->offset, SidebarWidth + 2);
+       else if (option (OPTBRAILLEFRIENDLY))
+ 	move (menu->current - menu->top + menu->offset, 0);
+       else
+@@ -758,6 +1026,14 @@ int mutt_index_menu (void)
+       mutt_curs_set (1);	/* fallback from the pager */
+     }
+ 
++#ifdef USE_NOTMUCH
++    if (Context)
++      nm_debug_check(Context);
++#endif
++
++#ifdef USE_NNTP
++    unset_option (OPTNEWS);	/* for any case */
++#endif
+     switch (op)
+     {
+ 
+@@ -808,6 +1084,161 @@ int mutt_index_menu (void)
+ 	menu_current_bottom (menu);
+ 	break;
+ 
++#ifdef USE_NNTP
++      case OP_GET_PARENT:
++	CHECK_MSGCOUNT;
++	CHECK_VISIBLE;
++
++      case OP_GET_MESSAGE:
++	CHECK_IN_MAILBOX;
++	CHECK_READONLY;
++	CHECK_ATTACH;
++	if (Context->magic == M_NNTP)
++	{
++	  HEADER *hdr;
++
++	  if (op == OP_GET_MESSAGE)
++	  {
++	    buf[0] = 0;
++	    if (mutt_get_field (_("Enter Message-Id: "),
++		buf, sizeof (buf), 0) != 0 || !buf[0])
++	      break;
++	  }
++	  else
++	  {
++	    LIST *ref = CURHDR->env->references;
++	    if (!ref)
++	    {
++	      mutt_error _("Article has no parent reference.");
++	      break;
++	    }
++	    strfcpy (buf, ref->data, sizeof (buf));
++	  }
++	  if (!Context->id_hash)
++	    Context->id_hash = mutt_make_id_hash (Context);
++	  hdr = hash_find (Context->id_hash, buf);
++	  if (hdr)
++	  {
++	    if (hdr->virtual != -1)
++	    {
++	      menu->current = hdr->virtual;
++	      menu->redraw = REDRAW_MOTION_RESYNCH;
++	    }
++	    else if (hdr->collapsed)
++	    {
++	      mutt_uncollapse_thread (Context, hdr);
++	      mutt_set_virtual (Context);
++	      menu->current = hdr->virtual;
++	      menu->redraw = REDRAW_MOTION_RESYNCH;
++	    }
++	    else
++	      mutt_error _("Message is not visible in limited view.");
++	  }
++	  else
++	  {
++	    int rc;
++
++	    mutt_message (_("Fetching %s from server..."), buf);
++	    rc = nntp_check_msgid (Context, buf);
++	    if (rc == 0)
++	    {
++	      hdr = Context->hdrs[Context->msgcount - 1];
++	      mutt_sort_headers (Context, 0);
++	      menu->current = hdr->virtual;
++	      menu->redraw = REDRAW_FULL;
++	    }
++	    else if (rc > 0)
++	      mutt_error (_("Article %s not found on the server."), buf);
++	  }
++	}
++	break;
++
++      case OP_GET_CHILDREN:
++      case OP_RECONSTRUCT_THREAD:
++	CHECK_MSGCOUNT;
++	CHECK_VISIBLE;
++	CHECK_READONLY;
++	CHECK_ATTACH;
++	if (Context->magic == M_NNTP)
++	{
++	  int oldmsgcount = Context->msgcount;
++	  int oldindex = CURHDR->index;
++	  int rc = 0;
++
++	  if (!CURHDR->env->message_id)
++	  {
++	    mutt_error _("No Message-Id. Unable to perform operation.");
++	    break;
++	  }
++
++	  mutt_message _("Fetching message headers...");
++	  if (!Context->id_hash)
++	    Context->id_hash = mutt_make_id_hash (Context);
++	  strfcpy (buf, CURHDR->env->message_id, sizeof (buf));
++
++	  /* trying to find msgid of the root message */
++	  if (op == OP_RECONSTRUCT_THREAD)
++	  {
++	    LIST *ref = CURHDR->env->references;
++	    while (ref)
++	    {
++	      if (hash_find (Context->id_hash, ref->data) == NULL)
++	      {
++		rc = nntp_check_msgid (Context, ref->data);
++		if (rc < 0)
++		  break;
++	      }
++
++	      /* the last msgid in References is the root message */
++	      if (!ref->next)
++		strfcpy (buf, ref->data, sizeof (buf));
++	      ref = ref->next;
++	    }
++	  }
++
++	  /* fetching all child messages */
++	  if (rc >= 0)
++	    rc = nntp_check_children (Context, buf);
++
++	  /* at least one message has been loaded */
++	  if (Context->msgcount > oldmsgcount)
++	  {
++	    HEADER *hdr;
++	    int i, quiet = Context->quiet;
++
++	    if (rc < 0)
++	      Context->quiet = 1;
++	    mutt_sort_headers (Context, (op == OP_RECONSTRUCT_THREAD));
++	    Context->quiet = quiet;
++
++	    /* if the root message was retrieved, move to it */
++	    hdr = hash_find (Context->id_hash, buf);
++	    if (hdr)
++	      menu->current = hdr->virtual;
++
++	    /* try to restore old position */
++	    else
++	    {
++	      for (i = 0; i < Context->msgcount; i++)
++	      {
++		if (Context->hdrs[i]->index == oldindex)
++		{
++		  menu->current = Context->hdrs[i]->virtual;
++		  /* as an added courtesy, recenter the menu
++		   * with the current entry at the middle of the screen */
++		  menu_check_recenter (menu);
++		  menu_current_middle (menu);
++		}
++	      }
++	    }
++	    menu->redraw = REDRAW_FULL;
++	  }
++	  else if (rc >= 0)
++	    mutt_error _("No deleted messages found in the thread.");
++	}
++	break;
++#endif
++
+       case OP_JUMP:
+ 
+ 	CHECK_MSGCOUNT;
+@@ -904,12 +1335,35 @@ int mutt_index_menu (void)
+ 	}
+         break;
+ 
++      case OP_LIMIT_CURRENT_THREAD:
+       case OP_MAIN_LIMIT:
++      case OP_TOGGLE_READ:
+ 
+ 	CHECK_IN_MAILBOX;
+ 	menu->oldcurrent = (Context->vcount && menu->current >= 0 && menu->current < Context->vcount) ?
+ 		CURHDR->index : -1;
+-	if (mutt_pattern_func (M_LIMIT, _("Limit to messages matching: ")) == 0)
++	if (op == OP_TOGGLE_READ)
++	{
++	  char buf[LONG_STRING];
++
++	  if (!Context->pattern || strncmp (Context->pattern, "!~R!~D~s", 8) != 0)
++	  {
++	    snprintf (buf, sizeof (buf), "!~R!~D~s%s",
++		      Context->pattern ? Context->pattern : ".*");
++	    set_option (OPTHIDEREAD);
++	  }
++	  else
++	  {
++	    strfcpy (buf, Context->pattern + 8, sizeof(buf));
++	    if (!*buf || strncmp (buf, ".*", 2) == 0)
++	      snprintf (buf, sizeof(buf), "~A");
++	    unset_option (OPTHIDEREAD);
++	  }
++	  FREE (&Context->pattern);
++	  Context->pattern = safe_strdup (buf);
++	}
++	if (((op == OP_LIMIT_CURRENT_THREAD) && mutt_limit_current_thread(CURHDR))
++	    || ((op == OP_MAIN_LIMIT) && (mutt_pattern_func (M_LIMIT, _("Limit to messages matching: ")) == 0)))
+ 	{
+ 	  if (menu->oldcurrent >= 0)
+ 	  {
+@@ -1150,19 +1604,172 @@ int mutt_index_menu (void)
+ 	  menu->redraw = REDRAW_FULL;
+ 	break;
+ 
+-      case OP_MAIN_CHANGE_FOLDER:
+-      case OP_MAIN_NEXT_UNREAD_MAILBOX:
++      case OP_MAIN_QUASI_DELETE:
++	if (tag) {
++	  for (j = 0; j < Context->vcount; j++) {
++	    if (Context->hdrs[Context->v2r[j]]->tagged) {
++	      Context->hdrs[Context->v2r[j]]->quasi_deleted = TRUE;
++	      Context->changed = TRUE;
++	    }
++	  }
++	} else {
++	  CURHDR->quasi_deleted = TRUE;
++	  Context->changed = 1;
++	}
++	break;
+ 
+-	if (attach_msg)
+-	  op = OP_MAIN_CHANGE_FOLDER_READONLY;
++#ifdef USE_NOTMUCH
++      case OP_MAIN_ENTIRE_THREAD:
++      {
++	int oldcount  = Context->msgcount;
++	if (Context->magic != M_NOTMUCH) {
++	  mutt_message _("No virtual folder, aborting.");
++	  break;
++	}
++	CHECK_MSGCOUNT;
++        CHECK_VISIBLE;
++	if (nm_read_entire_thread(Context, CURHDR) < 0) {
++	   mutt_message _("Failed to read thread, aborting.");
++	   break;
++	}
++	if (oldcount < Context->msgcount) {
++		HEADER *oldcur = CURHDR;
++
++		if ((Sort & SORT_MASK) == SORT_THREADS)
++			mutt_sort_headers (Context, 0);
++		menu->current = oldcur->virtual;
++		menu->redraw = REDRAW_STATUS | REDRAW_INDEX;
+ 
+-	/* fallback to the readonly case */
++		if (oldcur->collapsed || Context->collapsed) {
++			menu->current = mutt_uncollapse_thread(Context, CURHDR);
++			mutt_set_virtual(Context);
++		}
++	}
++	if (menu->menu == MENU_PAGER)
++	{
++	  op = OP_DISPLAY_MESSAGE;
++	  continue;
++	}
++	break;
++      }
++
++      case OP_MAIN_MODIFY_LABELS:
++      case OP_MAIN_MODIFY_LABELS_THEN_HIDE:
++      {
++	if (Context->magic != M_NOTMUCH) {
++	  mutt_message _("No virtual folder, aborting.");
++	  break;
++	}
++	CHECK_MSGCOUNT;
++        CHECK_VISIBLE;
++	*buf = '\0';
++	if (mutt_get_field ("Add/remove labels: ", buf, sizeof (buf), M_NM_TAG) || !*buf)
++	{
++          mutt_message _("No label specified, aborting.");
++          break;
++        }
++	if (tag)
++	{
++	  char msgbuf[STRING];
++	  progress_t progress;
++	  int px;
+ 
++	  if (!Context->quiet) {
++	    snprintf(msgbuf, sizeof (msgbuf), _("Update labels..."));
++	    mutt_progress_init(&progress, msgbuf, M_PROGRESS_MSG,
++				   1, Context->tagged);
++	  }
++	  nm_longrun_init(Context, TRUE);
++	  for (px = 0, j = 0; j < Context->vcount; j++) {
++	    if (Context->hdrs[Context->v2r[j]]->tagged) {
++	      if (!Context->quiet)
++		mutt_progress_update(&progress, ++px, -1);
++	      nm_modify_message_tags(Context, Context->hdrs[Context->v2r[j]], buf);
++	      if (op == OP_MAIN_MODIFY_LABELS_THEN_HIDE)
++	      {
++		Context->hdrs[Context->v2r[j]]->quasi_deleted = TRUE;
++	        Context->changed = TRUE;
++	      }
++	    }
++	  }
++	  nm_longrun_done(Context);
++	  menu->redraw = REDRAW_STATUS | REDRAW_INDEX;
++	}
++	else
++	{
++	  if (nm_modify_message_tags(Context, CURHDR, buf)) {
++	    mutt_message _("Failed to modify labels, aborting.");
++	    break;
++	  }
++	  if (op == OP_MAIN_MODIFY_LABELS_THEN_HIDE)
++	  {
++	    CURHDR->quasi_deleted = TRUE;
++	    Context->changed = TRUE;
++	  }
++	  if (menu->menu == MENU_PAGER)
++	  {
++	    op = OP_DISPLAY_MESSAGE;
++	    continue;
++	  }
++	  if (option (OPTRESOLVE))
++	  {
++	    if ((menu->current = ci_next_undeleted (menu->current)) == -1)
++	    {
++	      menu->current = menu->oldcurrent;
++	      menu->redraw = REDRAW_CURRENT;
++	    }
++	    else
++	      menu->redraw = REDRAW_MOTION_RESYNCH;
++	  }
++	  else
++	    menu->redraw = REDRAW_CURRENT;
++	}
++	menu->redraw |= REDRAW_STATUS;
++	break;
++      }
++
++      case OP_MAIN_VFOLDER_FROM_QUERY:
++	buf[0] = '\0';
++        if (mutt_get_field ("Query: ", buf, sizeof (buf), M_NM_QUERY) != 0 || !buf[0])
++        {
++          mutt_message _("No query, aborting.");
++          break;
++        }
++	if (!nm_uri_from_query(Context, buf, sizeof (buf)))
++	  mutt_message _("Failed to create query, aborting.");
++	else
++	  main_change_folder(menu, op, buf, sizeof (buf), &oldcount, &index_hint, 0);
++	break;
++
++      case OP_MAIN_CHANGE_VFOLDER:
++#endif
++#ifdef USE_SIDEBAR
++      case OP_SIDEBAR_OPEN:
++#endif
++      case OP_MAIN_CHANGE_FOLDER:
++      case OP_MAIN_NEXT_UNREAD_MAILBOX:
+       case OP_MAIN_CHANGE_FOLDER_READONLY:
++#ifdef USE_NNTP
++      case OP_MAIN_CHANGE_GROUP:
++      case OP_MAIN_CHANGE_GROUP_READONLY:
++	unset_option (OPTNEWS);
++#endif
++	if (attach_msg || option (OPTREADONLY) ||
++#ifdef USE_NNTP
++	    op == OP_MAIN_CHANGE_GROUP_READONLY ||
++#endif
++	    op == OP_MAIN_CHANGE_FOLDER_READONLY)
++	  flags = M_READONLY;
++	else
++	  flags = 0;
+ 
+-        if ((op == OP_MAIN_CHANGE_FOLDER_READONLY) || option (OPTREADONLY))
++	if (flags)
+           cp = _("Open mailbox in read-only mode");
+-        else
++#ifdef USE_NOTMUCH
++        else if (op == OP_MAIN_CHANGE_VFOLDER)
++	  cp = _("Open virtual folder");
++#endif
++	else
+           cp = _("Open mailbox");
+ 
+ 	buf[0] = '\0';
+@@ -1177,82 +1784,76 @@ int mutt_index_menu (void)
+ 	    break;
+ 	  }
+ 	}
+-	else
+-	{
+-	  mutt_buffy (buf, sizeof (buf));
 -
--#if HAVE_ICONV
--	"+HAVE_ICONV  "
--#else
--	"-HAVE_ICONV  "
--#endif
+-	  if (mutt_enter_fname (cp, buf, sizeof (buf), &menu->redraw, 1) == -1)
+-	  {
+-	    if (menu->menu == MENU_PAGER)
+-	    {
+-	      op = OP_DISPLAY_MESSAGE;
+-	      continue;
+-	    }
+-	    else
+-	      break;
++#ifdef USE_SIDEBAR
++        else if (op == OP_SIDEBAR_OPEN)
++        {
++          const char *path = mutt_sb_get_highlight();
++          if (!path || !*path)
++            break;
++          strncpy (buf, path, sizeof (buf));
++        }
++#endif
++#ifdef USE_NOTMUCH
++	else if (op == OP_MAIN_CHANGE_VFOLDER) {
++	  if (Context->magic == M_NOTMUCH) {
++		  strfcpy(buf, Context->path, sizeof (buf));
++		  mutt_buffy_vfolder (buf, sizeof (buf));
+ 	  }
++	  mutt_enter_vfolder (cp, buf, sizeof (buf), &menu->redraw, 1);
+ 	  if (!buf[0])
+ 	  {
+ 	    CLEARLINE (LINES-1);
+ 	    break;
+ 	  }
+ 	}
 -
--#if ICONV_NONTRANS
--	"+ICONV_NONTRANS  "
--#else
--	"-ICONV_NONTRANS  "
--#endif
+-	mutt_expand_path (buf, sizeof (buf));
+-	if (mx_get_magic (buf) <= 0)
++#endif
++	else
+ 	{
+-	  mutt_error (_("%s is not a mailbox."), buf);
+-	  break;
+-	}
+-	mutt_str_replace (&CurrentFolder, buf);
 -
--#if HAVE_LIBIDN
--	"+HAVE_LIBIDN  "
--#else
--	"-HAVE_LIBIDN  "
--#endif
--	
--#if HAVE_GETSID
--	"+HAVE_GETSID  "
--#else
--	"-HAVE_GETSID  "
--#endif
+-	/* keepalive failure in mutt_enter_fname may kill connection. #3028 */
+-	if (Context && !Context->path)
+-	  FREE (&Context);
 -
--#if USE_HCACHE
--	"+USE_HCACHE  "
--#else
--	"-USE_HCACHE  "
--#endif
+-        if (Context)
+-        {
+-	  int check;
 -
--	);
+-	  mutt_str_replace (&LastFolder, Context->path);
+-	  oldcount = Context ? Context->msgcount : 0;
 -
--#ifdef ISPELL
--  printf ("ISPELL=\"%s\"\n", ISPELL);
--#else
--  puts ("-ISPELL");
--#endif
+-	  if ((check = mx_close_mailbox (Context, &index_hint)) != 0)
++#ifdef USE_NNTP
++	  if (op == OP_MAIN_CHANGE_GROUP ||
++	      op == OP_MAIN_CHANGE_GROUP_READONLY)
+ 	  {
+-	    if (check == M_NEW_MAIL || check == M_REOPENED)
+-	      update_index (menu, Context, check, oldcount, index_hint);
++	    set_option (OPTNEWS);
++	    CurrentNewsSrv = nntp_select_server (NewsServer, 0);
++	    if (!CurrentNewsSrv)
++	      break;
++	    if (flags)
++	      cp = _("Open newsgroup in read-only mode");
++	    else
++	      cp = _("Open newsgroup");
++	    nntp_buffy (buf, sizeof (buf));
++	  }
++	  else
++#endif
++	  mutt_buffy (buf, sizeof (buf));
+ 
+-	    set_option (OPTSEARCHINVALID);
+-	    menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
++          if (mutt_enter_fname (cp, buf, sizeof (buf), &menu->redraw, 1) == -1)
++          {
++            if (menu->menu == MENU_PAGER)
++            {
++              op = OP_DISPLAY_MESSAGE;
++              continue;
++            }
++            else
++              break;
++          }
++	  if (!buf[0])
++	  {
++	    CLEARLINE (LINES-1);
+ 	    break;
+ 	  }
+-	  FREE (&Context);
+ 	}
+ 
+-        mutt_sleep (0);
 -
--  printf ("SENDMAIL=\"%s\"\n", SENDMAIL);
--  printf ("MAILPATH=\"%s\"\n", MAILPATH);
--  printf ("PKGDATADIR=\"%s\"\n", PKGDATADIR);
--  printf ("SYSCONFDIR=\"%s\"\n", SYSCONFDIR);
--  printf ("EXECSHELL=\"%s\"\n", EXECSHELL);
--#ifdef MIXMASTER
--  printf ("MIXMASTER=\"%s\"\n", MIXMASTER);
--#else
--  puts ("-MIXMASTER");
--#endif
+-	/* Set CurrentMenu to MENU_MAIN before executing any folder
+-	 * hooks so that all the index menu functions are available to
+-	 * the exec command.
+-	 */
 -
--  puts(_(ReachingUs));
+-	CurrentMenu = MENU_MAIN;
+-	mutt_folder_hook (buf);
 -
--  mutt_print_patchlist();
--  
--  exit (0);
--}
+-	if ((Context = mx_open_mailbox (buf,
+-					(option (OPTREADONLY) || op == OP_MAIN_CHANGE_FOLDER_READONLY) ?
+-					M_READONLY : 0, NULL)) != NULL)
+-	{
+-	  menu->current = ci_first_message ();
+-	}
+-	else
+-	  menu->current = 0;
 -
- static void start_curses (void)
- {
-   km_init (); /* must come before mutt_init */
-@@ -540,6 +157,7 @@
-   keypad (stdscr, TRUE);
-   cbreak ();
-   noecho ();
-+  nonl ();
- #if HAVE_TYPEAHEAD
-   typeahead (-1);       /* simulate smooth scrolling */
- #endif
-@@ -554,10 +172,17 @@
- #define M_NOSYSRC (1<<2)	/* -n */
- #define M_RO      (1<<3)	/* -R */
- #define M_SELECT  (1<<4)	/* -y */
+-	mutt_clear_error ();
+-	mutt_buffy_check(1); /* force the buffy check after we have changed
+-			      the folder */
+-	menu->redraw = REDRAW_FULL;
+-	set_option (OPTSEARCHINVALID);
++	main_change_folder(menu, op, buf, sizeof (buf), &oldcount, &index_hint, flags);
 +#ifdef USE_NNTP
-+#define M_NEWS    (1<<5)	/* -g and -G */
++	/* mutt_buffy_check() must be done with mail-reader mode! */
++	menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_MAIN,
++	  (Context && (Context->magic == M_NNTP)) ? IndexNewsHelp : IndexHelp);
 +#endif
- 
- int main (int argc, char **argv)
- {
++	mutt_expand_path (buf, sizeof (buf));
 +#ifdef USE_SIDEBAR
-+  char folder[PATH_MAX] = "";
-+#else
-   char folder[_POSIX_PATH_MAX] = "";
++	mutt_sb_set_open_buffy();
 +#endif
-   char *subject = NULL;
-   char *includeFile = NULL;
-   char *draftFile = NULL;
-@@ -598,7 +223,7 @@
+ 	break;
  
-   mutt_error = mutt_nocurses_error;
-   mutt_message = mutt_nocurses_error;
--  SRAND (time (NULL));
-+  (void)mutt_rand32();
-   umask (077);
+       case OP_DISPLAY_MESSAGE:
+@@ -1316,6 +1917,7 @@ int mutt_index_menu (void)
+ 	CHECK_MSGCOUNT;
+         CHECK_VISIBLE;
+ 	CHECK_READONLY;
++	CHECK_ACL(M_ACL_WRITE, _("Cannot break thread"));
  
-   memset (Options, 0, sizeof (Options));
-@@ -627,7 +252,11 @@
-         argv[nargc++] = argv[optind];
-     }
+         if ((Sort & SORT_MASK) != SORT_THREADS)
+ 	  mutt_error _("Threading is not enabled.");
+@@ -1351,7 +1953,7 @@ int mutt_index_menu (void)
+         CHECK_VISIBLE;
+ 	CHECK_READONLY;
+         /* L10N: CHECK_ACL */
+-	CHECK_ACL(M_ACL_DELETE, _("Cannot link threads"));
++	CHECK_ACL(M_ACL_WRITE, _("Cannot link threads"));
  
-+#ifdef USE_NNTP
-+    if ((i = getopt (argc, argv, "+A:a:b:F:f:c:Dd:Ee:g:GH:s:i:hm:npQ:RvxyzZ")) != EOF)
-+#else
-     if ((i = getopt (argc, argv, "+A:a:b:F:f:c:Dd:Ee:H:s:i:hm:npQ:RvxyzZ")) != EOF)
-+#endif
-       switch (i)
-       {
-       case 'A':
-@@ -728,6 +357,20 @@
- 	flags |= M_SELECT;
+         if ((Sort & SORT_MASK) != SORT_THREADS)
+ 	  mutt_error _("Threading is not enabled.");
+@@ -1919,6 +2521,7 @@ int mutt_index_menu (void)
+ 	MAYBE_REDRAW (menu->redraw);
+ 	break;
+ 
++      case OP_PURGE_MESSAGE:
+       case OP_DELETE:
+ 
+ 	CHECK_MSGCOUNT;
+@@ -1930,6 +2533,7 @@ int mutt_index_menu (void)
+ 	if (tag)
+ 	{
+ 	  mutt_tag_set_flag (M_DELETE, 1);
++	  mutt_tag_set_flag (M_PURGED, (op != OP_PURGE_MESSAGE) ? 0 : 1);
+ 	  if (option (OPTDELETEUNTAG))
+ 	    mutt_tag_set_flag (M_TAG, 0);
+ 	  menu->redraw = REDRAW_INDEX;
+@@ -1937,6 +2541,8 @@ int mutt_index_menu (void)
+ 	else
+ 	{
+ 	  mutt_set_flag (Context, CURHDR, M_DELETE, 1);
++	  mutt_set_flag (Context, CURHDR, M_PURGED,
++			 (op != OP_PURGE_MESSAGE) ? 0 : 1);
+ 	  if (option (OPTDELETEUNTAG))
+ 	    mutt_set_flag (Context, CURHDR, M_TAG, 0);
+ 	  if (option (OPTRESOLVE))
+@@ -1984,6 +2590,20 @@ int mutt_index_menu (void)
+ 	}
  	break;
  
 +#ifdef USE_NNTP
-+      case 'g': /* Specify a news server */
++      case OP_CATCHUP:
++	CHECK_MSGCOUNT;
++	CHECK_READONLY;
++	CHECK_ATTACH
++	if (Context && Context->magic == M_NNTP)
 +	{
-+	  char buf[LONG_STRING];
-+
-+	  snprintf (buf, sizeof (buf), "set news_server=%s", optarg);
-+	  commands = mutt_add_list (commands, buf);
++	  NNTP_DATA *nntp_data = Context->data;
++	  if (mutt_newsgroup_catchup (nntp_data->nserv, nntp_data->group))
++	    menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
 +	}
-+
-+      case 'G': /* List of newsgroups */
-+	flags |= M_SELECT | M_NEWS;
 +	break;
 +#endif
 +
-       case 'z':
- 	flags |= M_IGNORE;
+       case OP_DISPLAY_ADDRESS:
+ 
+ 	CHECK_MSGCOUNT;
+@@ -2045,6 +2665,21 @@ int mutt_index_menu (void)
+ 	menu->redraw = REDRAW_FULL;
  	break;
-@@ -752,14 +395,10 @@
-     case 0:
-       break;
-     case 1:
--      show_version ();
--      break;
-+      print_version();
-+      exit (0);
-     default:
--      puts (mutt_make_version ());
--      puts (_(Copyright));
--      puts (_(Licence));
--      puts (_(Obtaining));
--      puts (_(ReachingUs));
-+      print_copyright();
-       exit (0);
-   }
  
-@@ -828,6 +467,9 @@
-     clear ();
-     mutt_error = mutt_curses_error;
-     mutt_message = mutt_curses_message;
-+#ifdef USE_SIDEBAR
-+    mutt_sb_init();
-+#endif
-   }
++      case OP_EDIT_LABEL:
++
++	CHECK_MSGCOUNT;
++	CHECK_READONLY;
++	rc = mutt_label_message(tag ? NULL : CURHDR);
++	if (rc > 0) {
++	  Context->changed = 1;
++	  menu->redraw = REDRAW_FULL;
++	  mutt_message ("%d label%s changed.", rc, rc == 1 ? "" : "s");
++	}
++	else {
++	  mutt_message _("No labels changed.");
++	}
++	break;
++
+       case OP_LIST_REPLY:
+ 
+ 	CHECK_ATTACH;
+@@ -2190,6 +2825,39 @@ int mutt_index_menu (void)
+         menu->redraw = REDRAW_FULL;
+         break;
  
-   /* Create the Maildir directory if it doesn't exist. */
-@@ -1167,6 +809,18 @@
-     }
-     else if (flags & M_SELECT)
-     {
 +#ifdef USE_NNTP
-+      if (flags & M_NEWS)
-+      {
-+	set_option (OPTNEWS);
-+	if(!(CurrentNewsSrv = nntp_select_server (NewsServer, 0)))
++      case OP_FOLLOWUP:
++      case OP_FORWARD_TO_GROUP:
++
++	CHECK_MSGCOUNT;
++	CHECK_VISIBLE;
++
++      case OP_POST:
++
++	CHECK_ATTACH;
++	if (op != OP_FOLLOWUP || !CURHDR->env->followup_to ||
++	    mutt_strcasecmp (CURHDR->env->followup_to, "poster") ||
++	    query_quadoption (OPT_FOLLOWUPTOPOSTER,
++	    _("Reply by mail as poster prefers?")) != M_YES)
 +	{
-+	  mutt_endwin (Errorbuf);
-+	  exit (1);
++	  if (Context && Context->magic == M_NNTP &&
++	      !((NNTP_DATA *)Context->data)->allowed &&
++	      query_quadoption (OPT_TOMODERATED,
++	      _("Posting to this group not allowed, may be moderated. Continue?")) != M_YES)
++	    break;
++	  if (op == OP_POST)
++	    ci_send_message (SENDNEWS, NULL, NULL, Context, NULL);
++	  else
++	  {
++	    CHECK_MSGCOUNT;
++	    ci_send_message ((op == OP_FOLLOWUP ? SENDREPLY : SENDFORWARD) |
++			SENDNEWS, NULL, NULL, Context, tag ? NULL : CURHDR);
++	  }
++	  menu->redraw = REDRAW_FULL;
++	  break;
 +	}
-+      }
-+      else
-+#endif
-       if (!Incoming) {
- 	mutt_endwin _("No incoming mailboxes defined.");
- 	exit (1);
-@@ -1182,8 +836,26 @@
- 
-     if (!folder[0])
-       strfcpy (folder, NONULL(Spoolfile), sizeof (folder));
-+
-+#ifdef USE_NNTP
-+    if (option (OPTNEWS))
-+    {
-+      unset_option (OPTNEWS);
-+      nntp_expand_path (folder, sizeof (folder), &CurrentNewsSrv->conn->account);
-+    }
-+    else
-+#endif
-     mutt_expand_path (folder, sizeof (folder));
- 
-+#ifdef USE_SIDEBAR
-+    {
-+      char tmpfolder[PATH_MAX] = "";
-+      strfcpy (tmpfolder, folder, sizeof (tmpfolder));
-+      if (!realpath (tmpfolder, folder))
-+        strfcpy (folder, tmpfolder, sizeof (tmpfolder));
-+    }
 +#endif
 +
-     mutt_str_replace (&CurrentFolder, folder);
-     mutt_str_replace (&LastFolder, folder);
- 
-@@ -1206,9 +878,16 @@
-     if((Context = mx_open_mailbox (folder, ((flags & M_RO) || option (OPTREADONLY)) ? M_READONLY : 0, NULL))
-        || !explicit_folder)
-     {
-+#ifdef USE_SIDEBAR
-+      mutt_sb_set_open_buffy (folder);
-+#endif
-+      Labels = hash_create (131, 0);
-+      mutt_scan_labels(Context);
-       mutt_index_menu ();
-       if (Context)
- 	FREE (&Context);
-+      if (Labels)
-+        hash_destroy(&Labels, NULL);
-     }
- #ifdef USE_IMAP
-     imap_logout_all ();
-diff -urN mutt-1.6.1/Makefile.am mutt-1.6.1-neomutt/Makefile.am
---- mutt-1.6.1/Makefile.am	2016-06-12 18:43:00.389447388 +0100
-+++ mutt-1.6.1-neomutt/Makefile.am	2016-06-12 18:43:00.663451660 +0100
-@@ -10,7 +10,11 @@
- IMAP_INCLUDES = -I$(top_srcdir)/imap
- endif
- 
-+if QUICK_BUILD
-+SUBDIRS = $(IMAP_SUBDIR)
-+else
- SUBDIRS = m4 po intl doc contrib $(IMAP_SUBDIR)
-+endif
- 
- bin_SCRIPTS = muttbug flea $(SMIMEAUX_TARGET)
- 
-@@ -34,7 +38,7 @@
- 	score.c send.c sendlib.c signal.c sort.c \
- 	status.c system.c thread.c charset.c history.c lib.c \
- 	muttlib.c editmsg.c mbyte.c \
--	url.c ascii.c crypt-mod.c crypt-mod.h safe_asprintf.c
-+	url.c ascii.c crypt-mod.c crypt-mod.h safe_asprintf.c version.c
- 
- nodist_mutt_SOURCES = $(BUILT_SOURCES)
- 
-@@ -50,33 +54,44 @@
- 
- AM_CPPFLAGS=-I. -I$(top_srcdir) $(IMAP_INCLUDES) $(GPGME_CFLAGS) -Iintl
+       case OP_REPLY:
  
--EXTRA_mutt_SOURCES = account.c bcache.c crypt-gpgme.c crypt-mod-pgp-classic.c \
-+EXTRA_mutt_SOURCES = account.c bcache.c compress.c crypt-gpgme.c crypt-mod-pgp-classic.c \
- 	crypt-mod-pgp-gpgme.c crypt-mod-smime-classic.c \
- 	crypt-mod-smime-gpgme.c dotlock.c gnupgparse.c hcache.c md5.c \
- 	mutt_idna.c mutt_sasl.c mutt_socket.c mutt_ssl.c mutt_ssl_gnutls.c \
- 	mutt_tunnel.c pgp.c pgpinvoke.c pgpkey.c pgplib.c pgpmicalg.c \
- 	pgppacket.c pop.c pop_auth.c pop_lib.c remailer.c resize.c sha1.c \
--	smime.c smtp.c utf8.c wcwidth.c \
-+	nntp.c newsrc.c \
-+	sidebar.c smime.c smtp.c utf8.c wcwidth.c \
- 	bcache.h browser.h hcache.h mbyte.h mutt_idna.h remailer.h url.h
+ 	CHECK_ATTACH;
+@@ -2242,11 +2910,13 @@ int mutt_index_menu (void)
+ 	if (tag)
+ 	{
+ 	  mutt_tag_set_flag (M_DELETE, 0);
++	  mutt_tag_set_flag (M_PURGED, 0);
+ 	  menu->redraw = REDRAW_INDEX;
+ 	}
+ 	else
+ 	{
+ 	  mutt_set_flag (Context, CURHDR, M_DELETE, 0);
++	  mutt_set_flag (Context, CURHDR, M_PURGED, 0);
+ 	  if (option (OPTRESOLVE) && menu->current < Context->vcount - 1)
+ 	  {
+ 	    menu->current++;
+@@ -2268,9 +2938,11 @@ int mutt_index_menu (void)
+ 	CHECK_ACL(M_ACL_DELETE, _("Cannot undelete message(s)"));
  
- EXTRA_DIST = COPYRIGHT GPL OPS OPS.PGP OPS.CRYPT OPS.SMIME TODO UPDATING \
- 	configure account.h \
--	attach.h buffy.h charset.h copy.h crypthash.h dotlock.h functions.h gen_defs \
-+	attach.h buffy.h charset.h compress.h copy.h crypthash.h dotlock.h functions.h gen_defs \
- 	globals.h hash.h history.h init.h keymap.h mutt_crypt.h \
- 	mailbox.h mapping.h md5.h mime.h mutt.h mutt_curses.h mutt_menu.h \
- 	mutt_regex.h mutt_sasl.h mutt_socket.h mutt_ssl.h mutt_tunnel.h \
- 	mx.h pager.h pgp.h pop.h protos.h rfc1524.h rfc2047.h \
- 	rfc2231.h rfc822.h rfc3676.h sha1.h sort.h mime.types VERSION prepare \
-+	nntp.h ChangeLog.nntp \
- 	_regex.h OPS.MIX README.SECURITY remailer.c remailer.h browser.h \
- 	mbyte.h lib.h extlib.c pgpewrap.c smime_keys.pl pgplib.h \
- 	README.SSL smime.h group.h \
- 	muttbug pgppacket.h depcomp ascii.h BEWARE PATCHES patchlist.sh \
--	ChangeLog mkchangelog.sh mutt_idna.h \
-+	ChangeLog mkchangelog.sh mutt_idna.h sidebar.h OPS.sidebar \
- 	snprintf.c regex.c crypt-gpgme.h hcachever.sh.in sys_socket.h \
--	txt2c.c txt2c.sh version.sh check_sec.sh
-+	txt2c.c txt2c.sh version.sh check_sec.sh version.h
+ 	rc = mutt_thread_set_flag (CURHDR, M_DELETE, 0,
+-				   op == OP_UNDELETE_THREAD ? 0 : 1);
++				   op == OP_UNDELETE_THREAD ? 0 : 1)
++	  + mutt_thread_set_flag (CURHDR, M_PURGED, 0,
++				  (op == OP_UNDELETE_THREAD) ? 0 : 1);
  
- EXTRA_SCRIPTS = smime_keys
+-	if (rc != -1)
++	if (rc > -1)
+ 	{
+ 	  if (option (OPTRESOLVE))
+ 	  {
+@@ -2310,11 +2982,35 @@ int mutt_index_menu (void)
+ 	mutt_what_key();
+ 	break;
  
-+if BUILD_NOTMUCH
-+mutt_SOURCES += mutt_notmuch.c mutt_notmuch.h
-+mutt_LDADD += $(NOTMUCH_LIBS)
-+endif
-+
-+# kz
-+EXTRA_DIST += UPDATING.kz README.notmuch OPS.NOTMUCH
++#ifdef USE_SIDEBAR
++      case OP_SIDEBAR_NEXT:
++      case OP_SIDEBAR_NEXT_NEW:
++      case OP_SIDEBAR_PAGE_DOWN:
++      case OP_SIDEBAR_PAGE_UP:
++      case OP_SIDEBAR_PREV:
++      case OP_SIDEBAR_PREV_NEW:
++        mutt_sb_change_mailbox (op);
++        break;
 +
++      case OP_SIDEBAR_TOGGLE_VISIBLE:
++	toggle_option (OPTSIDEBAR);
++	menu->redraw = REDRAW_FULL;
++	break;
 +
- mutt_dotlock_SOURCES = mutt_dotlock.c
- mutt_dotlock_LDADD = $(LIBOBJS)
- mutt_dotlock_DEPENDENCIES = $(LIBOBJS)
-@@ -129,14 +144,15 @@
- keymap_defs.h: $(OPS) $(srcdir)/gen_defs
- 	$(srcdir)/gen_defs $(OPS) > keymap_defs.h
++      case OP_SIDEBAR_TOGGLE_VIRTUAL:
++	mutt_sb_toggle_virtual();
++	break;
++#endif
+       default:
+ 	if (menu->menu == MENU_MAIN)
+ 	  km_error_key (MENU_MAIN);
+     }
  
--keymap_alldefs.h: $(srcdir)/OPS $(srcdir)/OPS.PGP $(srcdir)/OPS.MIX $(srcdir)/OPS.CRYPT $(srcdir)/OPS.SMIME $(srcdir)/gen_defs
-+keymap_alldefs.h: $(srcdir)/OPS $(srcdir)/OPS.SIDEBAR $(srcdir)/OPS.NOTMUCH $(srcdir)/OPS.PGP $(srcdir)/OPS.MIX $(srcdir)/OPS.CRYPT $(srcdir)/OPS.SMIME $(srcdir)/gen_defs
- 	rm -f $@
--	$(srcdir)/gen_defs $(srcdir)/OPS $(srcdir)/OPS.PGP \
-+	$(srcdir)/gen_defs $(srcdir)/OPS $(srcdir)/OPS.SIDEBAR $(srcdir)/OPS.NOTMUCH $(srcdir)/OPS.PGP \
- 		$(srcdir)/OPS.MIX $(srcdir)/OPS.CRYPT $(srcdir)/OPS.SMIME \
- 			> keymap_alldefs.h
++#ifdef USE_NOTMUCH
++    if (Context)
++      nm_debug_check(Context);
++#endif
++
+     if (menu->menu == MENU_PAGER)
+     {
+       menu->menu = MENU_MAIN;
+diff --git a/doc/Makefile.am b/doc/Makefile.am
+index bc8f856..cd633dc 100644
+--- a/doc/Makefile.am
++++ b/doc/Makefile.am
+@@ -37,7 +37,8 @@ EXTRA_DIST = dotlock.man		\
  
--reldate.h: $(srcdir)/ChangeLog
--	echo 'const char *ReleaseDate = "'`head -n 1 $(srcdir)/ChangeLog | LC_ALL=C cut -d ' ' -f 1`'";' > reldate.h.tmp; \
-+reldate.h: $(top_srcdir)/ChangeLog.neomutt
-+	date=`head -n 1 $(top_srcdir)/ChangeLog.neomutt | LC_ALL=C cut -b 1-10` && \
-+	echo 'const char *ReleaseDate = "'$$date'";' > reldate.h.tmp; \
- 	cmp -s reldate.h.tmp reldate.h || cp reldate.h.tmp reldate.h; \
- 	rm reldate.h.tmp
+ CHUNKED_DOCFILES = index.html intro.html gettingstarted.html \
+ 	configuration.html mimesupport.html advancedusage.html \
+-	optionalfeatures.html security.html tuning.html reference.html miscellany.html
++	optionalfeatures.html security.html tuning.html reference.html miscellany.html \
++	compressed-folders.html
  
-@@ -184,17 +200,6 @@
- check-security:
- 	(cd $(top_srcdir) && ./check_sec.sh)
+ HTML_DOCFILES = manual.html $(CHUNKED_DOCFILES)
  
--commit:
--	@echo "make commit is obsolete; use hg-commit"; false
--
--update-changelog:
--	(cd $(top_srcdir); \
--	sh ./mkchangelog.sh | cat  - ChangeLog > ChangeLog.$$$$ && mv ChangeLog.$$$$ ChangeLog; \
--	$${VISUAL:-vi} ChangeLog)
--
--mutt-dist:
--	(cd $(srcdir) && ./build-release )
--
- update-doc:
- 	(cd doc && $(MAKE) update-doc)
+@@ -189,8 +190,8 @@ smime_keys.1: $(srcdir)/smime_keys.man
  
-diff -urN mutt-1.6.1/mbox.c mutt-1.6.1-neomutt/mbox.c
---- mutt-1.6.1/mbox.c	2016-06-12 18:43:00.409447699 +0100
-+++ mutt-1.6.1-neomutt/mbox.c	2016-06-12 18:43:00.714452456 +0100
-@@ -29,6 +29,10 @@
- #include "copy.h"
- #include "mutt_curses.h"
+ stamp-doc-xml: makedoc$(EXEEXT) $(top_srcdir)/init.h \
+                manual.xml.head $(top_srcdir)/functions.h $(top_srcdir)/OPS* manual.xml.tail \
+-               $(srcdir)/gen-map-doc $(top_srcdir)/VERSION $(top_srcdir)/ChangeLog
+-	( date=`head -n 1 $(top_srcdir)/ChangeLog | LC_ALL=C cut -d ' ' -f 1` && \
++               $(srcdir)/gen-map-doc $(top_srcdir)/VERSION $(top_srcdir)/ChangeLog.neomutt
++	( date=`head -n 1 $(top_srcdir)/ChangeLog.neomutt | LC_ALL=C cut -b 1-10` && \
+ 	  sed -e "s/@VERSION\@/`cat $(top_srcdir)/VERSION` ($$date)/" $(srcdir)/manual.xml.head && \
+ 	  $(MAKEDOC_CPP) $(top_srcdir)/init.h | ./makedoc$(EXEEXT) -s && \
+ 	  $(MAKEDOC_CPP) $(top_srcdir)/functions.h | \
+diff --git a/doc/Muttrc.head b/doc/Muttrc.head
+index 1f7012e..69e27ca 100644
+--- a/doc/Muttrc.head
++++ b/doc/Muttrc.head
+@@ -29,6 +29,11 @@ macro generic,pager <F1> "<shell-escape> less @docdir@/manual.txt<Enter>" "show
+ macro index,pager y "<change-folder>?<toggle-mailboxes>" "show incoming mailboxes list"
+ bind browser y exit
  
-+#ifdef USE_COMPRESSED
-+#include "compress.h"
-+#endif
++# Use folders which match on \\.gz$ as gzipped folders:
++# open-hook \\.gz$ "gzip -cd %f > %t"
++# close-hook \\.gz$ "gzip -c %t > %f"
++# append-hook \\.gz$ "gzip -c %t >> %f"
 +
- #include <sys/stat.h>
- #include <dirent.h>
- #include <string.h>
-@@ -100,6 +104,9 @@
-     mutt_perror (ctx->path);
-     return (-1);
-   }
-+#ifdef USE_SIDEBAR
-+  ctx->atime = sb.st_atime;
-+#endif
-   ctx->mtime = sb.st_mtime;
-   ctx->size = sb.st_size;
- 
-@@ -251,6 +258,9 @@
+ # If Mutt is unable to determine your site's domain name correctly, you can
+ # set the default here.
+ #
+diff --git a/doc/gen-map-doc b/doc/gen-map-doc
+index e2fadac..416ae9e 100644
+--- a/doc/gen-map-doc
++++ b/doc/gen-map-doc
+@@ -34,7 +34,8 @@ while (<STDIN>) {
+     $binding =~ s/^\\(0\d+)$/'^'.chr(64+oct($1))/e;
+     $binding =~ s/^\\(0\d+)(.)/'^'.chr(64+oct($1)) ." $2"/e;
+     $binding =~ s/\\t/<Tab>/;
+-    $binding =~ s/M_ENTER_S/<Return>/;
++    $binding =~ s/\\r/<Return>/;
++    $binding =~ s/\\n/<Enter>/;
+     $binding =~ s/NULL//;
+     die "unknown key $binding" if $binding =~ /\\[^\\]|<|>/;
+     die "unknown OP $op" unless $OPS{$op};
+diff --git a/doc/makedoc-defs.h b/doc/makedoc-defs.h
+index 8f1a349..ac6cd33 100644
+--- a/doc/makedoc-defs.h
++++ b/doc/makedoc-defs.h
+@@ -55,4 +55,7 @@
+ # ifndef USE_SASL
+ #  define USE_SASL
+ # endif
++# ifndef USE_SIDEBAR
++#  define USE_SIDEBAR
++# endif
+ #endif
+diff --git a/doc/manual.xml.head b/doc/manual.xml.head
+index b90908f..92919e6 100644
+--- a/doc/manual.xml.head
++++ b/doc/manual.xml.head
+@@ -405,6 +405,602 @@ attach to a message, select multiple files to attach and many more.
  
-   ctx->size = sb.st_size;
-   ctx->mtime = sb.st_mtime;
-+#ifdef USE_SIDEBAR
-+  ctx->atime = sb.st_atime;
-+#endif
+ </sect2>
  
- #ifdef NFS_ATTRIBUTE_HACK
-   if (sb.st_mtime > sb.st_atime)
-@@ -1073,6 +1083,12 @@
- int mbox_close_mailbox (CONTEXT *ctx)
- {
-   mx_unlock_file (ctx->path, fileno (ctx->fp), 1);
-+
-+#ifdef USE_COMPRESSED
-+  if (ctx->compress_info)
-+    comp_slow_close (ctx);
-+#endif
++<sect2 id="intro-sidebar">
++  <title>Sidebar</title>
++  <para>
++    The Sidebar shows a list of all your mailboxes.  The list can be
++    turned on and off, it can be themed and the list style can be
++    configured.
++  </para>
++  <para>
++    This part of the manual is suitable for beginners.
++    If you already know Mutt you could skip ahead to the main
++    <link linkend="sidebar">Sidebar guide</link>.
++    If you just want to get started, you could use the sample
++    <link linkend="sidebar-muttrc">Sidebar muttrc</link>.
++  </para>
++  <para>
++    To check if Mutt supports <quote>Sidebar</quote>, look for the string
++    <literal>+USE_SIDEBAR</literal> in the mutt version.
++  </para>
++<screen>
++mutt -v
++</screen>
++  <para>
++    <emphasis role="bold">Let's turn on the Sidebar:</emphasis>
++  </para>
++<screen>
++set sidebar_visible
++set sidebar_format = "%B%?F? [%F]?%* %?N?%N/?%S"
++set mail_check_stats
++</screen>
++  <para>
++    You will see something like this.
++    A list of mailboxes on the left.
++    A list of emails, from the selected mailbox, on the right.
++  </para>
++<screen>
++<emphasis role="indicator">Fruit [1]     3/8</emphasis>|  1    + Jan 24  Rhys Lee         (192)  Yew
++Animals [1]   2/6|  2    + Feb 11  Grace Hall       (167)  Ilama
++Cars            4|  3      Feb 23  Aimee Scott      (450)  Nectarine
++Seas          1/7|  4    ! Feb 28  Summer Jackson   (264)  Lemon
++                 |  5      Mar 07  Callum Harrison  (464)  Raspberry
++                 |<emphasis role="indicator">  6 N  + Mar 24  Samuel Harris    (353)  Tangerine          </emphasis>
++                 |  7 N  + Sep 05  Sofia Graham     (335)  Cherry
++                 |  8 N    Sep 16  Ewan Brown       (105)  Ugli
++                 |
++                 |
++</screen>
++<para>
++  This user has four mailboxes: <quote>Fruit</quote>,
++  <quote>Cars</quote>, <quote>Animals</quote> and
++  <quote>Seas</quote>.
++</para>
++<para>
++  The current, open, mailbox is <quote>Fruit</quote>.  We can
++  also see information about the other mailboxes.  For example:
++  The <quote>Animals</quote> mailbox contains, 1 flagged email, 2
++  new emails out of a total of 6 emails.
++</para>
++  <sect3 id="intro-sidebar-navigation">
++    <title>Navigation</title>
++    <para>
++      The Sidebar adds some new <link linkend="sidebar-functions">functions</link>
++      to Mutt.
++    </para>
++    <para>
++      The user pressed the <quote>c</quote> key to
++      <literal><change-folder></literal> to the
++      <quote>Animals</quote> mailbox.  The Sidebar automatically
++      updated the indicator to match.
++    </para>
++<screen>
++Fruit [1]     3/8|  1      Jan 03  Tia Gibson       (362)  Caiman
++<emphasis role="indicator">Animals [1]   2/6</emphasis>|  2    + Jan 22  Rhys Lee         ( 48)  Dolphin
++Cars            4|  3    ! Aug 16  Ewan Brown       (333)  Hummingbird
++Seas          1/7|  4      Sep 25  Grace Hall       ( 27)  Capybara
++                 |<emphasis role="indicator">  5 N  + Nov 12  Evelyn Rogers    (453)  Tapir              </emphasis>
++                 |  6 N  + Nov 16  Callum Harrison  (498)  Hedgehog
++                 |
++                 |
++                 |
++                 |
++</screen>
++    <para>
++      Let's map some functions:
++    </para>
++<screen>
++bind index,pager \CP sidebar-prev       <emphasis role="comment"># Ctrl-Shift-P - Previous Mailbox</emphasis>
++bind index,pager \CN sidebar-next       <emphasis role="comment"># Ctrl-Shift-N - Next Mailbox</emphasis>
++bind index,pager \CO sidebar-open       <emphasis role="comment"># Ctrl-Shift-O - Open Highlighted Mailbox</emphasis>
++</screen>
++    <para>
++      Press <quote>Ctrl-Shift-N</quote> (Next mailbox) twice will
++      move the Sidebar <emphasis role="bold">highlight</emphasis> to
++      down to the <quote>Seas</quote> mailbox.
++    </para>
++<screen>
++Fruit [1]     3/8|  1      Jan 03  Tia Gibson       (362)  Caiman
++<emphasis role="indicator">Animals [1]   2/6</emphasis>|  2    + Jan 22  Rhys Lee         ( 48)  Dolphin
++Cars            4|  3    ! Aug 16  Ewan Brown       (333)  Hummingbird
++<emphasis role="highlight">Seas          1/7</emphasis>|  4      Sep 25  Grace Hall       ( 27)  Capybara
++                 |<emphasis role="indicator">  5 N  + Nov 12  Evelyn Rogers    (453)  Tapir              </emphasis>
++                 |  6 N  + Nov 16  Callum Harrison  (498)  Hedgehog
++                 |
++                 |
++                 |
++                 |
++</screen>
++    <note>
++      <para>
++        Functions <literal><sidebar-next></literal> and
++        <literal><sidebar-prev></literal> move the Sidebar
++        <emphasis role="bold">highlight</emphasis>.
++        They <emphasis role="bold">do not</emphasis> change the open
++        mailbox.
++      </para>
++    </note>
++    <para>
++      Press <quote>Ctrl-Shift-O</quote>
++      (<literal><sidebar-open></literal>)
++      to open the highlighted mailbox.
++    </para>
++<screen>
++Fruit [1]     3/8|  1    ! Mar 07  Finley Jones     (139)  Molucca Sea
++Animals [1]   2/6|  2    + Mar 24  Summer Jackson   ( 25)  Arafura Sea
++Cars            4|  3    + Feb 28  Imogen Baker     (193)  Pechora Sea
++<emphasis role="indicator">Seas          1/7</emphasis>|<emphasis role="indicator">  4 N  + Feb 23  Isla Hussain     (348)  Balearic Sea       </emphasis>
++                 |
++                 |
++                 |
++                 |
++                 |
++                 |
++</screen>
++  </sect3>
++  <sect3 id="intro-sidebar-features">
++    <title>Features</title>
++    <para>
++      The Sidebar shows a list of mailboxes in a panel.
++    </para>
++    <para>
++      Everything about the Sidebar can be configured.
++    </para>
++    <itemizedlist>
++    <title><link linkend="intro-sidebar-basics">State of the Sidebar</link></title>
++      <listitem><para>Visibility</para></listitem>
++      <listitem><para>Width</para></listitem>
++    </itemizedlist>
++    <itemizedlist>
++    <title><link linkend="intro-sidebar-limit">Which mailboxes are displayed</link></title>
++      <listitem><para>Display all</para></listitem>
++      <listitem><para>Limit to mailboxes with new mail</para></listitem>
++      <listitem><para>Whitelist mailboxes to display always</para></listitem>
++    </itemizedlist>
++    <itemizedlist>
++    <title><link linkend="sidebar-sort">The order in which mailboxes are displayed</link></title>
++      <listitem><para>Unsorted (order of mailboxes commands)</para></listitem>
++      <listitem><para>Sorted alphabetically</para></listitem>
++      <listitem><para>Sorted by number of new mails</para></listitem>
++    </itemizedlist>
++    <itemizedlist>
++    <title><link linkend="intro-sidebar-colors">Color</link></title>
++      <listitem><para>Sidebar indicators and divider</para></listitem>
++      <listitem><para>Mailboxes depending on their type</para></listitem>
++      <listitem><para>Mailboxes depending on their contents</para></listitem>
++    </itemizedlist>
++    <itemizedlist>
++    <title><link linkend="sidebar-functions">Key bindings</link></title>
++      <listitem><para>Hide/Unhide the Sidebar</para></listitem>
++      <listitem><para>Select previous/next mailbox</para></listitem>
++      <listitem><para>Select previous/next mailbox with new mail</para></listitem>
++      <listitem><para>Page up/down through a list of mailboxes</para></listitem>
++    </itemizedlist>
++    <itemizedlist>
++    <title>Misc</title>
++      <listitem><para><link linkend="intro-sidebar-format">Formatting string for mailbox</link></para></listitem>
++      <listitem><para><link linkend="sidebar-next-new-wrap">Wraparound searching</link></para></listitem>
++      <listitem><para><link linkend="intro-sidebar-abbrev">Flexible mailbox abbreviations</link></para></listitem>
++      <listitem><para>Support for Unicode mailbox names (utf-8)</para></listitem>
++    </itemizedlist>
++  </sect3>
++  <sect3 id="intro-sidebar-display">
++    <title>Display</title>
++    <para>
++      Everything about the Sidebar can be configured.
++    </para>
++    <itemizedlist>
++      <title>For a quick reference:</title>
++      <listitem><para><link linkend="sidebar-variables">Sidebar variables to set</link> </para></listitem>
++      <listitem><para><link linkend="sidebar-colors">Sidebar colors to apply</link></para></listitem>
++      <listitem><para><link linkend="sidebar-sort">Sidebar sort methods</link></para></listitem>
++    </itemizedlist>
++    <sect4 id="intro-sidebar-basics">
++      <title>Sidebar Basics</title>
++      <para>
++        The most important variable is <literal>$sidebar_visible</literal>.
++        You can set this in your <quote>muttrc</quote>, or bind a key to the
++        function <literal><sidebar-toggle-visible></literal>.
++      </para>
++<screen>
++set sidebar_visible                         <emphasis role="comment"># Make the Sidebar visible by default</emphasis>
++bind index,pager B sidebar-toggle-visible   <emphasis role="comment"># Use 'B' to switch the Sidebar on and off</emphasis>
++</screen>
++      <para>
++        Next, decide how wide you want the Sidebar to be.  25
++        characters might be enough for the mailbox name and some numbers.
++    Remember, you can hide/show the Sidebar at the press of button.
++    </para>
++    <para>
++    Finally, you might want to change the divider character.
++    By default, Sidebar draws an ASCII line between it and the Index panel
++        If your terminal supports it, you can use a Unicode line-drawing character.
++      </para>
++<screen>
++set sidebar_width = 25                  <emphasis role="comment"># Plenty of space</emphasis>
++set sidebar_divider_char = '│'          <emphasis role="comment"># Pretty line-drawing character</emphasis>
++</screen>
++    </sect4>
++    <sect4 id="intro-sidebar-format">
++      <title>Sidebar Format String</title>
++      <para>
++        <literal>$sidebar_format</literal> allows you to customize the Sidebar display.
++        For an introduction, read <link linkend="index-format">format strings</link>
++        including the section about <link linkend="formatstrings-conditionals">conditionals</link>.
++      </para>
++      <para>
++        The default value is <literal>%B%*  %n</literal>
++        The default value is <literal>%B%?F? [%F]?%* %?N?%N/?%S</literal>
++      </para>
++      <itemizedlist>
++        <title>Which breaks down as:</title>
++        <listitem><para><literal>%B</literal> - Mailbox name</para></listitem>
++        <listitem><para><literal>%?F? [%F]?</literal> - If flagged emails <literal>[%F]</literal>, otherwise nothing</para></listitem>
++        <listitem><para><literal>%* </literal> - Pad with spaces</para></listitem>
++        <listitem><para><literal>%?N?%N/?</literal> - If new emails <literal>%N/</literal>, otherwise nothing</para></listitem>
++        <listitem><para><literal>%S</literal> - Total number of emails</para></listitem>
++      </itemizedlist>
++      <table>
++        <title>sidebar_format</title>
++        <tgroup cols="3">
++          <thead>
++            <row>
++              <entry>Format</entry>
++              <entry>Notes</entry>
++              <entry>Description</entry>
++            </row>
++          </thead>
++          <tbody>
++            <row>
++              <entry>%B</entry>
++              <entry></entry>
++              <entry>Name of the mailbox</entry>
++            </row>
++            <row>
++              <entry>%S</entry>
++              <entry>* †</entry>
++              <entry>Size of mailbox (total number of messages)</entry>
++            </row>
++            <row>
++              <entry>%F</entry>
++              <entry>* †</entry>
++              <entry>Number of Flagged messages in the mailbox</entry>
++            </row>
++            <row>
++              <entry>%N</entry>
++              <entry>* †</entry>
++              <entry>Number of New messages in the mailbox</entry>
++            </row>
++            <row>
++              <entry>%n</entry>
++              <entry>*</entry>
++              <entry>If there's new mail, display <quote>N</quote>, otherwise nothing</entry>
++            </row>
++            <row>
++              <entry>%!</entry>
++              <entry></entry>
++              <entry>
++                <quote>!</quote>: one flagged message;
++                <quote>!!</quote>: two flagged messages;
++                <quote>n!</quote>: n flagged messages (for n > 2).
++                Otherwise prints nothing.
++              </entry>
++            </row>
++            <row>
++              <entry>%d</entry>
++              <entry>* ‡</entry>
++              <entry>Number of deleted messages</entry>
++            </row>
++            <row>
++              <entry>%L</entry>
++              <entry>* ‡</entry>
++              <entry>Number of messages after limiting</entry>
++            </row>
++            <row>
++              <entry>%t</entry>
++              <entry>* ‡</entry>
++              <entry>Number of tagged messages</entry>
++            </row>
++            <row>
++              <entry>%>X</entry>
++              <entry></entry>
++              <entry>Right justify the rest of the string and pad with <quote>X</quote></entry>
++            </row>
++            <row>
++              <entry>%|X</entry>
++              <entry></entry>
++              <entry>Pad to the end of the line with
++              <quote>X</quote></entry>
++            </row>
++            <row>
++              <entry>%*X</entry>
++              <entry></entry>
++              <entry>Soft-fill with character <quote>X</quote>as pad</entry>
++            </row>
++          </tbody>
++        </tgroup>
++      </table>
++      <para>
++      * = Can be optionally printed if nonzero
++      </para>
++      <para>
++      † = To use this expandos, you must first: <screen>set mail_check_stats</screen>
++      </para>
++      <para>
++      ‡ = Only applicable to the current folder
++      </para>
++      <para>
++        Here are some examples.
++        They show the number of (F)lagged, (N)ew and (S)ize.
++      </para>
++      <table>
++        <title>sidebar_format</title>
++        <tgroup cols="2">
++          <thead>
++            <row>
++              <entry>Format</entry>
++              <entry>Example</entry>
++            </row>
++          </thead>
++          <tbody>
++            <row>
++              <entry><literal>%B%?F? [%F]?%* %?N?%N/?%S</literal></entry>
++              <entry><screen>mailbox [F]            N/S</screen></entry>
++            </row>
++            <row>
++              <entry><literal>%B%* %F:%N:%S</literal></entry>
++              <entry><screen>mailbox              F:N:S</screen></entry>
++            </row>
++            <row>
++              <entry><literal>%B %?N?(%N)?%* %S</literal></entry>
++              <entry><screen>mailbox (N)              S</screen></entry>
++            </row>
++            <row>
++              <entry><literal>%B%* ?F?%F/?%N</literal></entry>
++              <entry><screen>mailbox                F/S</screen></entry>
++            </row>
++          </tbody>
++        </tgroup>
++      </table>
++    </sect4>
++    <sect4 id="intro-sidebar-abbrev">
++      <title>Abbreviating Mailbox Names</title>
++      <para>
++        <literal>$sidebar_delim_chars</literal> tells Sidebar
++        how to split up mailbox paths.  For local directories
++        use <quote>/</quote>; for IMAP folders use <quote>.</quote>
++      </para>
++      <sect5 id="intro-sidebar-abbrev-ex1">
++        <title>Example 1</title>
++        <para>
++          This example works well if your mailboxes have unique names
++          after the last separator.
++        </para>
++        <para>
++          Add some mailboxes of diffent depths.
++        </para>
++<screen>
++set folder="~/mail"
++mailboxes =fruit/apple          =fruit/banana          =fruit/cherry
++mailboxes =water/sea/sicily     =water/sea/archipelago =water/sea/sibuyan
++mailboxes =water/ocean/atlantic =water/ocean/pacific   =water/ocean/arctic
++</screen>
++        <para>
++          Shorten the names:
++        </para>
++<screen>
++set sidebar_short_path                  <emphasis role="comment"># Shorten mailbox names</emphasis>
++set sidebar_delim_chars="/"             <emphasis role="comment"># Delete everything up to the last / character</emphasis>
++</screen>
++        <para>
++          The screenshot below shows what the Sidebar would look like
++          before and after shortening.
++        </para>
++<screen>
++|fruit/apple                            |apple
++|fruit/banana                           |banana
++|fruit/cherry                           |cherry
++|water/sea/sicily                       |sicily
++|water/sea/archipelago                  |archipelago
++|water/sea/sibuyan                      |sibuyan
++|water/ocean/atlantic                   |atlantic
++|water/ocean/pacific                    |pacific
++|water/ocean/arctic                     |arctic
++</screen>
++      </sect5>
++      <sect5 id="intro-sidebar-abbrev-ex2">
++        <title>Example 2</title>
++        <para>
++          This example works well if you have lots of mailboxes which are arranged
++          in a tree.
++        </para>
++        <para>
++          Add some mailboxes of diffent depths.
++        </para>
++<screen>
++set folder="~/mail"
++mailboxes =fruit
++mailboxes =fruit/apple =fruit/banana =fruit/cherry
++mailboxes =water
++mailboxes =water/sea
++mailboxes =water/sea/sicily =water/sea/archipelago =water/sea/sibuyan
++mailboxes =water/ocean
++mailboxes =water/ocean/atlantic =water/ocean/pacific =water/ocean/arctic
++</screen>
++        <para>
++          Shorten the names:
++        </para>
++<screen>
++set sidebar_short_path                  <emphasis role="comment"># Shorten mailbox names</emphasis>
++set sidebar_delim_chars="/"             <emphasis role="comment"># Delete everything up to the last / character</emphasis>
++set sidebar_folder_indent               <emphasis role="comment"># Indent folders whose names we've shortened</emphasis>
++set sidebar_indent_string="  "          <emphasis role="comment"># Indent with two spaces</emphasis>
++</screen>
++        <para>
++          The screenshot below shows what the Sidebar would look like
++          before and after shortening.
++        </para>
++<screen>
++|fruit                                  |fruit
++|fruit/apple                            |  apple
++|fruit/banana                           |  banana
++|fruit/cherry                           |  cherry
++|water                                  |water
++|water/sea                              |  sea
++|water/sea/sicily                       |    sicily
++|water/sea/archipelago                  |    archipelago
++|water/sea/sibuyan                      |    sibuyan
++|water/ocean                            |  ocean
++|water/ocean/atlantic                   |    atlantic
++|water/ocean/pacific                    |    pacific
++|water/ocean/arctic                     |    arctic
++</screen>
++        <para>
++          Sometimes, it will be necessary to add mailboxes, that you
++          don't use, to fill in part of the tree.  This will trade
++          vertical space for horizonal space (but it looks good).
++        </para>
++      </sect5>
++    </sect4>
++    <sect4 id="intro-sidebar-limit">
++      <title>Limiting the Number of Mailboxes</title>
++      <para>
++        If you have a lot of mailboxes, sometimes it can be useful to hide
++        the ones you aren't using.  <literal>$sidebar_new_mail_only</literal>
++        tells Sidebar to only show mailboxes that contain new, or flagged, email.
++      </para>
++      <para>
++        If you want some mailboxes to be always visible, then use the
++        <literal>sidebar_whitelist</literal> command.  It takes a list of
++        mailboxes as parameters.
++      </para>
++<screen>
++set sidebar_new_mail_only               <emphasis role="comment"># Only mailboxes with new/flagged email</emphasis>
++sidebar_whitelist fruit fruit/apple     <emphasis role="comment"># Always display these two mailboxes</emphasis>
++</screen>
++    </sect4>
++  </sect3>
++  <sect3 id="intro-sidebar-colors">
++    <title>Colors</title>
++    <para>
++      Here is a sample color scheme:
++    </para>
++<screen>
++color sidebar_indicator default color17         <emphasis role="comment"># Dark blue background</emphasis>
++color sidebar_highlight white   color238        <emphasis role="comment"># Grey background</emphasis>
++color sidebar_spoolfile yellow  default         <emphasis role="comment"># Yellow</emphasis>
++color sidebar_new       green   default         <emphasis role="comment"># Green</emphasis>
++color sidebar_flagged   red     default         <emphasis role="comment"># Red</emphasis>
++color sidebar_divider   color8  default         <emphasis role="comment"># Dark grey</emphasis>
++</screen>
++    <para>
++      There is a priority order when coloring Sidebar mailboxes.
++      e.g.  If a mailbox has new mail it will have the
++      <literal>sidebar_new</literal> color, even if it also contains
++      flagged mails.
++    </para>
++    <table id="table-intro-sidebar-colors">
++      <title>Sidebar Color Priority</title>
++      <tgroup cols="3">
++        <thead>
++          <row>
++            <entry>Priority</entry>
++            <entry>Color</entry>
++            <entry>Description</entry>
++          </row>
++        </thead>
++        <tbody>
++          <row>
++            <entry>Highest</entry>
++            <entry><literal>sidebar_indicator</literal></entry>
++            <entry>Mailbox is open</entry>
++          </row>
++          <row>
++            <entry></entry>
++            <entry><literal>sidebar_highlight</literal></entry>
++            <entry>Mailbox is highlighed</entry>
++          </row>
++          <row>
++            <entry></entry>
++            <entry><literal>sidebar_spoolfile</literal></entry>
++            <entry>Mailbox is the spoolfile (receives incoming mail)</entry>
++          </row>
++          <row>
++            <entry></entry>
++            <entry><literal>sidebar_new</literal></entry>
++            <entry>Mailbox contains new mail</entry>
++          </row>
++          <row>
++            <entry></entry>
++            <entry><literal>sidebar_flagged</literal></entry>
++            <entry>Mailbox contains flagged mail</entry>
++          </row>
++          <row>
++            <entry>Lowest</entry>
++            <entry>(None)</entry>
++            <entry>Mailbox does not match above</entry>
++          </row>
++        </tbody>
++      </tgroup>
++    </table>
++  </sect3>
++  <sect3 id="intro-sidebar-config-changes">
++    <title>Config Changes</title>
++    <para>
++      If you haven't used Sidebar before, you can ignore this section.
++    </para>
++    <para>
++      Some of the Sidebar config has been changed to make its meaning clearer.
++      These changes have been made since the previous Sidebar release: 2015-11-11.
++    </para>
++    <table id="table-intro-sidebar-config-changes">
++      <title>Config Changes</title>
++      <tgroup cols="2">
++        <thead>
++          <row>
++            <entry>Old Name</entry>
++            <entry>New Name</entry>
++          </row>
++        </thead>
++        <tbody>
++          <row>
++            <entry><literal>$sidebar_delim</literal></entry>
++            <entry><literal>$sidebar_divider_char</literal></entry>
++          </row>
++          <row>
++            <entry><literal>$sidebar_folderindent</literal></entry>
++            <entry><literal>$sidebar_folder_indent</literal></entry>
++          </row>
++          <row>
++            <entry><literal>$sidebar_indentstr</literal></entry>
++            <entry><literal>$sidebar_indent_string</literal></entry>
++          </row>
++          <row>
++            <entry><literal>$sidebar_newmail_only</literal></entry>
++            <entry><literal>$sidebar_new_mail_only</literal></entry>
++          </row>
++          <row>
++            <entry><literal>$sidebar_shortpath</literal></entry>
++            <entry><literal>$sidebar_short_path</literal></entry>
++          </row>
++          <row>
++            <entry><literal>$sidebar_sort</literal></entry>
++            <entry><literal>$sidebar_sort_method</literal></entry>
++          </row>
++          <row>
++            <entry><literal><sidebar-scroll-down></literal></entry>
++            <entry><literal><sidebar-page-down></literal></entry>
++          </row>
++          <row>
++            <entry><literal><sidebar-scroll-up></literal></entry>
++            <entry><literal><sidebar-page-up></literal></entry>
++          </row>
++        </tbody>
++      </tgroup>
++    </table>
++  </sect3>
++</sect2>
 +
-   mutt_unblock_signals ();
-   mx_fastclose_mailbox (ctx);
-   return 0;
-diff -urN mutt-1.6.1/mbyte.c mutt-1.6.1-neomutt/mbyte.c
---- mutt-1.6.1/mbyte.c	2016-06-12 18:43:00.409447699 +0100
-+++ mutt-1.6.1-neomutt/mbyte.c	2016-06-12 18:43:00.714452456 +0100
-@@ -107,7 +107,7 @@
-   char buf[MB_LEN_MAX+1];
-   ICONV_CONST char *ib;
-   char *ob;
--  size_t ibl, obl, r;
-+  size_t ibl, obl;
+ <sect2 id="intro-help">
+ <title>Help</title>
  
-   if (s)
-   {
-@@ -117,7 +117,7 @@
-     ib = buf;
-     ob = s;
-     obl = MB_LEN_MAX;
--    r = iconv (cd, &ib, &ibl, &ob, &obl);
-+    iconv (cd, &ib, &ibl, &ob, &obl);
-   }
-   else
-   {
-@@ -125,7 +125,7 @@
-     ibl = 1;
-     ob = buf;
-     obl = sizeof (buf);
--    r = iconv (cd, &ib, &ibl, &ob, &obl);
-+    iconv (cd, &ib, &ibl, &ob, &obl);
-   }
-   return ob - s;
- }
-diff -urN mutt-1.6.1/menu.c mutt-1.6.1-neomutt/menu.c
---- mutt-1.6.1/menu.c	2016-06-12 18:43:00.409447699 +0100
-+++ mutt-1.6.1-neomutt/menu.c	2016-06-12 18:43:00.715452471 +0100
-@@ -24,10 +24,56 @@
- #include "mutt_curses.h"
- #include "mutt_menu.h"
- #include "mbyte.h"
-+#ifdef USE_SIDEBAR
-+#include "sidebar.h"
-+#endif
+@@ -539,7 +1135,7 @@ descriptions.
+ <row><entry>^E or <End></entry><entry><literal><eol></literal></entry><entry>move to the end of the line</entry></row>
+ <row><entry>^F or <Right></entry><entry><literal><forward-char></literal></entry><entry>move forward one char</entry></row>
+ <row><entry>Esc F</entry><entry><literal><forward-word></literal></entry><entry>move forward one word</entry></row>
+-<row><entry><Tab></entry><entry><literal><complete></literal></entry><entry>complete filename or alias</entry></row>
++<row><entry><Tab></entry><entry><literal><complete></literal></entry><entry>complete filename, alias, or label</entry></row>
+ <row><entry>^T</entry><entry><literal><complete-query></literal></entry><entry>complete address with query</entry></row>
+ <row><entry>^K</entry><entry><literal><kill-eol></literal></entry><entry>delete to the end of the line</entry></row>
+ <row><entry>Esc d</entry><entry><literal><kill-eow></literal></entry><entry>delete to the end of the word</entry></row>
+@@ -2642,7 +3238,7 @@ silently truncated at the screen width, and are not wrapped.
  
- char* SearchBuffers[MENU_MAX];
+ <command>color</command>
+ <arg choice="plain">
+-<option>index</option>
++<option>index-object</option>
+ </arg>
+ <arg choice="plain">
+ <replaceable class="parameter">foreground</replaceable>
+@@ -2657,7 +3253,7 @@ silently truncated at the screen width, and are not wrapped.
+ <command>uncolor</command>
+ <group choice="req">
+ <arg choice="plain">
+-<option>index</option>
++<option>index-object</option>
+ </arg>
+ <arg choice="plain">
+ <option>header</option>
+@@ -2687,8 +3283,8 @@ specify one or the other).
+ <para>
+ <emphasis>header</emphasis> and <emphasis>body</emphasis> match
+ <emphasis>regexp</emphasis> in the header/body of a message,
+-<emphasis>index</emphasis> matches <emphasis>pattern</emphasis> (see
+-<xref linkend="patterns"/>) in the message index.  Note that IMAP
++<emphasis>index-object</emphasis> can match <emphasis>pattern</emphasis>
++(see <xref linkend="patterns"/>) in the message index. Note that IMAP
+ server-side searches (=b, =B, =h) are not supported for color index
+ patterns.
+ </para>
+@@ -2702,10 +3298,19 @@ patterns.
+ <listitem><para>bold (highlighting bold patterns in the body of messages)</para></listitem>
+ <listitem><para>error (error messages printed by Mutt)</para></listitem>
+ <listitem><para>hdrdefault (default color of the message header in the pager)</para></listitem>
++<listitem><para>index_author (color of the author name in the index, uses <emphasis>pattern</emphasis>)</para></listitem>
++<listitem><para>index_collapsed (the number of messages in a collapsed thread in the index)</para></listitem>
++<listitem><para>index_date (color of the date field in the index)</para></listitem>
++<listitem><para>index_flags (color of the message flags in the index)</para></listitem>
++<listitem><para>index_label (color of the message label in the index)</para></listitem>
++<listitem><para>index_number (color of the message number in the index)</para></listitem>
++<listitem><para>index_size (color of the message size and line number in the index)</para></listitem>
++<listitem><para>index_subject (color of the subject in the index, uses <emphasis>pattern</emphasis>)</para></listitem>
+ <listitem><para>indicator (arrow or bar used to indicate the current item in a menu)</para></listitem>
+ <listitem><para>markers (the <quote>+</quote> markers at the beginning of wrapped lines in the pager)</para></listitem>
+ <listitem><para>message (informational messages)</para></listitem>
+ <listitem><para>normal</para></listitem>
++<listitem><para><link linkend="progress">progress</link> (visual progress bar)</para></listitem>
+ <listitem><para>prompt</para></listitem>
+ <listitem><para>quoted (text matching <link linkend="quote-regexp">$quote_regexp</link> in the body of a message)</para></listitem>
+ <listitem><para>quoted1, quoted2, ..., quoted<emphasis>N</emphasis> (higher levels of quoting)</para></listitem>
+@@ -2717,6 +3322,24 @@ patterns.
+ </itemizedlist>
  
--static void print_enriched_string (int attr, unsigned char *s, int do_color)
-+/**
-+ * get_color - XXX
-+ */
-+static int
-+get_color (int index, unsigned char *s)
-+{
-+	COLOR_LINE *color;
-+	HEADER *hdr = Context->hdrs[Context->v2r[index]];
-+	int type = *s;
+ <para>
++<emphasis>index-object</emphasis> can be one of the following:
++</para>
 +
-+	switch (type) {
-+		case MT_COLOR_INDEX_AUTHOR:
-+			color = ColorIndexAuthorList;
-+			break;
-+		case MT_COLOR_INDEX_FLAGS:
-+			color = ColorIndexFlagsList;
-+			break;
-+		case MT_COLOR_INDEX_SUBJECT:
-+			color = ColorIndexSubjectList;
-+			break;
-+#ifdef USE_NOTMUCH
-+                case MT_COLOR_INDEX_TAG:
-+                        for (color = ColorIndexTagList; color; color = color->next)
-+                        {
-+				const char * transform = hash_find(TagTransforms, color->pattern);
-+				if (transform && (strncmp((const char *)(s+1),
-+				    transform, strlen(transform)) == 0))
-+					return color->pair;
-+                        }
-+                        return 0;
-+#endif
-+		default:
-+			return ColorDefs[type];
-+	}
++<itemizedlist>
++<listitem><para>index (default highlighting of the entire index line, uses <emphasis>pattern</emphasis>)</para></listitem>
++<listitem><para>index_date (the date field)</para></listitem>
++<listitem><para>index_flags (the message flags, %S %Z, uses <emphasis>pattern</emphasis>)</para></listitem>
++<listitem><para>index_number (the message number, %C)</para></listitem>
++<listitem><para>index_collapsed (the number of messages in a collapsed thread, %M)</para></listitem>
++<listitem><para>index_author (the author name, %A %a %F %L %n, uses <emphasis>pattern</emphasis>)</para></listitem>
++<listitem><para>index_subject (the subject, %s, uses <emphasis>pattern</emphasis>)</para></listitem>
++<listitem><para>index_size (the message size, %c %l)</para></listitem>
++<listitem><para>index_label (the message label, %y %Y)</para></listitem>
++<listitem><para>index_tags (the transformed message tags, %g)</para></listitem>
++<listitem><para>index_tag (an individual message tag, %G, uses <emphasis>pattern / tag name</emphasis>)</para></listitem>
++</itemizedlist>
 +
-+	for (; color; color = color->next)
-+		if (mutt_pattern_exec (color->color_pattern, M_MATCH_FULL_ADDRESS,
-+		    Context, hdr))
-+			return color->pair;
++<para>
+ <emphasis>foreground</emphasis> and <emphasis>background</emphasis> can
+ be one of the following:
+ </para>
+@@ -2833,7 +3456,7 @@ command. Usage:
+ <command>unmono</command>
+ <group choice="req">
+ <arg choice="plain">
+-<option>index</option>
++<option>index-object</option>
+ </arg>
+ <arg choice="plain">
+ <option>header</option>
+@@ -4532,8 +5155,8 @@ Mutt adds some other modifiers to format strings. If you use an equals
+ symbol (<literal>=</literal>) as a numeric prefix (like the minus
+ above), it will force the string to be centered within its minimum space
+ range. For example, <literal>%=14y</literal> will reserve 14 characters
+-for the %y expansion — that's the X-Label: header, in <link
+-linkend="index-format">$index_format</link>. If the expansion results in
++for the %y expansion — that's the set of message keywords (formerly
++X-Label).  If the expansion results in
+ a string less than 14 characters, it will be centered in a 14-character
+ space.  If the X-Label for a message were <quote>test</quote>, that
+ expansion would look like
+@@ -4595,6 +5218,18 @@ If the value of <emphasis>sequence_char</emphasis> is non-zero,
+ <emphasis>else_string</emphasis> will be expanded.
+ </para>
+ 
++<para>
++The conditional sequences can also be nested by using the %< and >
++operators. The %? notation can still be used but requires quoting. For example:
++</para>
 +
-+	return 0;
-+}
++<screen>
++%<x?true&false>
++%<x?%<y?%<z?xyz&xy>&x>&none>
++</screen>
 +
-+static void print_enriched_string (int index, int attr, unsigned char *s, int do_color)
- {
-   wchar_t wc;
-   size_t k;
-@@ -159,6 +205,22 @@
-       }
-       if (do_color) ATTRSET(attr);
-     }
-+    else if (*s == M_SPECIAL_INDEX) {
-+      s++;
-+      if (do_color) {
-+        if (*s == MT_COLOR_INDEX) {
-+          attrset (attr);
-+	} else {
-+          if (get_color (index, s) == 0) {
-+            attron (attr);
-+	  } else {
-+            attron (get_color (index, s));
-+	  }
-+        }
-+      }
-+      s++;
-+      n -= 2;
-+    }
-     else if ((k = mbrtowc (&wc, (char *)s, n, &mbstate)) > 0)
-     {
-       addnstr ((char *)s, k);
-@@ -184,7 +246,7 @@
- {
-   char *scratch = safe_strdup (s);
-   int shift = option (OPTARROWCURSOR) ? 3 : 0;
--  int cols = COLS - shift;
-+  int cols = COLS - shift - SidebarWidth;
- 
-   mutt_format_string (s, n, cols, cols, FMT_LEFT, ' ', scratch, mutt_strlen (scratch), 1);
-   s[n - 1] = 0;
-@@ -237,6 +299,9 @@
-   int do_color;
-   int attr;
- 
-+#ifdef USE_SIDEBAR
-+  mutt_sb_draw();
-+#endif
-   for (i = menu->top; i < menu->top + menu->pagelen; i++)
-   {
-     if (i < menu->max)
-@@ -247,7 +312,7 @@
-       menu_pad_string (buf, sizeof (buf));
- 
-       ATTRSET(attr);
--      move(i - menu->top + menu->offset, 0);
-+      move(i - menu->top + menu->offset, SidebarWidth);
-       do_color = 1;
- 
-       if (i == menu->current)
-@@ -265,12 +330,16 @@
-       else if (option(OPTARROWCURSOR))
- 	addstr("   ");
- 
--      print_enriched_string (attr, (unsigned char *) buf, do_color);
-+      print_enriched_string (i, attr, (unsigned char *) buf, do_color);
-     }
-     else
-     {
-       NORMAL_COLOR;
-+#ifdef USE_SIDEBAR
-+      CLEARLINE_WIN(i - menu->top + menu->offset);
-+#else
-       CLEARLINE(i - menu->top + menu->offset);
-+#endif
-     }
-   }
-   NORMAL_COLOR;
-@@ -287,7 +356,7 @@
-     return;
-   }
-   
--  move (menu->oldcurrent + menu->offset - menu->top, 0);
-+  move (menu->oldcurrent + menu->offset - menu->top, SidebarWidth);
-   ATTRSET(menu->color (menu->oldcurrent));
++<para>For more examples, see <xref linkend="nested-if"/></para>
++
+ </sect2>
  
-   if (option (OPTARROWCURSOR))
-@@ -299,27 +368,27 @@
-     {
-       menu_make_entry (buf, sizeof (buf), menu, menu->oldcurrent);
-       menu_pad_string (buf, sizeof (buf));
--      move (menu->oldcurrent + menu->offset - menu->top, 3);
--      print_enriched_string (menu->color(menu->oldcurrent), (unsigned char *) buf, 1);
-+      move (menu->oldcurrent + menu->offset - menu->top, SidebarWidth + 3);
-+      print_enriched_string (menu->oldcurrent, menu->color (menu->oldcurrent), (unsigned char *) buf, 1);
-     }
+ <sect2 id="formatstrings-filters">
+@@ -4701,6 +5336,27 @@ set index_format="%4C %Z %{%b %d} %-15.15L (%?l?%4l&%4c?)%*  %s"</screen>
  
-     /* now draw it in the new location */
-     SETCOLOR(MT_COLOR_INDICATOR);
--    mvaddstr(menu->current + menu->offset - menu->top, 0, "->");
-+    mvaddstr(menu->current + menu->offset - menu->top, SidebarWidth, "->");
-   }
-   else
-   {
-     /* erase the current indicator */
-     menu_make_entry (buf, sizeof (buf), menu, menu->oldcurrent);
-     menu_pad_string (buf, sizeof (buf));
--    print_enriched_string (menu->color(menu->oldcurrent), (unsigned char *) buf, 1);
-+    print_enriched_string (menu->oldcurrent, menu->color (menu->oldcurrent), (unsigned char *) buf, 1);
+ </sect2>
  
-     /* now draw the new one to reflect the change */
-     menu_make_entry (buf, sizeof (buf), menu, menu->current);
-     menu_pad_string (buf, sizeof (buf));
-     SETCOLOR(MT_COLOR_INDICATOR);
--    move(menu->current - menu->top + menu->offset, 0);
--    print_enriched_string (menu->color(menu->current), (unsigned char *) buf, 0);
-+    move (menu->current - menu->top + menu->offset, SidebarWidth);
-+    print_enriched_string (menu->current, menu->color (menu->current), (unsigned char *) buf, 0);
-   }
-   menu->redraw &= REDRAW_STATUS;
-   NORMAL_COLOR;
-@@ -330,7 +399,7 @@
-   char buf[LONG_STRING];
-   int attr = menu->color (menu->current);
-   
--  move (menu->current + menu->offset - menu->top, 0);
-+  move (menu->current + menu->offset - menu->top, SidebarWidth);
-   menu_make_entry (buf, sizeof (buf), menu, menu->current);
-   menu_pad_string (buf, sizeof (buf));
++<sect2 id="formatstrings-conditional-dates">
++<title>Conditional Dates</title>
++<para>
++This patch allows the format of dates in the index to vary based on how recent
++the message is. This is especially useful in combination with David Champion's
++patch to allow if-else sequences to be nested.
++</para>
++
++<para>
++For example, using
++<literal>%<[y?%<[d?%[%H:%M]&%[%m/%d]>&%[%y.%m]></literal>
++for the date in the <literal>$index_format</literal> will produce a display like:
++</para>
++
++<screen>
++   1   + 14.12 Grace Hall      (   13) Gulliver's Travels
++   2   + 10/02 Callum Harrison (   48) Huckleberry Finn
++   3     12:17 Rhys Lee        (   42) The Lord Of The Rings
++</screen>
++</sect2>
++
+ </sect1>
  
-@@ -341,10 +410,10 @@
-     ATTRSET(attr);
-     addch (' ');
-     menu_pad_string (buf, sizeof (buf));
--    print_enriched_string (attr, (unsigned char *) buf, 1);
-+    print_enriched_string (menu->current, attr, (unsigned char *) buf, 1);
-   }
-   else
--    print_enriched_string (attr, (unsigned char *) buf, 0);
-+    print_enriched_string (menu->current, attr, (unsigned char *) buf, 0);
-   menu->redraw &= REDRAW_STATUS;
-   NORMAL_COLOR;
- }
-@@ -873,7 +942,7 @@
-     
-     
-     if (option (OPTARROWCURSOR))
--      move (menu->current - menu->top + menu->offset, 2);
-+      move (menu->current - menu->top + menu->offset, SidebarWidth + 2);
-     else if (option (OPTBRAILLEFRIENDLY))
-       move (menu->current - menu->top + menu->offset, 0);
-     else
-diff -urN mutt-1.6.1/mh.c mutt-1.6.1-neomutt/mh.c
---- mutt-1.6.1/mh.c	2016-06-12 18:43:00.410447715 +0100
-+++ mutt-1.6.1-neomutt/mh.c	2016-06-12 18:43:00.715452471 +0100
-@@ -56,6 +56,10 @@
- #include <sys/time.h>
- #endif
+ <sect1 id="mailto-allow">
+@@ -5126,7 +5782,7 @@ shows several ways to select messages.
+ <row><entry>~V</entry><entry>cryptographically verified messages</entry></row>
+ <row><entry>~x <emphasis>EXPR</emphasis></entry><entry>messages which contain <emphasis>EXPR</emphasis> in the <quote>References</quote> or <quote>In-Reply-To</quote> field</entry></row>
+ <row><entry>~X [<emphasis>MIN</emphasis>]-[<emphasis>MAX</emphasis>]</entry><entry>messages with <emphasis>MIN</emphasis> to <emphasis>MAX</emphasis> attachments *)</entry></row>
+-<row><entry>~y <emphasis>EXPR</emphasis></entry><entry>messages which contain <emphasis>EXPR</emphasis> in the <quote>X-Label</quote> field</entry></row>
++<row><entry>~y <emphasis>EXPR</emphasis></entry><entry>messages which contain <emphasis>EXPR</emphasis> in their keywords</entry></row>
+ <row><entry>~z [<emphasis>MIN</emphasis>]-[<emphasis>MAX</emphasis>]</entry><entry>messages with a size in the range <emphasis>MIN</emphasis> to <emphasis>MAX</emphasis> *) **)</entry></row>
+ <row><entry>~=</entry><entry>duplicated messages (see <link linkend="duplicate-threads">$duplicate_threads</link>)</entry></row>
+ <row><entry>~$</entry><entry>unreferenced messages (requires threaded view)</entry></row>
+@@ -5521,12 +6177,24 @@ option/command.  See:
  
-+#ifdef USE_NOTMUCH
-+#include "mutt_notmuch.h"
-+#endif
+ <listitem>
+ <para>
++<link linkend="append-hook"><command>append-hook</command></link>
++</para>
++</listitem>
 +
- #define		INS_SORT_THRESHOLD		6
++<listitem>
++<para>
+ <link linkend="charset-hook"><command>charset-hook</command></link>
+ </para>
+ </listitem>
  
- struct maildir
-@@ -295,6 +299,48 @@
-   mhs_free_sequences (&mhs);
- }
+ <listitem>
+ <para>
++<link linkend="close-hook"><command>close-hook</command></link>
++</para>
++</listitem>
++
++<listitem>
++<para>
+ <link linkend="crypt-hook"><command>crypt-hook</command></link>
+ </para>
+ </listitem>
+@@ -5569,6 +6237,12 @@ option/command.  See:
  
-+#ifdef USE_SIDEBAR
-+/**
-+ * mh_buffy_update - Update messages counts for an mh mailbox
-+ * @mailbox: BUFFY representing a maildir mailbox
-+ *
-+ * Read through an mh mailbox and count messages.  Save the number of new,
-+ * flagged messages and a timestamp for now.
-+ */
-+void
-+mh_buffy_update (BUFFY *mailbox)
-+{
-+  int i;
-+  struct mh_sequences mhs;
+ <listitem>
+ <para>
++<link linkend="open-hook"><command>open-hook</command></link>
++</para>
++</listitem>
 +
-+  if (!mailbox)
-+    return;
++<listitem>
++<para>
+ <link linkend="reply-hook"><command>reply-hook</command></link>
+ </para>
+ </listitem>
+@@ -5978,18 +6652,6 @@ field.  When set to <emphasis>yes</emphasis>, the
+ </para>
+ 
+ <para>
+-The <quote>X-Label:</quote> header field can be used to further identify
+-mailing lists or list subject matter (or just to annotate messages
+-individually).  The <link linkend="index-format">$index_format</link>
+-variable's <quote>%y</quote> and <quote>%Y</quote> expandos can be used
+-to expand <quote>X-Label:</quote> fields in the index, and Mutt's
+-pattern-matcher can match regular expressions to <quote>X-Label:</quote>
+-fields with the <quote>~y</quote> selector.  <quote>X-Label:</quote> is
+-not a standard message header field, but it can easily be inserted by
+-procmail and other mail filtering agents.
+-</para>
+-
+-<para>
+ Lastly, Mutt has the ability to <link linkend="sort">sort</link> the
+ mailbox into <link linkend="threads">threads</link>.  A thread is a
+ group of messages which all relate to the same subject.  This is usually
+@@ -6002,6 +6664,121 @@ threads and quickly find topics of value.
+ 
+ </sect1>
+ 
++<sect1 id="using-keywords">
++<title>Keyword Management</title>
 +
-+  if (!option (OPTSIDEBAR))
-+    return;
++<para>
++Mutt has supported textual labels (usually known as X-Labels after
++the header that we use to store them) for many years.  Since we
++initially added support for X-Lanels, however, the larger community
++has evolved more common ways of using and managing such labels, often
++known as <quote>keywords</quote> or <quote>tags</quote>.
++</para>
++
++<para>
++If you are new to Mutt or to using keywords in Mutt, you only need
++to know that the <edit-label> binding (<literal>y</literal> by
++default) will edit keywords, and that you can search for keywords
++using the <literal>~y</literal> pattern, and use the <literal>%y</literal>
++expando to display it in your <literal>$index_format</literal>.  You also
++can sort by keyword.  Keywords that you set will be stored to the
++<literal>X-Label:</literal> header by default.
++</para>
++
++<para>
++If you've been using X-Labels for a while, things have grown slightly.
++Mutt still supports X-Labels much as it has since 2000, but the scope
++of this support has expanded to support three additional header-based
++techniques for storing keyword metadata on messages:
++</para>
 +
-+  memset (&mhs, 0, sizeof (mhs));
++<variablelist>
++
++<varlistentry>
++<term>X-Keywords</term>
++<listitem>
++<para>
++Informal design; space-delimited keywords
++</para>
++</listitem>
++</varlistentry>
++
++<varlistentry>
++<term>X-Mozilla-Keys</term>
++<listitem>
++<para>
++Informal design used by Mozilla-based agents; space-delimited keywords
++</para>
++</listitem>
++</varlistentry>
++
++<varlistentry>
++<term>Keywords</term>
++<listitem>
++<para>
++Standardized in RFC2822 (2001); comma-space-delimited keywords
++</para>
++</listitem>
++</varlistentry>
++
++<varlistentry>
++<term>X-Label</term>
++<listitem>
++<para>
++Mutt-specific design; freeform text (but see <link linkend="xlabel-delimiter">$xlabel_delimiter</link>)
++</para>
++</listitem>
++</varlistentry>
++
++</variablelist>
++
++<para>
++With X-Label, mutt's only notion of a message keyword was the literal
++string value of the X-Label header.  Under the new, integrated support,
++each message may have a list of distinct message keywords.  When reading
++keywords from one of the headers in the list above, the header value is
++split on the indicated delimiter (space or comma-space) for X-Keywords:,
++X-Mozilla-Keys:, and Keywords:.  By default, X-Label: is parsed as a
++single keyword.  By setting $xlabel_delimiter, you can force splitting
++of X-Label: as well.
++</para>
++
++<para>
++Two boolean variables control how keywords are saved when writing
++messages to a mailbox.  The default settings preserve backward
++compatibility within mutt completely, but by changing these
++values you can transition to more standard keyword storage. <link
++linkend="keywords-legacy">$keywords_legacy</link>, if set, will tell
++mutt to use only "legacy" headers -- i.e., <literal>X-Keywords:</literal>,
++<literal>X-Mozilla-Keys</literal>, <literal>Keywords</literal>, or
++<literal>X-Label:</literal>.  Keywords will be saved to whichever
++header was in use by the message the keyword was read from.  If
++<link linkend="keywords-standard">$keywords_standard</link> is
++set, keywords will be saved without exception to the standard
++<literal>Keywords:</literal> header.  (If both are set, both will be used;
++if both are unset, legacy headers are used.)  Additionally, <link
++linkend="xlabel-delimiter">$xlabel_delimiter</link> is used to format
++the X-Label: header on saves.
++</para>
 +
-+  if (mh_read_sequences (&mhs, mailbox->path) < 0)
-+    return;
++<para>
++To migrate completely to the new standard,
++unset <literal>$keywords_legacy</literal> and set
++<literal>$keywords_standard</literal>, and set
++<literal>$xlabel_delimiter</literal> either to what you currently use to
++delimit keywords in X-Labels, or to <quote>, </quote> (comma
++space).
++</para>
 +
-+  mailbox->msg_count   = 0;
-+  mailbox->msg_unread  = 0;
-+  mailbox->msg_flagged = 0;
++<para>
++Note that it is common practice to insert <literal>X-Label:</literal> or
++other keyword headers from proxmail or other mail filters.  This is
++a useful trick for categorizing messages en masse as they are delivered
++to your inbox, and it is fully compatible with the new keywords code.
++</para>
 +
-+  for (i = 0; i <= mhs.max; i++)
-+  {
-+    mailbox->msg_count++;
-+    if (mhs_check (&mhs, i) & MH_SEQ_UNSEEN)
-+      mailbox->msg_unread++;
-+    if (mhs_check (&mhs, i) & MH_SEQ_FLAGGED)
-+      mailbox->msg_flagged++;
-+  }
-+  mhs_free_sequences (&mhs);
-+  mailbox->sb_last_checked = time (NULL);
-+}
-+#endif
++</sect1>
 +
- static int mh_mkstemp (CONTEXT * dest, FILE ** fp, char **tgt)
- {
-   int fd;
-@@ -304,8 +350,8 @@
-   omask = umask (mh_umask (dest));
-   FOREVER
-   {
--    snprintf (path, _POSIX_PATH_MAX, "%s/.mutt-%s-%d-%d",
--	      dest->path, NONULL (Hostname), (int) getpid (), Counter++);
-+    snprintf (path, _POSIX_PATH_MAX, "%s/.mutt-%s-%d-%" PRIu64,
-+	      dest->path, NONULL (Hostname), (int) getpid (), mutt_rand64());
-     if ((fd = open (path, O_WRONLY | O_EXCL | O_CREAT, 0666)) == -1)
-     {
-       if (errno != EEXIST)
-@@ -610,7 +656,7 @@
-   }
- }
- 
--static void maildir_parse_flags (HEADER * h, const char *path)
-+void maildir_parse_flags (HEADER * h, const char *path)
- {
-   char *p, *q = NULL;
- 
-@@ -693,40 +739,51 @@
-  * Actually parse a maildir message.  This may also be used to fill
-  * out a fake header structure generated by lazy maildir parsing.
-  */
--static HEADER *maildir_parse_message (int magic, const char *fname,
-+HEADER *maildir_parse_stream (int magic, FILE *f, const char *fname,
- 				      int is_old, HEADER * _h)
- {
--  FILE *f;
-   HEADER *h = _h;
-   struct stat st;
- 
--  if ((f = fopen (fname, "r")) != NULL)
--  {
--    if (!h)
--      h = mutt_new_header ();
--    h->env = mutt_read_rfc822_header (f, h, 0, 0);
-+  if (!h)
-+    h = mutt_new_header ();
-+  h->env = mutt_read_rfc822_header (f, h, 0, 0);
+ <sect1 id="new-mail">
+ <title>New Mail Detection</title>
  
--    fstat (fileno (f), &st);
--    safe_fclose (&f);
-+  fstat (fileno (f), &st);
+@@ -6047,7 +6824,10 @@ New mail for Maildir is assumed if there is one message in the
+ <link linkend="maildir-trash">$maildir_trash</link>). For MH folders, a
+ mailbox is considered having new mail if there's at least one message in
+ the <quote>unseen</quote> sequence as specified by <link
+-linkend="mh-seq-unseen">$mh_seq_unseen</link>.
++linkend="mh-seq-unseen">$mh_seq_unseen</link>. Optionally, <link
++linkend="new-mail-command">$new_mail_command</link> can be configured to
++execute an external program every time new mail is detected in the current
++inbox.
+ </para>
  
--    if (!h->received)
--      h->received = h->date_sent;
-+  if (!h->received)
-+    h->received = h->date_sent;
+ <para>
+@@ -6062,6 +6842,14 @@ linkend="imap-idle">$imap_idle</link> option is set, it'll use the IMAP
+ IDLE extension if advertised by the server.
+ </para>
  
--    /* always update the length since we have fresh information available. */
--    h->content->length = st.st_size - h->content->offset;
-+  /* always update the length since we have fresh information available. */
-+  h->content->length = st.st_size - h->content->offset;
++<para>
++The <link linkend="mail-check-recent">$mail_check_recent</link>
++option changes whether Mutt will notify you of new mail in an
++already visited mailbox.  When set (the default) it will only notify
++you of new mail received since the last time you opened the mailbox.
++When unset, Mutt will notify you of any new mail in the mailbox.
++</para>
++
+ </sect2>
  
--    h->index = -1;
-+  h->index = -1;
+ <sect2 id="new-mail-polling">
+@@ -6110,6 +6898,26 @@ to immediately open the next folder with unread mail (if any).
  
--    if (magic == M_MAILDIR)
--    {
--      /* 
--       * maildir stores its flags in the filename, so ignore the
--       * flags in the header of the message 
--       */
-+  if (magic == M_MAILDIR)
-+  {
-+    /*
-+     * maildir stores its flags in the filename, so ignore the
-+     * flags in the header of the message
-+     */
+ </sect2>
  
--      h->old = is_old;
--      maildir_parse_flags (h, fname);
--    }
-+    h->old = is_old;
-+    maildir_parse_flags (h, fname);
-+  }
-+  return h;
-+}
++<sect2 id="calc-mailbox-counts">
++<title>Calculating Mailbox Message Counts</title>
 +
-+/*
-+ * Actually parse a maildir message.  This may also be used to fill
-+ * out a fake header structure generated by lazy maildir parsing.
-+ */
-+HEADER *maildir_parse_message (int magic, const char *fname,
-+				      int is_old, HEADER * h)
-+{
-+  FILE *f;
++<para>
++If <link linkend="mail-check-stats">$mail_check_stats</link> is set,
++Mutt will periodically calculate the unread, flagged, and total
++message counts for each mailbox watched by the
++<command>mailboxes</command> command.  This calculation takes place at
++the same time as new mail polling, but is controlled by a separate
++timer: <link
++linkend="mail-check-stats-interval">$mail_check_stats_interval</link>.
++</para>
 +
-+  if ((f = fopen (fname, "r")) != NULL) {
-+    h = maildir_parse_stream (magic, f, fname, is_old, h);
-+    safe_fclose (&f);
-     return h;
-   }
-   return NULL;
-@@ -1249,7 +1306,7 @@
-   return (int)( *((const char *) a) - *((const char *) b));
- }
- 
--static void maildir_flags (char *dest, size_t destlen, HEADER * hdr)
-+void maildir_flags (char *dest, size_t destlen, HEADER * hdr)
- {
-   *dest = '\0';
- 
-@@ -1313,9 +1370,9 @@
-   omask = umask (mh_umask (dest));
-   FOREVER
-   {
--    snprintf (path, _POSIX_PATH_MAX, "%s/tmp/%s.%lld.%u_%d.%s%s",
--	      dest->path, subdir, (long long)time (NULL), (unsigned int)getpid (),
--	      Counter++, NONULL (Hostname), suffix);
-+    snprintf (path, _POSIX_PATH_MAX, "%s/tmp/%s.%lld.R%" PRIu64 ".%s%s",
-+	      dest->path, subdir, (long long)time (NULL), mutt_rand64(),
-+              NONULL (Hostname), suffix);
- 
-     dprint (2, (debugfile, "maildir_open_new_message (): Trying %s.\n",
- 		path));
-@@ -1399,8 +1456,8 @@
-   /* construct a new file name. */
-   FOREVER
-   {
--    snprintf (path, _POSIX_PATH_MAX, "%s/%lld.%u_%d.%s%s", subdir,
--	      (long long)time (NULL), (unsigned int)getpid (), Counter++,
-+    snprintf (path, _POSIX_PATH_MAX, "%s/%lld.R%" PRIu64 ".%s%s", subdir,
-+	      (long long)time (NULL), mutt_rand64(),
- 	      NONULL (Hostname), suffix);
-     snprintf (full, _POSIX_PATH_MAX, "%s/%s", ctx->path, path);
- 
-@@ -1409,10 +1466,6 @@
- 
-     if (safe_rename (msg->path, full) == 0)
-     {
--      if (hdr)
--	mutt_str_replace (&hdr->path, path);
--      FREE (&msg->path);
--
-       /*
-        * Adjust the mtime on the file to match the time at which this
-        * message was received.  Currently this is only set when copying
-@@ -1428,11 +1481,23 @@
- 	if (utime (full, &ut))
- 	{
- 	  mutt_perror (_("maildir_commit_message(): unable to set time on file"));
--	  return -1;
-+	  goto post_rename_err;
- 	}
-       }
- 
-+#ifdef USE_NOTMUCH
-+      if (ctx->magic == M_NOTMUCH)
-+	nm_update_filename(ctx, hdr->path, full, hdr);
-+#endif
-+      if (hdr)
-+	mutt_str_replace (&hdr->path, path);
-+      mutt_str_replace (&msg->commited_path, full);
-+      FREE (&msg->path);
++<para>
++The sidebar can display these message counts.  See <link
++linkend="sidebar-format">$sidebar_format</link>.
++</para>
 +
-       return 0;
++</sect2>
 +
-+post_rename_err:
-+      return -1;
-     }
-     else if (errno != EEXIST)
-     {
-@@ -1508,6 +1573,7 @@
-     {
-       if (hdr)
- 	mutt_str_replace (&hdr->path, tmp);
-+      mutt_str_replace (&msg->commited_path, path);
-       FREE (&msg->path);
-       break;
-     }
-@@ -1612,7 +1678,7 @@
- {
-   HEADER *h = ctx->hdrs[msgno];
- 
--  if (h->attach_del || 
-+  if (h->attach_del || h->label_changed ||
-       (h->env && (h->env->refs_changed || h->env->irt_changed)))
-     if (mh_rewrite_message (ctx, msgno) != 0)
-       return -1;
-@@ -1624,7 +1690,7 @@
- {
-   HEADER *h = ctx->hdrs[msgno];
- 
--  if (h->attach_del || 
-+  if (h->attach_del || h->label_changed ||
-       (h->env && (h->env->refs_changed || h->env->irt_changed)))
-   {
-     /* when doing attachment deletion/rethreading, fall back to the MH case. */
-@@ -1683,96 +1749,114 @@
-   return (0);
- }
+ </sect1>
  
--int mh_sync_mailbox (CONTEXT * ctx, int *index_hint)
--{
--  char path[_POSIX_PATH_MAX], tmp[_POSIX_PATH_MAX];
--  int i, j;
--#if USE_HCACHE
--  header_cache_t *hc = NULL;
--#endif /* USE_HCACHE */
--  char msgbuf[STRING];
--  progress_t progress;
--
--  if (ctx->magic == M_MH)
--    i = mh_check_mailbox (ctx, index_hint);
--  else 
--    i = maildir_check_mailbox (ctx, index_hint);
--      
--  if (i != 0)
--    return i;
--
- #if USE_HCACHE
--  if (ctx->magic == M_MAILDIR || ctx->magic == M_MH)
--    hc = mutt_hcache_open(HeaderCache, ctx->path, NULL);
--#endif /* USE_HCACHE */
--
--  if (!ctx->quiet)
--  {
--    snprintf (msgbuf, sizeof (msgbuf), _("Writing %s..."), ctx->path);
--    mutt_progress_init (&progress, msgbuf, M_PROGRESS_MSG, WriteInc, ctx->msgcount);
--  }
--
--  for (i = 0; i < ctx->msgcount; i++)
--  {
--    if (!ctx->quiet)
--      mutt_progress_update (&progress, i, -1);
-+int mh_sync_mailbox_message (CONTEXT * ctx, int msgno, header_cache_t *hc)
-+#else
-+int mh_sync_mailbox_message (CONTEXT * ctx, int msgno)
-+#endif
-+{
-+    char path[_POSIX_PATH_MAX], tmp[_POSIX_PATH_MAX];
-+    HEADER *h = ctx->hdrs[msgno];
+ <sect1 id="editing-threads">
+@@ -6773,6 +7581,17 @@ to display the results.
+ </para>
  
--    if (ctx->hdrs[i]->deleted
--	&& (ctx->magic != M_MAILDIR || !option (OPTMAILDIRTRASH)))
-+    if (h->deleted && (ctx->magic != M_MAILDIR || !option (OPTMAILDIRTRASH)))
-     {
--      snprintf (path, sizeof (path), "%s/%s", ctx->path, ctx->hdrs[i]->path);
-+      snprintf (path, sizeof (path), "%s/%s", ctx->path, h->path);
-       if (ctx->magic == M_MAILDIR
- 	  || (option (OPTMHPURGE) && ctx->magic == M_MH))
-       {
- #if USE_HCACHE
--        if (ctx->magic == M_MAILDIR)
--          mutt_hcache_delete (hc, ctx->hdrs[i]->path + 3, &maildir_hcache_keylen);
--	else if (ctx->magic == M_MH)
--	  mutt_hcache_delete (hc, ctx->hdrs[i]->path, strlen);
-+	if (hc) {
-+           if (ctx->magic == M_MAILDIR)
-+              mutt_hcache_delete (hc, h->path + 3, &maildir_hcache_keylen);
-+	   else if (ctx->magic == M_MH)
-+	      mutt_hcache_delete (hc, h->path, strlen);
-+	}
- #endif /* USE_HCACHE */
- 	unlink (path);
-       }
-       else if (ctx->magic == M_MH)
-       {
- 	/* MH just moves files out of the way when you delete them */
--	if (*ctx->hdrs[i]->path != ',')
-+	if (*h->path != ',')
- 	{
--	  snprintf (tmp, sizeof (tmp), "%s/,%s", ctx->path,
--		    ctx->hdrs[i]->path);
-+	  snprintf (tmp, sizeof (tmp), "%s/,%s", ctx->path, h->path);
- 	  unlink (tmp);
- 	  rename (path, tmp);
- 	}
+ <para>
++Mutt will set the <literal>COLUMNS</literal> environment variable to
++the width of the pager.  Some programs make use of this environment
++variable automatically.  Others provide a command line argument that
++can use this to set the output width:
++</para>
++
++<screen>
++text/html; lynx -dump -width ${COLUMNS:-80} %s; copiousoutput
++</screen>
++
++<para>
+ Note that when using the built-in pager, <emphasis>only</emphasis>
+ entries with this flag will be considered a handler for a MIME type
+ — all other entries will be ignored.
+@@ -7467,6 +8286,16 @@ would contain:
  
-       }
-     }
--    else if (ctx->hdrs[i]->changed || ctx->hdrs[i]->attach_del ||
-+    else if (h->changed || h->attach_del ||
-+	     h->label_changed ||
- 	     (ctx->magic == M_MAILDIR
--	      && (option (OPTMAILDIRTRASH) || ctx->hdrs[i]->trash)
--	      && (ctx->hdrs[i]->deleted != ctx->hdrs[i]->trash)))
-+	      && (option (OPTMAILDIRTRASH) || h->trash)
-+	      && (h->deleted != h->trash)))
-     {
-       if (ctx->magic == M_MAILDIR)
-       {
--	if (maildir_sync_message (ctx, i) == -1)
--	  goto err;
-+	if (maildir_sync_message (ctx, msgno) == -1)
-+	  return -1;
-       }
-       else
-       {
--	if (mh_sync_message (ctx, i) == -1)
--	  goto err;
-+	if (mh_sync_message (ctx, msgno) == -1)
-+	  return -1;
-       }
-     }
+ </sect2>
  
- #if USE_HCACHE
--    if (ctx->hdrs[i]->changed)
-+    if (hc && h->changed)
-     {
-       if (ctx->magic == M_MAILDIR)
--	mutt_hcache_store (hc, ctx->hdrs[i]->path + 3, ctx->hdrs[i],
--			   0, &maildir_hcache_keylen, M_GENERATE_UIDVALIDITY);
-+	mutt_hcache_store (hc, h->path + 3, h, 0, &maildir_hcache_keylen, M_GENERATE_UIDVALIDITY);
-       else if (ctx->magic == M_MH)
--	mutt_hcache_store (hc, ctx->hdrs[i]->path, ctx->hdrs[i], 0, strlen, M_GENERATE_UIDVALIDITY);
-+	mutt_hcache_store (hc, h->path, h, 0, strlen, M_GENERATE_UIDVALIDITY);
-     }
- #endif
++<sect2 id="mutt-patches">
++<title>Mutt Patches</title>
++<para>
++Mutt may also be <quote>patched</quote> to support smaller features.
++These patches should add a free-form string to the end Mutt's version string.
++Running <literal>mutt -v</literal> might show:
++<screen>patch-1.6.2.sidebar.20160709</screen>
++</para>
++</sect2>
++
+ <sect2 id="url-syntax">
+ <title>URL Syntax</title>
  
-+    return 0;
-+}
+@@ -8081,6 +8910,4518 @@ please have a look at the mixmaster documentation.
+ 
+ </sect1>
+ 
++<sect1 id="compress">
++  <title>Compressed Folders Patch</title>
++  <subtitle>Read from/write to compressed mailboxes</subtitle>
++
++  <sect2 id="compress-patch">
++    <title>Patch</title>
++
++    <para>
++      To check if Mutt supports <quote>Compress Folders</quote>, look for
++      <quote>+USE_COMPRESSED</quote> in the mutt version.
++      See: <xref linkend="compile-time-features"/>.
++    </para>
++
++    <itemizedlist>
++      <title>Dependencies:</title>
++      <listitem><para>mutt-1.6.2</para></listitem>
++    </itemizedlist>
++
++    <para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
++  </sect2>
++
++  <sect2 id="compress-intro">
++    <title>Introduction</title>
++
++    <para>
++      The Compressed Folder patch allows Mutt to read mailbox files that are
++      compressed.  But it isn't limited to compressed files.  It works well
++      with encrypted files, too.  In fact, if you can create a program/script
++      to convert to and from your format, then Mutt can read it.
++    </para>
++
++    <para>
++      The patch adds three hooks to Mutt: <literal>open-hook</literal>,
++      <literal>close-hook</literal> and <literal>append-hook</literal>.  They
++      define commands to: uncompress a file; compress a file; append
++      messages to an already compressed file.
++    </para>
++
++    <para>
++      There are some examples of both compressed and encrypted files,
++      later.  For now, the documentation will just concentrate on
++      compressed files.
++    </para>
++
++  </sect2>
++
++<!--
++  <sect2 id="compress-variables">
++    <title>Variables</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="compress-functions">
++    <title>Functions</title>
++    <para>None</para>
++  </sect2>
++-->
++
++  <sect2 id="compress-commands">
++    <title>Commands</title>
++    <cmdsynopsis>
++      <command>open-hook</command>
++      <arg choice="plain">
++        <replaceable class="parameter">pattern</replaceable>
++      </arg>
++      <arg choice="plain">
++        <replaceable class="parameter">shell-command</replaceable>
++      </arg>
++      <command>close-hook</command>
++      <arg choice="plain">
++        <replaceable class="parameter">pattern</replaceable>
++      </arg>
++      <arg choice="plain">
++        <replaceable class="parameter">shell-command</replaceable>
++      </arg>
++      <command>append-hook</command>
++      <arg choice="plain">
++        <replaceable class="parameter">pattern</replaceable>
++      </arg>
++      <arg choice="plain">
++        <replaceable class="parameter">shell-command</replaceable>
++      </arg>
++    </cmdsynopsis>
++
++    <para>
++      The shell-command must contain two placeholders for filenames:
++      <literal>%f</literal> and <literal>%t</literal>.  These represent
++      <quote>from</quote> and <quote>to</quote> filenames.  It's a good idea to
++      put quotes around these placeholders.
++    </para>
++
++    <para>
++      If you need the exact string <quote>%f</quote> or <quote>%t</quote> in your
++      command, simply double up the <quote>%</quote> character, e.g.
++      <quote>%%f</quote> or <quote>%%t</quote>.
++    </para>
++
++    <table id="table-compress-optional">
++      <title>Not all Hooks are Required</title>
++      <tgroup cols="5">
++        <thead>
++          <row>
++            <entry>Open</entry>
++            <entry>Close</entry>
++            <entry>Append</entry>
++            <entry>Effect</entry>
++            <entry>Useful if</entry>
++          </row>
++        </thead>
++        <tbody>
++          <row>
++            <entry>Open</entry>
++            <entry>-</entry>
++            <entry>-</entry>
++            <entry>Folder is readonly</entry>
++            <entry>The folder is just a backup</entry>
++          </row>
++          <row>
++            <entry>Open</entry>
++            <entry>Close</entry>
++            <entry>-</entry>
++            <entry>Folder is read/write, but the entire folder must be
++              written if anything is changed</entry>
++            <entry>Your compression format doesn't support appending</entry>
++          </row>
++          <row>
++            <entry>Open</entry>
++            <entry>Close</entry>
++            <entry>Append</entry>
++            <entry>Folder is read/write and emails can be efficiently added
++              to the end</entry>
++            <entry>Your compression format supports appending</entry>
++          </row>
++          <row>
++            <entry>Open</entry>
++            <entry>-</entry>
++            <entry>Append</entry>
++            <entry>Folder is readonly, but can be appended to</entry>
++            <entry>You want to store emails, but never change them</entry>
++          </row>
++        </tbody>
++      </tgroup>
++    </table>
++
++    <note>
++      <para>The command:</para>
++      <itemizedlist>
++        <listitem><para>should return a non-zero exit status on failure</para></listitem>
++        <listitem><para>should not delete any files</para></listitem>
++      </itemizedlist>
++    </note>
++
++    <sect3 id="open-hook">
++      <title>Read from compressed mailbox</title>
++
++      <screen>open-hook regexp shell-command</screen>
++
++      <para>
++        If Mutt is unable to open a file, it then looks for
++        <literal>open-hook</literal> that matches the filename.
++      </para>
++
++      <para>
++        If your compression program doesn't have a well-defined extension,
++        then you can use <literal>.</literal> as the regexp.
++      </para>
++
++      <sect4 id="compress-open-hook-example">
++        <title>Example of open-hook</title>
++
++        <screen>open-hook '\.gz$' "gzip -cd '%f' > '%t'"</screen>
++
++        <itemizedlist>
++          <listitem><para>Mutt finds a file, <quote>example.gz</quote>,
++              that it can't read</para></listitem>
++          <listitem><para>Mutt has an <literal>open-hook</literal>
++              whose regexp matches the filename:
++              <literal>\.gz$</literal></para></listitem>
++          <listitem><para>Mutt uses the command <literal>gzip -cd</literal>
++              to create a temporary file that it <emphasis>can</emphasis>
++              read</para></listitem>
++        </itemizedlist>
++      </sect4>
++    </sect3>
++
++    <sect3 id="close-hook">
++      <title>Write to a compressed mailbox</title>
++
++      <screen>close-hook regexp shell-command</screen>
++
++      <para>
++        When Mutt has finished with a compressed mail folder, it will look
++        for a matching <literal>close-hook</literal> to recompress the file.
++        This hook is <link linkend="table-compress-optional">optional</link>.
++      </para>
++
++      <note>
++        <para>
++          If the folder has not been modifed, the
++          <literal>close-hook</literal> will not be called.
++        </para>
++      </note>
++
++      <sect4 id="compress-close-hook-example">
++        <title>Example of close-hook</title>
++
++        <screen>close-hook '\.gz$' "gzip -c '%t' > '%f'"</screen>
++
++        <itemizedlist>
++          <listitem><para>Mutt has finished with a folder, <quote>example.gz</quote>,
++              that it opened with <literal>open-hook</literal></para></listitem>
++          <listitem><para>The folder has been modified</para></listitem>
++          <listitem><para>Mutt has a <literal>close-hook</literal> whose regexp
++              matches the filename: <literal>\.gz$</literal></para></listitem>
++          <listitem><para>Mutt uses the command <literal>gzip -c</literal>
++              to create a new compressed file</para></listitem>
++        </itemizedlist>
++      </sect4>
++    </sect3>
++
++    <sect3 id="append-hook">
++      <title>Append to a compressed mailbox</title>
++
++      <screen>append-hook regexp shell-command</screen>
++
++      <para>
++        When Mutt wants to append an email to a compressed mail folder, it
++        will look for a matching <literal>append-hook</literal>.
++        This hook is <link linkend="table-compress-optional">optional</link>.
++      </para>
++
++      <para>
++        Using the <literal>append-hook</literal> will save time, but
++        Mutt won't be able to determine the type of the mail folder
++        inside the compressed file.
++      </para>
++
++      <para>
++        Mutt will <emphasis>assume</emphasis> the type to be that of
++        the <literal>$mbox_type</literal> variable.  Mutt also uses
++        this type for temporary files.
++      </para>
++
++      <para>
++        Mutt will only use the <literal>append-hook</literal> for existing files.
++        The <literal>close-hook</literal> will be used for empty, or missing files.
++      </para>
++
++      <sect4 id="compress-append-hook-example">
++        <title>Example of append-hook</title>
++
++        <screen>append-hook '\.gz$' "gzip -c '%t' >> '%f'"</screen>
++
++        <itemizedlist>
++          <listitem><para>Mutt wants to append an email to a folder, <quote>example.gz</quote>,
++              that it opened with <literal>open-hook</literal></para></listitem>
++          <listitem><para>Mutt has an <literal>append-hook</literal> whose regexp matches
++              the filename: <literal>\.gz$</literal></para></listitem>
++          <listitem><para>Mutt knows the mailbox type from the <literal>$mbox</literal>
++              variable</para></listitem>
++          <listitem><para>Mutt uses the command <literal>gzip -c</literal>
++              to append to an existing compressed file</para></listitem>
++        </itemizedlist>
++      </sect4>
++
++    </sect3>
++
++    <sect3 id="compress-empty">
++      <title>Empty Files</title>
++
++      <para>
++        Mutt assumes that an empty file is not compressed.  In this
++        situation, unset <link linkend="save-empty">$save_empty</link>, so
++        that the compressed file will be removed if you delete all of the
++        messages.
++      </para>
++    </sect3>
++
++    <sect3 id="compress-security">
++      <title>Security</title>
++
++      <para>
++        Encrypted files are decrypted into temporary files which are
++        stored in the <link linkend="tmpdir">$tmpdir</link> directory.
++        This could be a security risk.
++      </para>
++    </sect3>
++  </sect2>
++
++<!--
++  <sect2 id="compress-colors">
++    <title>Colors</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="compress-sort">
++    <title>Sort</title>
++    <para>None</para>
++  </sect2>
++-->
++
++  <sect2 id="compress-muttrc">
++    <title>Muttrc</title>
++<screen>
++<emphasis role="comment"># Example Mutt config file for the 'compressed folders' feature.
++ 
++# This feature adds three hooks to Mutt which allow it to
++# work with compressed, or encrypted, mailboxes.
++ 
++# The hooks are of the form:
++#       open-hook   regexp "shell-command"
++#       close-hook  regexp "shell-command"
++#       append-hook regexp "shell-command"
++ 
++# The 'append-hook' is optional.
++ 
++# Hander for gzip compressed mailboxes</emphasis>
++open-hook   '\.gz$'  "gzip -cd  '%f' >  '%t'"
++close-hook  '\.gz$'  "gzip -c   '%t' >  '%f'"
++append-hook '\.gz$'  "gzip -c   '%t' >> '%f'"
++ 
++<emphasis role="comment"># Hander for bzip2 compressed mailboxes</emphasis>
++open-hook   '\.bz2$' "bzip2 -cd '%f' >  '%t'"
++close-hook  '\.bz2$' "bzip2 -c  '%t' >  '%f'"
++append-hook '\.bz2$' "bzip2 -c  '%t' >> '%f'"
++ 
++<emphasis role="comment"># Hander for xz compressed mailboxes</emphasis>
++open-hook   '\.xz$'  "xz    -cd '%f' >  '%t'"
++close-hook  '\.xz$'  "xz    -c  '%t' >  '%f'"
++append-hook '\.xz$'  "xz    -c  '%t' >> '%f'"
++ 
++<emphasis role="comment"># Hander for pgp encrypted mailboxes
++# PGP does not support appending to an encrypted file</emphasis>
++open-hook   '\.pgp$' "pgp -f < '%f' > '%t'"
++close-hook  '\.pgp$' "pgp -fe YourPgpUserIdOrKeyId < '%t' > '%f'"
++ 
++<emphasis role="comment"># Hander for gpg encrypted mailboxes
++# gpg does not support appending to an encrypted file</emphasis>
++open-hook   '\.gpg$' "gpg --decrypt < '%f' > '%t'"
++close-hook  '\.gpg$' "gpg --encrypt --recipient YourGpgUserIdOrKeyId < '%t' > '%f'"
++ 
++<emphasis role="comment"># vim: syntax=muttrc</emphasis>
++</screen>
++  </sect2>
++
++  <sect2 id="compress-see-also">
++    <title>See Also</title>
++
++    <itemizedlist>
++      <listitem><para><ulink url="https://github.com/neomutt/neomutt/wiki">NeoMutt Project</ulink></para></listitem>
++      <listitem><para><link linkend="compile-time-features">Compile-Time Features</link></para></listitem>
++      <listitem><para><link linkend="regexp">Regular Expressions</link></para></listitem>
++      <listitem><para><link linkend="tmpdir">$tmpdir</link></para></listitem>
++      <listitem><para><link linkend="mbox-type">$mbox_type</link></para></listitem>
++      <listitem><para><link linkend="save-empty">$save_empty</link></para></listitem>
++      <listitem><para><link linkend="folder-hook">folder-hook</link></para></listitem>
++    </itemizedlist>
++  </sect2>
++
++  <sect2 id="compress-known-bugs">
++    <title>Known Bugs</title>
++
++    <itemizedlist>
++      <listitem><para>The Compressed Folder hooks cannot deal with filenames that contains quotes/apostrophes.</para></listitem>
++    </itemizedlist>
++  </sect2>
++
++  <sect2 id="compress-credits">
++    <title>Credits</title>
++    <itemizedlist>
++    <listitem><para>Roland Rosenfeld <email>roland at spinnaker.de</email></para></listitem>
++    <listitem><para>Alain Penders <email>Alain at Finale-Dev.com</email></para></listitem>
++    <listitem><para>Christoph <quote>Myon</quote> Berg <email>myon at debian.org</email></para></listitem>
++    <listitem><para>Evgeni Golov <email>evgeni at debian.org</email></para></listitem>
++    <listitem><para>Richard Russon <email>rich at flatcap.org</email></para></listitem>
++    </itemizedlist>
++  </sect2>
++</sect1>
++
++<sect1 id="cond-date">
++  <title>Conditional Dates Patch</title>
++  <subtitle>Use rules to choose date format</subtitle>
++
++  <sect2 id="cond-date-patch">
++    <title>Patch</title>
++
++    <para>
++      To check if Mutt supports <quote>Conditional Dates</quote>, look for
++      <quote>patch-cond-date</quote> in the mutt version.
++      See: <xref linkend="mutt-patches"/>.
++    </para>
++
++    <itemizedlist>
++      <title>Dependencies:</title>
++      <listitem><para>mutt-1.6.2</para></listitem>
++      <listitem><para><link linkend="nested-if">nested-if patch</link></para></listitem>
++    </itemizedlist>
++
++    <para>
++      This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.
++    </para>
++  </sect2>
++
++  <sect2 id="cond-date-intro">
++    <title>Introduction</title>
++
++    <para>
++    The <quote>cond-date</quote> patch allows you to construct
++    <link linkend="index-format">$index_format</link> expressions based on the age of the email.
++    </para>
++
++    <para>
++    Mutt's default <literal>$index_format</literal> displays email dates in the
++    form: abbreviated-month day-of-month — <quote>Jan 14</quote>.
++    </para>
++
++    <para>
++    The format is configurable but only per-mailbox.  This patch allows you
++    to configure the display depending on the age of the email.
++    </para>
++
++    <table id="table-cond-date-scheme">
++      <title>Potential Formatting Scheme</title>
++      <tgroup cols="3">
++        <thead>
++          <row>
++            <entry>Email Sent</entry>
++            <entry>Format</entry>
++            <entry>Example</entry>
++          </row>
++        </thead>
++        <tbody>
++          <row>
++            <entry>Today</entry>
++            <entry><literal>%H:%M</literal></entry>
++            <entry>13:23</entry>
++          </row>
++          <row>
++            <entry>This Month</entry>
++            <entry><literal>%a %d</literal></entry>
++            <entry>Thu 17</entry>
++          </row>
++          <row>
++            <entry>This Year</entry>
++            <entry><literal>%b %d</literal></entry>
++            <entry>Dec 10</entry>
++          </row>
++          <row>
++            <entry>Older than 1 Year</entry>
++            <entry><literal>%m/%y</literal></entry>
++            <entry>06/14</entry>
++          </row>
++        </tbody>
++      </tgroup>
++    </table>
++
++    <para>
++        For an explanation of the date formatting strings, see
++        <literal>strftime(3).</literal>
++    </para>
++
++    <para>
++        By carefully picking your formats, the dates can remain
++        unambiguous and compact.
++    </para>
++
++    <para>
++    Mutt's conditional format strings have the form:
++    (whitespace introduced for clarity)
++    </para>
++
++    <screen>%? TEST ? TRUE & FALSE ?</screen>
++
++    <para>
++    The examples below use the test <quote>%[</quote> — the date
++    of the message in the local timezone.  They will also work with
++    <quote>%(</quote> — the local time that the message arrived.
++    </para>
++
++    <para>
++    The date tests are of the form:
++    </para>
++
++    <screen>%[nX? TRUE & FALSE ?</screen>
++
++    <itemizedlist>
++    <listitem><para><quote>n</quote> is an optional count (defaults to 1 if missing)</para></listitem>
++    <listitem><para><quote>X</quote> is the time period</para></listitem>
++    </itemizedlist>
++
++    <table id="table-cond-date-format-codes">
++      <title>Date Formatting Codes</title>
++      <tgroup cols="2">
++        <thead>
++          <row>
++            <entry>Letter</entry>
++            <entry>Time Period</entry>
++          </row>
++        </thead>
++        <tbody>
++          <row>
++            <entry>y</entry>
++            <entry>Years</entry>
++          </row>
++          <row>
++            <entry>m</entry>
++            <entry>Months</entry>
++          </row>
++          <row>
++            <entry>w</entry>
++            <entry>Weeks</entry>
++          </row>
++          <row>
++            <entry>d</entry>
++            <entry>Days</entry>
++          </row>
++          <row>
++            <entry>H</entry>
++            <entry>Hours</entry>
++          </row>
++          <row>
++            <entry>M</entry>
++            <entry>Minutes</entry>
++          </row>
++        </tbody>
++      </tgroup>
++    </table>
++
++    <table id="table-cond-date-example-tests">
++      <title>Example Date Tests</title>
++      <tgroup cols="2">
++        <thead>
++          <row>
++            <entry>Test</entry>
++            <entry>Meaning</entry>
++          </row>
++        </thead>
++        <tbody>
++          <row>
++            <entry><literal>%[y</literal></entry>
++            <entry>This year</entry>
++          </row>
++          <row>
++            <entry><literal>%[1y</literal></entry>
++            <entry>This year</entry>
++          </row>
++          <row>
++            <entry><literal>%[6m</literal></entry>
++            <entry>In the last 6 months</entry>
++          </row>
++          <row>
++            <entry><literal>%[w</literal></entry>
++            <entry>This week</entry>
++          </row>
++          <row>
++            <entry><literal>%[d</literal></entry>
++            <entry>Today</entry>
++          </row>
++          <row>
++            <entry><literal>%[4H</literal></entry>
++            <entry>In the last 4 hours</entry>
++          </row>
++        </tbody>
++      </tgroup>
++    </table>
++
++    <sect3 id="cond-date-example1">
++      <title>Example 1</title>
++
++      <para>We start with a one-condition test.</para>
++
++      <table id="table-cond-date-example1">
++        <title>Example 1</title>
++        <tgroup cols="4">
++          <thead>
++            <row>
++              <entry>Test</entry>
++              <entry>Date Range</entry>
++              <entry>Format String</entry>
++              <entry>Example</entry>
++            </row>
++          </thead>
++          <tbody>
++            <row>
++              <entry><literal>%[1m</literal></entry>
++              <entry>This month</entry>
++              <entry><literal>%[%b %d]</literal></entry>
++              <entry>Dec 10</entry>
++            </row>
++            <row>
++              <entry></entry>
++              <entry>Older</entry>
++              <entry><literal>%[%Y-%m-%d]</literal></entry>
++              <entry>2015-04-23</entry>
++            </row>
++          </tbody>
++        </tgroup>
++      </table>
++
++      <para>The $index_format string would contain:</para>
++<screen>
++%?[1m?%[%b %d]&%[%Y-%m-%d]?
++</screen>
++ 
++      <para>
++        Reparsed a little, for clarity, you can see the
++        test condition and the two format strings.
++      </para>
++
++<screen>
++%?[1m?        &           ?
++      %[%b %d] %[%Y-%m-%d]
++</screen>
++
++    </sect3>
++
++    <sect3 id="cond-date-example2">
++      <title>Example 2</title>
++
++      <para>
++      This example contains three test conditions and four date formats.
++      </para>
++
++      <table id="table-cond-date-example2">
++        <title>Example 2</title>
++        <tgroup cols="4">
++          <thead>
++            <row>
++              <entry>Test</entry>
++              <entry>Date Range</entry>
++              <entry>Format String</entry>
++              <entry>Example</entry>
++            </row>
++          </thead>
++          <tbody>
++            <row>
++              <entry><literal>%[d</literal></entry>
++              <entry>Today</entry>
++              <entry><literal>%[%H:%M ] </literal></entry>
++              <entry>12:34</entry>
++            </row>
++            <row>
++              <entry><literal>%[m</literal></entry>
++              <entry>This month</entry>
++              <entry><literal>%[%a %d]</literal></entry>
++              <entry>Thu 12</entry>
++            </row>
++            <row>
++              <entry><literal>%[y</literal></entry>
++              <entry>This year</entry>
++              <entry><literal>%[%b %d]</literal></entry>
++              <entry>Dec 10</entry>
++            </row>
++            <row>
++              <entry></entry>
++              <entry>Older</entry>
++              <entry><literal>%[%m/%y ]</literal></entry>
++              <entry>06/15</entry>
++            </row>
++          </tbody>
++        </tgroup>
++      </table>
++
++      <para>The $index_format string would contain:</para>
++ 
++<screen>
++%<[y?%<[m?%<[d?%[%H:%M ]&%[%a %d]>&%[%b %d]>&%[%m/%y ]>
++</screen>
++
++      <para>
++        Reparsed a little, for clarity, you can see the
++        test conditions and the four format strings.
++      </para>
++
++<screen>
++%<[y?                                       &%[%m/%y ]>  Older
++     %<[m?                        &%[%b %d]>             This year
++          %<[d?         &%[%a %d]>                       This month
++               %[%H:%M ]                                 Today
++</screen>
++
++      <para>
++      This a another view of the same example, with some whitespace
++      for clarity.
++      </para>
++
++<screen>
++%<[y? %<[m? %<[d? AAA & BBB > & CCC > & DDD >
++</screen>
++
++      <literallayout>
++AAA = %[%H:%M ]
++BBB = %[%a %d]
++CCC = %[%b %d]
++DDD = %[%m/%y ]
++      </literallayout>
++    </sect3>
++  </sect2>
++
++  <sect2 id="cond-date-variables">
++    <title>Variables</title>
++
++        <para>
++    The <quote>cond-date</quote> patch doesn't have any config of its own.
++    It modifies the behavior of the format strings.
++        </para>
++  </sect2>
++
++<!--
++  <sect2 id="cond-date-functions">
++    <title>Functions</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="cond-date-commands">
++    <title>Commands</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="cond-date-colors">
++    <title>Colors</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="cond-date-sort">
++    <title>Sort</title>
++    <para>None</para>
++  </sect2>
++-->
++
++  <sect2 id="cond-date-muttrc">
++    <title>Muttrc</title>
++<screen>
++<emphasis role="comment"># Example Mutt config file for the 'index-color' feature.
++#
++# The default index_format is:
++#       '%4C %Z %{%b %d} %-15.15L (%?l?%4l&%4c?) %s'
++#
++# We replace the date field '%{%b %d}', giving:</emphasis>
++set index_format='%4C %Z %<[y?%<[m?%<[d?%[%H:%M ]&%[%a %d]>&%[%b %d]>&%[%m/%y ]> %-15.15L (%?l?%4l&%4c?) %s'
++ 
++<emphasis role="comment"># Test  Date Range  Format String  Example
++# --------------------------------------------
++# %[d   Today       %[%H:%M ]      12:34
++# %[m   This month  %[%a %d]       Thu 12
++# %[y   This year   %[%b %d]       Dec 10
++# -     Older       %[%m/%y ]      06/15
++ 
++# vim: syntax=muttrc</emphasis>
++</screen>
++  </sect2>
++
++  <sect2 id="cond-date-see-also">
++    <title>See Also</title>
++
++    <itemizedlist>
++      <listitem><para><ulink url="http://www.neomutt.org/">NeoMutt Project</ulink></para></listitem>
++      <listitem><para><link linkend="index-format">$index_format</link></para></listitem>
++      <listitem><para><link linkend="nested-if">nested-if patch</link></para></listitem>
++      <listitem><para><literal>strftime(3)</literal></para></listitem>
++    </itemizedlist>
++  </sect2>
++
++  <sect2 id="cond-date-known-bugs">
++    <title>Known Bugs</title>
++
++    <para>
++      Date parsing doesn't quite do what you expect.
++      <quote>1w</quote> doesn't mean the <quote>in the last 7 days</quote>, but
++      <quote><emphasis>this</emphasis> week</quote>.  This doesn't match
++      the normal Mutt behaviour: for example <literal>~d>1w</literal>
++      means emails dated in the last 7 days.
++    </para>
++
++  </sect2>
++
++  <sect2 id="cond-date-credits">
++    <title>Credits</title>
++    <itemizedlist>
++    <listitem><para>Aaron Schrab <email>aaron at schrab.com</email></para></listitem>
++    <listitem><para>Eric Davis <email>edavis at insanum.com</email></para></listitem>
++    <listitem><para>Richard Russon <email>rich at flatcap.org</email></para></listitem>
++    </itemizedlist>
++  </sect2>
++</sect1>
++
++<sect1 id="fmemopen">
++  <title>Fmemopen Patch</title>
++  <subtitle>Replace some temporary files with memory buffers</subtitle>
++
++  <sect2 id="fmemopen-patch">
++    <title>Patch</title>
++
++    <para>
++      To check if Mutt supports <quote>fmemopen</quote>, look for
++      <quote>patch-fmemopen</quote> in the mutt version.
++      See: <xref linkend="mutt-patches"/>.
++    </para>
++
++    <itemizedlist>
++      <title>Dependencies:</title>
++      <listitem><para>mutt-1.6.2</para></listitem>
++      <listitem><para><literal>open_memstream()</literal>, <literal>fmemopen()</literal> from glibc</para></listitem>
++    </itemizedlist>
++
++    <para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
++  </sect2>
++
++  <sect2 id="fmemopen-intro">
++    <title>Introduction</title>
++
++        <para>
++    The <quote>fmemopen</quote> patch speeds up some searches.
++        </para>
++
++        <para>
++    This patch changes a few places where Mutt creates temporary files.
++    It replaces them with in-memory buffers.  This should improve the
++    performance when searching the header or body using the
++    <link linkend="thorough-search">$thorough_search</link> option.
++        </para>
++
++        <para>
++    There are no user-configurable parts.
++        </para>
++
++        <para>
++    This patch depends on <literal>open_memstream()</literal> and
++    <literal>fmemopen()</literal>.  They are provided by glibc.  Without
++    them, Mutt will simply create temporary files.
++        </para>
++  </sect2>
++
++<!--
++  <sect2 id="fmemopen-variables">
++    <title>Variables</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="fmemopen-functions">
++    <title>Functions</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="fmemopen-commands">
++    <title>Commands</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="fmemopen-colors">
++    <title>Colors</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="fmemopen-sort">
++    <title>Sort</title>
++    <para>None</para>
++  </sect2>
++-->
++
++  <sect2 id="fmemopen-muttrc">
++    <title>Muttrc</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="fmemopen-see-also">
++    <title>See Also</title>
++
++    <itemizedlist>
++      <listitem><para><ulink url="http://www.neomutt.org/">NeoMutt Project</ulink></para></listitem>
++      <listitem><para><link linkend="compile-time-features">Compile-Time Features</link></para></listitem>
++      <listitem><para><literal>fmemopen(3)</literal></para></listitem>
++    </itemizedlist>
++  </sect2>
++
++  <sect2 id="fmemopen-known-bugs">
++    <title>Known Bugs</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="fmemopen-credits">
++    <title>Credits</title>
++    <itemizedlist>
++    <listitem><para>Julius Plenz <email>plenz at cis.fu-berlin.de</email></para></listitem>
++    <listitem><para>Richard Russon <email>rich at flatcap.org</email></para></listitem>
++    </itemizedlist>
++  </sect2>
++</sect1>
++
++<sect1 id="ifdef">
++  <title>Ifdef Patch</title>
++  <subtitle>Conditional config options</subtitle>
 +
-+int mh_sync_mailbox (CONTEXT * ctx, int *index_hint)
-+{
-+  int i, j;
-+#if USE_HCACHE
-+  header_cache_t *hc = NULL;
-+#endif /* USE_HCACHE */
-+  char msgbuf[STRING];
-+  progress_t progress;
++  <sect2 id="ifdef-patch">
++    <title>Patch</title>
 +
-+  if (ctx->magic == M_MH)
-+    i = mh_check_mailbox (ctx, index_hint);
-+  else
-+    i = maildir_check_mailbox (ctx, index_hint);
++    <para>
++      To check if Mutt supports <quote>ifdef</quote>, look for
++      <quote>patch-ifdef</quote> in the mutt version.
++      See: <xref linkend="mutt-patches"/>.
++    </para>
 +
-+  if (i != 0)
-+    return i;
++    <itemizedlist>
++      <title>Dependencies:</title>
++      <listitem><para>mutt-1.6.2</para></listitem>
++    </itemizedlist>
 +
-+#if USE_HCACHE
-+  if (ctx->magic == M_MAILDIR || ctx->magic == M_MH)
-+    hc = mutt_hcache_open(HeaderCache, ctx->path, NULL);
-+#endif /* USE_HCACHE */
++    <para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
++  </sect2>
 +
-+  if (!ctx->quiet)
-+  {
-+    snprintf (msgbuf, sizeof (msgbuf), _("Writing %s..."), ctx->path);
-+    mutt_progress_init (&progress, msgbuf, M_PROGRESS_MSG, WriteInc, ctx->msgcount);
-+  }
++  <sect2 id="ifdef-intro">
++    <title>Introduction</title>
 +
-+  for (i = 0; i < ctx->msgcount; i++)
-+  {
-+    if (!ctx->quiet)
-+      mutt_progress_update (&progress, i, -1);
++    <para>
++      The <quote>ifdef</quote> patch introduces three new commands to
++      Mutt and allow you to share one config file between versions of Mutt
++      that may have different features compiled in.
++    </para>
 +
-+#if USE_HCACHE
-+    if (mh_sync_mailbox_message (ctx, i, hc) == -1)
-+      goto err;
-+#else
-+    if (mh_sync_mailbox_message (ctx, i) == -1)
-+      goto err;
-+#endif
-   }
- 
- #if USE_HCACHE
-@@ -1851,7 +1935,7 @@
-   mutt_clear_threads (ctx);
- }
- 
--static void maildir_update_flags (CONTEXT *ctx, HEADER *o, HEADER *n)
-+void maildir_update_flags (CONTEXT *ctx, HEADER *o, HEADER *n)
- {
-   /* save the global state here so we can reset it at the
-    * end of list block if required.
-@@ -2154,7 +2238,7 @@
-  */
- 
- static FILE *_maildir_open_find_message (const char *folder, const char *unique,
--				  const char *subfolder)
-+				  const char *subfolder, char **newname)
- {
-   char dir[_POSIX_PATH_MAX];
-   char tunique[_POSIX_PATH_MAX];
-@@ -2190,11 +2274,15 @@
- 
-   closedir (dp);
- 
-+  if (newname && fp)
-+    *newname = safe_strdup(fname);
++<screen>
++ifdef  symbol config-command [args...]  <emphasis role="comment"># If a symbol is defined</emphasis>
++ifndef symbol config-command [args...]  <emphasis role="comment"># If a symbol is not defined</emphasis>
++finish                                  <emphasis role="comment"># Finish reading the current file</emphasis>
++</screen>
 +
-   errno = oe;
-   return fp;
- }
- 
--FILE *maildir_open_find_message (const char *folder, const char *msg)
-+FILE *maildir_open_find_message (const char *folder, const char *msg,
-+                                  char **newname)
- {
-   char unique[_POSIX_PATH_MAX];
-   FILE *fp;
-@@ -2206,7 +2294,8 @@
-   if (
-       (fp =
-        _maildir_open_find_message (folder, unique,
--				   new_hits > cur_hits ? "new" : "cur"))
-+				   new_hits > cur_hits ? "new" : "cur",
-+				   newname))
-       || errno != ENOENT)
-   {
-     if (new_hits < UINT_MAX && cur_hits < UINT_MAX)
-@@ -2220,7 +2309,8 @@
-   if (
-       (fp =
-        _maildir_open_find_message (folder, unique,
--				   new_hits > cur_hits ? "cur" : "new"))
-+				   new_hits > cur_hits ? "cur" : "new",
-+				   newname))
-       || errno != ENOENT)
-   {
-     if (new_hits < UINT_MAX && cur_hits < UINT_MAX)
-diff -urN mutt-1.6.1/mkchangelog.sh mutt-1.6.1-neomutt/mkchangelog.sh
---- mutt-1.6.1/mkchangelog.sh	2016-06-12 18:43:00.410447715 +0100
-+++ mutt-1.6.1-neomutt/mkchangelog.sh	1970-01-01 01:00:00.000000000 +0100
-@@ -1,5 +0,0 @@
--#!/bin/sh
--
--lrev=$(hg log --limit 1 --template '{rev}' ChangeLog)
--
--hg log --style=./hg-changelog-map -r "reverse($lrev::.)"
-diff -urN mutt-1.6.1/mutt_curses.h mutt-1.6.1-neomutt/mutt_curses.h
---- mutt-1.6.1/mutt_curses.h	2016-06-12 18:43:00.410447715 +0100
-+++ mutt-1.6.1-neomutt/mutt_curses.h	2016-06-12 18:43:00.716452487 +0100
-@@ -33,13 +33,6 @@
- #define KEY_DC SL_KEY_DELETE
- #define KEY_IC SL_KEY_IC
- 
--/*
-- * ncurses and SLang seem to send different characters when the Enter key is
-- * pressed, so define some macros to properly detect the Enter key.
-- */
--#define M_ENTER_C '\r'
--#define M_ENTER_S "\r"
--
- #else /* USE_SLANG_CURSES */
- 
- #if HAVE_NCURSESW_NCURSES_H
-@@ -52,9 +45,6 @@
- # include <curses.h>
- #endif
- 
--#define M_ENTER_C '\n'
--#define M_ENTER_S "\n"
--
- #endif /* USE_SLANG_CURSES */
- 
- /* AIX defines ``lines'' in <term.h>, but it's used as a var name in
-@@ -64,6 +54,9 @@
- #undef lines
- #endif /* lines */
- 
-+#ifdef USE_SIDEBAR
-+#define CLEARLINE_WIN(x) move (x,SidebarWidth), clrtoeol()
-+#endif
- #define CLEARLINE(x) move(x,0), clrtoeol()
- #define CENTERLINE(x,y) move(y, (COLS-strlen(x))/2), addstr(x)
- #define BEEP() do { if (option (OPTBEEP)) beep(); } while (0)
-@@ -122,14 +115,40 @@
-   MT_COLOR_SEARCH,
-   MT_COLOR_BOLD,
-   MT_COLOR_UNDERLINE,
--  MT_COLOR_INDEX,
-   MT_COLOR_PROMPT,
-+  MT_COLOR_PROGRESS,
-+#ifdef USE_SIDEBAR
-+  MT_COLOR_DIVIDER,
-+  MT_COLOR_FLAGGED,
-+  MT_COLOR_HIGHLIGHT,
-+  MT_COLOR_NEW,
-+  MT_COLOR_SB_INDICATOR,
-+  MT_COLOR_SB_SPOOLFILE,
-+#endif
-+  /* please no non-MT_COLOR_INDEX objects after this point */
-+#ifdef USE_NOTMUCH
-+  MT_COLOR_INDEX_TAG,
-+#endif
-+  MT_COLOR_INDEX,
-+  MT_COLOR_INDEX_AUTHOR,
-+  MT_COLOR_INDEX_FLAGS,
-+  MT_COLOR_INDEX_SUBJECT,
-+  /* below here - only index coloring stuff that doesn't have a pattern */
-+  MT_COLOR_INDEX_COLLAPSED,
-+  MT_COLOR_INDEX_DATE,
-+  MT_COLOR_INDEX_LABEL,
-+  MT_COLOR_INDEX_NUMBER,
-+  MT_COLOR_INDEX_SIZE,
-+#ifdef USE_NOTMUCH
-+  MT_COLOR_INDEX_TAGS,
-+#endif
-   MT_COLOR_MAX
- };
- 
- typedef struct color_line
- {
-   regex_t rx;
-+  int match; /* which substringmap 0 for old behaviour */
-   char *pattern;
-   pattern_t *color_pattern; /* compiled pattern to speed up index color
-                                calculation */
-@@ -163,12 +182,16 @@
- 
- static inline int mutt_term_width(short wrap)
- {
-+  int cols = COLS;
-+#ifdef USE_SIDEBAR
-+  cols -= SidebarWidth;
-+#endif
-   if (wrap < 0)
--    return COLS > -wrap ? COLS + wrap : COLS;
-+    return cols > -wrap ? cols + wrap : cols;
-   else if (wrap)
--    return wrap < COLS ? wrap : COLS;
-+    return wrap < cols ? wrap : cols;
-   else
--    return COLS;
-+    return cols;
- }
- 
- extern int *ColorQuote;
-@@ -176,7 +199,14 @@
- extern int ColorDefs[];
- extern COLOR_LINE *ColorHdrList;
- extern COLOR_LINE *ColorBodyList;
-+extern COLOR_LINE *ColorStatusList;
- extern COLOR_LINE *ColorIndexList;
-+extern COLOR_LINE *ColorIndexAuthorList;
-+extern COLOR_LINE *ColorIndexFlagsList;
-+extern COLOR_LINE *ColorIndexSubjectList;
-+#ifdef USE_NOTMUCH
-+extern COLOR_LINE *ColorIndexTagList;
-+#endif
- 
- void ci_init_color (void);
- void ci_start_color (void);
-diff -urN mutt-1.6.1/mutt.h mutt-1.6.1-neomutt/mutt.h
---- mutt-1.6.1/mutt.h	2016-06-12 18:43:00.410447715 +0100
-+++ mutt-1.6.1-neomutt/mutt.h	2016-06-12 18:43:00.716452487 +0100
-@@ -52,6 +52,11 @@
- #include <limits.h>
- #endif
- 
-+/* PATH_MAX is undefined on the hurd */
-+#ifndef PATH_MAX
-+#define PATH_MAX _POSIX_PATH_MAX
-+#endif
++    <para>
++      Here a symbol can be a <link linkend="variables">$variable</link>,
++      <link linkend="functions"><function></link>,
++      <link linkend="commands">command</link> or compile-time symbol, such
++      as <quote>USE_IMAP</quote>.
++    </para>
++
++        <para>
++            <literal>finish</literal> is particularly useful when combined with
++            <literal>ifndef</literal>. e.g.
++        </para>
++
++<screen>
++<emphasis role="comment"># Sidebar config file</emphasis>
++ifndef USE_SIDEBAR finish
++</screen>
++
++  </sect2>
++
++<!--
++  <sect2 id="ifdef-variables">
++    <title>Variables</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="ifdef-functions">
++    <title>Functions</title>
++    <para>None</para>
++  </sect2>
++-->
++
++  <sect2 id="ifdef-commands">
++    <title>Commands</title>
++    <cmdsynopsis>
++      <command>ifdef</command>
++      <arg choice="plain">
++        <replaceable class="parameter">symbol</replaceable>
++      </arg>
++      <arg choice="plain">
++        <replaceable class="parameter">"config-command [args]"</replaceable>
++      </arg>
++      <command>ifndef</command>
++      <arg choice="plain">
++        <replaceable class="parameter">symbol</replaceable>
++      </arg>
++      <arg choice="plain">
++        <replaceable class="parameter">"config-command [args]"</replaceable>
++      </arg>
++      <command>finish</command>
++    </cmdsynopsis>
++  </sect2>
++
++<!--
++  <sect2 id="ifdef-colors">
++    <title>Colors</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="ifdef-sort">
++    <title>Sort</title>
++    <para>None</para>
++  </sect2>
++-->
++
++  <sect2 id="ifdef-muttrc">
++    <title>Muttrc</title>
++<screen>
++<emphasis role="comment"># Example Mutt config file for the 'ifdef' feature.
++ 
++# This feature introduces three useful commands which allow you to share
++# one config file between versions of Mutt that may have different
++# features compiled in.
++ 
++#     ifdef  symbol config-command [args...]
++#     ifndef symbol config-command [args...]
++#     finish
++ 
++# The 'ifdef' command tests whether Mutt understands the name of
++# a variable, function, command or compile-time symbol.
++# If it does, then it executes a config command.
++ 
++# The 'ifndef' command tests whether a symbol does NOT exist.
++ 
++# The 'finish' command tells Mutt to stop reading current config file.
++ 
++# If the 'trash' variable exists, set it.</emphasis>
++ifdef trash 'set trash=~/Mail/trash'
++ 
++<emphasis role="comment"># If the 'tag-pattern' function exists, bind a key to it.</emphasis>
++ifdef tag-pattern 'bind index <F6> tag-pattern'
++ 
++<emphasis role="comment"># If the 'imap-fetch-mail' command exists, read my IMAP config.</emphasis>
++ifdef imap-fetch-mail 'source ~/.mutt/imap.rc'
++ 
++<emphasis role="comment"># If the compile-time symbol 'USE_SIDEBAR' does not exist, then
++# stop reading the current config file.</emphasis>
++ifndef USE_SIDEBAR finish
++ 
++<emphasis role="comment"># vim: syntax=muttrc</emphasis>
++</screen>
++  </sect2>
++
++  <sect2 id="ifdef-see-also">
++    <title>See Also</title>
++
++    <itemizedlist>
++      <listitem><para><ulink url="http://www.neomutt.org/">NeoMutt Project</ulink></para></listitem>
++    </itemizedlist>
++  </sect2>
++
++  <sect2 id="ifdef-known-bugs">
++    <title>Known Bugs</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="ifdef-credits">
++    <title>Credits</title>
++    <itemizedlist>
++    <listitem><para>Cedric Duval <email>cedricduval at free.fr</email></para></listitem>
++    <listitem><para>Matteo F. Vescovi <email>mfvescovi at gmail.com</email></para></listitem>
++    <listitem><para>Richard Russon <email>rich at flatcap.org</email></para></listitem>
++    </itemizedlist>
++  </sect2>
++</sect1>
 +
- #include <pwd.h>
- #include <grp.h>
- 
-@@ -66,6 +71,14 @@
- # define MB_LEN_MAX 16
- #endif
- 
-+#ifdef HAVE_FGETS_UNLOCKED
-+# define fgets fgets_unlocked
-+#endif
++<sect1 id="index-color">
++  <title>Index Color Patch</title>
++  <subtitle>Custom rules for theming the email index</subtitle>
 +
-+#ifdef HAVE_FGETC_UNLOCKED
-+# define fgetc fgetc_unlocked
-+#endif
++  <sect2 id="index-color-patch">
++    <title>Patch</title>
 +
- /* nifty trick I stole from ELM 2.5alpha. */
- #ifdef MAIN_C
- #define WHERE 
-@@ -88,6 +101,11 @@
- #define  M_CLEAR   (1<<5) /* clear input if printable character is pressed */
- #define  M_COMMAND (1<<6) /* do command completion */
- #define  M_PATTERN (1<<7) /* pattern mode - only used for history classes */
-+#define  M_LABEL   (1<<8) /* do label completion */
-+#if USE_NOTMUCH
-+#define  M_NM_QUERY (1<<9) /* Notmuch query mode. */
-+#define  M_NM_TAG   (1<<10) /* Notmuch tag +/- mode. */
-+#endif
- 
- /* flags for mutt_get_token() */
- #define M_TOKEN_EQUAL		1	/* treat '=' as a special */
-@@ -141,6 +159,11 @@
- #define M_ACCOUNTHOOK	(1<<9)
- #define M_REPLYHOOK	(1<<10)
- #define M_SEND2HOOK     (1<<11)
-+#ifdef USE_COMPRESSED
-+#define M_OPENHOOK	(1<<12)
-+#define M_APPENDHOOK	(1<<13)
-+#define M_CLOSEHOOK	(1<<14)
-+#endif
- 
- /* tree characters for linearize_tree and print_enriched_string */
- #define M_TREE_LLCORNER		1
-@@ -158,6 +181,8 @@
- #define M_TREE_MISSING		13
- #define M_TREE_MAX		14
- 
-+#define M_SPECIAL_INDEX		M_TREE_MAX
++    <para>
++      To check if Mutt supports <quote>Index Color</quote>, look for
++      <quote>patch-index-color</quote> in the mutt version.
++      See: <xref linkend="mutt-patches"/>.
++    </para>
 +
- #define M_THREAD_COLLAPSE	(1<<0)
- #define M_THREAD_UNCOLLAPSE	(1<<1)
- #define M_THREAD_GET_HIDDEN	(1<<2)
-@@ -182,6 +207,8 @@
-   M_DELETE,
-   M_UNDELETE,
-   M_DELETED,
-+  M_APPENDED,
-+  M_PURGED,
-   M_FLAG,
-   M_TAG,
-   M_UNTAG,
-@@ -223,7 +250,13 @@
-   M_CRYPT_ENCRYPT,
-   M_PGP_KEY,
-   M_XLABEL,
-+#ifdef USE_NOTMUCH
-+  M_NOTMUCH_LABEL,
-+#endif
-   M_MIMEATTACH,
-+#ifdef USE_NNTP
-+  M_NEWSGROUPS,
-+#endif
-   
-   /* Options for Mailcap lookup */
-   M_EDIT,
-@@ -280,6 +313,11 @@
- #endif
-   OPT_SUBJECT,
-   OPT_VERIFYSIG,      /* verify PGP signatures */
-+#ifdef USE_NNTP
-+  OPT_TOMODERATED,
-+  OPT_CATCHUP,
-+  OPT_FOLLOWUPTOPOSTER,
-+#endif
-     
-   /* THIS MUST BE THE LAST VALUE. */
-   OPT_MAX
-@@ -298,6 +336,7 @@
- #define SENDPOSTPONEDFCC	(1<<9) /* used by mutt_get_postponed() to signal that the x-mutt-fcc header field was present */
- #define SENDNOFREEHEADER	(1<<10)   /* Used by the -E flag */
- #define SENDDRAFTFILE		(1<<11)   /* Used by the -H flag */
-+#define SENDNEWS	(1<<12)
- 
- /* flags for mutt_compose_menu() */
- #define M_COMPOSE_NOFREEHEADER (1<<0)
-@@ -306,11 +345,18 @@
- #define M_SEL_BUFFY	(1<<0)
- #define M_SEL_MULTI	(1<<1)
- #define M_SEL_FOLDER	(1<<2)
-+#define M_SEL_VFOLDER	(1<<3)
- 
- /* flags for parse_spam_list */
- #define M_SPAM          1
- #define M_NOSPAM        2
- 
-+/* flags for keywords headers */
-+#define M_X_LABEL         (1<<0)  /* introduced to mutt in 2000 */
-+#define M_X_KEYWORDS      (1<<1)  /* used in c-client, dovecot */
-+#define M_X_MOZILLA_KEYS  (1<<2)  /* tbird */
-+#define M_KEYWORDS        (1<<3)  /* rfc2822 */
++    <itemizedlist>
++      <title>Dependencies:</title>
++      <listitem><para>mutt-1.6.2</para></listitem>
++      <listitem><para><link linkend="status-color">status-color patch</link></para></listitem>
++    </itemizedlist>
++
++    <para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
++  </sect2>
++
++  <sect2 id="index-color-intro">
++    <title>Introduction</title>
++
++        <para>
++    The <quote>index-color</quote> patch allows you to specify colors for
++    individual parts of the email index. e.g. Subject, Author, Flags.
++        </para>
++
++        <para>
++    First choose which part of the index you'd like to color.
++    Then, if needed, pick a pattern to match.
++        </para>
++
++    <para>
++    Note: The pattern does not have to refer to the object you wish to
++    color.  e.g.
++    </para>
++
++<screen>
++color index_author red default "~smutt"
++</screen>
++
++        <para>
++    The author appears red when the subject (~s) contains <quote>mutt</quote>.
++        </para>
++  </sect2>
++
++<!--
++  <sect2 id="index-color-variables">
++    <title>Variables</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="index-color-functions">
++    <title>Functions</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="index-color-commands">
++    <title>Commands</title>
++    <para>None</para>
++  </sect2>
++-->
++
++  <sect2 id="index-color-colors">
++    <title>Colors</title>
++
++        <para>
++    All the colors default to <literal>default</literal>, i.e. unset.
++        </para>
++
++        <para>
++    The index objects can be themed using the <literal>color</literal> command.
++    Some objects require a pattern.
++        </para>
++
++<screen>
++color index-object foreground background
++color index-object foreground background pattern
++</screen>
++
++    <table id="table-index-color-colors">
++      <title>Index Colors</title>
++      <tgroup cols="3">
++        <thead>
++          <row>
++            <entry>Object</entry>
++            <entry>Pattern</entry>
++            <entry>Highlights</entry>
++          </row>
++        </thead>
++        <tbody>
++          <row>
++            <entry><literal>index</literal></entry>
++            <entry>yes</entry>
++            <entry>Entire index line</entry>
++          </row>
++          <row>
++            <entry><literal>index_author</literal></entry>
++            <entry>yes</entry>
++            <entry>Author name, %A %a %F %L %n</entry>
++          </row>
++          <row>
++            <entry><literal>index_collapsed</literal></entry>
++            <entry>no</entry>
++            <entry>Number of messages in a collapsed thread, %M</entry>
++          </row>
++          <row>
++            <entry><literal>index_date</literal></entry>
++            <entry>no</entry>
++            <entry>Date field</entry>
++          </row>
++          <row>
++            <entry><literal>index_flags</literal></entry>
++            <entry>yes</entry>
++            <entry>Message flags, %S %Z</entry>
++          </row>
++          <row>
++            <entry><literal>index_label</literal></entry>
++            <entry>no</entry>
++            <entry>Message label, %y %Y</entry>
++          </row>
++          <row>
++            <entry><literal>index_number</literal></entry>
++            <entry>no</entry>
++            <entry>Message number, %C</entry>
++          </row>
++          <row>
++            <entry><literal>index_size</literal></entry>
++            <entry>no</entry>
++            <entry>Message size, %c %l</entry>
++          </row>
++          <row>
++            <entry><literal>index_subject</literal></entry>
++            <entry>yes</entry>
++            <entry>Subject, %s</entry>
++          </row>
++        </tbody>
++      </tgroup>
++    </table>
++  </sect2>
++
++<!--
++  <sect2 id="index-color-sort">
++    <title>Sort</title>
++    <para>None</para>
++  </sect2>
++-->
++
++  <sect2 id="index-color-muttrc">
++    <title>Muttrc</title>
++<screen>
++<emphasis role="comment"># Example Mutt config file for the 'index-color' feature.
++ 
++# Entire index line</emphasis>
++color index white black '.*'
++ 
++<emphasis role="comment"># Author name, %A %a %F %L %n
++ 
++# Give the author column a dark grey background</emphasis>
++color index_author default color234 '.*'
++ 
++<emphasis role="comment"># Highlight a particular from (~f)</emphasis>
++color index_author brightyellow color234 '~fRay Charles'
++ 
++<emphasis role="comment"># Message flags, %S %Z
++# Highlight the flags for flagged (~F) emails</emphasis>
++color index_flags default red '~F'
++ 
++<emphasis role="comment"># Subject, %s
++# Look for a particular subject (~s)</emphasis>
++color index_subject brightcyan default '~s\(closes #[0-9]+\)'
++ 
++<emphasis role="comment"># Number of messages in a collapsed thread, %M</emphasis>
++color index_collapsed default brightblue
++ 
++<emphasis role="comment"># Date field</emphasis>
++color index_date green default
++ 
++<emphasis role="comment"># Message label, %y %Y</emphasis>
++color index_label default brightgreen
++ 
++<emphasis role="comment"># Message number, %C</emphasis>
++color index_number red default
++ 
++<emphasis role="comment"># Message size, %c %l</emphasis>
++color index_size cyan default
++ 
++<emphasis role="comment"># vim: syntax=muttrc</emphasis>
++</screen>
++  </sect2>
++
++  <sect2 id="index-color-see-also">
++    <title>See Also</title>
++
++    <itemizedlist>
++      <listitem><para><ulink url="http://www.neomutt.org/">NeoMutt Project</ulink></para></listitem>
++      <listitem><para><link linkend="regexp">Regular Expressions</link></para></listitem>
++      <listitem><para><link linkend="patterns">Patterns</link></para></listitem>
++      <listitem><para><link linkend="index-format">$index_format</link></para></listitem>
++      <listitem><para><link linkend="color">Color command</link></para></listitem>
++      <listitem><para><link linkend="status-color">Status-Color patch</link></para></listitem>
++      <listitem><para><link linkend="keywords">Keywords patch</link></para></listitem>
++    </itemizedlist>
++  </sect2>
++
++  <sect2 id="index-color-known-bugs">
++    <title>Known Bugs</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="index-color-credits">
++    <title>Credits</title>
++    <itemizedlist>
++    <listitem><para>Christian Aichinger <email>Greek0 at gmx.net</email></para></listitem>
++    <listitem><para>Christoph <quote>Myon</quote> Berg <email>myon at debian.org</email></para></listitem>
++    <listitem><para>Elimar Riesebieter <email>riesebie at lxtec.de</email></para></listitem>
++    <listitem><para>Eric Davis <email>edavis at insanum.com</email></para></listitem>
++    <listitem><para>Vladimir Marek <email>Vladimir.Marek at oracle.com</email></para></listitem>
++    <listitem><para>Richard Russon <email>rich at flatcap.org</email></para></listitem>
++    </itemizedlist>
++  </sect2>
++</sect1>
++
++<sect1 id="initials">
++  <title>Initials Expando Patch</title>
++  <subtitle>Expando for author's initials</subtitle>
++
++  <sect2 id="initials-patch">
++    <title>Patch</title>
++
++    <para>
++      To check if Mutt supports <quote>Initials</quote>, look for
++      <quote>patch-initials</quote> in the mutt version.
++      See: <xref linkend="mutt-patches"/>.
++    </para>
++
++    <itemizedlist>
++      <title>Dependencies:</title>
++      <listitem><para>mutt-1.6.2</para></listitem>
++    </itemizedlist>
++
++    <para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
++  </sect2>
++
++  <sect2 id="initials-intro">
++    <title>Introduction</title>
++
++        <para>
++    The <quote>initials</quote> patch adds an expando (%I) for an author's
++    initials.
++        </para>
++
++    <para>
++    The index panel displays a list of emails.  Its layout is controlled by
++    the <link linkend="index-format">$index_format</link> variable.  Using
++    this expando saves space in the index panel.  This can be useful if you
++    are regularly working with a small set of people.
++    </para>
++  </sect2>
++
++  <sect2 id="initials-variables">
++    <title>Variables</title>
++
++        <para>
++        This patch has no config of its own.  It adds an expando which can be
++    used in the <link linkend="index-format">$index_format</link> variable.
++        </para>
++  </sect2>
++
++<!--
++  <sect2 id="initials-functions">
++    <title>Functions</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="initials-commands">
++    <title>Commands</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="initials-colors">
++    <title>Colors</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="initials-sort">
++    <title>Sort</title>
++    <para>None</para>
++  </sect2>
++-->
++
++  <sect2 id="initials-muttrc">
++    <title>Muttrc</title>
++<screen>
++<emphasis role="comment"># Example Mutt config file for the 'initials' patch.
++ 
++# The 'initials' patch has no config of its own.
++# It adds an expando for an author's initials,
++# which can be used in the 'index_format' variable.
++ 
++# The default 'index_format' is:</emphasis>
++set index_format='%4C %Z %{%b %d} %-15.15L (%?l?%4l&%4c?) %s'
++ 
++<emphasis role="comment"># Where %L represents the author/recipient
++ 
++# This might look like:
++#       1   + Nov 17 David Bowie   Changesbowie    ( 689)
++#       2   ! Nov 17 Stevie Nicks  Rumours         ( 555)
++#       3   + Nov 16 Jimi Hendrix  Voodoo Child    ( 263)
++#       4   + Nov 16 Debbie Harry  Parallel Lines  ( 540)
++ 
++# Using the %I expando:</emphasis>
++set index_format='%4C %Z %{%b %d} %I (%?l?%4l&%4c?) %s'
++ 
++<emphasis role="comment"># This might look like:
++#       1   + Nov 17 DB Changesbowie    ( 689)
++#       2   ! Nov 17 SN Rumours         ( 555)
++#       3   + Nov 16 JH Voodoo Child    ( 263)
++#       4   + Nov 16 DH Parallel Lines  ( 540)
++ 
++# vim: syntax=muttrc</emphasis>
++</screen>
++  </sect2>
++
++  <sect2 id="initials-see-also">
++    <title>See Also</title>
++
++    <itemizedlist>
++      <listitem><para><ulink url="http://www.neomutt.org/">NeoMutt Project</ulink></para></listitem>
++      <listitem><para><link linkend="index-format">$index_format</link></para></listitem>
++      <listitem><para><link linkend="index-color">index-color patch</link></para></listitem>
++      <listitem><para><link linkend="folder-hook">folder-hook</link></para></listitem>
++    </itemizedlist>
++  </sect2>
++
++  <sect2 id="initials-known-bugs">
++    <title>Known Bugs</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="initials-credits">
++    <title>Credits</title>
++    <itemizedlist>
++    <listitem><para>Vsevolod Volkov <email>vvv at mutt.org.ua</email></para></listitem>
++    <listitem><para>Richard Russon <email>rich at flatcap.org</email></para></listitem>
++    </itemizedlist>
++  </sect2>
++</sect1>
++
++<sect1 id="keywords">
++  <title>Keywords Patch</title>
++  <subtitle>Labels/Tagging for emails</subtitle>
++
++  <sect2 id="keywords-patch">
++    <title>Patch</title>
++
++    <para>
++      To check if Mutt supports <quote>Keywords</quote>, look for
++      <quote>patch-keywords</quote> in the mutt version.
++      See: <xref linkend="mutt-patches"/>.
++    </para>
++
++    <itemizedlist>
++      <title>Dependencies:</title>
++      <listitem><para>mutt-1.6.2</para></listitem>
++    </itemizedlist>
++
++    <para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
++  </sect2>
++
++  <sect2 id="keywords-intro">
++    <title>Introduction</title>
++
++    <para>
++    Unify label/keyword handling.
++    </para>
++
++    <para>
++    Since x-labels were added to mutt in 2000, a number of other approaches
++    to what we now call <quote>tagging</quote> have also emerged.
++    One of them was even made standard in RFC 2822.
++    This update unifies the handling of all these strategies.
++    </para>
++
++    <para>
++    We start by changing mutt's internal keyword storage from a single
++    string which may contain whitespace to a list of discrete keywords.
++    This has advantages for keyword completion as well as for portabilty
++    among varying "standards" for keyword storage.  This may represent
++    a significant change for existing mutt users who have set x-labels
++    containing spaces, and should be regarded with suspicion.  The
++    advantages are significant, though.
++    </para>
++
++    <para>
++    Next we allow mutt to parse keywords into this internal list from
++    any of the following headers: X-Label (freeform), X-Keywords
++    (space-delimited), X-Mozilla-Keys (space-delimited), and Keywords (RFC
++    2822, comma-space-delimited).  Mutt remembers which headers it sourced
++    keywords from, and can rewrite those headers when saving messages for
++    compatibility with the mailer of origin.
++    </para>
++
++    <para>
++    (X-Label was specified as freeform text by mutt, its only known
++    implementation.  X-Labels have been used both as a
++    <quote>tagging</quote> device, probably with space delimiting, and as a
++    <quote>memo</quote> field, where space-delimited parsing would ruin the
++    semantics of the memo.  By default mutt will not split X-Labels at all.
++    Set $xlabel_delimiter if your needs vary.)
++    </para>
++
++    <para>
++    Finally we add two booleans: $keywords_legacy=true and
++    $keywords_standard=FALSE.  When $keywords_legacy is true, mutt will
++    always save keyword to whatever original header it came from.  When
++    $keywords_standard=true, mutt will save to the Keywords: header.  If
++    both are true mutt saves to both; if neither is true, mutt saves only
++    to legacy headers to avoid complete loss of keywords.
++    </para>
++
++    <para>
++    Overall this represents convergence path for all competing
++    labelling/tagging/keywording systems toward one that is specified by
++    RFC.
++    </para>
++
++    <para>
++    You can change or delete the X-Label: field within
++    Mutt using the edit-label command, bound to the
++    y key by default.  This works for tagged messages, too.
++    </para>
++  </sect2>
++
++  <sect2 id="keywords-variables">
++    <title>Variables</title>
++
++    <table id="table-keywords-variables">
++      <title>Keywords Variables</title>
++      <tgroup cols="3">
++        <thead>
++          <row>
++            <entry>Name</entry>
++            <entry>Type</entry>
++            <entry>Default</entry>
++          </row>
++        </thead>
++        <tbody>
++          <row>
++            <entry><literal>keywords_legacy</literal></entry>
++            <entry>boolean</entry>
++            <entry><literal>yes</literal></entry>
++          </row>
++          <row>
++            <entry><literal>keywords_standard</literal></entry>
++            <entry>boolean</entry>
++            <entry><literal>no</literal></entry>
++          </row>
++          <row>
++            <entry><literal>xlabel_delimiter</literal></entry>
++            <entry>string</entry>
++            <entry>(empty)</entry>
++          </row>
++        </tbody>
++      </tgroup>
++    </table>
++  </sect2>
++
++  <sect2 id="keywords-functions">
++    <title>Functions</title>
++
++    <table id="table-keywords-funcions">
++      <title>Keyword Functions</title>
++      <tgroup cols="4">
++        <thead>
++          <row>
++            <entry>Menus</entry>
++            <entry>Default Key</entry>
++            <entry>Function</entry>
++            <entry>Description</entry>
++          </row>
++        </thead>
++        <tbody>
++          <row>
++            <entry>index,pager</entry>
++            <entry>y</entry>
++            <entry><literal><edit-label></literal></entry>
++            <entry>add, change, or delete a message's label</entry>
++          </row>
++        </tbody>
++      </tgroup>
++    </table>
++  </sect2>
++
++<!--
++  <sect2 id="keywords-commands">
++    <title>Commands</title>
++  </sect2>
++
++  <sect2 id="keywords-colors">
++    <title>Colors</title>
++    <para>None</para>
++  </sect2>
++-->
++
++  <sect2 id="keywords-sort">
++    <title>Sort</title>
++    <table id="table-keywords-sort">
++      <title>Keywords Sort</title>
++      <tgroup cols="2">
++        <thead>
++          <row>
++            <entry>Sort</entry>
++            <entry>Description</entry>
++          </row>
++        </thead>
++        <tbody>
++          <row>
++            <entry><literal>label</literal></entry>
++            <entry>Sort by label</entry>
++          </row>
++        </tbody>
++      </tgroup>
++    </table>
++  </sect2>
++
++  <sect2 id="keywords-muttrc">
++    <title>Muttrc</title>
++
++<screen>
++<emphasis role="comment"># This is a complete list of keywords-related configuration.
++ 
++# --------------------------------------------------------------------------
++# VARIABLES - shown with their default values
++# --------------------------------------------------------------------------
++ 
++# Should Mutt save the keywords to whatever keyword it came from?</emphasis>
++set keywords_legacy = yes
++ 
++<emphasis role="comment"># Should Mutt use the "Keywords:" header?</emphasis>
++set keywords_standard = no
++ 
++<emphasis role="comment"># How should the keywords be separated?</emphasis>
++set xlabel_delimiter = ""
++ 
++<emphasis role="comment"># --------------------------------------------------------------------------
++# FUNCTIONS - shown with an example mapping
++# --------------------------------------------------------------------------
++ 
++# Bind 'y' to edit labels/keywords</emphasis>
++bind index,pager y edit-label
++ 
++<emphasis role="comment"># --------------------------------------------------------------------------
++ 
++# vim: syntax=muttrc</emphasis>
++</screen>
++  </sect2>
++
++  <sect2 id="keywords-see-also">
++    <title>See Also</title>
++
++    <itemizedlist>
++      <listitem><para><ulink url="https://github.com/neomutt/neomutt/wiki">NeoMutt Project</ulink></para></listitem>
++      <listitem><para><link linkend="index-format">$index_format</link></para></listitem>
++      <listitem><para><link linkend="index-color">index-color patch</link></para></listitem>
++      <listitem><para><link linkend="folder-hook">folder-hook</link></para></listitem>
++    </itemizedlist>
++  </sect2>
++
++  <sect2 id="keywords-known-bugs">
++    <title>Known Bugs</title>
++    <para>
++      None
++    </para>
++  </sect2>
++
++  <sect2 id="keywords-credits">
++    <title>Credits</title>
++    <itemizedlist>
++    <listitem><para>David Champion <email>dgc at uchicago.edu</email></para></listitem>
++    <listitem><para>Richard Russon <email>rich at flatcap.org</email></para></listitem>
++    </itemizedlist>
++  </sect2>
++</sect1>
 +
- /* boolean vars */
- enum
- {
-@@ -320,6 +366,8 @@
-   OPTASCIICHARS,
-   OPTASKBCC,
-   OPTASKCC,
-+  OPTASKFOLLOWUP,
-+  OPTASKXCOMMENTTO,
-   OPTATTACHSPLIT,
-   OPTAUTOEDIT,
-   OPTAUTOTAG,
-@@ -386,6 +434,8 @@
-   OPTIMPLICITAUTOVIEW,
-   OPTINCLUDEONLYFIRST,
-   OPTKEEPFLAGGED,
-+  OPTKEYWORDSLEGACY,
-+  OPTKEYWORDSSTANDARD,
-   OPTMAILCAPSANITIZE,
-   OPTMAILCHECKRECENT,
-   OPTMAILDIRTRASH,
-@@ -401,6 +451,9 @@
-   OPTMETOO,
-   OPTMHPURGE,
-   OPTMIMEFORWDECODE,
-+#ifdef USE_NNTP
-+  OPTMIMESUBJECT,	/* encode subject line with RFC2047 */
-+#endif
-   OPTNARROWTREE,
-   OPTPAGERSTOP,
-   OPTPIPEDECODE,
-@@ -428,6 +481,13 @@
-   OPTSAVEEMPTY,
-   OPTSAVENAME,
-   OPTSCORE,
-+#ifdef USE_SIDEBAR
-+  OPTSIDEBAR,
-+  OPTSIDEBARFOLDERINDENT,
-+  OPTSIDEBARNEWMAILONLY,
-+  OPTSIDEBARNEXTNEWWRAP,
-+  OPTSIDEBARSHORTPATH,
-+#endif
-   OPTSIGDASHES,
-   OPTSIGONTOP,
-   OPTSORTRE,
-@@ -491,6 +551,17 @@
-   OPTPGPAUTOINLINE,
-   OPTPGPREPLYINLINE,
- 
-+  /* news options */
++<sect1 id="limit-current-thread">
++  <title>Limit-Current-Thread Patch</title>
++  <subtitle>Focus on one Email Thread</subtitle>
 +
-+#ifdef USE_NNTP
-+  OPTSHOWNEWNEWS,
-+  OPTSHOWONLYUNREAD,
-+  OPTSAVEUNSUB,
-+  OPTLISTGROUP,
-+  OPTLOADDESC,
-+  OPTXCOMMENTTO,
-+#endif
++  <sect2 id="limit-current-thread-patch">
++    <title>Patch</title>
 +
-   /* pseudo options */
- 
-   OPTAUXSORT,		/* (pseudo) using auxiliary sort function */
-@@ -511,6 +582,7 @@
-   OPTSORTSUBTHREADS,	/* (pseudo) used when $sort_aux changes */
-   OPTNEEDRESCORE,	/* (pseudo) set when the `score' command is used */
-   OPTATTACHMSG,		/* (pseudo) used by attach-message */
-+  OPTHIDEREAD,		/* (pseudo) whether or not hide read messages */
-   OPTKEEPQUIET,		/* (pseudo) shut up the message and refresh
- 			 * 	    functions while we are executing an
- 			 * 	    external program.
-@@ -521,6 +593,15 @@
-   OPTDONTHANDLEPGPKEYS,	/* (pseudo) used to extract PGP keys */
-   OPTIGNOREMACROEVENTS, /* (pseudo) don't process macro/push/exec events while set */
- 
-+#ifdef USE_NOTMUCH
-+  OPTVIRTSPOOLFILE,
-+  OPTNOTMUCHRECORD,
-+#endif
-+#ifdef USE_NNTP
-+  OPTNEWS,		/* (pseudo) used to change reader mode */
-+  OPTNEWSSEND,		/* (pseudo) used to change behavior when posting */
-+#endif
++    <para>
++      To check if Mutt supports <quote>limit-current-thread</quote>, look for
++      <quote>patch-limit-current-thread</quote> in the mutt version.
++      See: <xref linkend="mutt-patches"/>.
++    </para>
 +
-   OPTMAX
- };
- 
-@@ -600,10 +681,19 @@
-   char *supersedes;
-   char *date;
-   char *x_label;
-+  char *organization;
-+#ifdef USE_NNTP
-+  char *newsgroups;
-+  char *xref;
-+  char *followup_to;
-+  char *x_comment_to;
-+#endif
-   BUFFER *spam;
-   LIST *references;		/* message references (in reverse order) */
-   LIST *in_reply_to;		/* in-reply-to header content */
-   LIST *userhdrs;		/* user defined headers */
-+  LIST *labels;
-+  int kwtypes;
- 
-   unsigned int irt_changed : 1; /* In-Reply-To changed to link/break threads */
-   unsigned int refs_changed : 1; /* References changed to break thread */
-@@ -719,7 +809,10 @@
-   unsigned int mime : 1;    		/* has a MIME-Version header? */
-   unsigned int flagged : 1; 		/* marked important? */
-   unsigned int tagged : 1;
-+  unsigned int appended : 1;		/* has been saved */
-+  unsigned int purged : 1;   /* bypassing the trash folder */
-   unsigned int deleted : 1;
-+  unsigned int quasi_deleted : 1;	/* deleted from mutt, but not modified on disk */
-   unsigned int changed : 1;
-   unsigned int attach_del : 1; 		/* has an attachment marked for deletion */
-   unsigned int old : 1;
-@@ -736,6 +829,7 @@
- 					 * This flag is used by the maildir_trash
- 					 * option.
- 					 */
-+  unsigned int label_changed : 1;	/* editable - used for syncing */
-   
-   /* timezone of the sender of this message */
-   unsigned int zhours : 5;
-@@ -784,8 +878,9 @@
-   int refno;			/* message number on server */
- #endif
- 
--#if defined USE_POP || defined USE_IMAP
-+#if defined USE_POP || defined USE_IMAP || defined USE_NOTMUCH || defined USE_NNTP
-   void *data;            	/* driver-specific data */
-+  void (*free_cb)(struct header *); /* driver-specific data free function */
- #endif
-   
-   char *maildir_flags;		/* unknown maildir flags */
-@@ -872,6 +967,9 @@
- {
-   char *path;
-   FILE *fp;
-+#ifdef USE_SIDEBAR
-+  time_t atime;
-+#endif
-   time_t mtime;
-   off_t size;
-   off_t vsize;
-@@ -891,9 +989,15 @@
-   int new;			/* how many new messages? */
-   int unread;			/* how many unread messages? */
-   int deleted;			/* how many deleted messages */
-+  int appended;                 /* how many saved messages? */
-   int flagged;			/* how many flagged messages */
-   int msgnotreadyet;		/* which msg "new" in pager, -1 if none */
- 
-+#ifdef USE_COMPRESSED
-+  void *compress_info;		/* compressed mbox module private data */
-+  char *realpath;		/* path to compressed mailbox */
-+#endif /* USE_COMPRESSED */
++    <itemizedlist>
++      <title>Dependencies:</title>
++      <listitem><para>mutt-1.6.2</para></listitem>
++    </itemizedlist>
 +
-   short magic;			/* mailbox type */
- 
-   unsigned char rights[(RIGHTSMAX + 7)/8];	/* ACL bits */
-@@ -906,6 +1010,9 @@
-   unsigned int quiet : 1;	/* inhibit status messages? */
-   unsigned int collapsed : 1;   /* are all threads collapsed? */
-   unsigned int closing : 1;	/* mailbox is being closed */
-+#ifdef USE_SIDEBAR
-+  unsigned int peekonly : 1;	/* just taking a glance, revert atime */
-+#endif
- 
-   /* driver hooks */
-   void *data;			/* driver specific data */
-diff -urN mutt-1.6.1/muttlib.c mutt-1.6.1-neomutt/muttlib.c
---- mutt-1.6.1/muttlib.c	2016-06-12 18:43:00.411447731 +0100
-+++ mutt-1.6.1-neomutt/muttlib.c	2016-06-12 18:43:00.719452534 +0100
-@@ -32,11 +32,18 @@
- #include "imap.h"
- #endif
- 
-+#ifdef USE_NOTMUCH
-+#include "mutt_notmuch.h"
-+#endif
++    <para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
++  </sect2>
 +
- #include "mutt_crypt.h"
- 
- #include <string.h>
- #include <ctype.h>
- #include <unistd.h>
-+#ifdef HAVE_SYS_SYSCALL_H
-+#include <sys/syscall.h>
-+#endif
- #include <stdlib.h>
- #include <sys/wait.h>
- #include <errno.h>
-@@ -329,7 +336,9 @@
- #ifdef MIXMASTER
-   mutt_free_list (&(*h)->chain);
- #endif
--#if defined USE_POP || defined USE_IMAP
-+#if defined USE_POP || defined USE_IMAP || defined USE_NOTMUCH || defined USE_NNTP
-+  if ((*h)->free_cb)
-+    (*h)->free_cb(*h);
-   FREE (&(*h)->data);
- #endif
-   FREE (h);		/* __FREE_CHECKED__ */
-@@ -440,6 +449,11 @@
- 	  strfcpy (p, NONULL (Maildir), sizeof (p));
- 	else
- #endif
-+#ifdef USE_NOTMUCH
-+	if (mx_is_notmuch (NONULL (Maildir)))
-+	  strfcpy (p, NONULL (Maildir), sizeof (p));
-+	else
-+#endif
- 	if (Maildir && *Maildir && Maildir[strlen (Maildir) - 1] == '/')
- 	  strfcpy (p, NONULL (Maildir), sizeof (p));
- 	else
-@@ -714,12 +728,21 @@
-   FREE (&(*p)->supersedes);
-   FREE (&(*p)->date);
-   FREE (&(*p)->x_label);
-+  FREE (&(*p)->organization);
-+#ifdef USE_NNTP
-+  FREE (&(*p)->newsgroups);
-+  FREE (&(*p)->xref);
-+  FREE (&(*p)->followup_to);
-+  FREE (&(*p)->x_comment_to);
-+#endif
- 
-   mutt_buffer_free (&(*p)->spam);
- 
-   mutt_free_list (&(*p)->references);
-   mutt_free_list (&(*p)->in_reply_to);
-   mutt_free_list (&(*p)->userhdrs);
-+  mutt_label_ref_dec ((*p));
-+  mutt_free_list (&(*p)->labels);
-   FREE (p);		/* __FREE_CHECKED__ */
- }
- 
-@@ -742,7 +765,7 @@
-   MOVE_ELEM(message_id);
-   MOVE_ELEM(supersedes);
-   MOVE_ELEM(date);
--  MOVE_ELEM(x_label);
-+  MOVE_ELEM(labels);
-   if (!base->refs_changed)
-   {
-     MOVE_ELEM(references);
-@@ -771,12 +794,79 @@
-   mutt_free_envelope(extra);
- }
- 
-+static FILE *frandom;
++  <sect2 id="limit-current-thread-intro">
++    <title>Introduction</title>
++
++    <para>
++      This patch adds a new way of using the
++      <link linkend="tuning-search">Limit Command</link>.
++                        The <literal><limit-current-thread></literal>
++                        function restricts the view to just the current thread.
++                        Setting the limit (the <literal>l</literal> key) to
++                        <quote>all</quote> will restore the full email list.
++    </para>
++
++  </sect2>
++
++<!--
++  <sect2 id="limit-current-thread-variables">
++    <title>Variables</title>
++    <para>None</para>
++  </sect2>
++-->
++  <sect2 id="limit-current-thread-functions">
++    <title>Functions</title>
++
++    <table id="table-limit-current-thread-functions">
++      <title>Limit-Current-Thread Functions</title>
++      <tgroup cols="4">
++        <thead>
++          <row>
++            <entry>Menus</entry>
++            <entry>Default Key</entry>
++            <entry>Function</entry>
++            <entry>Description</entry>
++          </row>
++        </thead>
++        <tbody>
++          <row>
++            <entry>index</entry>
++            <entry><literal><Esc>L</literal></entry>
++            <entry><literal><limit-current-thread></literal></entry>
++            <entry>Limit view to current thread</entry>
++          </row>
++        </tbody>
++      </tgroup>
++    </table>
++
++  </sect2>
++<!--
++  <sect2 id="limit-current-thread-commands">
++    <title>Commands</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="limit-current-thread-colors">
++    <title>Colors</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="limit-current-thread-sort">
++    <title>Sort</title>
++    <para>None</para>
++  </sect2>
++-->
++
++  <sect2 id="limit-current-thread-muttrc">
++    <title>Muttrc</title>
++
++<screen>
++<emphasis role="comment"># Example Mutt config file for the 'limit-current-thread' patch.
++ 
++# Limit view to current thread</emphasis>
++bind index <esc>L limit-current-thread
++ 
++<emphasis role="comment"># vim: syntax=muttrc</emphasis>
++</screen>
++  </sect2>
++
++  <sect2 id="limit-current-thread-see-also">
++    <title>See Also</title>
++
++    <itemizedlist>
++      <listitem><para><ulink url="http://www.neomutt.org/">NeoMutt Project</ulink></para></listitem>
++    </itemizedlist>
++  </sect2>
++
++  <sect2 id="limit-current-thread-known-bugs">
++    <title>Known Bugs</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="limit-current-thread-credits">
++    <title>Credits</title>
++    <itemizedlist>
++    <listitem><para>David Sterba <email>dsterba at suse.cz</email></para></listitem>
++    <listitem><para>Richard Russon <email>rich at flatcap.org</email></para></listitem>
++    </itemizedlist>
++  </sect2>
++</sect1>
 +
-+void mutt_randbuf(void *out, size_t len)
-+{
-+  if (len > 1048576) {
-+    mutt_error (_("mutt_randbuf len=%zu"), len);
-+    exit(1);
-+  }
-+  /* XXX switch to HAVE_GETRANDOM and getrandom() in about 2017 */
-+#if defined(SYS_getrandom) && defined(__linux__)
-+  static int whined;
-+  long ret;
-+  do {
-+    ret = syscall(SYS_getrandom, out, len, 0, 0, 0, 0);
-+  } while ((ret == -1) && (errno == EINTR));
-+  if (ret == len) return;
-+  if (!whined) {
-+    mutt_error (_("getrandom failed: %s"), strerror(errno));
-+    mutt_sleep (1);
-+    whined = 1;
-+  }
-+  /* let's try urandom in case user has configured selinux or something
-+   * to not allow getrandom */
-+#endif
-+  if (frandom == NULL) {
-+    frandom = fopen("/dev/urandom", "rb");
-+    if (frandom == NULL) {
-+      mutt_error (_("open /dev/urandom: %s"), strerror(errno));
-+      exit(1);
-+    }
-+    setbuf(frandom, NULL);
-+  }
-+  if (fread(out, 1, len, frandom) != len) {
-+    mutt_error (_("read /dev/urandom: %s"), strerror(errno));
-+    exit(1);
-+  }
-+}
++<sect1 id="lmdb">
++  <title>LMDB Patch</title>
++  <subtitle>LMDB backend for the header cache</subtitle>
++
++  <sect2 id="lmdb-patch">
++    <title>Patch</title>
++
++    <para>
++      To check if Mutt supports <quote>lmdb</quote>, look for
++      <quote>patch-lmdb</quote> in the mutt version.
++      See: <xref linkend="mutt-patches"/>.
++    </para>
++
++    <itemizedlist>
++      <title>Dependencies:</title>
++      <listitem><para>mutt-1.6.2</para></listitem>
++    </itemizedlist>
++
++    <para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
++  </sect2>
++
++  <sect2 id="lmdb-intro">
++    <title>Introduction</title>
++
++    <para>
++      This patch adds support for using LMDB as a storage backend for
++      Mutt's header cache (hcache). It is enabled at configure time with
++      the <emphasis>--with-lmdb=<path></emphasis> switch.
++    </para>
++  </sect2>
++
++  <sect2 id="lmdb-see-also">
++    <title>See Also</title>
++
++    <itemizedlist>
++      <listitem><para><ulink url="http://www.neomutt.org/">NeoMutt Project</ulink></para></listitem>
++      <listitem><para><link linkend="caching">Local Caching</link></para></listitem>
++    </itemizedlist>
++  </sect2>
++
++  <sect2 id="lmdb-known-bugs">
++    <title>Known Bugs</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="lmdb-credits">
++    <title>Credits</title>
++    <itemizedlist>
++    <listitem><para>Pietro Cerutti <email>gahr at gahr.ch</email></para></listitem>
++    <listitem><para>Jan-Piet Mens <email>jp at mens.de</email></para></listitem>
++    </itemizedlist>
++  </sect2>
++</sect1>
 +
-+static const unsigned char base32[] = "abcdefghijklmnopqrstuvwxyz234567";
++<sect1 id="nested-if">
++  <title>Nested If Patch</title>
++  <subtitle>Allow complex nested conditions in format strings</subtitle>
 +
-+void mutt_rand_base32(void *out, size_t len)
-+{
-+  size_t pos;
-+  uint8_t *p = out;
++  <sect2 id="nested-if-patch">
++    <title>Patch</title>
 +
-+  mutt_randbuf(p, len);
-+  for (pos = 0; pos < len; pos++)
-+    p[pos] = base32[p[pos] % 32];
-+}
++    <para>
++      To check if Mutt supports <quote>Nested If</quote>, look for
++      <quote>patch-nested-if</quote> in the mutt version.
++      See: <xref linkend="mutt-patches"/>.
++    </para>
 +
-+uint32_t mutt_rand32(void)
-+{
-+  uint32_t ret;
++    <itemizedlist>
++      <title>Dependencies:</title>
++      <listitem><para>mutt-1.6.2</para></listitem>
++    </itemizedlist>
 +
-+  mutt_randbuf(&ret, sizeof(ret));
-+  return ret;
-+}
++    <para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
++  </sect2>
 +
-+uint64_t mutt_rand64(void)
-+{
-+  uint64_t ret;
++  <sect2 id="nested-if-intro">
++    <title>Introduction</title>
 +
-+  mutt_randbuf(&ret, sizeof(ret));
-+  return ret;
++    <para>
++      Mutt's format strings can contain embedded if-then-else conditions.
++      They are of the form:
++    </para>
++
++<screen>
++%?VAR?TRUE&FALSE?
++</screen>
++
++    <para>
++      If the variable <quote>VAR</quote> has a value greater than zero,
++      print the <quote>TRUE</quote> string, otherwise print the
++      <quote>FALSE</quote> string.
++    </para>
++
++    <para>
++      e.g.  <literal>%?S?Size: %S&Empty?</literal>
++    </para>
++
++    <para>Which can be read as:</para>
++
++    <literallayout>
++if (%S > 0) {
++    print "Size: %S"
++} else {
++    print "Empty"
 +}
++    </literallayout>
 +
++    <para>
++      These conditions are useful, but in Mutt they cannot be nested
++      within one another.  This patch uses the notation
++      <literal>%<VAR?TRUE&FALSE></literal> and allows them to be nested.
++    </para>
 +
- void _mutt_mktemp (char *s, size_t slen, const char *prefix, const char *suffix,
-                    const char *src, int line)
- {
--  size_t n = snprintf (s, slen, "%s/%s-%s-%d-%d-%ld%ld%s%s",
-+  size_t n = snprintf (s, slen, "%s/%s-%s-%d-%d-%" PRIu64 "%s%s",
-       NONULL (Tempdir), NONULL (prefix), NONULL (Hostname),
--      (int) getuid (), (int) getpid (), random (), random (),
-+      (int) getuid (), (int) getpid (), mutt_rand64(),
-       suffix ? "." : "", NONULL (suffix));
-   if (n >= slen)
-     dprint (1, (debugfile, "%s:%d: ERROR: insufficient buffer space to hold temporary filename! slen=%zu but need %zu\n",
-@@ -819,6 +909,11 @@
-   }
- #endif
- 
-+#ifdef USE_NOTMUCH
-+  if (scheme == U_NOTMUCH)
-+    return;
-+#endif
++    <para>
++      The <literal>%<...></literal> notation was used to format the
++      current local time.  but that's not really very useful since mutt
++      has no means of refreshing the screen periodically.
++    </para>
 +
-   /* if s is an url, only collapse path component */
-   if (scheme != U_UNKNOWN)
-   {
-@@ -1213,8 +1308,34 @@
- 
-       if (*src == '?')
-       {
-+	/* change original %? to new %< notation */
-+	/* %?x?y&z? to %<x?y&z> where y and z are nestable */
-+	char *p = (char *) src;
-+	*p = '<';
-+	for ( ; *p && *p != '?'; p++);
-+	  /* nothing */
-+	if (*p == '?') {
-+	  p++;
-+	}
-+	for ( ; *p && *p != '?'; p++);
-+	  /* nothing */
-+	if (*p == '?') {
-+	  *p = '>';
-+	}
-+      }
++    <para>
++      A simple nested condition might be:
++      (Some whitespace has been introduced for clarity)
++    </para>
 +
-+      if (*src == '<')
-+      {
- 	flags |= M_FORMAT_OPTIONAL;
-+	ch = *(++src); /* save the character to switch on */
- 	src++;
-+	cp = prefix;
-+	count = 0;
-+	while ((count < sizeof (prefix)) && (*src != '?')) {
-+	  *cp++ = *src++;
-+	  count++;
-+	}
-+	*cp = 0;
-       }
-       else
-       {
-@@ -1230,15 +1351,17 @@
- 	  count++;
- 	}
- 	*cp = 0;
--      }
- 
--      if (!*src)
--	break; /* bad format */
-+	if (!*src)
-+	  break; /* bad format */
- 
--      ch = *src++; /* save the character to switch on */
-+	ch = *src++; /* save the character to switch on */
-+      }
- 
-       if (flags & M_FORMAT_OPTIONAL)
-       {
-+	int lrbalance;
++<screen>
++%<x? %<y? XY & X > & %<y? Y & NONE > >  Conditions
++     %<y? XY & X >                      x>0
++          XY                            x>0,y>0
++               X                        x>0,y=0
++</screen>
 +
-         if (*src != '?')
-           break; /* bad format */
-         src++;
-@@ -1246,8 +1369,20 @@
-         /* eat the `if' part of the string */
-         cp = ifstring;
- 	count = 0;
--        while (count < sizeof (ifstring) && *src && *src != '?' && *src != '&')
--	{
-+	lrbalance = 1;
-+        while ((lrbalance > 0) && (count < sizeof (ifstring)) && *src) {
-+	  if (*src == '\\') {
-+	    src++;
-+	    *cp++ = *src++;
-+	  } else if ((src[0] == '%') && (src[1] == '<')) {
-+	    lrbalance++;
-+	  } else if (src[0] == '>') {
-+	    lrbalance--;
-+	  }
-+	  if (lrbalance == 0)
-+	    break;
-+	  if ((lrbalance == 1) && (src[0] == '&'))
-+	    break;
-           *cp++ = *src++;
- 	  count++;
- 	}
-@@ -1258,9 +1393,20 @@
- 	  src++; /* skip the & */
- 	cp = elsestring;
- 	count = 0;
--	while (count < sizeof (elsestring) && *src && *src != '?')
--	{
--	  *cp++ = *src++;
-+	while ((lrbalance > 0) && (count < sizeof (elsestring)) && *src) {
-+	  if (*src == '\\') {
-+	    src++;
-+	    *cp++ = *src++;
-+	  } else if ((src[0] == '%') && (src[1] == '<')) {
-+	    lrbalance++;
-+	  } else if (src[0] == '>') {
-+	    lrbalance--;
-+	  }
-+	  if (lrbalance == 0)
-+	    break;
-+	  if ((lrbalance == 1) && (src[0] == '&'))
-+	    break;
-+          *cp++ = *src++;
- 	  count++;
- 	}
- 	*cp = 0;
-@@ -1268,7 +1414,7 @@
- 	if (!*src)
- 	  break; /* bad format */
- 
--        src++; /* move past the trailing `?' */
-+        src++; /* move past the trailing `>' (formerly '?') */
-       }
- 
-       /* handle generic cases first */
-@@ -1282,7 +1428,7 @@
- 	  pl = pw = 1;
- 
- 	/* see if there's room to add content, else ignore */
--	if ((col < COLS && wlen < destlen) || soft)
-+	if ((col < (COLS - SidebarWidth) && (wlen < destlen)) || soft)
- 	{
- 	  int pad;
- 
-@@ -1293,7 +1439,7 @@
- 
- 	  /* try to consume as many columns as we can, if we don't have
- 	   * memory for that, use as much memory as possible */
--	  pad = (COLS - col - wid) / pw;
-+	  pad = (COLS - SidebarWidth - col - wid) / pw;
- 	  if (pad > 0 && wlen + (pad * pl) + len > destlen)
- 	    pad = ((signed)(destlen - wlen - len)) / pl;
- 	  if (pad > 0)
-@@ -1312,13 +1458,13 @@
- 	    /* \0-terminate dest for length computation in mutt_wstr_trunc() */
- 	    *wptr = 0;
- 	    /* make sure right part is at most as wide as display */
--	    len = mutt_wstr_trunc (buf, destlen, COLS-offset, &wid);
-+	    len = mutt_wstr_trunc (buf, destlen, COLS - offset - SidebarWidth, &wid);
- 	    /* truncate left so that right part fits completely in */
- 	    wlen = mutt_wstr_trunc (dest, destlen - len, col + pad*pw -offset, &col);
- 	    wptr = dest + wlen;
- 	  }
- 	  if (len + wlen > destlen)
--	    len = mutt_wstr_trunc (buf, destlen - wlen, COLS - col, NULL);
-+	    len = mutt_wstr_trunc (buf, destlen - wlen, COLS - SidebarWidth - col, NULL);
- 	  memcpy (wptr, buf, len);
- 	  wptr += len;
- 	  wlen += len;
-@@ -1511,7 +1657,9 @@
- 
-   if (magic > 0 && !mx_access (s, W_OK))
-   {
--    if (option (OPTCONFIRMAPPEND))
-+    if (option (OPTCONFIRMAPPEND) &&
-+       (!TrashPath || (mutt_strcmp (s, TrashPath) != 0)))
-+       /* if we're appending to the trash, there's no point in asking */
-     {
-       snprintf (tmp, sizeof (tmp), _("Append messages to %s?"), s);
-       if ((rc = mutt_yesorno (tmp, M_YES)) == M_NO)
-@@ -1521,6 +1669,14 @@
-     }
-   }
- 
-+#ifdef USE_NNTP
-+  if (magic == M_NNTP)
-+  {
-+    mutt_error _("Can't save message to news server.");
-+    return 0;
-+  }
-+#endif
++<screen>
++%<x? %<y? XY & X > & %<y? Y & NONE > >  Conditions
++                      %<y? Y & NONE >    x=0
++                          Y             x=0,y>0
++                              NONE      x=0,y=0
++</screen>
++
++    <para>Equivalent to:</para>
++
++    <literallayout>
++if (x > 0) {
++    if (y > 0) {
++        print 'XY'
++    } else {
++        print 'X'
++    }
++} else {
++    if (y > 0) {
++        print 'Y'
++    } else {
++        print 'NONE'
++    }
++}
++    </literallayout>
++
++    <para>Examples:</para>
++
++<screen>
++set index_format='%4C %Z %{%b %d} %-25.25n %s%> %<M?%M Msgs &%<l?%l Lines&%c Bytes>>'
++</screen>
++
++    <literallayout>
++if a thread is folded
++    display the number of messages (%M)
++else if we know how many lines in the message
++    display lines in message (%l)
++else
++    display the size of the message in bytes (%c)
++    </literallayout>
 +
-   if (stat (s, st) != -1)
-   {
-     if (magic == -1)
-diff -urN mutt-1.6.1/mutt_menu.h mutt-1.6.1-neomutt/mutt_menu.h
---- mutt-1.6.1/mutt_menu.h	2016-06-12 18:43:00.410447715 +0100
-+++ mutt-1.6.1-neomutt/mutt_menu.h	2016-06-12 18:43:00.717452503 +0100
-@@ -34,6 +34,9 @@
- #define REDRAW_FULL		(1<<5)
- #define REDRAW_BODY		(1<<6)
- #define REDRAW_SIGWINCH		(1<<7)
-+#ifdef USE_SIDEBAR
-+#define REDRAW_SIDEBAR		(1<<8)
-+#endif
- 
- #define M_MODEFMT "-- Mutt: %s"
- 
-@@ -115,4 +118,6 @@
- void index_make_entry (char *, size_t, struct menu_t *, int);
- int index_color (int);
- 
-+int mutt_limit_current_thread (HEADER *h);
++<screen>
++set index_format='%4C %Z %{%b %d} %-25.25n %<M?[%M] %s&%s%* %<l?%l&%c>>'
++</screen>
 +
- #endif /* _MUTT_MENU_H_ */
-diff -urN mutt-1.6.1/mutt_notmuch.c mutt-1.6.1-neomutt/mutt_notmuch.c
---- mutt-1.6.1/mutt_notmuch.c	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/mutt_notmuch.c	2016-06-12 18:43:00.717452503 +0100
-@@ -0,0 +1,1984 @@
-+/*
-+ * Notmuch support for mutt
-+ *
-+ * Copyright (C) 2011, 2012 Karel Zak <kzak at redhat.com>
-+ *
-+ * Notes:
-+ *
-+ * - notmuch uses private CONTEXT->data and private HEADER->data
-+ *
-+ * - all exported functions are usable within notmuch context only
-+ *
-+ * - all functions have to be covered by "ctx->magic == M_NOTMUCH" check
-+ *   (it's implemented in get_ctxdata() and init_context() functions).
-+ *
-+ * - exception are nm_nonctx_* functions -- these functions use nm_default_uri
-+ *   (or parse URI from another resource)
-+ */
-+#if HAVE_CONFIG_H
-+# include "config.h"
-+#endif
++    <literallayout>
++if a thread is folded
++    display the number of messages (%M)
++    display the subject (%s)
++else if we know how many lines in the message
++    display lines in message (%l)
++else
++    display the size of the message in bytes (%c)
++    </literallayout>
 +
-+#include "mutt.h"
-+#include "mx.h"
-+#include "rfc2047.h"
-+#include "sort.h"
-+#include "mailbox.h"
-+#include "copy.h"
-+#include "keymap.h"
-+#include "url.h"
-+#include "buffy.h"
++  </sect2>
 +
-+#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>
-+#include <utime.h>
++  <sect2 id="nested-if-variables">
++    <title>Variables</title>
++    <para>
++      The <quote>nested-if</quote> patch doesn't have any config of its own.
++      It modifies the behavior of the format strings.
++    </para>
++  </sect2>
 +
-+#include <notmuch.h>
++<!--
++  <sect2 id="nested-if-functions">
++    <title>Functions</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="nested-if-commands">
++    <title>Commands</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="nested-if-colors">
++    <title>Colors</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="nested-if-sort">
++    <title>Sort</title>
++    <para>None</para>
++  </sect2>
++-->
 +
-+#include "mutt_notmuch.h"
-+#include "mutt_curses.h"
++  <sect2 id="nested-if-muttrc">
++    <title>Muttrc</title>
++<screen>
++<emphasis role="comment"># Example Mutt config file for the 'nested-if' feature.
++ 
++# This patch uses the format: '%<VAR?TRUE&FALSE>' for conditional
++# format strings that can be nested.
++ 
++# Example 1
++# if a thread is folded
++#       display the number of messages (%M)
++# else if we know how many lines in the message
++#       display lines in message (%l)
++# else display the size of the message in bytes (%c)</emphasis>
++set index_format='%4C %Z %{%b %d} %-25.25n %s%> %<M?%M Msgs &%<l?%l Lines&%c Bytes>>'
++ 
++<emphasis role="comment"># Example 2
++# if a thread is folded
++#       display the number of messages (%M)
++#       display the subject (%s)
++# else if we know how many lines in the message
++#       display lines in message (%l)
++# else
++#       display the size of the message in bytes (%c)</emphasis>
++set index_format='%4C %Z %{%b %d} %-25.25n %<M?[%M] %s&%s%* %<l?%l&%c>>'
++ 
++<emphasis role="comment"># vim: syntax=muttrc</emphasis>
++</screen>
++  </sect2>
++
++  <sect2 id="nested-if-see-also">
++    <title>See Also</title>
++
++    <itemizedlist>
++      <listitem><para><ulink url="http://www.neomutt.org/">NeoMutt Project</ulink></para></listitem>
++      <listitem><para><link linkend="cond-date">cond-date patch</link></para></listitem>
++      <listitem><para><link linkend="index-format">$index_format</link></para></listitem>
++      <listitem><para><link linkend="status-format">$status_format</link></para></listitem>
++    </itemizedlist>
++  </sect2>
++
++  <sect2 id="nested-if-known-bugs">
++    <title>Known Bugs</title>
++    <para>
++      Patch overwrites $<fmt> handler in <literal>$index_format</literal>
++    </para>
++  </sect2>
++
++  <sect2 id="nested-if-credits">
++    <title>Credits</title>
++    <itemizedlist>
++    <listitem><para>David Champion <email>dgc at uchicago.edu</email></para></listitem>
++    <listitem><para>Richard Russon <email>rich at flatcap.org</email></para></listitem>
++    </itemizedlist>
++  </sect2>
++</sect1>
 +
-+#ifdef LIBNOTMUCH_CHECK_VERSION
-+#undef LIBNOTMUCH_CHECK_VERSION
-+#endif
++<sect1 id="new-mail-hook">
++  <title>new-mail Patch</title>
++  <subtitle>Execute a command upon the receipt of new mail.</subtitle>
 +
-+/* The definition in <notmuch.h> is broken */
-+#define LIBNOTMUCH_CHECK_VERSION(major, minor, micro)                               \
-+    (LIBNOTMUCH_MAJOR_VERSION > (major) ||                                          \
-+     (LIBNOTMUCH_MAJOR_VERSION == (major) && LIBNOTMUCH_MINOR_VERSION > (minor)) || \
-+     (LIBNOTMUCH_MAJOR_VERSION == (major) && LIBNOTMUCH_MINOR_VERSION == (minor) && \
-+      LIBNOTMUCH_MICRO_VERSION >= (micro)))
++  <sect2 id="new-mail-patch">
++    <title>Patch</title>
 +
++    <para>
++      To check if Mutt supports <quote>new-mail</quote>, look for
++      <quote>patch-new-mail</quote> in the mutt version.
++      See: <xref linkend="mutt-patches"/>.
++    </para>
 +
-+/* read whole-thread or matching messages only? */
-+enum {
-+	NM_QUERY_TYPE_MESGS = 1,	/* default */
-+	NM_QUERY_TYPE_THREADS
-+};
++    <itemizedlist>
++      <title>Dependencies:</title>
++      <listitem><para>mutt-1.6.2</para></listitem>
++    </itemizedlist>
 +
-+/*
-+ * Parsed URI arguments
-+ */
-+struct uri_tag {
-+	char *name;
-+	char *value;
-+	struct uri_tag *next;
-+};
++    <para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
++  </sect2>
 +
-+/*
-+ * HEADER->(nm_hdrdata *)data->tag_list node
-+ */
-+struct nm_hdrtag
-+{
-+  char *tag;
-+  char *transformed;
-+  struct nm_hdrtag *next;
-+};
++  <sect2 id="new-mail-intro">
++    <title>Introduction</title>
 +
-+/*
-+ * HEADER->data
-+ */
-+struct nm_hdrdata {
-+	char *folder;
-+	char *tags;
-+	char *tags_transformed;
-+	struct nm_hdrtag *tag_list;
-+	char *oldpath;
-+	char *virtual_id;
-+	int magic;
-+};
++    <para>
++      This patch enables the new_mail_command setting, which can be used to
++      execute a custom script (e.g., a notification handler) upon receiving a
++      new mail.
++    </para>
 +
-+/*
-+ * CONTEXT->data
-+ */
-+struct nm_ctxdata {
-+	notmuch_database_t *db;
++    <para>
++      The command string can contain expandos, such as <literal>%f</literal>
++      for the folder name.  For a complete list, see:
++      <link linkend="status-format">$status_format</link>.
++    </para>
 +
-+	char *db_filename;
-+	char *db_query;
-+	int db_limit;
-+	int query_type;
++    <para>
++      For example in Linux you can use (most distributions already provide notify-send):
++    </para>
 +
-+	struct uri_tag *query_items;
++<screen>
++set new_mail_command="notify-send --icon='/home/santiago/Pictures/mutt.png' 'New Email in %f' '%n new messages, %u unread.' &"
++</screen>
 +
-+	progress_t progress;
-+	int oldmsgcount;
-+	int ignmsgcount;	/* ingored messages */
++    <para>
++      And in OS X you will need to install a command line interface for
++      Notification Center, for example
++      <ulink url="https://github.com/julienXX/terminal-notifier">terminal-notifier</ulink>:
++    </para>
 +
-+	unsigned int noprogress : 1,
-+		     longrun : 1,
-+		     trans : 1,
-+		     progress_ready : 1;
++<screen>
++set new_mail_command="terminal-notifier -title '%v' -subtitle 'New Mail in %f' -message '%n new messages, %u unread.' -activate 'com.apple.Terminal'"
++</screen>
 +
-+};
++  </sect2>
++
++  <sect2 id="new-mail-variables">
++    <title>Variables</title>
++
++    <table id="table-new-mail-variables">
++      <title>New Mail Command Variables</title>
++      <tgroup cols="3">
++        <thead>
++          <row>
++            <entry>Name</entry>
++            <entry>Type</entry>
++            <entry>Default</entry>
++          </row>
++        </thead>
++        <tbody>
++          <row>
++            <entry><literal>new_mail_command</literal></entry>
++            <entry>string</entry>
++            <entry>(empty)</entry>
++          </row>
++        </tbody>
++      </tgroup>
++    </table>
++  </sect2>
++
++  <sect2 id="new-mail-muttrc">
++    <title>Muttrc</title>
++<screen>
++<emphasis role="comment"># Example Mutt config file for the 'new-mail-command' patch.
++ 
++# --------------------------------------------------------------------------
++# VARIABLES - shown with their default values
++# --------------------------------------------------------------------------
++ 
++# Set the command you want mutt to execute upon the receipt of a new email</emphasis>
++set new_mail_command = ""
++ 
++<emphasis role="comment"># Linux example:
++# set new_command="notify-send --icon='/home/santiago/Pictures/mutt.png' 'New Email in %f' '%n new messages, %u unread.' &"
++ 
++# OS X example:
++# set new_mail_command="terminal-notifier -title '%v' -subtitle 'New Mail in %f' -message '%n new messages, %u unread.' -activate 'com.apple.Terminal'"
 +
-+static HEADER *get_mutt_header(CONTEXT *ctx, notmuch_message_t *msg);
-+static notmuch_message_t *get_nm_message(notmuch_database_t *db, HEADER *hdr);
++# --------------------------------------------------------------------------
 +
-+static void url_free_tags(struct uri_tag *tags)
-+{
-+	while (tags) {
-+		struct uri_tag *next = tags->next;
-+		FREE(&tags->name);
-+		FREE(&tags->value);
-+		FREE(&tags);
-+		tags = next;
-+	}
-+}
++# vim: syntax=muttrc</emphasis>
++</screen>
++  </sect2>
 +
-+static int url_parse_query(char *url, char **filename, struct uri_tag **tags)
-+{
-+	char *p = strstr(url, "://");	/* remote unsupported */
-+	char *e;
-+	struct uri_tag *tag, *last = NULL;
++  <sect2 id="new-mail-see-also">
++    <title>See Also</title>
 +
-+	*filename = NULL;
-+	*tags = NULL;
++    <itemizedlist>
++      <listitem><para><ulink url="http://www.neomutt.org/">NeoMutt Project</ulink></para></listitem>
++      <listitem><para><link linkend="folder-hook">folder-hook</link></para></listitem>
++    </itemizedlist>
++  </sect2>
 +
-+	if (!p || !*(p + 3))
-+		return -1;
++  <sect2 id="new-mail-known-bugs">
++    <title>Known Bugs</title>
++    <itemizedlist>
++      <listitem>
++        <para>
++          Notifies about spurious <emphasis role="bold">new email</emphasis>
++          when an email is saved, see
++          <ulink url="https://github.com/neomutt/neomutt/issues/20">Issue #20</ulink>
++        </para>
++    </listitem>
++    <listitem>
++      <para>
++        Will not notify about new e-mail if the pager is open, see
++        <ulink url="https://github.com/neomutt/neomutt/issues/19">Issue #19</ulink>
++      </para>
++    </listitem>
++    </itemizedlist>
++  </sect2>
++
++  <sect2 id="new-mail-credits">
++    <title>Credits</title>
++    <itemizedlist>
++    <listitem><para>Yoshiki Vazquez-Baeza <email>yoshiki at ucsd.edu</email></para></listitem>
++    <listitem><para>Santiago Torres-Arias <email>santiago at nyu.edu</email></para></listitem>
++    <listitem><para>Richard Russon <email>rich at flatcap.org</email></para></listitem>
++    </itemizedlist>
++  </sect2>
++</sect1>
 +
-+	p += 3;
-+	*filename = p;
++<sect1 id="nntp">
++  <title>NNTP Patch</title>
++  <subtitle>Talk to a Usenet news server</subtitle>
++
++  <sect2 id="nntp-patch">
++    <title>Patch</title>
++
++    <para>
++      To check if Mutt supports <quote>NNTP</quote>, look for
++      <quote>+USE_NNTP</quote> in the mutt version.
++      See: <xref linkend="compile-time-features"/>.
++    </para>
++
++    <itemizedlist>
++      <title>Dependencies:</title>
++      <listitem><para>mutt-1.6.2</para></listitem>
++    </itemizedlist>
++
++    <para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
++  </sect2>
++
++  <sect2 id="nntp-intro">
++    <title>Introduction</title>
++
++    <para>Reading news via NNTP</para>
++    <para>
++    If compiled with <emphasis>--enable-nntp</emphasis> option, Mutt can
++    read news from news server via NNTP.  You can open a newsgroup with
++    function ``change-newsgroup'' (default: ``i'').  Default news server
++    can be obtained from <literal>$NNTPSERVER</literal> environment
++    variable or from <literal>/etc/nntpserver</literal> file.  Like other
++    news readers, info about subscribed newsgroups is saved in file by
++    <link linkend="newsrc">$newsrc</link> variable.  The variable <link
++    linkend="news-cache-dir">$news_cache_dir</link> can be used to point
++    to a directory.  Mutt will create a hierarchy of subdirectories named
++    like the account and newsgroup the cache is for.  Also the hierarchy
++    is used to store header cache if Mutt was compiled with <link
++    linkend="header-caching">header cache</link> support.
++    </para>
++  </sect2>
++
++  <sect2 id="nntp-variables">
++    <title>Variables</title>
++
++    <table id="table-nntp-variables">
++      <title>NNTP Variables</title>
++      <tgroup cols="3">
++        <thead>
++          <row>
++            <entry>Name</entry>
++            <entry>Type</entry>
++            <entry>Default</entry>
++          </row>
++        </thead>
++        <tbody>
++          <row>
++            <entry><literal>ask_follow_up</literal></entry>
++            <entry>boolean</entry>
++            <entry><literal>no</literal></entry>
++          </row>
++          <row>
++            <entry><literal>ask_x_comment_to</literal></entry>
++            <entry>boolean</entry>
++            <entry><literal>no</literal></entry>
++          </row>
++          <row>
++            <entry><literal>catchup_newsgroup</literal></entry>
++            <entry>quad</entry>
++            <entry><literal>ask-yes</literal></entry>
++          </row>
++          <row>
++            <entry><literal>followup_to_poster</literal></entry>
++            <entry>quad</entry>
++            <entry><literal>ask-yes</literal></entry>
++          </row>
++          <row>
++            <entry><literal>group_index_format</literal></entry>
++            <entry>string</entry>
++            <entry><literal>%4C %M%N %5s  %-45.45f %d</literal></entry>
++          </row>
++          <row>
++            <entry><literal>inews</literal></entry>
++            <entry>string</entry>
++            <entry>(empty)</entry>
++          </row>
++          <row>
++            <entry><literal>mime_subject</literal></entry>
++            <entry>boolean</entry>
++            <entry><literal>yes</literal></entry>
++          </row>
++          <row>
++            <entry><literal>newsgroups_charset</literal></entry>
++            <entry>string</entry>
++            <entry><literal>utf-8</literal></entry>
++          </row>
++          <row>
++            <entry><literal>newsrc</literal></entry>
++            <entry>string</entry>
++            <entry><literal>~/.newsrc</literal></entry>
++          </row>
++          <row>
++            <entry><literal>news_cache_dir</literal></entry>
++            <entry>string</entry>
++            <entry><literal>~/.mutt</literal></entry>
++          </row>
++          <row>
++            <entry><literal>news_server</literal></entry>
++            <entry>string</entry>
++            <entry>(empty)</entry>
++          </row>
++          <row>
++            <entry><literal>nntp_authenticators</literal></entry>
++            <entry>string</entry>
++            <entry>(empty)</entry>
++          </row>
++          <row>
++            <entry><literal>nntp_context</literal></entry>
++            <entry>number</entry>
++            <entry><literal>1000</literal></entry>
++          </row>
++          <row>
++            <entry><literal>nntp_listgroup</literal></entry>
++            <entry>boolean</entry>
++            <entry><literal>yes</literal></entry>
++          </row>
++          <row>
++            <entry><literal>nntp_load_description</literal></entry>
++            <entry>boolean</entry>
++            <entry><literal>yes</literal></entry>
++          </row>
++          <row>
++            <entry><literal>nntp_pass</literal></entry>
++            <entry>string</entry>
++            <entry>(empty)</entry>
++          </row>
++          <row>
++            <entry><literal>nntp_poll</literal></entry>
++            <entry>number</entry>
++            <entry><literal>60</literal></entry>
++          </row>
++          <row>
++            <entry><literal>nntp_user</literal></entry>
++            <entry>string</entry>
++            <entry>(empty)</entry>
++          </row>
++          <row>
++            <entry><literal>post_moderated</literal></entry>
++            <entry>quad</entry>
++            <entry><literal>ask-yes</literal></entry>
++          </row>
++          <row>
++            <entry><literal>save_unsubscribed</literal></entry>
++            <entry>boolean</entry>
++            <entry><literal>no</literal></entry>
++          </row>
++          <row>
++            <entry><literal>show_new_news</literal></entry>
++            <entry>boolean</entry>
++            <entry><literal>yes</literal></entry>
++          </row>
++          <row>
++            <entry><literal>show_only_unread</literal></entry>
++            <entry>boolean</entry>
++            <entry><literal>no</literal></entry>
++          </row>
++          <row>
++            <entry><literal>x_comment_to</literal></entry>
++            <entry>boolean</entry>
++            <entry><literal>no</literal></entry>
++          </row>
++        </tbody>
++      </tgroup>
++    </table>
++  </sect2>
++
++  <sect2 id="nntp-functions">
++    <title>Functions</title>
++
++    <table id="table-nntp-functions">
++      <title>NNTP Functions</title>
++      <tgroup cols="4">
++        <thead>
++          <row>
++            <entry>Menus</entry>
++            <entry>Default Key</entry>
++            <entry>Function</entry>
++            <entry>Description</entry>
++          </row>
++        </thead>
++        <tbody>
++          <row>
++            <entry>browser,index</entry>
++            <entry>y</entry>
++            <entry><literal><catchup></literal></entry>
++            <entry>mark all articles in newsgroup as read</entry>
++          </row>
++          <row>
++            <entry>index,pager</entry>
++            <entry>i</entry>
++            <entry><literal><change-newsgroup></literal></entry>
++            <entry>open a different newsgroup</entry>
++          </row>
++          <row>
++            <entry>pager</entry>
++            <entry>X</entry>
++            <entry><literal><change-vfolder></literal></entry>
++            <entry>open a different virtual folder</entry>
++          </row>
++          <row>
++            <entry>compose</entry>
++            <entry>o</entry>
++            <entry><literal><edit-followup-to></literal></entry>
++            <entry>edit the Followup-To field</entry>
++          </row>
++          <row>
++            <entry>compose</entry>
++            <entry>N</entry>
++            <entry><literal><edit-newsgroups></literal></entry>
++            <entry>edit the newsgroups list</entry>
++          </row>
++          <row>
++            <entry>compose</entry>
++            <entry>x</entry>
++            <entry><literal><edit-x-comment-to></literal></entry>
++            <entry>edit the X-Comment-To field</entry>
++          </row>
++          <row>
++            <entry>pager</entry>
++            <entry>+</entry>
++            <entry><literal><entire-thread></literal></entry>
++            <entry>read entire thread of the current message</entry>
++          </row>
++          <row>
++            <entry>attachment,index,pager</entry>
++            <entry>F</entry>
++            <entry><literal><followup-message></literal></entry>
++            <entry>followup to newsgroup</entry>
++          </row>
++          <row>
++            <entry>pager</entry>
++            <entry>`</entry>
++            <entry><literal><modify-labels></literal></entry>
++            <entry>modify (notmuch) tags</entry>
++          </row>
++          <row>
++            <entry>index,pager</entry>
++            <entry>P</entry>
++            <entry><literal><post-message></literal></entry>
++            <entry>post message to newsgroup</entry>
++          </row>
++          <row>
++            <entry>browser</entry>
++            <entry>g</entry>
++            <entry><literal><reload-active></literal></entry>
++            <entry>load list of all newsgroups from NNTP server</entry>
++          </row>
++          <row>
++            <entry>browser</entry>
++            <entry>s</entry>
++            <entry><literal><subscribe></literal></entry>
++            <entry>subscribe to current mbox (IMAP/NNTP only)</entry>
++          </row>
++          <row>
++            <entry>browser</entry>
++            <entry>S</entry>
++            <entry><literal><subscribe-pattern></literal></entry>
++            <entry>subscribe to newsgroups matching a pattern</entry>
++          </row>
++          <row>
++            <entry>browser</entry>
++            <entry>Y</entry>
++            <entry><literal><uncatchup></literal></entry>
++            <entry>mark all articles in newsgroup as unread</entry>
++          </row>
++          <row>
++            <entry>browser</entry>
++            <entry>u</entry>
++            <entry><literal><unsubscribe></literal></entry>
++            <entry>unsubscribe from current mbox (IMAP/NNTP only)</entry>
++          </row>
++          <row>
++            <entry>browser</entry>
++            <entry>U</entry>
++            <entry><literal><unsubscribe-pattern></literal></entry>
++            <entry>unsubscribe from newsgroups matching a pattern</entry>
++          </row>
++          <row>
++            <entry>index,pager</entry>
++            <entry>Alt-i</entry>
++            <entry><literal><change-newsgroup-readonly></literal></entry>
++            <entry>open a different newsgroup in read only mode</entry>
++          </row>
++          <row>
++            <entry>attachment,index,pager</entry>
++            <entry>Alt-F</entry>
++            <entry><literal><forward-to-group></literal></entry>
++            <entry>forward to newsgroup</entry>
++          </row>
++          <row>
++            <entry>index</entry>
++            <entry>(none)</entry>
++            <entry><literal><get-children></literal></entry>
++            <entry>get all children of the current message</entry>
++          </row>
++          <row>
++            <entry>index</entry>
++            <entry>Alt-G</entry>
++            <entry><literal><get-parent></literal></entry>
++            <entry>get parent of the current message</entry>
++          </row>
++          <row>
++            <entry>index,pager</entry>
++            <entry>(none)</entry>
++            <entry><literal><imap-fetch-mail></literal></entry>
++            <entry>force retrieval of mail from IMAP server</entry>
++          </row>
++          <row>
++            <entry>index,pager</entry>
++            <entry>(none)</entry>
++            <entry><literal><imap-logout-all></literal></entry>
++            <entry>logout from all IMAP servers</entry>
++          </row>
++          <row>
++            <entry>pager</entry>
++            <entry>(none)</entry>
++            <entry><literal><modify-labels-then-hide></literal></entry>
++            <entry>modify labeld and then hide message</entry>
++          </row>
++          <row>
++            <entry>index</entry>
++            <entry>(none)</entry>
++            <entry><literal><reconstruct-thread></literal></entry>
++            <entry>reconstruct thread containing current message</entry>
++          </row>
++          <row>
++            <entry>pager</entry>
++            <entry>Alt-X</entry>
++            <entry><literal><vfolder-from-query></literal></entry>
++            <entry>generate virtual folder from query</entry>
++          </row>
++          <row>
++            <entry>index</entry>
++            <entry>Ctrl-G</entry>
++            <entry><literal><get-message></literal></entry>
++            <entry>get message with Message-Id</entry>
++          </row>
++        </tbody>
++      </tgroup>
++    </table>
++  </sect2>
 +
-+	e = strchr(p, '?');
++<!--
++  <sect2 id="nntp-commands">
++    <title>Commands</title>
++  </sect2>
 +
-+	*filename = e ? e == p ? NULL : strndup(p, e - p) : safe_strdup(p);
-+	if (!e)
-+		return 0;
++  <sect2 id="nntp-colors">
++    <title>Colors</title>
++  </sect2>
 +
-+	if (*filename && url_pct_decode(*filename) < 0)
-+		goto err;
-+	if (!e)
-+		return 0;	/* only filename */
++  <sect2 id="nntp-sort">
++    <title>Sort</title>
++  </sect2>
++-->
 +
-+	++e;	/* skip '?' */
-+	p = e;
++  <sect2 id="nntp-muttrc">
++    <title>Muttrc</title>
 +
-+	while (p && *p) {
-+		tag = safe_calloc(1, sizeof(struct uri_tag));
-+		if (!tag)
-+			goto err;
++<screen>
++<emphasis role="comment"># This is a complete list of nntp configuration.
++
++# --------------------------------------------------------------------------
++# VARIABLES - shown with their default values
++# --------------------------------------------------------------------------</emphasis>
++
++set ask_follow_up = no
++set ask_x_comment_to = no
++set catchup_newsgroup = ask-yes
++set followup_to_poster = ask-yes
++set group_index_format = '%4C %M%N %5s  %-45.45f %d'
++set inews = ''
++set mime_subject = yes
++set newsgroups_charset = utf-8
++set newsrc = '~/.newsrc'
++set news_cache_dir = '~/.mutt'
++set news_server = ''
++set nntp_authenticators = ''
++set nntp_context = 1000
++set nntp_listgroup = yes
++set nntp_load_description = yes
++set nntp_pass = ''
++set nntp_poll = 60
++set nntp_user = ''
++set post_moderated = ask-yes
++set save_unsubscribed = no
++set show_new_news = yes
++set show_only_unread = no
++set x_comment_to = no
++
++<emphasis role="comment"># --------------------------------------------------------------------------
++# FUNCTIONS - shown with an example mapping
++# --------------------------------------------------------------------------
++
++# mark all articles in newsgroup as read</emphasis>
++bind browser,index y catchup 
++
++<emphasis role="comment"># open a different newsgroup</emphasis>
++bind index,pager i change-newsgroup 
++
++<emphasis role="comment"># open a different virtual folder</emphasis>
++bind pager X change-vfolder 
++
++<emphasis role="comment"># edit the Followup-To field</emphasis>
++bind compose o edit-followup-to 
++
++<emphasis role="comment"># edit the newsgroups list</emphasis>
++bind compose N edit-newsgroups 
++
++<emphasis role="comment"># edit the X-Comment-To field</emphasis>
++bind compose x edit-x-comment-to 
++
++<emphasis role="comment"># read entire thread of the current message</emphasis>
++bind pager + entire-thread 
++
++<emphasis role="comment"># followup to newsgroup</emphasis>
++bind attachment,index,pager F followup-message 
++
++<emphasis role="comment"># modify (notmuch) tags</emphasis>
++bind pager ` modify-labels 
++
++<emphasis role="comment"># post message to newsgroup</emphasis>
++bind index,pager P post-message 
++
++<emphasis role="comment"># load list of all newsgroups from NNTP server</emphasis>
++bind browser g reload-active 
++
++<emphasis role="comment"># subscribe to current mbox (IMAP/NNTP only)</emphasis>
++bind browser s subscribe 
++
++<emphasis role="comment"># subscribe to newsgroups matching a pattern</emphasis>
++bind browser S subscribe-pattern 
++
++<emphasis role="comment"># mark all articles in newsgroup as unread</emphasis>
++bind browser Y uncatchup 
++
++<emphasis role="comment"># unsubscribe from current mbox (IMAP/NNTP only)</emphasis>
++bind browser u unsubscribe 
++
++<emphasis role="comment"># unsubscribe from newsgroups matching a pattern</emphasis>
++bind browser U unsubscribe-pattern 
++
++<emphasis role="comment"># open a different newsgroup in read only mode</emphasis>
++bind index,pager \ei change-newsgroup-readonly 
++
++<emphasis role="comment"># forward to newsgroup</emphasis>
++bind attachment,index,pager \eF forward-to-group 
++
++<emphasis role="comment"># get all children of the current message</emphasis>
++# bind index ??? get-children 
++
++<emphasis role="comment"># get parent of the current message</emphasis>
++bind index \eG get-parent 
++
++<emphasis role="comment"># force retrieval of mail from IMAP server
++# bind index,pager ??? imap-fetch-mail 
++
++# logout from all IMAP servers
++# bind index,pager ??? imap-logout-all 
++
++# modify labeld and then hide message
++# bind pager ??? modify-labels-then-hide 
++
++# reconstruct thread containing current message
++# bind index ??? reconstruct-thread 
++
++# generate virtual folder from query</emphasis>
++bind pager \eX vfolder-from-query 
++
++<emphasis role="comment"># get message with Message-Id</emphasis>
++bind index \CG get-message 
++
++<emphasis role="comment"># --------------------------------------------------------------------------
++
++# vim: syntax=muttrc</emphasis>
++</screen>
++  </sect2>
++
++  <sect2 id="nntp-see-also">
++    <title>See Also</title>
++
++    <itemizedlist>
++      <listitem><para><ulink url="http://www.neomutt.org/">NeoMutt Project</ulink></para></listitem>
++      <listitem><para><link linkend="compile-time-features">Compile-Time Features</link></para></listitem>
++    </itemizedlist>
++  </sect2>
++
++  <sect2 id="nntp-known-bugs">
++    <title>Known Bugs</title>
++    <para>
++      None
++    </para>
++  </sect2>
++
++  <sect2 id="nntp-credits">
++    <title>Credits</title>
++    <itemizedlist>
++    <listitem><para>Vsevolod Volkov <email>vvv at mutt.org.ua</email></para></listitem>
++    <listitem><para>Felix von Leitner <email>leitner at fefe.de</email></para></listitem>
++    <listitem><para>Richard Russon <email>rich at flatcap.org</email></para></listitem>
++    </itemizedlist>
++  </sect2>
++</sect1>
++
++<sect1 id="notmuch">
++  <title>Notmuch Patch</title>
++  <subtitle>Email search engine</subtitle>
++
++  <sect2 id="notmuch-patch">
++    <title>Patch</title>
++
++    <para>
++      To check if Mutt supports <quote>Notmuch</quote>, look for
++      <quote>+USE_NOTMUCH</quote> in the mutt version.
++      See: <xref linkend="compile-time-features"/>.
++    </para>
 +
-+		if (!*tags)
-+			last = *tags = tag;
-+		else {
-+			last->next = tag;
-+			last = tag;
-+		}
++    <itemizedlist>
++      <title>Dependencies:</title>
++      <listitem><para>mutt-1.6.2</para></listitem>
++      <listitem><para><link linkend="sidebar">sidebar patch</link></para></listitem>
++      <listitem><para><link linkend="quasi-delete">quasi-delete patch</link></para></listitem>
++      <listitem><para><link linkend="index-color">index-color patch</link></para></listitem>
++      <listitem><para>Notmuch libraries</para></listitem>
++    </itemizedlist>
 +
-+		e = strchr(p, '=');
-+		if (!e)
-+			e = strchr(p, '&');
-+		tag->name = e ? strndup(p, e - p) : safe_strdup(p);
-+		if (!tag->name || url_pct_decode(tag->name) < 0)
-+			goto err;
-+		if (!e)
-+			break;
++    <para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
++  </sect2>
 +
-+		p = e + 1;
++<!--
++  <sect2 id="notmuch-intro">
++    <title>Introduction</title>
++  </sect2>
++-->
 +
-+		if (*e == '&')
-+			continue;
++  <sect2 id="notmuch-variables">
++    <title>Variables</title>
++
++    <table id="table-notmuch-variables">
++      <title>Notmuch Variables</title>
++      <tgroup cols="3">
++        <thead>
++          <row>
++            <entry>Name</entry>
++            <entry>Type</entry>
++            <entry>Default</entry>
++          </row>
++        </thead>
++        <tbody>
++          <row>
++            <entry><literal>nm_db_limit</literal></entry>
++            <entry>number</entry>
++            <entry><literal>0</literal></entry>
++          </row>
++          <row>
++            <entry><literal>nm_default_uri</literal></entry>
++            <entry>string</entry>
++            <entry>(empty)</entry>
++          </row>
++          <row>
++            <entry><literal>nm_exclude_tags</literal></entry>
++            <entry>string</entry>
++            <entry>(empty)</entry>
++          </row>
++          <row>
++            <entry><literal>nm_hidden_tags</literal></entry>
++            <entry>string</entry>
++            <entry><literal>unread,draft,flagged,passed,replied,attachment,signed,encrypted</literal></entry>
++          </row>
++          <row>
++            <entry><literal>nm_open_timeout</literal></entry>
++            <entry>number</entry>
++            <entry><literal>5</literal></entry>
++          </row>
++          <row>
++            <entry><literal>nm_query_type</literal></entry>
++            <entry>string</entry>
++            <entry><literal>messages</literal></entry>
++          </row>
++          <row>
++            <entry><literal>nm_record</literal></entry>
++            <entry>boolean</entry>
++            <entry><literal>no</literal></entry>
++          </row>
++          <row>
++            <entry><literal>nm_record_tags</literal></entry>
++            <entry>string</entry>
++            <entry>(empty)</entry>
++          </row>
++          <row>
++            <entry><literal>nm_unread_tag</literal></entry>
++            <entry>string</entry>
++            <entry><literal>unread</literal></entry>
++          </row>
++          <row>
++            <entry><literal>vfolder_format</literal></entry>
++            <entry>string</entry>
++            <entry><literal>%6n(%6N) %f</literal></entry>
++          </row>
++          <row>
++            <entry><literal>virtual_spoolfile</literal></entry>
++            <entry>boolean</entry>
++            <entry><literal>no</literal></entry>
++          </row>
++        </tbody>
++      </tgroup>
++    </table>
++  </sect2>
++
++  <sect2 id="notmuch-functions">
++    <title>Functions</title>
++
++    <table id="table-notmuch-functions">
++      <title>Notmuch Functions</title>
++      <tgroup cols="4">
++        <thead>
++          <row>
++            <entry>Menus</entry>
++            <entry>Default Key</entry>
++            <entry>Function</entry>
++            <entry>Description</entry>
++          </row>
++        </thead>
++        <tbody>
++          <row>
++            <entry>index,pager</entry>
++            <entry>X</entry>
++            <entry><literal><change-vfolder></literal></entry>
++            <entry>open a different virtual folder</entry>
++          </row>
++          <row>
++            <entry>index,pager</entry>
++            <entry>+</entry>
++            <entry><literal><entire-thread></literal></entry>
++            <entry>read entire thread of the current message</entry>
++          </row>
++          <row>
++            <entry>index,pager</entry>
++            <entry>`</entry>
++            <entry><literal><modify-labels></literal></entry>
++            <entry>modify (notmuch) tags</entry>
++          </row>
++          <row>
++            <entry>index,pager</entry>
++            <entry>(none)</entry>
++            <entry><literal><modify-labels-then-hide></literal></entry>
++            <entry>modify labels and then hide message</entry>
++          </row>
++          <row>
++            <entry>index,pager</entry>
++            <entry>(none)</entry>
++            <entry><literal><sidebar-toggle-virtual></literal></entry>
++            <entry>toggle between mailboxes and virtual mailboxes</entry>
++          </row>
++          <row>
++            <entry>index,pager</entry>
++            <entry>Alt-X</entry>
++            <entry><literal><vfolder-from-query></literal></entry>
++            <entry>generate virtual folder from query</entry>
++          </row>
++        </tbody>
++      </tgroup>
++    </table>
++  </sect2>
++
++  <sect2 id="notmuch-commands">
++    <title>Commands</title>
++    <cmdsynopsis>
++
++      <command>virtual-mailboxes</command>
++      <arg choice="plain">
++        <replaceable class="parameter">description</replaceable>
++        <arg choice="plain">
++          <replaceable class="parameter">notmuch-URI</replaceable>
++        </arg>
++      </arg>
++      <group choice="req" rep="repeat">
++        <arg choice="plain">
++          <replaceable class="parameter">description</replaceable>
++          <arg choice="plain">
++            <replaceable class="parameter">notmuch-URI</replaceable>
++          </arg>
++        </arg>
++      </group>
++
++      <command>tag-transforms</command>
++      <arg choice="plain">
++        <replaceable class="parameter">tag</replaceable>
++        <arg choice="plain">
++          <replaceable class="parameter">transformed-string</replaceable>
++        </arg>
++      </arg>
++      <group choice="req" rep="repeat">
++        <arg choice="plain">
++          <replaceable class="parameter">tag</replaceable>
++          <arg choice="plain">
++            <replaceable class="parameter">transformed-string</replaceable>
++          </arg>
++        </arg>
++      </group>
++
++      <command>tag-formats</command>
++      <arg choice="plain">
++        <replaceable class="parameter">tag</replaceable>
++        <arg choice="plain">
++          <replaceable class="parameter">format-string</replaceable>
++        </arg>
++      </arg>
++      <group choice="req" rep="repeat">
++        <arg choice="plain">
++          <replaceable class="parameter">tag</replaceable>
++          <arg choice="plain">
++            <replaceable class="parameter">format-string</replaceable>
++          </arg>
++        </arg>
++      </group>
++
++    </cmdsynopsis>
++  </sect2>
++
++  <sect2 id="notmuch-colors">
++    <title>Colors</title>
++
++    <para>Adds these to index-color patch:</para>
++
++    <table id="table-notmuch-colors">
++      <title>Index Colors</title>
++      <tgroup cols="3">
++        <thead>
++          <row>
++            <entry>Object</entry>
++            <entry>Pattern</entry>
++            <entry>Highlights</entry>
++          </row>
++        </thead>
++        <tbody>
++          <row>
++            <entry><literal>index_tag</literal></entry>
++            <entry>yes</entry>
++            <entry>an individual message tag, %G, uses tag name</entry>
++          </row>
++          <row>
++            <entry><literal>index_tags</literal></entry>
++            <entry>no</entry>
++            <entry>the transformed message tags, %g</entry>
++          </row>
++        </tbody>
++      </tgroup>
++    </table>
++  </sect2>
 +
-+		e = strchr(p, '&');
-+		tag->value = e ? strndup(p, e - p) : safe_strdup(p);
-+		if (!tag->value || url_pct_decode(tag->value) < 0)
-+			goto err;
-+		if (!e)
-+			break;
-+		p = e + 1;
-+	}
++<!--
++  <sect2 id="notmuch-sort">
++    <title>Sort</title>
++  </sect2>
++-->
 +
-+	return 0;
-+err:
-+	FREE(&(*filename));
-+	url_free_tags(*tags);
-+	return -1;
-+}
++  <sect2 id="notmuch-muttrc">
++    <title>Muttrc</title>
 +
-+static void free_tag_list(struct nm_hdrtag **tag_list)
-+{
-+	struct nm_hdrtag *tmp;
++<screen>
++<emphasis role="comment"># This is a complete list of notmuch-related configuration.
++ 
++# --------------------------------------------------------------------------
++# VARIABLES - shown with their default values
++# --------------------------------------------------------------------------
++ 
++# This variable specifies notmuch query limit.</emphasis>
++set nm_db_limit = 0
++ 
++<emphasis role="comment"># This variable specifies the default Notmuch database in format:
++# notmuch://<absolute path></emphasis>
++set nm_default_uri = ""
++ 
++<emphasis role="comment"># The messages tagged with these tags are excluded and not loaded
++# from notmuch DB to mutt unless specified explicitly.</emphasis>
++set nm_exclude_tags = ""
++ 
++<emphasis role="comment"># This variable specifies private notmuch tags which should not be printed
++# on screen (index, pager).</emphasis>
++set nm_hidden_tags = "unread,draft,flagged,passed,replied,attachment,signed,encrypted"
++ 
++<emphasis role="comment"># This option specifies timeout for Notmuch database. Default is 5 seconds.</emphasis>
++set nm_open_timeout = 5
++ 
++<emphasis role="comment"># This variable specifies notmuch query type, supported types: 'threads' and</emphasis>
++# 'messages'.
++set nm_query_type = messages
++ 
++<emphasis role="comment"># Add messages stored to the mutt record (see $record in the mutt docs)
++# also to notmuch DB.</emphasis>
++set nm_record = no
++ 
++<emphasis role="comment"># Tags that should be removed or added to the to the messages stored in the mutt record.</emphasis>
++set nm_record_tags = ""
++ 
++<emphasis role="comment"># This variable specifies notmuch tag which is used for unread messages.</emphasis>
++set nm_unread_tag = unread
++ 
++<emphasis role="comment"># This variable allows you to customize the file browser display for virtual
++# folders to your personal taste.</emphasis>
++set vfolder_format = "%6n(%6N) %f"
++ 
++<emphasis role="comment"># When set, mutt will use the first virtual mailbox (see virtual-mailboxes)
++# as a spoolfile.</emphasis>
++set virtual_spoolfile = no
++ 
++<emphasis role="comment"># --------------------------------------------------------------------------
++# FUNCTIONS - shown with an example mapping
++# --------------------------------------------------------------------------
++ 
++# open a different virtual folder</emphasis>
++bind index,pager X change-vfolder 
++ 
++<emphasis role="comment"># read entire thread of the current message</emphasis>
++bind index,pager + entire-thread 
++ 
++<emphasis role="comment"># modify (notmuch) tags</emphasis>
++bind index,pager ` modify-labels 
++ 
++<emphasis role="comment"># generate virtual folder from query</emphasis>
++bind index,pager \eX vfolder-from-query 
++ 
++<emphasis role="comment"># modify labels and then hide message
++# bind index,pager ??? modify-labels-then-hide 
++ 
++# toggle between mailboxes and virtual mailboxes
++# bind index,pager ??? sidebar-toggle-virtual 
++ 
++# --------------------------------------------------------------------------
++# COMMANDS - shown with an example
++# --------------------------------------------------------------------------
++ 
++# virtual-mailboxes description notmuch-URI { description notmuch-URI ...}
++# virtual-mailboxes "Climbing" "notmuch://?query=climbing"
++ 
++# Replace some tags with icons
++# tag-transforms tag transformed-string { tag transformed-string ...}
++# tag-transforms "inbox"   "i"   \
++#                "unread"  "u"   \
++#                "replied" "↻ "  \
++#                "sent"    "➥ "  \
++#                "todo"    "T"   \
++#                "deleted" "DEL" \
++#                "invites" "CAL"
++ 
++# See README.notmuch for an explanation
++# tag-formats tag format-string { tag format-string ...}
++# tag-formats "inbox"   "GI" \
++#              "unread"  "GU" \
++#              "replied" "GR" \
++#              "sent"    "GS" \
++#              "todo"    "Gt" \
++#              "deleted" "GD" \
++#              "invites" "Gi"
++ 
++# set index_format='4C %S %[%y.%m.%d] %-18.18n %?GU?%GU& ? %?GR?%GR& ? %?GI?%GI& ? %s'
++ 
++# --------------------------------------------------------------------------
++# COLORS - some unpleasant examples are given
++# --------------------------------------------------------------------------
++ 
++# These symbols are added to the index-color patch:
++ 
++# an individual message tag, %G, uses tag name
++# this symbol uses a pattern</emphasis>
++color index_tag red white "inbox"
++ 
++<emphasis role="comment"># the transformed message tags, %g
++# this symbol does not use a pattern</emphasis>
++color index_tags green default
++ 
++<emphasis role="comment"># --------------------------------------------------------------------------
++ 
++# vim: syntax=muttrc</emphasis>
++</screen>
++  </sect2>
++
++  <sect2 id="notmuch-see-also">
++    <title>See Also</title>
++
++    <itemizedlist>
++      <listitem><para><ulink url="http://www.neomutt.org/">NeoMutt Project</ulink></para></listitem>
++      <listitem><para><link linkend="compile-time-features">Compile-Time Features</link></para></listitem>
++    </itemizedlist>
++  </sect2>
++
++  <sect2 id="notmuch-known-bugs">
++    <title>Known Bugs</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="notmuch-credits">
++    <title>Credits</title>
++    <itemizedlist>
++    <listitem><para>Karel Zak <email>kzak at redhat.com</email></para></listitem>
++    <listitem><para>Chris Mason <email>clm at fb.com</email></para></listitem>
++    <listitem><para>Christoph Rissner <email>cri at visotech.at</email></para></listitem>
++    <listitem><para>David Riebenbauer <email>davrieb at liegesta.at</email></para></listitem>
++    <listitem><para>David Sterba <email>dsterba at suse.cz</email></para></listitem>
++    <listitem><para>David Wilson <email>dw at botanicus.net</email></para></listitem>
++    <listitem><para>Don Zickus <email>dzickus at redhat.com</email></para></listitem>
++    <listitem><para>Eric Davis <email>edavis at insanum.com</email></para></listitem>
++    <listitem><para>Jan Synacek <email>jsynacek at redhat.com</email></para></listitem>
++    <listitem><para>Jeremiah C. Foster <email>jeremiah at jeremiahfoster.com</email></para></listitem>
++    <listitem><para>Josh Poimboeuf <email>jpoimboe at redhat.com</email></para></listitem>
++    <listitem><para>Kirill A. Shutemov <email>kirill at shutemov.name</email></para></listitem>
++    <listitem><para>Luke Macken <email>lmacken at redhat.com</email></para></listitem>
++    <listitem><para>Mantas Mikulėnas <email>grawity at gmail.com</email></para></listitem>
++    <listitem><para>Patrick Brisbin <email>pbrisbin at gmail.com</email></para></listitem>
++    <listitem><para>Philippe Le Brouster <email>plb at nebkha.net</email></para></listitem>
++    <listitem><para>Raghavendra D Prabhu <email>rprabhu at wnohang.net</email></para></listitem>
++    <listitem><para>Sami Farin <email>hvtaifwkbgefbaei at gmail.com</email></para></listitem>
++    <listitem><para>Stefan Assmann <email>sassmann at kpanic.de</email></para></listitem>
++    <listitem><para>Stefan Kuhn <email>p_regius at gmx.ch</email></para></listitem>
++    <listitem><para>Tim Stoakes <email>tim at stoakes.net</email></para></listitem>
++    <listitem><para>Vladimir Marek <email>Vladimir.Marek at oracle.com</email></para></listitem>
++    <listitem><para>Víctor Manuel Jáquez Leal <email>vjaquez at igalia.com</email></para></listitem>
++    <listitem><para>Richard Russon <email>rich at flatcap.org</email></para></listitem>
++    </itemizedlist>
++  </sect2>
++</sect1>
 +
-+	while ((tmp = *tag_list) != NULL)
-+	{
-+		*tag_list = tmp->next;
-+		FREE(&tmp->tag);
-+		FREE(&tmp->transformed);
-+		FREE(&tmp);
-+	}
++<sect1 id="progress">
++  <title>Progress Bar Patch</title>
++  <subtitle>Show a visual progress bar on slow operations</subtitle>
 +
-+	*tag_list = 0;
-+}
++  <sect2 id="progress-patch">
++    <title>Patch</title>
 +
-+static void free_hdrdata(struct nm_hdrdata *data)
-+{
-+	if (!data)
-+		return;
++    <para>
++      To check if Mutt supports <quote>Progress Bar</quote>, look for
++      <quote>patch-progress</quote> in the mutt version.
++      See: <xref linkend="mutt-patches"/>.
++    </para>
 +
-+	dprint(2, (debugfile, "nm: freeing header %p\n", data));
-+	FREE(&data->folder);
-+	FREE(&data->tags);
-+	FREE(&data->tags_transformed);
-+	free_tag_list(&data->tag_list);
-+	FREE(&data->oldpath);
-+	FREE(&data->virtual_id);
-+	FREE(&data);
-+}
++    <itemizedlist>
++      <title>Dependencies:</title>
++      <listitem><para>mutt-1.6.2</para></listitem>
++    </itemizedlist>
 +
-+static void free_ctxdata(struct nm_ctxdata *data)
-+{
-+	if (!data)
-+		return;
++    <para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
++  </sect2>
 +
-+	dprint(1, (debugfile, "nm: freeing context data %p\n", data));
++  <sect2 id="progress-intro">
++    <title>Introduction</title>
 +
-+	if (data->db)
-+#ifdef NOTMUCH_API_3
-+	        notmuch_database_destroy(data->db);
-+#else
-+		notmuch_database_close(data->db);
-+#endif
-+	data->db = NULL;
++        <para>
++    The <quote>progress</quote> patch shows a visual progress bar on slow
++    tasks, such as indexing a large folder over the net.
++        </para>
++  </sect2>
 +
-+	FREE(&data->db_filename);
-+	FREE(&data->db_query);
-+	url_free_tags(data->query_items);
-+	FREE(&data);
-+}
++<!--
++  <sect2 id="progress-variables">
++    <title>Variables</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="progress-functions">
++    <title>Functions</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="progress-commands">
++    <title>Commands</title>
++    <para>None</para>
++  </sect2>
++-->
 +
-+static struct nm_ctxdata *new_ctxdata(char *uri)
-+{
-+	struct nm_ctxdata *data;
++  <sect2 id="progress-colors">
++    <title>Colors</title>
++    <table id="table-progress-colors">
++      <title>Progress Colors</title>
++      <tgroup cols="3">
++        <thead>
++          <row>
++            <entry>Name</entry>
++            <entry>Default Color</entry>
++            <entry>Description</entry>
++          </row>
++        </thead>
++        <tbody>
++          <row>
++            <entry><literal>progress</literal></entry>
++            <entry>default</entry>
++            <entry>Visual progress bar</entry>
++          </row>
++        </tbody>
++      </tgroup>
++    </table>
++  </sect2>
 +
-+	if (!uri)
-+		return NULL;
++<!--
++  <sect2 id="progress-sort">
++    <title>Sort</title>
++    <para>None</para>
++  </sect2>
++-->
 +
-+	data = safe_calloc(1, sizeof(struct nm_ctxdata));
-+	dprint(1, (debugfile, "nm: initialize context data %p\n", data));
++  <sect2 id="progress-muttrc">
++    <title>Muttrc</title>
++<screen>
++<emphasis role="comment"># Example Mutt config file for the 'progress' patch.
++ 
++# The 'progress' patch provides clear visual feedback for
++# slow tasks, such as indexing a large folder over the net.
++ 
++# Set the color of the progress bar
++# White text on a red background</emphasis>
++color progress white red
++ 
++<emphasis role="comment"># vim: syntax=muttrc</emphasis>
++</screen>
++  </sect2>
++
++  <sect2 id="progress-see-also">
++    <title>See Also</title>
++
++    <itemizedlist>
++      <listitem><para><ulink url="http://www.neomutt.org/">NeoMutt Project</ulink></para></listitem>
++      <listitem><para><link linkend="color">Color command</link></para></listitem>
++    </itemizedlist>
++  </sect2>
++
++  <sect2 id="progress-known-bugs">
++    <title>Known Bugs</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="progress-credits">
++    <title>Credits</title>
++    <itemizedlist>
++    <listitem><para>Rocco Rutte <email>pdmef at gmx.net</email></para></listitem>
++    <listitem><para>Vincent Lefevre <email>vincent at vinc17.org</email></para></listitem>
++    <listitem><para>Stefan Kuhn <email>wuodan at hispeed.ch</email></para></listitem>
++    <listitem><para>Karel Zak <email>kzak at redhat.com</email></para></listitem>
++    <listitem><para>Richard Russon <email>rich at flatcap.org</email></para></listitem>
++    </itemizedlist>
++  </sect2>
++</sect1>
 +
-+	data->db_limit = NotmuchDBLimit;
++<sect1 id="quasi-delete">
++  <title>Quasi-Delete Patch</title>
++  <subtitle>Mark emails that should be hidden, but not deleted</subtitle>
 +
-+	if (url_parse_query(uri, &data->db_filename, &data->query_items)) {
-+		mutt_error(_("failed to parse notmuch uri: %s"), uri);
-+		data->db_filename = NULL;
-+		data->query_items = NULL;
-+		data->query_type = 0;
-+		return NULL;
-+	}
++  <sect2 id="quasi-delete-patch">
++    <title>Patch</title>
 +
-+	return data;
-+}
++    <para>
++      To check if Mutt supports <quote>Quasi-Delete</quote>, look for
++      <quote>patch-quasi-delete</quote> in the mutt version.
++      See: <xref linkend="mutt-patches"/>.
++    </para>
 +
-+static int deinit_context(CONTEXT *ctx)
-+{
-+	int i;
++    <itemizedlist>
++      <title>Dependencies:</title>
++      <listitem><para>mutt-1.6.2</para></listitem>
++    </itemizedlist>
 +
-+	if (!ctx || ctx->magic != M_NOTMUCH)
-+		return -1;
++    <para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
++  </sect2>
 +
-+	for (i = 0; i < ctx->msgcount; i++) {
-+		HEADER *h = ctx->hdrs[i];
++  <sect2 id="quasi-delete-intro">
++    <title>Introduction</title>
 +
-+		if (h) {
-+			free_hdrdata(h->data);
-+			h->data = NULL;
-+		}
-+	}
++        <para>
++    The <quote>quasi-delete</quote> function marks an email that should be
++    hidden from the index, but NOT deleted.
++        </para>
 +
-+	free_ctxdata(ctx->data);
-+	ctx->data = NULL;
-+	return 0;
-+}
++        <para>
++    On its own, this patch isn't very useful.  It forms a useful part of
++    the notmuch plugin.
++        </para>
++  </sect2>
 +
-+static int init_context(CONTEXT *ctx)
-+{
-+	if (!ctx || ctx->magic != M_NOTMUCH)
-+		return -1;
++<!--
++  <sect2 id="quasi-delete-variables">
++    <title>Variables</title>
++    <para>None</para>
++  </sect2>
++-->
 +
-+	if (ctx->data)
-+		return 0;
++  <sect2 id="quasi-delete-functions">
++    <title>Functions</title>
++    <table id="table-quasi-delete-functions">
++      <title>Quasi-Delete Functions</title>
++      <tgroup cols="4">
++        <thead>
++          <row>
++            <entry>Menus</entry>
++            <entry>Default Key</entry>
++            <entry>Function</entry>
++            <entry>Description</entry>
++          </row>
++        </thead>
++        <tbody>
++          <row>
++            <entry>index,pager</entry>
++            <entry>(none)</entry>
++            <entry><literal><quasi-delete></literal></entry>
++            <entry>delete from mutt, don't touch on disk</entry>
++          </row>
++        </tbody>
++      </tgroup>
++    </table>
++  </sect2>
 +
-+	ctx->data = new_ctxdata(ctx->path);
-+	if (!ctx->data)
-+		return -1;
++<!--
++  <sect2 id="quasi-delete-commands">
++    <title>Commands</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="quasi-delete-colors">
++    <title>Colors</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="quasi-delete-sort">
++    <title>Sort</title>
++    <para>None</para>
++  </sect2>
++-->
 +
-+	ctx->mx_close = deinit_context;
-+	return 0;
-+}
++  <sect2 id="quasi-delete-muttrc">
++    <title>Muttrc</title>
++<screen>
++<emphasis role="comment"># Example Mutt config file for the 'quasi-delete' feature.
++ 
++# The 'quasi-delete' function marks an email that should be hidden
++# from the index, but NOT deleted.</emphasis>
++bind index,pager Q quasi-delete
++ 
++<emphasis role="comment"># vim: syntax=muttrc</emphasis>
++</screen>
++  </sect2>
++
++  <sect2 id="quasi-delete-see-also">
++    <title>See Also</title>
++
++    <itemizedlist>
++      <listitem><para><ulink url="http://www.neomutt.org/">NeoMutt Project</ulink></para></listitem>
++      <listitem><para><link linkend="notmuch">notmuch patch</link></para></listitem>
++    </itemizedlist>
++  </sect2>
++
++  <sect2 id="quasi-delete-known-bugs">
++    <title>Known Bugs</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="quasi-delete-credits">
++    <title>Credits</title>
++    <itemizedlist>
++    <listitem><para>Karel Zak <email>kzak at redhat.com</email></para></listitem>
++    <listitem><para>Richard Russon <email>rich at flatcap.org</email></para></listitem>
++    </itemizedlist>
++  </sect2>
++</sect1>
 +
-+char *nm_header_get_folder(HEADER *h)
-+{
-+	return h && h->data ? ((struct nm_hdrdata *) h->data)->folder : NULL;
-+}
++<sect1 id="sidebar">
++  <title>Sidebar Patch</title>
++  <subtitle>Overview of mailboxes</subtitle>
++
++  <sect2 id="sidebar-patch">
++    <title>Patch</title>
++
++    <para>
++      To check if Mutt supports <quote>Sidebar</quote>, look for
++      <quote>+USE_SIDEBAR</quote> in the mutt version.
++      See: <xref linkend="compile-time-features"/>.
++    </para>
++
++    <itemizedlist>
++      <title>Dependencies:</title>
++      <listitem><para>mutt-1.6.2</para></listitem>
++    </itemizedlist>
++
++    <para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
++  </sect2>
++
++  <sect2 id="sidebar-intro">
++    <title>Introduction</title>
++
++    <para>
++      The Sidebar shows a list of all your mailboxes.  The list can be
++      turned on and off, it can be themed and the list style can be
++      configured.
++    </para>
++
++    <para>
++      This part of the manual is a reference guide.
++      If you want a simple introduction with examples see the
++      <link linkend="intro-sidebar">Sidebar Howto</link>.
++      If you just want to get started, you could use the sample
++      <link linkend="sidebar-muttrc">Sidebar muttrc</link>.
++    </para>
++  </sect2>
++
++  <sect2 id="sidebar-variables">
++    <title>Variables</title>
++
++    <table id="table-sidebar-variables">
++      <title>Sidebar Variables</title>
++      <tgroup cols="3">
++        <thead>
++          <row>
++            <entry>Name</entry>
++            <entry>Type</entry>
++            <entry>Default</entry>
++          </row>
++        </thead>
++        <tbody>
++          <row>
++            <entry><literal>sidebar_delim_chars</literal></entry>
++            <entry>string</entry>
++            <entry><literal>/.</literal></entry>
++          </row>
++          <row>
++            <entry><literal>sidebar_divider_char</literal></entry>
++            <entry>string</entry>
++            <entry><literal>|</literal></entry>
++          </row>
++          <row>
++            <entry><literal>sidebar_folder_indent</literal></entry>
++            <entry>boolean</entry>
++            <entry><literal>no</literal></entry>
++          </row>
++          <row>
++            <entry><literal>sidebar_format</literal></entry>
++            <entry>string</entry>
++            <entry><literal>%B%*  %n</literal></entry>
++          </row>
++          <row>
++            <entry><literal>sidebar_indent_string</literal></entry>
++            <entry>string</entry>
++            <entry><literal>  </literal> (two spaces)</entry>
++          </row>
++          <row>
++            <entry><literal>sidebar_new_mail_only</literal></entry>
++            <entry>boolean</entry>
++            <entry><literal>no</literal></entry>
++          </row>
++          <row>
++            <entry><literal>sidebar_next_new_wrap</literal></entry>
++            <entry>boolean</entry>
++            <entry><literal>no</literal></entry>
++          </row>
++          <row>
++            <entry><literal>sidebar_short_path</literal></entry>
++            <entry>boolean</entry>
++            <entry><literal>no</literal></entry>
++          </row>
++          <row>
++            <entry><literal>sidebar_sort_method</literal></entry>
++            <entry>enum</entry>
++            <entry><literal>unsorted</literal></entry>
++          </row>
++          <row>
++            <entry><literal>sidebar_visible</literal></entry>
++            <entry>boolean</entry>
++            <entry><literal>no</literal></entry>
++          </row>
++          <row>
++            <entry><literal>sidebar_whitelist</literal></entry>
++            <entry>list</entry>
++            <entry>(empty)</entry>
++          </row>
++          <row>
++            <entry><literal>sidebar_width</literal></entry>
++            <entry>number</entry>
++            <entry><literal>20</literal></entry>
++          </row>
++        </tbody>
++      </tgroup>
++    </table>
++  <para>
++    For more details, and examples, about the <literal>$sidebar_format</literal>,
++    see the <link linkend="intro-sidebar-format">Sidebar Intro</link>.
++  </para>
++
++  </sect2>
++
++  <sect2 id="sidebar-functions">
++    <title>Functions</title>
++
++    <para>
++      Sidebar adds the following functions to Mutt.
++      By default, none of them are bound to keys.
++    </para>
++
++    <table id="table-sidebar-functions">
++      <title>Sidebar Functions</title>
++      <tgroup cols="3">
++        <thead>
++          <row>
++            <entry>Menus</entry>
++            <entry>Function</entry>
++            <entry>Description</entry>
++          </row>
++        </thead>
++        <tbody>
++          <row>
++            <entry>index,pager</entry>
++            <entry><literal><sidebar-next></literal></entry>
++            <entry>Move the highlight to next mailbox</entry>
++          </row>
++          <row>
++            <entry>index,pager</entry>
++            <entry><literal><sidebar-next-new></literal></entry>
++            <entry>Move the highlight to next mailbox with new mail</entry>
++          </row>
++          <row>
++            <entry>index,pager</entry>
++            <entry><literal><sidebar-open></literal></entry>
++            <entry>Open highlighted mailbox</entry>
++          </row>
++          <row>
++            <entry>index,pager</entry>
++            <entry><literal><sidebar-page-down></literal></entry>
++            <entry>Scroll the Sidebar down 1 page</entry>
++          </row>
++          <row>
++            <entry>index,pager</entry>
++            <entry><literal><sidebar-page-up></literal></entry>
++            <entry>Scroll the Sidebar up 1 page</entry>
++          </row>
++          <row>
++            <entry>index,pager</entry>
++            <entry><literal><sidebar-prev></literal></entry>
++            <entry>Move the highlight to previous mailbox</entry>
++          </row>
++          <row>
++            <entry>index,pager</entry>
++            <entry><literal><sidebar-prev-new></literal></entry>
++            <entry>Move the highlight to previous mailbox with new mail</entry>
++          </row>
++          <row>
++            <entry>index,pager</entry>
++            <entry><literal><sidebar-toggle-visible></literal></entry>
++            <entry>Make the Sidebar (in)visible</entry>
++          </row>
++        </tbody>
++      </tgroup>
++    </table>
++  </sect2>
++
++  <sect2 id="sidebar-commands">
++    <title>Commands</title>
++    <cmdsynopsis>
++      <command>sidebar_whitelist<anchor id="sidebar-whitelist"/></command>
++      <arg choice="plain">
++        <replaceable class="parameter">mailbox</replaceable>
++      </arg>
++      <arg choice="opt" rep="repeat">
++        <replaceable class="parameter">mailbox</replaceable>
++      </arg>
++    </cmdsynopsis>
++  </sect2>
++
++  <sect2 id="sidebar-colors">
++    <title>Colors</title>
++
++    <table id="table-sidebar-colors">
++      <title>Sidebar Colors</title>
++      <tgroup cols="3">
++        <thead>
++          <row>
++            <entry>Name</entry>
++            <entry>Default Color</entry>
++            <entry>Description</entry>
++          </row>
++        </thead>
++        <tbody>
++          <row>
++            <entry><literal>sidebar_divider</literal></entry>
++            <entry>default</entry>
++            <entry>The dividing line between the Sidebar and the Index/Pager panels</entry>
++          </row>
++          <row>
++            <entry><literal>sidebar_flagged</literal></entry>
++            <entry>default</entry>
++            <entry>Mailboxes containing flagged mail</entry>
++          </row>
++          <row>
++            <entry><literal>sidebar_highlight</literal></entry>
++            <entry>underline</entry>
++            <entry>Cursor to select a mailbox</entry>
++          </row>
++          <row>
++            <entry><literal>sidebar_indicator</literal></entry>
++            <entry>mutt <literal>indicator</literal></entry>
++            <entry>The mailbox open in the Index panel</entry>
++          </row>
++          <row>
++            <entry><literal>sidebar_new</literal></entry>
++            <entry>default</entry>
++            <entry>Mailboxes containing new mail</entry>
++          </row>
++          <row>
++            <entry><literal>sidebar_spoolfile</literal></entry>
++            <entry>default</entry>
++            <entry>Mailbox that receives incoming mail</entry>
++          </row>
++        </tbody>
++      </tgroup>
++    </table>
++
++    <para>
++    If the <literal>sidebar_indicator</literal> color isn't set, then the default Mutt
++    indicator color will be used (the color used in the index panel).
++    </para>
++  </sect2>
++
++  <sect2 id="sidebar-sort">
++    <title>Sort</title>
++
++    <table id="table-sidebar-sort">
++      <title>Sidebar Sort</title>
++      <tgroup cols="2">
++        <thead>
++          <row>
++            <entry>Sort</entry>
++            <entry>Description</entry>
++          </row>
++        </thead>
++        <tbody>
++          <row>
++            <entry><literal>alpha</literal></entry>
++            <entry>Alphabetically by path</entry>
++          </row>
++          <row>
++            <entry><literal>count</literal></entry>
++            <entry>Total number of messages</entry>
++          </row>
++          <row>
++            <entry><literal>flagged</literal></entry>
++            <entry>Number of flagged messages</entry>
++          </row>
++          <row>
++            <entry><literal>name</literal></entry>
++            <entry>Alphabetically by path</entry>
++          </row>
++          <row>
++            <entry><literal>new</literal></entry>
++            <entry>Number of new messages</entry>
++          </row>
++          <row>
++            <entry><literal>path</literal></entry>
++            <entry>Alphabetically by path</entry>
++          </row>
++          <row>
++            <entry><literal>unsorted</literal></entry>
++            <entry>Order of the <literal>mailboxes</literal> command</entry>
++          </row>
++        </tbody>
++      </tgroup>
++    </table>
++  </sect2>
++
++  <sect2 id="sidebar-muttrc">
++    <title>Muttrc</title>
++<screen>
++<emphasis role="comment"># This is a complete list of sidebar-related configuration.
++ 
++# --------------------------------------------------------------------------
++# VARIABLES - shown with their default values
++# --------------------------------------------------------------------------
++ 
++# Should the Sidebar be shown?</emphasis>
++set sidebar_visible = no
++ 
++<emphasis role="comment"># How wide should the Sidebar be in screen columns?
++# Note: Some characters, e.g. Chinese, take up two columns each.</emphasis>
++set sidebar_width = 20
++ 
++<emphasis role="comment"># Should the mailbox paths be abbreviated?</emphasis>
++set sidebar_short_path = no
++ 
++<emphasis role="comment"># When abbreviating mailbox path names, use any of these characters as path
++# separators.  Only the part after the last separators will be shown.
++# For file folders '/' is good.  For IMAP folders, often '.' is useful.</emphasis>
++set sidebar_delim_chars = '/.'
++ 
++<emphasis role="comment"># If the mailbox path is abbreviated, should it be indented?</emphasis>
++set sidebar_folder_indent = no
++ 
++<emphasis role="comment"># Indent mailbox paths with this string.</emphasis>
++set sidebar_indent_string = '  '
++ 
++<emphasis role="comment"># Make the Sidebar only display mailboxes that contain new, or flagged,
++# mail.</emphasis>
++set sidebar_new_mail_only = no
++ 
++<emphasis role="comment"># Any mailboxes that are whitelisted will always be visible, even if the
++# sidebar_new_mail_only option is enabled.</emphasis>
++sidebar_whitelist '/home/user/mailbox1'
++sidebar_whitelist '/home/user/mailbox2'
++ 
++<emphasis role="comment"># When searching for mailboxes containing new mail, should the search wrap
++# around when it reaches the end of the list?</emphasis>
++set sidebar_next_new_wrap = no
++ 
++<emphasis role="comment"># The character to use as the divider between the Sidebar and the other Mutt
++# panels.
++# Note: Only the first character of this string is used.</emphasis>
++set sidebar_divider_char = '|'
++ 
++<emphasis role="comment"># Display the Sidebar mailboxes using this format string.</emphasis>
++set sidebar_format = '%B%*  %n'
++ 
++<emphasis role="comment"># If you want to display more information, this is a useful format:</emphasis>
++set mail_check_stats
++set sidebar_format = '%B%?F? [%F]?%* %?N?%N/?%S'
++ 
++<emphasis role="comment"># Sort the mailboxes in the Sidebar using this method:
++#       count    - total number of messages
++#       flagged  - number of flagged messages
++#       new      - number of new messages
++#       path     - mailbox path
++#       unsorted - order of the mailboxes command</emphasis>
++set sidebar_sort_method = 'unsorted'
++ 
++<emphasis role="comment"># --------------------------------------------------------------------------
++# FUNCTIONS - shown with an example mapping
++# --------------------------------------------------------------------------
++ 
++# Move the highlight to the previous mailbox</emphasis>
++bind index,pager \Cp sidebar-prev
++ 
++<emphasis role="comment"># Move the highlight to the next mailbox</emphasis>
++bind index,pager \Cn sidebar-next
++ 
++<emphasis role="comment"># Open the highlighted mailbox</emphasis>
++bind index,pager \Co sidebar-open
++ 
++<emphasis role="comment"># Move the highlight to the previous page
++# This is useful if you have a LOT of mailboxes.</emphasis>
++bind index,pager <F3> sidebar-page-up
++ 
++<emphasis role="comment"># Move the highlight to the next page
++# This is useful if you have a LOT of mailboxes.</emphasis>
++bind index,pager <F4> sidebar-page-down
++ 
++<emphasis role="comment"># Move the highlight to the previous mailbox containing new, or flagged,
++# mail.</emphasis>
++bind index,pager <F5> sidebar-prev-new
++ 
++<emphasis role="comment"># Move the highlight to the next mailbox containing new, or flagged, mail.</emphasis>
++bind index,pager <F6> sidebar-next-new
++ 
++<emphasis role="comment"># Toggle the visibility of the Sidebar.</emphasis>
++bind index,pager B sidebar-toggle-visible
++ 
++<emphasis role="comment"># --------------------------------------------------------------------------
++# COLORS - some unpleasant examples are given
++# --------------------------------------------------------------------------
++# Note: All color operations are of the form:
++#       color OBJECT FOREGROUND BACKGROUND
++ 
++# Color of the current, open, mailbox
++# Note: This is a general Mutt option which colors all selected items.</emphasis>
++color indicator cyan black
++ 
++<emphasis role="comment"># Color of the highlighted, but not open, mailbox.</emphasis>
++color sidebar_highlight black color8
++ 
++<emphasis role="comment"># Color of the divider separating the Sidebar from Mutt panels</emphasis>
++color sidebar_divider color8 black
++ 
++<emphasis role="comment"># Color to give mailboxes containing flagged mail</emphasis>
++color sidebar_flagged red black
++ 
++<emphasis role="comment"># Color to give mailboxes containing new mail</emphasis>
++color sidebar_new green black
++ 
++<emphasis role="comment"># --------------------------------------------------------------------------
++ 
++# vim: syntax=muttrc</emphasis>
++</screen>
++  </sect2>
++
++  <sect2 id="sidebar-see-also">
++    <title>See Also</title>
++
++    <itemizedlist>
++      <listitem><para><link linkend="regexp">Regular Expressions</link></para></listitem>
++      <listitem><para><link linkend="patterns">Patterns</link></para></listitem>
++      <listitem><para><link linkend="color">Color command</link></para></listitem>
++      <listitem><para><link linkend="notmuch">notmuch patch</link></para></listitem>
++    </itemizedlist>
++  </sect2>
++
++  <sect2 id="sidebar-known-bugs">
++    <title>Known Bugs</title>
++    <para>
++      None
++    </para>
++  </sect2>
++
++  <sect2 id="sidebar-credits">
++    <title>Credits</title>
++    <itemizedlist>
++    <listitem><para>Justin Hibbits <email>jrh29 at po.cwru.edu</email></para></listitem>
++    <listitem><para>Thomer M. Gil <email>mutt at thomer.com</email></para></listitem>
++    <listitem><para>David Sterba <email>dsterba at suse.cz</email></para></listitem>
++    <listitem><para>Evgeni Golov <email>evgeni at debian.org</email></para></listitem>
++    <listitem><para>Fabian Groffen <email>grobian at gentoo.org</email></para></listitem>
++    <listitem><para>Jason DeTiberus <email>jdetiber at redhat.com</email></para></listitem>
++    <listitem><para>Stefan Assmann <email>sassmann at kpanic.de</email></para></listitem>
++    <listitem><para>Steve Kemp <email>steve at steve.org.uk</email></para></listitem>
++    <listitem><para>Terry Chan <email>tchan at lunar-linux.org</email></para></listitem>
++    <listitem><para>Tyler Earnest <email>tylere at rne.st</email></para></listitem>
++    <listitem><para>Richard Russon <email>rich at flatcap.org</email></para></listitem>
++    </itemizedlist>
++  </sect2>
++</sect1>
 +
-+/* returns all unhidden tags */
-+char *nm_header_get_tags(HEADER *h)
-+{
-+	return h && h->data ? ((struct nm_hdrdata *) h->data)->tags : NULL;
-+}
++<sect1 id="skip-quoted-patch">
++  <title>Skip-Quoted Patch</title>
++  <subtitle>Leave some context visible</subtitle>
++
++  <sect2 id="skip-quoted-patch2">
++    <title>Patch</title>
++
++    <para>
++      To check if Mutt supports <quote>skip-quoted</quote>, look for
++      <quote>patch-skip-quoted</quote> in the mutt version.
++      See: <xref linkend="mutt-patches"/>.
++    </para>
++
++    <itemizedlist>
++      <title>Dependencies:</title>
++      <listitem><para>mutt-1.6.2</para></listitem>
++    </itemizedlist>
++
++    <para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
++  </sect2>
++
++  <sect2 id="skip-quoted-intro">
++    <title>Introduction</title>
++
++    <para>
++      When viewing an email, the
++      <literal><skip-to-quoted></literal> function (by default the
++      <literal>S</literal> key) will scroll past any quoted text.
++      Sometimes, a little context is useful.
++    </para>
++
++    <para>
++      By setting the <literal>$skip_quoted_offset</literal> variable, you
++      can select how much of the quoted text is left visible.
++    </para>
++  </sect2>
++
++  <sect2 id="skip-quoted-variables">
++    <title>Variables</title>
++    <table id="table-skip-quoted-variables">
++      <title>Skip-Quoted Variables</title>
++      <tgroup cols="3">
++        <thead>
++          <row>
++            <entry>Name</entry>
++            <entry>Type</entry>
++            <entry>Default</entry>
++          </row>
++        </thead>
++        <tbody>
++          <row>
++            <entry><literal>skip_quoted_offset</literal></entry>
++            <entry>number</entry>
++            <entry>0</entry>
++          </row>
++        </tbody>
++      </tgroup>
++    </table>
++  </sect2>
 +
-+char *nm_header_get_tags_transformed(HEADER *h)
-+{
-+	return h && h->data ? ((struct nm_hdrdata *) h->data)->tags_transformed : NULL;
-+}
++<!--
++  <sect2 id="skip-quoted-functions">
++    <title>Functions</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="skip-quoted-commands">
++    <title>Commands</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="skip-quoted-colors">
++    <title>Colors</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="skip-quoted-sort">
++    <title>Sort</title>
++    <para>None</para>
++  </sect2>
++-->
 +
-+char *nm_header_get_tag_transformed(char *tag, HEADER *h)
-+{
-+	struct nm_hdrtag *tmp;
++  <sect2 id="skip-quoted-muttrc">
++    <title>Muttrc</title>
 +
-+	if (!h || !h->data)
-+		return NULL;
++<screen>
++<emphasis role="comment"># Example Mutt config file for the 'skip-quoted' patch.
++ 
++# The 'S' (skip-quoted) command scrolls the pager past the quoted text (usually
++# indented with '> '.  Setting 'skip_quoted_offset' leaves some lines of quoted
++# text on screen for context.
++ 
++# Show three quoted lines before the reply</emphasis>
++set skip_quoted_offset = 3
++ 
++<emphasis role="comment"># vim: syntax=muttrc</emphasis>
++</screen>
++  </sect2>
++
++  <sect2 id="skip-quoted-see-also">
++    <title>See Also</title>
++
++    <itemizedlist>
++      <listitem><para><ulink url="http://www.neomutt.org/">NeoMutt Project</ulink></para></listitem>
++    </itemizedlist>
++  </sect2>
++
++  <sect2 id="skip-quoted-known-bugs">
++    <title>Known Bugs</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="skip-quoted-credits">
++    <title>Credits</title>
++    <itemizedlist>
++    <listitem><para>David Sterba <email>dsterba at suse.cz</email></para></listitem>
++    <listitem><para>Richard Russon <email>rich at flatcap.org</email></para></listitem>
++    </itemizedlist>
++  </sect2>
++</sect1>
 +
-+	for (tmp = ((struct nm_hdrdata *) h->data)->tag_list;
-+	     tmp != NULL;
-+	     tmp = tmp->next)
-+	{
-+		if (strcmp(tag, tmp->tag) == 0)
-+			return tmp->transformed;
-+	}
++<sect1 id="smime-encrypt-self-patch">
++  <title>smime-encrypt-self Patch</title>
++  <subtitle>Save an self-encrypted copy of emails</subtitle>
 +
-+	return NULL;
-+}
++  <sect2 id="smime-encrypt-self-patch2">
++    <title>Patch</title>
 +
-+int nm_header_get_magic(HEADER *h)
-+{
-+	return h && h->data ? ((struct nm_hdrdata *) h->data)->magic : 0;
-+}
++    <para>
++      To check if Mutt supports <quote>smime-encrypt-self</quote>, look for
++      <quote>patch-smime-encrypt-self</quote> in the mutt version.
++      See: <xref linkend="mutt-patches"/>.
++    </para>
 +
-+/*
-+ * Returns notmuch message Id.
-+ */
-+static char *nm_header_get_id(HEADER *h)
-+{
-+	return h && h->data ? ((struct nm_hdrdata *) h->data)->virtual_id : NULL;
-+}
++    <itemizedlist>
++      <title>Dependencies:</title>
++      <listitem><para>mutt-1.6.2</para></listitem>
++    </itemizedlist>
 +
++    <para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
++  </sect2>
 +
-+char *nm_header_get_fullpath(HEADER *h, char *buf, size_t bufsz)
-+{
-+	snprintf(buf, bufsz, "%s/%s", nm_header_get_folder(h), h->path);
-+	/*dprint(2, (debugfile, "nm: returns fullpath '%s'\n", buf));*/
-+	return buf;
-+}
++  <sect2 id="smime-encrypt-self-intro">
++    <title>Introduction</title>
 +
++    <para>
++      Once you encrypt an email to someone you cannot read it.  This is good
++      for security, but bad for record-keeping.  If you wanted to keep a copy
++      of an encrypted email you could set <link linkend="fcc-clear">$fcc_clear</link>.
++    </para>
 +
-+static struct nm_ctxdata *get_ctxdata(CONTEXT *ctx)
-+{
-+	if (ctx && ctx->magic == M_NOTMUCH)
-+		return ctx->data;
++    <para>
++      A better option is to enable
++      <link linkend="smime-encrypt-self">$smime_encrypt_self</link>, then set
++      <link linkend="smime-default-key">$smime_default_key</link> to your
++      personal S/MIME key id.
++    </para>
 +
-+	return NULL;
-+}
++<screen>
++set smime_encrypt_self = yes
++set smime_default_key  = bb345e23.0
++</screen>
 +
-+static int string_to_guery_type(const char *str)
-+{
-+	if (!str)
-+		str = NotmuchQueryType;		/* user's default */
-+	if (!str)
-+		return NM_QUERY_TYPE_MESGS;	/* hardcoded default */
++  </sect2>
++
++  <sect2 id="smime-encrypt-self-variables">
++    <title>Variables</title>
++
++    <table id="table-smime-encrypt-self-variables">
++      <title>smime-encrypt-self Variables</title>
++      <tgroup cols="3">
++        <thead>
++          <row>
++            <entry>Name</entry>
++            <entry>Type</entry>
++            <entry>Default</entry>
++          </row>
++        </thead>
++        <tbody>
++          <row>
++            <entry><literal>smime_encrypt_self</literal></entry>
++            <entry>quad</entry>
++            <entry>No</entry>
++          </row>
++        </tbody>
++      </tgroup>
++    </table>
++  </sect2>
++
++  <sect2 id="smime-encrypt-self-muttrc">
++    <title>Muttrc</title>
++<screen>
++<emphasis role="comment"># This is a complete list of smime-encrypt-self-related configuration.
++ 
++# --------------------------------------------------------------------------
++# VARIABLES - shown with their default values
++# --------------------------------------------------------------------------
++ 
++# Save a copy of outgoing email, encrypted to yourself</emphasis>
++set smime_encrypt_self = "no"
++ 
++<emphasis role="comment"># vim: syntax=muttrc</emphasis>
++</screen>
++  </sect2>
++
++  <sect2 id="smime-encrypt-self-see-also">
++    <title>See Also</title>
++
++    <itemizedlist>
++      <listitem><para><ulink url="http://www.neomutt.org/">NeoMutt Project</ulink></para></listitem>
++    </itemizedlist>
++  </sect2>
++
++  <sect2 id="smime-encrypt-self-known-bugs">
++    <title>Known Bugs</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="smime-encrypt-self-credits">
++    <title>Credits</title>
++    <itemizedlist>
++    <listitem><para>Omen Wild <email>omen at mandarb.com</email></para></listitem>
++    <listitem><para>Richard Russon <email>rich at flatcap.org</email></para></listitem>
++    </itemizedlist>
++  </sect2>
++</sect1>
 +
-+	if (strcmp(str, "threads") == 0)
-+		return NM_QUERY_TYPE_THREADS;
-+	else if (strcmp(str, "messages") == 0)
-+		return NM_QUERY_TYPE_MESGS;
++<sect1 id="status-color">
++  <title>Status Color Patch</title>
++  <subtitle>Custom rules for theming the status bar</subtitle>
 +
-+	mutt_error (_("failed to parse notmuch query type: %s"), str);
-+	return NM_QUERY_TYPE_MESGS;
-+}
++  <sect2 id="status-color-patch">
++    <title>Patch</title>
 +
-+static char *get_query_string(struct nm_ctxdata *data)
-+{
-+	struct uri_tag *item;
++    <para>
++      To check if Mutt supports <quote>Status Color</quote>, look for
++      <quote>patch-status-color</quote> in the mutt version.
++      See: <xref linkend="mutt-patches"/>.
++    </para>
 +
-+	if (!data)
-+		return NULL;
-+	if (data->db_query)
-+		return data->db_query;
++    <itemizedlist>
++      <title>Dependencies:</title>
++      <listitem><para>mutt-1.6.2</para></listitem>
++    </itemizedlist>
 +
-+	for (item = data->query_items; item; item = item->next) {
-+		if (!item->value || !item->name)
-+			continue;
++    <para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
++  </sect2>
 +
-+		if (strcmp(item->name, "limit") == 0) {
-+			if (mutt_atoi(item->value, &data->db_limit))
-+				mutt_error (_("failed to parse notmuch limit: %s"), item->value);
++  <sect2 id="status-color-intro">
++    <title>Introduction</title>
 +
-+		} else if (strcmp(item->name, "type") == 0)
-+			data->query_type = string_to_guery_type(item->value);
++        <para>
++    The <quote>status-color</quote> patch allows you to theme different
++    parts of the status bar (also when it's used by the index).
++        </para>
 +
-+		else if (strcmp(item->name, "query") == 0)
-+			data->db_query = safe_strdup(item->value);
-+	}
++        <para>
++    Unlike normal color commands, <literal>color status</literal> can now
++    take up to 2 extra parameters (regex, num).
++        </para>
++  </sect2>
 +
-+	if (!data->query_type)
-+		data->query_type = string_to_guery_type(NULL);
++<!--
++  <sect2 id="status-color-variables">
++    <title>Variables</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="status-color-functions">
++    <title>Functions</title>
++    <para>None</para>
++  </sect2>
++-->
 +
-+	dprint(2, (debugfile, "nm: query '%s'\n", data->db_query));
++  <sect2 id="status-color-commands">
++    <title>Commands</title>
++    <cmdsynopsis>
++      <command>color</command>
++      <arg choice="plain">
++        <option>status</option>
++      </arg>
++      <arg choice="plain">
++        <replaceable class="parameter">foreground</replaceable>
++      </arg>
++      <arg choice="plain">
++        <replaceable class="parameter">background</replaceable>
++      </arg>
++      <group choice="opt">
++        <arg choice="plain">
++          <replaceable class="parameter">regex</replaceable>
++        </arg>
++        <group choice="opt">
++          <arg choice="plain">
++            <replaceable class="parameter">num</replaceable>
++          </arg>
++        </group>
++      </group>
++    </cmdsynopsis>
++
++    <para>
++      With zero parameters, Mutt will set the default color for the entire
++      status bar.
++    </para>
++
++    <para>
++      With one parameter, Mutt will only color the parts matching the
++      regex.
++    </para>
++
++    <para>
++      With two parameters, Mutt will only color the num'th sub-match of
++      the regex.
++    </para>
++  </sect2>
++
++  <sect2 id="status-color-colors">
++    <title>Colors</title>
++
++    <table id="table-status-color-colors">
++      <title>Status Colors</title>
++      <tgroup cols="3">
++        <thead>
++          <row>
++            <entry>Name</entry>
++            <entry>Default Color</entry>
++            <entry>Description</entry>
++          </row>
++        </thead>
++        <tbody>
++          <row>
++            <entry>status</entry>
++            <entry><literal>reverse</literal></entry>
++            <entry>Status bar</entry>
++          </row>
++        </tbody>
++      </tgroup>
++    </table>
++  </sect2>
 +
-+	return data->db_query;
-+}
++<!--
++  <sect2 id="status-color-sort">
++    <title>Sort</title>
++    <para>None</para>
++  </sect2>
++-->
 +
-+static int get_limit(struct nm_ctxdata *data)
-+{
-+	return data ? data->db_limit : 0;
-+}
++  <sect2 id="status-color-muttrc">
++    <title>Muttrc</title>
++<screen>
++<emphasis role="comment"># Example Mutt config file for the 'status-color' patch.
++ 
++# The 'status-color' patch allows you to theme different parts of
++# the status bar (also when it's used by the index).
++ 
++# For the examples below, set some defaults</emphasis>
++set status_format='-%r-Mutt: %f [Msgs:%?M?%M/?%m%?n? New:%n?%?o? Old:%o?%?d? Del:%d?%?F? Flag:%F?%?t? Tag:%t?%?p? Post:%p?%?b? Inc:%b?%?l? %l?]---(%s/%S)-%>-(%P)---'
++set index_format='%4C %Z %{%b %d} %-15.15L (%?l?%4l&%4c?) %s'
++set sort=threads
++set sort_aux=last-date-received
++ 
++<emphasis role="comment"># 'status color' can take up to 2 extra parameters
++ 
++# color status foreground background [ regex [ num ]]
++ 
++# 0 extra parameters
++# Set the default color for the entire status line</emphasis>
++color status blue white
++ 
++<emphasis role="comment"># 1 extra parameter
++# Set the color for a matching pattern
++# color status foreground background regexp
++ 
++# Highlight New, Deleted, or Flagged emails</emphasis>
++color status brightred white '(New|Del|Flag):[0-9]+'
++ 
++<emphasis role="comment"># Highlight mailbox ordering if it's different from the default
++# First, highlight anything (*/*)</emphasis>
++color status brightred default '\([^)]+/[^)]+\)'
++ 
++<emphasis role="comment"># Then override the color for one specfic case</emphasis>
++color status default   default '\(threads/last-date-received\)'
++ 
++<emphasis role="comment"># 2 extra parameters
++# Set the color for the nth submatch of a pattern
++# color status foreground background regexp num
++ 
++# Highlight the contents of the []s but not the [] themselves</emphasis>
++color status red default '\[([^]]+)\]' 1
++ 
++<emphasis role="comment"># The '1' refers to the first regex submatch, which is the inner
++# part in ()s
++ 
++# Highlight the mailbox</emphasis>
++color status brightwhite default 'Mutt: ([^ ]+)' 1
++ 
++<emphasis role="comment"># Search for 'Mutt: ' but only highlight what comes after it
++ 
++# vim: syntax=muttrc</emphasis>
++</screen>
++  </sect2>
++
++  <sect2 id="status-color-see-also">
++    <title>See Also</title>
++
++    <itemizedlist>
++      <listitem><para><ulink url="http://www.neomutt.org/">NeoMutt Project</ulink></para></listitem>
++      <listitem><para><link linkend="compile-time-features">Compile-Time Features</link></para></listitem>
++      <listitem><para><link linkend="regexp">Regular Expressions</link></para></listitem>
++      <listitem><para><link linkend="patterns">Patterns</link></para></listitem>
++      <listitem><para><link linkend="index-color">index-color patch</link></para></listitem>
++      <listitem><para><link linkend="color">Color command</link></para></listitem>
++    </itemizedlist>
++  </sect2>
++
++  <sect2 id="status-color-known-bugs">
++    <title>Known Bugs</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="status-color-credits">
++    <title>Credits</title>
++    <itemizedlist>
++    <listitem><para>David Sterba <email>dsterba at suse.cz</email></para></listitem>
++    <listitem><para>Thomas Glanzmann <email>thomas at glanzmann.de</email></para></listitem>
++    <listitem><para>Kirill A. Shutemov <email>kirill at shutemov.name</email></para></listitem>
++    <listitem><para>Richard Russon <email>rich at flatcap.org</email></para></listitem>
++    </itemizedlist>
++  </sect2>
++</sect1>
 +
-+static int get_query_type(struct nm_ctxdata *data)
-+{
-+	return (data && data->query_type) ? data->query_type : string_to_guery_type(NULL);
-+}
++<sect1 id="tls-sni">
++  <title>TLS-SNI Patch</title>
++  <subtitle>Negotiate with a server for a TSL/SSL certificate</subtitle>
++
++  <sect2 id="tls-sni-patch">
++    <title>Patch</title>
++
++    <para>
++      To check if Mutt supports <quote>TLS-SNI</quote>, look for
++      <quote>patch-tls-sni</quote> in the mutt version.
++      See: <xref linkend="mutt-patches"/>.
++    </para>
++
++    <itemizedlist>
++      <title>Dependencies:</title>
++      <listitem><para>mutt-1.6.2</para></listitem>
++      <listitem><para>OpenSSL</para></listitem>
++    </itemizedlist>
++
++    <para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
++  </sect2>
++
++  <sect2 id="tls-sni-intro">
++    <title>Introduction</title>
++
++    <para>
++    The <quote>TLS-SNI</quote> patch adds support for TLS virtual hosting.
++    If your mail server doesn't support this everything will still work
++    normally.
++    </para>
++
++    <para>
++    TLS supports sending the expected server hostname during the
++    handshake, via the SNI extension.  This can be used to select a
++    server certificate to issue to the client, permitting
++    virtual-hosting without requiring multiple IP addresses.
++    </para>
++
++    <para>
++    This has been tested against Exim 4.80, which optionally logs SNI
++    and can perform vhosting.
++    </para>
 +
-+static const char *get_db_filename(struct nm_ctxdata *data)
-+{
-+	char *db_filename;
++        <para>
++    To verify TLS SNI support by a server, you can use:
++        </para>
 +
-+	if (!data)
-+		return NULL;
++<screen>
++openssl s_client -host <imap server> -port <port> -tls1 -servername <imap server>
++</screen>
++  </sect2>
 +
-+	db_filename = data->db_filename ? data->db_filename : NotmuchDefaultUri;
-+	if (!db_filename)
-+		db_filename = Maildir;
-+	if (!db_filename)
-+		return NULL;
-+	if (strncmp(db_filename, "notmuch://", 10) == 0)
-+		db_filename += 10;
++<!--
++  <sect2 id="tls-sni-variables">
++    <title>Variables</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="tls-sni-functions">
++    <title>Functions</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="tls-sni-commands">
++    <title>Commands</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="tls-sni-colors">
++    <title>Colors</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="tls-sni-sort">
++    <title>Sort</title>
++    <para>None</para>
++  </sect2>
++-->
 +
-+	dprint(2, (debugfile, "nm: db filename '%s'\n", db_filename));
-+	return db_filename;
-+}
++  <sect2 id="tls-sni-muttrc">
++    <title>Muttrc</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="tls-sni-see-also">
++    <title>See Also</title>
++
++    <itemizedlist>
++      <listitem><para><ulink url="http://www.neomutt.org/">NeoMutt Project</ulink></para></listitem>
++    </itemizedlist>
++  </sect2>
++
++  <sect2 id="tls-sni-known-bugs">
++    <title>Known Bugs</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="tls-sni-credits">
++    <title>Credits</title>
++    <itemizedlist>
++    <listitem><para>Jeremy Katz <email>katzj at linuxpower.org</email></para></listitem>
++    <listitem><para>Phil Pennock <email>mutt-dev at spodhuis.demon.nl</email></para></listitem>
++    <listitem><para>Richard Russon <email>rich at flatcap.org</email></para></listitem>
++    </itemizedlist>
++  </sect2>
++</sect1>
 +
-+static notmuch_database_t *do_database_open(const char *filename,
-+					    int writable, int verbose)
-+{
-+	notmuch_database_t *db = NULL;
-+	unsigned int ct = 0;
-+	notmuch_status_t st = NOTMUCH_STATUS_SUCCESS;
++<sect1 id="trash-folder">
++  <title>Trash Folder Patch</title>
++  <subtitle>Automatically move <quote>deleted</quote> emails to a trash bin</subtitle>
++
++  <sect2 id="trash-folder-patch">
++    <title>Patch</title>
++
++    <para>
++      To check if Mutt supports <quote>Trash Folder</quote>, look for
++      <quote>patch-trash</quote> in the mutt version.
++      See: <xref linkend="mutt-patches"/>.
++    </para>
++
++    <para>
++      If IMAP is enabled, this patch will use it
++    </para>
++
++    <itemizedlist>
++      <title>Dependencies:</title>
++      <listitem><para>mutt-1.6.2</para></listitem>
++      <listitem><para>IMAP support</para></listitem>
++    </itemizedlist>
++
++    <para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
++  </sect2>
++
++  <sect2 id="trash-folder-intro">
++    <title>Introduction</title>
++
++    <para>
++    In Mutt, when you <quote>delete</quote> an email it is first marked
++    deleted.  The email isn't really gone until
++    <link linkend="index-map"><sync-mailbox></link> is called.
++    This happens when the user leaves the folder, or the function is called
++    manually.
++    </para>
++
++    <para>
++    After <literal><sync-mailbox></literal> has been called the email is gone forever.
++    </para>
++
++    <para>
++    The <link linkend="trash">$trash</link> variable defines a folder in
++    which to keep old emails.  As before, first you mark emails for
++    deletion.  When <sync-mailbox> is called the emails are moved to
++    the trash folder.
++    </para>
++
++    <para>
++    The <literal>$trash</literal> path can be either a full directory,
++    or be relative to the <link linkend="folder">$folder</link>
++    variable, like the <literal>mailboxes</literal> command.
++    </para>
++
++    <note>
++      <para>
++        Emails deleted from the trash folder are gone forever.
++      </para>
++    </note>
++  </sect2>
++
++  <sect2 id="trash-folder-variables">
++    <title>Variables</title>
++    <table id="table-trash-variables">
++      <title>Trash Variables</title>
++      <tgroup cols="3">
++        <thead>
++          <row>
++            <entry>Name</entry>
++            <entry>Type</entry>
++            <entry>Default</entry>
++          </row>
++        </thead>
++        <tbody>
++          <row>
++            <entry>trash</entry>
++            <entry>string</entry>
++            <entry>(none)</entry>
++          </row>
++        </tbody>
++      </tgroup>
++    </table>
++  </sect2>
++
++  <sect2 id="trash-folder-functions">
++    <title>Functions</title>
++    <table id="table-trash-functions">
++      <title>Trash Functions</title>
++      <tgroup cols="4">
++        <thead>
++          <row>
++            <entry>Menus</entry>
++            <entry>Default Key</entry>
++            <entry>Function</entry>
++            <entry>Description</entry>
++          </row>
++        </thead>
++        <tbody>
++          <row>
++            <entry>index,pager</entry>
++            <entry>(none)</entry>
++            <entry><literal><purge-message></literal></entry>
++            <entry>really delete the current entry, bypassing the trash folder</entry>
++          </row>
++        </tbody>
++      </tgroup>
++    </table>
++  </sect2>
 +
-+	dprint(1, (debugfile, "nm: db open '%s' %s (timeout %d)\n", filename,
-+			writable ? "[WRITE]" : "[READ]", NotmuchOpenTimeout));
-+	do {
-+#ifdef NOTMUCH_API_3
-+		st = notmuch_database_open(filename,
-+					writable ? NOTMUCH_DATABASE_MODE_READ_WRITE :
-+					NOTMUCH_DATABASE_MODE_READ_ONLY, &db);
-+#else
-+		db = notmuch_database_open(filename,
-+					writable ? NOTMUCH_DATABASE_MODE_READ_WRITE :
-+					NOTMUCH_DATABASE_MODE_READ_ONLY);
-+#endif
-+		if (db || !NotmuchOpenTimeout || ct / 2 > NotmuchOpenTimeout)
-+			break;
++<!--
++  <sect2 id="trash-folder-commands">
++    <title>Commands</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="trash-folder-colors">
++    <title>Colors</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="trash-folder-sort">
++    <title>Sort</title>
++    <para>None</para>
++  </sect2>
++-->
 +
-+		if (verbose && ct && ct % 2 == 0)
-+			mutt_error(_("Waiting for notmuch DB... (%d sec)"), ct / 2);
-+		usleep(500000);
-+		ct++;
-+	} while (1);
++  <sect2 id="trash-folder-muttrc">
++    <title>Muttrc</title>
++<screen>
++<emphasis role="comment"># Example Mutt config file for the 'trash' feature.
++ 
++# This feature defines a new 'trash' folder.
++# When mail is deleted it will be moved to this folder.
++ 
++# Folder in which to put deleted emails</emphasis>
++set trash='+Trash'
++set trash='/home/flatcap/Mail/Trash'
++ 
++<emphasis role="comment"># The default delete key 'd' will move an email to the 'trash' folder
++# Bind 'D' to REALLY delete an email</emphasis>
++bind index D purge-message
++ 
++<emphasis role="comment"># Note: Deleting emails from the 'trash' folder will REALLY delete them.
++ 
++# vim: syntax=muttrc</emphasis>
++</screen>
++  </sect2>
++
++  <sect2 id="trash-folder-see-also">
++    <title>See Also</title>
++
++    <itemizedlist>
++      <listitem><para><ulink url="http://www.neomutt.org/">NeoMutt Project</ulink></para></listitem>
++      <listitem><para><link linkend="folder-hook">folder-hook</link></para></listitem>
++    </itemizedlist>
++  </sect2>
++
++  <sect2 id="trash-folder-known-bugs">
++    <title>Known Bugs</title>
++    <para>None</para>
++  </sect2>
++
++  <sect2 id="trash-folder-credits">
++    <title>Credits</title>
++    <itemizedlist>
++    <listitem><para>Cedric Duval <email>cedricduval at free.fr</email></para></listitem>
++    <listitem><para>Benjamin Kuperman <email>kuperman at acm.org</email></para></listitem>
++    <listitem><para>Paul Miller <email>paul at voltar.org</email></para></listitem>
++    <listitem><para>Richard Russon <email>rich at flatcap.org</email></para></listitem>
++    </itemizedlist>
++  </sect2>
++</sect1>
 +
-+	if (verbose) {
-+		if (!db)
-+			mutt_error (_("Cannot open notmuch database: %s: %s"),
-+				    filename,
-+				    st ? notmuch_status_to_string(st) :
-+					 _("unknown reason"));
-+		else if (ct > 1)
-+			mutt_clear_error();
-+	}
-+	return db;
-+}
+ </chapter>
+ 
+ <chapter id="security">
+@@ -8623,6 +13964,18 @@ The following are the commands understood by Mutt:
+ 
+ <listitem>
+ <cmdsynopsis>
++<command><link linkend="append-hook">append-hook</link></command>
++<arg choice="plain">
++<replaceable class="parameter">pattern</replaceable>
++</arg>
++<arg choice="plain">
++<replaceable class="parameter">shell-command</replaceable>
++</arg>
++</cmdsynopsis>
++</listitem>
 +
-+static notmuch_database_t *get_db(struct nm_ctxdata *data, int writable)
-+{
-+	if (!data)
-+	       return NULL;
-+	if (!data->db) {
-+		const char *db_filename = get_db_filename(data);
++<listitem>
++<cmdsynopsis>
+ <command><link linkend="auto-view">auto_view</link></command>
+ <arg choice="plain">
+ <replaceable>mimetype</replaceable>
+@@ -8684,6 +14037,18 @@ The following are the commands understood by Mutt:
+ 
+ <listitem>
+ <cmdsynopsis>
++<command><link linkend="close-hook">close-hook</link></command>
++<arg choice="plain">
++<replaceable class="parameter">pattern</replaceable>
++</arg>
++<arg choice="plain">
++<replaceable class="parameter">shell-command</replaceable>
++</arg>
++</cmdsynopsis>
++</listitem>
 +
-+		if (db_filename)
-+			data->db = do_database_open(db_filename, writable, TRUE);
-+	}
-+	return data->db;
-+}
++<listitem>
++<cmdsynopsis>
+ <command><link linkend="color">color</link></command>
+ <arg choice="plain">
+ <replaceable class="parameter">object</replaceable>
+@@ -8753,6 +14118,18 @@ The following are the commands understood by Mutt:
+ 
+ <listitem>
+ <cmdsynopsis>
++<command><link linkend="open-hook">open-hook</link></command>
++<arg choice="plain">
++<replaceable class="parameter">pattern</replaceable>
++</arg>
++<arg choice="plain">
++<replaceable class="parameter">shell-command</replaceable>
++</arg>
++</cmdsynopsis>
++</listitem>
 +
-+static int release_db(struct nm_ctxdata *data)
-+{
-+	if (data && data->db) {
-+		dprint(1, (debugfile, "nm: db close\n"));
-+#ifdef NOTMUCH_API_3
-+		notmuch_database_destroy(data->db);
-+#else
-+		notmuch_database_close(data->db);
-+#endif
-+		data->db = NULL;
-+		data->longrun = 0;
-+		return 0;
-+	}
++<listitem>
++<cmdsynopsis>
+ <command><link linkend="crypt-hook">crypt-hook</link></command>
+ <arg choice="plain">
+ <replaceable class="parameter">regexp</replaceable>
+@@ -8874,6 +14251,18 @@ The following are the commands understood by Mutt:
+ 
+ <listitem>
+ <cmdsynopsis>
++<command>ifdef</command>
++<arg choice="plain">
++<replaceable class="parameter">item</replaceable>
++</arg>
++<arg choice="plain">
++<replaceable class="parameter">"config-command [args]"</replaceable>
++</arg>
++</cmdsynopsis>
++</listitem>
 +
-+	return -1;
-+}
++<listitem>
++<cmdsynopsis>
+ <command><link linkend="ignore">ignore</link></command>
+ <arg choice="plain">
+ <replaceable class="parameter">pattern</replaceable>
+@@ -9237,6 +14626,17 @@ The following are the commands understood by Mutt:
+ 
+ <listitem>
+ <cmdsynopsis>
++<command><link linkend="sidebar-whitelist">sidebar_whitelist</link></command>
++<arg choice="plain">
++<replaceable class="parameter">item</replaceable>
++</arg>
++<arg choice="plain">
++<replaceable class="parameter">command</replaceable>
++</arg>
++</cmdsynopsis>
++</listitem>
++<listitem>
++<cmdsynopsis>
+ <command><link linkend="source">source</link></command>
+ <arg choice="plain">
+ <replaceable class="parameter">filename</replaceable>
+diff --git a/doc/mutt.css b/doc/mutt.css
+index 5a37b3c..d7ff017 100644
+--- a/doc/mutt.css
++++ b/doc/mutt.css
+@@ -9,17 +9,24 @@ div.table-contents table td, div.informaltable td, div.table-contents table th,
+ div.table-contents table th, div.informaltable table th {
+     font-family:sans-serif;
+     background:#d0d0d0;
+-    font-weight:normal;
++    font-weight:bold;
+     vertical-align:top;
+ }
+-div.cmdsynopsis { border-left:1px solid #707070; padding-left:5px; }
++div.cmdsynopsis { border-left:1px solid #707070; padding-left: 1em; }
+ li div.cmdsynopsis { border-left:none; padding-left:0px; }
+-pre.screen, div.note { background:#f0f0f0; border:1px solid #c0c0c0; padding:5px; margin-left:2%; margin-right:2%; }
++li p { margin: 0; }
++pre.screen, div.note { border:1px solid #c0c0c0; margin-left:2%; margin-right:2%; }
++pre.screen { color: #ffffff; background:#000000; padding: 0.5em; }
++div.note { background:#ffff80; padding: 0.5em; }
+ div.example p.title { margin-left:2%; }
+ div.note h3 { font-size:small; font-style:italic; font-variant: small-caps; }
+ div.note h3:after { content: ":" }
+ div.note { margin-bottom: 5px; }
+-.command { font-family: monospace; font-weight: normal; }
++div.literallayout, .command { font-family: monospace; font-weight: normal; }
+ .command strong { font-weight: normal; }
+ tr { vertical-align: top; }
+-.comment { color:#707070; }
++.comment { color:#00c000; }
++code.literal { background: #f0f0f0; color: #000000; }
++span.indicator { background: #000060; color: #ffffff; }
++span.highlight { background: #404040; color: #ffffff; }
++span.reverse { background: #ffffff; color: #000000; }
+diff --git a/doc/mutt.man b/doc/mutt.man
+index d29294f..b5b7337 100644
+--- a/doc/mutt.man
++++ b/doc/mutt.man
+@@ -23,8 +23,8 @@ mutt \- The Mutt Mail User Agent
+ .SH SYNOPSIS
+ .PP
+ .B mutt
+-[\-nRyzZ]
+-[\-e \fIcmd\fP] [\-F \fIfile\fP] [\-m \fItype\fP] [\-f \fIfile\fP]
++[\-GnRyzZ]
++[\-e \fIcmd\fP] [\-F \fIfile\fP] [\-g \fIserver\fP] [\-m \fItype\fP] [\-f \fIfile\fP]
+ .PP
+ .B mutt 
+ [\-Enx] 
+@@ -104,6 +104,10 @@ files.
+ Specify which mailbox to load.
+ .IP "-F \fImuttrc\fP"
+ Specify an initialization file to read instead of ~/.muttrc
++.IP "-g \fIserver\fP"
++Start Mutt with a listing of subscribed newsgroups at specified news server.
++.IP "-G"
++Start Mutt with a listing of subscribed newsgroups.
+ .IP "-h"
+ Display help.
+ .IP "-H \fIdraft\fP"
+diff --git a/doc/muttrc.compress b/doc/muttrc.compress
+new file mode 100644
+index 0000000..ab6fe3c
+--- /dev/null
++++ b/doc/muttrc.compress
+@@ -0,0 +1,38 @@
++# Example Mutt config file for the 'compressed folders' feature.
 +
-+/* returns:	< 0 = error
-+ *		  1 = new transaction started
-+ *		  0 = already within transaction
-+ */
-+static int db_trans_begin(struct nm_ctxdata *data)
-+{
-+	if (!data || !data->db)
-+		return -1;
++# This feature adds three hooks to Mutt which allow it to
++# work with compressed, or encrypted, mailboxes.
++
++# The hooks are of the form:
++#       open-hook   regexp "shell-command"
++#       close-hook  regexp "shell-command"
++#       append-hook regexp "shell-command"
 +
-+	if (!data->trans) {
-+		dprint(2, (debugfile, "nm: db trans start\n"));
-+		if (notmuch_database_begin_atomic(data->db))
-+			return -1;
-+		data->trans = 1;
-+		return 1;
-+	}
++# The 'append-hook' is optional.
 +
-+	return 0;
-+}
++# Hander for gzip compressed mailboxes
++open-hook   '\.gz$'  "gzip -cd  '%f' >  '%t'"
++close-hook  '\.gz$'  "gzip -c   '%t' >  '%f'"
++append-hook '\.gz$'  "gzip -c   '%t' >> '%f'"
 +
-+static int db_trans_end(struct nm_ctxdata *data)
-+{
-+	if (!data || !data->db)
-+		return -1;
++# Hander for bzip2 compressed mailboxes
++open-hook   '\.bz2$' "bzip2 -cd '%f' >  '%t'"
++close-hook  '\.bz2$' "bzip2 -c  '%t' >  '%f'"
++append-hook '\.bz2$' "bzip2 -c  '%t' >> '%f'"
 +
-+	if (data->trans) {
-+		dprint(2, (debugfile, "nm: db trans end\n"));
-+		data->trans = 0;
-+		if (notmuch_database_end_atomic(data->db))
-+			return -1;
-+	}
++# Hander for xz compressed mailboxes
++open-hook   '\.xz$'  "xz    -cd '%f' >  '%t'"
++close-hook  '\.xz$'  "xz    -c  '%t' >  '%f'"
++append-hook '\.xz$'  "xz    -c  '%t' >> '%f'"
 +
-+	return 0;
-+}
++# Hander for pgp encrypted mailboxes
++# PGP does not support appending to an encrypted file
++open-hook   '\.pgp$' "pgp -f < '%f' > '%t'"
++close-hook  '\.pgp$' "pgp -fe YourPgpUserIdOrKeyId < '%t' > '%f'"
 +
-+void nm_longrun_init(CONTEXT *ctx, int writable)
-+{
-+	struct nm_ctxdata *data = get_ctxdata(ctx);
++# Hander for gpg encrypted mailboxes
++# gpg does not support appending to an encrypted file
++open-hook   '\.gpg$' "gpg --decrypt < '%f' > '%t'"
++close-hook  '\.gpg$' "gpg --encrypt --recipient YourGpgUserIdOrKeyId < '%t' > '%f'"
 +
-+	if (data && get_db(data, writable)) {
-+		data->longrun = 1;
-+		dprint(2, (debugfile, "nm: long run initialized\n"));
-+	}
-+}
++# vim: syntax=muttrc
+diff --git a/doc/muttrc.cond-date b/doc/muttrc.cond-date
+new file mode 100644
+index 0000000..b580e4f
+--- /dev/null
++++ b/doc/muttrc.cond-date
+@@ -0,0 +1,16 @@
++# Example Mutt config file for the 'index-color' feature.
++#
++# The default index_format is:
++#       '%4C %Z %{%b %d} %-15.15L (%?l?%4l&%4c?) %s'
++#
++# We replace the date field '%{%b %d}', giving:
++set index_format='%4C %Z %<[y?%<[m?%<[d?%[%H:%M ]&%[%a %d]>&%[%b %d]>&%[%m/%y ]> %-15.15L (%?l?%4l&%4c?) %s'
 +
-+void nm_longrun_done(CONTEXT *ctx)
-+{
-+	struct nm_ctxdata *data = get_ctxdata(ctx);
++# Test  Date Range  Format String  Example
++# --------------------------------------------
++# %[d   Today       %[%H:%M ]      12:34
++# %[m   This month  %[%a %d]       Thu 12
++# %[y   This year   %[%b %d]       Dec 10
++# -     Older       %[%m/%y ]      06/15
 +
-+	if (data && release_db(data) == 0)
-+		dprint(2, (debugfile, "nm: long run deinitialized\n"));
-+}
++# vim: syntax=muttrc
+diff --git a/doc/muttrc.ifdef b/doc/muttrc.ifdef
+new file mode 100644
+index 0000000..f618d5d
+--- /dev/null
++++ b/doc/muttrc.ifdef
+@@ -0,0 +1,32 @@
++# Example Mutt config file for the 'ifdef' feature.
 +
-+static int is_longrun(struct nm_ctxdata *data)
-+{
-+	return data && data->longrun;
-+}
++# This feature introduces three useful commands which allow you to share
++# one config file between versions of Mutt that may have different
++# features compiled in.
 +
-+void nm_debug_check(CONTEXT *ctx)
-+{
-+	struct nm_ctxdata *data = get_ctxdata(ctx);
++#	ifdef  symbol config-command [args...]
++#	ifndef symbol config-command [args...]
++#	finish                                
 +
-+	if (!data)
-+		return;
++# The 'ifdef' command tests whether Mutt understands the name of
++# a variable, function, command or compile-time symbol.
++# If it does, then it executes a config command.
 +
-+	if (data->db) {
-+		dprint(1, (debugfile, "nm: ERROR: db is open, closing\n"));
-+		release_db(data);
-+	}
-+}
++# The 'ifndef' command tests whether a symbol does NOT exist.
 +
-+static int get_database_mtime(struct nm_ctxdata *data, time_t *mtime)
-+{
-+	char path[_POSIX_PATH_MAX];
-+	struct stat st;
++# The 'finish' command tells Mutt to stop reading current config file.
 +
-+	if (!data)
-+	       return -1;
++# If the 'trash' variable exists, set it.
++ifdef trash 'set trash=~/Mail/trash'
 +
-+	snprintf(path, sizeof(path), "%s/.notmuch/xapian", get_db_filename(data));
-+	dprint(2, (debugfile, "nm: checking '%s' mtime\n", path));
++# If the 'tag-pattern' function exists, bind a key to it.
++ifdef tag-pattern 'bind index <F6> tag-pattern'
 +
-+	if (stat(path, &st))
-+		return -1;
++# If the 'imap-fetch-mail' command exists, read my IMAP config.
++ifdef imap-fetch-mail 'source ~/.mutt/imap.rc'
 +
-+	if (mtime)
-+		*mtime = st.st_mtime;
++# If the compile-time symbol 'USE_SIDEBAR' does not exist, then
++# stop reading the current config file.
++ifndef USE_SIDEBAR finish
 +
-+	return 0;
-+}
++# vim: syntax=muttrc
+diff --git a/doc/muttrc.index-color b/doc/muttrc.index-color
+new file mode 100644
+index 0000000..3ec91f5
+--- /dev/null
++++ b/doc/muttrc.index-color
+@@ -0,0 +1,37 @@
++# Example Mutt config file for the 'index-color' feature.
 +
-+static void apply_exclude_tags(notmuch_query_t *query)
-+{
-+	char *buf, *p, *end = NULL, *tag = NULL;
++# Entire index line
++color index white black '.*'
 +
-+	if (!NotmuchExcludeTags || !*NotmuchExcludeTags)
-+		return;
-+	buf = safe_strdup(NotmuchExcludeTags);
++# Author name, %A %a %F %L %n
 +
-+	for (p = buf; p && *p; p++) {
-+		if (!tag && isspace(*p))
-+			continue;
-+		if (!tag)
-+			tag = p;		/* begin of the tag */
-+		if (*p == ',' || *p == ' ')
-+			end = p;		/* terminate the tag */
-+		else if (*(p + 1) == '\0')
-+			end = p + 1;		/* end of optstr */
-+		if (!tag || !end)
-+			continue;
-+		if (tag >= end)
-+			break;
-+		*end = '\0';
++# Give the author column a dark grey background
++color index_author default color234 '.*'
 +
-+		dprint(2, (debugfile, "nm: query exclude tag '%s'\n", tag));
-+		notmuch_query_add_tag_exclude(query, tag);
-+		end = tag = NULL;
-+	}
-+	notmuch_query_set_omit_excluded(query, 1);
-+	FREE(&buf);
-+}
++# Highlight a particular from (~f)
++color index_author brightyellow color234 '~fRay Charles'
 +
-+static notmuch_query_t *get_query(struct nm_ctxdata *data, int writable)
-+{
-+	notmuch_database_t *db = NULL;
-+	notmuch_query_t *q = NULL;
-+	const char *str;
++# Message flags, %S %Z
++# Highlight the flags for flagged (~F) emails
++color index_flags default red '~F'
 +
-+	if (!data)
-+		return NULL;
++# Subject, %s
++# Look for a particular subject (~s)
++color index_subject brightcyan default '~s\(closes #[0-9]+\)'
 +
-+	db = get_db(data, writable);
-+	str = get_query_string(data);
++# Number of messages in a collapsed thread, %M
++color index_collapsed default brightblue
 +
-+	if (!db || !str)
-+		goto err;
++# Date field
++color index_date green default
 +
-+	q = notmuch_query_create(db, str);
-+	if (!q)
-+		goto err;
++# Message label, %y %Y
++color index_label default brightgreen
 +
-+	apply_exclude_tags(q);
-+	notmuch_query_set_sort(q, NOTMUCH_SORT_NEWEST_FIRST);
-+	dprint(2, (debugfile, "nm: query successfully initialized\n"));
-+	return q;
-+err:
-+	if (!is_longrun(data))
-+		release_db(data);
-+	return NULL;
-+}
++# Message number, %C
++color index_number red default
 +
-+static void append_str_item(char **str, const char *item, int sep)
-+{
-+	char *p;
-+	size_t sz = strlen(item);
-+	size_t ssz = *str ? strlen(*str) : 0;
++# Message size, %c %l
++color index_size cyan default
 +
-+	safe_realloc(str, ssz + (ssz && sep ? 1 : 0) + sz + 1);
-+	p = *str + ssz;
-+	if (sep && ssz)
-+	    *p++ = sep;
-+	memcpy(p, item, sz + 1);
-+}
++# vim: syntax=muttrc
+diff --git a/doc/muttrc.initials b/doc/muttrc.initials
+new file mode 100644
+index 0000000..644c1b7
+--- /dev/null
++++ b/doc/muttrc.initials
+@@ -0,0 +1,27 @@
++# Example Mutt config file for the 'initials' patch.
 +
-+static int update_header_tags(HEADER *h, notmuch_message_t *msg)
-+{
-+	struct nm_hdrdata *data = h->data;
-+	notmuch_tags_t *tags;
-+	char *tstr = NULL, *ttstr = NULL;
-+	struct nm_hdrtag *tag_list = NULL, *tmp;
++# The 'initials' patch has no config of its own.
++# It adds an expando for an author's initials,
++# which can be used in the 'index_format' variable.
 +
-+	dprint(2, (debugfile, "nm: tags update requested (%s)\n", data->virtual_id));
++# The default 'index_format' is:
++set index_format='%4C %Z %{%b %d} %-15.15L (%?l?%4l&%4c?) %s'
 +
-+	for (tags = notmuch_message_get_tags(msg);
-+	     tags && notmuch_tags_valid(tags);
-+	     notmuch_tags_move_to_next(tags)) {
++# Where %L represents the author/recipient
 +
-+		const char *t = notmuch_tags_get(tags);
-+		const char *tt = NULL;
++# This might look like:
++#       1   + Nov 17 David Bowie   Changesbowie    ( 689)
++#       2   ! Nov 17 Stevie Nicks  Rumours         ( 555)
++#       3   + Nov 16 Jimi Hendrix  Voodoo Child    ( 263)
++#       4   + Nov 16 Debbie Harry  Parallel Lines  ( 540)
 +
-+		if (!t || !*t)
-+			continue;
++# Using the %I expando:
++set index_format='%4C %Z %{%b %d} %I (%?l?%4l&%4c?) %s'
 +
-+		tt = hash_find(TagTransforms, t);
-+		if (!tt)
-+			tt = t;
++# This might look like:
++#       1   + Nov 17 DB Changesbowie    ( 689)
++#       2   ! Nov 17 SN Rumours         ( 555)
++#       3   + Nov 16 JH Voodoo Child    ( 263)
++#       4   + Nov 16 DH Parallel Lines  ( 540)
 +
-+		/* tags list contains all tags */
-+		tmp = safe_calloc(1, sizeof(*tmp));
-+		tmp->tag = safe_strdup(t);
-+		tmp->transformed = safe_strdup(tt);
-+		tmp->next = tag_list;
-+		tag_list = tmp;
++# vim: syntax=muttrc
+diff --git a/doc/muttrc.keywords b/doc/muttrc.keywords
+new file mode 100644
+index 0000000..5b72d4b
+--- /dev/null
++++ b/doc/muttrc.keywords
+@@ -0,0 +1,23 @@
++# This is a complete list of keywords-related configuration.
++
++# --------------------------------------------------------------------------
++# VARIABLES - shown with their default values
++# --------------------------------------------------------------------------
 +
-+		/* filter out hidden tags */
-+		if (NotmuchHiddenTags) {
-+			char *p = strstr(NotmuchHiddenTags, t);
-+			size_t xsz = p ? strlen(t) : 0;
++# Should Mutt save the keywords to whatever keyword it came from?
++set keywords_legacy = yes
 +
-+			if (p && (p == NotmuchHiddenTags
-+				  || *(p - 1) == ','
-+				  || *(p - 1) == ' ')
-+			    && (*(p + xsz) == '\0'
-+				  || *(p + xsz) == ','
-+				  || *(p + xsz) == ' '))
-+				continue;
-+		}
++# Should Mutt use the "Keywords:" header?
++set keywords_standard = no
 +
-+		/* expand the transformed tag string */
-+		append_str_item(&ttstr, tt, ' ');
++# How should the keywords be separated?
++set xlabel_delimiter = ""
 +
-+		/* expand the un-transformed tag string */
-+		append_str_item(&tstr, t, ' ');
-+	}
++# --------------------------------------------------------------------------
++# FUNCTIONS - shown with an example mapping
++# --------------------------------------------------------------------------
 +
-+	free_tag_list(&data->tag_list);
-+	data->tag_list = tag_list;
++# Bind 'y' to edit labels/keywords
++bind index,pager y edit-label
 +
-+	if (data->tags && tstr && strcmp(data->tags, tstr) == 0) {
-+		FREE(&tstr);
-+		FREE(&ttstr);
-+		dprint(2, (debugfile, "nm: tags unchanged\n"));
-+		return 1;
-+	}
++# vim: syntax=muttrc
+diff --git a/doc/muttrc.limit-current-thread b/doc/muttrc.limit-current-thread
+new file mode 100644
+index 0000000..5d32cf5
+--- /dev/null
++++ b/doc/muttrc.limit-current-thread
+@@ -0,0 +1,6 @@
++# Example Mutt config file for the 'limit-current-thread' patch.
++ 
++# Limit view to current thread
++bind index <esc>L limit-current-thread
++ 
++# vim: syntax=muttrc
+diff --git a/doc/muttrc.man.head b/doc/muttrc.man.head
+index b237c5a..6ab69a7 100644
+--- a/doc/muttrc.man.head
++++ b/doc/muttrc.man.head
+@@ -358,7 +358,24 @@ You may use multiple
+ \fBcrypt-hook\fPs with the same \fIregexp\fP; multiple matching
+ \fBcrypt-hook\fPs result in the use of multiple \fIkey-id\fPs for
+ a recipient.
+-
++.PP
++.nf
++\fBopen-hook\fP \fIregexp\fP "\fIcommand\fP"
++\fBclose-hook\fP \fIregexp\fP "\fIcommand\fP"
++\fBappend-hook\fP \fIregexp\fP "\fIcommand\fP"
++.fi
++.IP
++These commands provide a way to handle compressed folders. The given
++\fBregexp\fP specifies which folders are taken as compressed (e.g.
++"\fI\\\\.gz$\fP"). The commands tell Mutt how to uncompress a folder
++(\fBopen-hook\fP), compress a folder (\fBclose-hook\fP) or append a
++compressed mail to a compressed folder (\fBappend-hook\fP). The
++\fIcommand\fP string is the
++.BR printf (3)
++like format string, and it should accept two parameters: \fB%f\fP,
++which is replaced with the (compressed) folder name, and \fB%t\fP
++which is replaced with the name of the temporary folder to which to
++write.
+ .TP
+ \fBpush\fP \fIstring\fP
+ This command adds the named \fIstring\fP to the keyboard buffer.
+diff --git a/doc/muttrc.nested-if b/doc/muttrc.nested-if
+new file mode 100644
+index 0000000..aee76eb
+--- /dev/null
++++ b/doc/muttrc.nested-if
+@@ -0,0 +1,24 @@
++# Example Mutt config file for the 'nested-if' feature.
 +
-+	/* free old version */
-+	FREE(&data->tags);
-+	FREE(&data->tags_transformed);
++# This patch uses the format: '%<VAR?TRUE&FALSE>' for conditional
++# format strings that can be nested.
 +
-+	/* new version */
-+	data->tags = tstr;
-+	dprint(2, (debugfile, "nm: new tags: '%s'\n", tstr));
++# Example 1
++# if a thread is folded
++#       display the number of messages (%M)
++# else if we know how many lines in the message
++#       display lines in message (%l)
++# else display the size of the message in bytes (%c)
++set index_format='%4C %Z %{%b %d} %-25.25n %s%> %<M?%M Msgs &%<l?%l Lines&%c Bytes>>'
 +
-+	data->tags_transformed = ttstr;
-+	dprint(2, (debugfile, "nm: new tag transforms: '%s'\n", ttstr));
++# Example 2
++# if a thread is folded
++#       display the number of messages (%M)
++#       display the subject (%s)
++# else if we know how many lines in the message
++#       display lines in message (%l)
++# else
++#       display the size of the message in bytes (%c)
++set index_format='%4C %Z %{%b %d} %-25.25n %<M?[%M] %s&%s%* %<l?%l&%c>>'
 +
-+	return 0;
-+}
++# vim: syntax=muttrc
+diff --git a/doc/muttrc.new-mail b/doc/muttrc.new-mail
+new file mode 100644
+index 0000000..3c3ce1f
+--- /dev/null
++++ b/doc/muttrc.new-mail
+@@ -0,0 +1,18 @@
++# Example Mutt config file for the 'new-mail-command' patch.
 +
-+/*
-+ * set/update HEADER->path and HEADER->data->path
-+ */
-+static int update_message_path(HEADER *h, const char *path)
-+{
-+	struct nm_hdrdata *data = h->data;
-+	char *p;
++# --------------------------------------------------------------------------
++# VARIABLES - shown with their default values
++# --------------------------------------------------------------------------
 +
-+	dprint(2, (debugfile, "nm: path update requested path=%s, (%s)\n",
-+				path, data->virtual_id));
++# Set the command you want mutt to execute upon the receipt of a new email
++set new_mail_command = ""
 +
-+	p = strrchr(path, '/');
-+	if (p && p - path > 3 &&
-+	    (strncmp(p - 3, "cur", 3) == 0 ||
-+	     strncmp(p - 3, "new", 3) == 0 ||
-+	     strncmp(p - 3, "tmp", 3) == 0)) {
++# Linux example:
++# set new_command="notify-send --icon='/home/santiago/Pictures/mutt.png' 'New Email in %f' '%n new messages, %u unread.' &"
 +
-+		data->magic = M_MAILDIR;
++# OS X example:
++# set new_mail_command="terminal-notifier -title '%v' -subtitle 'New Mail in %f' -message '%n new messages, %u unread.' -activate 'com.apple.Terminal'"
 +
-+		FREE(&h->path);
-+		FREE(&data->folder);
++# --------------------------------------------------------------------------
 +
-+		p -= 3;				/* skip subfolder (e.g. "new") */
-+		h->path = safe_strdup(p);
++# vim: syntax=muttrc
+diff --git a/doc/muttrc.nntp b/doc/muttrc.nntp
+new file mode 100644
+index 0000000..73b5629
+--- /dev/null
++++ b/doc/muttrc.nntp
+@@ -0,0 +1,115 @@
++# This is a complete list of nntp configuration.
 +
-+		for (; p > path && *(p - 1) == '/'; p--);
++# --------------------------------------------------------------------------
++# VARIABLES - shown with their default values
++# --------------------------------------------------------------------------
 +
-+		data->folder = strndup(path, p - path);
++set ask_follow_up = no
++set ask_x_comment_to = no
++set catchup_newsgroup = ask-yes
++set followup_to_poster = ask-yes
++set group_index_format = '%4C %M%N %5s  %-45.45f %d'
++set inews = ''
++set mime_subject = yes
++set newsgroups_charset = utf-8
++set newsrc = '~/.newsrc'
++set news_cache_dir = '~/.mutt'
++set news_server = ''
++set nntp_authenticators = ''
++set nntp_context = 1000
++set nntp_listgroup = yes
++set nntp_load_description = yes
++set nntp_pass = ''
++set nntp_poll = 60
++set nntp_user = ''
++set post_moderated = ask-yes
++set save_unsubscribed = no
++set show_new_news = yes
++set show_only_unread = no
++set x_comment_to = no
 +
-+		dprint(2, (debugfile, "nm: folder='%s', file='%s'\n", data->folder, h->path));
-+		return 0;
-+	}
++# --------------------------------------------------------------------------
++# FUNCTIONS - shown with an example mapping
++# --------------------------------------------------------------------------
 +
-+	return 1;
-+}
++# mark all articles in newsgroup as read
++bind browser,index y catchup 
 +
-+static char *get_folder_from_path(const char *path)
-+{
-+	char *p = strrchr(path, '/');
++# open a different newsgroup
++bind index,pager i change-newsgroup 
 +
-+	if (p && p - path > 3 &&
-+	    (strncmp(p - 3, "cur", 3) == 0 ||
-+	     strncmp(p - 3, "new", 3) == 0 ||
-+	     strncmp(p - 3, "tmp", 3) == 0)) {
++# open a different virtual folder
++bind pager X change-vfolder 
 +
-+		p -= 3;
-+		for (; p > path && *(p - 1) == '/'; p--);
++# edit the Followup-To field
++bind compose o edit-followup-to 
 +
-+		return strndup(path, p - path);
-+	}
++# edit the newsgroups list
++bind compose N edit-newsgroups 
 +
-+	return NULL;
-+}
++# edit the X-Comment-To field
++bind compose x edit-x-comment-to 
 +
-+static void deinit_header(HEADER *h)
-+{
-+	if (h) {
-+		free_hdrdata(h->data);
-+		h->data = NULL;
-+	}
-+}
++# read entire thread of the current message
++bind pager + entire-thread 
 +
-+/* converts notmuch message Id to mutt message <Id> */
-+static char *nm2mutt_message_id(const char *id)
-+{
-+	size_t sz;
-+	char *mid;
++# followup to newsgroup
++bind attachment,index,pager F followup-message 
 +
-+	if (!id)
-+		return NULL;
-+	sz = strlen(id) + 3;
-+	mid = safe_malloc(sz);
++# modify (notmuch) tags
++bind pager ` modify-labels 
 +
-+	snprintf(mid, sz, "<%s>", id);
-+	return mid;
-+}
++# post message to newsgroup
++bind index,pager P post-message 
 +
-+static int init_header(HEADER *h, const char *path, notmuch_message_t *msg)
-+{
-+	const char *id;
++# load list of all newsgroups from NNTP server
++bind browser g reload-active 
 +
-+	if (h->data)
-+		return 0;
++# subscribe to current mbox (IMAP/NNTP only)
++bind browser s subscribe 
 +
-+	id = notmuch_message_get_message_id(msg);
++# subscribe to newsgroups matching a pattern
++bind browser S subscribe-pattern 
 +
-+	h->data = safe_calloc(1, sizeof(struct nm_hdrdata));
-+	h->free_cb = deinit_header;
++# mark all articles in newsgroup as unread
++bind browser Y uncatchup 
 +
-+	/*
-+	 * Notmuch ensures that message Id exists (if not notmuch Notmuch will
-+	 * generate an ID), so it's more safe than use mutt HEADER->env->id
-+	 */
-+	((struct nm_hdrdata *) h->data)->virtual_id = safe_strdup( id );
++# unsubscribe from current mbox (IMAP/NNTP only)
++bind browser u unsubscribe 
 +
-+	dprint(2, (debugfile, "nm: initialize header data: [hdr=%p, data=%p] (%s)\n",
-+				h, h->data, id));
++# unsubscribe from newsgroups matching a pattern
++bind browser U unsubscribe-pattern 
 +
-+	if (!h->env->message_id)
-+		h->env->message_id = nm2mutt_message_id( id );
++# open a different newsgroup in read only mode
++bind index,pager \ei change-newsgroup-readonly 
 +
-+	if (update_message_path(h, path))
-+		return -1;
++# forward to newsgroup
++bind attachment,index,pager \eF forward-to-group 
 +
-+	update_header_tags(h, msg);
++# get all children of the current message
++# bind index ??? get-children 
 +
-+	return 0;
-+}
++# get parent of the current message
++bind index \eG get-parent 
 +
-+/**
-+static void debug_print_filenames(notmuch_message_t *msg)
-+{
-+	notmuch_filenames_t *ls;
-+	const char *id = notmuch_message_get_message_id(msg);
++# force retrieval of mail from IMAP server
++# bind index,pager ??? imap-fetch-mail 
 +
-+	for (ls = notmuch_message_get_filenames(msg);
-+	     ls && notmuch_filenames_valid(ls);
-+	     notmuch_filenames_move_to_next(ls)) {
++# logout from all IMAP servers
++# bind index,pager ??? imap-logout-all 
 +
-+		dprint(2, (debugfile, "nm: %s: %s\n", id, notmuch_filenames_get(ls)));
-+	}
-+}
++# modify labeld and then hide message
++# bind pager ??? modify-labels-then-hide 
 +
-+static void debug_print_tags(notmuch_message_t *msg)
-+{
-+	notmuch_tags_t *tags;
-+	const char *id = notmuch_message_get_message_id(msg);
++# reconstruct thread containing current message
++# bind index ??? reconstruct-thread 
 +
-+	for (tags = notmuch_message_get_tags(msg);
-+	     tags && notmuch_tags_valid(tags);
-+	     notmuch_tags_move_to_next(tags)) {
++# generate virtual folder from query
++bind pager \eX vfolder-from-query 
 +
-+		dprint(2, (debugfile, "nm: %s: %s\n", id, notmuch_tags_get(tags)));
-+	}
-+}
-+***/
++# get message with Message-Id
++bind index \CG get-message 
 +
-+static const char *get_message_last_filename(notmuch_message_t *msg)
-+{
-+	notmuch_filenames_t *ls;
-+	const char *name = NULL;
++# --------------------------------------------------------------------------
 +
-+	for (ls = notmuch_message_get_filenames(msg);
-+	     ls && notmuch_filenames_valid(ls);
-+	     notmuch_filenames_move_to_next(ls)) {
++# vim: syntax=muttrc
+diff --git a/doc/muttrc.notmuch b/doc/muttrc.notmuch
+new file mode 100644
+index 0000000..c752395
+--- /dev/null
++++ b/doc/muttrc.notmuch
+@@ -0,0 +1,114 @@
++# This is a complete list of notmuch-related configuration.
 +
-+		name = notmuch_filenames_get(ls);
-+	}
++# --------------------------------------------------------------------------
++# VARIABLES - shown with their default values
++# --------------------------------------------------------------------------
 +
-+	return name;
-+}
++# This variable specifies notmuch query limit.
++set nm_db_limit = 0
 +
-+static void nm_progress_reset(CONTEXT *ctx)
-+{
-+	struct nm_ctxdata *data;
++# This variable specifies the default Notmuch database in format:
++# notmuch://<absolute path>
++set nm_default_uri = ""
 +
-+	if (ctx->quiet)
-+		return;
++# The messages tagged with these tags are excluded and not loaded
++# from notmuch DB to mutt unless specified explicitly.
++set nm_exclude_tags = ""
 +
-+	data = get_ctxdata(ctx);
++# This variable specifies private notmuch tags which should not be printed
++# on screen (index, pager).
++set nm_hidden_tags = "unread,draft,flagged,passed,replied,attachment,signed,encrypted"
 +
-+	memset(&data->progress, 0, sizeof(data->progress));
-+	data->oldmsgcount = ctx->msgcount;
-+	data->ignmsgcount = 0;
-+	data->noprogress = 0;
-+	data->progress_ready = 0;
-+}
++# This option specifies timeout for Notmuch database. Default is 5 seconds.
++set nm_open_timeout = 5
 +
-+static void nm_progress_update(CONTEXT *ctx, notmuch_query_t *q)
-+{
-+	struct nm_ctxdata *data = get_ctxdata(ctx);
++# This variable specifies notmuch query type, supported types: 'threads' and
++# 'messages'.
++set nm_query_type = messages
 +
-+	if (ctx->quiet || data->noprogress)
-+		return;
++# Add messages stored to the mutt record (see $record in the mutt docs)
++# also to notmuch DB.
++set nm_record = no
 +
-+	if (!data->progress_ready && q) {
-+		unsigned count;
-+		static char msg[STRING];
-+		snprintf(msg, sizeof(msg), _("Reading messages..."));
++# Tags that should be removed or added to the to the messages stored in the mutt record.
++set nm_record_tags = ""
 +
-+#if LIBNOTMUCH_CHECK_VERSION(4,3,0)
-+		if (notmuch_query_count_messages_st (q, &count) != NOTMUCH_STATUS_SUCCESS)
-+			count = 0;	/* may not be defined on error */
-+#else
-+		count = notmuch_query_count_messages(q);
-+#endif
-+		mutt_progress_init(&data->progress, msg, M_PROGRESS_MSG,
-+			ReadInc, count);
-+		data->progress_ready = 1;
-+	}
++# This variable specifies notmuch tag which is used for unread messages.
++set nm_unread_tag = unread
++
++# This variable allows you to customize the file browser display for virtual
++# folders to your personal taste.
++set vfolder_format = "%6n(%6N) %f"
++
++# When set, mutt will use the first virtual mailbox (see virtual-mailboxes)
++# as a spoolfile.
++set virtual_spoolfile = no
 +
-+	if (data->progress_ready)
-+		mutt_progress_update(&data->progress,
-+				ctx->msgcount + data->ignmsgcount
-+					      - data->oldmsgcount, -1);
-+}
++# --------------------------------------------------------------------------
++# FUNCTIONS - shown with an example mapping
++# --------------------------------------------------------------------------
 +
-+static void append_message(CONTEXT *ctx,
-+			   notmuch_query_t *q,
-+			   notmuch_message_t *msg,
-+			   int dedup)
-+{
-+	char *newpath = NULL;
-+	const char *path;
-+	HEADER *h = NULL;
++# open a different virtual folder
++bind index,pager X change-vfolder
 +
-+	/* deduplicate */
-+	if (dedup && get_mutt_header(ctx, msg)) {
-+		get_ctxdata(ctx)->ignmsgcount++;
-+		nm_progress_update(ctx, q);
-+	        dprint(2, (debugfile, "nm: ignore id=%s, already in the context\n",
-+					notmuch_message_get_message_id(msg)));
-+		return;
-+	}
++# read entire thread of the current message
++bind index,pager + entire-thread
 +
-+	path = get_message_last_filename(msg);
-+	if (!path)
-+		return;
++# modify (notmuch) tags
++bind index,pager ` modify-labels
 +
-+	dprint(2, (debugfile, "nm: appending message, i=%d, id=%s, path=%s\n",
-+				ctx->msgcount,
-+				notmuch_message_get_message_id(msg),
-+				path));
++# generate virtual folder from query
++bind index,pager \eX vfolder-from-query
 +
-+	if (ctx->msgcount >= ctx->hdrmax) {
-+		dprint(2, (debugfile, "nm: allocate mx memory\n"));
-+		mx_alloc_memory(ctx);
-+	}
-+	if (access(path, F_OK) == 0)
-+		h = maildir_parse_message(M_MAILDIR, path, 0, NULL);
-+	else {
-+		/* maybe moved try find it... */
-+		char *folder = get_folder_from_path(path);
++# modify labels and then hide message
++# bind index,pager ??? modify-labels-then-hide
 +
-+		if (folder) {
-+			FILE *f = maildir_open_find_message(folder, path, &newpath);
-+			if (f) {
-+				h = maildir_parse_stream(M_MAILDIR, f, newpath, 0, NULL);
-+				fclose(f);
++# toggle between mailboxes and virtual mailboxes
++# bind index,pager ??? sidebar-toggle-virtual
 +
-+				dprint(1, (debugfile, "nm: not up-to-date: %s -> %s\n",
-+							path, newpath));
-+			}
-+		}
-+		FREE(&folder);
-+	}
++# --------------------------------------------------------------------------
++# COMMANDS - shown with an example
++# --------------------------------------------------------------------------
 +
-+	if (!h) {
-+		dprint(1, (debugfile, "nm: failed to parse message: %s\n", path));
-+		goto done;
-+	}
-+	if (init_header(h, newpath ? newpath : path, msg) != 0) {
-+		mutt_free_header(&h);
-+		dprint(1, (debugfile, "nm: failed to append header!\n"));
-+		goto done;
-+	}
++# virtual-mailboxes description notmuch-URI { description notmuch-URI ...}
++# virtual-mailboxes "Climbing" "notmuch://?query=climbing"
++
++# Replace some tags with icons
++# tag-transforms tag transformed-string { tag transformed-string ...}
++# tag-transforms "inbox"   "i"   \
++#                "unread"  "u"   \
++#                "replied" "↻ "  \
++#                "sent"    "➥ "  \
++#                "todo"    "T"   \
++#                "deleted" "DEL" \
++#                "invites" "CAL"
++
++# See README.notmuch for an explanation
++# tag-formats tag format-string { tag format-string ...}
++# tag-formats "inbox"   "GI" \
++#              "unread"  "GU" \
++#              "replied" "GR" \
++#              "sent"    "GS" \
++#              "todo"    "Gt" \
++#              "deleted" "GD" \
++#              "invites" "Gi"
++
++# set index_format='4C %S %[%y.%m.%d] %-18.18n %?GU?%GU& ? %?GR?%GR& ? %?GI?%GI& ? %s'
 +
-+	h->active = 1;
-+	h->index = ctx->msgcount;
-+	ctx->size += h->content->length
-+		   + h->content->offset
-+		   - h->content->hdr_offset;
-+	ctx->hdrs[ctx->msgcount] = h;
-+	ctx->msgcount++;
++# --------------------------------------------------------------------------
++# COLORS - some unpleasant examples are given
++# --------------------------------------------------------------------------
 +
-+	if (newpath) {
-+		/* remember that file has been moved -- nm_sync() will update the DB */
-+		struct nm_hdrdata *hd = (struct nm_hdrdata *) h->data;
++# These symbols are added to the index-color patch:
 +
-+		if (hd) {
-+			dprint(1, (debugfile, "nm: remember obsolete path: %s\n", path));
-+			hd->oldpath = safe_strdup(path);
-+		}
-+	}
-+	nm_progress_update(ctx, q);
-+done:
-+	FREE(&newpath);
-+}
++# an individual message tag, %G, uses tag name
++# this symbol uses a pattern
++color index_tag red white "inbox"
 +
-+/*
-+ * add all the replies to a given messages into the display.
-+ * Careful, this calls itself recursively to make sure we get
-+ * everything.
-+ */
-+static void append_replies(CONTEXT *ctx,
-+			   notmuch_query_t *q,
-+			   notmuch_message_t *top,
-+			   int dedup)
-+{
-+	notmuch_messages_t *msgs;
++# the transformed message tags, %g
++# this symbol does not use a pattern
++color index_tags green default
 +
-+	for (msgs = notmuch_message_get_replies(top);
-+	     notmuch_messages_valid(msgs);
-+	     notmuch_messages_move_to_next(msgs)) {
++# --------------------------------------------------------------------------
 +
-+		notmuch_message_t *m = notmuch_messages_get(msgs);
-+		append_message(ctx, q, m, dedup);
-+		/* recurse through all the replies to this message too */
-+		append_replies(ctx, q, m, dedup);
-+		notmuch_message_destroy(m);
-+	}
-+}
++# vim: syntax=muttrc
+diff --git a/doc/muttrc.progress b/doc/muttrc.progress
+new file mode 100644
+index 0000000..7efe45c
+--- /dev/null
++++ b/doc/muttrc.progress
+@@ -0,0 +1,10 @@
++# Example Mutt config file for the 'progress' patch.
 +
-+/*
-+ * add each top level reply in the thread, and then add each
-+ * reply to the top level replies
-+ */
-+static void append_thread(CONTEXT *ctx,
-+			  notmuch_query_t *q,
-+			  notmuch_thread_t *thread,
-+			  int dedup)
-+{
-+	notmuch_messages_t *msgs;
++# The 'progress' patch provides clear visual feedback for
++# slow tasks, such as indexing a large folder over the net.
 +
-+	for (msgs = notmuch_thread_get_toplevel_messages(thread);
-+	     notmuch_messages_valid(msgs);
-+	     notmuch_messages_move_to_next(msgs)) {
++# Set the color of the progress bar
++# White text on a red background
++color progress white red
 +
-+		notmuch_message_t *m = notmuch_messages_get(msgs);
-+		append_message(ctx, q, m, dedup);
-+		append_replies(ctx, q, m, dedup);
-+		notmuch_message_destroy(m);
-+	}
-+}
++# vim: syntax=muttrc
+diff --git a/doc/muttrc.quasi-delete b/doc/muttrc.quasi-delete
+new file mode 100644
+index 0000000..67031ff
+--- /dev/null
++++ b/doc/muttrc.quasi-delete
+@@ -0,0 +1,7 @@
++# Example Mutt config file for the 'quasi-delete' feature.
 +
-+static void read_mesgs_query(CONTEXT *ctx, notmuch_query_t *q, int dedup)
-+{
-+	struct nm_ctxdata *data = get_ctxdata(ctx);
-+	int limit;
-+	notmuch_messages_t *msgs;
++# The 'quasi-delete' function marks an email that should be hidden
++# from the index, but NOT deleted.
++bind index,pager Q quasi-delete
 +
-+	if (!data)
-+		return;
++# vim: syntax=muttrc
+diff --git a/doc/muttrc.sidebar b/doc/muttrc.sidebar
+new file mode 100644
+index 0000000..f21db26
+--- /dev/null
++++ b/doc/muttrc.sidebar
+@@ -0,0 +1,116 @@
++# This is a complete list of sidebar-related configuration.
 +
-+	limit = get_limit(data);
++# --------------------------------------------------------------------------
++# VARIABLES - shown with their default values
++# --------------------------------------------------------------------------
 +
-+#if LIBNOTMUCH_CHECK_VERSION(4,3,0)
-+	if (notmuch_query_search_messages_st (q, &msgs) != NOTMUCH_STATUS_SUCCESS)
-+		return;
-+#else
-+	msgs = notmuch_query_search_messages(q);
-+#endif
++# Should the Sidebar be shown?
++set sidebar_visible = no
 +
-+	for (; notmuch_messages_valid(msgs) &&
-+		(limit == 0 || ctx->msgcount < limit);
-+	     notmuch_messages_move_to_next(msgs)) {
++# How wide should the Sidebar be in screen columns?
++# Note: Some characters, e.g. Chinese, take up two columns each.
++set sidebar_width = 20
 +
-+		notmuch_message_t *m = notmuch_messages_get(msgs);
-+		append_message(ctx, q, m, dedup);
-+		notmuch_message_destroy(m);
-+	}
-+}
++# Should the mailbox paths be abbreviated?
++set sidebar_short_path = no
 +
-+static void read_threads_query(CONTEXT *ctx, notmuch_query_t *q, int dedup, int limit)
-+{
-+	struct nm_ctxdata *data = get_ctxdata(ctx);
-+	notmuch_threads_t *threads;
++# When abbreviating mailbox path names, use any of these characters as path
++# separators.  Only the part after the last separators will be shown.
++# For file folders '/' is good.  For IMAP folders, often '.' is useful.
++set sidebar_delim_chars = '/.'
 +
-+	if (!data)
-+		return;
++# If the mailbox path is abbreviated, should it be indented?
++set sidebar_folder_indent = no
 +
-+#if LIBNOTMUCH_CHECK_VERSION(4,3,0)
-+	if (notmuch_query_search_threads_st (q, &threads) != NOTMUCH_STATUS_SUCCESS)
-+		return;
-+#else
-+	threads = notmuch_query_search_threads(q);
-+#endif
++# Indent mailbox paths with this string.
++set sidebar_indent_string = '  '
 +
-+	for (; notmuch_threads_valid(threads) &&
-+		(limit == 0 || ctx->msgcount < limit);
-+	     notmuch_threads_move_to_next(threads)) {
++# Make the Sidebar only display mailboxes that contain new, or flagged,
++# mail.
++set sidebar_new_mail_only = no
 +
-+		notmuch_thread_t *thread = notmuch_threads_get(threads);
-+		append_thread(ctx, q, thread, dedup);
-+		notmuch_thread_destroy(thread);
-+	}
-+}
++# Any mailboxes that are whitelisted will always be visible, even if the
++# sidebar_new_mail_only option is enabled.
++sidebar_whitelist '/home/user/mailbox1'
++sidebar_whitelist '/home/user/mailbox2'
 +
-+int nm_read_query(CONTEXT *ctx)
-+{
-+	notmuch_query_t *q;
-+	struct nm_ctxdata *data;
-+	int rc = -1;
++# When searching for mailboxes containing new mail, should the search wrap
++# around when it reaches the end of the list?
++set sidebar_next_new_wrap = no
 +
-+	if (init_context(ctx) != 0)
-+		return -1;
++# The character to use as the divider between the Sidebar and the other Mutt
++# panels.
++# Note: Only the first character of this string is used.
++set sidebar_divider_char = '|'
 +
-+	data = get_ctxdata(ctx);
-+	if (!data)
-+		return -1;
++# Enable extended buffy mode to calculate total, new, and flagged
++# message counts for each mailbox.
++set mail_check_stats
 +
-+	dprint(1, (debugfile, "nm: reading messages...[current count=%d]\n",
-+				ctx->msgcount));
++# Display the Sidebar mailboxes using this format string.
++set sidebar_format = '%B%?F? [%F]?%* %?N?%N/?%S'
 +
-+	nm_progress_reset(ctx);
++# Sort the mailboxes in the Sidebar using this method:
++#       count    - total number of messages
++#       flagged  - number of flagged messages
++#       new      - number of new messages
++#       path     - mailbox path
++#       unsorted - do not sort the mailboxes
++set sidebar_sort_method = 'unsorted'
 +
-+	q = get_query(data, FALSE);
-+	if (q) {
-+		switch(get_query_type(data)) {
-+		case NM_QUERY_TYPE_MESGS:
-+			read_mesgs_query(ctx, q, 0);
-+			break;
-+		case NM_QUERY_TYPE_THREADS:
-+			read_threads_query(ctx, q, 0, get_limit(data));
-+			break;
-+		}
-+		notmuch_query_destroy(q);
-+		rc = 0;
++# --------------------------------------------------------------------------
++# FUNCTIONS - shown with an example mapping
++# --------------------------------------------------------------------------
++
++# Move the highlight to the previous mailbox
++bind index,pager \Cp sidebar-prev
 +
-+	}
++# Move the highlight to the next mailbox
++bind index,pager \Cn sidebar-next
 +
-+	if (!is_longrun(data))
-+		release_db(data);
++# Open the highlighted mailbox
++bind index,pager \Co sidebar-open
 +
-+	ctx->mtime = time(NULL);
++# Move the highlight to the previous page
++# This is useful if you have a LOT of mailboxes.
++bind index,pager <F3> sidebar-page-up
 +
-+	mx_update_context(ctx, ctx->msgcount);
-+	data->oldmsgcount = 0;
++# Move the highlight to the next page
++# This is useful if you have a LOT of mailboxes.
++bind index,pager <F4> sidebar-page-down
 +
-+	dprint(1, (debugfile, "nm: reading messages... done [rc=%d, count=%d]\n",
-+				rc, ctx->msgcount));
-+	return rc;
-+}
++# Move the highlight to the previous mailbox containing new, or flagged,
++# mail.
++bind index,pager <F5> sidebar-prev-new
 +
-+int nm_read_entire_thread(CONTEXT *ctx, HEADER *h)
-+{
-+	struct nm_ctxdata *data = get_ctxdata(ctx);
-+	const char *id;
-+	char *qstr = NULL;
-+	notmuch_query_t *q = NULL;
-+	notmuch_database_t *db = NULL;
-+	notmuch_message_t *msg = NULL;
-+	int rc = -1;
++# Move the highlight to the next mailbox containing new, or flagged, mail.
++bind index,pager <F6> sidebar-next-new
 +
-+	if (!data)
-+		return -1;
-+	if (!(db = get_db(data, FALSE)) || !(msg = get_nm_message(db, h)))
-+		goto done;
++# Toggle the visibility of the Sidebar.
++bind index,pager B sidebar-toggle-visible
 +
-+	dprint(1, (debugfile, "nm: reading entire-thread messages...[current count=%d]\n",
-+				ctx->msgcount));
++# --------------------------------------------------------------------------
++# COLORS - some unpleasant examples are given
++# --------------------------------------------------------------------------
++# Note: All color operations are of the form:
++#       color OBJECT FOREGROUND BACKGROUND
 +
-+	nm_progress_reset(ctx);
-+	id = notmuch_message_get_thread_id(msg);
-+	if (!id)
-+		goto done;
-+	append_str_item(&qstr, "thread:", 0);
-+	append_str_item(&qstr, id, 0);
++# Color of the current, open, mailbox
++# Note: This is a general Mutt option which colors all selected items.
++color indicator cyan black
 +
-+	q = notmuch_query_create(db, qstr);
-+	FREE(&qstr);
-+	if (!q)
-+		goto done;
-+	apply_exclude_tags(q);
-+	notmuch_query_set_sort(q, NOTMUCH_SORT_NEWEST_FIRST);
++# Color of the highlighted, but not open, mailbox.
++color sidebar_highlight black color8
 +
-+	read_threads_query(ctx, q, 1, 0);
-+	ctx->mtime = time(NULL);
-+	rc = 0;
++# Color of the divider separating the Sidebar from Mutt panels
++color sidebar_divider color8 black
 +
-+	if (ctx->msgcount > data->oldmsgcount)
-+		mx_update_context(ctx, ctx->msgcount - data->oldmsgcount);
-+done:
-+	if (q)
-+		notmuch_query_destroy(q);
-+	if (!is_longrun(data))
-+		release_db(data);
++# Color to give mailboxes containing flagged mail
++color sidebar_flagged red black
 +
-+	if (ctx->msgcount == data->oldmsgcount)
-+		mutt_message _("No more messages in the thread.");
++# Color to give mailboxes containing new mail
++color sidebar_new green black
 +
-+	data->oldmsgcount = 0;
-+	dprint(1, (debugfile, "nm: reading entire-thread messages... done [rc=%d, count=%d]\n",
-+				rc, ctx->msgcount));
-+	return rc;
-+}
++# --------------------------------------------------------------------------
 +
-+char *nm_uri_from_query(CONTEXT *ctx, char *buf, size_t bufsz)
-+{
-+	struct nm_ctxdata *data = get_ctxdata(ctx);
-+	char uri[_POSIX_PATH_MAX + LONG_STRING + 32];	/* path to DB + query + URI "decoration" */
++# vim: syntax=muttrc
+diff --git a/doc/muttrc.skip-quoted b/doc/muttrc.skip-quoted
+new file mode 100644
+index 0000000..cd13ed4
+--- /dev/null
++++ b/doc/muttrc.skip-quoted
+@@ -0,0 +1,10 @@
++# Example Mutt config file for the 'skip-quoted' patch.
++ 
++# The 'S' (skip-quoted) command scrolls the pager past the quoted text (usually
++# indented with '> '.  Setting 'skip_quoted_offset' leaves some lines of quoted
++# text on screen for context.
++ 
++# Show three quoted lines before the reply
++set skip_quoted_offset = 3
++ 
++# vim: syntax=muttrc
+diff --git a/doc/muttrc.smime-encrypt-self b/doc/muttrc.smime-encrypt-self
+new file mode 100644
+index 0000000..0ef7c48
+--- /dev/null
++++ b/doc/muttrc.smime-encrypt-self
+@@ -0,0 +1,10 @@
++# This is a complete list of smime-encrypt-self-related configuration.
 +
-+	if (data)
-+		snprintf(uri, sizeof(uri), "notmuch://%s?query=%s",
-+			 get_db_filename(data), buf);
-+	else if (NotmuchDefaultUri)
-+		snprintf(uri, sizeof(uri), "%s?query=%s", NotmuchDefaultUri, buf);
-+	else if (Maildir)
-+		snprintf(uri, sizeof(uri), "notmuch://%s?query=%s", Maildir, buf);
-+	else
-+		return NULL;
++# --------------------------------------------------------------------------
++# VARIABLES - shown with their default values
++# --------------------------------------------------------------------------
 +
-+	strncpy(buf, uri, bufsz);
-+	buf[bufsz - 1] = '\0';
++# Save a copy of outgoing email, encrypted to yourself
++set smime_encrypt_self = "no"
 +
-+	dprint(1, (debugfile, "nm: uri from query '%s'\n", buf));
-+	return buf;
-+}
++# vim: syntax=muttrc
+diff --git a/doc/muttrc.status-color b/doc/muttrc.status-color
+new file mode 100644
+index 0000000..9a1350c
+--- /dev/null
++++ b/doc/muttrc.status-color
+@@ -0,0 +1,49 @@
++# Example Mutt config file for the 'status-color' patch.
 +
-+/*
-+ * returns message from notmuch database
-+ */
-+static notmuch_message_t *get_nm_message(notmuch_database_t *db, HEADER *hdr)
-+{
-+	notmuch_message_t *msg = NULL;
-+	char *id = nm_header_get_id(hdr);
++# The 'status-color' patch allows you to theme different parts of
++# the status bar (also when it's used by the index).
 +
-+	dprint(2, (debugfile, "nm: find message (%s)\n", id));
++# For the examples below, set some defaults
++set status_format='-%r-Mutt: %f [Msgs:%?M?%M/?%m%?n? New:%n?%?o? Old:%o?%?d? Del:%d?%?F? Flag:%F?%?t? Tag:%t?%?p? Post:%p?%?b? Inc:%b?%?l? %l?]---(%s/%S)-%>-(%P)---'
++set index_format='%4C %Z %{%b %d} %-15.15L (%?l?%4l&%4c?) %s'
++set sort=threads
++set sort_aux=last-date-received
 +
-+	if (id && db)
-+		notmuch_database_find_message(db, id, &msg);
++# 'status color' can take up to 2 extra parameters
 +
-+	return msg;
-+}
++# color status foreground background [ regex [ num ]]
 +
-+static int update_tags(notmuch_message_t *msg, const char *tags)
-+{
-+	char *tag = NULL, *end = NULL, *p;
-+	char *buf = safe_strdup(tags);
++# 0 extra parameters
++# Set the default color for the entire status line
++color status blue white
 +
-+	if (!buf)
-+		return -1;
++# 1 extra parameter
++# Set the color for a matching pattern
++# color status foreground background regexp
 +
-+	notmuch_message_freeze(msg);
++# Highlight New, Deleted, or Flagged emails
++color status brightred white '(New|Del|Flag):[0-9]+'
 +
-+	for (p = buf; p && *p; p++) {
-+		if (!tag && isspace(*p))
-+			continue;
-+		if (!tag)
-+			tag = p;		/* begin of the tag */
-+		if (*p == ',' || *p == ' ')
-+			end = p;		/* terminate the tag */
-+		else if (*(p + 1) == '\0')
-+			end = p + 1;		/* end of optstr */
-+		if (!tag || !end)
-+			continue;
-+		if (tag >= end)
-+			break;
++# Highlight mailbox ordering if it's different from the default
++# First, highlight anything (*/*)
++color status brightred default '\([^)]+/[^)]+\)'
 +
-+		*end = '\0';
++# Then override the color for one specific case
++color status default   default '\(threads/last-date-received\)'
 +
-+		if (*tag == '-') {
-+			dprint(1, (debugfile, "nm: remove tag: '%s'\n", tag + 1));
-+			notmuch_message_remove_tag(msg, tag + 1);
-+		} else {
-+			dprint(1, (debugfile, "nm: add tag: '%s'\n", *tag == '+' ? tag + 1 : tag));
-+			notmuch_message_add_tag(msg, *tag == '+' ? tag + 1 : tag);
-+		}
-+		end = tag = NULL;
-+	}
++# 2 extra parameters
++# Set the color for the nth submatch of a pattern
++# color status foreground background regexp num
 +
-+	notmuch_message_thaw(msg);
-+	FREE(&buf);
-+	return 0;
-+}
++# Highlight the contents of the []s but not the [] themselves
++color status red default '\[([^]]+)\]' 1
 +
-+int nm_modify_message_tags(CONTEXT *ctx, HEADER *hdr, char *buf)
-+{
-+	struct nm_ctxdata *data = get_ctxdata(ctx);
-+	notmuch_database_t *db = NULL;
-+	notmuch_message_t *msg = NULL;
-+	int rc = -1;
++# The '1' refers to the first regex submatch, which is the inner
++# part in ()s
 +
-+	if (!buf || !*buf || !data)
-+		return -1;
++# Highlight the mailbox
++color status brightwhite default 'Mutt: ([^ ]+)' 1
 +
-+	if (!(db = get_db(data, TRUE)) || !(msg = get_nm_message(db, hdr)))
-+		goto done;
++# Search for 'Mutt: ' but only highlight what comes after it
 +
-+	dprint(1, (debugfile, "nm: tags modify: '%s'\n", buf));
++# vim: syntax=muttrc
+diff --git a/doc/muttrc.trash b/doc/muttrc.trash
+new file mode 100644
+index 0000000..8ecf8f0
+--- /dev/null
++++ b/doc/muttrc.trash
+@@ -0,0 +1,16 @@
++# Example Mutt config file for the 'trash' feature.
 +
-+	update_tags(msg, buf);
-+	update_header_tags(hdr, msg);
-+	mutt_set_header_color(ctx, hdr);
++# This feature defines a new 'trash' folder.
++# When mail is deleted it will be moved to this folder.
 +
-+	rc = 0;
-+	hdr->changed = TRUE;
-+done:
-+	if (!is_longrun(data))
-+		release_db(data);
-+	if (hdr->changed)
-+		ctx->mtime = time(NULL);
-+	dprint(1, (debugfile, "nm: tags modify done [rc=%d]\n", rc));
-+	return rc;
-+}
++# Folder in which to put deleted emails
++set trash='+Trash'
++set trash='/home/flatcap/Mail/Trash'
 +
-+static int rename_maildir_filename(const char *old, char *newpath, size_t newsz, HEADER *h)
-+{
-+	char filename[_POSIX_PATH_MAX];
-+	char suffix[_POSIX_PATH_MAX];
-+	char folder[_POSIX_PATH_MAX];
-+	char *p;
++# The default delete key 'd' will move an email to the 'trash' folder
++# Bind 'D' to REALLY delete an email
++bind index D purge-message
 +
-+	strfcpy(folder, old, sizeof(folder));
-+	p = strrchr(folder, '/');
-+	if (p)
-+		*p = '\0';
++# Note: Deleting emails from the 'trash' folder will REALLY delete them.
++
++# vim: syntax=muttrc
+diff --git a/doc/vimrc.compress b/doc/vimrc.compress
+new file mode 100644
+index 0000000..e84fad2
+--- /dev/null
++++ b/doc/vimrc.compress
+@@ -0,0 +1,7 @@
++" Vim syntax file for the mutt compress patch
++
++syntax keyword muttrcCommand    append-hook
++syntax keyword muttrcCommand    close-hook
++syntax keyword muttrcCommand    open-hook
 +
-+	p++;
-+	strfcpy(filename, p, sizeof(filename));
++" vim: syntax=vim
+diff --git a/doc/vimrc.ifdef b/doc/vimrc.ifdef
+new file mode 100644
+index 0000000..342c75e
+--- /dev/null
++++ b/doc/vimrc.ifdef
+@@ -0,0 +1,7 @@
++" Vim syntax file for the mutt ifdef patch
 +
-+	/* remove (new,cur,...) from folder path */
-+	p = strrchr(folder, '/');
-+	if (p)
-+		*p = '\0';
++syntax keyword muttrcCommand    ifdef
++syntax keyword muttrcCommand    ifndef
++syntax keyword muttrcCommand    finish
 +
-+	/* remove old flags from filename */
-+	if ((p = strchr(filename, ':')))
-+		*p = '\0';
++" vim: syntax=vim
+diff --git a/doc/vimrc.index-color b/doc/vimrc.index-color
+new file mode 100644
+index 0000000..8de9c67
+--- /dev/null
++++ b/doc/vimrc.index-color
+@@ -0,0 +1,13 @@
++" Vim syntax file for the mutt index-color patch
 +
-+	/* compose new flags */
-+	maildir_flags(suffix, sizeof(suffix), h);
++syntax keyword muttrcColorField contained index
++syntax keyword muttrcColorField contained index_author
++syntax keyword muttrcColorField contained index_collapsed
++syntax keyword muttrcColorField contained index_date
++syntax keyword muttrcColorField contained index_flags
++syntax keyword muttrcColorField contained index_label
++syntax keyword muttrcColorField contained index_number
++syntax keyword muttrcColorField contained index_size
++syntax keyword muttrcColorField contained index_subject
 +
-+	snprintf(newpath, newsz, "%s/%s/%s%s",
-+			folder,
-+			(h->read || h->old) ? "cur" : "new",
-+			filename,
-+			suffix);
++" vim: syntax=vim
+diff --git a/doc/vimrc.keywords b/doc/vimrc.keywords
+new file mode 100644
+index 0000000..e217ed3
+--- /dev/null
++++ b/doc/vimrc.keywords
+@@ -0,0 +1,10 @@
++" Vim syntax file for the mutt keywords patch
 +
-+	if (strcmp(old, newpath) == 0)
-+		return 1;
++syntax keyword muttrcVarBool    contained skipwhite keywords_legacy       nextgroup=muttrcSetBoolAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
++syntax keyword muttrcVarBool    contained skipwhite keywords_standard     nextgroup=muttrcSetBoolAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
 +
-+	if (rename(old, newpath) != 0) {
-+		dprint(1, (debugfile, "nm: rename(2) failed %s -> %s\n", old, newpath));
-+		return -1;
-+	}
++syntax keyword muttrcVarStr     contained skipwhite xlabel_delimiter      nextgroup=muttrcVarEqualsIdxFmt
 +
-+	return 0;
-+}
++syntax match muttrcFunction     contained "\<edit-label\>"
 +
-+static int remove_filename(struct nm_ctxdata *data, const char *path)
-+{
-+	notmuch_status_t st;
-+	notmuch_filenames_t *ls;
-+	notmuch_message_t *msg = NULL;
-+	notmuch_database_t *db = get_db(data, TRUE);
-+	int trans;
++" vim: syntax=vim
+diff --git a/doc/vimrc.new-mail b/doc/vimrc.new-mail
+new file mode 100644
+index 0000000..0d58075
+--- /dev/null
++++ b/doc/vimrc.new-mail
+@@ -0,0 +1,5 @@
++" Vim syntax file for the mutt new-mail patch
 +
-+	dprint(2, (debugfile, "nm: remove filename '%s'\n", path));
++syntax keyword muttrcVarStr     contained skipwhite new_mail_command         nextgroup=muttrcVarEqualsIdxFmt
 +
-+	if (!db)
-+		return -1;
-+	st = notmuch_database_find_message_by_filename(db, path, &msg);
-+	if (st || !msg)
-+		return -1;
-+	trans = db_trans_begin(data);
-+	if (trans < 0)
-+		return -1;
++" vim: syntax=vim
+diff --git a/doc/vimrc.nntp b/doc/vimrc.nntp
+new file mode 100644
+index 0000000..58a5d38
+--- /dev/null
++++ b/doc/vimrc.nntp
+@@ -0,0 +1,50 @@
++" Vim syntax file for the mutt nntp patch
 +
-+	/*
-+	 * note that unlink() is probably unnecessary here, it's already removed
-+	 * by mh_sync_mailbox_message(), but for sure...
-+	 */
-+	st = notmuch_database_remove_message(db, path);
-+	switch (st) {
-+	case NOTMUCH_STATUS_SUCCESS:
-+		dprint(2, (debugfile, "nm: remove success, call unlink\n"));
-+		unlink(path);
-+		break;
-+	case NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID:
-+		dprint(2, (debugfile, "nm: remove success (duplicate), call unlink\n"));
-+		unlink(path);
-+		for (ls = notmuch_message_get_filenames(msg);
-+		     ls && notmuch_filenames_valid(ls);
-+		     notmuch_filenames_move_to_next(ls)) {
++syntax keyword muttrcVarBool    contained skipwhite ask_follow_up         nextgroup=muttrcSetBoolAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
++syntax keyword muttrcVarBool    contained skipwhite ask_x_comment_to      nextgroup=muttrcSetBoolAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
++syntax keyword muttrcVarBool    contained skipwhite mime_subject          nextgroup=muttrcSetBoolAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
++syntax keyword muttrcVarBool    contained skipwhite nntp_listgroup        nextgroup=muttrcSetBoolAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
++syntax keyword muttrcVarBool    contained skipwhite nntp_load_description nextgroup=muttrcSetBoolAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
++syntax keyword muttrcVarBool    contained skipwhite save_unsubscribed     nextgroup=muttrcSetBoolAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
++syntax keyword muttrcVarBool    contained skipwhite show_new_news         nextgroup=muttrcSetBoolAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
++syntax keyword muttrcVarBool    contained skipwhite show_only_unread      nextgroup=muttrcSetBoolAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
++syntax keyword muttrcVarBool    contained skipwhite x_comment_to          nextgroup=muttrcSetBoolAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
 +
-+			path = notmuch_filenames_get(ls);
++syntax keyword muttrcVarNum     contained skipwhite nntp_context          nextgroup=muttrcSetNumAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
++syntax keyword muttrcVarNum     contained skipwhite nntp_poll             nextgroup=muttrcSetNumAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
 +
-+			dprint(2, (debugfile, "nm: remove duplicate: '%s'\n", path));
-+			unlink(path);
-+			notmuch_database_remove_message(db, path);
-+		}
-+		break;
-+	default:
-+		dprint(1, (debugfile, "nm: failed to remove '%s' [st=%d]\n", path, (int) st));
-+		break;
-+	}
++syn keyword muttrcVarQuad	contained skipwhite catchup_newsgroup     nextgroup=muttrcSetQuadAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
++syn keyword muttrcVarQuad	contained skipwhite followup_to_poster    nextgroup=muttrcSetQuadAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
++syn keyword muttrcVarQuad	contained skipwhite post_moderated        nextgroup=muttrcSetQuadAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
 +
-+	notmuch_message_destroy(msg);
-+	if (trans)
-+		db_trans_end(data);
-+	return 0;
-+}
++syntax keyword muttrcVarStr     contained skipwhite group_index_format    nextgroup=muttrcVarEqualsIdxFmt
++syntax keyword muttrcVarStr     contained skipwhite inews                 nextgroup=muttrcVarEqualsIdxFmt
++syntax keyword muttrcVarStr     contained skipwhite newsgroups_charset    nextgroup=muttrcVarEqualsIdxFmt
++syntax keyword muttrcVarStr     contained skipwhite newsrc                nextgroup=muttrcVarEqualsIdxFmt
++syntax keyword muttrcVarStr     contained skipwhite news_cache_dir        nextgroup=muttrcVarEqualsIdxFmt
++syntax keyword muttrcVarStr     contained skipwhite news_server           nextgroup=muttrcVarEqualsIdxFmt
++syntax keyword muttrcVarStr     contained skipwhite nntp_authenticators   nextgroup=muttrcVarEqualsIdxFmt
++syntax keyword muttrcVarStr     contained skipwhite nntp_pass             nextgroup=muttrcVarEqualsIdxFmt
++syntax keyword muttrcVarStr     contained skipwhite nntp_user             nextgroup=muttrcVarEqualsIdxFmt
 +
-+static int rename_filename(struct nm_ctxdata *data,
-+			const char *old, const char *new, HEADER *h)
-+{
-+	int rc = -1;
-+	notmuch_status_t st;
-+	notmuch_filenames_t *ls;
-+	notmuch_message_t *msg;
-+	notmuch_database_t *db = get_db(data, TRUE);
-+	int trans;
++syntax match muttrcFunction     contained "\<attach-news-message>"
++syntax match muttrcFunction     contained "\<catchup>"
++syntax match muttrcFunction     contained "\<change-newsgroup-readonly>"
++syntax match muttrcFunction     contained "\<change-newsgroup>"
++syntax match muttrcFunction     contained "\<edit-followup-to>"
++syntax match muttrcFunction     contained "\<edit-newsgroups>"
++syntax match muttrcFunction     contained "\<edit-x-comment-to>"
++syntax match muttrcFunction     contained "\<followup-message>"
++syntax match muttrcFunction     contained "\<forward-to-group>"
++syntax match muttrcFunction     contained "\<get-children>"
++syntax match muttrcFunction     contained "\<get-message>"
++syntax match muttrcFunction     contained "\<get-parent>"
++syntax match muttrcFunction     contained "\<post-message>"
++syntax match muttrcFunction     contained "\<reconstruct-thread>"
++syntax match muttrcFunction     contained "\<reload-active>"
++syntax match muttrcFunction     contained "\<subscribe-pattern>"
++syntax match muttrcFunction     contained "\<toggle-read>"
++syntax match muttrcFunction     contained "\<uncatchup>"
++syntax match muttrcFunction     contained "\<unsubscribe-pattern>"
 +
-+	if (!db || !new || !old || access(new, F_OK) != 0)
-+		return -1;
++" vim: syntax=vim
+diff --git a/doc/vimrc.notmuch b/doc/vimrc.notmuch
+new file mode 100644
+index 0000000..918d23d
+--- /dev/null
++++ b/doc/vimrc.notmuch
+@@ -0,0 +1,28 @@
++" Vim syntax file for the mutt notmuch patch
++
++syntax keyword muttrcVarBool    contained skipwhite nm_record             nextgroup=muttrcSetBoolAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
++syntax keyword muttrcVarBool    contained skipwhite virtual_spoolfile     nextgroup=muttrcSetBoolAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
++
++syntax keyword muttrcVarNum     contained skipwhite nm_db_limit           nextgroup=muttrcSetNumAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
++syntax keyword muttrcVarNum     contained skipwhite nm_open_timeout       nextgroup=muttrcSetNumAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
++
++syntax keyword muttrcVarStr     contained skipwhite nm_default_uri        nextgroup=muttrcVarEqualsIdxFmt
++syntax keyword muttrcVarStr     contained skipwhite nm_exclude_tags       nextgroup=muttrcVarEqualsIdxFmt
++syntax keyword muttrcVarStr     contained skipwhite nm_hidden_tags        nextgroup=muttrcVarEqualsIdxFmt
++syntax keyword muttrcVarStr     contained skipwhite nm_query_type         nextgroup=muttrcVarEqualsIdxFmt
++syntax keyword muttrcVarStr     contained skipwhite nm_record_tags        nextgroup=muttrcVarEqualsIdxFmt
++syntax keyword muttrcVarStr     contained skipwhite nm_unread_tag         nextgroup=muttrcVarEqualsIdxFmt
++syntax keyword muttrcVarStr     contained skipwhite vfolder_format        nextgroup=muttrcVarEqualsIdxFmt
++
++syntax keyword muttrcCommand    virtual-mailboxes
++syntax keyword muttrcCommand    tag-transforms
++syntax keyword muttrcCommand    tag-formats
++
++syntax match muttrcFunction     contained "<change-vfolder>"
++syntax match muttrcFunction     contained "<entire-thread>"
++syntax match muttrcFunction     contained "<modify-labels-then-hide>"
++syntax match muttrcFunction     contained "<modify-labels>"
++syntax match muttrcFunction     contained "<sidebar-toggle>"
++syntax match muttrcFunction     contained "<vfolder-from-query>"
 +
-+	dprint(1, (debugfile, "nm: rename filename, %s -> %s\n", old, new));
-+	trans = db_trans_begin(data);
-+	if (trans < 0)
-+		return -1;
++" vim: syntax=vim
+diff --git a/doc/vimrc.progress b/doc/vimrc.progress
+new file mode 100644
+index 0000000..a632dc0
+--- /dev/null
++++ b/doc/vimrc.progress
+@@ -0,0 +1,5 @@
++" Vim syntax file for the mutt progress patch
 +
-+	dprint(2, (debugfile, "nm: rename: add '%s'\n", new));
-+	st = notmuch_database_add_message(db, new, &msg);
++syntax keyword muttrcColorField contained progress
 +
-+	if (st != NOTMUCH_STATUS_SUCCESS &&
-+	    st != NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID) {
-+		dprint(1, (debugfile, "nm: failed to add '%s' [st=%d]\n", new, (int) st));
-+		goto done;
-+	}
++" vim: syntax=vim
+diff --git a/doc/vimrc.quasi-delete b/doc/vimrc.quasi-delete
+new file mode 100644
+index 0000000..f8a69e7
+--- /dev/null
++++ b/doc/vimrc.quasi-delete
+@@ -0,0 +1,5 @@
++" Vim syntax file for the mutt quasi-delete patch
 +
-+	dprint(2, (debugfile, "nm: rename: rem '%s'\n", old));
-+	st = notmuch_database_remove_message(db, old);
-+	switch (st) {
-+	case NOTMUCH_STATUS_SUCCESS:
-+		break;
-+	case NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID:
-+		dprint(2, (debugfile, "nm: rename: syncing duplicate filename\n"));
-+		notmuch_message_destroy(msg);
-+		msg = NULL;
-+		notmuch_database_find_message_by_filename(db, new, &msg);
++syntax match muttrcFunction     contained "\<quasi-delete\>"
 +
-+		for (ls = notmuch_message_get_filenames(msg);
-+		     msg && ls && notmuch_filenames_valid(ls);
-+		     notmuch_filenames_move_to_next(ls)) {
++" vim: syntax=vim
+diff --git a/doc/vimrc.sidebar b/doc/vimrc.sidebar
+new file mode 100644
+index 0000000..ac1efc4
+--- /dev/null
++++ b/doc/vimrc.sidebar
+@@ -0,0 +1,34 @@
++" Vim syntax file for the mutt sidebar patch
 +
-+			const char *path = notmuch_filenames_get(ls);
-+			char newpath[_POSIX_PATH_MAX];
++syntax keyword muttrcVarBool    contained skipwhite sidebar_folder_indent nextgroup=muttrcSetBoolAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
++syntax keyword muttrcVarBool    contained skipwhite sidebar_new_mail_only nextgroup=muttrcSetBoolAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
++syntax keyword muttrcVarBool    contained skipwhite sidebar_next_new_wrap nextgroup=muttrcSetBoolAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
++syntax keyword muttrcVarBool    contained skipwhite sidebar_short_path    nextgroup=muttrcSetBoolAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
++syntax keyword muttrcVarBool    contained skipwhite sidebar_visible       nextgroup=muttrcSetBoolAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
 +
-+			if (strcmp(new, path) == 0)
-+				continue;
++syntax keyword muttrcVarNum     contained skipwhite sidebar_width         nextgroup=muttrcSetNumAssignment,muttrcVPrefix,muttrcVarBool,muttrcVarQuad,muttrcVarNum,muttrcVarStr
 +
-+			dprint(2, (debugfile, "nm: rename: syncing duplicate: %s\n", path));
++syntax keyword muttrcVarStr     contained skipwhite sidebar_divider_char  nextgroup=muttrcVarEqualsIdxFmt
++syntax keyword muttrcVarStr     contained skipwhite sidebar_delim_chars   nextgroup=muttrcVarEqualsIdxFmt
++syntax keyword muttrcVarStr     contained skipwhite sidebar_format        nextgroup=muttrcVarEqualsIdxFmt
++syntax keyword muttrcVarStr     contained skipwhite sidebar_indent_string nextgroup=muttrcVarEqualsIdxFmt
++syntax keyword muttrcVarStr     contained skipwhite sidebar_sort_method   nextgroup=muttrcVarEqualsIdxFmt
 +
-+			if (rename_maildir_filename(path, newpath, sizeof(newpath), h) == 0) {
-+				dprint(2, (debugfile, "nm: rename dup %s -> %s\n", path, newpath));
-+				notmuch_database_remove_message(db, path);
-+				notmuch_database_add_message(db, newpath, NULL);
-+			}
-+		}
-+		notmuch_message_destroy(msg);
-+		msg = NULL;
-+		notmuch_database_find_message_by_filename(db, new, &msg);
-+		st = NOTMUCH_STATUS_SUCCESS;
-+		break;
-+	default:
-+		dprint(1, (debugfile, "nm: failed to remove '%s' [st=%d]\n",
-+					old, (int) st));
-+		break;
-+	}
++syntax keyword muttrcCommand    sidebar_whitelist
 +
-+	if (st == NOTMUCH_STATUS_SUCCESS && h && msg) {
-+		notmuch_message_maildir_flags_to_tags(msg);
-+		update_header_tags(h, msg);
-+		update_tags(msg, nm_header_get_tags(h));
-+	}
++syntax match muttrcFunction     contained "\<sidebar-next\>"
++syntax match muttrcFunction     contained "\<sidebar-next-new\>"
++syntax match muttrcFunction     contained "\<sidebar-open\>"
++syntax match muttrcFunction     contained "\<sidebar-page-down\>"
++syntax match muttrcFunction     contained "\<sidebar-page-up\>"
++syntax match muttrcFunction     contained "\<sidebar-prev\>"
++syntax match muttrcFunction     contained "\<sidebar-prev-new\>"
++syntax match muttrcFunction     contained "\<sidebar-toggle-visible\>"
 +
-+	rc = 0;
-+done:
-+	if (msg)
-+		notmuch_message_destroy(msg);
-+	if (trans)
-+		db_trans_end(data);
-+	return rc;
-+}
++syntax keyword muttrcColorField contained sidebar_divider
++syntax keyword muttrcColorField contained sidebar_flagged
++syntax keyword muttrcColorField contained sidebar_highlight
++syntax keyword muttrcColorField contained sidebar_indicator
++syntax keyword muttrcColorField contained sidebar_new
 +
-+int nm_update_filename(CONTEXT *ctx, const char *old, const char *new, HEADER *h)
-+{
-+	char buf[PATH_MAX];
-+	int rc;
-+	struct nm_ctxdata *data = get_ctxdata(ctx);
++" vim: syntax=vim
+diff --git a/doc/vimrc.smime-encrypt-self b/doc/vimrc.smime-encrypt-self
+new file mode 100644
+index 0000000..7fe9357
+--- /dev/null
++++ b/doc/vimrc.smime-encrypt-self
+@@ -0,0 +1,5 @@
++" Vim syntax file for the mutt smime-encrypt-self patch
 +
-+	if (!data || !new)
-+		return -1;
++syntax keyword muttrcVarQuad    contained skipwhite muttrcVarQuad
 +
-+	if (!old && h && h->data) {
-+		nm_header_get_fullpath(h, buf, sizeof(buf));
-+		old = buf;
-+	}
++" vim: syntax=vim
+diff --git a/doc/vimrc.trash b/doc/vimrc.trash
+new file mode 100644
+index 0000000..73b3137
+--- /dev/null
++++ b/doc/vimrc.trash
+@@ -0,0 +1,7 @@
++" Vim syntax file for the mutt trash patch
 +
-+	rc = rename_filename(data, old, new, h);
++syntax keyword muttrcVarStr     contained skipwhite trash                 nextgroup=muttrcVarEqualsIdxFmt
 +
-+	if (!is_longrun(data))
-+		release_db(data);
-+	ctx->mtime = time(NULL);
-+	return rc;
-+}
++syntax match muttrcFunction     contained "\<purge-message\>"
++
++" vim: syntax=vim
+diff --git a/enter.c b/enter.c
+index 23610ae..851d12b 100644
+--- a/enter.c
++++ b/enter.c
+@@ -565,6 +565,49 @@ int _mutt_enter_string (char *buf, size_t buflen, int y, int x,
+ 	    }
+ 	    break;
+ 	  }
++	  else if (flags & M_LABEL && ch == OP_EDITOR_COMPLETE)
++	  {
++	    for (i = state->curpos; i && state->wbuf[i-1] != ',' && 
++		 state->wbuf[i-1] != ':'; i--)
++	      ;
++	    for (; i < state->lastchar && state->wbuf[i] == ' '; i++)
++	      ;
++	    my_wcstombs (buf, buflen, state->wbuf + i, state->curpos - i);
++	    r = mutt_label_complete (buf, buflen, i, state->tabs);
++	    replace_part (state, i, buf);
++	    if (!r)
++	    {
++	      rv = 1;
++	      goto bye;
++	    }
++	    break;
++	  }
++	  else if (flags & M_PATTERN && ch == OP_EDITOR_COMPLETE)
++	  {
++        char *p;
++	    for (i = state->curpos; i && state->wbuf[i-1] != ',' && 
++		 state->wbuf[i-1] != ':'; i--)
++	      ;
++	    for (; i < state->lastchar && state->wbuf[i] == ' '; i++)
++	      ;
++	    my_wcstombs (buf, buflen, state->wbuf + i, state->curpos - i);
++        p = &buf[i];
++        while (p > buf && *(p-1) != '~')
++          p--;
++        if (*p == '~' && *(p+1) == 'y')
++        {
++	      r = mutt_label_complete (buf, buflen, i, state->tabs);
++	      replace_part (state, i, buf);
++	      if (!r)
++	      {
++	        rv = 1;
++	        goto bye;
++	      }
++        }
++        else
++          goto self_insert;
++	    break;
++	  }
+ 	  else if (flags & M_ALIAS && ch == OP_EDITOR_COMPLETE_QUERY)
+ 	  {
+ 	    /* invoke the query-menu to get more addresses */
+@@ -630,6 +673,27 @@ int _mutt_enter_string (char *buf, size_t buflen, int y, int x,
+ 	      BEEP (); /* let the user know that nothing matched */
+ 	    replace_part (state, 0, buf);
+ 	  }
++#if USE_NOTMUCH
++	  else if (flags & M_NM_QUERY)
++	  {
++	    my_wcstombs (buf, buflen, state->wbuf, state->curpos);
++	    i = strlen (buf);
++	    if (!mutt_nm_query_complete(buf, buflen, i, state->tabs))
++	      BEEP ();
 +
-+int nm_sync(CONTEXT *ctx, int *index_hint)
-+{
-+	struct nm_ctxdata *data = get_ctxdata(ctx);
-+	int i, rc = 0;
-+	char msgbuf[STRING];
-+	progress_t progress;
-+	char *uri = ctx->path;
-+	int changed = 0;
++	    replace_part (state, 0, buf);
++	  }
++	  else if (flags & M_NM_TAG)
++	  {
++	    my_wcstombs (buf, buflen, state->wbuf, state->curpos);
++	    i = strlen (buf);
++	    if (!mutt_nm_tag_complete(buf, buflen, i, state->tabs))
++	      BEEP ();
 +
-+	if (!data)
-+		return -1;
++	    replace_part (state, 0, buf);
++	  }
 +
-+	dprint(1, (debugfile, "nm: sync start ...\n"));
++#endif
+ 	  else
+ 	    goto self_insert;
+ 	  break;
+@@ -677,12 +741,6 @@ self_insert:
+       /* use the raw keypress */
+       ch = LastKey;
+ 
+-#ifdef KEY_ENTER
+-      /* treat ENTER the same as RETURN */
+-      if (ch == KEY_ENTER)
+-	ch = '\r';
+-#endif
+-
+       /* quietly ignore all other function keys */
+       if (ch & ~0xff)
+ 	continue;
+diff --git a/filter.c b/filter.c
+index 91a4d75..a8dc2f5 100644
+--- a/filter.c
++++ b/filter.c
+@@ -21,6 +21,7 @@
+ #endif
+ 
+ #include "mutt.h"
++#include "mutt_curses.h"
+ 
+ #include <unistd.h>
+ #include <stdlib.h>
+@@ -34,6 +35,7 @@ mutt_create_filter_fd (const char *cmd, FILE **in, FILE **out, FILE **err,
+ 		       int fdin, int fdout, int fderr)
+ {
+   int pin[2], pout[2], perr[2], thepid;
++  char columns[11];
+ 
+   if (in)
+   {
+@@ -117,6 +119,9 @@ mutt_create_filter_fd (const char *cmd, FILE **in, FILE **out, FILE **err,
+       close (fderr);
+     }
+ 
++    snprintf (columns, sizeof (columns), "%d", COLS - SidebarWidth);
++    setenv ("COLUMNS", columns, 1);
 +
-+	if (!ctx->quiet) {
-+		/* all is in this function so we don't use data->progress here */
-+		snprintf(msgbuf, sizeof (msgbuf), _("Writing %s..."), ctx->path);
-+		mutt_progress_init(&progress, msgbuf, M_PROGRESS_MSG,
-+				   WriteInc, ctx->msgcount);
-+	}
+     execl (EXECSHELL, "sh", "-c", cmd, NULL);
+     _exit (127);
+   }
+diff --git a/flags.c b/flags.c
+index f0f3d81..1354bb7 100644
+--- a/flags.c
++++ b/flags.c
+@@ -65,7 +65,13 @@ void _mutt_set_flag (CONTEXT *ctx, HEADER *h, int flag, int bf, int upd_ctx)
+       {
+ 	h->deleted = 0;
+         update = 1;
+-	if (upd_ctx) ctx->deleted--;
++        if (upd_ctx) {
++          ctx->deleted--;
++          if (h->appended) {
++            ctx->appended--;
++	  }
++        }
++        h->appended = 0; /* when undeleting, also reset the appended flag */
+ #ifdef USE_IMAP
+         /* see my comment above */
+ 	if (ctx->magic == M_IMAP) 
+@@ -87,6 +93,27 @@ void _mutt_set_flag (CONTEXT *ctx, HEADER *h, int flag, int bf, int upd_ctx)
+       }
+       break;
+ 
++    case M_APPENDED:
++      if (bf) {
++        if (!h->appended) {
++          h->appended = 1;
++          if (upd_ctx) {
++            ctx->appended++;
++          }
++        }
++      }
++      break;
 +
-+	for (i = 0; i < ctx->msgcount; i++) {
-+		char old[_POSIX_PATH_MAX], new[_POSIX_PATH_MAX];
-+		HEADER *h = ctx->hdrs[i];
-+		struct nm_hdrdata *hd = h->data;
++    case M_PURGED:
++      if (bf) {
++        if (!h->purged) {
++          h->purged = 1;
++        }
++      } else if (h->purged) {
++        h->purged = 0;
++      }
++      break;
 +
-+		if (!ctx->quiet)
-+			mutt_progress_update(&progress, i, -1);
+     case M_NEW:
+ 
+       if (!mutt_bit_isset(ctx->rights,M_ACL_SEEN))
+@@ -255,7 +282,12 @@ void _mutt_set_flag (CONTEXT *ctx, HEADER *h, int flag, int bf, int upd_ctx)
+   }
+ 
+   if (update)
++  {
+     mutt_set_header_color(ctx, h);
++#ifdef USE_SIDEBAR
++    SidebarNeedsRedraw = 1;
++#endif
++  }
+ 
+   /* if the message status has changed, we need to invalidate the cached
+    * search results so that any future search will match the current status
+diff --git a/functions.h b/functions.h
+index 7a1c5a9..347bcde 100644
+--- a/functions.h
++++ b/functions.h
+@@ -22,9 +22,6 @@
+  *
+  * Notes:
+  *
+- * - If you want to bind \n or \r, use M_ENTER_S so that it will work
+- * correctly under both ncurses and S-Lang
+- *
+  * - If you need to bind a control char, use the octal value because the \cX
+  * construct does not work at this level.
+  *
+@@ -70,7 +67,8 @@ const struct binding_t OpGeneric[] = { /* map: generic */
+   { "tag-prefix-cond",	OP_TAG_PREFIX_COND,	NULL },
+   { "end-cond",		OP_END_COND,		NULL },
+   { "shell-escape",	OP_SHELL_ESCAPE,	"!" },
+-  { "select-entry",	OP_GENERIC_SELECT_ENTRY,M_ENTER_S },
++  { "select-entry",	OP_GENERIC_SELECT_ENTRY,"\n" },
++  { "select-entry",	OP_GENERIC_SELECT_ENTRY,"\r" },
+   { "search",		OP_SEARCH,		"/" },
+   { "search-reverse",	OP_SEARCH_REVERSE,	"\033/" },
+   { "search-opposite",	OP_SEARCH_OPPOSITE,	NULL },
+@@ -88,6 +86,10 @@ const struct binding_t OpMain[] = { /* map: index */
+   { "break-thread",		OP_MAIN_BREAK_THREAD,		"#" },
+   { "change-folder",		OP_MAIN_CHANGE_FOLDER,		"c" },
+   { "change-folder-readonly",	OP_MAIN_CHANGE_FOLDER_READONLY,	"\033c" },
++#ifdef USE_NNTP
++  { "change-newsgroup",		OP_MAIN_CHANGE_GROUP,		"i" },
++  { "change-newsgroup-readonly",OP_MAIN_CHANGE_GROUP_READONLY,	"\033i" },
++#endif
+   { "next-unread-mailbox",	OP_MAIN_NEXT_UNREAD_MAILBOX,    NULL },
+   { "collapse-thread",		OP_MAIN_COLLAPSE_THREAD,	"\033v" },
+   { "collapse-all",		OP_MAIN_COLLAPSE_ALL,		"\033V" },
+@@ -99,9 +101,18 @@ const struct binding_t OpMain[] = { /* map: index */
+   { "delete-thread",		OP_DELETE_THREAD,		"\004" },
+   { "delete-subthread",		OP_DELETE_SUBTHREAD,		"\033d" },
+   { "edit",			OP_EDIT_MESSAGE,		"e" },
++  { "edit-label",		OP_EDIT_LABEL,			"y" },
+   { "edit-type",		OP_EDIT_TYPE,			"\005" },
+   { "forward-message",		OP_FORWARD_MESSAGE,		"f" },
+-  { "flag-message",		OP_FLAG_MESSAGE,		"F" },
++#ifdef USE_NNTP
++  { "forward-to-group",		OP_FORWARD_TO_GROUP,		"\033F" },
++  { "followup-message",		OP_FOLLOWUP,			"F" },
++  { "get-children",		OP_GET_CHILDREN,		NULL },
++  { "get-message",		OP_GET_MESSAGE,			"\007" },
++  { "get-parent",		OP_GET_PARENT,			"\033G" },
++  { "reconstruct-thread",	OP_RECONSTRUCT_THREAD,		NULL },
++#endif
++  { "flag-message",		OP_FLAG_MESSAGE,		"\033f" },
+   { "group-reply",		OP_GROUP_REPLY,			"g" },
+ #ifdef USE_POP
+   { "fetch-mail",		OP_MAIN_FETCH_MAIL,		"G" },
+@@ -114,6 +125,7 @@ const struct binding_t OpMain[] = { /* map: index */
+   { "next-undeleted",		OP_MAIN_NEXT_UNDELETED,		"j" },
+   { "previous-undeleted",	OP_MAIN_PREV_UNDELETED,		"k" },
+   { "limit",			OP_MAIN_LIMIT,			"l" },
++  { "limit-current-thread",	OP_LIMIT_CURRENT_THREAD,	"\033L" },
+   { "link-threads",		OP_MAIN_LINK_THREADS,		"&" },
+   { "list-reply",		OP_LIST_REPLY,			"L" },
+   { "mail",			OP_MAIL,			"m" },
+@@ -121,6 +133,7 @@ const struct binding_t OpMain[] = { /* map: index */
+   { "toggle-write",		OP_TOGGLE_WRITE,		"%" },
+   { "next-thread",		OP_MAIN_NEXT_THREAD,		"\016" },
+   { "next-subthread",		OP_MAIN_NEXT_SUBTHREAD,		"\033n" },
++  { "purge-message",		OP_PURGE_MESSAGE,		NULL },
+   { "query",			OP_QUERY,			"Q" },
+   { "quit",			OP_QUIT,			"q" },
+   { "reply",			OP_REPLY,			"r" },
+@@ -128,6 +141,9 @@ const struct binding_t OpMain[] = { /* map: index */
+   { "sort-mailbox",		OP_SORT,			"o" },
+   { "sort-reverse",		OP_SORT_REVERSE,		"O" },
+   { "print-message",		OP_PRINT,			"p" },
++#ifdef USE_NNTP
++  { "post-message",		OP_POST,			"P" },
++#endif
+   { "previous-thread",		OP_MAIN_PREV_THREAD,		"\020" },
+   { "previous-subthread",	OP_MAIN_PREV_SUBTHREAD,		"\033p" },
+   { "recall-message",		OP_RECALL_MESSAGE,		"R" },
+@@ -147,7 +163,12 @@ const struct binding_t OpMain[] = { /* map: index */
+   { "show-version",		OP_VERSION,			"V" },
+   { "set-flag",			OP_MAIN_SET_FLAG,		"w" },
+   { "clear-flag",		OP_MAIN_CLEAR_FLAG,		"W" },
+-  { "display-message",		OP_DISPLAY_MESSAGE,		M_ENTER_S },
++  { "toggle-read",		OP_TOGGLE_READ,			"X" },
++#ifdef USE_NNTP
++  { "catchup",			OP_CATCHUP,			"y" },
++#endif
++  { "display-message",		OP_DISPLAY_MESSAGE,		"\n" },
++  { "display-message",		OP_DISPLAY_MESSAGE,		"\r" },
+   { "buffy-list",		OP_BUFFY_LIST,			"." },
+   { "sync-mailbox",		OP_MAIN_SYNC_FOLDER,		"$" },
+   { "display-address",		OP_DISPLAY_ADDRESS,		"@" },
+@@ -158,7 +179,7 @@ const struct binding_t OpMain[] = { /* map: index */
+   { "previous-new-then-unread",	OP_MAIN_PREV_NEW_THEN_UNREAD,	"\033\t" },
+   { "next-unread",		OP_MAIN_NEXT_UNREAD,		NULL },
+   { "previous-unread",		OP_MAIN_PREV_UNREAD,		NULL },
+-  { "parent-message",		OP_MAIN_PARENT_MESSAGE,		"P" },
++  { "parent-message",		OP_MAIN_PARENT_MESSAGE,		NULL },
+ 
+ 
+   { "extract-keys",		OP_EXTRACT_KEYS,		"\013" },
+@@ -167,8 +188,27 @@ const struct binding_t OpMain[] = { /* map: index */
+   { "mail-key",			OP_MAIL_KEY,			"\033k" },
+   { "decrypt-copy",		OP_DECRYPT_COPY,		NULL },
+   { "decrypt-save",		OP_DECRYPT_SAVE,		NULL },
++  { "quasi-delete",		OP_MAIN_QUASI_DELETE,		NULL },
 +
-+		*old = *new = '\0';
++#ifdef USE_SIDEBAR
++  { "sidebar-next",		OP_SIDEBAR_NEXT,		NULL },
++  { "sidebar-next-new",		OP_SIDEBAR_NEXT_NEW,		NULL },
++  { "sidebar-open",		OP_SIDEBAR_OPEN,		NULL },
++  { "sidebar-page-down",	OP_SIDEBAR_PAGE_DOWN,		NULL },
++  { "sidebar-page-up",		OP_SIDEBAR_PAGE_UP,		NULL },
++  { "sidebar-prev",		OP_SIDEBAR_PREV,		NULL },
++  { "sidebar-prev-new",		OP_SIDEBAR_PREV_NEW,		NULL },
++  { "sidebar-toggle-virtual",	OP_SIDEBAR_TOGGLE_VIRTUAL,	NULL },
++  { "sidebar-toggle-visible",	OP_SIDEBAR_TOGGLE_VISIBLE,	NULL },
++#endif
+ 
+-
++#ifdef USE_NOTMUCH
++  { "change-vfolder",		OP_MAIN_CHANGE_VFOLDER,         "X" },
++  { "vfolder-from-query",	OP_MAIN_VFOLDER_FROM_QUERY,     "\033X" },
++  { "modify-labels",		OP_MAIN_MODIFY_LABELS,		"`" },
++  { "modify-labels-then-hide",	OP_MAIN_MODIFY_LABELS_THEN_HIDE, NULL },
++  { "entire-thread",		OP_MAIN_ENTIRE_THREAD,          "+" },
++#endif
+   { NULL,			0,				NULL }
+ };
+ 
+@@ -178,6 +218,10 @@ const struct binding_t OpPager[] = { /* map: pager */
+   { "bounce-message",	OP_BOUNCE_MESSAGE,		"b" },
+   { "change-folder",	OP_MAIN_CHANGE_FOLDER,		"c" },
+   { "change-folder-readonly",	OP_MAIN_CHANGE_FOLDER_READONLY,	"\033c" },
++#ifdef USE_NNTP
++  { "change-newsgroup",		OP_MAIN_CHANGE_GROUP,		"i" },
++  { "change-newsgroup-readonly",OP_MAIN_CHANGE_GROUP_READONLY,	"\033i" },
++#endif
+   { "next-unread-mailbox",	OP_MAIN_NEXT_UNREAD_MAILBOX, NULL },
+   { "copy-message",	OP_COPY_MESSAGE,		"C" },
+   { "decode-copy",	OP_DECODE_COPY,			"\033C" },
+@@ -187,9 +231,14 @@ const struct binding_t OpPager[] = { /* map: pager */
+   { "set-flag",  	OP_MAIN_SET_FLAG,		"w" },
+   { "clear-flag",       OP_MAIN_CLEAR_FLAG,		"W" },
+   { "edit",		OP_EDIT_MESSAGE,		"e" },
++  { "edit-label",	OP_EDIT_LABEL,			"y" },
+   { "edit-type",	OP_EDIT_TYPE,			"\005" },
++#ifdef USE_NNTP
++  { "followup-message",	OP_FOLLOWUP,			"F" },
++  { "forward-to-group",	OP_FORWARD_TO_GROUP,		"\033F" },
++#endif
+   { "forward-message",	OP_FORWARD_MESSAGE,		"f" },
+-  { "flag-message",	OP_FLAG_MESSAGE,		"F" },
++  { "flag-message",	OP_FLAG_MESSAGE,		"\033f" },
+   { "group-reply",	OP_GROUP_REPLY,			"g" },
+ #ifdef USE_IMAP
+   { "imap-fetch-mail",  OP_MAIN_IMAP_FETCH,		NULL },
+@@ -211,8 +260,12 @@ const struct binding_t OpPager[] = { /* map: pager */
+   { "sort-mailbox",	OP_SORT,			"o" },
+   { "sort-reverse",	OP_SORT_REVERSE,		"O" },
+   { "print-message",	OP_PRINT,			"p" },
++#ifdef USE_NNTP
++  { "post-message",	OP_POST,			"P" },
++#endif
+   { "previous-thread",	OP_MAIN_PREV_THREAD,		"\020" },
+   { "previous-subthread",OP_MAIN_PREV_SUBTHREAD,	"\033p" },
++  { "purge-message",	OP_PURGE_MESSAGE,		NULL },
+   { "quit",		OP_QUIT,			"Q" },
+   { "exit",		OP_EXIT,			"q" },
+   { "reply",		OP_REPLY,			"r" },
+@@ -247,7 +300,8 @@ const struct binding_t OpPager[] = { /* map: pager */
+   { "search",		OP_SEARCH,			"/" },
+   { "search-reverse",	OP_SEARCH_REVERSE,		"\033/" },
+   { "search-opposite",	OP_SEARCH_OPPOSITE,		NULL },
+-  { "next-line",	OP_NEXT_LINE,			M_ENTER_S },
++  { "next-line",	OP_NEXT_LINE,			"\n" },
++  { "next-line",	OP_NEXT_LINE,			"\r" },
+   { "jump",		OP_JUMP,			NULL },
+   { "next-unread",	OP_MAIN_NEXT_UNREAD,		NULL },
+   { "previous-new",	OP_MAIN_PREV_NEW,		NULL },
+@@ -258,7 +312,7 @@ const struct binding_t OpPager[] = { /* map: pager */
+   { "half-down",	OP_HALF_DOWN,			NULL },
+   { "previous-line",	OP_PREV_LINE,			NULL },
+   { "bottom",		OP_PAGER_BOTTOM,		NULL },
+-  { "parent-message",	OP_MAIN_PARENT_MESSAGE,		"P" },
++  { "parent-message",	OP_MAIN_PARENT_MESSAGE,		NULL },
+ 
+ 
+ 
+@@ -271,6 +325,27 @@ const struct binding_t OpPager[] = { /* map: pager */
+   { "decrypt-save",    	OP_DECRYPT_SAVE,		NULL },
+ 
+   { "what-key",		OP_WHAT_KEY,		NULL },
++  { "quasi-delete",	OP_MAIN_QUASI_DELETE,		NULL },
 +
-+		if (hd->oldpath) {
-+			strncpy(old, hd->oldpath, sizeof(old));
-+			old[sizeof(old) - 1] = '\0';
-+			dprint(2, (debugfile, "nm: fixing obsolete path '%s'\n", old));
-+		} else
-+			nm_header_get_fullpath(h, old, sizeof(old));
++#ifdef USE_SIDEBAR
++  { "sidebar-next",		OP_SIDEBAR_NEXT,		NULL },
++  { "sidebar-next-new",		OP_SIDEBAR_NEXT_NEW,		NULL },
++  { "sidebar-open",		OP_SIDEBAR_OPEN,		NULL },
++  { "sidebar-page-down",	OP_SIDEBAR_PAGE_DOWN,		NULL },
++  { "sidebar-page-up",		OP_SIDEBAR_PAGE_UP,		NULL },
++  { "sidebar-prev",		OP_SIDEBAR_PREV,		NULL },
++  { "sidebar-prev-new",		OP_SIDEBAR_PREV_NEW,		NULL },
++  { "sidebar-toggle-virtual",	OP_SIDEBAR_TOGGLE_VIRTUAL,	NULL },
++  { "sidebar-toggle-visible",	OP_SIDEBAR_TOGGLE_VISIBLE,	NULL },
++#endif
 +
-+		ctx->path = hd->folder;
-+		ctx->magic = hd->magic;
-+#if USE_HCACHE
-+		rc = mh_sync_mailbox_message(ctx, i, NULL);
-+#else
-+		rc = mh_sync_mailbox_message(ctx, i);
++#ifdef USE_NOTMUCH
++  { "change-vfolder",		OP_MAIN_CHANGE_VFOLDER,		"X" },
++  { "vfolder-from-query",	OP_MAIN_VFOLDER_FROM_QUERY,	"\033X" },
++  { "modify-labels",		OP_MAIN_MODIFY_LABELS,		"`" },
++  { "modify-labels-then-hide",	OP_MAIN_MODIFY_LABELS_THEN_HIDE, NULL },
++  { "entire-thread",		OP_MAIN_ENTIRE_THREAD,          "+" },
++#endif
+ 
+   { NULL,		0,				NULL }
+ };
+@@ -279,6 +354,10 @@ const struct binding_t OpAttach[] = { /* map: attachment */
+   { "bounce-message",	OP_BOUNCE_MESSAGE,		"b" },
+   { "display-toggle-weed",	OP_DISPLAY_HEADERS,	"h" },
+   { "edit-type",	OP_EDIT_TYPE,			"\005" },
++#ifdef USE_NNTP
++  { "followup-message",	OP_FOLLOWUP,			"F" },
++  { "forward-to-group",	OP_FORWARD_TO_GROUP,		"\033F" },
++#endif
+   { "print-entry",	OP_PRINT,			"p" },
+   { "save-entry",	OP_SAVE,			"s" },
+   { "pipe-entry",	OP_PIPE,			"|" },
+@@ -289,7 +368,8 @@ const struct binding_t OpAttach[] = { /* map: attachment */
+   { "list-reply",	OP_LIST_REPLY,			"L" },
+   { "forward-message",	OP_FORWARD_MESSAGE,		"f" },
+   { "view-text",	OP_ATTACH_VIEW_TEXT,		"T" },
+-  { "view-attach",	OP_VIEW_ATTACH,			M_ENTER_S },
++  { "view-attach",	OP_VIEW_ATTACH,			"\n" },
++  { "view-attach",	OP_VIEW_ATTACH,			"\r" },
+   { "delete-entry",	OP_DELETE,			"d" },
+   { "undelete-entry",	OP_UNDELETE,			"u" },
+   { "collapse-parts",	OP_ATTACH_COLLAPSE,		"v" },
+@@ -304,6 +384,7 @@ const struct binding_t OpAttach[] = { /* map: attachment */
+ const struct binding_t OpCompose[] = { /* map: compose */
+   { "attach-file",	OP_COMPOSE_ATTACH_FILE,		"a" },
+   { "attach-message",	OP_COMPOSE_ATTACH_MESSAGE,	"A" },
++  { "attach-news-message",OP_COMPOSE_ATTACH_NEWS_MESSAGE,"\033a" },
+   { "edit-bcc",		OP_COMPOSE_EDIT_BCC,		"b" },
+   { "edit-cc",		OP_COMPOSE_EDIT_CC,		"c" },
+   { "copy-file",	OP_SAVE,			"C" },
+@@ -323,6 +404,11 @@ const struct binding_t OpCompose[] = { /* map: compose */
+   { "print-entry",	OP_PRINT,			"l" },
+   { "edit-mime",	OP_COMPOSE_EDIT_MIME,		"m" },
+   { "new-mime",		OP_COMPOSE_NEW_MIME,		"n" },
++#ifdef USE_NNTP
++  { "edit-newsgroups",	OP_COMPOSE_EDIT_NEWSGROUPS,	"N" },
++  { "edit-followup-to",	OP_COMPOSE_EDIT_FOLLOWUP_TO,	"o" },
++  { "edit-x-comment-to",OP_COMPOSE_EDIT_X_COMMENT_TO,	"x" },
++#endif
+   { "postpone-message",	OP_COMPOSE_POSTPONE_MESSAGE,	"P" },
+   { "edit-reply-to",	OP_COMPOSE_EDIT_REPLY_TO,	"r" },
+   { "rename-file",	OP_COMPOSE_RENAME_FILE,		"R" },
+@@ -333,7 +419,8 @@ const struct binding_t OpCompose[] = { /* map: compose */
+   { "toggle-unlink",	OP_COMPOSE_TOGGLE_UNLINK,	"u" },
+   { "toggle-recode",    OP_COMPOSE_TOGGLE_RECODE,	NULL },
+   { "update-encoding",	OP_COMPOSE_UPDATE_ENCODING,	"U" },
+-  { "view-attach",	OP_VIEW_ATTACH,			M_ENTER_S },
++  { "view-attach",	OP_VIEW_ATTACH,			"\n" },
++  { "view-attach",	OP_VIEW_ATTACH,			"\r" },
+   { "send-message",	OP_COMPOSE_SEND_MESSAGE,	"y" },
+   { "pipe-entry",	OP_PIPE,			"|" },
+ 
+@@ -374,14 +461,25 @@ const struct binding_t OpBrowser[] = { /* map: browser */
+   { "select-new",	OP_BROWSER_NEW_FILE,	"N" },
+   { "check-new",	OP_CHECK_NEW,		NULL },
+   { "toggle-mailboxes", OP_TOGGLE_MAILBOXES, 	"\t" },
++#ifdef USE_NNTP
++  { "reload-active",	OP_LOAD_ACTIVE,		"g" },
++  { "subscribe-pattern", OP_SUBSCRIBE_PATTERN,	"S" },
++  { "unsubscribe-pattern", OP_UNSUBSCRIBE_PATTERN, "U" },
++  { "catchup",		OP_CATCHUP,		"y" },
++  { "uncatchup",	OP_UNCATCHUP,		"Y" },
++#endif
+   { "view-file",	OP_BROWSER_VIEW_FILE,	" " },
+   { "buffy-list",	OP_BUFFY_LIST,		"." },
+ #ifdef USE_IMAP
+   { "create-mailbox",   OP_CREATE_MAILBOX,      "C" },
+   { "delete-mailbox",   OP_DELETE_MAILBOX,      "d" },
+   { "rename-mailbox",   OP_RENAME_MAILBOX,      "r" },
++#endif
++#if defined USE_IMAP || defined USE_NNTP
+   { "subscribe",	OP_BROWSER_SUBSCRIBE,	"s" },
+   { "unsubscribe",	OP_BROWSER_UNSUBSCRIBE,	"u" },
++#endif
++#ifdef USE_IMAP
+   { "toggle-subscribed", OP_BROWSER_TOGGLE_LSUB, "T" },
+ #endif
+   { NULL,		0,			NULL }
+@@ -446,7 +544,8 @@ const struct binding_t OpSmime[] = { /* map: smime */
+ 
+ #ifdef MIXMASTER
+ const struct binding_t OpMix[] = { /* map: mixmaster */
+-  { "accept",		OP_MIX_USE,	M_ENTER_S },
++  { "accept",		OP_MIX_USE,	"\n" },
++  { "accept",		OP_MIX_USE,	"\r" },
+   { "append",		OP_MIX_APPEND,	"a"       },
+   { "insert",		OP_MIX_INSERT,	"i"       },
+   { "delete",		OP_MIX_DELETE,  "d"	  },
+diff --git a/globals.h b/globals.h
+index abefade..3e3e4da 100644
+--- a/globals.h
++++ b/globals.h
+@@ -66,10 +66,11 @@ WHERE char *ImapUser INITVAL (NULL);
+ #endif
+ WHERE char *Inbox;
+ WHERE char *Ispell;
++WHERE char *KeywordsSave;
+ WHERE char *Locale;
+ WHERE char *MailcapPath;
+ WHERE char *Maildir;
+-#if defined(USE_IMAP) || defined(USE_POP)
++#if defined(USE_IMAP) || defined(USE_POP) || defined(USE_NNTP)
+ WHERE char *MessageCachedir;
+ #endif
+ #if USE_HCACHE
+@@ -95,6 +96,17 @@ WHERE char *MixEntryFormat;
+ #endif
+ 
+ WHERE char *Muttrc INITVAL (NULL);
++#ifdef USE_NNTP
++WHERE char *GroupFormat;
++WHERE char *Inews;
++WHERE char *NewsCacheDir;
++WHERE char *NewsServer;
++WHERE char *NewsgroupsCharset;
++WHERE char *NewsRc;
++WHERE char *NntpAuthenticators;
++WHERE char *NntpUser;
++WHERE char *NntpPass;
++#endif
+ WHERE char *Outbox;
+ WHERE char *Pager;
+ WHERE char *PagerFmt;
+@@ -111,6 +123,7 @@ WHERE char *Postponed;
+ WHERE char *PostponeEncryptAs;
+ WHERE char *Prefix;
+ WHERE char *PrintCmd;
++WHERE char *NewMailCmd;
+ WHERE char *QueryCmd;
+ WHERE char *QueryFormat;
+ WHERE char *Realname;
+@@ -118,6 +131,12 @@ WHERE short SearchContext;
+ WHERE char *SendCharset;
+ WHERE char *Sendmail;
+ WHERE char *Shell;
++#ifdef USE_SIDEBAR
++WHERE char *SidebarDelimChars;
++WHERE char *SidebarDividerChar;
++WHERE char *SidebarFormat;
++WHERE char *SidebarIndentString;
++#endif
+ WHERE char *Signature;
+ WHERE char *SimpleSearch;
+ #if USE_SMTP
+@@ -141,11 +160,13 @@ WHERE char *StChars;
+ WHERE char *Status;
+ WHERE char *Tempdir;
+ WHERE char *Tochars;
++WHERE char *TrashPath;
+ WHERE char *TSStatusFormat;
+ WHERE char *TSIconFormat;
+ WHERE short TSSupported;
+ WHERE char *Username;
+ WHERE char *Visual;
++WHERE char *XlabelDelim;
+ 
+ WHERE char *CurrentFolder;
+ WHERE char *LastFolder;
+@@ -154,7 +175,12 @@ WHERE char *LastFolder;
+ WHERE const char *ReleaseDate;
+ 
+ WHERE HASH *Groups;
++WHERE HASH *Labels;
+ WHERE HASH *ReverseAlias;
++#ifdef USE_NOTMUCH
++WHERE HASH *TagTransforms;
++WHERE HASH *TagFormats;
++#endif
+ 
+ WHERE LIST *AutoViewList INITVAL(0);
+ WHERE LIST *AlternativeOrderList INITVAL(0);
+@@ -194,6 +220,11 @@ extern unsigned char QuadOptions[];
+ 
+ WHERE unsigned short Counter INITVAL (0);
+ 
++#ifdef USE_NNTP
++WHERE short NewsPollTimeout;
++WHERE short NntpContext;
 +#endif
-+		ctx->path = uri;
-+		ctx->magic = M_NOTMUCH;
-+
-+		if (rc)
-+			break;
-+
-+		if (!h->deleted)
-+			nm_header_get_fullpath(h, new, sizeof(new));
-+
-+		if (h->deleted || strcmp(old, new) != 0) {
-+			if (h->deleted && remove_filename(data, old) == 0)
-+				changed = 1;
-+			else if (*new && *old && rename_filename(data, old, new, h) == 0)
-+				changed = 1;
-+		}
-+
-+		FREE(&hd->oldpath);
-+	}
-+
-+	ctx->path = uri;
-+	ctx->magic = M_NOTMUCH;
-+
-+	if (!is_longrun(data))
-+		release_db(data);
-+	if (changed)
-+		ctx->mtime = time(NULL);
 +
-+	dprint(1, (debugfile, "nm: .... sync done [rc=%d]\n", rc));
-+	return rc;
-+}
+ WHERE short ConnectTimeout;
+ WHERE short HistSize;
+ WHERE short MenuContext;
+@@ -204,6 +235,7 @@ WHERE short ReflowWrap;
+ WHERE short SaveHist;
+ WHERE short SendmailWait;
+ WHERE short SleepTime INITVAL (1);
++WHERE short SkipQuotedOffset;
+ WHERE short TimeInc;
+ WHERE short Timeout;
+ WHERE short Wrap;
+@@ -214,6 +246,12 @@ WHERE short ScoreThresholdDelete;
+ WHERE short ScoreThresholdRead;
+ WHERE short ScoreThresholdFlag;
+ 
++WHERE short SidebarWidth INITVAL(0);
++#ifdef USE_SIDEBAR
++WHERE LIST *SidebarWhitelist INITVAL(0);
++WHERE int SidebarNeedsRedraw INITVAL (0);
++#endif
 +
-+static unsigned count_query(notmuch_database_t *db, const char *qstr)
-+{
-+	unsigned res = 0;
-+	notmuch_query_t *q = notmuch_query_create(db, qstr);
+ #ifdef USE_IMAP
+ WHERE short ImapKeepalive;
+ WHERE short ImapPipelineDepth;
+@@ -269,6 +307,17 @@ WHERE char *SmimeGetCertCommand;
+ WHERE char *SmimeImportCertCommand;
+ WHERE char *SmimeGetCertEmailCommand;
+ 
++#ifdef USE_NOTMUCH
++WHERE int NotmuchOpenTimeout;
++WHERE char *NotmuchDefaultUri;
++WHERE char *NotmuchExcludeTags;
++WHERE char *NotmuchUnreadTag;
++WHERE char *NotmuchHiddenTags;
++WHERE char *VirtFolderFormat;
++WHERE int NotmuchDBLimit;
++WHERE char *NotmuchQueryType;
++WHERE char *NotmuchRecordTags;
++#endif
+ 
+ 
+ 
+diff --git a/handler.c b/handler.c
+index 4944d49..6068291 100644
+--- a/handler.c
++++ b/handler.c
+@@ -1595,7 +1595,9 @@ static int run_decode_and_handler (BODY *b, STATE *s, handler_t handler, int pla
+   int origType;
+   char *savePrefix = NULL;
+   FILE *fp = NULL;
++#ifndef HAVE_FMEMOPEN
+   char tempfile[_POSIX_PATH_MAX];
++#endif
+   size_t tmplength = 0;
+   LOFF_T tmpoffset = 0;
+   int decode = 0;
+@@ -1603,6 +1605,11 @@ static int run_decode_and_handler (BODY *b, STATE *s, handler_t handler, int pla
+ 
+   fseeko (s->fpin, b->offset, 0);
+ 
++#ifdef HAVE_FMEMOPEN
++  char *temp;
++  size_t tempsize;
++#endif
 +
-+	if (q) {
-+		apply_exclude_tags(q);
-+#if LIBNOTMUCH_CHECK_VERSION(4,3,0)
-+		if (notmuch_query_count_messages_st (q, &res) != NOTMUCH_STATUS_SUCCESS)
-+			res = 0;	/* may not be defined on error */
+   /* see if we need to decode this part before processing it */
+   if (b->encoding == ENCBASE64 || b->encoding == ENCQUOTEDPRINTABLE ||
+       b->encoding == ENCUUENCODED || plaintext ||
+@@ -1618,6 +1625,14 @@ static int run_decode_and_handler (BODY *b, STATE *s, handler_t handler, int pla
+     {
+       /* decode to a tempfile, saving the original destination */
+       fp = s->fpout;
++#ifdef HAVE_FMEMOPEN
++     s->fpout = open_memstream (&temp, &tempsize);
++     if (!s->fpout) {
++       mutt_error _("Unable to open memory stream!");
++       dprint (1, (debugfile, "Can't open memory stream.\n"));
++       return -1;
++     }
 +#else
-+		res = notmuch_query_count_messages(q);
+       mutt_mktemp (tempfile, sizeof (tempfile));
+       if ((s->fpout = safe_fopen (tempfile, "w")) == NULL)
+       {
+@@ -1625,6 +1640,7 @@ static int run_decode_and_handler (BODY *b, STATE *s, handler_t handler, int pla
+         dprint (1, (debugfile, "Can't open %s.\n", tempfile));
+         return -1;
+       }
 +#endif
-+		notmuch_query_destroy(q);
-+		dprint(1, (debugfile, "nm: count '%s', result=%d\n", qstr, res));
-+	}
-+	return res;
-+}
-+
-+int nm_nonctx_get_count(char *path, int *all, int *new)
-+{
-+	struct uri_tag *query_items = NULL, *item;
-+	char *db_filename = NULL, *db_query = NULL;
-+	notmuch_database_t *db = NULL;
-+	int rc = -1, dflt = 0;
-+
-+	dprint(1, (debugfile, "nm: count\n"));
-+
-+	if (url_parse_query(path, &db_filename, &query_items)) {
-+		mutt_error(_("failed to parse notmuch uri: %s"), path);
-+		goto done;
-+	}
-+	if (!query_items)
-+		goto done;
-+
-+	for (item = query_items; item; item = item->next) {
-+		if (item->value && strcmp(item->name, "query") == 0) {
-+			db_query = item->value;
-+			break;
-+		}
-+	}
-+
-+	if (!db_query)
-+		goto done;
-+
-+	if (!db_filename) {
-+		if (NotmuchDefaultUri) {
-+			if (strncmp(NotmuchDefaultUri, "notmuch://", 10) == 0)
-+				db_filename = NotmuchDefaultUri + 10;
-+			else
-+				db_filename = NotmuchDefaultUri;
-+		} else if (Maildir)
-+			db_filename = Maildir;
-+		dflt = 1;
-+	}
-+
-+	/* don't be verbose about connection, as we're called from
-+	 * sidebar/buffy very often */
-+	db = do_database_open(db_filename, FALSE, FALSE);
-+	if (!db)
-+		goto done;
-+
-+	/* all emails */
-+	if (all)
-+		*all = count_query(db, db_query);
-+
-+	/* new messages */
-+	if (new) {
-+		char *qstr;
-+
-+		safe_asprintf(&qstr, "( %s ) tag:%s",
-+				db_query, NotmuchUnreadTag);
-+		*new = count_query(db, qstr);
-+		FREE(&qstr);
-+	}
-+
-+	rc = 0;
-+done:
-+	if (db) {
-+#ifdef NOTMUCH_API_3
-+		notmuch_database_destroy(db);
+       /* decoding the attachment changes the size and offset, so save a copy
+         * of the "real" values now, and restore them after processing
+         */
+@@ -1653,9 +1669,20 @@ static int run_decode_and_handler (BODY *b, STATE *s, handler_t handler, int pla
+       /* restore final destination and substitute the tempfile for input */
+       s->fpout = fp;
+       fp = s->fpin;
++#ifdef HAVE_FMEMOPEN
++      if (tempsize) {
++        s->fpin = fmemopen (temp, tempsize, "r");
++      } else { /* fmemopen cannot handle zero-length buffers */
++        s->fpin = safe_fopen ("/dev/null", "r");
++      }
++      if (!s->fpin) {
++        mutt_perror ("failed to re-open memstream!");
++        return -1;
++      }
 +#else
-+		notmuch_database_close(db);
+       s->fpin = fopen (tempfile, "r");
+       unlink (tempfile);
+-
 +#endif
-+		dprint(1, (debugfile, "nm: count close DB\n"));
-+	}
-+	if (!dflt)
-+		FREE(&db_filename);
-+	url_free_tags(query_items);
-+
-+	dprint(1, (debugfile, "nm: count done [rc=%d]\n", rc));
-+	return rc;
-+}
-+
-+char *nm_get_description(CONTEXT *ctx)
+       /* restore the prefix */
+       s->prefix = savePrefix;
+     }
+@@ -1680,6 +1707,10 @@ static int run_decode_and_handler (BODY *b, STATE *s, handler_t handler, int pla
+ 
+       /* restore the original source stream */
+       safe_fclose (&s->fpin);
++#ifdef HAVE_FMEMOPEN
++      if (tempsize)
++        FREE(&temp);
++#endif
+       s->fpin = fp;
+     }
+   }
+diff --git a/hash.c b/hash.c
+index 08f7171..34b96ef 100644
+--- a/hash.c
++++ b/hash.c
+@@ -57,6 +57,7 @@ HASH *hash_create (int nelem, int lower)
+   if (nelem == 0)
+     nelem = 2;
+   table->nelem = nelem;
++  table->curnelem = 0;
+   table->table = safe_calloc (nelem, sizeof (struct hash_elem *));
+   if (lower)
+   {
+@@ -71,6 +72,29 @@ HASH *hash_create (int nelem, int lower)
+   return table;
+ }
+ 
++HASH *hash_resize (HASH *ptr, int nelem, int lower)
 +{
-+	BUFFY *p;
++  HASH *table;
++  struct hash_elem *elem, *tmp;
++  int i;
 +
-+	for (p = VirtIncoming; p; p = p->next)
-+		if (p->path && p->desc && strcmp(p->path, ctx->path) == 0)
-+			return p->desc;
++  table = hash_create (nelem, lower);
 +
-+	return NULL;
++  for (i = 0; i < ptr->nelem; i++)
++  {
++    for (elem = ptr->table[i]; elem; )
++    {
++      tmp = elem;
++      elem = elem->next;
++      hash_insert (table, tmp->key, tmp->data, 1);
++      FREE (&tmp);
++    }
++  }
++  FREE (&ptr->table);
++  FREE (&ptr);
++  return table;
 +}
 +
-+int nm_description_to_path(const char *desc, char *buf, size_t bufsz)
-+{
-+	BUFFY *p;
-+
-+	if (!desc || !buf || !bufsz)
-+		return -EINVAL;
-+
-+	for (p = VirtIncoming; p; p = p->next)
-+		if (p->path && p->desc && strcmp(desc, p->desc) == 0) {
-+			strncpy(buf, p->path, bufsz);
-+			buf[bufsz - 1] = '\0';
-+			return 0;
-+		}
-+
-+	return -1;
-+}
+ /* table        hash table to update
+  * key          key to hash on
+  * data         data to associate with `key'
+@@ -90,6 +114,7 @@ int hash_insert (HASH * table, const char *key, void *data, int allow_dup)
+   {
+     ptr->next = table->table[h];
+     table->table[h] = ptr;
++    table->curnelem++;
+   }
+   else
+   {
+@@ -112,6 +137,7 @@ int hash_insert (HASH * table, const char *key, void *data, int allow_dup)
+     else
+       table->table[h] = ptr;
+     ptr->next = tmp;
++    table->curnelem++;
+   }
+   return h;
+ }
+@@ -142,6 +168,7 @@ void hash_delete_hash (HASH * table, int hash, const char *key, const void *data
+       if (destroy)
+ 	destroy (ptr->data);
+       FREE (&ptr);
++      table->curnelem--;
+       
+       ptr = *last;
+     }
+@@ -176,3 +203,30 @@ void hash_destroy (HASH **ptr, void (*destroy) (void *))
+   FREE (&pptr->table);
+   FREE (ptr);		/* __FREE_CHECKED__ */
+ }
 +
-+/*
-+ * returns header from mutt context
-+ */
-+static HEADER *get_mutt_header(CONTEXT *ctx, notmuch_message_t *msg)
++struct hash_elem *hash_walk(const HASH *table, struct hash_walk_state *state)
 +{
-+	char *mid;
-+	const char *id;
-+	HEADER *h;
-+
-+	if (!ctx || !msg)
-+		return NULL;
-+
-+	id = notmuch_message_get_message_id(msg);
-+	if (!id)
-+		return NULL;
-+
-+	dprint(2, (debugfile, "nm: mutt header, id='%s'\n", id));
++  if (state->last && state->last->next)
++  {
++    state->last = state->last->next;
++    return state->last;
++  }
 +
-+	if (!ctx->id_hash) {
-+		dprint(2, (debugfile, "nm: init hash\n"));
-+		ctx->id_hash = mutt_make_id_hash(ctx);
-+		if (!ctx->id_hash)
-+			return NULL;
-+	}
++  if (state->last)
++    state->index++;
 +
-+	mid = nm2mutt_message_id( id );
-+	dprint(2, (debugfile, "nm: mutt id='%s'\n", mid));
++  while (state->index < table->nelem)
++  {
++    if (table->table[state->index])
++    {
++      state->last = table->table[state->index];
++      return state->last;
++    }
++    state->index++;
++  } 
 +
-+	h = hash_find(ctx->id_hash, mid);
-+	FREE(&mid);
-+	return h;
++  state->index = 0;
++  state->last = NULL;
++  return NULL;
 +}
 +
-+int nm_check_database(CONTEXT *ctx, int *index_hint)
-+{
-+	struct nm_ctxdata *data = get_ctxdata(ctx);
-+	time_t mtime = 0;
-+	notmuch_query_t *q;
-+	notmuch_messages_t *msgs;
-+	int i, limit, occult = 0, new_flags = 0;
-+
-+	if (!data || get_database_mtime(data, &mtime) != 0)
-+		return -1;
-+
-+	if (ctx->mtime >= mtime) {
-+		dprint(2, (debugfile, "nm: check unnecessary (db=%d ctx=%d)\n", mtime, ctx->mtime));
-+		return 0;
-+	}
-+
-+	dprint(1, (debugfile, "nm: checking (db=%d ctx=%d)\n", mtime, ctx->mtime));
-+
-+	q = get_query(data, FALSE);
-+	if (!q)
-+		goto done;
-+
-+	dprint(1, (debugfile, "nm: start checking (count=%d)\n", ctx->msgcount));
-+	data->oldmsgcount = ctx->msgcount;
-+	data->noprogress = 1;
+diff --git a/hash.h b/hash.h
+index fb77d0c..c944660 100644
+--- a/hash.h
++++ b/hash.h
+@@ -28,7 +28,7 @@ struct hash_elem
+ 
+ typedef struct
+ {
+-  int nelem;
++  int nelem, curnelem;
+   struct hash_elem **table;
+   unsigned int (*hash_string)(const unsigned char *, unsigned int);
+   int (*cmp_string)(const char *, const char *);
+@@ -41,9 +41,17 @@ HASH;
+ 
+ HASH *hash_create (int nelem, int lower);
+ int hash_insert (HASH * table, const char *key, void *data, int allow_dup);
++HASH *hash_resize (HASH * table, int nelem, int lower);
+ void *hash_find_hash (const HASH * table, int hash, const char *key);
+ void hash_delete_hash (HASH * table, int hash, const char *key, const void *data,
+ 		       void (*destroy) (void *));
+ void hash_destroy (HASH ** hash, void (*destroy) (void *));
+ 
++struct hash_walk_state {
++  int index;
++  struct hash_elem *last;
++};
 +
-+	for (i = 0; i < ctx->msgcount; i++)
-+		ctx->hdrs[i]->active = 0;
++struct hash_elem *hash_walk(const HASH *table, struct hash_walk_state *state);
 +
-+	limit = get_limit(data);
+ #endif
+diff --git a/hcache.c b/hcache.c
+index f4c0ecf..75a2671 100644
+--- a/hcache.c
++++ b/hcache.c
+@@ -32,6 +32,9 @@
+ #include <gdbm.h>
+ #elif HAVE_DB4
+ #include <db.h>
++#elif HAVE_LMDB
++#define LMDB_DB_SIZE    (1024 * 1024 * 1024)
++#include <lmdb.h>
+ #endif
+ 
+ #include <errno.h>
+@@ -83,6 +86,15 @@ struct header_cache
+ 
+ static void mutt_hcache_dbt_init(DBT * dbt, void *data, size_t len);
+ static void mutt_hcache_dbt_empty_init(DBT * dbt);
++#elif HAVE_LMDB
++struct header_cache
++{
++  MDB_env *env;
++  MDB_txn *txn;
++  MDB_dbi db;
++  char *folder;
++  unsigned int crc;
++};
+ #endif
+ 
+ typedef union
+@@ -439,13 +451,19 @@ dump_envelope(ENVELOPE * e, unsigned char *d, int *off, int convert)
+   d = dump_char(e->message_id, d, off, 0);
+   d = dump_char(e->supersedes, d, off, 0);
+   d = dump_char(e->date, d, off, 0);
+-  d = dump_char(e->x_label, d, off, convert);
+ 
+   d = dump_buffer(e->spam, d, off, convert);
+ 
+   d = dump_list(e->references, d, off, 0);
+   d = dump_list(e->in_reply_to, d, off, 0);
+   d = dump_list(e->userhdrs, d, off, convert);
++  d = dump_list(e->labels, d, off, convert);
 +
-+#if LIBNOTMUCH_CHECK_VERSION(4,3,0)
-+	if (notmuch_query_search_messages_st (q, &msgs) != NOTMUCH_STATUS_SUCCESS)
-+		goto done;
-+#else
-+	msgs = notmuch_query_search_messages(q);
++#ifdef USE_NNTP
++  d = dump_char(e->xref, d, off, 0);
++  d = dump_char(e->followup_to, d, off, 0);
++  d = dump_char(e->x_comment_to, d, off, convert);
 +#endif
+ 
+   return d;
+ }
+@@ -476,13 +494,19 @@ restore_envelope(ENVELOPE * e, const unsigned char *d, int *off, int convert)
+   restore_char(&e->message_id, d, off, 0);
+   restore_char(&e->supersedes, d, off, 0);
+   restore_char(&e->date, d, off, 0);
+-  restore_char(&e->x_label, d, off, convert);
+ 
+   restore_buffer(&e->spam, d, off, convert);
+ 
+   restore_list(&e->references, d, off, 0);
+   restore_list(&e->in_reply_to, d, off, 0);
+   restore_list(&e->userhdrs, d, off, convert);
++  restore_list(&e->labels, d, off, convert);
 +
-+	for (i = 0;
-+	     notmuch_messages_valid(msgs) && (limit == 0 || i < limit);
-+	     notmuch_messages_move_to_next(msgs), i++) {
-+
-+		char old[_POSIX_PATH_MAX];
-+		const char *new;
-+
-+		notmuch_message_t *m = notmuch_messages_get(msgs);
-+		HEADER *h = get_mutt_header(ctx, m);
-+
-+		if (!h) {
-+			/* new email */
-+			append_message(ctx, NULL, m, 0);
-+			notmuch_message_destroy(m);
-+			continue;
-+		}
-+
-+		/* message already exists, merge flags */
-+		h->active = 1;
++#ifdef USE_NNTP
++  restore_char(&e->xref, d, off, 0);
++  restore_char(&e->followup_to, d, off, 0);
++  restore_char(&e->x_comment_to, d, off, convert);
++#endif
+ }
+ 
+ static int
+@@ -732,6 +756,11 @@ mutt_hcache_fetch_raw (header_cache_t *h, const char *filename,
+ #elif HAVE_DB4
+   DBT key;
+   DBT data;
++#elif HAVE_LMDB
++  MDB_val key;
++  MDB_val data;
++  size_t folderlen;
++  int rc;
+ #endif
+   
+   if (!h)
+@@ -748,6 +777,42 @@ mutt_hcache_fetch_raw (header_cache_t *h, const char *filename,
+   h->db->get(h->db, NULL, &key, &data, 0);
+   
+   return data.data;
++#elif HAVE_LMDB
++  strncpy(path, h->folder, sizeof (path));
++  safe_strcat(path, sizeof (path), filename);
++
++  folderlen = strlen(h->folder);
++  ksize = folderlen + keylen(path + folderlen);  
++  key.mv_data = (char *)path;
++  key.mv_size = ksize;
++  data.mv_data = NULL;
++  data.mv_size = 0;
++  rc = mdb_txn_renew(h->txn);
++  if (rc != MDB_SUCCESS) {
++    h->txn = NULL;
++    fprintf(stderr, "txn_renew: %s\n", mdb_strerror(rc));
++    return NULL;
++  }
++  rc = mdb_get(h->txn, h->db, &key, &data);
++  if (rc == MDB_NOTFOUND) {
++    mdb_txn_reset(h->txn);
++    return NULL;
++  }
++  if (rc != MDB_SUCCESS) {
++    fprintf(stderr, "mdb_get: %s\n", mdb_strerror(rc));
++    mdb_txn_reset(h->txn);
++    return NULL;
++  }
++  /* Caller frees the data we return, so I MUST make a copy of it */
 +
-+		/* check to see if the message has moved to a different
-+		 * subdirectory.  If so, update the associated filename.
-+		 */
-+		new = get_message_last_filename(m);
-+		nm_header_get_fullpath(h, old, sizeof(old));
++  char *d = malloc(data.mv_size);
++  if (d) {
++    memcpy(d, data.mv_data, data.mv_size);
++  }
++  mdb_txn_reset(h->txn);
++
++  return d;
++
+ #else
+   strncpy(path, h->folder, sizeof (path));
+   safe_strcat(path, sizeof (path), filename);
+@@ -813,6 +878,12 @@ mutt_hcache_store_raw (header_cache_t* h, const char* filename, void* data,
+ #elif HAVE_DB4
+   DBT key;
+   DBT databuf;
++#elif HAVE_LMDB
++  MDB_val key;
++  MDB_val databuf;
++  MDB_txn *txn;
++  size_t folderlen;
++  int rc;
+ #endif
+   
+   if (!h)
+@@ -831,6 +902,29 @@ mutt_hcache_store_raw (header_cache_t* h, const char* filename, void* data,
+   databuf.ulen = dlen;
+   
+   return h->db->put(h->db, NULL, &key, &databuf, 0);
++#elif HAVE_LMDB
++  folderlen = strlen(h->folder);
++  strncpy(path, h->folder, sizeof (path));
++  safe_strcat(path, sizeof (path), filename);
++  ksize = folderlen + keylen(path + folderlen);
++
++  key.mv_data = (char *)path;
++  key.mv_size = ksize;
++  databuf.mv_data = data;
++  databuf.mv_size = dlen;
++  rc = mdb_txn_begin(h->env, NULL, 0, &txn);
++  if (rc != MDB_SUCCESS) {
++  	fprintf(stderr, "txn_begin: %s\n", mdb_strerror(rc));
++    return rc;
++  }
++  rc = mdb_put(txn, h->db, &key, &databuf, 0);
++  if (rc != MDB_SUCCESS) {
++  	fprintf(stderr, "mdb_put: %s\n", mdb_strerror(rc));
++    mdb_txn_abort(txn);
++    return rc;
++  }
++  rc = mdb_txn_commit(txn);
++  return rc;
+ #else
+   strncpy(path, h->folder, sizeof (path));
+   safe_strcat(path, sizeof (path), filename);
+@@ -1134,6 +1228,97 @@ mutt_hcache_delete(header_cache_t *h, const char *filename,
+   mutt_hcache_dbt_init(&key, (void *) filename, keylen(filename));
+   return h->db->del(h->db, NULL, &key, 0);
+ }
++#elif HAVE_LMDB
 +
-+		if (mutt_strcmp(old, new) != 0)
-+			update_message_path(h, new);
++static int
++hcache_open_lmdb (struct header_cache* h, const char* path)
++{
++  int rc;
 +
-+		if (!h->changed) {
-+			/* if the user hasn't modified the flags on
-+			 * this message, update the flags we just
-+			 * detected.
-+			 */
-+			HEADER tmp;
-+			memset(&tmp, 0, sizeof(tmp));
-+			maildir_parse_flags(&tmp, new);
-+			maildir_update_flags(ctx, h, &tmp);
-+		}
++  h->txn = NULL;
 +
-+		if (update_header_tags(h, m) == 0)
-+			new_flags++;
++  rc = mdb_env_create(&h->env);
++  if (rc != MDB_SUCCESS) {
++	  fprintf(stderr, "hcache_open_lmdb: mdb_env_create: %s", mdb_strerror(rc));
++	  return -1;
++  }
 +
-+		notmuch_message_destroy(m);
-+	}
++  mdb_env_set_mapsize(h->env, LMDB_DB_SIZE);
 +
-+	for (i = 0; i < ctx->msgcount; i++) {
-+		if (ctx->hdrs[i]->active == 0) {
-+			occult = 1;
-+			break;
-+		}
-+	}
++  rc = mdb_env_open(h->env, path, MDB_NOSUBDIR, 0644);
++  if (rc != MDB_SUCCESS) {
++	  fprintf(stderr, "hcache_open_lmdb: mdb_env_open: %s", mdb_strerror(rc));
++	  goto fail_env;
++  }
 +
-+	if (ctx->msgcount > data->oldmsgcount)
-+		mx_update_context(ctx, ctx->msgcount - data->oldmsgcount);
-+done:
-+	if (q)
-+		notmuch_query_destroy(q);
++  rc = mdb_txn_begin(h->env, NULL, MDB_RDONLY, &h->txn);
++  if (rc != MDB_SUCCESS) {
++      fprintf(stderr, "hcache_open_lmdb: mdb_txn_begin: %s", mdb_strerror(rc));
++      goto fail_env;
++  }
 +
-+	if (!is_longrun(data))
-+		release_db(data);
++  rc = mdb_dbi_open(h->txn, NULL, MDB_CREATE, &h->db);
++  if (rc != MDB_SUCCESS) {
++	  fprintf(stderr, "hcache_open_lmdb: mdb_dbi_open: %s", mdb_strerror(rc));
++	  goto fail_dbi;
++  }
 +
-+	ctx->mtime = time(NULL);
++  mdb_txn_reset(h->txn);
++  return 0;
 +
-+	dprint(1, (debugfile, "nm: ... check done [count=%d, new_flags=%d, occult=%d]\n",
-+				ctx->msgcount, new_flags, occult));
++fail_dbi:
++  mdb_txn_abort(h->txn);
++  h->txn = NULL;
 +
-+	return occult ? M_REOPENED :
-+	       ctx->msgcount > data->oldmsgcount ? M_NEW_MAIL :
-+	       new_flags ? M_FLAGS : 0;
++fail_env:
++  mdb_env_close(h->env);
++  return -1;
 +}
 +
-+int nm_record_message(CONTEXT *ctx, char *path, HEADER *h)
++void
++mutt_hcache_close(header_cache_t *h)
 +{
-+	notmuch_database_t *db;
-+	notmuch_status_t st;
-+	notmuch_message_t *msg = NULL;
-+	int rc = -1, trans;
-+	struct nm_ctxdata *data = get_ctxdata(ctx);
-+
-+	if (!path || !data || access(path, F_OK) != 0)
-+		return 0;
-+	db = get_db(data, TRUE);
-+	if (!db)
-+		return -1;
-+
-+	dprint(1, (debugfile, "nm: record message: %s\n", path));
-+	trans = db_trans_begin(data);
-+	if (trans < 0)
-+		goto done;
-+
-+	st = notmuch_database_add_message(db, path, &msg);
-+
-+	if (st != NOTMUCH_STATUS_SUCCESS &&
-+	    st != NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID) {
-+		dprint(1, (debugfile, "nm: failed to add '%s' [st=%d]\n", path, (int) st));
-+		goto done;
-+	}
-+
-+	if (st == NOTMUCH_STATUS_SUCCESS && msg) {
-+		notmuch_message_maildir_flags_to_tags(msg);
-+		if (h)
-+			update_tags(msg, nm_header_get_tags(h));
-+		if (NotmuchRecordTags)
-+			update_tags(msg, NotmuchRecordTags);
-+	}
++  if (!h)
++    return;
 +
-+	rc = 0;
-+done:
-+	if (msg)
-+		notmuch_message_destroy(msg);
-+	if (trans == 1)
-+		db_trans_end(data);
-+	if (!is_longrun(data))
-+		release_db(data);
-+	return rc;
++  mdb_env_close(h->env);
++  FREE (&h->folder);
++  FREE (&h);
 +}
 +
-+/*
-+ * Fill a list with all notmuch tags.
-+ *
-+ * If tag_list is NULL, just count the tags.
-+ */
-+int nm_get_all_tags(CONTEXT *ctx, char **tag_list, int *tag_count)
++int
++mutt_hcache_delete(header_cache_t *h, const char *filename,
++		   size_t(*keylen) (const char *fn))
 +{
-+	struct nm_ctxdata *data = get_ctxdata(ctx);
-+	notmuch_database_t *db = NULL;
-+	notmuch_tags_t *tags = NULL;
-+	int rc = -1;
-+
-+	if (!data)
-+		return -1;
-+
-+	if (!(db = get_db(data, FALSE)) ||
-+			!(tags = notmuch_database_get_all_tags(db)))
-+		goto done;
-+
-+	*tag_count = 0;
-+	dprint(1, (debugfile, "nm: get all tags\n"));
++  MDB_val key;
++  MDB_txn *txn;
++  int rc;
 +
-+	while (notmuch_tags_valid(tags)) {
-+		if (tag_list != NULL) {
-+			tag_list[*tag_count] = safe_strdup(notmuch_tags_get(tags));
-+		}
-+		(*tag_count)++;
-+		notmuch_tags_move_to_next(tags);
-+	}
++  if (!h)
++    return -1;
 +
-+	rc = 0;
-+done:
-+	if (tags)
-+		notmuch_tags_destroy(tags);
++  if (filename[0] == '/')
++    filename++;
 +
-+	if (!is_longrun(data))
-+		release_db(data);
++  key.mv_data = (char *)filename;
++  key.mv_size = strlen(filename);
++  rc = mdb_txn_begin(h->env, NULL, 0, &txn);
++  if (rc != MDB_SUCCESS) {
++  	fprintf(stderr, "txn_begin: %s\n", mdb_strerror(rc));
++    return rc;
++  }
++  rc = mdb_del(txn, h->db, &key, NULL);
++  if (rc != MDB_SUCCESS) {
++    if (rc != MDB_NOTFOUND) {
++  	  fprintf(stderr, "mdb_del: %s\n", mdb_strerror(rc));
++    }
++    mdb_txn_abort(txn);
++    return rc;
++  }
 +
-+	dprint(1, (debugfile, "nm: get all tags done [rc=%d tag_count=%u]\n", rc,
-+						 *tag_count));
-+	return rc;
++  mdb_txn_commit(txn);
++  return rc;
 +}
-diff -urN mutt-1.6.1/mutt_notmuch.h mutt-1.6.1-neomutt/mutt_notmuch.h
---- mutt-1.6.1/mutt_notmuch.h	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/mutt_notmuch.h	2016-06-12 18:43:00.717452503 +0100
-@@ -0,0 +1,39 @@
-+/*
-+ * Copyright (C) 2011 Karel Zak <kzak at redhat.com>
-+ */
-+#ifndef _MUTT_NOTMUCH_H_
-+#define _MUTT_NOTMUCH_H_ 1
-+
-+int nm_read_query(CONTEXT *ctx);
-+int nm_read_entire_thread(CONTEXT *ctx, HEADER *h);
-+
-+int nm_sync(CONTEXT * ctx, int *index_hint);
-+int nm_check_database(CONTEXT * ctx, int *index_hint);
-+char *nm_header_get_folder(HEADER *h);
-+int nm_header_get_magic(HEADER *h);
-+char *nm_header_get_fullpath(HEADER *h, char *buf, size_t bufsz);
-+int nm_update_filename(CONTEXT *ctx, const char *o, const char *n, HEADER *h);
-+char *nm_uri_from_query(CONTEXT *ctx, char *buf, size_t bufsz);
-+int nm_modify_message_tags(CONTEXT *ctx, HEADER *hdr, char *tags);
-+
-+void nm_longrun_init(CONTEXT *cxt, int writable);
-+void nm_longrun_done(CONTEXT *cxt);
-+
-+char *nm_get_description(CONTEXT *ctx);
-+int nm_description_to_path(const char *desc, char *buf, size_t bufsz);
-+
-+int nm_record_message(CONTEXT *ctx, char *path, HEADER *h);
-+
-+void nm_debug_check(CONTEXT *ctx);
-+int nm_get_all_tags(CONTEXT *ctx, char **tag_list, int *tag_count);
-+
-+/*
-+ * functions usable outside notmuch CONTEXT
-+ */
-+int nm_nonctx_get_count(char *path, int *all, int *new);
-+
-+char *nm_header_get_tag_transformed(char *tag, HEADER *h);
-+char *nm_header_get_tags_transformed(HEADER *h);
-+char *nm_header_get_tags(HEADER *h);
-+
-+#endif /* _MUTT_NOTMUCH_H_ */
-diff -urN mutt-1.6.1/mutt_sasl.c mutt-1.6.1-neomutt/mutt_sasl.c
---- mutt-1.6.1/mutt_sasl.c	2016-06-12 18:43:00.410447715 +0100
-+++ mutt-1.6.1-neomutt/mutt_sasl.c	2016-06-12 18:43:00.717452503 +0100
-@@ -190,6 +190,11 @@
-     case M_ACCT_TYPE_SMTP:
-       service = "smtp";
-       break;
-+#ifdef USE_NNTP
-+    case M_ACCT_TYPE_NNTP:
-+      service = "nntp";
-+      break;
-+#endif
-     default:
-       mutt_error (_("Unknown SASL profile"));
-       return -1;
-diff -urN mutt-1.6.1/mutt_ssl.c mutt-1.6.1-neomutt/mutt_ssl.c
---- mutt-1.6.1/mutt_ssl.c	2016-06-12 18:43:00.411447731 +0100
-+++ mutt-1.6.1-neomutt/mutt_ssl.c	2016-06-12 18:43:00.718452518 +0100
-@@ -401,6 +401,18 @@
-   SSL_set_mode (ssldata->ssl, SSL_MODE_AUTO_RETRY);
  #endif
  
-+#if (OPENSSL_VERSION_NUMBER >= 0x0090806fL) && !defined(OPENSSL_NO_TLSEXT)
-+  /* TLS Virtual-hosting requires that the server present the correct
-+   * certificate; to do this, the ServerNameIndication TLS extension is used.
-+   * If TLS is negotiated, and OpenSSL is recent enough that it might have
-+   * support, and support was enabled when OpenSSL was built, mutt supports
-+   * sending the hostname we think we're connecting to, so a server can send
-+   * back the correct certificate.
-+   * This has been tested over SMTP against Exim 4.80.
-+   * Not yet found an IMAP server which supports this. */
-+  SSL_set_tlsext_host_name (ssldata->ssl, conn->account.host);
-+#endif
-+
-   if ((err = SSL_connect (ssldata->ssl)) != 1)
-   {
-     switch (SSL_get_error (ssldata->ssl, err))
-@@ -432,14 +444,6 @@
-   if (!ssl_check_certificate (conn, ssldata))
-     return -1;
+ header_cache_t *
+@@ -1151,6 +1336,8 @@ mutt_hcache_open(const char *path, const char *folder, hcache_namer_t namer)
+   hcache_open = hcache_open_gdbm;
+ #elif HAVE_DB4
+   hcache_open = hcache_open_db4;
++#elif HAVE_LMDB
++  hcache_open = hcache_open_lmdb;
+ #endif
  
--  /* L10N:
--     %1$s is version (e.g. "TLSv1.2")
--     %2$s is cipher_version (e.g. "TLSv1/SSLv3")
--     %3$s is cipher_name (e.g. "ECDHE-RSA-AES128-GCM-SHA256") */
--  mutt_message (_("%s connection using %s (%s)"),
--    SSL_get_version(ssldata->ssl), SSL_get_cipher_version (ssldata->ssl), SSL_get_cipher_name (ssldata->ssl));
--  mutt_sleep (0);
--
-   return 0;
- }
+   /* Calculate the current hcache version from dynamic configuration */
+@@ -1188,7 +1375,11 @@ mutt_hcache_open(const char *path, const char *folder, hcache_namer_t namer)
+     hcachever = digest.intval;
+   }
  
-diff -urN mutt-1.6.1/mx.c mutt-1.6.1-neomutt/mx.c
---- mutt-1.6.1/mx.c	2016-06-12 18:43:00.411447731 +0100
-+++ mutt-1.6.1-neomutt/mx.c	2016-06-12 18:43:00.719452534 +0100
-@@ -29,6 +29,13 @@
- #include "copy.h"
- #include "keymap.h"
- #include "url.h"
-+#ifdef USE_SIDEBAR
-+#include "sidebar.h"
-+#endif
-+
-+#ifdef USE_COMPRESSED
-+#include "compress.h"
++#if HAVE_LMDB
++  h->db = 0;
++#else
+   h->db = NULL;
 +#endif
+   h->folder = get_foldername(folder);
+   h->crc = hcachever;
  
- #ifdef USE_IMAP
- #include "imap.h"
-@@ -38,6 +45,14 @@
- #include "pop.h"
+@@ -1223,6 +1414,11 @@ const char *mutt_hcache_backend (void)
+ {
+   return DB_VERSION_STRING;
+ }
++#elif HAVE_LMDB
++const char *mutt_hcache_backend (void)
++{
++  return "lmdb " MDB_VERSION_STRING;
++}
+ #elif HAVE_GDBM
+ const char *mutt_hcache_backend (void)
+ {
+diff --git a/hdrline.c b/hdrline.c
+index b844411..ccddd05 100644
+--- a/hdrline.c
++++ b/hdrline.c
+@@ -36,6 +36,10 @@
+ #include <alloca.h>
  #endif
  
 +#ifdef USE_NOTMUCH
 +#include "mutt_notmuch.h"
 +#endif
 +
-+#ifdef USE_NNTP
-+#include "nntp.h"
-+#endif
-+
- #include "buffy.h"
- 
- #ifdef USE_DOTLOCK
-@@ -57,6 +72,10 @@
- #include <ctype.h>
- #include <utime.h>
- 
-+#if USE_NOTMUCH
-+#include "mutt_notmuch.h"
-+#endif
-+
- 
- #define mutt_is_spool(s)  (mutt_strcmp (Spoolfile, s) == 0)
- 
-@@ -343,6 +362,40 @@
+ int mutt_is_mail_list (ADDRESS *addr)
+ {
+   if (!mutt_match_rx_list (addr->mailbox, UnMailLists))
+@@ -103,6 +107,38 @@ static int first_mailing_list (char *buf, size_t buflen, ADDRESS *a)
+   return 0;
  }
- #endif
  
-+#ifdef USE_NNTP
-+int mx_is_nntp (const char *p)
++/**
++ * add_index_color - XXX
++ *
++ * Takes the color to embed, the buffer to manipulate and the buffer length as
++ * arguments.
++ * Returns the number of chars written.
++ */
++static size_t
++add_index_color (char *buf, size_t buflen, format_flag flags, char color)
 +{
-+  url_scheme_t scheme;
++	int len;
 +
-+  if (!p)
-+    return 0;
++	/* only add color markers if we are operating on main index entries. */
++	if (!(flags & M_FORMAT_INDEX))
++		return 0;
 +
-+  scheme = url_check_scheme (p);
-+  if (scheme == U_NNTP || scheme == U_NNTPS)
-+    return 1;
++	if (color == MT_COLOR_INDEX) { /* buf might be uninitialized other cases */
++		len = mutt_strlen (buf);
++		buf += len;
++		buflen -= len;
++	}
 +
-+  return 0;
-+}
-+#endif
++	if (buflen < 2)
++		return 0;
 +
-+#ifdef USE_NOTMUCH
++	buf[0] = M_SPECIAL_INDEX;
++	buf[1] = color;
++	buf[2] = '\0';
 +
-+int mx_is_notmuch(const char *p)
-+{
-+  url_scheme_t scheme;
++	return 2;
++}
 +
-+  if (!p)
-+    return 0;
+ static void make_from (ENVELOPE *hdr, char *buf, size_t len, int do_lists)
+ {
+   int me;
+@@ -211,7 +247,10 @@ int mutt_user_is_recipient (HEADER *h)
+  * %E = number of messages in current thread
+  * %f = entire from line
+  * %F = like %n, unless from self
++ * %g = message labels (e.g. notmuch tags)
++ * %g = newsgroup name (if compiled with NNTP support)
+  * %i = message-id
++ * %I = initials of author
+  * %l = number of lines in the message
+  * %L = like %F, except `lists' are displayed first
+  * %m = number of messages in the mailbox
+@@ -227,6 +266,8 @@ int mutt_user_is_recipient (HEADER *h)
+  * %T = $to_chars
+  * %u = user (login) name of author
+  * %v = first name of author, unless from self
++ * %W = where user is (organization)
++ * %x = `x-comment-to:' field (if present and compiled with NNTP support)
+  * %X = number of MIME attachments
+  * %y = `x-label:' field (if present)
+  * %Y = `x-label:' field (if present, tree unfolded, and != parent's x-label)
+@@ -236,6 +277,7 @@ static const char *
+ hdr_format_str (char *dest,
+ 		size_t destlen,
+ 		size_t col,
++                int cols,
+ 		char op,
+ 		const char *src,
+ 		const char *prefix,
+@@ -255,6 +297,7 @@ hdr_format_str (char *dest,
+ #define THREAD_NEW (threads && hdr->collapsed && hdr->num_hidden > 1 && mutt_thread_contains_unread (ctx, hdr) == 1)
+ #define THREAD_OLD (threads && hdr->collapsed && hdr->num_hidden > 1 && mutt_thread_contains_unread (ctx, hdr) == 2)
+   size_t len;
++  size_t colorlen;
+ 
+   hdr = hfi->hdr;
+   ctx = hfi->ctx;
+@@ -265,7 +308,9 @@ hdr_format_str (char *dest,
+     case 'A':
+       if(hdr->env->reply_to && hdr->env->reply_to->mailbox)
+       {
+-	mutt_format_s (dest, destlen, prefix, mutt_addr_for_display (hdr->env->reply_to));
++        colorlen = add_index_color (dest, destlen, flags, MT_COLOR_INDEX_AUTHOR);
++        mutt_format_s (dest + colorlen, destlen - colorlen, prefix, mutt_addr_for_display (hdr->env->reply_to));
++        add_index_color (dest + colorlen, destlen - colorlen, flags, MT_COLOR_INDEX);
+ 	break;
+       }
+       /* fall through if 'A' returns nothing */
+@@ -273,7 +318,9 @@ hdr_format_str (char *dest,
+     case 'a':
+       if(hdr->env->from && hdr->env->from->mailbox)
+       {
+-	mutt_format_s (dest, destlen, prefix, mutt_addr_for_display (hdr->env->from));
++        colorlen = add_index_color (dest, destlen, flags, MT_COLOR_INDEX_AUTHOR);
++        mutt_format_s (dest + colorlen, destlen - colorlen, prefix, mutt_addr_for_display (hdr->env->from));
++        add_index_color (dest + colorlen, destlen - colorlen, flags, MT_COLOR_INDEX);
+       }
+       else
+         dest[0] = '\0';
+@@ -306,12 +353,16 @@ hdr_format_str (char *dest,
+       break;
+     
+     case 'c':
++      colorlen = add_index_color (dest, destlen, flags, MT_COLOR_INDEX_SIZE);
+       mutt_pretty_size (buf2, sizeof (buf2), (long) hdr->content->length);
+-      mutt_format_s (dest, destlen, prefix, buf2);
++      mutt_format_s (dest + colorlen, destlen - colorlen, prefix, buf2);
++      add_index_color (dest + colorlen, destlen - colorlen, flags, MT_COLOR_INDEX);
+       break;
+ 
+     case 'C':
+-      snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
++      colorlen = add_index_color (fmt, sizeof (fmt), flags, MT_COLOR_INDEX_NUMBER);
++      snprintf (fmt + colorlen, sizeof (fmt) - colorlen, "%%%sd", prefix);
++      add_index_color (fmt + colorlen, sizeof (fmt) - colorlen, flags, MT_COLOR_INDEX);
+       snprintf (dest, destlen, fmt, hdr->msgno + 1);
+       break;
+ 
+@@ -327,6 +378,98 @@ hdr_format_str (char *dest,
+ 	const char *cp;
+ 	struct tm *tm; 
+ 	time_t T;
++	int i = 0, invert = 0;
 +
-+  scheme = url_check_scheme (p);
-+  if (scheme == U_NOTMUCH)
-+    return 1;
++	if (optional && ((op == '[') || (op == '('))) {
++	  char *is;
++	  T = time (NULL);
++	  tm = localtime (&T);
++	  T -= (op == '(') ? hdr->received : hdr->date_sent;
 +
-+  return 0;
-+}
++	  is = (char *) prefix;
++	  if (*is == '>') {
++	    invert = 1;
++	    is++;
++	  }
 +
-+#endif
++	  while (*is && (*is != '?')) {
++	    int t = strtol (is, &is, 10);
++	    /* semi-broken (assuming 30 days in all months) */
++	    switch (*(is++)) {
++	      case 'y':
++		if (t > 1) {
++		  t--;
++		  t *= (60 * 60 * 24 * 365);
++		}
++		t += ((tm->tm_mon  * 60 * 60 * 24 * 30) +
++		      (tm->tm_mday * 60 * 60 * 24) +
++		      (tm->tm_hour * 60 * 60) +
++		      (tm->tm_min  * 60) +
++		       tm->tm_sec);
++		break;
 +
- int mx_get_magic (const char *path)
- {
-   struct stat st;
-@@ -360,6 +413,16 @@
-     return M_POP;
- #endif /* USE_POP */
- 
-+#ifdef USE_NOTMUCH
-+  if (mx_is_notmuch(path))
-+    return M_NOTMUCH;
-+#endif
++	      case 'm':
++		if (t > 1) {
++		  t--;
++		  t *= (60 * 60 * 24 * 30);
++		}
++		t += ((tm->tm_mday * 60 * 60 * 24) +
++		      (tm->tm_hour * 60 * 60) +
++		      (tm->tm_min  * 60) +
++		      tm->tm_sec);
++		break;
 +
-+#ifdef USE_NNTP
-+  if (mx_is_nntp (path))
-+    return M_NNTP;
-+#endif /* USE_NNTP */
++	      case 'w':
++		if (t > 1) {
++		  t--;
++		  t *= (60 * 60 * 24 * 7);
++		}
++		t += ((tm->tm_wday * 60 * 60 * 24) +
++		      (tm->tm_hour * 60 * 60) +
++		      (tm->tm_min  * 60) +
++		       tm->tm_sec);
++		break;
 +
-   if (stat (path, &st) == -1)
-   {
-     dprint (1, (debugfile, "mx_get_magic(): unable to stat %s: %s (errno %d).\n",
-@@ -414,6 +477,10 @@
-     return (-1);
-   }
- 
-+#ifdef USE_COMPRESSED
-+  if (magic == 0 && comp_can_read (path))
-+    return M_COMPRESSED;
-+#endif
-   return (magic);
- }
- 
-@@ -453,6 +520,13 @@
- {
-   struct stat sb;
- 
-+#ifdef USE_COMPRESSED
-+  /* special case for appending to compressed folders -
-+   * even if we can not open them for reading */
-+  if (comp_can_append (ctx->path))
-+    comp_open_append (ctx);
-+#endif
++	      case 'd':
++		if (t > 1) {
++		  t--;
++		  t *= (60 * 60 * 24);
++		}
++		t += ((tm->tm_hour * 60 * 60) +
++		      (tm->tm_min  * 60) +
++		       tm->tm_sec);
++		break;
 +
-   ctx->append = 1;
- 
- #ifdef USE_IMAP
-@@ -580,6 +654,7 @@
-  *		M_APPEND	open mailbox for appending
-  *		M_READONLY	open mailbox in read-only mode
-  *		M_QUIET		only print error messages
-+ *		M_PEEK		revert atime where applicable
-  *	ctx	if non-null, context struct to use
-  */
- CONTEXT *mx_open_mailbox (const char *path, int flags, CONTEXT *pctx)
-@@ -602,6 +677,10 @@
-     ctx->quiet = 1;
-   if (flags & M_READONLY)
-     ctx->readonly = 1;
-+#ifdef USE_SIDEBAR
-+  if (flags & M_PEEK)
-+    ctx->peekonly = 1;
-+#endif
- 
-   if (flags & (M_APPEND|M_NEWFOLDER))
-   {
-@@ -616,7 +695,12 @@
-   }
- 
-   ctx->magic = mx_get_magic (path);
--  
++	      case 'H':
++		if (t > 1) {
++		  t--;
++		  t *= (60 * 60);
++		}
++		t += ((tm->tm_min * 60) +
++		       tm->tm_sec);
++		break;
++
++	      case 'M':
++		if (t > 1) {
++		  t--;
++		  t *= (60);
++		}
++		t += (tm->tm_sec);
++		break;
 +
-+#ifdef USE_COMPRESSED
-+  if (ctx->magic == M_COMPRESSED)
-+    comp_open_read (ctx);
-+#endif
++	      default:
++		break;
++	    }
++	    i += t;
++	  }
 +
-   if(ctx->magic == 0)
-     mutt_error (_("%s is not a mailbox."), path);
++	  if (i < 0)
++	    i *= -1;
++
++	  if (((T > i) || (T < (-1*i))) ^ invert)
++	    optional = 0;
++	  break;
++	}
  
-@@ -668,6 +752,18 @@
-       break;
- #endif /* USE_POP */
+ 	p = dest;
  
-+#ifdef USE_NOTMUCH
-+    case M_NOTMUCH:
-+      rc = nm_read_query (ctx);
-+      break;
-+#endif /* USE_IMAP */
-+
-+#ifdef USE_NNTP
-+    case M_NNTP:
-+      rc = nntp_open_mailbox (ctx);
-+      break;
-+#endif /* USE_NNTP */
+@@ -410,7 +553,10 @@ hdr_format_str (char *dest,
+ 	if (do_locales)
+ 	  setlocale (LC_TIME, "C");
+ 
+-	mutt_format_s (dest, destlen, prefix, buf2);
++	colorlen = add_index_color (dest, destlen, flags, MT_COLOR_INDEX_DATE);
++	mutt_format_s (dest + colorlen, destlen - colorlen, prefix, buf2);
++	add_index_color (dest + colorlen, destlen - colorlen, flags, MT_COLOR_INDEX);
 +
-     default:
-       rc = -1;
+ 	if (len > 0 && op != 'd' && op != 'D') /* Skip ending op */
+ 	  src = cp + 1;
+       }
+@@ -440,13 +586,28 @@ hdr_format_str (char *dest,
+     case 'F':
+       if (!optional)
+       {
++        colorlen = add_index_color (dest, destlen, flags, MT_COLOR_INDEX_AUTHOR);
+         make_from (hdr->env, buf2, sizeof (buf2), 0);
+-	mutt_format_s (dest, destlen, prefix, buf2);
++        mutt_format_s (dest + colorlen, destlen - colorlen, prefix, buf2);
++        add_index_color (dest + colorlen, destlen - colorlen, flags, MT_COLOR_INDEX);
+       }
+       else if (mutt_addr_is_user (hdr->env->from))
+         optional = 0;
        break;
-@@ -705,8 +801,21 @@
-   if(!ctx) 
-     return;
  
-+#ifdef USE_SIDEBAR
-+  /* fix up the times so buffy won't get confused */
-+  struct utimbuf ut;
-+  if (ctx->peekonly && ctx->path && (ctx->mtime > ctx->atime)) {
-+    ut.actime  = ctx->atime;
-+    ut.modtime = ctx->mtime;
-+    utime (ctx->path, &ut);
-+  }
++#ifdef USE_NOTMUCH
++    case 'g':
++      if (!optional)
++      {
++        colorlen = add_index_color(dest, destlen, flags, MT_COLOR_INDEX_TAGS);
++        mutt_format_s (dest+colorlen, destlen-colorlen, prefix, nm_header_get_tags_transformed(hdr));
++        add_index_color(dest+colorlen, destlen-colorlen, flags, MT_COLOR_INDEX);
++      }
++      else if (!nm_header_get_tags_transformed(hdr))
++        optional = 0;
++      break;
 +#endif
 +
-   /* never announce that a mailbox we've just left has new mail. #3290
-    * XXX: really belongs in mx_close_mailbox, but this is a nice hook point */
-+#ifdef USE_SIDEBAR
-+  if (!ctx->peekonly)
-+#endif
-   mutt_buffy_setnotified(ctx->path);
+     case 'H':
+       /* (Hormel) spam score */
+       if (optional)
+@@ -459,15 +620,45 @@ hdr_format_str (char *dest,
  
-   if (ctx->mx_close)
-@@ -721,6 +830,10 @@
-     mutt_free_header (&ctx->hdrs[i]);
-   FREE (&ctx->hdrs);
-   FREE (&ctx->v2r);
-+#ifdef USE_COMPRESSED
-+  if (ctx->compress_info)
-+    comp_fast_close (ctx);
-+#endif
-   FREE (&ctx->path);
-   FREE (&ctx->pattern);
-   if (ctx->limit_pattern) 
-@@ -764,6 +877,18 @@
-       rc = pop_sync_mailbox (ctx, index_hint);
        break;
- #endif /* USE_POP */
-+
-+#ifdef USE_NOTMUCH
-+    case M_NOTMUCH:
-+      rc = nm_sync (ctx, index_hint);
-+      break;
-+#endif /* USE_NOTMUCH */
-+
+ 
 +#ifdef USE_NNTP
-+    case M_NNTP:
-+      rc = nntp_sync_mailbox (ctx);
++    case 'q':
++      mutt_format_s (dest, destlen, prefix, hdr->env->newsgroups ? hdr->env->newsgroups : "");
 +      break;
-+#endif /* USE_NNTP */
-   }
- 
- #if 0
-@@ -773,9 +898,71 @@
-   
-   if (tmp && tmp->new == 0)
-     mutt_update_mailbox (tmp);
-+
-+#ifdef USE_COMPRESSED
-+  if (rc == 0 && ctx->compress_info)
-+    return comp_sync (ctx);
 +#endif
 +
-   return rc;
- }
+     case 'i':
+       mutt_format_s (dest, destlen, prefix, hdr->env->message_id ? hdr->env->message_id : "<no.id>");
+       break;
  
-+/**
-+ * trash_append - XXX
-+ *
-+ * move deleted mails to the trash folder
-+ */
-+static int trash_append (CONTEXT *ctx)
-+{
-+	CONTEXT *ctx_trash;
-+	int i = 0;
-+	struct stat st, stc;
-+
-+	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++);
-+		/* nothing */
-+
-+	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 (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 */
-+	}
-+
-+#ifdef USE_IMAP
-+	if (!imap_fast_trash())
-+		return 0;
-+#endif
-+
-+	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;
-+			}
-+		}
++    case 'I':
++      {
++	int iflag = FALSE;
++	int j = 0;
 +
-+		mx_close_mailbox (ctx_trash, NULL);
-+	} else {
-+		mutt_error _("Can't open trash folder");
-+		return -1;
++	for (i = 0; hdr->env->from && hdr->env->from->personal &&
++		    hdr->env->from->personal[i] && (j < (SHORT_STRING - 1)); i++) {
++	  if (isalpha ((int) hdr->env->from->personal[i])) {
++	    if (!iflag) {
++	      buf2[j++] = hdr->env->from->personal[i];
++	      iflag = TRUE;
++	    }
++	  } else {
++	    iflag = FALSE;
++	  }
 +	}
 +
-+	return 0;
-+}
++	buf2[j] = '\0';
++      }
++      mutt_format_s (dest, destlen, prefix, buf2);
++      break;
 +
- /* save changes and close mailbox */
- int mx_close_mailbox (CONTEXT *ctx, int *index_hint)
- {
-@@ -807,13 +994,44 @@
-     return 0;
-   }
+     case 'l':
+       if (!optional)
+       {
+ 	snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
+-	snprintf (dest, destlen, fmt, (int) hdr->lines);
++	colorlen = add_index_color (dest, destlen, flags, MT_COLOR_INDEX_SIZE);
++	snprintf (dest + colorlen, destlen - colorlen, fmt, (int) hdr->lines);
++	add_index_color (dest + colorlen, destlen - colorlen, flags, MT_COLOR_INDEX);
+       }
+       else if (hdr->lines <= 0)
+         optional = 0;
+@@ -476,8 +667,10 @@ hdr_format_str (char *dest,
+     case 'L':
+       if (!optional)
+       {
++	colorlen = add_index_color (dest, destlen, flags, MT_COLOR_INDEX_AUTHOR);
+ 	make_from (hdr->env, buf2, sizeof (buf2), 1);
+-	mutt_format_s (dest, destlen, prefix, buf2);
++	mutt_format_s (dest + colorlen, destlen - colorlen, prefix, buf2);
++	add_index_color (dest + colorlen, destlen - colorlen, flags, MT_COLOR_INDEX);
+       }
+       else if (!check_for_mailing_list (hdr->env->to, NULL, NULL, 0) &&
+ 	       !check_for_mailing_list (hdr->env->cc, NULL, NULL, 0))
+@@ -497,7 +690,9 @@ hdr_format_str (char *dest,
+       break;
  
-+#ifdef USE_NNTP
-+  if (ctx->unread && ctx->magic == M_NNTP)
-+  {
-+    NNTP_DATA *nntp_data = ctx->data;
-+
-+    if (nntp_data && nntp_data->nserv && nntp_data->group)
-+    {
-+      int rc = query_quadoption (OPT_CATCHUP, _("Mark all articles read?"));
-+      if (rc < 0)
-+      {
-+	ctx->closing = 0;
-+	return -1;
+     case 'n':
+-      mutt_format_s (dest, destlen, prefix, mutt_get_name (hdr->env->from));
++      colorlen = add_index_color (dest, destlen, flags, MT_COLOR_INDEX_AUTHOR);
++      mutt_format_s (dest + colorlen, destlen - colorlen, prefix, mutt_get_name (hdr->env->from));
++      add_index_color (dest + colorlen, destlen - colorlen, flags, MT_COLOR_INDEX);
+       break;
+ 
+     case 'N':
+@@ -532,10 +727,15 @@ hdr_format_str (char *dest,
+       snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
+       if (!optional)
+       {
+-	if (threads && is_index && hdr->collapsed && hdr->num_hidden > 1)
+-	  snprintf (dest, destlen, fmt, hdr->num_hidden);
+-	else if (is_index && threads)
+-	  mutt_format_s (dest, destlen, prefix, " ");
++	colorlen = add_index_color (dest, destlen, flags,
++				   MT_COLOR_INDEX_COLLAPSED);
++	if (threads && is_index && hdr->collapsed && hdr->num_hidden > 1) {
++	  snprintf (dest + colorlen, destlen - colorlen, fmt, hdr->num_hidden);
++	  add_index_color (dest, destlen - colorlen, flags, MT_COLOR_INDEX);
++	} else if (is_index && threads) {
++	  mutt_format_s (dest + colorlen, destlen - colorlen, prefix, " ");
++	  add_index_color (dest, destlen - colorlen, flags, MT_COLOR_INDEX);
++	}
+ 	else
+ 	  *dest = '\0';
+       }
+@@ -572,15 +772,20 @@ hdr_format_str (char *dest,
+       {
+ 	if (flags & M_FORMAT_FORCESUBJ)
+ 	{
+-	  mutt_format_s (dest, destlen, "", NONULL (hdr->env->subject));
++	  colorlen = add_index_color (dest, destlen, flags, MT_COLOR_INDEX_SUBJECT);
++	  mutt_format_s (dest + colorlen, destlen - colorlen, "", NONULL (hdr->env->subject));
++	  add_index_color (dest + colorlen, destlen - colorlen, flags, MT_COLOR_INDEX);
+ 	  snprintf (buf2, sizeof (buf2), "%s%s", hdr->tree, dest);
+ 	  mutt_format_s_tree (dest, destlen, prefix, buf2);
+ 	}
+ 	else
+ 	  mutt_format_s_tree (dest, destlen, prefix, hdr->tree);
+       }
+-      else
+-	mutt_format_s (dest, destlen, prefix, NONULL (hdr->env->subject));
++      else {
++	colorlen = add_index_color (dest, destlen, flags, MT_COLOR_INDEX_SUBJECT);
++	mutt_format_s (dest + colorlen, destlen - colorlen, prefix, NONULL (hdr->env->subject));
++	add_index_color (dest + colorlen, destlen - colorlen, flags, MT_COLOR_INDEX);
 +      }
-+      else if (rc == M_YES)
-+	mutt_newsgroup_catchup (nntp_data->nserv, nntp_data->group);
-+    }
-+  }
-+#endif
-+
-   for (i = 0; i < ctx->msgcount; i++)
-   {
-     if (!ctx->hdrs[i]->deleted && ctx->hdrs[i]->read 
-         && !(ctx->hdrs[i]->flagged && option (OPTKEEPFLAGGED)))
-       read_msgs++;
-+#ifdef USE_SIDEBAR
-+    if (ctx->hdrs[i]->deleted && !ctx->hdrs[i]->read)
-+      ctx->unread--;
-+    if (ctx->hdrs[i]->deleted && ctx->hdrs[i]->flagged)
-+      ctx->flagged--;
-+#endif
-   }
+       break;
  
-+#ifdef USE_NNTP
-+  /* don't need to move articles from newsgroup */
-+  if (ctx->magic == M_NNTP)
-+    read_msgs = 0;
-+#endif
-+
-   if (read_msgs && quadoption (OPT_MOVE) != M_NO)
-   {
-     char *p;
-@@ -912,6 +1130,7 @@
- 	  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
- 	  {
-@@ -936,6 +1155,14 @@
-     return 0;
-   }
-   
-+  /* copy mails to the trash before expunging */
-+  if (purge && ctx->deleted && mutt_strcmp (ctx->path, TrashPath)) {
-+    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)
-@@ -981,6 +1208,15 @@
-       !mutt_is_spool(ctx->path) && !option (OPTSAVEEMPTY))
-     mx_unlink_empty (ctx->path);
+     case 'S':
+@@ -603,8 +808,11 @@ hdr_format_str (char *dest,
  
-+#ifdef USE_COMPRESSED
-+  if (ctx->compress_info && comp_slow_close (ctx))
-+    return (-1);
-+#endif
-+#ifdef USE_SIDEBAR
-+  ctx->msgcount -= ctx->deleted;
-+  mutt_sb_set_buffystats (ctx);
+       /* FOO - this is probably unsafe, but we are not likely to have such
+ 	 a short string passed into this routine */
+-      *dest = ch;
+-      *(dest + 1) = 0;
++      buf2[0] = ch;
++      buf2[1] = 0;
++      colorlen = add_index_color (dest, destlen, flags, MT_COLOR_INDEX_FLAGS);
++      mutt_format_s (dest + colorlen, destlen - colorlen, prefix, buf2);
++      add_index_color (dest + colorlen, destlen - colorlen, flags, MT_COLOR_INDEX);
+       break;
+ 
+     case 't':
+@@ -655,6 +863,22 @@ hdr_format_str (char *dest,
+       mutt_format_s (dest, destlen, prefix, buf2);
+       break;
+ 
++    case 'W':
++      if (!optional)
++	mutt_format_s (dest, destlen, prefix, hdr->env->organization ? hdr->env->organization : "");
++      else if (!hdr->env->organization)
++	optional = 0;
++      break;
++
++#ifdef USE_NNTP
++    case 'x':
++      if (!optional)
++	mutt_format_s (dest, destlen, prefix, hdr->env->x_comment_to ? hdr->env->x_comment_to : "");
++      else if (!hdr->env->x_comment_to)
++	optional = 0;
++      break;
 +#endif
 +
-   mx_fastclose_mailbox (ctx);
+     case 'Z':
+     
+       ch = ' ';
+@@ -676,7 +900,9 @@ hdr_format_str (char *dest,
+ 		hdr->tagged ? '*' :
+ 		(hdr->flagged ? '!' :
+ 		 (Tochars && ((i = mutt_user_is_recipient (hdr)) < mutt_strlen (Tochars)) ? Tochars[i] : ' ')));
+-      mutt_format_s (dest, destlen, prefix, buf2);
++      colorlen = add_index_color (dest, destlen, flags, MT_COLOR_INDEX_FLAGS);
++      mutt_format_s (dest + colorlen, destlen - colorlen, prefix, buf2);
++      add_index_color (dest + colorlen, destlen - colorlen, flags, MT_COLOR_INDEX);
+       break;
  
-   return 0;
-@@ -1005,9 +1241,10 @@
- #define this_body ctx->hdrs[j]->content
-   for (i = 0, j = 0; i < ctx->msgcount; i++)
-   {
--    if ((committing && (!ctx->hdrs[i]->deleted || 
-+    if (!ctx->hdrs[i]->quasi_deleted &&
-+	((committing && (!ctx->hdrs[i]->deleted ||
- 			(ctx->magic == M_MAILDIR && option (OPTMAILDIRTRASH)))) ||
--	(!committing && ctx->hdrs[i]->active))
-+	(!committing && ctx->hdrs[i]->active)))
-     {
-       if (i != j)
-       {
-@@ -1140,6 +1377,12 @@
-   msgcount = ctx->msgcount;
-   deleted = ctx->deleted;
+     case 'X':
+@@ -694,40 +920,100 @@ hdr_format_str (char *dest,
  
-+  if (purge && ctx->deleted && mutt_strcmp (ctx->path, TrashPath)) {
-+    if (trash_append (ctx) == -1) {
-+      return -1;
-+    }
-+  }
-+
- #ifdef USE_IMAP
-   if (ctx->magic == M_IMAP)
-     rc = imap_sync_mailbox (ctx, purge, index_hint);
-@@ -1301,6 +1544,11 @@
- {
-   int rc;
+      case 'y':
+        if (optional)
+-	 optional = hdr->env->x_label ? 1 : 0;
++	 optional = hdr->env->labels ? 1 : 0;
  
-+#ifdef USE_COMPRESSED
-+  if (ctx->compress_info)
-+    return comp_check_mailbox (ctx);
-+#endif
+-       mutt_format_s (dest, destlen, prefix, NONULL (hdr->env->x_label));
++       colorlen = add_index_color (dest, destlen, flags, MT_COLOR_INDEX_LABEL);
++       mutt_format_s (dest + colorlen, destlen - colorlen, prefix, mutt_labels(NULL, 0, hdr->env, NULL));
++       add_index_color (dest + colorlen, destlen - colorlen, flags, MT_COLOR_INDEX);
+        break;
+- 
 +
-   if (ctx)
-   {
-     if (ctx->locked) lock = 0;
-@@ -1349,6 +1597,16 @@
-       case M_POP:
- 	return (pop_check_mailbox (ctx, index_hint));
- #endif /* USE_POP */
+     case 'Y':
+-      if (hdr->env->x_label)
++      if (hdr->env->labels == NULL)
+       {
+-	i = 1;	/* reduce reuse recycle */
+-	htmp = NULL;
+-	if (flags & M_FORMAT_TREE
+-	    && (hdr->thread->prev && hdr->thread->prev->message
+-		&& hdr->thread->prev->message->env->x_label))
+-	  htmp = hdr->thread->prev->message;
+-	else if (flags & M_FORMAT_TREE
+-		 && (hdr->thread->parent && hdr->thread->parent->message
+-		     && hdr->thread->parent->message->env->x_label))
+-	  htmp = hdr->thread->parent->message;
+-	if (htmp && mutt_strcasecmp (hdr->env->x_label,
+-				     htmp->env->x_label) == 0)
+-	  i = 0;
++        if (optional)
++          optional = 0;
++        mutt_format_s(dest, destlen, prefix, "");
++        break;
+       }
+       else
+-	i = 0;
++      {
++        char labels[HUGE_STRING];
++        char labelstmp[HUGE_STRING];
 +
-+#ifdef USE_NOTMUCH
-+      case M_NOTMUCH:
-+	return nm_check_database(ctx, index_hint);
-+#endif
++        i = 1;  /* reduce reuse recycle */
++        htmp = NULL;
++        if ((flags & M_FORMAT_TREE) &&
++            hdr->thread->prev &&
++            hdr->thread->prev->message &&
++            hdr->thread->prev->message->env->labels)
++          htmp = hdr->thread->prev->message;
++        else if ((flags & M_FORMAT_TREE) &&
++                 hdr->thread->parent &&
++                 hdr->thread->parent->message &&
++                 hdr->thread->parent->message->env->labels)
++          htmp = hdr->thread->parent->message;
 +
-+#ifdef USE_NNTP
-+      case M_NNTP:
-+	return (nntp_check_mailbox (ctx, 0));
-+#endif /* USE_NNTP */
-     }
-   }
- 
-@@ -1360,7 +1618,7 @@
- MESSAGE *mx_open_message (CONTEXT *ctx, int msgno)
- {
-   MESSAGE *msg;
--  
++        mutt_labels(labels, sizeof(labels), hdr->env, NULL);
++        if (htmp)
++        {
++          mutt_labels(labelstmp, sizeof(labelstmp), htmp->env, NULL);
++          if (htmp && mutt_strcasecmp (labels, labelstmp) == 0)
++            i = 0;
++        }
 +
-   msg = safe_calloc (1, sizeof (MESSAGE));
-   switch (msg->magic = ctx->magic)
-   {
-@@ -1371,15 +1629,24 @@
- 
-     case M_MH:
-     case M_MAILDIR:
-+#ifdef USE_NOTMUCH
-+    case M_NOTMUCH:
-+#endif
-     {
-       HEADER *cur = ctx->hdrs[msgno];
-       char path[_POSIX_PATH_MAX];
--      
--      snprintf (path, sizeof (path), "%s/%s", ctx->path, cur->path);
--      
-+      char *folder = ctx->path;
-+#ifdef USE_NOTMUCH
-+      if (ctx->magic == M_NOTMUCH) {
-+	msg->magic = nm_header_get_magic(cur);
-+	folder = nm_header_get_folder(cur);
-+      }
-+#endif
-+      snprintf (path, sizeof (path), "%s/%s", folder, cur->path);
++        if (optional)
++	  optional = i;
 +
-       if ((msg->fp = fopen (path, "r")) == NULL && errno == ENOENT &&
--	  ctx->magic == M_MAILDIR)
--	msg->fp = maildir_open_find_message (ctx->path, cur->path);
-+	  (ctx->magic == M_MAILDIR || ctx->magic == M_NOTMUCH))
-+	msg->fp = maildir_open_find_message (folder, cur->path, NULL);
-       
-       if (msg->fp == NULL)
-       {
-@@ -1409,6 +1676,15 @@
-     }
- #endif /* USE_POP */
++        colorlen = add_index_color (dest, destlen, flags, MT_COLOR_INDEX_LABEL);
++        if (i)
++	  mutt_format_s (dest + colorlen, destlen - colorlen, prefix, labels);
++        else
++          mutt_format_s (dest + colorlen, destlen - colorlen, prefix, "");
++        add_index_color (dest + colorlen, destlen - colorlen, flags, MT_COLOR_INDEX);
++      }
++      break;
  
-+#ifdef USE_NNTP
-+    case M_NNTP:
+-      if (optional)
+-	optional = i;
++#ifdef USE_NOTMUCH
++    case 'G':
 +    {
-+      if (nntp_fetch_message (msg, ctx, msgno) != 0)
-+	FREE (&msg);
-+      break;
-+    }
-+#endif /* USE_NNTP */
-+
-     default:
-       dprint (1, (debugfile, "mx_open_message(): function not implemented for mailbox type %d.\n", ctx->magic));
-       FREE (&msg);
-@@ -1454,13 +1730,17 @@
-       break;
-     }
- #endif
--    
++      char *tag_transformed;
++      char format[3];
++      char *tag;
+ 
+-      if (i)
+-        mutt_format_s (dest, destlen, prefix, NONULL (hdr->env->x_label));
++      if (!optional)
++      {
++        format[0] = op;
++        format[1] = *src;
++        format[2] = 0;
 +
-     case M_MAILDIR:
-     {
-       r = maildir_commit_message (ctx, msg, NULL);
-       break;
-     }
--    
++        tag = hash_find(TagFormats, format);
++        if (tag != NULL)
++        {
++            tag_transformed = nm_header_get_tag_transformed(tag, hdr);
 +
-+    case M_NOTMUCH:
-+      mutt_perror _("Can't write to virtual folder.");
-+      break;
++            colorlen = add_index_color(dest, destlen, flags, MT_COLOR_INDEX_TAG);
++            mutt_format_s (dest+colorlen, destlen-colorlen, prefix,
++                           (tag_transformed) ? tag_transformed : "");
++            add_index_color(dest+colorlen, destlen-colorlen, flags, MT_COLOR_INDEX);
++        }
 +
-     case M_MH:
-     {
-       r = mh_commit_message (ctx, msg, NULL);
-@@ -1474,7 +1754,7 @@
-     mutt_perror _("Can't write message");
-     r = -1;
-   }
-- 
++        src++;
++      }
+       else
+-        mutt_format_s (dest, destlen, prefix, "");
++      {
++        format[0] = op;
++        format[1] = *prefix;
++        format[2] = 0;
 +
-   return r;
- }
- 
-@@ -1484,6 +1764,10 @@
-   int r = 0;
++        tag = hash_find(TagFormats, format);
++        if (tag != NULL)
++          if (nm_header_get_tag_transformed(tag, hdr) == NULL)
++            optional = 0;
++      }
  
-   if ((*msg)->magic == M_MH || (*msg)->magic == M_MAILDIR
-+#ifdef USE_NNTP
-+      || (*msg)->magic == M_NNTP
+       break;
++    }
 +#endif
-+      || (*msg)->magic == M_NOTMUCH
-       || (*msg)->magic == M_IMAP || (*msg)->magic == M_POP)
-   {
-     r = safe_fclose (&(*msg)->fp);
-@@ -1491,7 +1775,10 @@
-   else
-     (*msg)->fp = NULL;
  
--  if ((*msg)->path)
-+  dprint (2, (debugfile, "mx_close_message (): close: path=%s, commited=%s\n",
-+	(*msg)->path, (*msg)->commited_path));
-+
-+  if ((*msg)->path && (*msg)->magic != M_NOTMUCH)
-   {
-     dprint (1, (debugfile, "mx_close_message (): unlinking %s\n",
- 		(*msg)->path));
-@@ -1499,6 +1786,7 @@
-     FREE (&(*msg)->path);
+     default:
+       snprintf (dest, destlen, "%%%s%c", prefix, op);
+@@ -735,9 +1021,9 @@ hdr_format_str (char *dest,
    }
  
-+  FREE (&(*msg)->commited_path);
-   FREE (msg);		/* __FREE_CHECKED__ */
-   return (r);
- }
-diff -urN mutt-1.6.1/mx.h mutt-1.6.1-neomutt/mx.h
---- mutt-1.6.1/mx.h	2016-06-12 18:43:00.411447731 +0100
-+++ mutt-1.6.1-neomutt/mx.h	2016-06-12 18:43:00.719452534 +0100
-@@ -26,6 +26,7 @@
- #define _MX_H
+   if (optional)
+-    mutt_FormatString (dest, destlen, col, ifstring, hdr_format_str, (unsigned long) hfi, flags);
++    mutt_FormatString (dest, destlen, col, cols, ifstring, hdr_format_str, (unsigned long) hfi, flags);
+   else if (flags & M_FORMAT_OPTIONAL)
+-    mutt_FormatString (dest, destlen, col, elsestring, hdr_format_str, (unsigned long) hfi, flags);
++    mutt_FormatString (dest, destlen, col, cols, elsestring, hdr_format_str, (unsigned long) hfi, flags);
  
- #include "mailbox.h"
-+#include "buffy.h"
+   return (src);
+ #undef THREAD_NEW
+@@ -753,11 +1039,11 @@ _mutt_make_string (char *dest, size_t destlen, const char *s, CONTEXT *ctx, HEAD
+   hfi.ctx = ctx;
+   hfi.pager_progress = 0;
  
- /* supported mailbox formats */
- enum
-@@ -34,8 +35,15 @@
-   M_MMDF,
-   M_MH,
-   M_MAILDIR,
-+#ifdef USE_NNTP
-+  M_NNTP,
-+#endif
-   M_IMAP,
-+  M_NOTMUCH,
-   M_POP
-+#ifdef USE_COMPRESSED
-+  , M_COMPRESSED
-+#endif
- };
+-  mutt_FormatString (dest, destlen, 0, s, hdr_format_str, (unsigned long) &hfi, flags);
++  mutt_FormatString (dest, destlen, 0, COLS - SidebarWidth, s, hdr_format_str, (unsigned long) &hfi, flags);
+ }
  
- WHERE short DefaultMagic INITVAL (M_MBOX);
-@@ -57,19 +65,39 @@
- int mh_read_dir (CONTEXT *, const char *);
- int mh_sync_mailbox (CONTEXT *, int *);
- int mh_check_mailbox (CONTEXT *, int *);
-+#ifdef USE_SIDEBAR
-+void mh_buffy_update (BUFFY *mailbox);
+ void
+ mutt_make_string_info (char *dst, size_t dstlen, const char *s, struct hdr_format_info *hfi, format_flag flags)
+ {
+-  mutt_FormatString (dst, dstlen, 0, s, hdr_format_str, (unsigned long) hfi, flags);
++  mutt_FormatString (dst, dstlen, 0, COLS - SidebarWidth, s, hdr_format_str, (unsigned long) hfi, flags);
+ }
+diff --git a/headers.c b/headers.c
+index 0a75998..d1343ad 100644
+--- a/headers.c
++++ b/headers.c
+@@ -114,6 +114,9 @@ void mutt_edit_headers (const char *editor,
+      $edit_headers set, we remove References: as they're likely invalid;
+      we can simply compare strings as we don't generate References for
+      multiple Message-Ids in IRT anyways */
++#ifdef USE_NNTP
++  if (!option (OPTNEWSSEND))
 +#endif
- int mh_check_empty (const char *);
- 
- int maildir_read_dir (CONTEXT *);
- int maildir_check_mailbox (CONTEXT *, int *);
- int maildir_check_empty (const char *);
- 
-+HEADER *maildir_parse_message (int magic, const char *fname, int is_old, HEADER * _h);
-+HEADER *maildir_parse_stream (int magic, FILE *f, const char *fname, int is_old, HEADER * _h);
-+void maildir_parse_flags (HEADER * h, const char *path);
-+void maildir_update_flags (CONTEXT *ctx, HEADER *o, HEADER *n);
-+void maildir_flags(char *dest, size_t destlen, HEADER * hdr);
+   if (msg->env->in_reply_to &&
+       (!n->in_reply_to || mutt_strcmp (n->in_reply_to->data,
+ 				       msg->env->in_reply_to->data) != 0))
+@@ -211,3 +214,199 @@ void mutt_edit_headers (const char *editor,
+     }
+   }
+ }
++
++void mutt_label_ref_dec(ENVELOPE *env)
++{
++  uintptr_t count;
++  LIST *label;
++
++  if (!env || !env->labels || !Labels)
++    return;
++
++  for (label = env->labels; label; label = label->next)
++  {
++    if (label->data == NULL)
++      continue;
++    count = (uintptr_t)hash_find(Labels, label->data);
++    if (count)
++    {
++      hash_delete(Labels, label->data, NULL, NULL);
++      count--;
++      if (count > 0)
++        hash_insert(Labels, label->data, (void *)count, 0);
++    }
++    dprint(1, (debugfile, "--label %s: %d\n", label->data, count));
++  }
++}
++
++void mutt_label_ref_inc(ENVELOPE *env)
++{
++  uintptr_t count;
++  LIST *label;
++
++  if (!env || !env->labels || !Labels)
++    return;
++
++  for (label = env->labels; label; label = label->next)
++  {
++    if (label->data == NULL)
++      continue;
++    count = (uintptr_t)hash_find(Labels, label->data);
++    if (count)
++      hash_delete(Labels, label->data, NULL, NULL);
++    count++;  /* was zero if not found */
++    hash_insert(Labels, label->data, (void *)count, 0);
++    dprint(1, (debugfile, "++label %s: %d\n", label->data, count));
++  }
++}
++
++/*
++ * set labels on a message
++ */
++static int label_message(HEADER *hdr, char *new)
++{
++  if (hdr == NULL)
++    return 0;
++  if (hdr->env->labels == NULL && new == NULL)
++    return 0;
++  if (hdr->env->labels != NULL && new != NULL)
++  {
++    char old[HUGE_STRING];
++    mutt_labels(old, sizeof(old), hdr->env, NULL);
++    if (!strcmp(old, new))
++      return 0;
++  }
++
++  if (hdr->env->labels != NULL)
++  {
++    mutt_label_ref_dec(hdr->env);
++    mutt_free_list(&hdr->env->labels);
++  }
++
++  if (new == NULL)
++    hdr->env->labels = NULL;
++  else
++  {
++    char *last, *label;
++
++    for (label = strtok_r(new, ",", &last); label;
++         label = strtok_r(NULL, ",", &last)) 
++    {
++      SKIPWS(label);
++      if (mutt_find_list(hdr->env->labels, label))
++        continue;
++      if (hdr->env->labels == NULL)
++      {
++        hdr->env->labels = mutt_new_list();
++        hdr->env->labels->data = safe_strdup(label);
++      }
++      else
++        mutt_add_list(hdr->env->labels, label);
++    }
++    mutt_label_ref_inc(hdr->env);
++  }
++  return hdr->changed = hdr->label_changed = 1;
++}
 +
-+#if USE_HCACHE
-+#include <hcache.h>
-+int mh_sync_mailbox_message (CONTEXT * ctx, int msgno, header_cache_t *hc);
-+#else
-+int mh_sync_mailbox_message (CONTEXT * ctx, int msgno);
-+#endif
++int mutt_label_message(HEADER *hdr)
++{
++  char buf[LONG_STRING], *new;
++  int i;
++  int changed;
 +
-+#ifdef USE_NOTMUCH
-+int mx_is_notmuch(const char *p);
-+#endif
++  *buf = '\0';
++  if (hdr != NULL && hdr->env->labels != NULL)
++    mutt_labels(buf, sizeof(buf)-2, hdr->env, NULL);
 +
- int maildir_commit_message (CONTEXT *, MESSAGE *, HEADER *);
- int mh_commit_message (CONTEXT *, MESSAGE *, HEADER *);
- 
- int maildir_open_new_message (MESSAGE *, CONTEXT *, HEADER *);
- int mh_open_new_message (MESSAGE *, CONTEXT *, HEADER *);
- 
--FILE *maildir_open_find_message (const char *, const char *);
-+FILE *maildir_open_find_message (const char *, const char *, char **);
- 
- int mbox_strict_cmp_headers (const HEADER *, const HEADER *);
- int mutt_reopen_mailbox (CONTEXT *, int *);
-diff -urN mutt-1.6.1/newsrc.c mutt-1.6.1-neomutt/newsrc.c
---- mutt-1.6.1/newsrc.c	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/newsrc.c	2016-06-12 18:43:00.720452549 +0100
-@@ -0,0 +1,1262 @@
-+/*
-+ * Copyright (C) 1998 Brandon Long <blong at fiction.net>
-+ * Copyright (C) 1999 Andrej Gritsenko <andrej at lucky.net>
-+ * Copyright (C) 2000-2012 Vsevolod Volkov <vvv at mutt.org.ua>
-+ *
-+ *     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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ */
++  /* add a comma-space so that new typing is a new keyword */
++  if (buf[0])
++    strcat(buf, ", ");    /* __STRCAT_CHECKED__ */
 +
-+#if HAVE_CONFIG_H
-+#include "config.h"
-+#endif
++  if (mutt_get_field("Label: ", buf, sizeof(buf), M_LABEL /* | M_CLEAR */) != 0)
++    return 0;
 +
-+#include "mutt.h"
-+#include "mutt_curses.h"
-+#include "sort.h"
-+#include "mx.h"
-+#include "mime.h"
-+#include "mailbox.h"
-+#include "nntp.h"
-+#include "rfc822.h"
-+#include "rfc1524.h"
-+#include "rfc2047.h"
-+#include "bcache.h"
++  new = buf;
++  SKIPWS(new);
++  if (new && *new)
++  {
++    char *p;
++    int len = strlen(new);
++    p = &new[len]; /* '\0' */
++    while (p > new)
++    {
++      if (!isspace((unsigned char)*(p-1)) && *(p-1) != ',')
++        break;
++      p--;
++    }
++    *p = '\0';
++  }
++  if (*new == '\0')
++    new = NULL;
 +
-+#if USE_HCACHE
-+#include "hcache.h"
-+#endif
++  changed = 0;
++  if (hdr != NULL) {
++    changed += label_message(hdr, new);
++  } else {
++#define HDR_OF(index) Context->hdrs[Context->v2r[(index)]]
++    for (i = 0; i < Context->vcount; ++i) {
++      if (HDR_OF(i)->tagged)
++        if (label_message(HDR_OF(i), new)) {
++          ++changed;
++          mutt_set_flag(Context, HDR_OF(i),
++            M_TAG, 0);
++        }
++    }
++  }
 +
-+#include <unistd.h>
-+#include <string.h>
-+#include <ctype.h>
-+#include <stdlib.h>
-+#include <sys/stat.h>
-+#include <sys/types.h>
-+#include <dirent.h>
-+#include <errno.h>
++  return changed;
++}
 +
-+/* Find NNTP_DATA for given newsgroup or add it */
-+static NNTP_DATA *nntp_data_find (NNTP_SERVER *nserv, const char *group)
++/* scan a context (mailbox) and hash all labels we find */
++void mutt_scan_labels(CONTEXT *ctx)
 +{
-+  NNTP_DATA *nntp_data = hash_find (nserv->groups_hash, group);
++  int i;
 +
-+  if (!nntp_data)
++  if (!ctx)
++    return;
++
++  for (i = 0; i < ctx->msgcount; i++)
++    if (ctx->hdrs[i]->env->labels)
++      mutt_label_ref_inc(ctx->hdrs[i]->env);
++}
++
++
++char *mutt_labels(char *dst, int sz, ENVELOPE *env, char *sep)
++{
++  static char sbuf[HUGE_STRING];
++  int off = 0;
++  int len;
++  LIST *label;
++
++  if (sep == NULL)
++    sep = ", ";
++
++  if (dst == NULL)
 +  {
-+    /* create NNTP_DATA structure and add it to hash */
-+    nntp_data = safe_calloc (1, sizeof (NNTP_DATA) + strlen (group) + 1);
-+    nntp_data->group = (char *)nntp_data + sizeof (NNTP_DATA);
-+    strcpy (nntp_data->group, group);
-+    nntp_data->nserv = nserv;
-+    nntp_data->deleted = 1;
-+    if (nserv->groups_hash->nelem < nserv->groups_hash->curnelem * 2)
-+      nserv->groups_hash = hash_resize (nserv->groups_hash,
-+			   nserv->groups_hash->nelem * 2, 0);
-+    hash_insert (nserv->groups_hash, nntp_data->group, nntp_data, 0);
++    dst = sbuf;
++    sz = sizeof(sbuf);
++  }
 +
-+    /* add NNTP_DATA to list */
-+    if (nserv->groups_num >= nserv->groups_max)
++  *dst = '\0';
++
++  for (label = env->labels; label; label = label->next)
++  {
++    if (label->data == NULL)
++      continue;
++    len = MIN(mutt_strlen(label->data), sz-off);
++    strfcpy(&dst[off], label->data, len+1);
++    off += len;
++    if (label->next)
 +    {
-+      nserv->groups_max *= 2;
-+      safe_realloc (&nserv->groups_list,
-+		    nserv->groups_max * sizeof (nntp_data));
++      len = MIN(mutt_strlen(sep), sz-off);
++      strfcpy(&dst[off], sep, len+1);
++      off += len;
 +    }
-+    nserv->groups_list[nserv->groups_num++] = nntp_data;
 +  }
-+  return nntp_data;
++
++  return dst;
 +}
+diff --git a/hook.c b/hook.c
+index a89b615..98c2f26 100644
+--- a/hook.c
++++ b/hook.c
+@@ -24,6 +24,10 @@
+ #include "mailbox.h"
+ #include "mutt_crypt.h"
+ 
++#ifdef USE_COMPRESSED
++#include "compress.h"
++#endif
 +
-+/* Remove all temporarily cache files */
-+void nntp_acache_free (NNTP_DATA *nntp_data)
-+{
-+  int i;
+ #include <limits.h>
+ #include <string.h>
+ #include <stdlib.h>
+@@ -109,6 +113,14 @@ int mutt_parse_hook (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
+     memset (&pattern, 0, sizeof (pattern));
+     pattern.data = safe_strdup (path);
+   }
++#ifdef USE_COMPRESSED
++  else if (data & (M_APPENDHOOK | M_OPENHOOK | M_CLOSEHOOK)) {
++    if (comp_valid_command (command.data) == 0) {
++      strfcpy (err->data, _("badly formatted command string"), err->dsize);
++      return -1;
++    }
++  }
++#endif
+   else if (DefaultHook && !(data & (M_CHARSETHOOK | M_ICONVHOOK | M_ACCOUNTHOOK))
+            && (!WithCrypto || !(data & M_CRYPTHOOK))
+       )
+@@ -362,7 +374,7 @@ void mutt_message_hook (CONTEXT *ctx, HEADER *hdr, int type)
+ 
+     if (hook->type & type)
+       if ((mutt_pattern_exec (hook->pattern, 0, ctx, hdr) > 0) ^ hook->rx.not)
+-	if (mutt_parse_rc_line (hook->command, &token, &err) != 0)
++	if (mutt_parse_rc_line (hook->command, &token, &err) == -1)
+ 	{
+ 	  FREE (&token.data);
+ 	  mutt_error ("%s", err.data);
+diff --git a/imap/command.c b/imap/command.c
+index d99a99a..b5c896d 100644
+--- a/imap/command.c
++++ b/imap/command.c
+@@ -900,6 +900,7 @@ static void cmd_parse_status (IMAP_DATA* idata, char* s)
+   IMAP_STATUS *status;
+   unsigned int olduv, oldun;
+   long litlen;
++  short new = 0;
+ 
+   mailbox = imap_next_word (s);
+ 
+@@ -1000,16 +1001,26 @@ static void cmd_parse_status (IMAP_DATA* idata, char* s)
+ 	  if (olduv && olduv == status->uidvalidity)
+ 	  {
+ 	    if (oldun < status->uidnext)
+-	      inc->new = status->unseen;
++	      new = (status->unseen > 0);
+ 	  }
+ 	  else if (!olduv && !oldun)
+ 	    /* first check per session, use recent. might need a flag for this. */
+-	    inc->new = status->recent;
++	    new = (status->recent > 0);
+ 	  else
+-	    inc->new = status->unseen;
++	    new = (status->unseen > 0);
+ 	}
+ 	else
+-          inc->new = status->unseen;
++          new = (status->unseen > 0);
 +
-+  for (i = 0; i < NNTP_ACACHE_LEN; i++)
-+  {
-+    if (nntp_data->acache[i].path)
++#ifdef USE_SIDEBAR
++        if ((inc->new != new) ||
++            (inc->msg_count != status->messages) ||
++            (inc->msg_unread != status->unseen))
++          SidebarNeedsRedraw = 1;
++#endif
++        inc->new = new;
++        inc->msg_count  = status->messages;
++        inc->msg_unread = status->unseen;
+ 
+ 	if (inc->new)
+ 	  /* force back to keep detecting new mail until the mailbox is
+diff --git a/imap/imap.c b/imap/imap.c
+index 1b63b3a..feb06ef 100644
+--- a/imap/imap.c
++++ b/imap/imap.c
+@@ -589,7 +589,9 @@ int imap_open_mailbox (CONTEXT* ctx)
+   imap_qualify_path (buf, sizeof (buf), &mx, idata->mailbox);
+ 
+   FREE (&(ctx->path));
++  FREE (&(ctx->realpath));
+   ctx->path = safe_strdup (buf);
++  ctx->realpath = safe_strdup (ctx->path);
+ 
+   idata->ctx = ctx;
+ 
+@@ -888,6 +890,12 @@ static int imap_make_msg_set (IMAP_DATA* idata, BUFFER* buf, int flag,
+           if (hdrs[n]->deleted != HEADER_DATA(hdrs[n])->deleted)
+             match = invert ^ hdrs[n]->deleted;
+ 	  break;
++        case M_EXPIRED: /* imap_fast_trash version of M_DELETED */
++	  if (hdrs[n]->purged)
++	    break;
++          if (hdrs[n]->deleted != HEADER_DATA(hdrs[n])->deleted)
++            match = invert ^ (hdrs[n]->deleted && !hdrs[n]->appended);
++	  break;
+         case M_FLAG:
+           if (hdrs[n]->flagged != HEADER_DATA(hdrs[n])->flagged)
+             match = invert ^ hdrs[n]->flagged;
+@@ -1222,7 +1230,7 @@ int imap_sync_mailbox (CONTEXT* ctx, int expunge, int* index_hint)
+        * we delete the message and reupload it.
+        * This works better if we're expunging, of course. */
+       if ((h->env && (h->env->refs_changed || h->env->irt_changed)) ||
+-	  h->attach_del)
++	  h->attach_del || h->label_changed)
+       {
+         mutt_message (_("Saving changed messages... [%d/%d]"), n+1,
+                       ctx->msgcount);
+@@ -1232,6 +1240,7 @@ int imap_sync_mailbox (CONTEXT* ctx, int expunge, int* index_hint)
+ 	  dprint (1, (debugfile, "imap_sync_mailbox: Error opening mailbox in append mode\n"));
+ 	else
+ 	  _mutt_save_message (h, appendctx, 1, 0, 0);
++	h->label_changed = 0;
+       }
+     }
+   }
+@@ -1479,7 +1488,7 @@ static int imap_get_mailbox (const char* path, IMAP_DATA** hidata, char* buf, si
+ /* check for new mail in any subscribed mailboxes. Given a list of mailboxes
+  * rather than called once for each so that it can batch the commands and
+  * save on round trips. Returns number of mailboxes with new mail. */
+-int imap_buffy_check (int force)
++int imap_buffy_check (int force, int check_stats)
+ {
+   IMAP_DATA* idata;
+   IMAP_DATA* lastdata = NULL;
+@@ -1501,17 +1510,21 @@ int imap_buffy_check (int force)
+     if (mailbox->magic != M_IMAP)
+       continue;
+ 
+-    mailbox->new = 0;
+-
+     if (imap_get_mailbox (mailbox->path, &idata, name, sizeof (name)) < 0)
 +    {
-+      unlink (nntp_data->acache[i].path);
-+      FREE (&nntp_data->acache[i].path);
++      mailbox->new = 0;
+       continue;
++    }
+ 
+     /* Don't issue STATUS on the selected mailbox, it will be NOOPed or
+      * IDLEd elsewhere.
+      * idata->mailbox may be NULL for connections other than the current
+      * mailbox's, and shouldn't expand to INBOX in that case. #3216. */
+     if (idata->mailbox && !imap_mxcmp (name, idata->mailbox))
++    {
++      mailbox->new = 0;
+       continue;
 +    }
-+  }
-+}
-+
-+/* Free NNTP_DATA, used to destroy hash elements */
-+void nntp_data_free (void *data)
-+{
-+  NNTP_DATA *nntp_data = data;
-+
-+  if (!nntp_data)
-+    return;
-+  nntp_acache_free (nntp_data);
-+  mutt_bcache_close (&nntp_data->bcache);
-+  FREE (&nntp_data->newsrc_ent);
-+  FREE (&nntp_data->desc);
-+  FREE (&data);
-+}
-+
-+/* Unlock and close .newsrc file */
-+void nntp_newsrc_close (NNTP_SERVER *nserv)
-+{
-+  if (!nserv->newsrc_fp)
-+    return;
-+
-+  dprint (1, (debugfile, "Unlocking %s\n", nserv->newsrc_file));
-+  mx_unlock_file (nserv->newsrc_file, fileno (nserv->newsrc_fp), 0);
-+  safe_fclose (&nserv->newsrc_fp);
-+}
+ 
+     if (!mutt_bit_isset (idata->capabilities, IMAP4REV1) &&
+         !mutt_bit_isset (idata->capabilities, STATUS))
+@@ -1534,7 +1547,11 @@ int imap_buffy_check (int force)
+       lastdata = idata;
+ 
+     imap_munge_mbox_name (idata, munged, sizeof (munged), name);
+-    snprintf (command, sizeof (command),
++    if (check_stats)
++      snprintf (command, sizeof (command),
++	      "STATUS %s (UIDNEXT UIDVALIDITY UNSEEN RECENT MESSAGES)", munged);
++    else
++      snprintf (command, sizeof (command),
+ 	      "STATUS %s (UIDNEXT UIDVALIDITY UNSEEN RECENT)", munged);
+ 
+     if (imap_exec (idata, command, IMAP_CMD_QUEUE) < 0)
+@@ -2038,3 +2055,53 @@ int imap_complete(char* dest, size_t dlen, char* path) {
+ 
+   return -1;
+ }
 +
-+/* Parse .newsrc file:
-+ *  0 - not changed
-+ *  1 - parsed
-+ * -1 - error */
-+int nntp_newsrc_parse (NNTP_SERVER *nserv)
++/**
++ * imap_fast_trash - XXX
++ */
++int
++imap_fast_trash (void)
 +{
-+  unsigned int i;
-+  char *line;
-+  struct stat sb;
++	if ((Context->magic == M_IMAP) && mx_is_imap (TrashPath)) {
++		IMAP_MBOX mx;
++		IMAP_DATA *idata = (IMAP_DATA *) Context->data;
++		char mbox[LONG_STRING];
++		char mmbox[LONG_STRING];
++		int rc;
++		dprint (1, (debugfile, "[itf] trashcan seems to be on imap.\n"));
 +
-+  /* if file doesn't exist, create it */
-+  nserv->newsrc_fp = safe_fopen (nserv->newsrc_file, "a");
-+  safe_fclose (&nserv->newsrc_fp);
++		if (imap_parse_path (TrashPath, &mx) == 0) {
++			if (mutt_account_match (&(idata->conn->account), &(mx.account))) {
++				dprint (1, (debugfile, "[itf] trashcan seems to be on the same account.\n"));
 +
-+  /* open .newsrc */
-+  nserv->newsrc_fp = safe_fopen (nserv->newsrc_file, "r");
-+  if (!nserv->newsrc_fp)
-+  {
-+    mutt_perror (nserv->newsrc_file);
-+    mutt_sleep (2);
-+    return -1;
-+  }
++				imap_fix_path (idata, mx.mbox, mbox, sizeof (mbox));
++				if (!*mbox)
++					strfcpy (mbox, "INBOX", sizeof (mbox));
++				imap_munge_mbox_name (idata, mmbox, sizeof (mmbox), mbox);
 +
-+  /* lock it */
-+  dprint (1, (debugfile, "Locking %s\n", nserv->newsrc_file));
-+  if (mx_lock_file (nserv->newsrc_file, fileno (nserv->newsrc_fp), 0, 0, 1))
-+  {
-+    safe_fclose (&nserv->newsrc_fp);
-+    return -1;
-+  }
++				rc = imap_exec_msgset (idata, "UID COPY", mmbox, M_EXPIRED, 0, 0);
++				if (rc == 0) {
++					dprint (1, (debugfile, "imap_copy_messages: No messages del-tagged\n"));
++					rc = -1;
++					goto old_way;
++				} else if (rc < 0) {
++					dprint (1, (debugfile, "could not queue copy\n"));
++					goto old_way;
++				} else {
++					mutt_message (_("Copying %d messages to %s..."), rc, mbox);
++					return 0;
++				}
++			} else {
++				dprint (1, (debugfile, "[itf] trashcan seems to be on a different account.\n"));
++			}
++old_way:
++			FREE(&mx.mbox); /* we probably only need to free this when the parse works */
++		} else {
++			dprint (1, (debugfile, "[itf] failed to parse TrashPath.\n"));
++		}
 +
-+  if (stat (nserv->newsrc_file, &sb))
-+  {
-+    mutt_perror (nserv->newsrc_file);
-+    nntp_newsrc_close (nserv);
-+    mutt_sleep (2);
-+    return -1;
-+  }
++		dprint (1, (debugfile, "[itf] giving up and trying old fasioned way.\n"));
++	}
 +
-+  if (nserv->size == sb.st_size && nserv->mtime == sb.st_mtime)
-+    return 0;
++	return 1;
++}
+diff --git a/imap/imap.h b/imap/imap.h
+index a914b40..4fc8ab3 100644
+--- a/imap/imap.h
++++ b/imap/imap.h
+@@ -39,7 +39,7 @@ int imap_open_mailbox (CONTEXT *ctx);
+ int imap_open_mailbox_append (CONTEXT *ctx);
+ int imap_sync_mailbox (CONTEXT *ctx, int expunge, int *index_hint);
+ int imap_close_mailbox (CONTEXT *ctx);
+-int imap_buffy_check (int force);
++int imap_buffy_check (int force, int check_stats);
+ int imap_status (char *path, int queue);
+ int imap_search (CONTEXT* ctx, const pattern_t* pat);
+ int imap_subscribe (char *path, int subscribe);
+@@ -72,4 +72,7 @@ void imap_keepalive (void);
+ 
+ int imap_account_match (const ACCOUNT* a1, const ACCOUNT* a2);
+ 
++/* trash */
++int imap_fast_trash (void);
 +
-+  nserv->size = sb.st_size;
-+  nserv->mtime = sb.st_mtime;
-+  nserv->newsrc_modified = 1;
-+  dprint (1, (debugfile, "Parsing %s\n", nserv->newsrc_file));
+ #endif
+diff --git a/imap/message.c b/imap/message.c
+index 02a726f..3280f5d 100644
+--- a/imap/message.c
++++ b/imap/message.c
+@@ -69,7 +69,7 @@ int imap_read_headers (IMAP_DATA* idata, int msgbegin, int msgend)
+   int rc, mfhrc, oldmsgcount;
+   int fetchlast = 0;
+   int maxuid = 0;
+-  static const char * const want_headers = "DATE FROM SUBJECT TO CC MESSAGE-ID REFERENCES CONTENT-TYPE CONTENT-DESCRIPTION IN-REPLY-TO REPLY-TO LINES LIST-POST X-LABEL";
++  static const char * const want_headers = "DATE FROM SUBJECT TO CC MESSAGE-ID REFERENCES CONTENT-TYPE CONTENT-DESCRIPTION IN-REPLY-TO REPLY-TO LINES LIST-POST X-LABEL X-KEYWORDS X-MOZILLA-KEYS KEYWORDS";
+   progress_t progress;
+   int retval = -1;
+ 
+@@ -406,6 +406,7 @@ int imap_fetch_message (MESSAGE *msg, CONTEXT *ctx, int msgno)
+   IMAP_CACHE *cache;
+   int read;
+   int rc;
 +
-+  /* .newsrc has been externally modified or hasn't been loaded yet */
-+  for (i = 0; i < nserv->groups_num; i++)
-+  {
-+    NNTP_DATA *nntp_data = nserv->groups_list[i];
+   /* Sam's weird courier server returns an OK response even when FETCH
+    * fails. Thanks Sam. */
+   short fetched = 0;
+@@ -886,6 +887,7 @@ int imap_copy_messages (CONTEXT* ctx, HEADER* h, char* dest, int delete)
+         if (ctx->hdrs[n]->tagged)
+         {
+           mutt_set_flag (ctx, ctx->hdrs[n], M_DELETE, 1);
++          mutt_set_flag (ctx, ctx->hdrs[n], M_APPENDED, 1);
+           if (option (OPTDELETEUNTAG))
+             mutt_set_flag (ctx, ctx->hdrs[n], M_TAG, 0);
+         }
+@@ -893,6 +895,7 @@ int imap_copy_messages (CONTEXT* ctx, HEADER* h, char* dest, int delete)
+     else
+     {
+       mutt_set_flag (ctx, h, M_DELETE, 1);
++      mutt_set_flag (ctx, h, M_APPENDED, 1);
+       if (option (OPTDELETEUNTAG))
+         mutt_set_flag (ctx, h, M_TAG, 0);
+     }
+diff --git a/init.c b/init.c
+index 69e2f76..b22e8e9 100644
+--- a/init.c
++++ b/init.c
+@@ -32,12 +32,15 @@
+ #include "mutt_crypt.h"
+ #include "mutt_idna.h"
+ #include "group.h"
++#include "version.h"
+ 
+ #if defined(USE_SSL)
+ #include "mutt_ssl.h"
+ #endif
+ 
+-
++#if USE_NOTMUCH
++#include "mutt_notmuch.h"
++#endif
+ 
+ #include "mx.h"
+ #include "init.h"
+@@ -76,6 +79,12 @@ 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);
+ 
++#if USE_NOTMUCH
++/* List of tags found in last call to mutt_nm_query_complete(). */
++static char **nm_tags;
++#endif
 +
-+    if (!nntp_data)
-+      continue;
 +
-+    nntp_data->subscribed = 0;
-+    nntp_data->newsrc_len = 0;
-+    FREE (&nntp_data->newsrc_ent);
-+  }
+ static void toggle_quadoption (int opt)
+ {
+   int n = opt/4;
+@@ -601,6 +610,113 @@ static void remove_from_list (LIST **l, const char *str)
+   }
+ }
+ 
++/**
++ * finish_source - 'finish' command: stop processing current config file
++ * @tmp:  Temporary space shared by all command handlers
++ * @s:    Current line of the config file
++ * @data: data field from init.h:struct command_t
++ * @err:  Buffer for any error message
++ *
++ * If the 'finish' command is found, we should stop reading the current file.
++ *
++ * Returns:
++ *	 1 Stop processing the current file
++ *	-1 Failed
++ */
++static int finish_source (BUFFER *tmp, BUFFER *s, unsigned long data, BUFFER *err)
++{
++	if (MoreArgs (s)) {
++		snprintf (err->data, err->dsize, _("finish: too many arguments"));
++		return -1;
++	}
 +
-+  line = safe_malloc (sb.st_size + 1);
-+  while (sb.st_size && fgets (line, sb.st_size + 1, nserv->newsrc_fp))
-+  {
-+    char *b, *h, *p;
-+    unsigned int subs = 0, i = 1;
-+    NNTP_DATA *nntp_data;
++	return 1;
++}
 +
-+    /* find end of newsgroup name */
-+    p = strpbrk (line, ":!");
-+    if (!p)
-+      continue;
++/**
++ * parse_ifdef - 'ifdef' command: conditional config
++ * @tmp:  Temporary space shared by all command handlers
++ * @s:    Current line of the config file
++ * @data: data field from init.h:struct command_t
++ * @err:  Buffer for any error message
++ *
++ * The 'ifdef' command allows conditional elements in the config file.
++ * If a given variable, function, command or compile-time symbol exists, then
++ * read the rest of the line of config commands.
++ * e.g.
++ *	ifdef USE_SIDEBAR source ~/.mutt/sidebar.rc
++ *
++ * If (data == 1) then it means use the 'ifndef' (if-not-defined) command.
++ * e.g.
++ *	ifndef USE_IMAP finish
++ *
++ * Returns:
++ *	 0 Success
++ *	-1 Failed
++ */
++static int parse_ifdef (BUFFER *tmp, BUFFER *s, unsigned long data, BUFFER *err)
++{
++	int i, j, res = 0;
++	BUFFER token;
 +
-+    /* ":" - subscribed, "!" - unsubscribed */
-+    if (*p == ':')
-+      subs++;
-+    *p++ = '\0';
++	memset (&token, 0, sizeof (token));
++	mutt_extract_token (tmp, s, 0);
 +
-+    /* get newsgroup data */
-+    nntp_data = nntp_data_find (nserv, line);
-+    FREE (&nntp_data->newsrc_ent);
++	/* is the item defined as a variable? */
++	res = (mutt_option_index (tmp->data) != -1);
 +
-+    /* count number of entries */
-+    b = p;
-+    while (*b)
-+      if (*b++ == ',')
-+	i++;
-+    nntp_data->newsrc_ent = safe_calloc (i, sizeof (NEWSRC_ENTRY));
-+    nntp_data->subscribed = subs;
++	/* is the item a compiled-in feature? */
++	if (!res) {
++		res = feature_enabled (tmp->data);
++	}
 +
-+    /* parse entries */
-+    i = 0;
-+    while (p)
-+    {
-+      b = p;
++	/* or a function? */
++	if (!res) {
++		for (i = 0; !res && (i < MENU_MAX); i++) {
++			const struct binding_t *b = km_get_table (Menus[i].value);
++			if (!b)
++				continue;
 +
-+      /* find end of entry */
-+      p = strchr (p, ',');
-+      if (p)
-+	*p++ = '\0';
++			for (j = 0; b[j].name; j++) {
++				if (mutt_strcmp (tmp->data, b[j].name) == 0) {
++					res = 1;
++					break;
++				}
++			}
++		}
++	}
 +
-+      /* first-last or single number */
-+      h = strchr (b, '-');
-+      if (h)
-+	*h++ = '\0';
-+      else
-+	h = b;
++	/* or a command? */
++	if (!res) {
++		for (i = 0; Commands[i].name; i++) {
++			if (mutt_strcmp (tmp->data, Commands[i].name) == 0) {
++				res = 1;
++				break;
++			}
++		}
++	}
 +
-+      if (sscanf (b, ANUM, &nntp_data->newsrc_ent[i].first) == 1 &&
-+	  sscanf (h, ANUM, &nntp_data->newsrc_ent[i].last) == 1)
-+	i++;
-+    }
-+    if (i == 0)
-+    {
-+	nntp_data->newsrc_ent[i].first = 1;
-+	nntp_data->newsrc_ent[i].last = 0;
-+	i++;
-+    }
-+    if (nntp_data->lastMessage == 0)
-+      nntp_data->lastMessage = nntp_data->newsrc_ent[i - 1].last;
-+    nntp_data->newsrc_len = i;
-+    safe_realloc (&nntp_data->newsrc_ent, i * sizeof (NEWSRC_ENTRY));
-+    nntp_group_unread_stat (nntp_data);
-+    dprint (2, (debugfile, "nntp_newsrc_parse: %s\n", nntp_data->group));
-+  }
-+  FREE (&line);
-+  return 1;
++	if (!MoreArgs (s)) {
++		snprintf (err->data, err->dsize, _("%s: too few arguments"),
++			(data ? "ifndef" : "ifdef"));
++		return -1;
++	}
++	mutt_extract_token (tmp, s, M_TOKEN_SPACE);
++
++        /* ifdef KNOWN_SYMBOL or ifndef UNKNOWN_SYMBOL */
++	if ((res && (data == 0)) || (!res && (data == 1))) {
++                int rc = mutt_parse_rc_line (tmp->data, &token, err);
++		if (rc == -1) {
++			mutt_error ("Error: %s", err->data);
++			FREE(&token.data);
++			return -1;
++		}
++		FREE(&token.data);
++                return rc;
++	}
++	return 0;
 +}
 +
-+/* Generate array of .newsrc entries */
-+void nntp_newsrc_gen_entries (CONTEXT *ctx)
-+{
-+  NNTP_DATA *nntp_data = ctx->data;
-+  anum_t last = 0, first = 1;
-+  int series, i;
-+  int save_sort = SORT_ORDER;
-+  unsigned int entries;
+ static int parse_unignore (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
+ {
+   do
+@@ -1611,6 +1727,10 @@ static void mutt_restore_default (struct option_t *p)
+     set_option (OPTRESORTINIT);
+   if (p->flags & R_TREE)
+     set_option (OPTREDRAWTREE);
++#ifdef USE_SIDEBAR
++  if (p->flags & R_SIDEBAR)
++    SidebarNeedsRedraw = 1;
++#endif
+ }
+ 
+ static size_t escape_string (char *dst, size_t len, const char* src)
+@@ -2173,6 +2293,9 @@ static int parse_set (BUFFER *tmp, BUFFER *s, unsigned long data, BUFFER *err)
+ 	case DT_SORT_AUX:
+ 	  map = SortAuxMethods;
+ 	  break;
++	case DT_SORT_SIDEBAR:
++	  map = SortSidebarMethods;
++	  break;
+ 	default:
+ 	  map = SortMethods;
+ 	  break;
+@@ -2226,6 +2349,10 @@ static int parse_set (BUFFER *tmp, BUFFER *s, unsigned long data, BUFFER *err)
+         set_option (OPTRESORTINIT);
+       if (MuttVars[idx].flags & R_TREE)
+         set_option (OPTREDRAWTREE);
++#ifdef USE_SIDEBAR
++      if (MuttVars[idx].flags & R_SIDEBAR)
++        SidebarNeedsRedraw = 1;
++#endif
+     }
+   }
+   return (r);
+@@ -2238,7 +2365,7 @@ static int parse_set (BUFFER *tmp, BUFFER *s, unsigned long data, BUFFER *err)
+ static int source_rc (const char *rcfile, BUFFER *err)
+ {
+   FILE *f;
+-  int line = 0, rc = 0, conv = 0;
++  int line = 0, rc = 0, conv = 0, line_rc;
+   BUFFER token;
+   char *linebuf = NULL;
+   char *currentline = NULL;
+@@ -2267,17 +2394,17 @@ static int source_rc (const char *rcfile, BUFFER *err)
+     else 
+       currentline=linebuf;
+ 
+-    if (mutt_parse_rc_line (currentline, &token, err) == -1)
+-    {
++    line_rc = mutt_parse_rc_line (currentline, &token, err);
++    if (line_rc == -1) {
+       mutt_error (_("Error in %s, line %d: %s"), rcfile, line, err->data);
+       if (--rc < -MAXERRS) 
+       {
+         if (conv) FREE(&currentline);
+         break;
+       }
+-    }
+-    else
+-    {
++    } else if (line_rc == 1) {
++      break;	/* Found "finish" command */
++    } else {
+       if (rc < 0)
+         rc = -1;
+     }
+@@ -2332,7 +2459,7 @@ static int parse_source (BUFFER *tmp, BUFFER *s, unsigned long data, BUFFER *err
+    err		where to write error messages */
+ int mutt_parse_rc_line (/* const */ char *line, BUFFER *token, BUFFER *err)
+ {
+-  int i, r = -1;
++  int i, r = 0;
+   BUFFER expn;
+ 
+   if (!line || !*line)
+@@ -2359,22 +2486,24 @@ int mutt_parse_rc_line (/* const */ char *line, BUFFER *token, BUFFER *err)
+     {
+       if (!mutt_strcmp (token->data, Commands[i].name))
+       {
+-	if (Commands[i].func (token, &expn, Commands[i].data, err) != 0)
+-	  goto finish;
+-        break;
++        r = Commands[i].func (token, &expn, Commands[i].data, err);
++        if (r != 0) {   /* -1 Error, +1 Finish */
++          goto finish;  /* Propagate return code */
++        }
++        break;          /* Continue with next command */
+       }
+     }
+     if (!Commands[i].name)
+     {
+       snprintf (err->data, err->dsize, _("%s: unknown command"), NONULL (token->data));
+-      goto finish;
++      r = -1;
++      break;            /* Ignore the rest of the line */
+     }
+   }
+-  r = 0;
+ finish:
+   if (expn.destroy)
+     FREE (&expn.data);
+-  return (r);
++  return r;
+ }
+ 
+ 
+@@ -2633,6 +2762,182 @@ int mutt_var_value_complete (char *buffer, size_t len, int pos)
+   return 0;
+ }
+ 
++#if USE_NOTMUCH
 +
-+  if (Sort != SORT_ORDER)
-+  {
-+    save_sort = Sort;
-+    Sort = SORT_ORDER;
-+    mutt_sort_headers (ctx, 0);
-+  }
++/* Fetch a list of all notmuch tags and insert them into the completion
++ * machinery.
++ */
++static int complete_all_nm_tags (const char *pt)
++{
++  int num;
++  int tag_count_1 = 0;
++  int tag_count_2 = 0;
 +
-+  entries = nntp_data->newsrc_len;
-+  if (!entries)
-+  {
-+    entries = 5;
-+    nntp_data->newsrc_ent = safe_calloc (entries, sizeof (NEWSRC_ENTRY));
-+  }
++  Num_matched = 0;
++  strfcpy (User_typed, pt, sizeof (User_typed));
++  memset (Matches, 0, Matches_listsize);
++  memset (Completed, 0, sizeof (Completed));
 +
-+  /* Set up to fake initial sequence from 1 to the article before the
-+   * first article in our list */
-+  nntp_data->newsrc_len = 0;
-+  series = 1;
-+  for (i = 0; i < ctx->msgcount; i++)
-+  {
-+    /* search for first unread */
-+    if (series)
-+    {
-+      /* We don't actually check sequential order, since we mark
-+       * "missing" entries as read/deleted */
-+      last = NHDR (ctx->hdrs[i])->article_num;
-+      if (last >= nntp_data->firstMessage && !ctx->hdrs[i]->deleted &&
-+	  !ctx->hdrs[i]->read)
-+      {
-+	if (nntp_data->newsrc_len >= entries)
-+	{
-+	  entries *= 2;
-+	  safe_realloc (&nntp_data->newsrc_ent, entries * sizeof (NEWSRC_ENTRY));
-+	}
-+	nntp_data->newsrc_ent[nntp_data->newsrc_len].first = first;
-+	nntp_data->newsrc_ent[nntp_data->newsrc_len].last = last - 1;
-+	nntp_data->newsrc_len++;
-+	series = 0;
-+      }
-+    }
++  nm_longrun_init(Context, FALSE);
 +
-+    /* search for first read */
-+    else
-+    {
-+      if (ctx->hdrs[i]->deleted || ctx->hdrs[i]->read)
-+      {
-+	first = last + 1;
-+	series = 1;
-+      }
-+      last = NHDR (ctx->hdrs[i])->article_num;
-+    }
++  /* Work out how many tags there are. */
++  if (nm_get_all_tags(Context, NULL, &tag_count_1) || tag_count_1 == 0)
++    goto done;
++
++  /* Free the old list, if any. */
++  if (nm_tags != NULL) {
++    int i;
++    for (i = 0; nm_tags[i] != NULL; i++)
++      FREE (&nm_tags[i]);
++    FREE (&nm_tags);
 +  }
++  /* Allocate a new list, with sentinel. */
++  nm_tags = safe_malloc((tag_count_1 + 1) * sizeof (char *));
++  nm_tags[tag_count_1] = NULL;
 +
-+  if (series && first <= nntp_data->lastLoaded)
-+  {
-+    if (nntp_data->newsrc_len >= entries)
-+    {
-+      entries++;
-+      safe_realloc (&nntp_data->newsrc_ent, entries * sizeof (NEWSRC_ENTRY));
-+    }
-+    nntp_data->newsrc_ent[nntp_data->newsrc_len].first = first;
-+    nntp_data->newsrc_ent[nntp_data->newsrc_len].last = nntp_data->lastLoaded;
-+    nntp_data->newsrc_len++;
++  /* Get all the tags. */
++  if (nm_get_all_tags(Context, nm_tags, &tag_count_2) ||
++      tag_count_1 != tag_count_2) {
++    FREE (&nm_tags);
++    nm_tags = NULL;
++    nm_longrun_done(Context);
++    return -1;
 +  }
-+  safe_realloc (&nntp_data->newsrc_ent,
-+		nntp_data->newsrc_len * sizeof (NEWSRC_ENTRY));
 +
-+  if (save_sort != Sort)
-+  {
-+    Sort = save_sort;
-+    mutt_sort_headers (ctx, 0);
++  /* Put them into the completion machinery. */
++  for (num = 0; num < tag_count_1; num++) {
++    candidate (Completed, User_typed, nm_tags[num], sizeof (Completed));
 +  }
++
++  matches_ensure_morespace (Num_matched);
++  Matches[Num_matched++] = User_typed;
++
++done:
++  nm_longrun_done(Context);
++  return 0;
 +}
 +
-+/* Update file with new contents */
-+static int update_file (char *filename, char *buf)
++/* Return the last instance of needle in the haystack, or NULL.
++ * Like strstr(), only backwards, and for a limited haystack length.
++ */
++static const char* rstrnstr(const char* haystack,
++                            size_t haystack_length,
++                            const char* needle)
 +{
-+  FILE *fp;
-+  char tmpfile[_POSIX_PATH_MAX];
-+  int rc = -1;
++  int needle_length = strlen(needle);
++  const char* haystack_end = haystack + haystack_length - needle_length;
++  const char* p;
 +
-+  while (1)
++  for (p = haystack_end; p >= haystack; --p)
 +  {
-+    snprintf (tmpfile, sizeof (tmpfile), "%s.tmp", filename);
-+    fp = fopen (tmpfile, "w");
-+    if (!fp)
-+    {
-+      mutt_perror (tmpfile);
-+      *tmpfile = '\0';
-+      break;
-+    }
-+    if (fputs (buf, fp) == EOF)
-+    {
-+      mutt_perror (tmpfile);
-+      break;
-+    }
-+    if (fclose (fp) == EOF)
-+    {
-+      mutt_perror (tmpfile);
-+      fp = NULL;
-+      break;
-+    }
-+    fp = NULL;
-+    if (rename (tmpfile, filename) < 0)
-+    {
-+      mutt_perror (filename);
-+      break;
++    size_t i;
++    for (i = 0; i < needle_length; ++i) {
++      if (p[i] != needle[i])
++        goto next;
 +    }
-+    *tmpfile = '\0';
-+    rc = 0;
-+    break;
++    return p;
++
++    next:;
 +  }
-+  if (fp)
-+    fclose (fp);
-+  if (*tmpfile)
-+    unlink (tmpfile);
-+  if (rc)
-+    mutt_sleep (2);
-+  return rc;
++  return NULL;
 +}
 +
-+/* Update .newsrc file */
-+int nntp_newsrc_update (NNTP_SERVER *nserv)
++/* Complete the nearest "tag:"-prefixed string previous to pos. */
++int mutt_nm_query_complete (char *buffer, size_t len, int pos, int numtabs)
 +{
-+  char *buf;
-+  size_t buflen, off;
-+  unsigned int i;
-+  int rc = -1;
++  char *pt = buffer;
++  int spaces;
 +
-+  if (!nserv)
-+    return -1;
++  SKIPWS (buffer);
++  spaces = buffer - pt;
 +
-+  buflen = 10 * LONG_STRING;
-+  buf = safe_calloc (1, buflen);
-+  off = 0;
++  pt = (char *)rstrnstr((char *)buffer, pos, "tag:");
++  if (pt != NULL) {
++    pt += 4;
++    if (numtabs == 1) {
++      /* First TAB. Collect all the matches */
++      complete_all_nm_tags(pt);
 +
-+  /* we will generate full newsrc here */
-+  for (i = 0; i < nserv->groups_num; i++)
-+  {
-+    NNTP_DATA *nntp_data = nserv->groups_list[i];
-+    unsigned int n;
++      /* All matches are stored. Longest non-ambiguous string is ""
++       * i.e. don't change 'buffer'. Fake successful return this time.
++       */
++      if (User_typed[0] == 0)
++	return 1;
++    }
 +
-+    if (!nntp_data || !nntp_data->newsrc_ent)
-+      continue;
++    if (Completed[0] == 0 && User_typed[0])
++      return 0;
 +
-+    /* write newsgroup name */
-+    if (off + strlen (nntp_data->group) + 3 > buflen)
-+    {
-+      buflen *= 2;
-+      safe_realloc (&buf, buflen);
-+    }
-+    snprintf (buf + off, buflen - off, "%s%c ", nntp_data->group,
-+	      nntp_data->subscribed ? ':' : '!');
-+    off += strlen (buf + off);
++    /* Num_matched will _always_ be atleast 1 since the initial
++     * user-typed string is always stored */
++    if (numtabs == 1 && Num_matched == 2)
++      snprintf(Completed, sizeof(Completed),"%s", Matches[0]);
++    else if (numtabs > 1 && Num_matched > 2)
++      /* cycle thru all the matches */
++      snprintf(Completed, sizeof(Completed), "%s",
++	       Matches[(numtabs - 2) % Num_matched]);
 +
-+    /* write entries */
-+    for (n = 0; n < nntp_data->newsrc_len; n++)
++    /* return the completed query */
++    strncpy (pt, Completed, buffer + len - pt - spaces);
++  }
++  else
++    return 0;
++
++  return 1;
++}
++
++/* Complete the nearest "+" or "-" -prefixed string previous to pos. */
++int mutt_nm_tag_complete (char *buffer, size_t len, int pos, int numtabs)
++{
++  char *pt = buffer;
++  int spaces;
++  const char *first_plus = NULL;
++  const char *first_minus = NULL;
++
++  SKIPWS (buffer);
++  spaces = buffer - pt;
++
++  first_plus = rstrnstr((char *)buffer, pos, "+");
++  first_minus = rstrnstr((char *)buffer, pos, "-");
++  pt = (char *)MAX(first_plus, first_minus);
++
++  if (pt != NULL) {
++    pt++;
++
++    if (numtabs == 1)
 +    {
-+      if (off + LONG_STRING > buflen)
-+      {
-+	buflen *= 2;
-+	safe_realloc (&buf, buflen);
-+      }
-+      if (n)
-+	buf[off++] = ',';
-+      if (nntp_data->newsrc_ent[n].first == nntp_data->newsrc_ent[n].last)
-+	snprintf (buf + off, buflen - off, "%d", nntp_data->newsrc_ent[n].first);
-+      else if (nntp_data->newsrc_ent[n].first < nntp_data->newsrc_ent[n].last)
-+	snprintf (buf + off, buflen - off, "%d-%d",
-+		  nntp_data->newsrc_ent[n].first, nntp_data->newsrc_ent[n].last);
-+      off += strlen (buf + off);
++      /* First TAB. Collect all the matches */
++      complete_all_nm_tags(pt);
++
++      /* All matches are stored. Longest non-ambiguous string is ""
++       * i.e. don't change 'buffer'. Fake successful return this time.
++       */
++      if (User_typed[0] == 0)
++	return 1;
 +    }
-+    buf[off++] = '\n';
++
++    if (Completed[0] == 0 && User_typed[0])
++      return 0;
++
++    /* Num_matched will _always_ be atleast 1 since the initial
++     * user-typed string is always stored */
++    if (numtabs == 1 && Num_matched == 2)
++      snprintf(Completed, sizeof(Completed),"%s", Matches[0]);
++    else if (numtabs > 1 && Num_matched > 2)
++      /* cycle thru all the matches */
++      snprintf(Completed, sizeof(Completed), "%s",
++	       Matches[(numtabs - 2) % Num_matched]);
++
++    /* return the completed query */
++    strncpy (pt, Completed, buffer + len - pt - spaces);
 +  }
-+  buf[off] = '\0';
++  else
++    return 0;
++
++  return 1;
++}
++#endif
++
+ static int var_to_string (int idx, char* val, size_t len)
+ {
+   char tmp[LONG_STRING];
+@@ -2852,7 +3157,7 @@ static int mutt_execute_commands (LIST *p)
+   mutt_buffer_init (&token);
+   for (; p; p = p->next)
+   {
+-    if (mutt_parse_rc_line (p->data, &token, &err) != 0)
++    if (mutt_parse_rc_line (p->data, &token, &err) == -1)
+     {
+       fprintf (stderr, _("Error in command line: %s\n"), err.data);
+       FREE (&token.data);
+@@ -2867,23 +3172,6 @@ static int mutt_execute_commands (LIST *p)
+   return 0;
+ }
+ 
+-static void mutt_srandom (void)
+-{
+-  struct timeval tv;
+-  unsigned seed;
+-
+-  gettimeofday(&tv, NULL);
+-  /* POSIX.1-2008 states that seed is 'unsigned' without specifying its width.
+-   * Use as many of the lower order bits from the current time of day as the seed.
+-   * If the upper bound is truncated, that is fine.
+-   *
+-   * tv_sec is integral of type integer or float.  Cast to 'long long' before
+-   * bitshift in case it is a float.
+-   */
+-  seed = ((LONGLONG) tv.tv_sec << 20) | tv.tv_usec;
+-  srandom(seed);
+-}
+-
+ void mutt_init (int skip_sys_rc, LIST *commands)
+ {
+   struct passwd *pw;
+@@ -2900,15 +3188,15 @@ void mutt_init (int skip_sys_rc, LIST *commands)
+ 
+   Groups = hash_create (1031, 0);
+   ReverseAlias = hash_create (1031, 1);
+-  
++#ifdef USE_NOTMUCH
++  TagTransforms = hash_create (64, 1);
++  TagFormats = hash_create (64, 0);
++#endif
 +
-+  /* newrc being fully rewritten */
-+  dprint (1, (debugfile, "Updating %s\n", nserv->newsrc_file));
-+  if (nserv->newsrc_file && update_file (nserv->newsrc_file, buf) == 0)
+   mutt_menu_init ();
+-  mutt_srandom ();
+ 
+-  /* 
+-   * XXX - use something even more difficult to predict?
+-   */
+   snprintf (AttachmentMarker, sizeof (AttachmentMarker),
+-	    "\033]9;%ld\a", (long) time (NULL));
++	    "\033]9;%" PRIu64 "\a", mutt_rand64());
+   
+   /* on one of the systems I use, getcwd() does not return the same prefix
+      as is listed in the passwd file */
+@@ -3002,6 +3290,28 @@ void mutt_init (int skip_sys_rc, LIST *commands)
+     Fqdn = safe_strdup(utsname.nodename);
+ 
+ 
++#ifdef USE_NNTP
 +  {
-+    struct stat sb;
++    FILE *f;
++    char *i;
 +
-+    rc = stat (nserv->newsrc_file, &sb);
-+    if (rc == 0)
-+    {
-+      nserv->size = sb.st_size;
-+      nserv->mtime = sb.st_mtime;
-+    }
-+    else
++    if ((f = safe_fopen (SYSCONFDIR "/nntpserver", "r")))
 +    {
-+      mutt_perror (nserv->newsrc_file);
-+      mutt_sleep (2);
++      buffer[0] = '\0';
++      fgets (buffer, sizeof (buffer), f);
++      p = buffer;
++      SKIPWS (p);
++      i = p;
++      while (*i && (*i != ' ') && (*i != '\t') && (*i != '\r') && (*i != '\n')) i++;
++      *i = '\0';
++      NewsServer = safe_strdup (p);
++      fclose (f);
 +    }
 +  }
-+  FREE (&buf);
-+  return rc;
-+}
++  if ((p = getenv ("NNTPSERVER")))
++    NewsServer = safe_strdup (p);
++#endif
 +
-+/* Make fully qualified cache file name */
-+static void cache_expand (char *dst, size_t dstlen, ACCOUNT *acct, char *src)
+   if ((p = getenv ("MAIL")))
+     Spoolfile = safe_strdup (p);
+   else if ((p = getenv ("MAILDIR")))
+@@ -3188,6 +3498,11 @@ void mutt_init (int skip_sys_rc, LIST *commands)
+ 
+   mutt_read_histfile ();
+ 
++#ifdef USE_NOTMUCH
++  if (option (OPTVIRTSPOOLFILE) && VirtIncoming)
++    mutt_str_replace(&Spoolfile, VirtIncoming->path);
++#endif
++
+ #if 0
+   set_option (OPTWEED); /* turn weeding on by default */
+ #endif
+@@ -3235,6 +3550,70 @@ static int parse_group_context (group_context_t **ctx, BUFFER *buf, BUFFER *s, u
+   return -1;
+ }
+ 
++#ifdef USE_NOTMUCH
++int parse_tag_transforms (BUFFER *b, BUFFER *s, unsigned long data, BUFFER *err)
 +{
-+  char *c;
-+  char file[_POSIX_PATH_MAX];
++  char *tmp;
 +
-+  /* server subdirectory */
-+  if (acct)
++  while (MoreArgs (s))
 +  {
-+    ciss_url_t url;
-+
-+    mutt_account_tourl (acct, &url);
-+    url.path = src;
-+    url_ciss_tostring (&url, file, sizeof (file), U_PATH);
-+  }
-+  else
-+    strfcpy (file, src ? src : "", sizeof (file));
++    char *tag, *transform;
 +
-+  snprintf (dst, dstlen, "%s/%s", NewsCacheDir, file);
++    mutt_extract_token (b, s, 0);
++    if (b->data && *b->data)
++      tag = safe_strdup (b->data);
++    else
++      continue;
 +
-+  /* remove trailing slash */
-+  c = dst + strlen (dst) - 1;
-+  if (*c == '/')
-+    *c = '\0';
-+  mutt_expand_path (dst, dstlen);
-+}
++    mutt_extract_token (b, s, 0);
++    transform = safe_strdup (b->data);
 +
-+/* Make fully qualified url from newsgroup name */
-+void nntp_expand_path (char *line, size_t len, ACCOUNT *acct)
-+{
-+  ciss_url_t url;
++    /* avoid duplicates */
++    tmp = hash_find(TagTransforms, tag);
++    if (tmp) {
++      dprint(3,(debugfile,"tag transform '%s' already registered as '%s'\n", tag, tmp));
++      FREE(&tag);
++      FREE(&transform);
++      continue;
++    }
 +
-+  url.path = safe_strdup (line);
-+  mutt_account_tourl (acct, &url);
-+  url_ciss_tostring (&url, line, len, 0);
-+  FREE (&url.path);
++    hash_insert(TagTransforms, tag, transform, 0);
++  }
++  return 0;
 +}
 +
-+/* Parse newsgroup */
-+int nntp_add_group (char *line, void *data)
++int parse_tag_formats (BUFFER *b, BUFFER *s, unsigned long data, BUFFER *err)
 +{
-+  NNTP_SERVER *nserv = data;
-+  NNTP_DATA *nntp_data;
-+  char group[LONG_STRING];
-+  char desc[HUGE_STRING] = "";
-+  char mod;
-+  anum_t first, last;
-+
-+  if (!nserv || !line)
-+    return 0;
++  char *tmp;
 +
-+  if (sscanf (line, "%s " ANUM " " ANUM " %c %[^\n]", group,
-+	      &last, &first, &mod, desc) < 4)
-+    return 0;
++  while (MoreArgs (s))
++  {
++    char *tag, *format;
 +
-+  nntp_data = nntp_data_find (nserv, group);
-+  nntp_data->deleted = 0;
-+  nntp_data->firstMessage = first;
-+  nntp_data->lastMessage = last;
-+  nntp_data->allowed = mod == 'y' || mod == 'm' ? 1 : 0;
-+  mutt_str_replace (&nntp_data->desc, desc);
-+  if (nntp_data->newsrc_ent || nntp_data->lastCached)
-+    nntp_group_unread_stat (nntp_data);
-+  else if (nntp_data->lastMessage &&
-+	   nntp_data->firstMessage <= nntp_data->lastMessage)
-+    nntp_data->unread = nntp_data->lastMessage - nntp_data->firstMessage + 1;
-+  else
-+    nntp_data->unread = 0;
-+  return 0;
-+}
++    mutt_extract_token (b, s, 0);
++    if (b->data && *b->data)
++      tag = safe_strdup (b->data);
++    else
++      continue;
 +
-+/* Load list of all newsgroups from cache */
-+static int active_get_cache (NNTP_SERVER *nserv)
-+{
-+  char buf[HUGE_STRING];
-+  char file[_POSIX_PATH_MAX];
-+  time_t t;
-+  FILE *fp;
++    mutt_extract_token (b, s, 0);
++    format = safe_strdup (b->data);
 +
-+  cache_expand (file, sizeof (file), &nserv->conn->account, ".active");
-+  dprint (1, (debugfile, "Parsing %s\n", file));
-+  fp = safe_fopen (file, "r");
-+  if (!fp)
-+    return -1;
++    /* avoid duplicates */
++    tmp = hash_find(TagFormats, format);
++    if (tmp) {
++      dprint(3,(debugfile,"tag format '%s' already registered as '%s'\n", format, tmp));
++      FREE(&tag);
++      FREE(&format);
++      continue;
++    }
 +
-+  if (fgets (buf, sizeof (buf), fp) == NULL ||
-+      sscanf (buf, "%ld%s", &t, file) != 1 || t == 0)
-+  {
-+    fclose (fp);
-+    return -1;
++    hash_insert(TagFormats, format, tag, 0);
 +  }
-+  nserv->newgroups_time = t;
-+
-+  mutt_message _("Loading list of groups from cache...");
-+  while (fgets (buf, sizeof (buf), fp))
-+    nntp_add_group (buf, nserv);
-+  nntp_add_group (NULL, NULL);
-+  fclose (fp);
-+  mutt_clear_error ();
 +  return 0;
 +}
++#endif
 +
-+/* Save list of all newsgroups to cache */
-+int nntp_active_save_cache (NNTP_SERVER *nserv)
-+{
-+  char file[_POSIX_PATH_MAX];
-+  char *buf;
-+  size_t buflen, off;
-+  unsigned int i;
-+  int rc;
-+
-+  if (!nserv->cacheable)
-+    return 0;
-+
-+  buflen = 10 * LONG_STRING;
-+  buf = safe_calloc (1, buflen);
-+  snprintf (buf, buflen, "%lu\n", (unsigned long)nserv->newgroups_time);
-+  off = strlen (buf);
-+
-+  for (i = 0; i < nserv->groups_num; i++)
-+  {
-+    NNTP_DATA *nntp_data = nserv->groups_list[i];
+ static void myvar_set (const char* var, const char* val)
+ {
+   myvar_t** cur;
+@@ -3282,3 +3661,58 @@ static const char* myvar_get (const char* var)
+ 
+   return NULL;
+ }
 +
-+    if (!nntp_data || nntp_data->deleted)
-+      continue;
++int mutt_label_complete (char *buffer, size_t len, int pos, int numtabs)
++{
++  char *pt = buffer;
++  int spaces; /* keep track of the number of leading spaces on the line */
++  int prefix;
 +
-+    if (off + strlen (nntp_data->group) +
-+	(nntp_data->desc ? strlen (nntp_data->desc) : 0) + 50 > buflen)
-+    {
-+      buflen *= 2;
-+      safe_realloc (&buf, buflen);
-+    }
-+    snprintf (buf + off, buflen - off, "%s %d %d %c%s%s\n", nntp_data->group,
-+	      nntp_data->lastMessage, nntp_data->firstMessage,
-+	      nntp_data->allowed ? 'y' : 'n', nntp_data->desc ? " " : "",
-+	      nntp_data->desc ? nntp_data->desc : "");
-+    off += strlen (buf + off);
-+  }
++  SKIPWS (buffer);
++  spaces = buffer - pt;
 +
-+  cache_expand (file, sizeof (file), &nserv->conn->account, ".active");
-+  dprint (1, (debugfile, "Updating %s\n", file));
-+  rc = update_file (file, buf);
-+  FREE (&buf);
-+  return rc;
-+}
++  for (pt = buffer; pt && *pt && *(pt+1); pt++);
++  for (; pt > buffer && !isspace(*(pt-1)); pt--);
++  prefix = pt - buffer;
 +
-+#ifdef USE_HCACHE
-+/* Used by mutt_hcache_open() to compose hcache file name */
-+static int nntp_hcache_namer (const char *path, char *dest, size_t destlen)
-+{
-+  return snprintf (dest, destlen, "%s.hcache", path);
-+}
++  /* first TAB. Collect all the matches */
++  if (numtabs == 1)
++  {
++    struct hash_elem *entry;
++    struct hash_walk_state state;
 +
-+/* Open newsgroup hcache */
-+header_cache_t *nntp_hcache_open (NNTP_DATA *nntp_data)
-+{
-+  ciss_url_t url;
-+  char file[_POSIX_PATH_MAX];
++    Num_matched = 0;
++    strfcpy (User_typed, pt, sizeof (User_typed));
++    memset (Matches, 0, Matches_listsize);
++    memset (Completed, 0, sizeof (Completed));
++    memset (&state, 0, sizeof(state));
++    while ((entry = hash_walk(Labels, &state)))
++      candidate (Completed, User_typed, entry->key, sizeof (Completed));
++    matches_ensure_morespace (Num_matched);
++    qsort(Matches, Num_matched, sizeof(char *), (sort_t *) mutt_strcasecmp);
++    Matches[Num_matched++] = User_typed;
 +
-+  if (!nntp_data->nserv || !nntp_data->nserv->cacheable ||
-+      !nntp_data->nserv->conn || !nntp_data->group ||
-+      !(nntp_data->newsrc_ent || nntp_data->subscribed ||
-+      option (OPTSAVEUNSUB)))
-+    return NULL;
++    /* All matches are stored. Longest non-ambiguous string is ""
++     * i.e. dont change 'buffer'. Fake successful return this time */
++    if (User_typed[0] == 0)
++      return 1;
++  }
 +
-+  mutt_account_tourl (&nntp_data->nserv->conn->account, &url);
-+  url.path = nntp_data->group;
-+  url_ciss_tostring (&url, file, sizeof (file), U_PATH);
-+  return mutt_hcache_open (NewsCacheDir, file, nntp_hcache_namer);
-+}
++  if (Completed[0] == 0 && User_typed[0])
++    return 0;
 +
-+/* Remove stale cached headers */
-+void nntp_hcache_update (NNTP_DATA *nntp_data, header_cache_t *hc)
-+{
-+  char buf[16];
-+  int old = 0;
-+  void *hdata;
-+  anum_t first, last, current;
++   /* Num_matched will _always_ be atleast 1 since the initial
++    * user-typed string is always stored */
++  if (numtabs == 1 && Num_matched == 2)
++    snprintf(Completed, sizeof(Completed), "%s", Matches[0]);
++  else if (numtabs > 1 && Num_matched > 2)
++    /* cycle thru all the matches */
++    snprintf(Completed, sizeof(Completed), "%s", 
++             Matches[(numtabs - 2) % Num_matched]);
 +
-+  if (!hc)
-+    return;
++  /* return the completed label */
++  strncpy (&buffer[prefix], Completed, len - spaces);
 +
-+  /* fetch previous values of first and last */
-+  hdata = mutt_hcache_fetch_raw (hc, "index", strlen);
-+  if (hdata)
-+  {
-+    dprint (2, (debugfile,
-+		"nntp_hcache_update: mutt_hcache_fetch index: %s\n", hdata));
-+    if (sscanf (hdata, ANUM " " ANUM, &first, &last) == 2)
-+    {
-+      old = 1;
-+      nntp_data->lastCached = last;
++  return 1;
++}
++
+diff --git a/init.h b/init.h
+index 5a12ec0..bc5134d 100644
+--- a/init.h
++++ b/init.h
+@@ -42,11 +42,12 @@
+ #define DTYPE(x) ((x) & DT_MASK)
+ 
+ /* subtypes */
+-#define DT_SUBTYPE_MASK	0xf0
++#define DT_SUBTYPE_MASK	0xff0
+ #define DT_SORT_ALIAS	0x10
+ #define DT_SORT_BROWSER 0x20
+ #define DT_SORT_KEYS	0x40
+ #define DT_SORT_AUX	0x80
++#define DT_SORT_SIDEBAR	0x100
+ 
+ /* flags to parse_set() */
+ #define M_SET_INV	(1<<0)	/* default is to invert all vars */
+@@ -61,6 +62,8 @@
+ #define R_RESORT_SUB	(1<<3)	/* resort subthreads */
+ #define R_RESORT_INIT	(1<<4)  /* resort from scratch */
+ #define R_TREE		(1<<5)  /* redraw the thread tree */
++#define R_REFLOW        (1<<6)  /* reflow window layout */
++#define R_SIDEBAR       (1<<7)  /* redraw the sidebar */
+ #define R_BOTH		(R_INDEX | R_PAGER)
+ #define R_RESORT_BOTH	(R_RESORT | R_RESORT_SUB)
+ 
+@@ -176,6 +179,20 @@ struct option_t MuttVars[] = {
+   ** If \fIset\fP, Mutt will prompt you for carbon-copy (Cc) recipients before
+   ** editing the body of an outgoing message.
+   */
++#ifdef USE_NNTP
++  { "ask_follow_up",	DT_BOOL, R_NONE, OPTASKFOLLOWUP, 0 },
++  /*
++  ** .pp
++  ** If set, Mutt will prompt you for follow-up groups before editing
++  ** the body of an outgoing message.
++  */
++  { "ask_x_comment_to",	DT_BOOL, R_NONE, OPTASKXCOMMENTTO, 0 },
++  /*
++  ** .pp
++  ** If set, Mutt will prompt you for x-comment-to field before editing
++  ** the body of an outgoing message.
++  */
++#endif
+   { "assumed_charset", DT_STR, R_NONE, UL &AssumedCharset, UL 0},
+   /*
+   ** .pp
+@@ -290,6 +307,13 @@ struct option_t MuttVars[] = {
+   { "beep",		DT_BOOL, R_NONE, OPTBEEP, 1 },
+   /*
+   ** .pp
++  ** If \fIset\fP, Mutt will call this command after a new message is received.
++  ** See the $$status_format documentation for the values that can be formatted
++  ** into this command.
++  */
++  { "new_mail_command",	DT_PATH, R_NONE, UL &NewMailCmd, UL NULL },
++  /*
++  ** .pp
+   ** When this variable is \fIset\fP, mutt will beep when an error occurs.
+   */
+   { "beep_new",		DT_BOOL, R_NONE, OPTBEEPNEW, 0 },
+@@ -322,6 +346,14 @@ struct option_t MuttVars[] = {
+   ** follow these menus.  The option is \fIunset\fP by default because many
+   ** visual terminals don't permit making the cursor invisible.
+   */
++#ifdef USE_NNTP
++  { "catchup_newsgroup", DT_QUAD, R_NONE, OPT_CATCHUP, M_ASKYES },
++  /*
++  ** .pp
++  ** If this variable is \fIset\fP, Mutt will mark all articles in newsgroup
++  ** as read when you quit the newsgroup (catchup newsgroup).
++  */
++#endif
+ #if defined(USE_SSL)
+   { "certificate_file",	DT_PATH, R_NONE, UL &SslCertFile, UL "~/.mutt_certificates" },
+   /*
+@@ -504,19 +536,19 @@ struct option_t MuttVars[] = {
+   ** .pp
+   ** Setting this variable will cause Mutt to automatically enable and
+   ** disable encryption, based on whether all message recipient keys
+-  ** can be located by mutt.
++  ** can be located by Mutt.
+   ** .pp
+-  ** When this option is enabled, mutt will determine the encryption
+-  ** setting each time the TO, CC, and BCC lists are edited.  If
+-  ** $$edit_headers is set, mutt will also do so each time the message
++  ** When this option is enabled, Mutt will enable/disable encryption
++  ** each time the TO, CC, and BCC lists are edited.  If
++  ** $$edit_headers is set, Mutt will also do so each time the message
+   ** is edited.
+   ** .pp
+-  ** While this is set, encryption settings can't be manually changed.
+-  ** The pgp or smime menus provide an option to disable the option for
+-  ** a particular message.
++  ** While this is set, encryption can't be manually enabled/disabled.
++  ** The pgp or smime menus provide a selection to temporarily disable
++  ** this option for the current message.
+   ** .pp
+   ** If $$crypt_autoencrypt or $$crypt_replyencrypt enable encryption for
+-  ** a message, this option will be disabled for the message.  It can
++  ** a message, this option will be disabled for that message.  It can
+   ** be manually re-enabled in the pgp or smime menus.
+   ** (Crypto only)
+    */
+@@ -841,6 +873,16 @@ struct option_t MuttVars[] = {
+   ** sent to both the list and your address, resulting in two copies
+   ** of the same email for you.
+   */
++#ifdef USE_NNTP
++  { "followup_to_poster", DT_QUAD, R_NONE, OPT_FOLLOWUPTOPOSTER, M_ASKYES },
++  /*
++  ** .pp
++  ** If this variable is \fIset\fP and the keyword "poster" is present in
++  ** \fIFollowup-To\fP header, follow-up to newsgroup function is not
++  ** permitted.  The message will be mailed to the submitter of the
++  ** message via mail.
++  */
++#endif
+   { "force_name",	DT_BOOL, R_NONE, OPTFORCENAME, 0 },
+   /*
+   ** .pp
+@@ -923,6 +965,26 @@ struct option_t MuttVars[] = {
+   ** a regular expression that will match the whole name so mutt will expand
+   ** ``Franklin'' to ``Franklin, Steve''.
+   */
++#ifdef USE_NNTP
++  { "group_index_format", DT_STR, R_BOTH, UL &GroupFormat, UL "%4C %M%N %5s  %-45.45f %d" },
++  /*
++  ** .pp
++  ** This variable allows you to customize the newsgroup browser display to
++  ** your personal taste.  This string is similar to ``$index_format'', but
++  ** has its own set of printf()-like sequences:
++  ** .dl
++  ** .dt %C  .dd current newsgroup number
++  ** .dt %d  .dd description of newsgroup (becomes from server)
++  ** .dt %f  .dd newsgroup name
++  ** .dt %M  .dd - if newsgroup not allowed for direct post (moderated for example)
++  ** .dt %N  .dd N if newsgroup is new, u if unsubscribed, blank otherwise
++  ** .dt %n  .dd number of new articles in newsgroup
++  ** .dt %s  .dd number of unread articles in newsgroup
++  ** .dt %>X .dd right justify the rest of the string and pad with character "X"
++  ** .dt %|X .dd pad to the end of the line with character "X"
++  ** .de
++  */
++#endif
+   { "hdr_format",	DT_SYN,  R_NONE, UL "index_format", 0 },
+   /*
+   */
+@@ -1315,6 +1377,8 @@ struct option_t MuttVars[] = {
+   ** .dt %E .dd number of messages in current thread
+   ** .dt %f .dd sender (address + real name), either From: or Return-Path:
+   ** .dt %F .dd author name, or recipient name if the message is from you
++  ** .dt %g .dd message labels (e.g. notmuch tags)
++  ** .dt %g .dd newsgroup name (if compiled with NNTP support)
+   ** .dt %H .dd spam attribute(s) of this message
+   ** .dt %i .dd message-id of the current message
+   ** .dt %l .dd number of lines in the message (does not work with maildir,
+@@ -1338,6 +1402,8 @@ struct option_t MuttVars[] = {
+   ** .dt %T .dd the appropriate character from the $$to_chars string
+   ** .dt %u .dd user (login) name of the author
+   ** .dt %v .dd first name of the author, or the recipient if the message is from you
++  ** .dt %W .dd name of organization of author (``Organization:'' field)
++  ** .dt %x .dd ``X-Comment-To:'' field (if present and compiled with NNTP support)
+   ** .dt %X .dd number of attachments
+   **            (please see the ``$attachments'' section for possible speed effects)
+   ** .dt %y .dd ``X-Label:'' field, if present
+@@ -1361,6 +1427,10 @@ struct option_t MuttVars[] = {
+   ** .dt %*X    .dd soft-fill with character ``X'' as pad
+   ** .de
+   ** .pp
++  ** Date format expressions can be constructed based on relative dates. Using
++  ** the date formatting operators along with nested conditionals, the date
++  ** format can be modified based on how old a message is.  See the section on
++  ** ``Conditional Dates'' for an explanation and examples
+   ** ``Soft-fill'' deserves some explanation: Normal right-justification
+   ** will print everything to the left of the ``%>'', displaying padding and
+   ** whatever lies to the right only if there's room. By contrast,
+@@ -1372,6 +1442,25 @@ struct option_t MuttVars[] = {
+   ** Note that these expandos are supported in
+   ** ``$save-hook'', ``$fcc-hook'' and ``$fcc-save-hook'', too.
+   */
++#ifdef USE_NNTP
++  { "inews",		DT_PATH, R_NONE, UL &Inews, UL "" },
++  /*
++  ** .pp
++  ** If set, specifies the program and arguments used to deliver news posted
++  ** by Mutt.  Otherwise, mutt posts article using current connection to
++  ** news server.  The following printf-style sequence is understood:
++  ** .dl
++  ** .dt %a .dd account url
++  ** .dt %p .dd port
++  ** .dt %P .dd port if specified
++  ** .dt %s .dd news server name
++  ** .dt %S .dd url schema
++  ** .dt %u .dd username
++  ** .de
++  ** .pp
++  ** Example: set inews="/usr/local/bin/inews -hS"
++  */
++#endif
+   { "ispell",		DT_PATH, R_NONE, UL &Ispell, UL ISPELL },
+   /*
+   ** .pp
+@@ -1384,6 +1473,28 @@ struct option_t MuttVars[] = {
+   ** from your spool mailbox to your $$mbox mailbox, or as a result of
+   ** a ``$mbox-hook'' command.
+   */
++  { "keywords_legacy", DT_BOOL, R_NONE, OPTKEYWORDSLEGACY, 1 },
++  /*
++  ** .pp
++  ** If \fIset\fP, keywords/labels/tags will be written to whatever
++  ** legacy, nonstandard headers (X-Label, X-Keywords, X-Mozilla-Keys)
++  ** they were sourced from.
++  ** .pp
++  ** If both ``$$keywords_legacy'' and
++  ** ``$$keywords_standard'' are \fCfalse\fP, mutt will save keywords
++  ** to legacy headers to ensure that it does not lose your labels.
++  */
++  { "keywords_standard", DT_BOOL, R_NONE, OPTKEYWORDSSTANDARD, 0 },
++  /*
++  ** .pp
++  ** If \fIset\fP, keywords/labels/tags will be written to the
++  ** RFC2822-standard Keywords: header; this may imply a conversion from
++  ** legacy headers.
++  ** .pp
++  ** If both ``$$keywords_legacy'' and
++  ** ``$$keywords_standard'' are \fCfalse\fP, mutt will save keywords
++  ** to legacy headers to ensure that it does not lose your labels.
++  */
+   { "locale",		DT_STR,  R_BOTH, UL &Locale, UL "C" },
+   /*
+   ** .pp
+@@ -1407,6 +1518,22 @@ struct option_t MuttVars[] = {
+   ** When \fI$$mark_old\fP is set, Mutt does not consider the mailbox to contain new
+   ** mail if only old messages exist.
+   */
++  { "mail_check_stats", DT_BOOL, R_NONE, OPTMAILCHECKSTATS, 0 },
++  /*
++  ** .pp
++  ** When \fIset\fP, mutt will periodically calculate message
++  ** statistics of a mailbox while polling for new mail.  It will
++  ** check for unread, flagged, and total message counts.  Because
++  ** this operation is more performance intensive, it defaults to
++  ** \fIunset\fP, and has a separate option, $$mail_check_stats_interval, to
++  ** control how often to update these counts.
++  */
++  { "mail_check_stats_interval", DT_NUM, R_NONE, UL &BuffyCheckStatsInterval, 60 },
++  /*
++  ** .pp
++  ** When $$mail_check_stats is \fIset\fP, this variable configures
++  ** how often (in seconds) mutt will update message counts.
++  */
+   { "mailcap_path",	DT_STR,	 R_NONE, UL &MailcapPath, 0 },
+   /*
+   ** .pp
+@@ -1616,6 +1743,15 @@ struct option_t MuttVars[] = {
+   ** menu, attachments which cannot be decoded in a reasonable manner will
+   ** be attached to the newly composed message if this option is \fIset\fP.
+   */
++#ifdef USE_NNTP
++  { "mime_subject",	DT_BOOL, R_NONE, OPTMIMESUBJECT, 1 },
++  /*
++  ** .pp
++  ** If \fIunset\fP, 8-bit ``subject:'' line in article header will not be
++  ** encoded according to RFC2047 to base64.  This is useful when message
++  ** is Usenet article, because MIME for news is nonstandard feature.
++  */
++#endif
+ #ifdef MIXMASTER
+   { "mix_entry_format", DT_STR,  R_NONE, UL &MixEntryFormat, UL "%4n %c %-16s %a" },
+   /*
+@@ -1663,6 +1799,160 @@ struct option_t MuttVars[] = {
+    ** See also $$read_inc, $$write_inc and $$net_inc.
+    */
+ #endif
++#ifdef USE_NNTP
++  { "news_cache_dir",	DT_PATH, R_NONE, UL &NewsCacheDir, UL "~/.mutt" },
++  /*
++  ** .pp
++  ** This variable pointing to directory where Mutt will save cached news
++  ** articles and headers in. If \fIunset\fP, articles and headers will not be
++  ** saved at all and will be reloaded from the server each time.
++  */
++  { "news_server",	DT_STR, R_NONE, UL &NewsServer, 0 },
++  /*
++  ** .pp
++  ** This variable specifies domain name or address of NNTP server. It
++  ** defaults to the news server specified in the environment variable
++  ** $$$NNTPSERVER or contained in the file /etc/nntpserver.  You can also
++  ** specify username and an alternative port for each news server, ie:
++  ** .pp
++  ** [[s]news://][username[:password]@]server[:port]
++  */
++  { "newsgroups_charset", DT_STR, R_NONE, UL &NewsgroupsCharset, UL "utf-8" },
++  /*
++  ** .pp
++  ** Character set of newsgroups descriptions.
++  */
++  { "newsrc",		DT_PATH, R_NONE, UL &NewsRc, UL "~/.newsrc" },
++  /*
++  ** .pp
++  ** The file, containing info about subscribed newsgroups - names and
++  ** indexes of read articles.  The following printf-style sequence
++  ** is understood:
++  ** .dl
++  ** .dt %a .dd account url
++  ** .dt %p .dd port
++  ** .dt %P .dd port if specified
++  ** .dt %s .dd news server name
++  ** .dt %S .dd url schema
++  ** .dt %u .dd username
++  ** .de
++  */
++  { "nntp_authenticators", DT_STR, R_NONE, UL &NntpAuthenticators, UL 0 },
++  /*
++  ** .pp
++  ** This is a colon-delimited list of authentication methods mutt may
++  ** attempt to use to log in to a news server, in the order mutt should
++  ** try them.  Authentication methods are either ``user'' or any
++  ** SASL mechanism, e.g. ``digest-md5'', ``gssapi'' or ``cram-md5''.
++  ** This option is case-insensitive.  If it's \fIunset\fP (the default)
++  ** mutt will try all available methods, in order from most-secure to
++  ** least-secure.
++  ** .pp
++  ** Example:
++  ** .ts
++  ** set nntp_authenticators="digest-md5:user"
++  ** .te
++  ** .pp
++  ** \fBNote:\fP Mutt will only fall back to other authentication methods if
++  ** the previous methods are unavailable. If a method is available but
++  ** authentication fails, mutt will not connect to the IMAP server.
++  */
++  { "nntp_context",	DT_NUM, R_NONE, UL &NntpContext, 1000 },
++  /*
++  ** .pp
++  ** This variable defines number of articles which will be in index when
++  ** newsgroup entered.  If active newsgroup have more articles than this
++  ** number, oldest articles will be ignored.  Also controls how many
++  ** articles headers will be saved in cache when you quit newsgroup.
++  */
++  { "nntp_listgroup",	DT_BOOL, R_NONE, OPTLISTGROUP, 1 },
++  /*
++  ** .pp
++  ** This variable controls whether or not existence of each article is
++  ** checked when newsgroup is entered.
++  */
++  { "nntp_load_description", DT_BOOL, R_NONE, OPTLOADDESC, 1 },
++  /*
++  ** .pp
++  ** This variable controls whether or not descriptions for each newsgroup
++  ** must be loaded when newsgroup is added to list (first time list
++  ** loading or new newsgroup adding).
++  */
++  { "nntp_user",	DT_STR, R_NONE, UL &NntpUser, UL "" },
++  /*
++  ** .pp
++  ** Your login name on the NNTP server.  If \fIunset\fP and NNTP server requires
++  ** authentication, Mutt will prompt you for your account name when you
++  ** connect to news server.
++  */
++  { "nntp_pass",	DT_STR, R_NONE, UL &NntpPass, UL "" },
++  /*
++  ** .pp
++  ** Your password for NNTP account.
++  */
++  { "nntp_poll",	DT_NUM, R_NONE, UL &NewsPollTimeout, 60 },
++  /*
++  ** .pp
++  ** The time in seconds until any operations on newsgroup except post new
++  ** article will cause recheck for new news.  If set to 0, Mutt will
++  ** recheck newsgroup on each operation in index (stepping, read article,
++  ** etc.).
++  */
++#endif
++#ifdef USE_NOTMUCH
++  { "nm_open_timeout", DT_NUM, R_NONE, UL &NotmuchOpenTimeout, 5 },
++  /*
++   ** .pp
++   ** This variable specifies the timeout for database open in seconds.
++   */
 +
-+      /* clean removed headers from cache */
-+      for (current = first; current <= last; current++)
-+      {
-+	if (current >= nntp_data->firstMessage &&
-+	    current <= nntp_data->lastMessage)
-+	  continue;
++  { "nm_default_uri", DT_STR, R_NONE, UL &NotmuchDefaultUri, 0 },
++  /*
++   ** .pp
++   ** This variable specifies the default Notmuch database in format
++   ** notmuch://<absolute path>.
++   */
 +
-+	snprintf (buf, sizeof (buf), "%d", current);
-+	dprint (2, (debugfile,
-+		    "nntp_hcache_update: mutt_hcache_delete %s\n", buf));
-+	mutt_hcache_delete (hc, buf, strlen);
-+      }
-+    }
-+    FREE (&hdata);
-+  }
++  { "nm_hidden_tags", DT_STR, R_NONE, UL &NotmuchHiddenTags, UL "unread,draft,flagged,passed,replied,attachment,signed,encrypted" },
++  /*
++   ** .pp
++   ** This variable specifies private notmuch tags which should not be printed
++   ** on screen.
++   */
++  { "nm_exclude_tags", DT_STR,  R_NONE, UL &NotmuchExcludeTags, 0 },
++  /*
++   ** .pp
++   ** The messages tagged with these tags are excluded and not loaded
++   ** from notmuch DB to mutt unless specified explicitly.
++   */
++  { "nm_unread_tag", DT_STR, R_NONE, UL &NotmuchUnreadTag, UL "unread" },
++  /*
++   ** .pp
++   ** This variable specifies notmuch tag which is used for unread messages. The
++   ** variable is used to count unread messages in DB only. All other mutt commands
++   ** use standard (e.g. maildir) flags.
++   */
++  { "nm_db_limit", DT_NUM, R_NONE, UL &NotmuchDBLimit, 0 },
++  /*
++   ** .pp
++   ** This variable specifies the default limit used in notmuch queries.
++   */
++  { "nm_query_type", DT_STR, R_NONE, UL &NotmuchQueryType, UL "messages" },
++  /*
++   ** .pp
++   ** This variable specifies the default query type (threads or messages) used in notmuch queries.
++   */
++  { "nm_record", DT_BOOL, R_NONE, OPTNOTMUCHRECORD, 0 },
++  /*
++   ** .pp
++   ** This variable specifies if the mutt record should indexed by notmuch.
++   */
++  { "nm_record_tags", DT_STR, R_NONE, UL &NotmuchRecordTags, 0 },
++  /*
++   ** .pp
++   ** This variable specifies the default tags applied to messages stored to the mutt record.
++   */
++#endif
+   { "pager",		DT_PATH, R_NONE, UL &Pager, UL "builtin" },
+   /*
+   ** .pp
+@@ -2189,6 +2479,16 @@ struct option_t MuttVars[] = {
+   { "post_indent_str",  DT_SYN,  R_NONE, UL "post_indent_string", 0 },
+   /*
+   */
++#ifdef USE_NNTP
++  { "post_moderated",	DT_QUAD, R_NONE, OPT_TOMODERATED, M_ASKYES },
++  /*
++  ** .pp
++  ** If set to \fIyes\fP, Mutt will post article to newsgroup that have
++  ** not permissions to posting (e.g. moderated).  \fBNote:\fP if news server
++  ** does not support posting to that newsgroup or totally read-only, that
++  ** posting will not have an effect.
++  */
++#endif
+   { "postpone",		DT_QUAD, R_NONE, OPT_POSTPONE, M_ASKYES },
+   /*
+   ** .pp
+@@ -2665,6 +2965,164 @@ struct option_t MuttVars[] = {
+   ** Command to use when spawning a subshell.  By default, the user's login
+   ** shell from \fC/etc/passwd\fP is used.
+   */
++#ifdef USE_NNTP
++  { "save_unsubscribed", DT_BOOL, R_NONE, OPTSAVEUNSUB, 0 },
++  /*
++  ** .pp
++  ** When \fIset\fP, info about unsubscribed newsgroups will be saved into
++  ** ``newsrc'' file and into cache.
++  */
++  { "show_new_news",	DT_BOOL, R_NONE, OPTSHOWNEWNEWS, 1 },
++  /*
++  ** .pp
++  ** If \fIset\fP, news server will be asked for new newsgroups on entering
++  ** the browser.  Otherwise, it will be done only once for a news server.
++  ** Also controls whether or not number of new articles of subscribed
++  ** newsgroups will be then checked.
++  */
++  { "show_only_unread",	DT_BOOL, R_NONE, OPTSHOWONLYUNREAD, 0 },
++  /*
++  ** .pp
++  ** If \fIset\fP, only subscribed newsgroups that contain unread articles
++  ** will be displayed in browser.
++  */
++#endif
++#ifdef USE_SIDEBAR
++  { "sidebar_divider_char", DT_STR, R_SIDEBAR, UL &SidebarDividerChar, UL "|" },
++  /*
++  ** .pp
++  ** This specifies the characters to be drawn between the sidebar (when
++  ** visible) and the other Mutt panels. ASCII and Unicode line-drawing
++  ** characters are supported.
++  */
++  { "sidebar_delim_chars", DT_STR, R_SIDEBAR, UL &SidebarDelimChars, UL "/." },
++  /*
++  ** .pp
++  ** This contains the list of characters which you would like to treat
++  ** as folder separators for displaying paths in the sidebar.
++  ** .pp
++  ** Local mail is often arranged in directories: `dir1/dir2/mailbox'.
++  ** .ts
++  ** set sidebar_delim_chars='/'
++  ** .te
++  ** .pp
++  ** IMAP mailboxes are often named: `folder1.folder2.mailbox'.
++  ** .ts
++  ** set sidebar_delim_chars='.'
++  ** .te
++  ** .pp
++  ** \fBSee also:\fP $$sidebar_short_path, $$sidebar_folder_indent, $$sidebar_indent_string.
++  */
++  { "sidebar_folder_indent", DT_BOOL, R_SIDEBAR, OPTSIDEBARFOLDERINDENT, 0 },
++  /*
++  ** .pp
++  ** Set this to indent mailboxes in the sidebar.
++  ** .pp
++  ** \fBSee also:\fP $$sidebar_short_path, $$sidebar_indent_string, $$sidebar_delim_chars.
++  */
++  { "sidebar_format", DT_STR, R_SIDEBAR, UL &SidebarFormat, UL "%B%*  %n" },
++  /*
++  ** .pp
++  ** This variable allows you to customize the sidebar display. This string is
++  ** similar to $$index_format, but has its own set of \fCprintf(3)\fP-like
++  ** sequences:
++  ** .dl
++  ** .dt %B  .dd Name of the mailbox
++  ** .dt %S  .dd * Size of mailbox (total number of messages)
++  ** .dt %N  .dd * Number of New messages in the mailbox
++  ** .dt %n  .dd N if mailbox has new mail, blank otherwise
++  ** .dt %F  .dd * Number of Flagged messages in the mailbox
++  ** .dt %!  .dd ``!'' : one flagged message;
++  **             ``!!'' : two flagged messages;
++  **             ``n!'' : n flagged messages (for n > 2).
++  **             Otherwise prints nothing.
++  ** .dt %d  .dd * @ Number of deleted messages
++  ** .dt %L  .dd * @ Number of messages after limiting
++  ** .dt %t  .dd * @ Number of tagged messages
++  ** .dt %>X .dd right justify the rest of the string and pad with ``X''
++  ** .dt %|X .dd pad to the end of the line with ``X''
++  ** .dt %*X .dd soft-fill with character ``X'' as pad
++  ** .de
++  ** .pp
++  ** * = Can be optionally printed if nonzero
++  ** @ = Only applicable to the current folder
++  ** .pp
++  ** In order to use %S, %N, %F, and %!, $$mail_check_stats must
++  ** be \fIset\fP.  When thus set, a suggested value for this option is
++  ** "%B%?F? [%F]?%* %?N?%N/?%S".
++  */
++  { "sidebar_indent_string", DT_STR, R_SIDEBAR, UL &SidebarIndentString, UL "  " },
++  /*
++  ** .pp
++  ** This specifies the string that is used to indent mailboxes in the sidebar.
++  ** It defaults to two spaces.
++  ** .pp
++  ** \fBSee also:\fP $$sidebar_short_path, $$sidebar_folder_indent, $$sidebar_delim_chars.
++  */
++  { "sidebar_new_mail_only", DT_BOOL, R_SIDEBAR, OPTSIDEBARNEWMAILONLY, 0 },
++  /*
++  ** .pp
++  ** When set, the sidebar will only display mailboxes containing new, or
++  ** flagged, mail.
++  ** .pp
++  ** \fBSee also:\fP $sidebar_whitelist.
++  */
++  { "sidebar_next_new_wrap", DT_BOOL, R_NONE, UL OPTSIDEBARNEXTNEWWRAP, 0 },
++  /*
++  ** .pp
++  ** When set, the \fC<sidebar-next-new>\fP command will not stop and the end of
++  ** the list of mailboxes, but wrap around to the beginning. The
++  ** \fC<sidebar-prev-new>\fP command is similarly affected, wrapping around to
++  ** the end of the list.
++  */
++  { "sidebar_short_path", DT_BOOL, R_SIDEBAR, OPTSIDEBARSHORTPATH, 0 },
++  /*
++  ** .pp
++  ** By default the sidebar will show the mailbox's path, relative to the
++  ** $$folder variable. Setting \fCsidebar_shortpath=yes\fP will shorten the
++  ** names relative to the previous name. Here's an example:
++  ** .dl
++  ** .dt \fBshortpath=no\fP .dd \fBshortpath=yes\fP .dd \fBshortpath=yes, folderindent=yes, indentstr=".."\fP
++  ** .dt \fCfruit\fP        .dd \fCfruit\fP         .dd \fCfruit\fP
++  ** .dt \fCfruit.apple\fP  .dd \fCapple\fP         .dd \fC..apple\fP
++  ** .dt \fCfruit.banana\fP .dd \fCbanana\fP        .dd \fC..banana\fP
++  ** .dt \fCfruit.cherry\fP .dd \fCcherry\fP        .dd \fC..cherry\fP
++  ** .de
++  ** .pp
++  ** \fBSee also:\fP $$sidebar_delim_chars, $$sidebar_folder_indent, $$sidebar_indent_string.
++  */
++  { "sidebar_sort_method", DT_SORT|DT_SORT_SIDEBAR, R_SIDEBAR, UL &SidebarSortMethod, SORT_ORDER },
++  /*
++  ** .pp
++  ** Specifies how to sort entries in the file browser.  By default, the
++  ** entries are sorted alphabetically.  Valid values:
++  ** .il
++  ** .dd alpha (alphabetically)
++  ** .dd count (all message count)
++  ** .dd flagged (flagged message count)
++  ** .dd new (new message count)
++  ** .dd unsorted
++  ** .ie
++  ** .pp
++  ** You may optionally use the ``reverse-'' prefix to specify reverse sorting
++  ** order (example: ``\fCset sort_browser=reverse-date\fP'').
++  */
++  { "sidebar_visible", DT_BOOL, R_BOTH, OPTSIDEBAR, 0 },
++  /*
++  ** .pp
++  ** This specifies whether or not to show sidebar. The sidebar shows a list of
++  ** all your mailboxes.
++  ** .pp
++  ** \fBSee also:\fP $$sidebar_format, $$sidebar_width
++  */
++  { "sidebar_width", DT_NUM, R_BOTH, UL &SidebarWidth, 0 },
++  /*
++  ** .pp
++  ** This controls the width of the sidebar.  It is measured in screen columns.
++  ** For example: sidebar_width=20 could display 20 ASCII characters, or 10
++  ** Chinese characters.
++  */
++#endif
+   { "sig_dashes",	DT_BOOL, R_NONE, OPTSIGDASHES, 1 },
+   /*
+   ** .pp
+@@ -2703,6 +3161,12 @@ struct option_t MuttVars[] = {
+   ** replacing ``%s'' with the supplied string.
+   ** For the default value, ``joe'' would be expanded to: ``~f joe | ~s joe''.
+   */
++  { "skip_quoted_offset", DT_NUM, R_NONE, UL &SkipQuotedOffset, 0 },
++  /*
++  ** .pp
++  ** Lines of quoted text that are displayed before the unquoted text after
++  ** "skip to quoted" command (S)
++  */
+   { "sleep_time",	DT_NUM, R_NONE, UL &SleepTime, 1 },
+   /*
+   ** .pp
+@@ -2808,6 +3272,12 @@ struct option_t MuttVars[] = {
+   ** possible \fCprintf(3)\fP-like sequences.
+   ** (S/MIME only)
+   */
++  { "smime_encrypt_self",		DT_QUAD,	 R_NONE, OPT_SMIMEENCRYPTSELF, M_NO },
++  /*
++  ** .pp
++  ** Encrypt the message to $$smime_default_key too.
++  ** (S/MIME only)
++  */
+   { "smime_encrypt_with",	DT_STR,	 R_NONE, UL &SmimeCryptAlg, UL "aes256" },
+   /*
+   ** .pp
+@@ -3046,7 +3516,10 @@ struct option_t MuttVars[] = {
+   ** entries are sorted alphabetically.  Valid values:
+   ** .il
+   ** .dd alpha (alphabetically)
++  ** .dd count (all message count)
+   ** .dd date
++  ** .dd desc (description)
++  ** .dd new (new message count)
+   ** .dd size
+   ** .dd unsorted
+   ** .ie
+@@ -3057,14 +3530,15 @@ struct option_t MuttVars[] = {
+   { "sort_re",		DT_BOOL, R_INDEX|R_RESORT|R_RESORT_INIT, OPTSORTRE, 1 },
+   /*
+   ** .pp
+-  ** This variable is only useful when sorting by threads with
+-  ** $$strict_threads \fIunset\fP.  In that case, it changes the heuristic
+-  ** mutt uses to thread messages by subject.  With $$sort_re \fIset\fP, mutt will
+-  ** only attach a message as the child of another message by subject if
+-  ** the subject of the child message starts with a substring matching the
+-  ** setting of $$reply_regexp.  With $$sort_re \fIunset\fP, mutt will attach
+-  ** the message whether or not this is the case, as long as the
+-  ** non-$$reply_regexp parts of both messages are identical.
++  ** This variable is only useful when sorting by mailboxes in sidebar. By default,
++  ** entries are unsorted.  Valid values:
++  ** .il
++  ** .dd count (all message count)
++  ** .dd desc  (virtual mailbox description)
++  ** .dd new (new message count)
++  ** .dd path
++  ** .dd unsorted
++  ** .ie
+   */
+   { "spam_separator",   DT_STR, R_NONE, UL &SpamSep, UL "," },
+   /*
+@@ -3419,6 +3893,16 @@ struct option_t MuttVars[] = {
+   ** provided that ``$$ts_enabled'' has been set. This string is identical in
+   ** formatting to the one used by ``$$status_format''.
+   */
++  { "trash",            DT_PATH, R_NONE, UL &TrashPath, 0 },
++  /*
++  ** .pp
++  ** If set, this variable specifies the path of the trash folder where the
++  ** mails marked for deletion will be moved, instead of being irremediably
++  ** purged.
++  ** .pp
++  ** NOTE: When you delete a message in the trash folder, it is really
++  ** deleted, so that you have a way to clean the trash.
++  */
+ #ifdef USE_SOCKET
+   { "tunnel",            DT_STR, R_NONE, UL &Tunnel, UL 0 },
+   /*
+@@ -3507,6 +3991,31 @@ struct option_t MuttVars[] = {
+   ** Specifies the visual editor to invoke when the ``\fC~v\fP'' command is
+   ** given in the built-in editor.
+   */
++#ifdef USE_NOTMUCH
++  { "vfolder_format",	DT_STR,	 R_INDEX, UL &VirtFolderFormat, UL " %6n(%6N) %f " },
++  /*
++  ** .pp
++  ** This variable allows you to customize the file browser display for virtual
++  ** folders to your ** personal taste.  This string is similar to $$index_format,
++  ** but has its own set of \fCprintf(3)\fP-like sequences:
++  ** .dl
++  ** .dt %f  .dd folder name (description)
++  ** .dt %n  .dd number of all messages
++  ** .dt %N  .dd number of new messages
++  ** .dt %>X .dd right justify the rest of the string and pad with character ``X''
++  ** .dt %|X .dd pad to the end of the line with character ``X''
++  ** .dt %*X .dd soft-fill with character ``X'' as pad
++  ** .de
++  ** .pp
++  ** For an explanation of ``soft-fill'', see the $$index_format documentation.
++  */
++  { "virtual_spoolfile", DT_BOOL, R_NONE, OPTVIRTSPOOLFILE, 0 },
++  /*
++  ** .pp
++  ** When \fset\fP, mutt will use the first defined virtual mailbox (see
++  ** virtual-mailboxes) as a spool file.
++  */
++#endif
+   { "wait_key",		DT_BOOL, R_NONE, OPTWAITKEY, 1 },
+   /*
+   ** .pp
+@@ -3590,6 +4099,28 @@ struct option_t MuttVars[] = {
+   {"xterm_set_titles",	DT_SYN,  R_NONE, UL "ts_enabled", 0 },
+   /*
+   */
++  { "xlabel_delimiter", DT_STR, R_NONE, UL &XlabelDelim, UL "" },
++  /*
++  ** .pp
++  ** The character used to delimit distinct keywords in X-Label headers.
++  ** X-Label is primarily a Mutt artifact, and the semantics of the field
++  ** were never defined: it is free-form text.  However interaction with
++  ** X-Keywords:, X-Mozilla-Keys:, and Keywords: requires that we adopt
++  ** some means of identifying separate keywords within the field.  Set
++  ** this to your personal convention.
++  ** .pp
++  ** This affect both parsing existing X-Label headers and writing new
++  ** X-Label headers.  You can modify this variable in runtime to accomplish
++  ** various kinds of conversion.
++  */
++#ifdef USE_NNTP
++  { "x_comment_to",	DT_BOOL, R_NONE, OPTXCOMMENTTO, 0 },
++  /*
++  ** .pp
++  ** If \fIset\fP, Mutt will add ``X-Comment-To:'' field (that contains full
++  ** name of original article author) to article that followuped to newsgroup.
++  */
++#endif
+   /*--*/
+   { NULL, 0, 0, 0, 0 }
+ };
+@@ -3606,6 +4137,7 @@ const struct mapping_t SortMethods[] = {
+   { "to",		SORT_TO },
+   { "score",		SORT_SCORE },
+   { "spam",		SORT_SPAM },
++  { "label",		SORT_LABEL },
+   { NULL,               0 }
+ };
+ 
+@@ -3625,13 +4157,17 @@ const struct mapping_t SortAuxMethods[] = {
+   { "to",		SORT_TO },
+   { "score",		SORT_SCORE },
+   { "spam",		SORT_SPAM },
++  { "label",		SORT_LABEL },
+   { NULL,               0 }
+ };
+ 
+ 
+ const struct mapping_t SortBrowserMethods[] = {
+   { "alpha",	SORT_SUBJECT },
++  { "count",	SORT_COUNT },
+   { "date",	SORT_DATE },
++  { "desc",	SORT_DESC },
++  { "new",	SORT_COUNT_NEW },
+   { "size",	SORT_SIZE },
+   { "unsorted",	SORT_ORDER },
+   { NULL,       0 }
+@@ -3652,6 +4188,19 @@ const struct mapping_t SortKeyMethods[] = {
+   { NULL,       0 }
+ };
+ 
++const struct mapping_t SortSidebarMethods[] = {
++  { "alpha",		SORT_PATH },
++  { "count",		SORT_COUNT },
++  { "desc",		SORT_DESC },
++  { "flagged",		SORT_FLAGGED },
++  { "mailbox-order",	SORT_ORDER },
++  { "name",		SORT_PATH },
++  { "new",		SORT_COUNT_NEW },
++  { "path",		SORT_PATH },
++  { "unsorted",		SORT_ORDER },
++  { NULL,		0 }
++};
 +
-+  /* store current values of first and last */
-+  if (!old || nntp_data->firstMessage != first ||
-+	      nntp_data->lastMessage != last)
-+  {
-+    snprintf (buf, sizeof (buf), "%u %u", nntp_data->firstMessage,
-+					  nntp_data->lastMessage);
-+    dprint (2, (debugfile,
-+		"nntp_hcache_update: mutt_hcache_store index: %s\n", buf));
-+    mutt_hcache_store_raw (hc, "index", buf, strlen (buf) + 1, strlen);
-+  }
-+}
+ 
+ /* functions used to parse commands in a rc file */
+ 
+@@ -3665,6 +4214,8 @@ static int parse_lists (BUFFER *, BUFFER *, unsigned long, BUFFER *);
+ static int parse_unlists (BUFFER *, BUFFER *, unsigned long, BUFFER *);
+ static int parse_alias (BUFFER *, BUFFER *, unsigned long, BUFFER *);
+ static int parse_unalias (BUFFER *, BUFFER *, unsigned long, BUFFER *);
++static int finish_source (BUFFER *, BUFFER *, unsigned long, BUFFER *);
++static int parse_ifdef (BUFFER *, BUFFER *, unsigned long, BUFFER *);
+ static int parse_ignore (BUFFER *, BUFFER *, unsigned long, BUFFER *);
+ static int parse_unignore (BUFFER *, BUFFER *, unsigned long, BUFFER *);
+ static int parse_source (BUFFER *, BUFFER *, unsigned long, BUFFER *);
+@@ -3676,13 +4227,16 @@ static int parse_unsubscribe (BUFFER *, BUFFER *, unsigned long, BUFFER *);
+ static int parse_attachments (BUFFER *, BUFFER *, unsigned long, BUFFER *);
+ static int parse_unattachments (BUFFER *, BUFFER *, unsigned long, BUFFER *);
+ 
+-
+ static int parse_alternates (BUFFER *, BUFFER *, unsigned long, BUFFER *);
+ static int parse_unalternates (BUFFER *, BUFFER *, unsigned long, BUFFER *);
+ 
+ /* Parse -group arguments */
+ static int parse_group_context (group_context_t **ctx, BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err);
+ 
++#ifdef USE_NOTMUCH
++static int parse_tag_transforms (BUFFER *, BUFFER *, unsigned long, BUFFER *);
++static int parse_tag_formats (BUFFER *, BUFFER *, unsigned long, BUFFER *);
++#endif
+ 
+ struct command_t
+ {
+@@ -3712,9 +4266,17 @@ const struct command_t Commands[] = {
+   { "fcc-hook",		mutt_parse_hook,	M_FCCHOOK },
+   { "fcc-save-hook",	mutt_parse_hook,	M_FCCHOOK | M_SAVEHOOK },
+   { "folder-hook",	mutt_parse_hook,	M_FOLDERHOOK },
++#ifdef USE_COMPRESSED
++  { "open-hook",	mutt_parse_hook,	M_OPENHOOK },
++  { "close-hook",	mutt_parse_hook,	M_CLOSEHOOK },
++  { "append-hook",	mutt_parse_hook,	M_APPENDHOOK },
++#endif
+   { "group",		parse_group,		M_GROUP },
+   { "ungroup",		parse_group,		M_UNGROUP },
+   { "hdr_order",	parse_list,		UL &HeaderOrderList },
++  { "ifdef",		parse_ifdef,		0 },
++  { "ifndef",		parse_ifdef,		1 },
++  { "finish",		finish_source,		0 },
+ #ifdef HAVE_ICONV
+   { "iconv-hook",	mutt_parse_hook,	M_ICONVHOOK },
+ #endif
+@@ -3723,6 +4285,11 @@ const struct command_t Commands[] = {
+   { "macro",		mutt_parse_macro,	0 },
+   { "mailboxes",	mutt_parse_mailboxes,	M_MAILBOXES },
+   { "unmailboxes",	mutt_parse_mailboxes,	M_UNMAILBOXES },
++#ifdef USE_NOTMUCH
++  { "virtual-mailboxes",mutt_parse_virtual_mailboxes, 0 },
++  { "tag-transforms",	parse_tag_transforms,	0 },
++  { "tag-formats",	parse_tag_formats,	0 },
++#endif
+   { "mailto_allow",	parse_list,		UL &MailtoAllow },
+   { "unmailto_allow",	parse_unlist,		UL &MailtoAllow },
+   { "message-hook",	mutt_parse_hook,	M_MESSAGEHOOK },
+@@ -3741,6 +4308,9 @@ const struct command_t Commands[] = {
+   { "send-hook",	mutt_parse_hook,	M_SENDHOOK },
+   { "send2-hook",	mutt_parse_hook,	M_SEND2HOOK },
+   { "set",		parse_set,		0 },
++#ifdef USE_SIDEBAR
++  { "sidebar_whitelist",parse_list,		UL &SidebarWhitelist },
++#endif
+   { "source",		parse_source,		0 },
+   { "spam",		parse_spam_list,	M_SPAM },
+   { "nospam",		parse_spam_list,	M_NOSPAM },
+diff --git a/keymap.c b/keymap.c
+index 09bef6b..4d7103d 100644
+--- a/keymap.c
++++ b/keymap.c
+@@ -76,10 +76,8 @@ static struct mapping_t KeyNames[] = {
+   { "<Insert>",	KEY_IC },
+   { "<Home>",	KEY_HOME },
+   { "<End>",	KEY_END },
+-#ifdef KEY_ENTER
+-  { "<Enter>",	KEY_ENTER },
+-#endif
+-  { "<Return>",	M_ENTER_C },
++  { "<Enter>",	'\n' },
++  { "<Return>",	'\r' },
+   { "<Esc>",	'\033' },
+   { "<Tab>",	'\t' },
+   { "<Space>",	' ' },
+@@ -785,6 +783,7 @@ void km_init (void)
+   km_bindkey ("8", MENU_GENERIC, OP_JUMP);
+   km_bindkey ("9", MENU_GENERIC, OP_JUMP);
+ 
++  km_bindkey ("<return>", MENU_GENERIC, OP_GENERIC_SELECT_ENTRY);
+   km_bindkey ("<enter>", MENU_GENERIC, OP_GENERIC_SELECT_ENTRY);
+ 
+   /* Miscellaneous extra bindings */
+@@ -796,10 +795,10 @@ void km_init (void)
+   km_bindkey ("K", MENU_MAIN, OP_PREV_ENTRY);
+   km_bindkey ("x", MENU_MAIN, OP_EXIT);
+ 
++  km_bindkey ("<return>", MENU_MAIN, OP_DISPLAY_MESSAGE);
+   km_bindkey ("<enter>", MENU_MAIN, OP_DISPLAY_MESSAGE);
+ 
+   km_bindkey ("x", MENU_PAGER, OP_EXIT);
+-  km_bindkey ("i", MENU_PAGER, OP_EXIT);
+   km_bindkey ("<backspace>", MENU_PAGER, OP_PREV_LINE);
+   km_bindkey ("<pagedown>", MENU_PAGER, OP_NEXT_PAGE);
+   km_bindkey ("<pageup>", MENU_PAGER, OP_PREV_PAGE);
+@@ -819,13 +818,16 @@ void km_init (void)
+   km_bindkey ("8", MENU_PAGER, OP_JUMP);
+   km_bindkey ("9", MENU_PAGER, OP_JUMP);
+ 
++  km_bindkey ("<return>", MENU_PAGER, OP_NEXT_LINE);
+   km_bindkey ("<enter>", MENU_PAGER, OP_NEXT_LINE);
+   
+   km_bindkey ("<return>", MENU_ALIAS, OP_GENERIC_SELECT_ENTRY);
+   km_bindkey ("<enter>",  MENU_ALIAS, OP_GENERIC_SELECT_ENTRY);
+   km_bindkey ("<space>", MENU_ALIAS, OP_TAG);
+ 
++  km_bindkey ("<return>", MENU_ATTACH, OP_VIEW_ATTACH);
+   km_bindkey ("<enter>", MENU_ATTACH, OP_VIEW_ATTACH);
++  km_bindkey ("<return>", MENU_COMPOSE, OP_VIEW_ATTACH);
+   km_bindkey ("<enter>", MENU_COMPOSE, OP_VIEW_ATTACH);
+ 
+   /* edit-to (default "t") hides generic tag-entry in Compose menu
+diff --git a/lib.c b/lib.c
+index 2f500bc..fa3067e 100644
+--- a/lib.c
++++ b/lib.c
+@@ -219,8 +219,10 @@ int safe_fsync_close (FILE **f)
+   {
+     if (fflush (*f) || fsync (fileno (*f)))
+     {
++      int save_errno = errno;
+       r = -1;
+       safe_fclose (f);
++      errno = save_errno;
+     }
+     else
+       r = safe_fclose (f);
+@@ -367,6 +369,7 @@ int mutt_copy_bytes (FILE *in, FILE *out, size_t size)
+     size -= chunk;
+   }
+ 
++  if (fflush(out) != 0) return -1;
+   return 0;
+ }
+ 
+@@ -381,6 +384,7 @@ int mutt_copy_stream (FILE *fin, FILE *fout)
+       return (-1);
+   }
+ 
++  if (fflush(fout) != 0) return -1;
+   return 0;
+ }
+ 
+diff --git a/m4/gssapi.m4 b/m4/gssapi.m4
+index e8451ea..0e0194e 100644
+--- a/m4/gssapi.m4
++++ b/m4/gssapi.m4
+@@ -23,8 +23,8 @@ AC_DEFUN([MUTT_AM_PATH_GSSAPI],
+   AC_PATH_PROG(KRB5CFGPATH, krb5-config, none, $krb5_path)
+   if test "$KRB5CFGPATH" != "none"
+   then
+-    GSSAPI_CFLAGS="$CPPFLAGS `$KRB5CFGPATH --cflags gssapi`"
+-    GSSAPI_LIBS="$MUTTLIBS `$KRB5CFGPATH --libs gssapi`"
++    GSSAPI_CFLAGS="`$KRB5CFGPATH --cflags gssapi`"
++    GSSAPI_LIBS="`$KRB5CFGPATH --libs gssapi`"
+     case "`$KRB5CFGPATH --version`" in
+       "Kerberos 5 "*)	GSSAPI_IMPL="MIT";;
+       ?eimdal*)		GSSAPI_IMPL="Heimdal";;
+diff --git a/mailbox.h b/mailbox.h
+index 2b2c9a1..1b1cad1 100644
+--- a/mailbox.h
++++ b/mailbox.h
+@@ -20,13 +20,13 @@
+ #define _MAILBOX_H
+ 
+ /* flags for mutt_open_mailbox() */
+-#define M_NOSORT	(1<<0) /* do not sort the mailbox after opening it */
+-#define M_APPEND	(1<<1) /* open mailbox for appending messages */
+-#define M_READONLY	(1<<2) /* open in read-only mode */
+-#define M_QUIET		(1<<3) /* do not print any messages */
+-#define M_NEWFOLDER	(1<<4) /* create a new folder - same as M_APPEND, but uses
+-				* safe_fopen() for mbox-style folders.
+-				*/
++#define M_NOSORT     (1<<0) /* do not sort the mailbox after opening it */
++#define M_APPEND     (1<<1) /* open mailbox for appending messages */
++#define M_READONLY   (1<<2) /* open in read-only mode */
++#define M_QUIET      (1<<3) /* do not print any messages */
++#define M_NEWFOLDER  (1<<4) /* create a new folder - same as M_APPEND, but uses
++                                * safe_fopen() for mbox-style folders. */
++#define M_PEEK       (1<<5) /* revert atime back after taking a look (if applicable) */
+ 
+ /* mx_open_new_message() */
+ #define M_ADD_FROM	(1<<0)	/* add a From_ line */
+@@ -45,6 +45,7 @@ typedef struct
+ {
+   FILE *fp;	/* pointer to the message data */
+   char *path;	/* path to temp file */
++  char *commited_path; /* the final path generated by mx_commit_message() */
+   short magic;	/* type of mailbox this message belongs to */
+   short write;	/* nonzero if message is open for writing */
+   struct {
+@@ -76,6 +77,9 @@ int mx_is_imap (const char *);
+ #ifdef USE_POP
+ int mx_is_pop (const char *);
+ #endif
++#ifdef USE_NNTP
++int mx_is_nntp (const char *);
++#endif
+ 
+ int mx_access (const char*, int);
+ int mx_check_empty (const char *);
+diff --git a/main.c b/main.c
+index d0a1128..09d6be6 100644
+--- a/main.c
++++ b/main.c
+@@ -31,6 +31,10 @@
+ #include "url.h"
+ #include "mutt_crypt.h"
+ #include "mutt_idna.h"
++#ifdef USE_SIDEBAR
++#include "sidebar.h"
++#endif
++#include "version.h"
+ 
+ #ifdef USE_SASL
+ #include "mutt_sasl.h"
+@@ -62,45 +66,9 @@
+ #include <idn/stringprep.h>
+ #endif
+ 
+-static const char *ReachingUs = N_("\
+-To contact the developers, please mail to <mutt-dev at mutt.org>.\n\
+-To report a bug, please visit http://bugs.mutt.org/.\n");
+-
+-static const char *Notice = N_("\
+-Copyright (C) 1996-2016 Michael R. Elkins and others.\n\
+-Mutt comes with ABSOLUTELY NO WARRANTY; for details type `mutt -vv'.\n\
+-Mutt is free software, and you are welcome to redistribute it\n\
+-under certain conditions; type `mutt -vv' for details.\n");
+-
+-static const char *Copyright = N_("\
+-Copyright (C) 1996-2014 Michael R. Elkins <me at mutt.org>\n\
+-Copyright (C) 1996-2002 Brandon Long <blong at fiction.net>\n\
+-Copyright (C) 1997-2009 Thomas Roessler <roessler at does-not-exist.org>\n\
+-Copyright (C) 1998-2005 Werner Koch <wk at isil.d.shuttle.de>\n\
+-Copyright (C) 1999-2014 Brendan Cully <brendan at kublai.com>\n\
+-Copyright (C) 1999-2002 Tommi Komulainen <Tommi.Komulainen at iki.fi>\n\
+-Copyright (C) 2000-2004 Edmund Grimley Evans <edmundo at rano.org>\n\
+-Copyright (C) 2006-2009 Rocco Rutte <pdmef at gmx.net>\n\
+-Copyright (C) 2014-2015 Kevin J. McCarthy <kevin at 8t8.us>\n\
+-\n\
+-Many others not mentioned here contributed code, fixes,\n\
+-and suggestions.\n");
+-
+-static const char *Licence = N_("\
+-    This program is free software; you can redistribute it and/or modify\n\
+-    it under the terms of the GNU General Public License as published by\n\
+-    the Free Software Foundation; either version 2 of the License, or\n\
+-    (at your option) any later version.\n\
+-\n\
+-    This program is distributed in the hope that it will be useful,\n\
+-    but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
+-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n\
+-    GNU General Public License for more details.\n");
+-static const char *Obtaining = N_("\
+-    You should have received a copy of the GNU General Public License\n\
+-    along with this program; if not, write to the Free Software\n\
+-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\n\
+-");
++#ifdef USE_NNTP
++#include "nntp.h"
++#endif
+ 
+ void mutt_exit (int code)
+ {
+@@ -138,6 +106,8 @@ options:\n\
+   -e <command>\tspecify a command to be executed after initialization\n\
+   -f <file>\tspecify which mailbox to read\n\
+   -F <file>\tspecify an alternate muttrc file\n\
++  -g <server>\tspecify a news server (if compiled with NNTP)\n\
++  -G\t\tselect a newsgroup (if compiled with NNTP)\n\
+   -H <file>\tspecify a draft file to read header and body from\n\
+   -i <file>\tspecify a file which Mutt should include in the body\n\
+   -m <type>\tspecify a default mailbox type\n\
+@@ -158,359 +128,6 @@ options:\n\
+   exit (0);
+ }
+ 
+-extern const char cc_version[];
+-extern const char cc_cflags[];
+-extern const char configure_options[];
+-
+-static char *
+-rstrip_in_place(char *s)
+-{
+-  char *p;
+-
+-  p = &s[strlen(s)];
+-  if (p == s)
+-    return s;
+-  p--;
+-  while (p >= s && (*p == '\n' || *p == '\r'))
+-    *p-- = '\0';
+-  return s;
+-}
+-
+-static void show_version (void)
+-{
+-  struct utsname uts;
+-
+-  puts (mutt_make_version());
+-  puts (_(Notice));
+-
+-  uname (&uts);
+-
+-#ifdef _AIX
+-  printf ("System: %s %s.%s", uts.sysname, uts.version, uts.release);
+-#elif defined (SCO)
+-  printf ("System: SCO %s", uts.release);
+-#else
+-  printf ("System: %s %s", uts.sysname, uts.release);
+-#endif
+-
+-  printf (" (%s)", uts.machine);
+-
+-#ifdef NCURSES_VERSION
+-  printf ("\nncurses: %s (compiled with %s)", curses_version(), NCURSES_VERSION);
+-#elif defined(USE_SLANG_CURSES)
+-  printf ("\nslang: %d", SLANG_VERSION);
+-#endif
+-
+-#ifdef _LIBICONV_VERSION
+-  printf ("\nlibiconv: %d.%d", _LIBICONV_VERSION >> 8,
+-	  _LIBICONV_VERSION & 0xff);
+-#endif
+-
+-#ifdef HAVE_LIBIDN
+-  printf ("\nlibidn: %s (compiled with %s)", stringprep_check_version (NULL), 
+-	  STRINGPREP_VERSION);
+-#endif
+-
+-#ifdef USE_HCACHE
+-  printf ("\nhcache backend: %s", mutt_hcache_backend ());
+-#endif
+-
+-  puts ("\n\nCompiler:");
+-  rstrip_in_place((char *)cc_version);
+-  puts (cc_version);
+-
+-  rstrip_in_place((char *)configure_options);
+-  printf ("\nConfigure options: %s\n", configure_options);
+-
+-  rstrip_in_place((char *)cc_cflags);
+-  printf ("\nCompilation CFLAGS: %s\n", cc_cflags);
+-
+-  puts (_("\nCompile options:"));
+-
+-#ifdef DOMAIN
+-  printf ("DOMAIN=\"%s\"\n", DOMAIN);
+-#else
+-  puts ("-DOMAIN");
+-#endif
+-
+-#ifdef DEBUG
+-  puts ("+DEBUG");
+-#else
+-  puts ("-DEBUG");
+-#endif
+-  
+-
+-  
+-  puts (
+-
+-#ifdef HOMESPOOL
+-	"+HOMESPOOL  "
+-#else
+-	"-HOMESPOOL  "
+-#endif
+-
+-#ifdef USE_SETGID
+-	"+USE_SETGID  "
+-#else
+-	"-USE_SETGID  "
+-#endif
+-
+-#ifdef USE_DOTLOCK
+-	"+USE_DOTLOCK  "
+-#else
+-	"-USE_DOTLOCK  "
+-#endif
+-
+-#ifdef DL_STANDALONE
+-	"+DL_STANDALONE  "
+-#else
+-	"-DL_STANDALONE  "
+-#endif
+-
+-#ifdef USE_FCNTL
+-	"+USE_FCNTL  "
+-#else
+-	"-USE_FCNTL  "
+-#endif
+-
+-#ifdef USE_FLOCK
+-	"+USE_FLOCK   "
+-#else
+-	"-USE_FLOCK   "
+-#endif
+-    );
+-  puts (
+-#ifdef USE_POP
+-	"+USE_POP  "
+-#else
+-	"-USE_POP  "
+-#endif
+-
+-#ifdef USE_IMAP
+-        "+USE_IMAP  "
+-#else
+-        "-USE_IMAP  "
+-#endif
+-
+-#ifdef USE_SMTP
+-	"+USE_SMTP  "
+-#else
+-	"-USE_SMTP  "
+-#endif
+-	"\n"
+-	
+-#ifdef USE_SSL_OPENSSL
+-	"+USE_SSL_OPENSSL  "
+-#else
+-	"-USE_SSL_OPENSSL  "
+-#endif
+-
+-#ifdef USE_SSL_GNUTLS
+-	"+USE_SSL_GNUTLS  "
+-#else
+-	"-USE_SSL_GNUTLS  "
+-#endif
+-
+-#ifdef USE_SASL
+-	"+USE_SASL  "
+-#else
+-	"-USE_SASL  "
+-#endif
+-#ifdef USE_GSS
+-	"+USE_GSS  "
+-#else
+-	"-USE_GSS  "
+-#endif
+-
+-#if HAVE_GETADDRINFO
+-	"+HAVE_GETADDRINFO  "
+-#else
+-	"-HAVE_GETADDRINFO  "
+-#endif
+-        );
+-  	
+-  puts (
+-#ifdef HAVE_REGCOMP
+-	"+HAVE_REGCOMP  "
+-#else
+-	"-HAVE_REGCOMP  "
+-#endif
+-
+-#ifdef USE_GNU_REGEX
+-	"+USE_GNU_REGEX  "
+-#else
+-	"-USE_GNU_REGEX  "
+-#endif
+-
+-	"\n"
+-	
+-#ifdef HAVE_COLOR
+-	"+HAVE_COLOR  "
+-#else
+-	"-HAVE_COLOR  "
+-#endif
+-	
+-#ifdef HAVE_START_COLOR
+-	"+HAVE_START_COLOR  "
+-#else
+-	"-HAVE_START_COLOR  "
+-#endif
+-	
+-#ifdef HAVE_TYPEAHEAD
+-	"+HAVE_TYPEAHEAD  "
+-#else
+-	"-HAVE_TYPEAHEAD  "
+-#endif
+-	
+-#ifdef HAVE_BKGDSET
+-	"+HAVE_BKGDSET  "
+-#else
+-	"-HAVE_BKGDSET  "
+-#endif
+-
+-	"\n"
+-	
+-#ifdef HAVE_CURS_SET
+-	"+HAVE_CURS_SET  "
+-#else
+-	"-HAVE_CURS_SET  "
+-#endif
+-	
+-#ifdef HAVE_META
+-	"+HAVE_META  "
+-#else
+-	"-HAVE_META  "
+-#endif
+-	
+-#ifdef HAVE_RESIZETERM
+-	"+HAVE_RESIZETERM  "
+-#else
+-	"-HAVE_RESIZETERM  "
+-#endif
+-        );	
+-  
+-  puts (
+-#ifdef CRYPT_BACKEND_CLASSIC_PGP
+-        "+CRYPT_BACKEND_CLASSIC_PGP  "
+-#else
+-        "-CRYPT_BACKEND_CLASSIC_PGP  "
+-#endif
+-#ifdef CRYPT_BACKEND_CLASSIC_SMIME
+-        "+CRYPT_BACKEND_CLASSIC_SMIME  "
+-#else
+-        "-CRYPT_BACKEND_CLASSIC_SMIME  "
+-#endif
+-#ifdef CRYPT_BACKEND_GPGME
+-        "+CRYPT_BACKEND_GPGME  "
+-#else
+-        "-CRYPT_BACKEND_GPGME  "
+-#endif
+-        );
+-  
+-  puts (
+-#ifdef EXACT_ADDRESS
+-	"+EXACT_ADDRESS  "
+-#else
+-	"-EXACT_ADDRESS  "
+-#endif
+-
+-#ifdef SUN_ATTACHMENT
+-	"+SUN_ATTACHMENT  "
+-#else
+-	"-SUN_ATTACHMENT  "
+-#endif
+-
+-	"\n"
+-	
+-#ifdef ENABLE_NLS
+-	"+ENABLE_NLS  "
+-#else
+-	"-ENABLE_NLS  "
+-#endif
+-
+-#ifdef LOCALES_HACK
+-	"+LOCALES_HACK  "
+-#else
+-	"-LOCALES_HACK  "
+-#endif
+-	      
+-#ifdef HAVE_WC_FUNCS
+-	"+HAVE_WC_FUNCS  "
+-#else
+-	"-HAVE_WC_FUNCS  "
+-#endif
+-	
+-#ifdef HAVE_LANGINFO_CODESET
+-	"+HAVE_LANGINFO_CODESET  "
+-#else
+-	"-HAVE_LANGINFO_CODESET  "
+-#endif
+-
+-	
+-#ifdef HAVE_LANGINFO_YESEXPR
+- 	"+HAVE_LANGINFO_YESEXPR  "
+-#else
+- 	"-HAVE_LANGINFO_YESEXPR  "
+-#endif
+-	
+-	"\n"
+-
+-#if HAVE_ICONV
+-	"+HAVE_ICONV  "
+-#else
+-	"-HAVE_ICONV  "
+-#endif
+-
+-#if ICONV_NONTRANS
+-	"+ICONV_NONTRANS  "
+-#else
+-	"-ICONV_NONTRANS  "
+-#endif
+-
+-#if HAVE_LIBIDN
+-	"+HAVE_LIBIDN  "
+-#else
+-	"-HAVE_LIBIDN  "
+-#endif
+-	
+-#if HAVE_GETSID
+-	"+HAVE_GETSID  "
+-#else
+-	"-HAVE_GETSID  "
+-#endif
+-
+-#if USE_HCACHE
+-	"+USE_HCACHE  "
+-#else
+-	"-USE_HCACHE  "
+-#endif
+-
+-	);
+-
+-#ifdef ISPELL
+-  printf ("ISPELL=\"%s\"\n", ISPELL);
+-#else
+-  puts ("-ISPELL");
+-#endif
+-
+-  printf ("SENDMAIL=\"%s\"\n", SENDMAIL);
+-  printf ("MAILPATH=\"%s\"\n", MAILPATH);
+-  printf ("PKGDATADIR=\"%s\"\n", PKGDATADIR);
+-  printf ("SYSCONFDIR=\"%s\"\n", SYSCONFDIR);
+-  printf ("EXECSHELL=\"%s\"\n", EXECSHELL);
+-#ifdef MIXMASTER
+-  printf ("MIXMASTER=\"%s\"\n", MIXMASTER);
+-#else
+-  puts ("-MIXMASTER");
+-#endif
+-
+-  puts(_(ReachingUs));
+-
+-  mutt_print_patchlist();
+-  
+-  exit (0);
+-}
+-
+ static void start_curses (void)
+ {
+   km_init (); /* must come before mutt_init */
+@@ -540,6 +157,7 @@ static void start_curses (void)
+   keypad (stdscr, TRUE);
+   cbreak ();
+   noecho ();
++  nonl ();
+ #if HAVE_TYPEAHEAD
+   typeahead (-1);       /* simulate smooth scrolling */
+ #endif
+@@ -554,6 +172,9 @@ init_extended_keys();
+ #define M_NOSYSRC (1<<2)	/* -n */
+ #define M_RO      (1<<3)	/* -R */
+ #define M_SELECT  (1<<4)	/* -y */
++#ifdef USE_NNTP
++#define M_NEWS    (1<<5)	/* -g and -G */
 +#endif
-+
-+/* Remove bcache file */
-+static int nntp_bcache_delete (const char *id, body_cache_t *bcache, void *data)
-+{
-+  NNTP_DATA *nntp_data = data;
-+  anum_t anum;
-+  char c;
-+
-+  if (!nntp_data || sscanf (id, ANUM "%c", &anum, &c) != 1 ||
-+      anum < nntp_data->firstMessage || anum > nntp_data->lastMessage)
-+  {
-+    if (nntp_data)
-+      dprint (2, (debugfile, "nntp_bcache_delete: mutt_bcache_del %s\n", id));
-+    mutt_bcache_del (bcache, id);
-+  }
-+  return 0;
-+}
-+
-+/* Remove stale cached messages */
-+void nntp_bcache_update (NNTP_DATA *nntp_data)
-+{
-+  mutt_bcache_list (nntp_data->bcache, nntp_bcache_delete, nntp_data);
-+}
-+
-+/* Remove hcache and bcache of newsgroup */
-+void nntp_delete_group_cache (NNTP_DATA *nntp_data)
-+{
-+  char file[_POSIX_PATH_MAX];
-+
-+  if (!nntp_data || !nntp_data->nserv || !nntp_data->nserv->cacheable)
-+    return;
-+
-+#ifdef USE_HCACHE
-+  nntp_hcache_namer (nntp_data->group, file, sizeof (file));
-+  cache_expand (file, sizeof (file), &nntp_data->nserv->conn->account, file);
-+  unlink (file);
-+  nntp_data->lastCached = 0;
-+  dprint (2, (debugfile, "nntp_delete_group_cache: %s\n", file));
+ 
+ int main (int argc, char **argv)
+ {
+@@ -598,7 +219,7 @@ int main (int argc, char **argv)
+ 
+   mutt_error = mutt_nocurses_error;
+   mutt_message = mutt_nocurses_error;
+-  SRAND (time (NULL));
++  (void)mutt_rand32();
+   umask (077);
+ 
+   memset (Options, 0, sizeof (Options));
+@@ -627,7 +248,11 @@ int main (int argc, char **argv)
+         argv[nargc++] = argv[optind];
+     }
+ 
++#ifdef USE_NNTP
++    if ((i = getopt (argc, argv, "+A:a:b:F:f:c:Dd:Ee:g:GH:s:i:hm:npQ:RvxyzZ")) != EOF)
++#else
+     if ((i = getopt (argc, argv, "+A:a:b:F:f:c:Dd:Ee:H:s:i:hm:npQ:RvxyzZ")) != EOF)
 +#endif
+       switch (i)
+       {
+       case 'A':
+@@ -728,6 +353,20 @@ int main (int argc, char **argv)
+ 	flags |= M_SELECT;
+ 	break;
+ 
++#ifdef USE_NNTP
++      case 'g': /* Specify a news server */
++	{
++	  char buf[LONG_STRING];
 +
-+  if (!nntp_data->bcache)
-+    nntp_data->bcache = mutt_bcache_open (&nntp_data->nserv->conn->account,
-+			nntp_data->group);
-+  if (nntp_data->bcache)
-+  {
-+    dprint (2, (debugfile, "nntp_delete_group_cache: %s/*\n", nntp_data->group));
-+    mutt_bcache_list (nntp_data->bcache, nntp_bcache_delete, NULL);
-+    mutt_bcache_close (&nntp_data->bcache);
-+  }
-+}
-+
-+/* Remove hcache and bcache of all unexistent and unsubscribed newsgroups */
-+void nntp_clear_cache (NNTP_SERVER *nserv)
-+{
-+  char file[_POSIX_PATH_MAX];
-+  char *fp;
-+  struct dirent *entry;
-+  DIR *dp;
-+
-+  if (!nserv || !nserv->cacheable)
-+    return;
-+
-+  cache_expand (file, sizeof (file), &nserv->conn->account, NULL);
-+  dp = opendir (file);
-+  if (dp)
-+  {
-+    safe_strncat (file, sizeof (file), "/", 1);
-+    fp = file + strlen (file);
-+    while ((entry = readdir (dp)))
-+    {
-+      char *group = entry->d_name;
-+      struct stat sb;
-+      NNTP_DATA *nntp_data;
-+      NNTP_DATA nntp_tmp;
++	  snprintf (buf, sizeof (buf), "set news_server=%s", optarg);
++	  commands = mutt_add_list (commands, buf);
++	}
 +
-+      if (mutt_strcmp (group, ".") == 0 ||
-+	  mutt_strcmp (group, "..") == 0)
-+	continue;
-+      *fp = '\0';
-+      safe_strncat (file, sizeof (file), group, strlen (group));
-+      if (stat (file, &sb))
-+	continue;
++      case 'G': /* List of newsgroups */
++	flags |= M_SELECT | M_NEWS;
++	break;
++#endif
 +
-+#ifdef USE_HCACHE
-+      if (S_ISREG (sb.st_mode))
+       case 'z':
+ 	flags |= M_IGNORE;
+ 	break;
+@@ -752,14 +391,10 @@ int main (int argc, char **argv)
+     case 0:
+       break;
+     case 1:
+-      show_version ();
+-      break;
++      print_version();
++      exit (0);
+     default:
+-      puts (mutt_make_version ());
+-      puts (_(Copyright));
+-      puts (_(Licence));
+-      puts (_(Obtaining));
+-      puts (_(ReachingUs));
++      print_copyright();
+       exit (0);
+   }
+ 
+@@ -828,6 +463,9 @@ int main (int argc, char **argv)
+     clear ();
+     mutt_error = mutt_curses_error;
+     mutt_message = mutt_curses_message;
++#ifdef USE_SIDEBAR
++    mutt_sb_init();
++#endif
+   }
+ 
+   /* Create the Maildir directory if it doesn't exist. */
+@@ -1167,6 +805,18 @@ int main (int argc, char **argv)
+     }
+     else if (flags & M_SELECT)
+     {
++#ifdef USE_NNTP
++      if (flags & M_NEWS)
 +      {
-+	char *ext = group + strlen (group) - 7;
-+	if (strlen (group) < 8 || mutt_strcmp (ext, ".hcache"))
-+	  continue;
-+	*ext = '\0';
++	set_option (OPTNEWS);
++	if(!(CurrentNewsSrv = nntp_select_server (NewsServer, 0)))
++	{
++	  mutt_endwin (Errorbuf);
++	  exit (1);
++	}
 +      }
 +      else
 +#endif
-+      if (!S_ISDIR (sb.st_mode))
-+	continue;
-+
-+      nntp_data = hash_find (nserv->groups_hash, group);
-+      if (!nntp_data)
-+      {
-+	nntp_data = &nntp_tmp;
-+	nntp_data->nserv = nserv;
-+	nntp_data->group = group;
-+	nntp_data->bcache = NULL;
-+      }
-+      else if (nntp_data->newsrc_ent || nntp_data->subscribed ||
-+	       option (OPTSAVEUNSUB))
-+	continue;
+       if (!Incoming) {
+ 	mutt_endwin _("No incoming mailboxes defined.");
+ 	exit (1);
+@@ -1182,6 +832,15 @@ int main (int argc, char **argv)
+ 
+     if (!folder[0])
+       strfcpy (folder, NONULL(Spoolfile), sizeof (folder));
 +
-+      nntp_delete_group_cache (nntp_data);
-+      if (S_ISDIR (sb.st_mode))
-+      {
-+	rmdir (file);
-+	dprint (2, (debugfile, "nntp_clear_cache: %s\n", file));
-+      }
++#ifdef USE_NNTP
++    if (option (OPTNEWS))
++    {
++      unset_option (OPTNEWS);
++      nntp_expand_path (folder, sizeof (folder), &CurrentNewsSrv->conn->account);
 +    }
-+    closedir (dp);
-+  }
-+  return;
-+}
-+
-+/* %a = account url
-+ * %p = port
-+ * %P = port if specified
-+ * %s = news server name
-+ * %S = url schema
-+ * %u = username */
-+const char *
-+nntp_format_str (char *dest, size_t destlen, size_t col, char op, const char *src,
-+		const char *fmt, const char *ifstring, const char *elsestring,
-+		unsigned long data, format_flag flags)
-+{
-+  NNTP_SERVER *nserv = (NNTP_SERVER *)data;
-+  ACCOUNT *acct = &nserv->conn->account;
-+  ciss_url_t url;
-+  char fn[SHORT_STRING], tmp[SHORT_STRING], *p;
-+
-+  switch (op)
-+  {
-+    case 'a':
-+      mutt_account_tourl (acct, &url);
-+      url_ciss_tostring (&url, fn, sizeof (fn), U_PATH);
-+      p = strchr (fn, '/');
-+      if (p)
-+	*p = '\0';
-+      snprintf (tmp, sizeof (tmp), "%%%ss", fmt);
-+      snprintf (dest, destlen, tmp, fn);
-+      break;
-+    case 'p':
-+      snprintf (tmp, sizeof (tmp), "%%%su", fmt);
-+      snprintf (dest, destlen, tmp, acct->port);
-+      break;
-+    case 'P':
-+      *dest = '\0';
-+      if (acct->flags & M_ACCT_PORT)
-+      {
-+	snprintf (tmp, sizeof (tmp), "%%%su", fmt);
-+	snprintf (dest, destlen, tmp, acct->port);
-+      }
-+      break;
-+    case 's':
-+      strncpy (fn, acct->host, sizeof (fn) - 1);
-+      mutt_strlower (fn);
-+      snprintf (tmp, sizeof (tmp), "%%%ss", fmt);
-+      snprintf (dest, destlen, tmp, fn);
-+      break;
-+    case 'S':
-+      mutt_account_tourl (acct, &url);
-+      url_ciss_tostring (&url, fn, sizeof (fn), U_PATH);
-+      p = strchr (fn, ':');
-+      if (p)
-+	*p = '\0';
-+      snprintf (tmp, sizeof (tmp), "%%%ss", fmt);
-+      snprintf (dest, destlen, tmp, fn);
-+      break;
-+    case 'u':
-+      snprintf (tmp, sizeof (tmp), "%%%ss", fmt);
-+      snprintf (dest, destlen, tmp, acct->user);
-+      break;
-+  }
-+  return (src);
-+}
-+
-+/* Automatically loads a newsrc into memory, if necessary.
-+ * Checks the size/mtime of a newsrc file, if it doesn't match, load
-+ * again.  Hmm, if a system has broken mtimes, this might mean the file
-+ * is reloaded every time, which we'd have to fix. */
-+NNTP_SERVER *nntp_select_server (char *server, int leave_lock)
-+{
-+  char file[_POSIX_PATH_MAX];
-+  char *p;
-+  int rc;
-+  struct stat sb;
-+  ACCOUNT acct;
-+  NNTP_SERVER *nserv;
-+  NNTP_DATA *nntp_data;
-+  CONNECTION *conn;
-+  ciss_url_t url;
-+
-+  if (!server || !*server)
-+  {
-+    mutt_error _("No news server defined!");
-+    mutt_sleep (2);
-+    return NULL;
-+  }
-+
-+  /* create account from news server url */
-+  acct.flags = 0;
-+  acct.port = NNTP_PORT;
-+  acct.type = M_ACCT_TYPE_NNTP;
-+  snprintf (file, sizeof (file), "%s%s",
-+	    strstr (server, "://") ? "" : "news://", server);
-+  if (url_parse_ciss (&url, file) < 0 ||
-+      (url.path && *url.path) ||
-+      !(url.scheme == U_NNTP || url.scheme == U_NNTPS) ||
-+      mutt_account_fromurl (&acct, &url) < 0)
-+  {
-+    mutt_error (_("%s is an invalid news server specification!"), server);
-+    mutt_sleep (2);
-+    return NULL;
-+  }
-+  if (url.scheme == U_NNTPS)
-+  {
-+    acct.flags |= M_ACCT_SSL;
-+    acct.port = NNTP_SSL_PORT;
-+  }
-+
-+  /* find connection by account */
-+  conn = mutt_conn_find (NULL, &acct);
-+  if (!conn)
-+    return NULL;
-+  if (!(conn->account.flags & M_ACCT_USER) && acct.flags & M_ACCT_USER)
-+  {
-+    conn->account.flags |= M_ACCT_USER;
-+    conn->account.user[0] = '\0';
-+  }
++    else
++#endif
+     mutt_expand_path (folder, sizeof (folder));
+ 
+     mutt_str_replace (&CurrentFolder, folder);
+@@ -1206,9 +865,16 @@ int main (int argc, char **argv)
+     if((Context = mx_open_mailbox (folder, ((flags & M_RO) || option (OPTREADONLY)) ? M_READONLY : 0, NULL))
+        || !explicit_folder)
+     {
++#ifdef USE_SIDEBAR
++      mutt_sb_set_open_buffy ();
++#endif
++      Labels = hash_create (131, 0);
++      mutt_scan_labels(Context);
+       mutt_index_menu ();
+       if (Context)
+ 	FREE (&Context);
++      if (Labels)
++        hash_destroy(&Labels, NULL);
+     }
+ #ifdef USE_IMAP
+     imap_logout_all ();
+diff --git a/mbox.c b/mbox.c
+index 95cba65..abdd0b4 100644
+--- a/mbox.c
++++ b/mbox.c
+@@ -29,6 +29,10 @@
+ #include "copy.h"
+ #include "mutt_curses.h"
+ 
++#ifdef USE_COMPRESSED
++#include "compress.h"
++#endif
 +
-+  /* news server already exists */
-+  nserv = conn->data;
-+  if (nserv)
-+  {
-+    if (nserv->status == NNTP_BYE)
-+      nserv->status = NNTP_NONE;
-+    if (nntp_open_connection (nserv) < 0)
-+      return NULL;
+ #include <sys/stat.h>
+ #include <dirent.h>
+ #include <string.h>
+@@ -100,6 +104,7 @@ int mmdf_parse_mailbox (CONTEXT *ctx)
+     mutt_perror (ctx->path);
+     return (-1);
+   }
++  ctx->atime = sb.st_atime;
+   ctx->mtime = sb.st_mtime;
+   ctx->size = sb.st_size;
+ 
+@@ -251,6 +256,7 @@ int mbox_parse_mailbox (CONTEXT *ctx)
+ 
+   ctx->size = sb.st_size;
+   ctx->mtime = sb.st_mtime;
++  ctx->atime = sb.st_atime;
+ 
+ #ifdef NFS_ATTRIBUTE_HACK
+   if (sb.st_mtime > sb.st_atime)
+@@ -1073,6 +1079,12 @@ bail:  /* Come here in case of disaster */
+ int mbox_close_mailbox (CONTEXT *ctx)
+ {
+   mx_unlock_file (ctx->path, fileno (ctx->fp), 1);
 +
-+    rc = nntp_newsrc_parse (nserv);
-+    if (rc < 0)
-+      return NULL;
++#ifdef USE_COMPRESSED
++  if (ctx->compress_info)
++    comp_slow_close (ctx);
++#endif
 +
-+    /* check for new newsgroups */
-+    if (!leave_lock && nntp_check_new_groups (nserv) < 0)
-+      rc = -1;
+   mutt_unblock_signals ();
+   mx_fastclose_mailbox (ctx);
+   return 0;
+diff --git a/mbyte.c b/mbyte.c
+index 470686c..fb5718f 100644
+--- a/mbyte.c
++++ b/mbyte.c
+@@ -107,7 +107,7 @@ static size_t wcrtomb_iconv (char *s, wchar_t wc, iconv_t cd)
+   char buf[MB_LEN_MAX+1];
+   ICONV_CONST char *ib;
+   char *ob;
+-  size_t ibl, obl, r;
++  size_t ibl, obl;
+ 
+   if (s)
+   {
+@@ -117,7 +117,7 @@ static size_t wcrtomb_iconv (char *s, wchar_t wc, iconv_t cd)
+     ib = buf;
+     ob = s;
+     obl = MB_LEN_MAX;
+-    r = iconv (cd, &ib, &ibl, &ob, &obl);
++    iconv (cd, &ib, &ibl, &ob, &obl);
+   }
+   else
+   {
+@@ -125,7 +125,7 @@ static size_t wcrtomb_iconv (char *s, wchar_t wc, iconv_t cd)
+     ibl = 1;
+     ob = buf;
+     obl = sizeof (buf);
+-    r = iconv (cd, &ib, &ibl, &ob, &obl);
++    iconv (cd, &ib, &ibl, &ob, &obl);
+   }
+   return ob - s;
+ }
+diff --git a/menu.c b/menu.c
+index 828df9c..567b962 100644
+--- a/menu.c
++++ b/menu.c
+@@ -24,10 +24,56 @@
+ #include "mutt_curses.h"
+ #include "mutt_menu.h"
+ #include "mbyte.h"
++#ifdef USE_SIDEBAR
++#include "sidebar.h"
++#endif
+ 
+ char* SearchBuffers[MENU_MAX];
+ 
+-static void print_enriched_string (int attr, unsigned char *s, int do_color)
++/**
++ * get_color - XXX
++ */
++static int
++get_color (int index, unsigned char *s)
++{
++	COLOR_LINE *color;
++	HEADER *hdr = Context->hdrs[Context->v2r[index]];
++	int type = *s;
 +
-+    /* .newsrc has been externally modified */
-+    if (rc > 0)
-+      nntp_clear_cache (nserv);
-+    if (rc < 0 || !leave_lock)
-+      nntp_newsrc_close (nserv);
-+    return rc < 0 ? NULL : nserv;
-+  }
++	switch (type) {
++		case MT_COLOR_INDEX_AUTHOR:
++			color = ColorIndexAuthorList;
++			break;
++		case MT_COLOR_INDEX_FLAGS:
++			color = ColorIndexFlagsList;
++			break;
++		case MT_COLOR_INDEX_SUBJECT:
++			color = ColorIndexSubjectList;
++			break;
++#ifdef USE_NOTMUCH
++                case MT_COLOR_INDEX_TAG:
++                        for (color = ColorIndexTagList; color; color = color->next)
++                        {
++				const char * transform = hash_find(TagTransforms, color->pattern);
++				if (transform && (strncmp((const char *)(s+1),
++				    transform, strlen(transform)) == 0))
++					return color->pair;
++                        }
++                        return 0;
++#endif
++		default:
++			return ColorDefs[type];
++	}
 +
-+  /* new news server */
-+  nserv = safe_calloc (1, sizeof (NNTP_SERVER));
-+  nserv->conn = conn;
-+  nserv->groups_hash = hash_create (1009, 0);
-+  nserv->groups_max = 16;
-+  nserv->groups_list = safe_malloc (nserv->groups_max * sizeof (nntp_data));
++	for (; color; color = color->next)
++		if (mutt_pattern_exec (color->color_pattern, M_MATCH_FULL_ADDRESS,
++		    Context, hdr))
++			return color->pair;
 +
-+  rc = nntp_open_connection (nserv);
++	return 0;
++}
 +
-+  /* try to create cache directory and enable caching */
-+  nserv->cacheable = 0;
-+  if (rc >= 0 && NewsCacheDir && *NewsCacheDir)
-+  {
-+    cache_expand (file, sizeof (file), &conn->account, NULL);
-+    p = *file == '/' ? file + 1 : file;
-+    while (1)
-+    {
-+      p = strchr (p, '/');
-+      if (p)
-+	*p = '\0';
-+      if ((stat (file, &sb) || (sb.st_mode & S_IFDIR) == 0) &&
-+	  mkdir (file, 0700))
-+      {
-+	mutt_error (_("Can't create %s: %s."), file, strerror (errno));
-+	mutt_sleep (2);
-+	break;
-+      }
-+      if (!p)
-+      {
-+	nserv->cacheable = 1;
-+	break;
++static void print_enriched_string (int index, int attr, unsigned char *s, int do_color)
+ {
+   wchar_t wc;
+   size_t k;
+@@ -159,6 +205,22 @@ static void print_enriched_string (int attr, unsigned char *s, int do_color)
+       }
+       if (do_color) ATTRSET(attr);
+     }
++    else if (*s == M_SPECIAL_INDEX) {
++      s++;
++      if (do_color) {
++        if (*s == MT_COLOR_INDEX) {
++          attrset (attr);
++	} else {
++          if (get_color (index, s) == 0) {
++            attron (attr);
++	  } else {
++            attron (get_color (index, s));
++	  }
++        }
 +      }
-+      *p++ = '/';
++      s++;
++      n -= 2;
 +    }
-+  }
-+
-+  /* load .newsrc */
-+  if (rc >= 0)
-+  {
-+    mutt_FormatString (file, sizeof (file), 0, NONULL (NewsRc),
-+		       nntp_format_str, (unsigned long)nserv, 0);
-+    mutt_expand_path (file, sizeof (file));
-+    nserv->newsrc_file = safe_strdup (file);
-+    rc = nntp_newsrc_parse (nserv);
-+  }
-+  if (rc >= 0)
-+  {
-+    /* try to load list of newsgroups from cache */
-+    if (nserv->cacheable && active_get_cache (nserv) == 0)
-+      rc = nntp_check_new_groups (nserv);
-+
-+    /* load list of newsgroups from server */
-+    else
-+      rc = nntp_active_fetch (nserv);
-+  }
+     else if ((k = mbrtowc (&wc, (char *)s, n, &mbstate)) > 0)
+     {
+       addnstr ((char *)s, k);
+@@ -184,7 +246,7 @@ static void menu_pad_string (char *s, size_t n)
+ {
+   char *scratch = safe_strdup (s);
+   int shift = option (OPTARROWCURSOR) ? 3 : 0;
+-  int cols = COLS - shift;
++  int cols = COLS - shift - SidebarWidth;
+ 
+   mutt_format_string (s, n, cols, cols, FMT_LEFT, ' ', scratch, mutt_strlen (scratch), 1);
+   s[n - 1] = 0;
+@@ -216,6 +278,9 @@ void menu_redraw_full (MUTTMENU *menu)
+   mutt_show_error ();
+ 
+   menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
++#ifdef USE_SIDEBAR
++  menu->redraw |= REDRAW_SIDEBAR;
++#endif
+ }
+ 
+ void menu_redraw_status (MUTTMENU *menu)
+@@ -230,6 +295,14 @@ void menu_redraw_status (MUTTMENU *menu)
+   menu->redraw &= ~REDRAW_STATUS;
+ }
+ 
++#ifdef USE_SIDEBAR
++void menu_redraw_sidebar (MUTTMENU *menu)
++{
++  SidebarNeedsRedraw = 0;
++  mutt_sb_draw ();
++}
++#endif
 +
-+  if (rc >= 0)
-+    nntp_clear_cache (nserv);
+ void menu_redraw_index (MUTTMENU *menu)
+ {
+   char buf[LONG_STRING];
+@@ -247,7 +320,7 @@ void menu_redraw_index (MUTTMENU *menu)
+       menu_pad_string (buf, sizeof (buf));
+ 
+       ATTRSET(attr);
+-      move(i - menu->top + menu->offset, 0);
++      move(i - menu->top + menu->offset, SidebarWidth);
+       do_color = 1;
+ 
+       if (i == menu->current)
+@@ -265,12 +338,16 @@ void menu_redraw_index (MUTTMENU *menu)
+       else if (option(OPTARROWCURSOR))
+ 	addstr("   ");
+ 
+-      print_enriched_string (attr, (unsigned char *) buf, do_color);
++      print_enriched_string (i, attr, (unsigned char *) buf, do_color);
+     }
+     else
+     {
+       NORMAL_COLOR;
++#ifdef USE_SIDEBAR
++      CLEARLINE_WIN(i - menu->top + menu->offset);
++#else
+       CLEARLINE(i - menu->top + menu->offset);
++#endif
+     }
+   }
+   NORMAL_COLOR;
+@@ -287,7 +364,7 @@ void menu_redraw_motion (MUTTMENU *menu)
+     return;
+   }
+   
+-  move (menu->oldcurrent + menu->offset - menu->top, 0);
++  move (menu->oldcurrent + menu->offset - menu->top, SidebarWidth);
+   ATTRSET(menu->color (menu->oldcurrent));
+ 
+   if (option (OPTARROWCURSOR))
+@@ -299,27 +376,27 @@ void menu_redraw_motion (MUTTMENU *menu)
+     {
+       menu_make_entry (buf, sizeof (buf), menu, menu->oldcurrent);
+       menu_pad_string (buf, sizeof (buf));
+-      move (menu->oldcurrent + menu->offset - menu->top, 3);
+-      print_enriched_string (menu->color(menu->oldcurrent), (unsigned char *) buf, 1);
++      move (menu->oldcurrent + menu->offset - menu->top, SidebarWidth + 3);
++      print_enriched_string (menu->oldcurrent, menu->color (menu->oldcurrent), (unsigned char *) buf, 1);
+     }
+ 
+     /* now draw it in the new location */
+     SETCOLOR(MT_COLOR_INDICATOR);
+-    mvaddstr(menu->current + menu->offset - menu->top, 0, "->");
++    mvaddstr(menu->current + menu->offset - menu->top, SidebarWidth, "->");
+   }
+   else
+   {
+     /* erase the current indicator */
+     menu_make_entry (buf, sizeof (buf), menu, menu->oldcurrent);
+     menu_pad_string (buf, sizeof (buf));
+-    print_enriched_string (menu->color(menu->oldcurrent), (unsigned char *) buf, 1);
++    print_enriched_string (menu->oldcurrent, menu->color (menu->oldcurrent), (unsigned char *) buf, 1);
+ 
+     /* now draw the new one to reflect the change */
+     menu_make_entry (buf, sizeof (buf), menu, menu->current);
+     menu_pad_string (buf, sizeof (buf));
+     SETCOLOR(MT_COLOR_INDICATOR);
+-    move(menu->current - menu->top + menu->offset, 0);
+-    print_enriched_string (menu->color(menu->current), (unsigned char *) buf, 0);
++    move (menu->current - menu->top + menu->offset, SidebarWidth);
++    print_enriched_string (menu->current, menu->color (menu->current), (unsigned char *) buf, 0);
+   }
+   menu->redraw &= REDRAW_STATUS;
+   NORMAL_COLOR;
+@@ -330,7 +407,7 @@ void menu_redraw_current (MUTTMENU *menu)
+   char buf[LONG_STRING];
+   int attr = menu->color (menu->current);
+   
+-  move (menu->current + menu->offset - menu->top, 0);
++  move (menu->current + menu->offset - menu->top, SidebarWidth);
+   menu_make_entry (buf, sizeof (buf), menu, menu->current);
+   menu_pad_string (buf, sizeof (buf));
+ 
+@@ -341,10 +418,10 @@ void menu_redraw_current (MUTTMENU *menu)
+     ATTRSET(attr);
+     addch (' ');
+     menu_pad_string (buf, sizeof (buf));
+-    print_enriched_string (attr, (unsigned char *) buf, 1);
++    print_enriched_string (menu->current, attr, (unsigned char *) buf, 1);
+   }
+   else
+-    print_enriched_string (attr, (unsigned char *) buf, 0);
++    print_enriched_string (menu->current, attr, (unsigned char *) buf, 0);
+   menu->redraw &= REDRAW_STATUS;
+   NORMAL_COLOR;
+ }
+@@ -835,6 +912,10 @@ int menu_redraw (MUTTMENU *menu)
+   
+   if (menu->redraw & REDRAW_STATUS)
+     menu_redraw_status (menu);
++#ifdef USE_SIDEBAR
++  if (menu->redraw & REDRAW_SIDEBAR || SidebarNeedsRedraw)
++    menu_redraw_sidebar (menu);
++#endif
+   if (menu->redraw & REDRAW_INDEX)
+     menu_redraw_index (menu);
+   else if (menu->redraw & (REDRAW_MOTION | REDRAW_MOTION_RESYNCH))
+@@ -873,7 +954,7 @@ int mutt_menuLoop (MUTTMENU *menu)
+     
+     
+     if (option (OPTARROWCURSOR))
+-      move (menu->current - menu->top + menu->offset, 2);
++      move (menu->current - menu->top + menu->offset, SidebarWidth + 2);
+     else if (option (OPTBRAILLEFRIENDLY))
+       move (menu->current - menu->top + menu->offset, 0);
+     else
+diff --git a/mh.c b/mh.c
+index bc87660..c36b413 100644
+--- a/mh.c
++++ b/mh.c
+@@ -56,6 +56,10 @@
+ #include <sys/time.h>
+ #endif
+ 
++#ifdef USE_NOTMUCH
++#include "mutt_notmuch.h"
++#endif
 +
-+#ifdef USE_HCACHE
-+  /* check cache files */
-+  if (rc >= 0 && nserv->cacheable)
+ #define		INS_SORT_THRESHOLD		6
+ 
+ struct maildir
+@@ -261,38 +265,86 @@ static int mh_already_notified(BUFFY *b, int msgno)
+   return -1;
+ }
+ 
+-void mh_buffy(BUFFY *b)
++/* Checks new mail for a mh mailbox.
++ * check_stats: if true, also count total, new, and flagged mesages.
++ * Returns 1 if the mailbox has new mail.
++ */
++int mh_buffy (BUFFY *mailbox, int check_stats)
+ {
+   int i;
+   struct mh_sequences mhs;
+-
+-  b->new = 0;
++  int check_new = 1;
++  int rc = 0;
++  DIR *dirp;
++  struct dirent *de;
+ 
+   /* when $mail_check_recent is set and the .mh_sequences file hasn't changed
+-   * since the last mailbox visit, there is nothing to do */
+-  if (option(OPTMAILCHECKRECENT) && mh_sequences_changed(b) <= 0)
+-      return;
++   * since the last mailbox visit, there is no "new mail" */
++  if (option(OPTMAILCHECKRECENT) && mh_sequences_changed(mailbox) <= 0)
 +  {
-+    struct dirent *entry;
-+    DIR *dp = opendir (file);
-+
-+    if (dp)
-+    {
-+      while ((entry = readdir (dp)))
-+      {
-+	header_cache_t *hc;
-+	void *hdata;
-+	char *group = entry->d_name;
-+
-+	p = group + strlen (group) - 7;
-+	if (strlen (group) < 8 || strcmp (p, ".hcache"))
-+	  continue;
-+	*p = '\0';
-+	nntp_data = hash_find (nserv->groups_hash, group);
-+	if (!nntp_data)
-+	  continue;
-+
-+	hc = nntp_hcache_open (nntp_data);
-+	if (!hc)
-+	  continue;
-+
-+	/* fetch previous values of first and last */
-+	hdata = mutt_hcache_fetch_raw (hc, "index", strlen);
-+	if (hdata)
-+	{
-+	  anum_t first, last;
-+
-+	  if (sscanf (hdata, ANUM " " ANUM, &first, &last) == 2)
-+	  {
-+	    if (nntp_data->deleted)
-+	    {
-+	      nntp_data->firstMessage = first;
-+	      nntp_data->lastMessage = last;
-+	    }
-+	    if (last >= nntp_data->firstMessage &&
-+		last <= nntp_data->lastMessage)
-+	    {
-+	      nntp_data->lastCached = last;
-+	      dprint (2, (debugfile, "nntp_select_server: %s lastCached=%u\n",
-+			  nntp_data->group, last));
-+	    }
-+	  }
-+	  FREE (&hdata);
-+	}
-+	mutt_hcache_close (hc);
-+      }
-+      closedir (dp);
-+    }
++    rc = 0;
++    check_new = 0;
 +  }
-+#endif
-+
-+  if (rc < 0 || !leave_lock)
-+    nntp_newsrc_close (nserv);
 +
-+  if (rc < 0)
++  if (! (check_new || check_stats))
++    return rc;
+ 
+   memset (&mhs, 0, sizeof (mhs));
++  if (mh_read_sequences (&mhs, mailbox->path) < 0)
++    return 0;
+ 
+-  if (mh_read_sequences (&mhs, b->path) < 0)
+-    return;
++  if (check_stats)
 +  {
-+    hash_destroy (&nserv->groups_hash, nntp_data_free);
-+    FREE (&nserv->groups_list);
-+    FREE (&nserv->newsrc_file);
-+    FREE (&nserv->authenticators);
-+    FREE (&nserv);
-+    mutt_socket_close (conn);
-+    mutt_socket_free (conn);
-+    return NULL;
++    mailbox->msg_count   = 0;
++    mailbox->msg_unread  = 0;
++    mailbox->msg_flagged = 0;
 +  }
+ 
+-  /* Traverse the sequence from high to low in order to support
+-   * $mail_check_recent.  Given that new messages are appended, this should
+-   * also be faster when it is unset as well.
+-   */
+   for (i = mhs.max; i > 0; i--)
+   {
++    if (check_stats &&
++        (mhs_check (&mhs, i) & MH_SEQ_FLAGGED))
++      mailbox->msg_flagged++;
+     if (mhs_check (&mhs, i) & MH_SEQ_UNSEEN)
+     {
+-      /* if the first unseen message we encounter was in the mailbox during the last visit, don't notify about it */
+-      if (!option(OPTMAILCHECKRECENT) || mh_already_notified(b, i) == 0)
+-	b->new = 1;
+-      break;
++      if (check_stats)
++        mailbox->msg_unread++;
++      if (check_new)
++      {
++        /* if the first unseen message we encounter was in the mailbox during the
++           last visit, don't notify about it */
++        if (!option(OPTMAILCHECKRECENT) || mh_already_notified(mailbox, i) == 0)
++        {
++          mailbox->new = 1;
++          rc = 1;
++        }
++        /* Because we are traversing from high to low, we can stop
++         * checking for new mail after the first unseen message.
++         * Whether it resulted in "new mail" or not. */
++        check_new = 0;
++        if (!check_stats)
++          break;
++      }
+     }
+   }
+   mhs_free_sequences (&mhs);
 +
-+  conn->data = nserv;
-+  return nserv;
-+}
-+
-+/* Full status flags are not supported by nntp, but we can fake some of them:
-+ * Read = a read message number is in the .newsrc
-+ * New = not read and not cached
-+ * Old = not read but cached */
-+void nntp_article_status (CONTEXT *ctx, HEADER *hdr, char *group, anum_t anum)
-+{
-+  NNTP_DATA *nntp_data = ctx->data;
-+  unsigned int i;
-+
-+  if (group)
-+    nntp_data = hash_find (nntp_data->nserv->groups_hash, group);
-+
-+  if (!nntp_data)
-+    return;
-+
-+  for (i = 0; i < nntp_data->newsrc_len; i++)
++  if (check_stats)
 +  {
-+    if ((anum >= nntp_data->newsrc_ent[i].first) &&
-+	(anum <= nntp_data->newsrc_ent[i].last))
++    if ((dirp = opendir (mailbox->path)) != NULL)
 +    {
-+      /* can't use mutt_set_flag() because mx_update_context()
-+	 didn't called yet */
-+      hdr->read = 1;
-+      return;
++      while ((de = readdir (dirp)) != NULL)
++      {
++        if (*de->d_name == '.')
++          continue;
++        if (mh_valid_message (de->d_name))
++          mailbox->msg_count++;
++      }
++      closedir (dirp);
 +    }
 +  }
 +
-+  /* article was not cached yet, it's new */
-+  if (anum > nntp_data->lastCached)
-+    return;
-+
-+  /* article isn't read but cached, it's old */
-+  if (option (OPTMARKOLD))
-+    hdr->old = 1;
-+}
-+
-+/* calculate number of unread articles using .newsrc data */
-+void nntp_group_unread_stat (NNTP_DATA *nntp_data)
-+{
-+  unsigned int i;
-+  anum_t first, last;
-+
-+  nntp_data->unread = 0;
-+  if (nntp_data->lastMessage == 0 ||
-+      nntp_data->firstMessage > nntp_data->lastMessage)
-+    return;
-+
-+  nntp_data->unread = nntp_data->lastMessage - nntp_data->firstMessage + 1;
-+  for (i = 0; i < nntp_data->newsrc_len; i++)
-+  {
-+    first = nntp_data->newsrc_ent[i].first;
-+    if (first < nntp_data->firstMessage)
-+      first = nntp_data->firstMessage;
-+    last = nntp_data->newsrc_ent[i].last;
-+    if (last > nntp_data->lastMessage)
-+      last = nntp_data->lastMessage;
-+    if (first <= last)
-+      nntp_data->unread -= last - first + 1;
-+  }
-+}
-+
-+/* Subscribe newsgroup */
-+NNTP_DATA *mutt_newsgroup_subscribe (NNTP_SERVER *nserv, char *group)
-+{
-+  NNTP_DATA *nntp_data;
-+
-+  if (!nserv || !nserv->groups_hash || !group || !*group)
-+    return NULL;
-+
-+  nntp_data = nntp_data_find (nserv, group);
-+  nntp_data->subscribed = 1;
-+  if (!nntp_data->newsrc_ent)
++  return rc;
+ }
+ 
+ static int mh_mkstemp (CONTEXT * dest, FILE ** fp, char **tgt)
+@@ -304,8 +356,8 @@ static int mh_mkstemp (CONTEXT * dest, FILE ** fp, char **tgt)
+   omask = umask (mh_umask (dest));
+   FOREVER
+   {
+-    snprintf (path, _POSIX_PATH_MAX, "%s/.mutt-%s-%d-%d",
+-	      dest->path, NONULL (Hostname), (int) getpid (), Counter++);
++    snprintf (path, _POSIX_PATH_MAX, "%s/.mutt-%s-%d-%" PRIu64,
++	      dest->path, NONULL (Hostname), (int) getpid (), mutt_rand64());
+     if ((fd = open (path, O_WRONLY | O_EXCL | O_CREAT, 0666)) == -1)
+     {
+       if (errno != EEXIST)
+@@ -610,7 +662,7 @@ static void maildir_free_maildir (struct maildir **md)
+   }
+ }
+ 
+-static void maildir_parse_flags (HEADER * h, const char *path)
++void maildir_parse_flags (HEADER * h, const char *path)
+ {
+   char *p, *q = NULL;
+ 
+@@ -693,40 +745,51 @@ static void maildir_update_mtime (CONTEXT * ctx)
+  * Actually parse a maildir message.  This may also be used to fill
+  * out a fake header structure generated by lazy maildir parsing.
+  */
+-static HEADER *maildir_parse_message (int magic, const char *fname,
++HEADER *maildir_parse_stream (int magic, FILE *f, const char *fname,
+ 				      int is_old, HEADER * _h)
+ {
+-  FILE *f;
+   HEADER *h = _h;
+   struct stat st;
+ 
+-  if ((f = fopen (fname, "r")) != NULL)
+-  {
+-    if (!h)
+-      h = mutt_new_header ();
+-    h->env = mutt_read_rfc822_header (f, h, 0, 0);
++  if (!h)
++    h = mutt_new_header ();
++  h->env = mutt_read_rfc822_header (f, h, 0, 0);
+ 
+-    fstat (fileno (f), &st);
+-    safe_fclose (&f);
++  fstat (fileno (f), &st);
+ 
+-    if (!h->received)
+-      h->received = h->date_sent;
++  if (!h->received)
++    h->received = h->date_sent;
+ 
+-    /* always update the length since we have fresh information available. */
+-    h->content->length = st.st_size - h->content->offset;
++  /* always update the length since we have fresh information available. */
++  h->content->length = st.st_size - h->content->offset;
+ 
+-    h->index = -1;
++  h->index = -1;
+ 
+-    if (magic == M_MAILDIR)
+-    {
+-      /* 
+-       * maildir stores its flags in the filename, so ignore the
+-       * flags in the header of the message 
+-       */
++  if (magic == M_MAILDIR)
 +  {
-+    nntp_data->newsrc_ent = safe_calloc (1, sizeof (NEWSRC_ENTRY));
-+    nntp_data->newsrc_len = 1;
-+    nntp_data->newsrc_ent[0].first = 1;
-+    nntp_data->newsrc_ent[0].last = 0;
++    /*
++     * maildir stores its flags in the filename, so ignore the
++     * flags in the header of the message
++     */
+ 
+-      h->old = is_old;
+-      maildir_parse_flags (h, fname);
+-    }
++    h->old = is_old;
++    maildir_parse_flags (h, fname);
 +  }
-+  return nntp_data;
++  return h;
 +}
 +
-+/* Unsubscribe newsgroup */
-+NNTP_DATA *mutt_newsgroup_unsubscribe (NNTP_SERVER *nserv, char *group)
++/*
++ * Actually parse a maildir message.  This may also be used to fill
++ * out a fake header structure generated by lazy maildir parsing.
++ */
++HEADER *maildir_parse_message (int magic, const char *fname,
++				      int is_old, HEADER * h)
 +{
-+  NNTP_DATA *nntp_data;
++  FILE *f;
 +
-+  if (!nserv || !nserv->groups_hash || !group || !*group)
-+    return NULL;
++  if ((f = fopen (fname, "r")) != NULL) {
++    h = maildir_parse_stream (magic, f, fname, is_old, h);
++    safe_fclose (&f);
+     return h;
+   }
+   return NULL;
+@@ -1249,7 +1312,7 @@ static int ch_compar (const void *a, const void *b)
+   return (int)( *((const char *) a) - *((const char *) b));
+ }
+ 
+-static void maildir_flags (char *dest, size_t destlen, HEADER * hdr)
++void maildir_flags (char *dest, size_t destlen, HEADER * hdr)
+ {
+   *dest = '\0';
+ 
+@@ -1313,9 +1376,9 @@ int maildir_open_new_message (MESSAGE * msg, CONTEXT * dest, HEADER * hdr)
+   omask = umask (mh_umask (dest));
+   FOREVER
+   {
+-    snprintf (path, _POSIX_PATH_MAX, "%s/tmp/%s.%lld.%u_%d.%s%s",
+-	      dest->path, subdir, (long long)time (NULL), (unsigned int)getpid (),
+-	      Counter++, NONULL (Hostname), suffix);
++    snprintf (path, _POSIX_PATH_MAX, "%s/tmp/%s.%lld.R%" PRIu64 ".%s%s",
++	      dest->path, subdir, (long long)time (NULL), mutt_rand64(),
++              NONULL (Hostname), suffix);
+ 
+     dprint (2, (debugfile, "maildir_open_new_message (): Trying %s.\n",
+ 		path));
+@@ -1399,8 +1462,8 @@ int maildir_commit_message (CONTEXT * ctx, MESSAGE * msg, HEADER * hdr)
+   /* construct a new file name. */
+   FOREVER
+   {
+-    snprintf (path, _POSIX_PATH_MAX, "%s/%lld.%u_%d.%s%s", subdir,
+-	      (long long)time (NULL), (unsigned int)getpid (), Counter++,
++    snprintf (path, _POSIX_PATH_MAX, "%s/%lld.R%" PRIu64 ".%s%s", subdir,
++	      (long long)time (NULL), mutt_rand64(),
+ 	      NONULL (Hostname), suffix);
+     snprintf (full, _POSIX_PATH_MAX, "%s/%s", ctx->path, path);
+ 
+@@ -1409,10 +1472,6 @@ int maildir_commit_message (CONTEXT * ctx, MESSAGE * msg, HEADER * hdr)
+ 
+     if (safe_rename (msg->path, full) == 0)
+     {
+-      if (hdr)
+-	mutt_str_replace (&hdr->path, path);
+-      FREE (&msg->path);
+-
+       /*
+        * Adjust the mtime on the file to match the time at which this
+        * message was received.  Currently this is only set when copying
+@@ -1428,11 +1487,23 @@ int maildir_commit_message (CONTEXT * ctx, MESSAGE * msg, HEADER * hdr)
+ 	if (utime (full, &ut))
+ 	{
+ 	  mutt_perror (_("maildir_commit_message(): unable to set time on file"));
+-	  return -1;
++	  goto post_rename_err;
+ 	}
+       }
+ 
++#ifdef USE_NOTMUCH
++      if (ctx->magic == M_NOTMUCH)
++	nm_update_filename(ctx, hdr->path, full, hdr);
++#endif
++      if (hdr)
++	mutt_str_replace (&hdr->path, path);
++      mutt_str_replace (&msg->commited_path, full);
++      FREE (&msg->path);
 +
-+  nntp_data = hash_find (nserv->groups_hash, group);
-+  if (!nntp_data)
-+    return NULL;
+       return 0;
 +
-+  nntp_data->subscribed = 0;
-+  if (!option (OPTSAVEUNSUB))
-+  {
-+    nntp_data->newsrc_len = 0;
-+    FREE (&nntp_data->newsrc_ent);
-+  }
-+  return nntp_data;
++post_rename_err:
++      return -1;
+     }
+     else if (errno != EEXIST)
+     {
+@@ -1508,6 +1579,7 @@ static int _mh_commit_message (CONTEXT * ctx, MESSAGE * msg, HEADER * hdr,
+     {
+       if (hdr)
+ 	mutt_str_replace (&hdr->path, tmp);
++      mutt_str_replace (&msg->commited_path, path);
+       FREE (&msg->path);
+       break;
+     }
+@@ -1612,7 +1684,7 @@ static int mh_sync_message (CONTEXT * ctx, int msgno)
+ {
+   HEADER *h = ctx->hdrs[msgno];
+ 
+-  if (h->attach_del || 
++  if (h->attach_del || h->label_changed ||
+       (h->env && (h->env->refs_changed || h->env->irt_changed)))
+     if (mh_rewrite_message (ctx, msgno) != 0)
+       return -1;
+@@ -1624,7 +1696,7 @@ static int maildir_sync_message (CONTEXT * ctx, int msgno)
+ {
+   HEADER *h = ctx->hdrs[msgno];
+ 
+-  if (h->attach_del || 
++  if (h->attach_del || h->label_changed ||
+       (h->env && (h->env->refs_changed || h->env->irt_changed)))
+   {
+     /* when doing attachment deletion/rethreading, fall back to the MH case. */
+@@ -1683,96 +1755,114 @@ static int maildir_sync_message (CONTEXT * ctx, int msgno)
+   return (0);
+ }
+ 
+-int mh_sync_mailbox (CONTEXT * ctx, int *index_hint)
+-{
+-  char path[_POSIX_PATH_MAX], tmp[_POSIX_PATH_MAX];
+-  int i, j;
+-#if USE_HCACHE
+-  header_cache_t *hc = NULL;
+-#endif /* USE_HCACHE */
+-  char msgbuf[STRING];
+-  progress_t progress;
+-
+-  if (ctx->magic == M_MH)
+-    i = mh_check_mailbox (ctx, index_hint);
+-  else 
+-    i = maildir_check_mailbox (ctx, index_hint);
+-      
+-  if (i != 0)
+-    return i;
+-
+ #if USE_HCACHE
+-  if (ctx->magic == M_MAILDIR || ctx->magic == M_MH)
+-    hc = mutt_hcache_open(HeaderCache, ctx->path, NULL);
+-#endif /* USE_HCACHE */
+-
+-  if (!ctx->quiet)
+-  {
+-    snprintf (msgbuf, sizeof (msgbuf), _("Writing %s..."), ctx->path);
+-    mutt_progress_init (&progress, msgbuf, M_PROGRESS_MSG, WriteInc, ctx->msgcount);
+-  }
+-
+-  for (i = 0; i < ctx->msgcount; i++)
+-  {
+-    if (!ctx->quiet)
+-      mutt_progress_update (&progress, i, -1);
++int mh_sync_mailbox_message (CONTEXT * ctx, int msgno, header_cache_t *hc)
++#else
++int mh_sync_mailbox_message (CONTEXT * ctx, int msgno)
++#endif
++{
++    char path[_POSIX_PATH_MAX], tmp[_POSIX_PATH_MAX];
++    HEADER *h = ctx->hdrs[msgno];
+ 
+-    if (ctx->hdrs[i]->deleted
+-	&& (ctx->magic != M_MAILDIR || !option (OPTMAILDIRTRASH)))
++    if (h->deleted && (ctx->magic != M_MAILDIR || !option (OPTMAILDIRTRASH)))
+     {
+-      snprintf (path, sizeof (path), "%s/%s", ctx->path, ctx->hdrs[i]->path);
++      snprintf (path, sizeof (path), "%s/%s", ctx->path, h->path);
+       if (ctx->magic == M_MAILDIR
+ 	  || (option (OPTMHPURGE) && ctx->magic == M_MH))
+       {
+ #if USE_HCACHE
+-        if (ctx->magic == M_MAILDIR)
+-          mutt_hcache_delete (hc, ctx->hdrs[i]->path + 3, &maildir_hcache_keylen);
+-	else if (ctx->magic == M_MH)
+-	  mutt_hcache_delete (hc, ctx->hdrs[i]->path, strlen);
++	if (hc) {
++           if (ctx->magic == M_MAILDIR)
++              mutt_hcache_delete (hc, h->path + 3, &maildir_hcache_keylen);
++	   else if (ctx->magic == M_MH)
++	      mutt_hcache_delete (hc, h->path, strlen);
++	}
+ #endif /* USE_HCACHE */
+ 	unlink (path);
+       }
+       else if (ctx->magic == M_MH)
+       {
+ 	/* MH just moves files out of the way when you delete them */
+-	if (*ctx->hdrs[i]->path != ',')
++	if (*h->path != ',')
+ 	{
+-	  snprintf (tmp, sizeof (tmp), "%s/,%s", ctx->path,
+-		    ctx->hdrs[i]->path);
++	  snprintf (tmp, sizeof (tmp), "%s/,%s", ctx->path, h->path);
+ 	  unlink (tmp);
+ 	  rename (path, tmp);
+ 	}
+ 
+       }
+     }
+-    else if (ctx->hdrs[i]->changed || ctx->hdrs[i]->attach_del ||
++    else if (h->changed || h->attach_del ||
++	     h->label_changed ||
+ 	     (ctx->magic == M_MAILDIR
+-	      && (option (OPTMAILDIRTRASH) || ctx->hdrs[i]->trash)
+-	      && (ctx->hdrs[i]->deleted != ctx->hdrs[i]->trash)))
++	      && (option (OPTMAILDIRTRASH) || h->trash)
++	      && (h->deleted != h->trash)))
+     {
+       if (ctx->magic == M_MAILDIR)
+       {
+-	if (maildir_sync_message (ctx, i) == -1)
+-	  goto err;
++	if (maildir_sync_message (ctx, msgno) == -1)
++	  return -1;
+       }
+       else
+       {
+-	if (mh_sync_message (ctx, i) == -1)
+-	  goto err;
++	if (mh_sync_message (ctx, msgno) == -1)
++	  return -1;
+       }
+     }
+ 
+ #if USE_HCACHE
+-    if (ctx->hdrs[i]->changed)
++    if (hc && h->changed)
+     {
+       if (ctx->magic == M_MAILDIR)
+-	mutt_hcache_store (hc, ctx->hdrs[i]->path + 3, ctx->hdrs[i],
+-			   0, &maildir_hcache_keylen, M_GENERATE_UIDVALIDITY);
++	mutt_hcache_store (hc, h->path + 3, h, 0, &maildir_hcache_keylen, M_GENERATE_UIDVALIDITY);
+       else if (ctx->magic == M_MH)
+-	mutt_hcache_store (hc, ctx->hdrs[i]->path, ctx->hdrs[i], 0, strlen, M_GENERATE_UIDVALIDITY);
++	mutt_hcache_store (hc, h->path, h, 0, strlen, M_GENERATE_UIDVALIDITY);
+     }
+ #endif
+ 
++    return 0;
 +}
 +
-+/* Catchup newsgroup */
-+NNTP_DATA *mutt_newsgroup_catchup (NNTP_SERVER *nserv, char *group)
++int mh_sync_mailbox (CONTEXT * ctx, int *index_hint)
 +{
-+  NNTP_DATA *nntp_data;
++  int i, j;
++#if USE_HCACHE
++  header_cache_t *hc = NULL;
++#endif /* USE_HCACHE */
++  char msgbuf[STRING];
++  progress_t progress;
 +
-+  if (!nserv || !nserv->groups_hash || !group || !*group)
-+    return NULL;
++  if (ctx->magic == M_MH)
++    i = mh_check_mailbox (ctx, index_hint);
++  else
++    i = maildir_check_mailbox (ctx, index_hint);
 +
-+  nntp_data = hash_find (nserv->groups_hash, group);
-+  if (!nntp_data)
-+    return NULL;
++  if (i != 0)
++    return i;
 +
-+  if (nntp_data->newsrc_ent)
++#if USE_HCACHE
++  if (ctx->magic == M_MAILDIR || ctx->magic == M_MH)
++    hc = mutt_hcache_open(HeaderCache, ctx->path, NULL);
++#endif /* USE_HCACHE */
++
++  if (!ctx->quiet)
 +  {
-+    safe_realloc (&nntp_data->newsrc_ent, sizeof (NEWSRC_ENTRY));
-+    nntp_data->newsrc_len = 1;
-+    nntp_data->newsrc_ent[0].first = 1;
-+    nntp_data->newsrc_ent[0].last = nntp_data->lastMessage;
++    snprintf (msgbuf, sizeof (msgbuf), _("Writing %s..."), ctx->path);
++    mutt_progress_init (&progress, msgbuf, M_PROGRESS_MSG, WriteInc, ctx->msgcount);
 +  }
-+  nntp_data->unread = 0;
-+  if (Context && Context->data == nntp_data)
++
++  for (i = 0; i < ctx->msgcount; i++)
 +  {
-+    unsigned int i;
++    if (!ctx->quiet)
++      mutt_progress_update (&progress, i, -1);
 +
-+    for (i = 0; i < Context->msgcount; i++)
-+      mutt_set_flag (Context, Context->hdrs[i], M_READ, 1);
-+  }
-+  return nntp_data;
-+}
++#if USE_HCACHE
++    if (mh_sync_mailbox_message (ctx, i, hc) == -1)
++      goto err;
++#else
++    if (mh_sync_mailbox_message (ctx, i) == -1)
++      goto err;
++#endif
+   }
+ 
+ #if USE_HCACHE
+@@ -1851,7 +1941,7 @@ static void maildir_update_tables (CONTEXT *ctx, int *index_hint)
+   mutt_clear_threads (ctx);
+ }
+ 
+-static void maildir_update_flags (CONTEXT *ctx, HEADER *o, HEADER *n)
++void maildir_update_flags (CONTEXT *ctx, HEADER *o, HEADER *n)
+ {
+   /* save the global state here so we can reset it at the
+    * end of list block if required.
+@@ -2154,7 +2244,7 @@ int mh_check_mailbox (CONTEXT * ctx, int *index_hint)
+  */
+ 
+ static FILE *_maildir_open_find_message (const char *folder, const char *unique,
+-				  const char *subfolder)
++				  const char *subfolder, char **newname)
+ {
+   char dir[_POSIX_PATH_MAX];
+   char tunique[_POSIX_PATH_MAX];
+@@ -2190,11 +2280,15 @@ static FILE *_maildir_open_find_message (const char *folder, const char *unique,
+ 
+   closedir (dp);
+ 
++  if (newname && fp)
++    *newname = safe_strdup(fname);
 +
-+/* Uncatchup newsgroup */
-+NNTP_DATA *mutt_newsgroup_uncatchup (NNTP_SERVER *nserv, char *group)
-+{
-+  NNTP_DATA *nntp_data;
+   errno = oe;
+   return fp;
+ }
+ 
+-FILE *maildir_open_find_message (const char *folder, const char *msg)
++FILE *maildir_open_find_message (const char *folder, const char *msg,
++                                  char **newname)
+ {
+   char unique[_POSIX_PATH_MAX];
+   FILE *fp;
+@@ -2206,7 +2300,8 @@ FILE *maildir_open_find_message (const char *folder, const char *msg)
+   if (
+       (fp =
+        _maildir_open_find_message (folder, unique,
+-				   new_hits > cur_hits ? "new" : "cur"))
++				   new_hits > cur_hits ? "new" : "cur",
++				   newname))
+       || errno != ENOENT)
+   {
+     if (new_hits < UINT_MAX && cur_hits < UINT_MAX)
+@@ -2220,7 +2315,8 @@ FILE *maildir_open_find_message (const char *folder, const char *msg)
+   if (
+       (fp =
+        _maildir_open_find_message (folder, unique,
+-				   new_hits > cur_hits ? "cur" : "new"))
++				   new_hits > cur_hits ? "cur" : "new",
++				   newname))
+       || errno != ENOENT)
+   {
+     if (new_hits < UINT_MAX && cur_hits < UINT_MAX)
+diff --git a/mutt.h b/mutt.h
+index de26fd8..5991e46 100644
+--- a/mutt.h
++++ b/mutt.h
+@@ -52,6 +52,11 @@
+ #include <limits.h>
+ #endif
+ 
++/* PATH_MAX is undefined on the hurd */
++#ifndef PATH_MAX
++#define PATH_MAX _POSIX_PATH_MAX
++#endif
 +
-+  if (!nserv || !nserv->groups_hash || !group || !*group)
-+    return NULL;
+ #include <pwd.h>
+ #include <grp.h>
+ 
+@@ -66,6 +71,14 @@
+ # define MB_LEN_MAX 16
+ #endif
+ 
++#ifdef HAVE_FGETS_UNLOCKED
++# define fgets fgets_unlocked
++#endif
 +
-+  nntp_data = hash_find (nserv->groups_hash, group);
-+  if (!nntp_data)
-+    return NULL;
++#ifdef HAVE_FGETC_UNLOCKED
++# define fgetc fgetc_unlocked
++#endif
 +
-+  if (nntp_data->newsrc_ent)
-+  {
-+    safe_realloc (&nntp_data->newsrc_ent, sizeof (NEWSRC_ENTRY));
-+    nntp_data->newsrc_len = 1;
-+    nntp_data->newsrc_ent[0].first = 1;
-+    nntp_data->newsrc_ent[0].last = nntp_data->firstMessage - 1;
-+  }
-+  if (Context && Context->data == nntp_data)
-+  {
-+    unsigned int i;
+ /* nifty trick I stole from ELM 2.5alpha. */
+ #ifdef MAIN_C
+ #define WHERE 
+@@ -88,6 +101,11 @@
+ #define  M_CLEAR   (1<<5) /* clear input if printable character is pressed */
+ #define  M_COMMAND (1<<6) /* do command completion */
+ #define  M_PATTERN (1<<7) /* pattern mode - only used for history classes */
++#define  M_LABEL   (1<<8) /* do label completion */
++#if USE_NOTMUCH
++#define  M_NM_QUERY (1<<9) /* Notmuch query mode. */
++#define  M_NM_TAG   (1<<10) /* Notmuch tag +/- mode. */
++#endif
+ 
+ /* flags for mutt_get_token() */
+ #define M_TOKEN_EQUAL		1	/* treat '=' as a special */
+@@ -141,6 +159,11 @@ typedef enum
+ #define M_ACCOUNTHOOK	(1<<9)
+ #define M_REPLYHOOK	(1<<10)
+ #define M_SEND2HOOK     (1<<11)
++#ifdef USE_COMPRESSED
++#define M_OPENHOOK	(1<<12)
++#define M_APPENDHOOK	(1<<13)
++#define M_CLOSEHOOK	(1<<14)
++#endif
+ 
+ /* tree characters for linearize_tree and print_enriched_string */
+ #define M_TREE_LLCORNER		1
+@@ -158,6 +181,8 @@ typedef enum
+ #define M_TREE_MISSING		13
+ #define M_TREE_MAX		14
+ 
++#define M_SPECIAL_INDEX		M_TREE_MAX
 +
-+    nntp_data->unread = Context->msgcount;
-+    for (i = 0; i < Context->msgcount; i++)
-+      mutt_set_flag (Context, Context->hdrs[i], M_READ, 0);
-+  }
-+  else
-+    nntp_data->unread = nntp_data->lastMessage - nntp_data->newsrc_ent[0].last;
-+  return nntp_data;
-+}
+ #define M_THREAD_COLLAPSE	(1<<0)
+ #define M_THREAD_UNCOLLAPSE	(1<<1)
+ #define M_THREAD_GET_HIDDEN	(1<<2)
+@@ -182,6 +207,8 @@ enum
+   M_DELETE,
+   M_UNDELETE,
+   M_DELETED,
++  M_APPENDED,
++  M_PURGED,
+   M_FLAG,
+   M_TAG,
+   M_UNTAG,
+@@ -223,7 +250,13 @@ enum
+   M_CRYPT_ENCRYPT,
+   M_PGP_KEY,
+   M_XLABEL,
++#ifdef USE_NOTMUCH
++  M_NOTMUCH_LABEL,
++#endif
+   M_MIMEATTACH,
++#ifdef USE_NNTP
++  M_NEWSGROUPS,
++#endif
+   
+   /* Options for Mailcap lookup */
+   M_EDIT,
+@@ -266,6 +299,7 @@ enum
+   OPT_MIMEFWDREST,
+   OPT_MOVE,
+   OPT_PGPMIMEAUTO,     /* ask to revert to PGP/MIME when inline fails */
++  OPT_SMIMEENCRYPTSELF,
+ #ifdef USE_POP
+   OPT_POPDELETE,
+   OPT_POPRECONNECT,
+@@ -280,6 +314,11 @@ enum
+ #endif
+   OPT_SUBJECT,
+   OPT_VERIFYSIG,      /* verify PGP signatures */
++#ifdef USE_NNTP
++  OPT_TOMODERATED,
++  OPT_CATCHUP,
++  OPT_FOLLOWUPTOPOSTER,
++#endif
+     
+   /* THIS MUST BE THE LAST VALUE. */
+   OPT_MAX
+@@ -298,6 +337,7 @@ enum
+ #define SENDPOSTPONEDFCC	(1<<9) /* used by mutt_get_postponed() to signal that the x-mutt-fcc header field was present */
+ #define SENDNOFREEHEADER	(1<<10)   /* Used by the -E flag */
+ #define SENDDRAFTFILE		(1<<11)   /* Used by the -H flag */
++#define SENDNEWS	(1<<12)
+ 
+ /* flags for mutt_compose_menu() */
+ #define M_COMPOSE_NOFREEHEADER (1<<0)
+@@ -306,11 +346,18 @@ enum
+ #define M_SEL_BUFFY	(1<<0)
+ #define M_SEL_MULTI	(1<<1)
+ #define M_SEL_FOLDER	(1<<2)
++#define M_SEL_VFOLDER	(1<<3)
+ 
+ /* flags for parse_spam_list */
+ #define M_SPAM          1
+ #define M_NOSPAM        2
+ 
++/* flags for keywords headers */
++#define M_X_LABEL         (1<<0)  /* introduced to mutt in 2000 */
++#define M_X_KEYWORDS      (1<<1)  /* used in c-client, dovecot */
++#define M_X_MOZILLA_KEYS  (1<<2)  /* tbird */
++#define M_KEYWORDS        (1<<3)  /* rfc2822 */
++
+ /* boolean vars */
+ enum
+ {
+@@ -320,6 +367,8 @@ enum
+   OPTASCIICHARS,
+   OPTASKBCC,
+   OPTASKCC,
++  OPTASKFOLLOWUP,
++  OPTASKXCOMMENTTO,
+   OPTATTACHSPLIT,
+   OPTAUTOEDIT,
+   OPTAUTOTAG,
+@@ -386,8 +435,11 @@ enum
+   OPTIMPLICITAUTOVIEW,
+   OPTINCLUDEONLYFIRST,
+   OPTKEEPFLAGGED,
++  OPTKEYWORDSLEGACY,
++  OPTKEYWORDSSTANDARD,
+   OPTMAILCAPSANITIZE,
+   OPTMAILCHECKRECENT,
++  OPTMAILCHECKSTATS,
+   OPTMAILDIRTRASH,
+   OPTMAILDIRCHECKCUR,
+   OPTMARKERS,
+@@ -401,6 +453,9 @@ enum
+   OPTMETOO,
+   OPTMHPURGE,
+   OPTMIMEFORWDECODE,
++#ifdef USE_NNTP
++  OPTMIMESUBJECT,	/* encode subject line with RFC2047 */
++#endif
+   OPTNARROWTREE,
+   OPTPAGERSTOP,
+   OPTPIPEDECODE,
+@@ -428,6 +483,13 @@ enum
+   OPTSAVEEMPTY,
+   OPTSAVENAME,
+   OPTSCORE,
++#ifdef USE_SIDEBAR
++  OPTSIDEBAR,
++  OPTSIDEBARFOLDERINDENT,
++  OPTSIDEBARNEWMAILONLY,
++  OPTSIDEBARNEXTNEWWRAP,
++  OPTSIDEBARSHORTPATH,
++#endif
+   OPTSIGDASHES,
+   OPTSIGONTOP,
+   OPTSORTRE,
+@@ -491,6 +553,17 @@ enum
+   OPTPGPAUTOINLINE,
+   OPTPGPREPLYINLINE,
+ 
++  /* news options */
 +
-+/* Get first newsgroup with new messages */
-+void nntp_buffy (char *buf, size_t len)
-+{
-+  unsigned int i;
++#ifdef USE_NNTP
++  OPTSHOWNEWNEWS,
++  OPTSHOWONLYUNREAD,
++  OPTSAVEUNSUB,
++  OPTLISTGROUP,
++  OPTLOADDESC,
++  OPTXCOMMENTTO,
++#endif
 +
-+  for (i = 0; i < CurrentNewsSrv->groups_num; i++)
-+  {
-+    NNTP_DATA *nntp_data = CurrentNewsSrv->groups_list[i];
+   /* pseudo options */
+ 
+   OPTAUXSORT,		/* (pseudo) using auxiliary sort function */
+@@ -511,6 +584,7 @@ enum
+   OPTSORTSUBTHREADS,	/* (pseudo) used when $sort_aux changes */
+   OPTNEEDRESCORE,	/* (pseudo) set when the `score' command is used */
+   OPTATTACHMSG,		/* (pseudo) used by attach-message */
++  OPTHIDEREAD,		/* (pseudo) whether or not hide read messages */
+   OPTKEEPQUIET,		/* (pseudo) shut up the message and refresh
+ 			 * 	    functions while we are executing an
+ 			 * 	    external program.
+@@ -521,6 +595,15 @@ enum
+   OPTDONTHANDLEPGPKEYS,	/* (pseudo) used to extract PGP keys */
+   OPTIGNOREMACROEVENTS, /* (pseudo) don't process macro/push/exec events while set */
+ 
++#ifdef USE_NOTMUCH
++  OPTVIRTSPOOLFILE,
++  OPTNOTMUCHRECORD,
++#endif
++#ifdef USE_NNTP
++  OPTNEWS,		/* (pseudo) used to change reader mode */
++  OPTNEWSSEND,		/* (pseudo) used to change behavior when posting */
++#endif
 +
-+    if (!nntp_data || !nntp_data->subscribed || !nntp_data->unread)
-+      continue;
+   OPTMAX
+ };
+ 
+@@ -600,10 +683,19 @@ typedef struct envelope
+   char *supersedes;
+   char *date;
+   char *x_label;
++  char *organization;
++#ifdef USE_NNTP
++  char *newsgroups;
++  char *xref;
++  char *followup_to;
++  char *x_comment_to;
++#endif
+   BUFFER *spam;
+   LIST *references;		/* message references (in reverse order) */
+   LIST *in_reply_to;		/* in-reply-to header content */
+   LIST *userhdrs;		/* user defined headers */
++  LIST *labels;
++  int kwtypes;
+ 
+   unsigned int irt_changed : 1; /* In-Reply-To changed to link/break threads */
+   unsigned int refs_changed : 1; /* References changed to break thread */
+@@ -719,7 +811,10 @@ typedef struct header
+   unsigned int mime : 1;    		/* has a MIME-Version header? */
+   unsigned int flagged : 1; 		/* marked important? */
+   unsigned int tagged : 1;
++  unsigned int appended : 1;		/* has been saved */
++  unsigned int purged : 1;   /* bypassing the trash folder */
+   unsigned int deleted : 1;
++  unsigned int quasi_deleted : 1;	/* deleted from mutt, but not modified on disk */
+   unsigned int changed : 1;
+   unsigned int attach_del : 1; 		/* has an attachment marked for deletion */
+   unsigned int old : 1;
+@@ -736,6 +831,7 @@ typedef struct header
+ 					 * This flag is used by the maildir_trash
+ 					 * option.
+ 					 */
++  unsigned int label_changed : 1;	/* editable - used for syncing */
+   
+   /* timezone of the sender of this message */
+   unsigned int zhours : 5;
+@@ -784,8 +880,9 @@ typedef struct header
+   int refno;			/* message number on server */
+ #endif
+ 
+-#if defined USE_POP || defined USE_IMAP
++#if defined USE_POP || defined USE_IMAP || defined USE_NOTMUCH || defined USE_NNTP
+   void *data;            	/* driver-specific data */
++  void (*free_cb)(struct header *); /* driver-specific data free function */
+ #endif
+   
+   char *maildir_flags;		/* unknown maildir flags */
+@@ -871,7 +968,9 @@ enum
+ typedef struct _context
+ {
+   char *path;
++  char *realpath;               /* used for buffy comparison and the sidebar */
+   FILE *fp;
++  time_t atime;
+   time_t mtime;
+   off_t size;
+   off_t vsize;
+@@ -891,9 +990,14 @@ typedef struct _context
+   int new;			/* how many new messages? */
+   int unread;			/* how many unread messages? */
+   int deleted;			/* how many deleted messages */
++  int appended;                 /* how many saved messages? */
+   int flagged;			/* how many flagged messages */
+   int msgnotreadyet;		/* which msg "new" in pager, -1 if none */
+ 
++#ifdef USE_COMPRESSED
++  void *compress_info;		/* compressed mbox module private data */
++#endif /* USE_COMPRESSED */
 +
-+    if (Context && Context->magic == M_NNTP &&
-+	!mutt_strcmp (nntp_data->group, ((NNTP_DATA *)Context->data)->group))
-+    {
-+      unsigned int i, unread = 0;
+   short magic;			/* mailbox type */
+ 
+   unsigned char rights[(RIGHTSMAX + 7)/8];	/* ACL bits */
+@@ -906,6 +1010,7 @@ typedef struct _context
+   unsigned int quiet : 1;	/* inhibit status messages? */
+   unsigned int collapsed : 1;   /* are all threads collapsed? */
+   unsigned int closing : 1;	/* mailbox is being closed */
++  unsigned int peekonly : 1;	/* just taking a glance, revert atime */
+ 
+   /* driver hooks */
+   void *data;			/* driver specific data */
+diff --git a/mutt_curses.h b/mutt_curses.h
+index 93d9aea..c891c5a 100644
+--- a/mutt_curses.h
++++ b/mutt_curses.h
+@@ -33,13 +33,6 @@
+ #define KEY_DC SL_KEY_DELETE
+ #define KEY_IC SL_KEY_IC
+ 
+-/*
+- * ncurses and SLang seem to send different characters when the Enter key is
+- * pressed, so define some macros to properly detect the Enter key.
+- */
+-#define M_ENTER_C '\r'
+-#define M_ENTER_S "\r"
+-
+ #else /* USE_SLANG_CURSES */
+ 
+ #if HAVE_NCURSESW_NCURSES_H
+@@ -52,9 +45,6 @@
+ # include <curses.h>
+ #endif
+ 
+-#define M_ENTER_C '\n'
+-#define M_ENTER_S "\n"
+-
+ #endif /* USE_SLANG_CURSES */
+ 
+ /* AIX defines ``lines'' in <term.h>, but it's used as a var name in
+@@ -64,6 +54,9 @@
+ #undef lines
+ #endif /* lines */
+ 
++#ifdef USE_SIDEBAR
++#define CLEARLINE_WIN(x) move (x,SidebarWidth), clrtoeol()
++#endif
+ #define CLEARLINE(x) move(x,0), clrtoeol()
+ #define CENTERLINE(x,y) move(y, (COLS-strlen(x))/2), addstr(x)
+ #define BEEP() do { if (option (OPTBEEP)) beep(); } while (0)
+@@ -122,14 +115,40 @@ enum
+   MT_COLOR_SEARCH,
+   MT_COLOR_BOLD,
+   MT_COLOR_UNDERLINE,
+-  MT_COLOR_INDEX,
+   MT_COLOR_PROMPT,
++  MT_COLOR_PROGRESS,
++#ifdef USE_SIDEBAR
++  MT_COLOR_DIVIDER,
++  MT_COLOR_FLAGGED,
++  MT_COLOR_HIGHLIGHT,
++  MT_COLOR_NEW,
++  MT_COLOR_SB_INDICATOR,
++  MT_COLOR_SB_SPOOLFILE,
++#endif
++  /* please no non-MT_COLOR_INDEX objects after this point */
++#ifdef USE_NOTMUCH
++  MT_COLOR_INDEX_TAG,
++#endif
++  MT_COLOR_INDEX,
++  MT_COLOR_INDEX_AUTHOR,
++  MT_COLOR_INDEX_FLAGS,
++  MT_COLOR_INDEX_SUBJECT,
++  /* below here - only index coloring stuff that doesn't have a pattern */
++  MT_COLOR_INDEX_COLLAPSED,
++  MT_COLOR_INDEX_DATE,
++  MT_COLOR_INDEX_LABEL,
++  MT_COLOR_INDEX_NUMBER,
++  MT_COLOR_INDEX_SIZE,
++#ifdef USE_NOTMUCH
++  MT_COLOR_INDEX_TAGS,
++#endif
+   MT_COLOR_MAX
+ };
+ 
+ typedef struct color_line
+ {
+   regex_t rx;
++  int match; /* which substringmap 0 for old behaviour */
+   char *pattern;
+   pattern_t *color_pattern; /* compiled pattern to speed up index color
+                                calculation */
+@@ -163,12 +182,16 @@ void mutt_progress_update (progress_t* progress, long pos, int percent);
+ 
+ static inline int mutt_term_width(short wrap)
+ {
++  int cols = COLS;
++#ifdef USE_SIDEBAR
++  cols -= SidebarWidth;
++#endif
+   if (wrap < 0)
+-    return COLS > -wrap ? COLS + wrap : COLS;
++    return cols > -wrap ? cols + wrap : cols;
+   else if (wrap)
+-    return wrap < COLS ? wrap : COLS;
++    return wrap < cols ? wrap : cols;
+   else
+-    return COLS;
++    return cols;
+ }
+ 
+ extern int *ColorQuote;
+@@ -176,7 +199,14 @@ extern int ColorQuoteUsed;
+ extern int ColorDefs[];
+ extern COLOR_LINE *ColorHdrList;
+ extern COLOR_LINE *ColorBodyList;
++extern COLOR_LINE *ColorStatusList;
+ extern COLOR_LINE *ColorIndexList;
++extern COLOR_LINE *ColorIndexAuthorList;
++extern COLOR_LINE *ColorIndexFlagsList;
++extern COLOR_LINE *ColorIndexSubjectList;
++#ifdef USE_NOTMUCH
++extern COLOR_LINE *ColorIndexTagList;
++#endif
+ 
+ void ci_init_color (void);
+ void ci_start_color (void);
+diff --git a/mutt_menu.h b/mutt_menu.h
+index 8192019..c10171f 100644
+--- a/mutt_menu.h
++++ b/mutt_menu.h
+@@ -34,6 +34,9 @@
+ #define REDRAW_FULL		(1<<5)
+ #define REDRAW_BODY		(1<<6)
+ #define REDRAW_SIGWINCH		(1<<7)
++#ifdef USE_SIDEBAR
++#define REDRAW_SIDEBAR		(1<<8)
++#endif
+ 
+ #define M_MODEFMT "-- Mutt: %s"
+ 
+@@ -82,6 +85,9 @@ typedef struct menu_t
+ void mutt_menu_init (void);
+ void menu_jump (MUTTMENU *);
+ void menu_redraw_full (MUTTMENU *);
++#ifdef USE_SIDEBAR
++void menu_redraw_sidebar (MUTTMENU *);
++#endif
+ void menu_redraw_index (MUTTMENU *);
+ void menu_redraw_status (MUTTMENU *);
+ void menu_redraw_motion (MUTTMENU *);
+@@ -115,4 +121,6 @@ int mutt_menuLoop (MUTTMENU *);
+ void index_make_entry (char *, size_t, struct menu_t *, int);
+ int index_color (int);
+ 
++int mutt_limit_current_thread (HEADER *h);
 +
-+      for (i = 0; i < Context->msgcount; i++)
-+	if (!Context->hdrs[i]->read && !Context->hdrs[i]->deleted)
-+	  unread++;
-+      if (!unread)
-+	continue;
-+    }
-+    strfcpy (buf, nntp_data->group, len);
-+    break;
-+  }
-+}
-diff -urN mutt-1.6.1/nntp.c mutt-1.6.1-neomutt/nntp.c
---- mutt-1.6.1/nntp.c	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/nntp.c	2016-06-12 18:43:00.720452549 +0100
-@@ -0,0 +1,2434 @@
+ #endif /* _MUTT_MENU_H_ */
+diff --git a/mutt_notmuch.c b/mutt_notmuch.c
+new file mode 100644
+index 0000000..e17d3df
+--- /dev/null
++++ b/mutt_notmuch.c
+@@ -0,0 +1,1984 @@
 +/*
-+ * Copyright (C) 1998 Brandon Long <blong at fiction.net>
-+ * Copyright (C) 1999 Andrej Gritsenko <andrej at lucky.net>
-+ * Copyright (C) 2000-2012 Vsevolod Volkov <vvv at mutt.org.ua>
++ * Notmuch support for mutt
 + *
-+ *     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.
++ * Copyright (C) 2011, 2012 Karel Zak <kzak at redhat.com>
 + *
-+ *     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.
++ * Notes:
 + *
-+ *     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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ * - notmuch uses private CONTEXT->data and private HEADER->data
++ *
++ * - all exported functions are usable within notmuch context only
++ *
++ * - all functions have to be covered by "ctx->magic == M_NOTMUCH" check
++ *   (it's implemented in get_ctxdata() and init_context() functions).
++ *
++ * - exception are nm_nonctx_* functions -- these functions use nm_default_uri
++ *   (or parse URI from another resource)
 + */
-+
 +#if HAVE_CONFIG_H
-+#include "config.h"
++# include "config.h"
 +#endif
 +
 +#include "mutt.h"
-+#include "mutt_curses.h"
-+#include "sort.h"
 +#include "mx.h"
-+#include "mime.h"
-+#include "rfc1524.h"
 +#include "rfc2047.h"
++#include "sort.h"
 +#include "mailbox.h"
-+#include "mutt_crypt.h"
-+#include "nntp.h"
-+
-+#if defined(USE_SSL)
-+#include "mutt_ssl.h"
-+#endif
-+
-+#ifdef HAVE_PGP
-+#include "pgp.h"
-+#endif
-+
-+#ifdef HAVE_SMIME
-+#include "smime.h"
-+#endif
-+
-+#if USE_HCACHE
-+#include "hcache.h"
-+#endif
++#include "copy.h"
++#include "keymap.h"
++#include "url.h"
++#include "buffy.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>
-+#include <stdlib.h>
-+
-+#ifdef USE_SASL
-+#include <sasl/sasl.h>
-+#include <sasl/saslutil.h>
-+
-+#include "mutt_sasl.h"
-+#endif
-+
-+static int nntp_connect_error (NNTP_SERVER *nserv)
-+{
-+  nserv->status = NNTP_NONE;
-+  mutt_error _("Server closed connection!");
-+  mutt_sleep (2);
-+  return -1;
-+}
-+
-+/* Get capabilities:
-+ * -1 - error, connection is closed
-+ *  0 - mode is reader, capabilities setted up
-+ *  1 - need to switch to reader mode */
-+static int nntp_capabilities (NNTP_SERVER *nserv)
-+{
-+  CONNECTION *conn = nserv->conn;
-+  unsigned int mode_reader = 0;
-+  char buf[LONG_STRING];
-+  char authinfo[LONG_STRING] = "";
-+
-+  nserv->hasCAPABILITIES = 0;
-+  nserv->hasSTARTTLS = 0;
-+  nserv->hasDATE = 0;
-+  nserv->hasLIST_NEWSGROUPS = 0;
-+  nserv->hasLISTGROUP = 0;
-+  nserv->hasLISTGROUPrange = 0;
-+  nserv->hasOVER = 0;
-+  FREE (&nserv->authenticators);
++#include <utime.h>
 +
-+  if (mutt_socket_write (conn, "CAPABILITIES\r\n") < 0 ||
-+      mutt_socket_readln (buf, sizeof (buf), conn) < 0)
-+    return nntp_connect_error (nserv);
++#include <notmuch.h>
 +
-+  /* no capabilities */
-+  if (mutt_strncmp ("101", buf, 3))
-+    return 1;
-+  nserv->hasCAPABILITIES = 1;
++#include "mutt_notmuch.h"
++#include "mutt_curses.h"
 +
-+  /* parse capabilities */
-+  do
-+  {
-+    if (mutt_socket_readln (buf, sizeof (buf), conn) < 0)
-+      return nntp_connect_error (nserv);
-+    if (!mutt_strcmp ("STARTTLS", buf))
-+      nserv->hasSTARTTLS = 1;
-+    else if (!mutt_strcmp ("MODE-READER", buf))
-+      mode_reader = 1;
-+    else if (!mutt_strcmp ("READER", buf))
-+    {
-+      nserv->hasDATE = 1;
-+      nserv->hasLISTGROUP = 1;
-+      nserv->hasLISTGROUPrange = 1;
-+    }
-+    else if (!mutt_strncmp ("AUTHINFO ", buf, 9))
-+    {
-+      safe_strcat (buf, sizeof (buf), " ");
-+      strfcpy (authinfo, buf + 8, sizeof (authinfo));
-+    }
-+#ifdef USE_SASL
-+    else if (!mutt_strncmp ("SASL ", buf, 5))
-+    {
-+      char *p = buf + 5;
-+      while (*p == ' ')
-+	p++;
-+      nserv->authenticators = safe_strdup (p);
-+    }
-+#endif
-+    else if (!mutt_strcmp ("OVER", buf))
-+      nserv->hasOVER = 1;
-+    else if (!mutt_strncmp ("LIST ", buf, 5))
-+    {
-+      char *p = strstr (buf, " NEWSGROUPS");
-+      if (p)
-+      {
-+	p += 11;
-+	if (*p == '\0' || *p == ' ')
-+	  nserv->hasLIST_NEWSGROUPS = 1;
-+      }
-+    }
-+  } while (mutt_strcmp (".", buf));
-+  *buf = '\0';
-+#ifdef USE_SASL
-+  if (nserv->authenticators && strcasestr (authinfo, " SASL "))
-+    strfcpy (buf, nserv->authenticators, sizeof (buf));
++#ifdef LIBNOTMUCH_CHECK_VERSION
++#undef LIBNOTMUCH_CHECK_VERSION
 +#endif
-+  if (strcasestr (authinfo, " USER "))
-+  {
-+    if (*buf)
-+      safe_strcat (buf, sizeof (buf), " ");
-+    safe_strcat (buf, sizeof (buf), "USER");
-+  }
-+  mutt_str_replace (&nserv->authenticators, buf);
-+
-+  /* current mode is reader */
-+  if (nserv->hasDATE)
-+    return 0;
-+
-+  /* server is mode-switching, need to switch to reader mode */
-+  if (mode_reader)
-+    return 1;
-+
-+  mutt_socket_close (conn);
-+  nserv->status = NNTP_BYE;
-+  mutt_error _("Server doesn't support reader mode.");
-+  mutt_sleep (2);
-+  return -1;
-+}
 +
-+char *OverviewFmt =
-+	"Subject:\0"
-+	"From:\0"
-+	"Date:\0"
-+	"Message-ID:\0"
-+	"References:\0"
-+	"Content-Length:\0"
-+	"Lines:\0"
-+	"\0";
++/* The definition in <notmuch.h> is broken */
++#define LIBNOTMUCH_CHECK_VERSION(major, minor, micro)                               \
++    (LIBNOTMUCH_MAJOR_VERSION > (major) ||                                          \
++     (LIBNOTMUCH_MAJOR_VERSION == (major) && LIBNOTMUCH_MINOR_VERSION > (minor)) || \
++     (LIBNOTMUCH_MAJOR_VERSION == (major) && LIBNOTMUCH_MINOR_VERSION == (minor) && \
++      LIBNOTMUCH_MICRO_VERSION >= (micro)))
 +
-+/* Detect supported commands */
-+static int nntp_attempt_features (NNTP_SERVER *nserv)
-+{
-+  CONNECTION *conn = nserv->conn;
-+  char buf[LONG_STRING];
 +
-+  /* no CAPABILITIES, trying DATE, LISTGROUP, LIST NEWSGROUPS */
-+  if (!nserv->hasCAPABILITIES)
-+  {
-+    if (mutt_socket_write (conn, "DATE\r\n") < 0 ||
-+	mutt_socket_readln (buf, sizeof (buf), conn) < 0)
-+      return nntp_connect_error (nserv);
-+    if (mutt_strncmp ("500", buf, 3))
-+      nserv->hasDATE = 1;
++/* read whole-thread or matching messages only? */
++enum {
++	NM_QUERY_TYPE_MESGS = 1,	/* default */
++	NM_QUERY_TYPE_THREADS
++};
 +
-+    if (mutt_socket_write (conn, "LISTGROUP\r\n") < 0 ||
-+	mutt_socket_readln (buf, sizeof (buf), conn) < 0)
-+      return nntp_connect_error (nserv);
-+    if (mutt_strncmp ("500", buf, 3))
-+      nserv->hasLISTGROUP = 1;
++/*
++ * Parsed URI arguments
++ */
++struct uri_tag {
++	char *name;
++	char *value;
++	struct uri_tag *next;
++};
 +
-+    if (mutt_socket_write (conn, "LIST NEWSGROUPS +\r\n") < 0 ||
-+	mutt_socket_readln (buf, sizeof (buf), conn) < 0)
-+      return nntp_connect_error (nserv);
-+    if (mutt_strncmp ("500", buf, 3))
-+      nserv->hasLIST_NEWSGROUPS = 1;
-+    if (!mutt_strncmp ("215", buf, 3))
-+    {
-+      do
-+      {
-+	if (mutt_socket_readln (buf, sizeof (buf), conn) < 0)
-+	  return nntp_connect_error (nserv);
-+      } while (mutt_strcmp (".", buf));
-+    }
-+  }
++/*
++ * HEADER->(nm_hdrdata *)data->tag_list node
++ */
++struct nm_hdrtag
++{
++  char *tag;
++  char *transformed;
++  struct nm_hdrtag *next;
++};
 +
-+  /* no LIST NEWSGROUPS, trying XGTITLE */
-+  if (!nserv->hasLIST_NEWSGROUPS)
-+  {
-+    if (mutt_socket_write (conn, "XGTITLE\r\n") < 0 ||
-+	mutt_socket_readln (buf, sizeof (buf), conn) < 0)
-+      return nntp_connect_error (nserv);
-+    if (mutt_strncmp ("500", buf, 3))
-+      nserv->hasXGTITLE = 1;
-+  }
++/*
++ * HEADER->data
++ */
++struct nm_hdrdata {
++	char *folder;
++	char *tags;
++	char *tags_transformed;
++	struct nm_hdrtag *tag_list;
++	char *oldpath;
++	char *virtual_id;
++	int magic;
++};
 +
-+  /* no OVER, trying XOVER */
-+  if (!nserv->hasOVER)
-+  {
-+    if (mutt_socket_write (conn, "XOVER\r\n") < 0 ||
-+	mutt_socket_readln (buf, sizeof (buf), conn) < 0)
-+      return nntp_connect_error (nserv);
-+    if (mutt_strncmp ("500", buf, 3))
-+      nserv->hasXOVER = 1;
-+  }
++/*
++ * CONTEXT->data
++ */
++struct nm_ctxdata {
++	notmuch_database_t *db;
 +
-+  /* trying LIST OVERVIEW.FMT */
-+  if (nserv->hasOVER || nserv->hasXOVER)
-+  {
-+    if (mutt_socket_write (conn, "LIST OVERVIEW.FMT\r\n") < 0 ||
-+	mutt_socket_readln (buf, sizeof (buf), conn) < 0)
-+      return nntp_connect_error (nserv);
-+    if (mutt_strncmp ("215", buf, 3))
-+      nserv->overview_fmt = OverviewFmt;
-+    else
-+    {
-+      int chunk, cont = 0;
-+      size_t buflen = 2 * LONG_STRING, off = 0, b = 0;
++	char *db_filename;
++	char *db_query;
++	int db_limit;
++	int query_type;
 +
-+      if (nserv->overview_fmt)
-+	FREE (&nserv->overview_fmt);
-+      nserv->overview_fmt = safe_malloc (buflen);
++	struct uri_tag *query_items;
 +
-+      while (1)
-+      {
-+	if (buflen - off < LONG_STRING)
-+	{
-+	  buflen *= 2;
-+	  safe_realloc (&nserv->overview_fmt, buflen);
-+	}
++	progress_t progress;
++	int oldmsgcount;
++	int ignmsgcount;	/* ingored messages */
 +
-+	chunk = mutt_socket_readln (nserv->overview_fmt + off,
-+				    buflen - off, conn);
-+	if (chunk < 0)
-+	{
-+	  FREE (&nserv->overview_fmt);
-+	  return nntp_connect_error (nserv);
-+	}
++	unsigned int noprogress : 1,
++		     longrun : 1,
++		     trans : 1,
++		     progress_ready : 1;
 +
-+	if (!cont && !mutt_strcmp (".", nserv->overview_fmt + off))
-+	  break;
++};
 +
-+	cont = chunk >= buflen - off ? 1 : 0;
-+	off += strlen (nserv->overview_fmt + off);
-+	if (!cont)
-+	{
-+	  char *colon;
++static HEADER *get_mutt_header(CONTEXT *ctx, notmuch_message_t *msg);
++static notmuch_message_t *get_nm_message(notmuch_database_t *db, HEADER *hdr);
 +
-+	  if (nserv->overview_fmt[b] == ':')
-+	  {
-+	    memmove (nserv->overview_fmt + b,
-+		     nserv->overview_fmt + b + 1, off - b - 1);
-+	    nserv->overview_fmt[off - 1] = ':';
-+	  }
-+	  colon = strchr (nserv->overview_fmt + b, ':');
-+	  if (!colon)
-+	    nserv->overview_fmt[off++] = ':';
-+	  else if (strcmp (colon + 1, "full"))
-+	    off = colon + 1 - nserv->overview_fmt;
-+	  if (!strcasecmp (nserv->overview_fmt + b, "Bytes:"))
-+	  {
-+	    strcpy (nserv->overview_fmt + b, "Content-Length:");
-+	    off = b + strlen (nserv->overview_fmt + b);
-+	  }
-+	  nserv->overview_fmt[off++] = '\0';
-+	  b = off;
++static void url_free_tags(struct uri_tag *tags)
++{
++	while (tags) {
++		struct uri_tag *next = tags->next;
++		FREE(&tags->name);
++		FREE(&tags->value);
++		FREE(&tags);
++		tags = next;
 +	}
-+      }
-+      nserv->overview_fmt[off++] = '\0';
-+      safe_realloc (&nserv->overview_fmt, off);
-+    }
-+  }
-+  return 0;
 +}
 +
-+/* Get login, password and authenticate */
-+static int nntp_auth (NNTP_SERVER *nserv)
++static int url_parse_query(char *url, char **filename, struct uri_tag **tags)
 +{
-+  CONNECTION *conn = nserv->conn;
-+  char buf[LONG_STRING];
-+  char authenticators[LONG_STRING] = "USER";
-+  char *method, *a, *p;
-+  unsigned char flags = conn->account.flags;
++	char *p = strstr(url, "://");	/* remote unsupported */
++	char *e;
++	struct uri_tag *tag, *last = NULL;
 +
-+  while (1)
-+  {
-+    /* get login and password */
-+    if (mutt_account_getuser (&conn->account) || !conn->account.user[0] ||
-+	mutt_account_getpass (&conn->account) || !conn->account.pass[0])
-+      break;
++	*filename = NULL;
++	*tags = NULL;
 +
-+    /* get list of authenticators */
-+    if (NntpAuthenticators && *NntpAuthenticators)
-+      strfcpy (authenticators, NntpAuthenticators, sizeof (authenticators));
-+    else if (nserv->hasCAPABILITIES)
-+    {
-+      strfcpy (authenticators, NONULL (nserv->authenticators),
-+	       sizeof (authenticators));
-+      p = authenticators;
-+      while (*p)
-+      {
-+	if (*p == ' ')
-+	  *p = ':';
-+	p++;
-+      }
-+    }
-+    p = authenticators;
-+    while (*p)
-+    {
-+      *p = ascii_toupper (*p);
-+      p++;
-+    }
++	if (!p || !*(p + 3))
++		return -1;
 +
-+    dprint (1, (debugfile,
-+		"nntp_auth: available methods: %s\n", nserv->authenticators));
-+    a = authenticators;
-+    while (1)
-+    {
-+      if (!a)
-+      {
-+	mutt_error _("No authenticators available");
-+	mutt_sleep (2);
-+	break;
-+      }
++	p += 3;
++	*filename = p;
 +
-+      method = a;
-+      a = strchr (a, ':');
-+      if (a)
-+	*a++ = '\0';
++	e = strchr(p, '?');
 +
-+      /* check authenticator */
-+      if (nserv->hasCAPABILITIES)
-+      {
-+	char *m;
++	*filename = e ? e == p ? NULL : strndup(p, e - p) : safe_strdup(p);
++	if (!e)
++		return 0;
 +
-+	if (!nserv->authenticators)
-+	  continue;
-+	m = strcasestr (nserv->authenticators, method);
-+	if (!m)
-+	  continue;
-+	if (m > nserv->authenticators && *(m - 1) != ' ')
-+	  continue;
-+	m += strlen (method);
-+	if (*m != '\0' && *m != ' ')
-+	  continue;
-+      }
-+      dprint (1, (debugfile, "nntp_auth: trying method %s\n", method));
++	if (*filename && url_pct_decode(*filename) < 0)
++		goto err;
++	if (!e)
++		return 0;	/* only filename */
 +
-+      /* AUTHINFO USER authentication */
-+      if (!strcmp (method, "USER"))
-+      {
-+	mutt_message (_("Authenticating (%s)..."), method);
-+	snprintf (buf, sizeof (buf), "AUTHINFO USER %s\r\n", conn->account.user);
-+	if (mutt_socket_write (conn, buf) < 0 ||
-+	    mutt_socket_readln (buf, sizeof (buf), conn) < 0)
-+	  break;
++	++e;	/* skip '?' */
++	p = e;
 +
-+	/* authenticated, password is not required */
-+	if (!mutt_strncmp ("281", buf, 3))
-+	  return 0;
++	while (p && *p) {
++		tag = safe_calloc(1, sizeof(struct uri_tag));
++		if (!tag)
++			goto err;
 +
-+	/* username accepted, sending password */
-+	if (!mutt_strncmp ("381", buf, 3))
-+	{
-+#ifdef DEBUG
-+	  if (debuglevel < M_SOCK_LOG_FULL)
-+	    dprint (M_SOCK_LOG_CMD, (debugfile,
-+		    "%d> AUTHINFO PASS *\n", conn->fd));
-+#endif
-+	  snprintf (buf, sizeof (buf), "AUTHINFO PASS %s\r\n",
-+		    conn->account.pass);
-+	  if (mutt_socket_write_d (conn, buf, -1, M_SOCK_LOG_FULL) < 0 ||
-+	      mutt_socket_readln (buf, sizeof (buf), conn) < 0)
-+	  break;
++		if (!*tags)
++			last = *tags = tag;
++		else {
++			last->next = tag;
++			last = tag;
++		}
++
++		e = strchr(p, '=');
++		if (!e)
++			e = strchr(p, '&');
++		tag->name = e ? strndup(p, e - p) : safe_strdup(p);
++		if (!tag->name || url_pct_decode(tag->name) < 0)
++			goto err;
++		if (!e)
++			break;
++
++		p = e + 1;
++
++		if (*e == '&')
++			continue;
 +
-+	  /* authenticated */
-+	  if (!mutt_strncmp ("281", buf, 3))
-+	    return 0;
++		e = strchr(p, '&');
++		tag->value = e ? strndup(p, e - p) : safe_strdup(p);
++		if (!tag->value || url_pct_decode(tag->value) < 0)
++			goto err;
++		if (!e)
++			break;
++		p = e + 1;
 +	}
 +
-+	/* server doesn't support AUTHINFO USER, trying next method */
-+	if (*buf == '5')
-+	  continue;
-+      }
++	return 0;
++err:
++	FREE(&(*filename));
++	url_free_tags(*tags);
++	return -1;
++}
 +
-+      else
-+      {
-+#ifdef USE_SASL
-+	sasl_conn_t *saslconn;
-+	sasl_interact_t *interaction = NULL;
-+	int rc;
-+	char inbuf[LONG_STRING] = "";
-+	const char *mech;
-+	const char *client_out = NULL;
-+	unsigned int client_len, len;
++static void free_tag_list(struct nm_hdrtag **tag_list)
++{
++	struct nm_hdrtag *tmp;
 +
-+	if (mutt_sasl_client_new (conn, &saslconn) < 0)
++	while ((tmp = *tag_list) != NULL)
 +	{
-+	  dprint (1, (debugfile,
-+		  "nntp_auth: error allocating SASL connection.\n"));
-+	  continue;
++		*tag_list = tmp->next;
++		FREE(&tmp->tag);
++		FREE(&tmp->transformed);
++		FREE(&tmp);
 +	}
 +
-+	while (1)
-+	{
-+	  rc = sasl_client_start (saslconn, method, &interaction,
-+				  &client_out, &client_len, &mech);
-+	  if (rc != SASL_INTERACT)
-+	    break;
-+	  mutt_sasl_interact (interaction);
-+	}
-+	if (rc != SASL_OK && rc != SASL_CONTINUE)
-+	{
-+	  sasl_dispose (&saslconn);
-+	  dprint (1, (debugfile,
-+		  "nntp_auth: error starting SASL authentication exchange.\n"));
-+	  continue;
-+	}
++	*tag_list = 0;
++}
 +
-+	mutt_message (_("Authenticating (%s)..."), method);
-+	snprintf (buf, sizeof (buf), "AUTHINFO SASL %s", method);
++static void free_hdrdata(struct nm_hdrdata *data)
++{
++	if (!data)
++		return;
 +
-+	/* looping protocol */
-+	while (rc == SASL_CONTINUE || (rc == SASL_OK && client_len))
-+	{
-+	  /* send out client response */
-+	  if (client_len)
-+	  {
-+#ifdef DEBUG
-+	    if (debuglevel >= M_SOCK_LOG_FULL)
-+	    {
-+	      char tmp[LONG_STRING];
-+	      memcpy (tmp, client_out, client_len);
-+	      for (p = tmp; p < tmp + client_len; p++)
-+	      {
-+		if (*p == '\0')
-+		  *p = '.';
-+	      }
-+	      *p = '\0';
-+	      dprint (1, (debugfile, "SASL> %s\n", tmp));
-+	    }
-+#endif
++	dprint(2, (debugfile, "nm: freeing header %p\n", data));
++	FREE(&data->folder);
++	FREE(&data->tags);
++	FREE(&data->tags_transformed);
++	free_tag_list(&data->tag_list);
++	FREE(&data->oldpath);
++	FREE(&data->virtual_id);
++	FREE(&data);
++}
 +
-+	    if (*buf)
-+	      safe_strcat (buf, sizeof (buf), " ");
-+	    len = strlen (buf);
-+	    if (sasl_encode64 (client_out, client_len,
-+		buf + len, sizeof (buf) - len, &len) != SASL_OK)
-+	    {
-+	      dprint (1, (debugfile,
-+		      "nntp_auth: error base64-encoding client response.\n"));
-+	      break;
-+	    }
-+	  }
++static void free_ctxdata(struct nm_ctxdata *data)
++{
++	if (!data)
++		return;
 +
-+	  safe_strcat (buf, sizeof (buf), "\r\n");
-+#ifdef DEBUG
-+	  if (debuglevel < M_SOCK_LOG_FULL)
-+	  {
-+	    if (strchr (buf, ' '))
-+	      dprint (M_SOCK_LOG_CMD, (debugfile, "%d> AUTHINFO SASL %s%s\n",
-+		      conn->fd, method, client_len ? " sasl_data" : ""));
-+	    else
-+	      dprint (M_SOCK_LOG_CMD, (debugfile, "%d> sasl_data\n", conn->fd));
-+	  }
-+#endif
-+	  client_len = 0;
-+	  if (mutt_socket_write_d (conn, buf, -1, M_SOCK_LOG_FULL) < 0 ||
-+	      mutt_socket_readln_d (inbuf, sizeof (inbuf), conn, M_SOCK_LOG_FULL) < 0)
-+	    break;
-+	  if (mutt_strncmp (inbuf, "283 ", 4) &&
-+	      mutt_strncmp (inbuf, "383 ", 4))
-+	  {
-+#ifdef DEBUG
-+	    if (debuglevel < M_SOCK_LOG_FULL)
-+	      dprint (M_SOCK_LOG_CMD, (debugfile, "%d< %s\n", conn->fd, inbuf));
-+#endif
-+	    break;
-+	  }
-+#ifdef DEBUG
-+	  if (debuglevel < M_SOCK_LOG_FULL)
-+	  {
-+	    inbuf[3] = '\0';
-+	    dprint (M_SOCK_LOG_CMD, (debugfile,
-+		    "%d< %s sasl_data\n", conn->fd, inbuf));
-+	  }
-+#endif
++	dprint(1, (debugfile, "nm: freeing context data %p\n", data));
 +
-+	  if (!strcmp ("=", inbuf + 4))
-+	    len = 0;
-+	  else if (sasl_decode64 (inbuf + 4, strlen (inbuf + 4),
-+		   buf, sizeof (buf) - 1, &len) != SASL_OK)
-+	  {
-+	    dprint (1, (debugfile,
-+		    "nntp_auth: error base64-decoding server response.\n"));
-+	    break;
-+	  }
-+#ifdef DEBUG
-+	  else if (debuglevel >= M_SOCK_LOG_FULL)
-+	  {
-+	    char tmp[LONG_STRING];
-+	    memcpy (tmp, buf, len);
-+	    for (p = tmp; p < tmp + len; p++)
-+	    {
-+	      if (*p == '\0')
-+		*p = '.';
-+	    }
-+	    *p = '\0';
-+	    dprint (1, (debugfile, "SASL< %s\n", tmp));
-+	  }
++	if (data->db)
++#ifdef NOTMUCH_API_3
++	        notmuch_database_destroy(data->db);
++#else
++		notmuch_database_close(data->db);
 +#endif
++	data->db = NULL;
 +
-+	  while (1)
-+	  {
-+	    rc = sasl_client_step (saslconn, buf, len,
-+				   &interaction, &client_out, &client_len);
-+	    if (rc != SASL_INTERACT)
-+	      break;
-+	    mutt_sasl_interact (interaction);
-+	  }
-+	  if (*inbuf != '3')
-+	    break;
++	FREE(&data->db_filename);
++	FREE(&data->db_query);
++	url_free_tags(data->query_items);
++	FREE(&data);
++}
 +
-+	  *buf = '\0';
-+	} /* looping protocol */
++static struct nm_ctxdata *new_ctxdata(char *uri)
++{
++	struct nm_ctxdata *data;
 +
-+	if (rc == SASL_OK && client_len == 0 && *inbuf == '2')
-+	{
-+	  mutt_sasl_setup_conn (conn, saslconn);
-+	  return 0;
-+	}
++	if (!uri)
++		return NULL;
 +
-+	/* terminate SASL sessoin */
-+	sasl_dispose (&saslconn);
-+	if (conn->fd < 0)
-+	  break;
-+	if (!mutt_strncmp (inbuf, "383 ", 4))
-+	{
-+	  if (mutt_socket_write (conn, "*\r\n") < 0 ||
-+	      mutt_socket_readln (inbuf, sizeof (inbuf), conn) < 0)
-+	    break;
-+	}
++	data = safe_calloc(1, sizeof(struct nm_ctxdata));
++	dprint(1, (debugfile, "nm: initialize context data %p\n", data));
 +
-+	/* server doesn't support AUTHINFO SASL, trying next method */
-+	if (*inbuf == '5')
-+	  continue;
-+#else
-+	continue;
-+#endif /* USE_SASL */
-+      }
++	data->db_limit = NotmuchDBLimit;
 +
-+      mutt_error (_("%s authentication failed."), method);
-+      mutt_sleep (2);
-+      break;
-+    }
-+    break;
-+  }
++	if (url_parse_query(uri, &data->db_filename, &data->query_items)) {
++		mutt_error(_("failed to parse notmuch uri: %s"), uri);
++		data->db_filename = NULL;
++		data->query_items = NULL;
++		data->query_type = 0;
++		return NULL;
++	}
 +
-+  /* error */
-+  nserv->status = NNTP_BYE;
-+  conn->account.flags = flags;
-+  if (conn->fd < 0)
-+  {
-+    mutt_error _("Server closed connection!");
-+    mutt_sleep (2);
-+  }
-+  else
-+    mutt_socket_close (conn);
-+  return -1;
++	return data;
 +}
 +
-+/* Connect to server, authenticate and get capabilities */
-+int nntp_open_connection (NNTP_SERVER *nserv)
++static int deinit_context(CONTEXT *ctx)
 +{
-+  CONNECTION *conn = nserv->conn;
-+  char buf[STRING];
-+  int cap;
-+  unsigned int posting = 0, auth = 1;
++	int i;
 +
-+  if (nserv->status == NNTP_OK)
-+    return 0;
-+  if (nserv->status == NNTP_BYE)
-+    return -1;
-+  nserv->status = NNTP_NONE;
++	if (!ctx || ctx->magic != M_NOTMUCH)
++		return -1;
 +
-+  if (mutt_socket_open (conn) < 0)
-+    return -1;
++	for (i = 0; i < ctx->msgcount; i++) {
++		HEADER *h = ctx->hdrs[i];
 +
-+  if (mutt_socket_readln (buf, sizeof (buf), conn) < 0)
-+    return nntp_connect_error (nserv);
++		if (h) {
++			free_hdrdata(h->data);
++			h->data = NULL;
++		}
++	}
 +
-+  if (!mutt_strncmp ("200", buf, 3))
-+    posting = 1;
-+  else if (mutt_strncmp ("201", buf, 3))
-+  {
-+    mutt_socket_close (conn);
-+    mutt_remove_trailing_ws (buf);
-+    mutt_error ("%s", buf);
-+    mutt_sleep (2);
-+    return -1;
-+  }
++	free_ctxdata(ctx->data);
++	ctx->data = NULL;
++	return 0;
++}
 +
-+  /* get initial capabilities */
-+  cap = nntp_capabilities (nserv);
-+  if (cap < 0)
-+    return -1;
++static int init_context(CONTEXT *ctx)
++{
++	if (!ctx || ctx->magic != M_NOTMUCH)
++		return -1;
 +
-+  /* tell news server to switch to mode reader if it isn't so */
-+  if (cap > 0)
-+  {
-+    if (mutt_socket_write (conn, "MODE READER\r\n") < 0 ||
-+	mutt_socket_readln (buf, sizeof (buf), conn) < 0)
-+      return nntp_connect_error (nserv);
++	if (ctx->data)
++		return 0;
 +
-+    if (!mutt_strncmp ("200", buf, 3))
-+      posting = 1;
-+    else if (!mutt_strncmp ("201", buf, 3))
-+      posting = 0;
-+    /* error if has capabilities, ignore result if no capabilities */
-+    else if (nserv->hasCAPABILITIES)
-+    {
-+      mutt_socket_close (conn);
-+      mutt_error _("Could not switch to reader mode.");
-+      mutt_sleep (2);
-+      return -1;
-+    }
++	ctx->data = new_ctxdata(ctx->path);
++	if (!ctx->data)
++		return -1;
 +
-+    /* recheck capabilities after MODE READER */
-+    if (nserv->hasCAPABILITIES)
-+    {
-+      cap = nntp_capabilities (nserv);
-+      if (cap < 0)
-+	return -1;
-+    }
-+  }
++	ctx->mx_close = deinit_context;
++	return 0;
++}
 +
-+  mutt_message (_("Connected to %s. %s"), conn->account.host,
-+		posting ? _("Posting is ok.") : _("Posting is NOT ok."));
-+  mutt_sleep (1);
++char *nm_header_get_folder(HEADER *h)
++{
++	return h && h->data ? ((struct nm_hdrdata *) h->data)->folder : NULL;
++}
 +
-+#if defined(USE_SSL)
-+  /* Attempt STARTTLS if available and desired. */
-+  if (nserv->use_tls != 1 && (nserv->hasSTARTTLS || option (OPTSSLFORCETLS)))
-+  {
-+    if (nserv->use_tls == 0)
-+      nserv->use_tls = option (OPTSSLFORCETLS) ||
-+			query_quadoption (OPT_SSLSTARTTLS,
-+			_("Secure connection with TLS?")) == M_YES ? 2 : 1;
-+    if (nserv->use_tls == 2)
-+    {
-+      if (mutt_socket_write (conn, "STARTTLS\r\n") < 0 ||
-+	  mutt_socket_readln (buf, sizeof (buf), conn) < 0)
-+	return nntp_connect_error (nserv);
-+      if (mutt_strncmp ("382", buf, 3))
-+      {
-+	nserv->use_tls = 0;
-+	mutt_error ("STARTTLS: %s", buf);
-+	mutt_sleep (2);
-+      }
-+      else if (mutt_ssl_starttls (conn))
-+      {
-+	nserv->use_tls = 0;
-+	nserv->status = NNTP_NONE;
-+	mutt_socket_close (nserv->conn);
-+	mutt_error _("Could not negotiate TLS connection");
-+	mutt_sleep (2);
-+	return -1;
-+      }
-+      else
-+      {
-+	/* recheck capabilities after STARTTLS */
-+	cap = nntp_capabilities (nserv);
-+	if (cap < 0)
-+	  return -1;
-+      }
-+    }
-+  }
-+#endif
++/* returns all unhidden tags */
++char *nm_header_get_tags(HEADER *h)
++{
++	return h && h->data ? ((struct nm_hdrdata *) h->data)->tags : NULL;
++}
 +
-+  /* authentication required? */
-+  if (conn->account.flags & M_ACCT_USER)
-+  {
-+    if (!conn->account.user[0])
-+      auth = 0;
-+  }
-+  else
-+  {
-+    if (mutt_socket_write (conn, "STAT\r\n") < 0 ||
-+	mutt_socket_readln (buf, sizeof (buf), conn) < 0)
-+      return nntp_connect_error (nserv);
-+    if (mutt_strncmp ("480", buf, 3))
-+      auth = 0;
-+  }
++char *nm_header_get_tags_transformed(HEADER *h)
++{
++	return h && h->data ? ((struct nm_hdrdata *) h->data)->tags_transformed : NULL;
++}
 +
-+  /* authenticate */
-+  if (auth && nntp_auth (nserv) < 0)
-+      return -1;
++char *nm_header_get_tag_transformed(char *tag, HEADER *h)
++{
++	struct nm_hdrtag *tmp;
 +
-+  /* get final capabilities after authentication */
-+  if (nserv->hasCAPABILITIES && (auth || cap > 0))
-+  {
-+    cap = nntp_capabilities (nserv);
-+    if (cap < 0)
-+      return -1;
-+    if (cap > 0)
-+    {
-+      mutt_socket_close (conn);
-+      mutt_error _("Could not switch to reader mode.");
-+      mutt_sleep (2);
-+      return -1;
-+    }
-+  }
++	if (!h || !h->data)
++		return NULL;
 +
-+  /* attempt features */
-+  if (nntp_attempt_features (nserv) < 0)
-+    return -1;
++	for (tmp = ((struct nm_hdrdata *) h->data)->tag_list;
++	     tmp != NULL;
++	     tmp = tmp->next)
++	{
++		if (strcmp(tag, tmp->tag) == 0)
++			return tmp->transformed;
++	}
 +
-+  nserv->status = NNTP_OK;
-+  return 0;
++	return NULL;
 +}
 +
-+/* Send data from buffer and receive answer to same buffer */
-+static int nntp_query (NNTP_DATA *nntp_data, char *line, size_t linelen)
++int nm_header_get_magic(HEADER *h)
 +{
-+  NNTP_SERVER *nserv = nntp_data->nserv;
-+  char buf[LONG_STRING];
++	return h && h->data ? ((struct nm_hdrdata *) h->data)->magic : 0;
++}
 +
-+  if (nserv->status == NNTP_BYE)
-+    return -1;
++/*
++ * Returns notmuch message Id.
++ */
++static char *nm_header_get_id(HEADER *h)
++{
++	return h && h->data ? ((struct nm_hdrdata *) h->data)->virtual_id : NULL;
++}
 +
-+  while (1)
-+  {
-+    if (nserv->status == NNTP_OK)
-+    {
-+      int rc = 0;
 +
-+      if (*line)
-+	rc = mutt_socket_write (nserv->conn, line);
-+      else if (nntp_data->group)
-+      {
-+	snprintf (buf, sizeof (buf), "GROUP %s\r\n", nntp_data->group);
-+	rc = mutt_socket_write (nserv->conn, buf);
-+      }
-+      if (rc >= 0)
-+	rc = mutt_socket_readln (buf, sizeof (buf), nserv->conn);
-+      if (rc >= 0)
-+	break;
-+    }
++char *nm_header_get_fullpath(HEADER *h, char *buf, size_t bufsz)
++{
++	snprintf(buf, bufsz, "%s/%s", nm_header_get_folder(h), h->path);
++	/*dprint(2, (debugfile, "nm: returns fullpath '%s'\n", buf));*/
++	return buf;
++}
 +
-+    /* reconnect */
-+    while (1)
-+    {
-+      nserv->status = NNTP_NONE;
-+      if (nntp_open_connection (nserv) == 0)
-+	break;
 +
-+      snprintf (buf, sizeof (buf), _("Connection to %s lost. Reconnect?"),
-+		nserv->conn->account.host);
-+      if (mutt_yesorno (buf, M_YES) != M_YES)
-+      {
-+	nserv->status = NNTP_BYE;
-+	return -1;
-+      }
-+    }
++static struct nm_ctxdata *get_ctxdata(CONTEXT *ctx)
++{
++	if (ctx && ctx->magic == M_NOTMUCH)
++		return ctx->data;
 +
-+    /* select newsgroup after reconnection */
-+    if (nntp_data->group)
-+    {
-+      snprintf (buf, sizeof (buf), "GROUP %s\r\n", nntp_data->group);
-+      if (mutt_socket_write (nserv->conn, buf) < 0 ||
-+	  mutt_socket_readln (buf, sizeof (buf), nserv->conn) < 0)
-+	return nntp_connect_error (nserv);
-+    }
-+    if (!*line)
-+      break;
-+  }
++	return NULL;
++}
 +
-+  strfcpy (line, buf, linelen);
-+  return 0;
++static int string_to_guery_type(const char *str)
++{
++	if (!str)
++		str = NotmuchQueryType;		/* user's default */
++	if (!str)
++		return NM_QUERY_TYPE_MESGS;	/* hardcoded default */
++
++	if (strcmp(str, "threads") == 0)
++		return NM_QUERY_TYPE_THREADS;
++	else if (strcmp(str, "messages") == 0)
++		return NM_QUERY_TYPE_MESGS;
++
++	mutt_error (_("failed to parse notmuch query type: %s"), str);
++	return NM_QUERY_TYPE_MESGS;
 +}
 +
-+/* This function calls funct(*line, *data) for each received line,
-+ * funct(NULL, *data) if rewind(*data) needs, exits when fail or done:
-+ *  0 - success
-+ *  1 - bad response (answer in query buffer)
-+ * -1 - conection lost
-+ * -2 - error in funct(*line, *data) */
-+static int nntp_fetch_lines (NNTP_DATA *nntp_data, char *query, size_t qlen,
-+			char *msg, int (*funct) (char *, void *), void *data)
++static char *get_query_string(struct nm_ctxdata *data)
 +{
-+  int done = FALSE;
-+  int rc;
-+
-+  while (!done)
-+  {
-+    char buf[LONG_STRING];
-+    char *line;
-+    unsigned int lines = 0;
-+    size_t off = 0;
-+    progress_t progress;
++	struct uri_tag *item;
 +
-+    if (msg)
-+      mutt_progress_init (&progress, msg, M_PROGRESS_MSG, ReadInc, -1);
++	if (!data)
++		return NULL;
++	if (data->db_query)
++		return data->db_query;
 +
-+    strfcpy (buf, query, sizeof (buf));
-+    if (nntp_query (nntp_data, buf, sizeof (buf)) < 0)
-+      return -1;
-+    if (buf[0] != '2')
-+    {
-+      strfcpy (query, buf, qlen);
-+      return 1;
-+    }
++	for (item = data->query_items; item; item = item->next) {
++		if (!item->value || !item->name)
++			continue;
 +
-+    line = safe_malloc (sizeof (buf));
-+    rc = 0;
++		if (strcmp(item->name, "limit") == 0) {
++			if (mutt_atoi(item->value, &data->db_limit))
++				mutt_error (_("failed to parse notmuch limit: %s"), item->value);
 +
-+    while (1)
-+    {
-+      char *p;
-+      int chunk = mutt_socket_readln_d (buf, sizeof (buf),
-+		  nntp_data->nserv->conn, M_SOCK_LOG_HDR);
-+      if (chunk < 0)
-+      {
-+	nntp_data->nserv->status = NNTP_NONE;
-+	break;
-+      }
++		} else if (strcmp(item->name, "type") == 0)
++			data->query_type = string_to_guery_type(item->value);
 +
-+      p = buf;
-+      if (!off && buf[0] == '.')
-+      {
-+	if (buf[1] == '\0')
-+	{
-+	  done = TRUE;
-+	  break;
++		else if (strcmp(item->name, "query") == 0)
++			data->db_query = safe_strdup(item->value);
 +	}
-+	if (buf[1] == '.')
-+	  p++;
-+      }
-+
-+      strfcpy (line + off, p, sizeof (buf));
 +
-+      if (chunk >= sizeof (buf))
-+	off += strlen (p);
-+      else
-+      {
-+	if (msg)
-+	  mutt_progress_update (&progress, ++lines, -1);
++	if (!data->query_type)
++		data->query_type = string_to_guery_type(NULL);
 +
-+	if (rc == 0 && funct (line, data) < 0)
-+	  rc = -2;
-+	off = 0;
-+      }
++	dprint(2, (debugfile, "nm: query '%s'\n", data->db_query));
 +
-+      safe_realloc (&line, off + sizeof (buf));
-+    }
-+    FREE (&line);
-+    funct (NULL, data);
-+  }
-+  return rc;
++	return data->db_query;
 +}
 +
-+/* Parse newsgroup description */
-+static int fetch_description (char *line, void *data)
++static int get_limit(struct nm_ctxdata *data)
 +{
-+  NNTP_SERVER *nserv = data;
-+  NNTP_DATA *nntp_data;
-+  char *desc;
-+
-+  if (!line)
-+    return 0;
-+
-+  desc = strpbrk (line, " \t");
-+  if (desc)
-+  {
-+    *desc++ = '\0';
-+    desc += strspn (desc, " \t");
-+  }
-+  else
-+    desc = strchr (line, '\0');
++	return data ? data->db_limit : 0;
++}
 +
-+  nntp_data = hash_find (nserv->groups_hash, line);
-+  if (nntp_data && mutt_strcmp (desc, nntp_data->desc))
-+  {
-+    mutt_str_replace (&nntp_data->desc, desc);
-+    dprint (2, (debugfile, "group: %s, desc: %s\n", line, desc));
-+  }
-+  return 0;
++static int get_query_type(struct nm_ctxdata *data)
++{
++	return (data && data->query_type) ? data->query_type : string_to_guery_type(NULL);
 +}
 +
-+/* Fetch newsgroups descriptions.
-+ * Returns the same code as nntp_fetch_lines() */
-+static int get_description (NNTP_DATA *nntp_data, char *wildmat, char *msg)
++static const char *get_db_filename(struct nm_ctxdata *data)
 +{
-+  NNTP_SERVER *nserv;
-+  char buf[STRING];
-+  char *cmd;
-+  int rc;
++	char *db_filename;
 +
-+  /* get newsgroup description, if possible */
-+  nserv = nntp_data->nserv;
-+  if (!wildmat)
-+    wildmat = nntp_data->group;
-+  if (nserv->hasLIST_NEWSGROUPS)
-+    cmd = "LIST NEWSGROUPS";
-+  else if (nserv->hasXGTITLE)
-+    cmd = "XGTITLE";
-+  else
-+    return 0;
++	if (!data)
++		return NULL;
 +
-+  snprintf (buf, sizeof (buf), "%s %s\r\n", cmd, wildmat);
-+  rc = nntp_fetch_lines (nntp_data, buf, sizeof (buf), msg,
-+			 fetch_description, nserv);
-+  if (rc > 0)
-+  {
-+    mutt_error ("%s: %s", cmd, buf);
-+    mutt_sleep (2);
-+  }
-+  return rc;
++	db_filename = data->db_filename ? data->db_filename : NotmuchDefaultUri;
++	if (!db_filename)
++		db_filename = Maildir;
++	if (!db_filename)
++		return NULL;
++	if (strncmp(db_filename, "notmuch://", 10) == 0)
++		db_filename += 10;
++
++	dprint(2, (debugfile, "nm: db filename '%s'\n", db_filename));
++	return db_filename;
 +}
 +
-+/* Update read flag and set article number if empty */
-+static void nntp_parse_xref (CONTEXT *ctx, HEADER *hdr)
++static notmuch_database_t *do_database_open(const char *filename,
++					    int writable, int verbose)
 +{
-+  NNTP_DATA *nntp_data = ctx->data;
-+  char *buf, *p;
-+
-+  buf = p = safe_strdup (hdr->env->xref);
-+  while (p)
-+  {
-+    char *grp, *colon;
-+    anum_t anum;
-+
-+    /* skip to next word */
-+    p += strspn (p, " \t");
-+    grp = p;
++	notmuch_database_t *db = NULL;
++	unsigned int ct = 0;
++	notmuch_status_t st = NOTMUCH_STATUS_SUCCESS;
 +
-+    /* skip to end of word */
-+    p = strpbrk (p, " \t");
-+    if (p)
-+      *p++ = '\0';
++	dprint(1, (debugfile, "nm: db open '%s' %s (timeout %d)\n", filename,
++			writable ? "[WRITE]" : "[READ]", NotmuchOpenTimeout));
++	do {
++#ifdef NOTMUCH_API_3
++		st = notmuch_database_open(filename,
++					writable ? NOTMUCH_DATABASE_MODE_READ_WRITE :
++					NOTMUCH_DATABASE_MODE_READ_ONLY, &db);
++#else
++		db = notmuch_database_open(filename,
++					writable ? NOTMUCH_DATABASE_MODE_READ_WRITE :
++					NOTMUCH_DATABASE_MODE_READ_ONLY);
++#endif
++		if (db || !NotmuchOpenTimeout || ct / 2 > NotmuchOpenTimeout)
++			break;
 +
-+    /* find colon */
-+    colon = strchr (grp, ':');
-+    if (!colon)
-+      continue;
-+    *colon++ = '\0';
-+    if (sscanf (colon, ANUM, &anum) != 1)
-+      continue;
++		if (verbose && ct && ct % 2 == 0)
++			mutt_error(_("Waiting for notmuch DB... (%d sec)"), ct / 2);
++		usleep(500000);
++		ct++;
++	} while (1);
 +
-+    nntp_article_status (ctx, hdr, grp, anum);
-+    if (hdr && !NHDR (hdr)->article_num && !mutt_strcmp (nntp_data->group, grp))
-+      NHDR (hdr)->article_num = anum;
-+  }
-+  FREE (&buf);
++	if (verbose) {
++		if (!db)
++			mutt_error (_("Cannot open notmuch database: %s: %s"),
++				    filename,
++				    st ? notmuch_status_to_string(st) :
++					 _("unknown reason"));
++		else if (ct > 1)
++			mutt_clear_error();
++	}
++	return db;
 +}
 +
-+/* Write line to temporarily file */
-+static int fetch_tempfile (char *line, void *data)
++static notmuch_database_t *get_db(struct nm_ctxdata *data, int writable)
 +{
-+  FILE *fp = data;
++	if (!data)
++	       return NULL;
++	if (!data->db) {
++		const char *db_filename = get_db_filename(data);
 +
-+  if (!line)
-+    rewind (fp);
-+  else if (fputs (line, fp) == EOF || fputc ('\n', fp) == EOF)
-+    return -1;
-+  return 0;
++		if (db_filename)
++			data->db = do_database_open(db_filename, writable, TRUE);
++	}
++	return data->db;
 +}
 +
-+typedef struct
++static int release_db(struct nm_ctxdata *data)
 +{
-+  CONTEXT *ctx;
-+  anum_t first;
-+  anum_t last;
-+  int restore;
-+  unsigned char *messages;
-+  progress_t progress;
-+#ifdef USE_HCACHE
-+  header_cache_t *hc;
++	if (data && data->db) {
++		dprint(1, (debugfile, "nm: db close\n"));
++#ifdef NOTMUCH_API_3
++		notmuch_database_destroy(data->db);
++#else
++		notmuch_database_close(data->db);
 +#endif
-+} FETCH_CTX;
++		data->db = NULL;
++		data->longrun = 0;
++		return 0;
++	}
 +
-+/* Parse article number */
-+static int fetch_numbers (char *line, void *data)
++	return -1;
++}
++
++/* returns:	< 0 = error
++ *		  1 = new transaction started
++ *		  0 = already within transaction
++ */
++static int db_trans_begin(struct nm_ctxdata *data)
 +{
-+  FETCH_CTX *fc = data;
-+  anum_t anum;
++	if (!data || !data->db)
++		return -1;
 +
-+  if (!line)
-+    return 0;
-+  if (sscanf (line, ANUM, &anum) != 1)
-+    return 0;
-+  if (anum < fc->first || anum > fc->last)
-+    return 0;
-+  fc->messages[anum - fc->first] = 1;
-+  return 0;
++	if (!data->trans) {
++		dprint(2, (debugfile, "nm: db trans start\n"));
++		if (notmuch_database_begin_atomic(data->db))
++			return -1;
++		data->trans = 1;
++		return 1;
++	}
++
++	return 0;
 +}
 +
-+/* Parse overview line */
-+static int parse_overview_line (char *line, void *data)
++static int db_trans_end(struct nm_ctxdata *data)
 +{
-+  FETCH_CTX *fc = data;
-+  CONTEXT *ctx = fc->ctx;
-+  NNTP_DATA *nntp_data = ctx->data;
-+  HEADER *hdr;
-+  FILE *fp;
-+  char tempfile[_POSIX_PATH_MAX];
-+  char *header, *field;
-+  int save = 1;
-+  anum_t anum;
++	if (!data || !data->db)
++		return -1;
 +
-+  if (!line)
-+    return 0;
++	if (data->trans) {
++		dprint(2, (debugfile, "nm: db trans end\n"));
++		data->trans = 0;
++		if (notmuch_database_end_atomic(data->db))
++			return -1;
++	}
 +
-+  /* parse article number */
-+  field = strchr (line, '\t');
-+  if (field)
-+    *field++ = '\0';
-+  if (sscanf (line, ANUM, &anum) != 1)
-+    return 0;
-+  dprint (2, (debugfile, "parse_overview_line: " ANUM "\n", anum));
++	return 0;
++}
 +
-+  /* out of bounds */
-+  if (anum < fc->first || anum > fc->last)
-+    return 0;
++void nm_longrun_init(CONTEXT *ctx, int writable)
++{
++	struct nm_ctxdata *data = get_ctxdata(ctx);
 +
-+  /* not in LISTGROUP */
-+  if (!fc->messages[anum - fc->first])
-+  {
-+    /* progress */
-+    if (!ctx->quiet)
-+      mutt_progress_update (&fc->progress, anum - fc->first + 1, -1);
-+    return 0;
-+  }
++	if (data && get_db(data, writable)) {
++		data->longrun = 1;
++		dprint(2, (debugfile, "nm: long run initialized\n"));
++	}
++}
 +
-+  /* convert overview line to header */
-+  mutt_mktemp (tempfile, sizeof (tempfile));
-+  fp = safe_fopen (tempfile, "w+");
-+  if (!fp)
-+    return -1;
++void nm_longrun_done(CONTEXT *ctx)
++{
++	struct nm_ctxdata *data = get_ctxdata(ctx);
 +
-+  header = nntp_data->nserv->overview_fmt;
-+  while (field)
-+  {
-+    char *b = field;
++	if (data && release_db(data) == 0)
++		dprint(2, (debugfile, "nm: long run deinitialized\n"));
++}
 +
-+    if (*header)
-+    {
-+      if (strstr (header, ":full") == NULL && fputs (header, fp) == EOF)
-+      {
-+	fclose (fp);
-+	unlink (tempfile);
-+	return -1;
-+      }
-+      header = strchr (header, '\0') + 1;
-+    }
++static int is_longrun(struct nm_ctxdata *data)
++{
++	return data && data->longrun;
++}
 +
-+    field = strchr (field, '\t');
-+    if (field)
-+      *field++ = '\0';
-+    if (fputs (b, fp) == EOF || fputc ('\n', fp) == EOF)
-+    {
-+      fclose (fp);
-+      unlink (tempfile);
-+      return -1;
-+    }
-+  }
-+  rewind (fp);
++void nm_debug_check(CONTEXT *ctx)
++{
++	struct nm_ctxdata *data = get_ctxdata(ctx);
 +
-+  /* allocate memory for headers */
-+  if (ctx->msgcount >= ctx->hdrmax)
-+    mx_alloc_memory (ctx);
++	if (!data)
++		return;
 +
-+  /* parse header */
-+  hdr = ctx->hdrs[ctx->msgcount] = mutt_new_header ();
-+  hdr->env = mutt_read_rfc822_header (fp, hdr, 0, 0);
-+  hdr->env->newsgroups = safe_strdup (nntp_data->group);
-+  hdr->received = hdr->date_sent;
-+  fclose (fp);
-+  unlink (tempfile);
++	if (data->db) {
++		dprint(1, (debugfile, "nm: ERROR: db is open, closing\n"));
++		release_db(data);
++	}
++}
 +
-+#ifdef USE_HCACHE
-+  if (fc->hc)
-+  {
-+    void *hdata;
-+    char buf[16];
++static int get_database_mtime(struct nm_ctxdata *data, time_t *mtime)
++{
++	char path[_POSIX_PATH_MAX];
++	struct stat st;
 +
-+    /* try to replace with header from cache */
-+    snprintf (buf, sizeof (buf), "%d", anum);
-+    hdata = mutt_hcache_fetch (fc->hc, buf, strlen);
-+    if (hdata)
-+    {
-+      dprint (2, (debugfile,
-+		  "parse_overview_line: mutt_hcache_fetch %s\n", buf));
-+      mutt_free_header (&hdr);
-+      ctx->hdrs[ctx->msgcount] =
-+      hdr = mutt_hcache_restore (hdata, NULL);
-+      FREE (&hdata);
-+      hdr->data = 0;
-+      hdr->read = 0;
-+      hdr->old = 0;
++	if (!data)
++	       return -1;
 +
-+      /* skip header marked as deleted in cache */
-+      if (hdr->deleted && !fc->restore)
-+      {
-+	if (nntp_data->bcache)
-+	{
-+	  dprint (2, (debugfile,
-+		      "parse_overview_line: mutt_bcache_del %s\n", buf));
-+	  mutt_bcache_del (nntp_data->bcache, buf);
-+	}
-+	save = 0;
-+      }
-+    }
++	snprintf(path, sizeof(path), "%s/.notmuch/xapian", get_db_filename(data));
++	dprint(2, (debugfile, "nm: checking '%s' mtime\n", path));
 +
-+    /* not chached yet, store header */
-+    else
-+    {
-+      dprint (2, (debugfile,
-+		  "parse_overview_line: mutt_hcache_store %s\n", buf));
-+      mutt_hcache_store (fc->hc, buf, hdr, 0, strlen, M_GENERATE_UIDVALIDITY);
-+    }
-+  }
-+#endif
++	if (stat(path, &st))
++		return -1;
 +
-+  if (save)
-+  {
-+    hdr->index = ctx->msgcount++;
-+    hdr->read = 0;
-+    hdr->old = 0;
-+    hdr->deleted = 0;
-+    hdr->data = safe_calloc (1, sizeof (NNTP_HEADER_DATA));
-+    NHDR (hdr)->article_num = anum;
-+    if (fc->restore)
-+      hdr->changed = 1;
-+    else
-+    {
-+      nntp_article_status (ctx, hdr, NULL, anum);
-+      if (!hdr->read)
-+	nntp_parse_xref (ctx, hdr);
-+    }
-+    if (anum > nntp_data->lastLoaded)
-+      nntp_data->lastLoaded = anum;
-+  }
-+  else
-+    mutt_free_header (&hdr);
++	if (mtime)
++		*mtime = st.st_mtime;
 +
-+  /* progress */
-+  if (!ctx->quiet)
-+    mutt_progress_update (&fc->progress, anum - fc->first + 1, -1);
-+  return 0;
++	return 0;
 +}
 +
-+/* Fetch headers */
-+static int nntp_fetch_headers (CONTEXT *ctx, void *hc,
-+			       anum_t first, anum_t last, int restore)
++static void apply_exclude_tags(notmuch_query_t *query)
 +{
-+  NNTP_DATA *nntp_data = ctx->data;
-+  FETCH_CTX fc;
-+  HEADER *hdr;
-+  char buf[HUGE_STRING];
-+  int rc = 0;
-+  int oldmsgcount = ctx->msgcount;
-+  anum_t current;
-+  anum_t first_over = first;
-+#ifdef USE_HCACHE
-+  void *hdata;
-+#endif
-+
-+  /* if empty group or nothing to do */
-+  if (!last || first > last)
-+    return 0;
++	char *buf, *p, *end = NULL, *tag = NULL;
 +
-+  /* init fetch context */
-+  fc.ctx = ctx;
-+  fc.first = first;
-+  fc.last = last;
-+  fc.restore = restore;
-+  fc.messages = safe_calloc (last - first + 1, sizeof (unsigned char));
-+#ifdef USE_HCACHE
-+  fc.hc = hc;
-+#endif
++	if (!NotmuchExcludeTags || !*NotmuchExcludeTags)
++		return;
++	buf = safe_strdup(NotmuchExcludeTags);
 +
-+  /* fetch list of articles */
-+  if (option (OPTLISTGROUP) && nntp_data->nserv->hasLISTGROUP &&
-+      !nntp_data->deleted)
-+  {
-+    if (!ctx->quiet)
-+      mutt_message _("Fetching list of articles...");
-+    if (nntp_data->nserv->hasLISTGROUPrange)
-+      snprintf (buf, sizeof (buf), "LISTGROUP %s %d-%d\r\n", nntp_data->group,
-+		first, last);
-+    else
-+      snprintf (buf, sizeof (buf), "LISTGROUP %s\r\n", nntp_data->group);
-+    rc = nntp_fetch_lines (nntp_data, buf, sizeof (buf), NULL,
-+			   fetch_numbers, &fc);
-+    if (rc > 0)
-+    {
-+      mutt_error ("LISTGROUP: %s", buf);
-+      mutt_sleep (2);
-+    }
-+    if (rc == 0)
-+    {
-+      for (current = first; current <= last && rc == 0; current++)
-+      {
-+	if (fc.messages[current - first])
-+	  continue;
++	for (p = buf; p && *p; p++) {
++		if (!tag && isspace(*p))
++			continue;
++		if (!tag)
++			tag = p;		/* begin of the tag */
++		if (*p == ',' || *p == ' ')
++			end = p;		/* terminate the tag */
++		else if (*(p + 1) == '\0')
++			end = p + 1;		/* end of optstr */
++		if (!tag || !end)
++			continue;
++		if (tag >= end)
++			break;
++		*end = '\0';
 +
-+	snprintf (buf, sizeof (buf), "%d", current);
-+	if (nntp_data->bcache)
-+	{
-+	  dprint (2, (debugfile,
-+		      "nntp_fetch_headers: mutt_bcache_del %s\n", buf));
-+	  mutt_bcache_del (nntp_data->bcache, buf);
++		dprint(2, (debugfile, "nm: query exclude tag '%s'\n", tag));
++		notmuch_query_add_tag_exclude(query, tag);
++		end = tag = NULL;
 +	}
++	notmuch_query_set_omit_excluded(query, 1);
++	FREE(&buf);
++}
 +
-+#ifdef USE_HCACHE
-+	if (fc.hc)
-+	{
-+	  dprint (2, (debugfile,
-+		      "nntp_fetch_headers: mutt_hcache_delete %s\n", buf));
-+	  mutt_hcache_delete (fc.hc, buf, strlen);
-+	}
-+#endif
-+      }
-+    }
-+  }
-+  else
-+    for (current = first; current <= last; current++)
-+      fc.messages[current - first] = 1;
++static notmuch_query_t *get_query(struct nm_ctxdata *data, int writable)
++{
++	notmuch_database_t *db = NULL;
++	notmuch_query_t *q = NULL;
++	const char *str;
 +
-+  /* fetching header from cache or server, or fallback to fetch overview */
-+  if (!ctx->quiet)
-+    mutt_progress_init (&fc.progress, _("Fetching message headers..."),
-+			M_PROGRESS_MSG, ReadInc, last - first + 1);
-+  for (current = first; current <= last && rc == 0; current++)
-+  {
-+    if (!ctx->quiet)
-+      mutt_progress_update (&fc.progress, current - first + 1, -1);
++	if (!data)
++		return NULL;
 +
-+#ifdef USE_HCACHE
-+    snprintf (buf, sizeof (buf), "%d", current);
-+#endif
++	db = get_db(data, writable);
++	str = get_query_string(data);
 +
-+    /* delete header from cache that does not exist on server */
-+    if (!fc.messages[current - first])
-+      continue;
++	if (!db || !str)
++		goto err;
 +
-+    /* allocate memory for headers */
-+    if (ctx->msgcount >= ctx->hdrmax)
-+      mx_alloc_memory (ctx);
++	q = notmuch_query_create(db, str);
++	if (!q)
++		goto err;
 +
-+#ifdef USE_HCACHE
-+    /* try to fetch header from cache */
-+    hdata = mutt_hcache_fetch (fc.hc, buf, strlen);
-+    if (hdata)
-+    {
-+      dprint (2, (debugfile,
-+		  "nntp_fetch_headers: mutt_hcache_fetch %s\n", buf));
-+      ctx->hdrs[ctx->msgcount] =
-+      hdr = mutt_hcache_restore (hdata, NULL);
-+      FREE (&hdata);
-+      hdr->data = 0;
++	apply_exclude_tags(q);
++	notmuch_query_set_sort(q, NOTMUCH_SORT_NEWEST_FIRST);
++	dprint(2, (debugfile, "nm: query successfully initialized\n"));
++	return q;
++err:
++	if (!is_longrun(data))
++		release_db(data);
++	return NULL;
++}
 +
-+      /* skip header marked as deleted in cache */
-+      if (hdr->deleted && !restore)
-+      {
-+	mutt_free_header (&hdr);
-+	if (nntp_data->bcache)
-+	{
-+	  dprint (2, (debugfile,
-+		      "nntp_fetch_headers: mutt_bcache_del %s\n", buf));
-+	  mutt_bcache_del (nntp_data->bcache, buf);
-+	}
-+	continue;
-+      }
++static void append_str_item(char **str, const char *item, int sep)
++{
++	char *p;
++	size_t sz = strlen(item);
++	size_t ssz = *str ? strlen(*str) : 0;
 +
-+      hdr->read = 0;
-+      hdr->old = 0;
-+    }
-+    else
-+#endif
++	safe_realloc(str, ssz + (ssz && sep ? 1 : 0) + sz + 1);
++	p = *str + ssz;
++	if (sep && ssz)
++	    *p++ = sep;
++	memcpy(p, item, sz + 1);
++}
 +
-+    /* don't try to fetch header from removed newsgroup */
-+    if (nntp_data->deleted)
-+      continue;
++static int update_header_tags(HEADER *h, notmuch_message_t *msg)
++{
++	struct nm_hdrdata *data = h->data;
++	notmuch_tags_t *tags;
++	char *tstr = NULL, *ttstr = NULL;
++	struct nm_hdrtag *tag_list = NULL, *tmp;
 +
-+    /* fallback to fetch overview */
-+    else if (nntp_data->nserv->hasOVER || nntp_data->nserv->hasXOVER)
-+      if (option (OPTLISTGROUP) && nntp_data->nserv->hasLISTGROUP)
-+	break;
-+      else
-+	continue;
++	dprint(2, (debugfile, "nm: tags update requested (%s)\n", data->virtual_id));
 +
-+    /* fetch header from server */
-+    else
-+    {
-+      FILE *fp;
-+      char tempfile[_POSIX_PATH_MAX];
++	for (tags = notmuch_message_get_tags(msg);
++	     tags && notmuch_tags_valid(tags);
++	     notmuch_tags_move_to_next(tags)) {
 +
-+      mutt_mktemp (tempfile, sizeof (tempfile));
-+      fp = safe_fopen (tempfile, "w+");
-+      if (!fp)
-+      {
-+	mutt_perror (tempfile);
-+	mutt_sleep (2);
-+	unlink (tempfile);
-+	rc = -1;
-+	break;
-+      }
++		const char *t = notmuch_tags_get(tags);
++		const char *tt = NULL;
 +
-+      snprintf (buf, sizeof (buf), "HEAD %d\r\n", current);
-+      rc = nntp_fetch_lines (nntp_data, buf, sizeof (buf), NULL,
-+			     fetch_tempfile, fp);
-+      if (rc)
-+      {
-+	fclose (fp);
-+	unlink (tempfile);
-+	if (rc < 0)
-+	  break;
++		if (!t || !*t)
++			continue;
 +
-+	/* invalid response */
-+	if (mutt_strncmp ("423", buf, 3))
-+	{
-+	  mutt_error ("HEAD: %s", buf);
-+	  mutt_sleep (2);
-+	  break;
-+	}
++		tt = hash_find(TagTransforms, t);
++		if (!tt)
++			tt = t;
 +
-+	/* no such article */
-+	if (nntp_data->bcache)
-+	{
-+	  snprintf (buf, sizeof (buf), "%d", current);
-+	  dprint (2, (debugfile,
-+		      "nntp_fetch_headers: mutt_bcache_del %s\n", buf));
-+	  mutt_bcache_del (nntp_data->bcache, buf);
-+	}
-+	rc = 0;
-+	continue;
-+      }
++		/* tags list contains all tags */
++		tmp = safe_calloc(1, sizeof(*tmp));
++		tmp->tag = safe_strdup(t);
++		tmp->transformed = safe_strdup(tt);
++		tmp->next = tag_list;
++		tag_list = tmp;
 +
-+      /* parse header */
-+      hdr = ctx->hdrs[ctx->msgcount] = mutt_new_header ();
-+      hdr->env = mutt_read_rfc822_header (fp, hdr, 0, 0);
-+      hdr->received = hdr->date_sent;
-+      fclose (fp);
-+      unlink (tempfile);
-+    }
++		/* filter out hidden tags */
++		if (NotmuchHiddenTags) {
++			char *p = strstr(NotmuchHiddenTags, t);
++			size_t xsz = p ? strlen(t) : 0;
 +
-+    /* save header in context */
-+    hdr->index = ctx->msgcount++;
-+    hdr->read = 0;
-+    hdr->old = 0;
-+    hdr->deleted = 0;
-+    hdr->data = safe_calloc (1, sizeof (NNTP_HEADER_DATA));
-+    NHDR (hdr)->article_num = current;
-+    if (restore)
-+      hdr->changed = 1;
-+    else
-+    {
-+      nntp_article_status (ctx, hdr, NULL, NHDR (hdr)->article_num);
-+      if (!hdr->read)
-+	nntp_parse_xref (ctx, hdr);
-+    }
-+    if (current > nntp_data->lastLoaded)
-+      nntp_data->lastLoaded = current;
-+    first_over = current + 1;
-+  }
++			if (p && (p == NotmuchHiddenTags
++				  || *(p - 1) == ','
++				  || *(p - 1) == ' ')
++			    && (*(p + xsz) == '\0'
++				  || *(p + xsz) == ','
++				  || *(p + xsz) == ' '))
++				continue;
++		}
++
++		/* expand the transformed tag string */
++		append_str_item(&ttstr, tt, ' ');
 +
-+  if (!option (OPTLISTGROUP) || !nntp_data->nserv->hasLISTGROUP)
-+    current = first_over;
++		/* expand the un-transformed tag string */
++		append_str_item(&tstr, t, ' ');
++	}
 +
-+  /* fetch overview information */
-+  if (current <= last && rc == 0 && !nntp_data->deleted) {
-+    char *cmd = nntp_data->nserv->hasOVER ? "OVER" : "XOVER";
-+    snprintf (buf, sizeof (buf), "%s %d-%d\r\n", cmd, current, last);
-+    rc = nntp_fetch_lines (nntp_data, buf, sizeof (buf), NULL,
-+	 parse_overview_line, &fc);
-+    if (rc > 0)
-+    {
-+      mutt_error ("%s: %s", cmd, buf);
-+      mutt_sleep (2);
-+    }
-+  }
++	free_tag_list(&data->tag_list);
++	data->tag_list = tag_list;
 +
-+  if (ctx->msgcount > oldmsgcount)
-+    mx_update_context (ctx, ctx->msgcount - oldmsgcount);
++	if (data->tags && tstr && strcmp(data->tags, tstr) == 0) {
++		FREE(&tstr);
++		FREE(&ttstr);
++		dprint(2, (debugfile, "nm: tags unchanged\n"));
++		return 1;
++	}
 +
-+  FREE (&fc.messages);
-+  if (rc != 0)
-+    return -1;
-+  mutt_clear_error ();
-+  return 0;
++	/* free old version */
++	FREE(&data->tags);
++	FREE(&data->tags_transformed);
++
++	/* new version */
++	data->tags = tstr;
++	dprint(2, (debugfile, "nm: new tags: '%s'\n", tstr));
++
++	data->tags_transformed = ttstr;
++	dprint(2, (debugfile, "nm: new tag transforms: '%s'\n", ttstr));
++
++	return 0;
 +}
 +
-+/* Open newsgroup */
-+int nntp_open_mailbox (CONTEXT *ctx)
++/*
++ * set/update HEADER->path and HEADER->data->path
++ */
++static int update_message_path(HEADER *h, const char *path)
 +{
-+  NNTP_SERVER *nserv;
-+  NNTP_DATA *nntp_data;
-+  char buf[HUGE_STRING];
-+  char server[LONG_STRING];
-+  char *group;
-+  int rc;
-+  void *hc = NULL;
-+  anum_t first, last, count = 0;
-+  ciss_url_t url;
-+
-+  strfcpy (buf, ctx->path, sizeof (buf));
-+  if (url_parse_ciss (&url, buf) < 0 || !url.path ||
-+     !(url.scheme == U_NNTP || url.scheme == U_NNTPS))
-+  {
-+    mutt_error (_("%s is an invalid newsgroup specification!"), ctx->path);
-+    mutt_sleep (2);
-+    return -1;
-+  }
++	struct nm_hdrdata *data = h->data;
++	char *p;
 +
-+  group = url.path;
-+  url.path = strchr (url.path, '\0');
-+  url_ciss_tostring (&url, server, sizeof (server), 0);
-+  nserv = nntp_select_server (server, 1);
-+  if (!nserv)
-+    return -1;
-+  CurrentNewsSrv = nserv;
++	dprint(2, (debugfile, "nm: path update requested path=%s, (%s)\n",
++				path, data->virtual_id));
 +
-+  /* find news group data structure */
-+  nntp_data = hash_find (nserv->groups_hash, group);
-+  if (!nntp_data)
-+  {
-+    nntp_newsrc_close (nserv);
-+    mutt_error (_("Newsgroup %s not found on the server."), group);
-+    mutt_sleep (2);
-+    return -1;
-+  }
++	p = strrchr(path, '/');
++	if (p && p - path > 3 &&
++	    (strncmp(p - 3, "cur", 3) == 0 ||
++	     strncmp(p - 3, "new", 3) == 0 ||
++	     strncmp(p - 3, "tmp", 3) == 0)) {
 +
-+  mutt_bit_unset (ctx->rights, M_ACL_INSERT);
-+  if (!nntp_data->newsrc_ent && !nntp_data->subscribed &&
-+      !option (OPTSAVEUNSUB))
-+    ctx->readonly = 1;
++		data->magic = M_MAILDIR;
 +
-+  /* select newsgroup */
-+  mutt_message (_("Selecting %s..."), group);
-+  buf[0] = '\0';
-+  if (nntp_query (nntp_data, buf, sizeof (buf)) < 0)
-+  {
-+    nntp_newsrc_close (nserv);
-+    return -1;
-+  }
++		FREE(&h->path);
++		FREE(&data->folder);
 +
-+  /* newsgroup not found, remove it */
-+  if (!mutt_strncmp ("411", buf, 3))
-+  {
-+    mutt_error (_("Newsgroup %s has been removed from the server."),
-+		nntp_data->group);
-+    if (!nntp_data->deleted)
-+    {
-+      nntp_data->deleted = 1;
-+      nntp_active_save_cache (nserv);
-+    }
-+    if (nntp_data->newsrc_ent && !nntp_data->subscribed &&
-+	!option (OPTSAVEUNSUB))
-+    {
-+      FREE (&nntp_data->newsrc_ent);
-+      nntp_data->newsrc_len = 0;
-+      nntp_delete_group_cache (nntp_data);
-+      nntp_newsrc_update (nserv);
-+    }
-+    mutt_sleep (2);
-+  }
++		p -= 3;				/* skip subfolder (e.g. "new") */
++		h->path = safe_strdup(p);
 +
-+  /* parse newsgroup info */
-+  else {
-+    if (sscanf (buf, "211 " ANUM " " ANUM " " ANUM, &count, &first, &last) != 3)
-+    {
-+      nntp_newsrc_close (nserv);
-+      mutt_error ("GROUP: %s", buf);
-+      mutt_sleep (2);
-+      return -1;
-+    }
-+    nntp_data->firstMessage = first;
-+    nntp_data->lastMessage = last;
-+    nntp_data->deleted = 0;
++		for (; p > path && *(p - 1) == '/'; p--);
 +
-+    /* get description if empty */
-+    if (option (OPTLOADDESC) && !nntp_data->desc)
-+    {
-+      if (get_description (nntp_data, NULL, NULL) < 0)
-+      {
-+	nntp_newsrc_close (nserv);
-+	return -1;
-+      }
-+      if (nntp_data->desc)
-+	nntp_active_save_cache (nserv);
-+    }
-+  }
++		data->folder = strndup(path, p - path);
 +
-+  time (&nserv->check_time);
-+  ctx->data = nntp_data;
-+  ctx->mx_close = nntp_fastclose_mailbox;
-+  if (!nntp_data->bcache && (nntp_data->newsrc_ent ||
-+      nntp_data->subscribed || option (OPTSAVEUNSUB)))
-+    nntp_data->bcache = mutt_bcache_open (&nserv->conn->account,
-+			nntp_data->group);
++		dprint(2, (debugfile, "nm: folder='%s', file='%s'\n", data->folder, h->path));
++		return 0;
++	}
 +
-+  /* strip off extra articles if adding context is greater than $nntp_context */
-+  first = nntp_data->firstMessage;
-+  if (NntpContext && nntp_data->lastMessage - first + 1 > NntpContext)
-+    first = nntp_data->lastMessage - NntpContext + 1;
-+  nntp_data->lastLoaded = first ? first - 1 : 0;
-+  count = nntp_data->firstMessage;
-+  nntp_data->firstMessage = first;
-+  nntp_bcache_update (nntp_data);
-+  nntp_data->firstMessage = count;
-+#ifdef USE_HCACHE
-+  hc = nntp_hcache_open (nntp_data);
-+  nntp_hcache_update (nntp_data, hc);
-+#endif
-+  if (!hc)
-+  {
-+    mutt_bit_unset (ctx->rights, M_ACL_WRITE);
-+    mutt_bit_unset (ctx->rights, M_ACL_DELETE);
-+  }
-+  nntp_newsrc_close (nserv);
-+  rc = nntp_fetch_headers (ctx, hc, first, nntp_data->lastMessage, 0);
-+#ifdef USE_HCACHE
-+  mutt_hcache_close (hc);
-+#endif
-+  if (rc < 0)
-+    return -1;
-+  nntp_data->lastLoaded = nntp_data->lastMessage;
-+  nserv->newsrc_modified = 0;
-+  return 0;
++	return 1;
 +}
 +
-+/* Fetch message */
-+int nntp_fetch_message (MESSAGE *msg, CONTEXT *ctx, int msgno)
++static char *get_folder_from_path(const char *path)
 +{
-+  NNTP_DATA *nntp_data = ctx->data;
-+  NNTP_ACACHE *acache;
-+  HEADER *hdr = ctx->hdrs[msgno];
-+  char buf[_POSIX_PATH_MAX];
-+  char article[16];
-+  char *fetch_msg = _("Fetching message...");
-+  int rc;
++	char *p = strrchr(path, '/');
 +
-+  /* try to get article from cache */
-+  acache = &nntp_data->acache[hdr->index % NNTP_ACACHE_LEN];
-+  if (acache->path)
-+  {
-+    if (acache->index == hdr->index)
-+    {
-+      msg->fp = fopen (acache->path, "r");
-+      if (msg->fp)
-+	return 0;
-+    }
-+    /* clear previous entry */
-+    else
-+    {
-+      unlink (acache->path);
-+      FREE (&acache->path);
-+    }
-+  }
-+  snprintf (article, sizeof (article), "%d", NHDR (hdr)->article_num);
-+  msg->fp = mutt_bcache_get (nntp_data->bcache, article);
-+  if (msg->fp)
-+  {
-+    if (NHDR (hdr)->parsed)
-+      return 0;
-+  }
-+  else
-+  {
-+    /* don't try to fetch article from removed newsgroup */
-+    if (nntp_data->deleted)
-+      return -1;
++	if (p && p - path > 3 &&
++	    (strncmp(p - 3, "cur", 3) == 0 ||
++	     strncmp(p - 3, "new", 3) == 0 ||
++	     strncmp(p - 3, "tmp", 3) == 0)) {
++
++		p -= 3;
++		for (; p > path && *(p - 1) == '/'; p--);
++
++		return strndup(path, p - path);
++	}
++
++	return NULL;
++}
++
++static void deinit_header(HEADER *h)
++{
++	if (h) {
++		free_hdrdata(h->data);
++		h->data = NULL;
++	}
++}
 +
-+    /* create new cache file */
-+    mutt_message (fetch_msg);
-+    msg->fp = mutt_bcache_put (nntp_data->bcache, article, 1);
-+    if (!msg->fp)
-+    {
-+      mutt_mktemp (buf, sizeof (buf));
-+      acache->path = safe_strdup (buf);
-+      acache->index = hdr->index;
-+      msg->fp = safe_fopen (acache->path, "w+");
-+      if (!msg->fp)
-+      {
-+	mutt_perror (acache->path);
-+	unlink (acache->path);
-+	FREE (&acache->path);
-+	return -1;
-+      }
-+    }
++/* converts notmuch message Id to mutt message <Id> */
++static char *nm2mutt_message_id(const char *id)
++{
++	size_t sz;
++	char *mid;
 +
-+    /* fetch message to cache file */
-+    snprintf (buf, sizeof (buf), "ARTICLE %s\r\n",
-+	      NHDR (hdr)->article_num ? article : hdr->env->message_id);
-+    rc = nntp_fetch_lines (nntp_data, buf, sizeof (buf), fetch_msg,
-+			   fetch_tempfile, msg->fp);
-+    if (rc)
-+    {
-+      safe_fclose (&msg->fp);
-+      if (acache->path)
-+      {
-+	unlink (acache->path);
-+	FREE (&acache->path);
-+      }
-+      if (rc > 0)
-+      {
-+	if (!mutt_strncmp (NHDR (hdr)->article_num ? "423" : "430", buf, 3))
-+	  mutt_error (_("Article %d not found on the server."),
-+		      NHDR (hdr)->article_num ? article : hdr->env->message_id);
-+	else
-+	  mutt_error ("ARTICLE: %s", buf);
-+      }
-+      return -1;
-+    }
++	if (!id)
++		return NULL;
++	sz = strlen(id) + 3;
++	mid = safe_malloc(sz);
 +
-+    if (!acache->path)
-+      mutt_bcache_commit (nntp_data->bcache, article);
-+  }
++	snprintf(mid, sz, "<%s>", id);
++	return mid;
++}
 +
-+  /* replace envelope with new one
-+   * hash elements must be updated because pointers will be changed */
-+  if (ctx->id_hash && hdr->env->message_id)
-+    hash_delete (ctx->id_hash, hdr->env->message_id, hdr, NULL);
-+  if (ctx->subj_hash && hdr->env->real_subj)
-+    hash_delete (ctx->subj_hash, hdr->env->real_subj, hdr, NULL);
++static int init_header(HEADER *h, const char *path, notmuch_message_t *msg)
++{
++	const char *id;
 +
-+  mutt_free_envelope (&hdr->env);
-+  hdr->env = mutt_read_rfc822_header (msg->fp, hdr, 0, 0);
++	if (h->data)
++		return 0;
 +
-+  if (ctx->id_hash && hdr->env->message_id)
-+    hash_insert (ctx->id_hash, hdr->env->message_id, hdr, 0);
-+  if (ctx->subj_hash && hdr->env->real_subj)
-+    hash_insert (ctx->subj_hash, hdr->env->real_subj, hdr, 1);
++	id = notmuch_message_get_message_id(msg);
 +
-+  /* fix content length */
-+  fseek (msg->fp, 0, SEEK_END);
-+  hdr->content->length = ftell (msg->fp) - hdr->content->offset;
++	h->data = safe_calloc(1, sizeof(struct nm_hdrdata));
++	h->free_cb = deinit_header;
 +
-+  /* this is called in mutt before the open which fetches the message,
-+   * which is probably wrong, but we just call it again here to handle
-+   * the problem instead of fixing it */
-+  NHDR (hdr)->parsed = 1;
-+  mutt_parse_mime_message (ctx, hdr);
++	/*
++	 * Notmuch ensures that message Id exists (if not notmuch Notmuch will
++	 * generate an ID), so it's more safe than use mutt HEADER->env->id
++	 */
++	((struct nm_hdrdata *) h->data)->virtual_id = safe_strdup( id );
 +
-+  /* these would normally be updated in mx_update_context(), but the
-+   * full headers aren't parsed with overview, so the information wasn't
-+   * available then */
-+  if (WithCrypto)
-+    hdr->security = crypt_query (hdr->content);
++	dprint(2, (debugfile, "nm: initialize header data: [hdr=%p, data=%p] (%s)\n",
++				h, h->data, id));
 +
-+  rewind (msg->fp);
-+  mutt_clear_error();
-+  return 0;
-+}
++	if (!h->env->message_id)
++		h->env->message_id = nm2mutt_message_id( id );
 +
-+/* Post article */
-+int nntp_post (const char *msg) {
-+  NNTP_DATA *nntp_data, nntp_tmp;
-+  FILE *fp;
-+  char buf[LONG_STRING];
-+  size_t len;
++	if (update_message_path(h, path))
++		return -1;
 +
-+  if (Context && Context->magic == M_NNTP)
-+    nntp_data = Context->data;
-+  else
-+  {
-+    CurrentNewsSrv = nntp_select_server (NewsServer, 0);
-+    if (!CurrentNewsSrv)
-+      return -1;
++	update_header_tags(h, msg);
 +
-+    nntp_data = &nntp_tmp;
-+    nntp_data->nserv = CurrentNewsSrv;
-+    nntp_data->group = NULL;
-+  }
++	return 0;
++}
 +
-+  fp = safe_fopen (msg, "r");
-+  if (!fp)
-+  {
-+    mutt_perror (msg);
-+    return -1;
-+  }
++/**
++static void debug_print_filenames(notmuch_message_t *msg)
++{
++	notmuch_filenames_t *ls;
++	const char *id = notmuch_message_get_message_id(msg);
 +
-+  strfcpy (buf, "POST\r\n", sizeof (buf));
-+  if (nntp_query (nntp_data, buf, sizeof (buf)) < 0)
-+    return -1;
-+  if (buf[0] != '3')
-+  {
-+    mutt_error (_("Can't post article: %s"), buf);
-+    return -1;
-+  }
++	for (ls = notmuch_message_get_filenames(msg);
++	     ls && notmuch_filenames_valid(ls);
++	     notmuch_filenames_move_to_next(ls)) {
 +
-+  buf[0] = '.';
-+  buf[1] = '\0';
-+  while (fgets (buf + 1, sizeof (buf) - 2, fp))
-+  {
-+    len = strlen (buf);
-+    if (buf[len - 1] == '\n')
-+    {
-+      buf[len - 1] = '\r';
-+      buf[len] = '\n';
-+      len++;
-+      buf[len] = '\0';
-+    }
-+    if (mutt_socket_write_d (nntp_data->nserv->conn,
-+	buf[1] == '.' ? buf : buf + 1, -1, M_SOCK_LOG_HDR) < 0)
-+      return nntp_connect_error (nntp_data->nserv);
-+  }
-+  fclose (fp);
++		dprint(2, (debugfile, "nm: %s: %s\n", id, notmuch_filenames_get(ls)));
++	}
++}
 +
-+  if ((buf[strlen (buf) - 1] != '\n' &&
-+      mutt_socket_write_d (nntp_data->nserv->conn, "\r\n", -1, M_SOCK_LOG_HDR) < 0) ||
-+      mutt_socket_write_d (nntp_data->nserv->conn, ".\r\n", -1, M_SOCK_LOG_HDR) < 0 ||
-+      mutt_socket_readln (buf, sizeof (buf), nntp_data->nserv->conn) < 0)
-+    return nntp_connect_error (nntp_data->nserv);
-+  if (buf[0] != '2')
-+  {
-+    mutt_error (_("Can't post article: %s"), buf);
-+    return -1;
-+  }
-+  return 0;
++static void debug_print_tags(notmuch_message_t *msg)
++{
++	notmuch_tags_t *tags;
++	const char *id = notmuch_message_get_message_id(msg);
++
++	for (tags = notmuch_message_get_tags(msg);
++	     tags && notmuch_tags_valid(tags);
++	     notmuch_tags_move_to_next(tags)) {
++
++		dprint(2, (debugfile, "nm: %s: %s\n", id, notmuch_tags_get(tags)));
++	}
 +}
++***/
 +
-+/* Save changes to .newsrc and cache */
-+int nntp_sync_mailbox (CONTEXT *ctx)
++static const char *get_message_last_filename(notmuch_message_t *msg)
 +{
-+  NNTP_DATA *nntp_data = ctx->data;
-+  int rc, i;
-+#ifdef USE_HCACHE
-+  header_cache_t *hc;
-+#endif
++	notmuch_filenames_t *ls;
++	const char *name = NULL;
 +
-+  /* check for new articles */
-+  nntp_data->nserv->check_time = 0;
-+  rc = nntp_check_mailbox (ctx, 1);
-+  if (rc)
-+    return rc;
++	for (ls = notmuch_message_get_filenames(msg);
++	     ls && notmuch_filenames_valid(ls);
++	     notmuch_filenames_move_to_next(ls)) {
 +
-+#ifdef USE_HCACHE
-+  nntp_data->lastCached = 0;
-+  hc = nntp_hcache_open (nntp_data);
-+#endif
++		name = notmuch_filenames_get(ls);
++	}
 +
-+  nntp_data->unread = ctx->unread;
-+  for (i = 0; i < ctx->msgcount; i++)
-+  {
-+    HEADER *hdr = ctx->hdrs[i];
-+    char buf[16];
++	return name;
++}
 +
-+    snprintf (buf, sizeof (buf), "%d", NHDR (hdr)->article_num);
-+    if (nntp_data->bcache && hdr->deleted)
-+    {
-+      dprint (2, (debugfile, "nntp_sync_mailbox: mutt_bcache_del %s\n", buf));
-+      mutt_bcache_del (nntp_data->bcache, buf);
-+    }
++static void nm_progress_reset(CONTEXT *ctx)
++{
++	struct nm_ctxdata *data;
 +
-+#ifdef USE_HCACHE
-+    if (hc && (hdr->changed || hdr->deleted))
-+    {
-+      if (hdr->deleted && !hdr->read)
-+	nntp_data->unread--;
-+      dprint (2, (debugfile, "nntp_sync_mailbox: mutt_hcache_store %s\n", buf));
-+      mutt_hcache_store (hc, buf, hdr, 0, strlen, M_GENERATE_UIDVALIDITY);
-+    }
-+#endif
-+  }
++	if (ctx->quiet)
++		return;
 +
-+#ifdef USE_HCACHE
-+  if (hc)
-+  {
-+    mutt_hcache_close (hc);
-+    nntp_data->lastCached = nntp_data->lastLoaded;
-+  }
-+#endif
++	data = get_ctxdata(ctx);
 +
-+  /* save .newsrc entries */
-+  nntp_newsrc_gen_entries (ctx);
-+  nntp_newsrc_update (nntp_data->nserv);
-+  nntp_newsrc_close (nntp_data->nserv);
-+  return 0;
++	memset(&data->progress, 0, sizeof(data->progress));
++	data->oldmsgcount = ctx->msgcount;
++	data->ignmsgcount = 0;
++	data->noprogress = 0;
++	data->progress_ready = 0;
 +}
 +
-+/* Free up memory associated with the newsgroup context */
-+int nntp_fastclose_mailbox (CONTEXT *ctx)
++static void nm_progress_update(CONTEXT *ctx, notmuch_query_t *q)
 +{
-+  NNTP_DATA *nntp_data = ctx->data, *nntp_tmp;
++	struct nm_ctxdata *data = get_ctxdata(ctx);
 +
-+  if (!nntp_data)
-+    return 0;
++	if (ctx->quiet || data->noprogress)
++		return;
 +
-+  nntp_acache_free (nntp_data);
-+  if (!nntp_data->nserv || !nntp_data->nserv->groups_hash || !nntp_data->group)
-+    return 0;
++	if (!data->progress_ready && q) {
++		unsigned count;
++		static char msg[STRING];
++		snprintf(msg, sizeof(msg), _("Reading messages..."));
 +
-+  nntp_tmp = hash_find (nntp_data->nserv->groups_hash, nntp_data->group);
-+  if (nntp_tmp == NULL || nntp_tmp != nntp_data)
-+    nntp_data_free (nntp_data);
-+  return 0;
++#if LIBNOTMUCH_CHECK_VERSION(4,3,0)
++		if (notmuch_query_count_messages_st (q, &count) != NOTMUCH_STATUS_SUCCESS)
++			count = 0;	/* may not be defined on error */
++#else
++		count = notmuch_query_count_messages(q);
++#endif
++		mutt_progress_init(&data->progress, msg, M_PROGRESS_MSG,
++			ReadInc, count);
++		data->progress_ready = 1;
++	}
++
++	if (data->progress_ready)
++		mutt_progress_update(&data->progress,
++				ctx->msgcount + data->ignmsgcount
++					      - data->oldmsgcount, -1);
 +}
 +
-+/* Get date and time from server */
-+int nntp_date (NNTP_SERVER *nserv, time_t *now)
++static void append_message(CONTEXT *ctx,
++			   notmuch_query_t *q,
++			   notmuch_message_t *msg,
++			   int dedup)
 +{
-+  if (nserv->hasDATE)
-+  {
-+    NNTP_DATA nntp_data;
-+    char buf[LONG_STRING];
-+    struct tm tm;
++	char *newpath = NULL;
++	const char *path;
++	HEADER *h = NULL;
 +
-+    nntp_data.nserv = nserv;
-+    nntp_data.group = NULL;
-+    strfcpy (buf, "DATE\r\n", sizeof (buf));
-+    if (nntp_query (&nntp_data, buf, sizeof (buf)) < 0)
-+      return -1;
++	/* deduplicate */
++	if (dedup && get_mutt_header(ctx, msg)) {
++		get_ctxdata(ctx)->ignmsgcount++;
++		nm_progress_update(ctx, q);
++	        dprint(2, (debugfile, "nm: ignore id=%s, already in the context\n",
++					notmuch_message_get_message_id(msg)));
++		return;
++	}
 +
-+    if (sscanf (buf, "111 %4d%2d%2d%2d%2d%2d%*s", &tm.tm_year, &tm.tm_mon,
-+		&tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec) == 6)
-+    {
-+      tm.tm_year -= 1900;
-+      tm.tm_mon--;
-+      *now = timegm (&tm);
-+      if (*now >= 0)
-+      {
-+	dprint (1, (debugfile, "nntp_date: server time is %d\n", *now));
-+	return 0;
-+      }
-+    }
-+  }
-+  time (now);
-+  return 0;
-+}
++	path = get_message_last_filename(msg);
++	if (!path)
++		return;
 +
-+/* Fetch list of all newsgroups from server */
-+int nntp_active_fetch (NNTP_SERVER *nserv)
-+{
-+  NNTP_DATA nntp_data;
-+  char msg[SHORT_STRING];
-+  char buf[LONG_STRING];
-+  unsigned int i;
-+  int rc;
++	dprint(2, (debugfile, "nm: appending message, i=%d, id=%s, path=%s\n",
++				ctx->msgcount,
++				notmuch_message_get_message_id(msg),
++				path));
 +
-+  snprintf (msg, sizeof (msg), _("Loading list of groups from server %s..."),
-+	    nserv->conn->account.host);
-+  mutt_message (msg);
-+  if (nntp_date (nserv, &nserv->newgroups_time) < 0)
-+    return -1;
++	if (ctx->msgcount >= ctx->hdrmax) {
++		dprint(2, (debugfile, "nm: allocate mx memory\n"));
++		mx_alloc_memory(ctx);
++	}
++	if (access(path, F_OK) == 0)
++		h = maildir_parse_message(M_MAILDIR, path, 0, NULL);
++	else {
++		/* maybe moved try find it... */
++		char *folder = get_folder_from_path(path);
 +
-+  nntp_data.nserv = nserv;
-+  nntp_data.group = NULL;
-+  strfcpy (buf, "LIST\r\n", sizeof (buf));
-+  rc = nntp_fetch_lines (&nntp_data, buf, sizeof (buf), msg,
-+			 nntp_add_group, nserv);
-+  if (rc)
-+  {
-+    if (rc > 0)
-+    {
-+      mutt_error ("LIST: %s", buf);
-+      mutt_sleep (2);
-+    }
-+    return -1;
-+  }
++		if (folder) {
++			FILE *f = maildir_open_find_message(folder, path, &newpath);
++			if (f) {
++				h = maildir_parse_stream(M_MAILDIR, f, newpath, 0, NULL);
++				fclose(f);
 +
-+  if (option (OPTLOADDESC) &&
-+      get_description (&nntp_data, "*", _("Loading descriptions...")) < 0)
-+    return -1;
++				dprint(1, (debugfile, "nm: not up-to-date: %s -> %s\n",
++							path, newpath));
++			}
++		}
++		FREE(&folder);
++	}
 +
-+  for (i = 0; i < nserv->groups_num; i++)
-+  {
-+    NNTP_DATA *nntp_data = nserv->groups_list[i];
++	if (!h) {
++		dprint(1, (debugfile, "nm: failed to parse message: %s\n", path));
++		goto done;
++	}
++	if (init_header(h, newpath ? newpath : path, msg) != 0) {
++		mutt_free_header(&h);
++		dprint(1, (debugfile, "nm: failed to append header!\n"));
++		goto done;
++	}
 +
-+    if (nntp_data && nntp_data->deleted && !nntp_data->newsrc_ent)
-+    {
-+      nntp_delete_group_cache (nntp_data);
-+      hash_delete (nserv->groups_hash, nntp_data->group, NULL, nntp_data_free);
-+      nserv->groups_list[i] = NULL;
-+    }
-+  }
-+  nntp_active_save_cache (nserv);
-+  mutt_clear_error ();
-+  return 0;
++	h->active = 1;
++	h->index = ctx->msgcount;
++	ctx->size += h->content->length
++		   + h->content->offset
++		   - h->content->hdr_offset;
++	ctx->hdrs[ctx->msgcount] = h;
++	ctx->msgcount++;
++
++	if (newpath) {
++		/* remember that file has been moved -- nm_sync() will update the DB */
++		struct nm_hdrdata *hd = (struct nm_hdrdata *) h->data;
++
++		if (hd) {
++			dprint(1, (debugfile, "nm: remember obsolete path: %s\n", path));
++			hd->oldpath = safe_strdup(path);
++		}
++	}
++	nm_progress_update(ctx, q);
++done:
++	FREE(&newpath);
 +}
 +
-+/* Check newsgroup for new articles:
-+ *  1 - new articles found
-+ *  0 - no change
-+ * -1 - lost connection */
-+static int nntp_group_poll (NNTP_DATA *nntp_data, int update_stat)
++/*
++ * add all the replies to a given messages into the display.
++ * Careful, this calls itself recursively to make sure we get
++ * everything.
++ */
++static void append_replies(CONTEXT *ctx,
++			   notmuch_query_t *q,
++			   notmuch_message_t *top,
++			   int dedup)
 +{
-+  char buf[LONG_STRING] = "";
-+  anum_t count, first, last;
++	notmuch_messages_t *msgs;
 +
-+  /* use GROUP command to poll newsgroup */
-+  if (nntp_query (nntp_data, buf, sizeof (buf)) < 0)
-+    return -1;
-+  if (sscanf (buf, "211 " ANUM " " ANUM " " ANUM, &count, &first, &last) != 3)
-+    return 0;
-+  if (first == nntp_data->firstMessage && last == nntp_data->lastMessage)
-+    return 0;
++	for (msgs = notmuch_message_get_replies(top);
++	     notmuch_messages_valid(msgs);
++	     notmuch_messages_move_to_next(msgs)) {
 +
-+  /* articles have been renumbered */
-+  if (last < nntp_data->lastMessage)
-+  {
-+    nntp_data->lastCached = 0;
-+    if (nntp_data->newsrc_len)
-+    {
-+      safe_realloc (&nntp_data->newsrc_ent, sizeof (NEWSRC_ENTRY));
-+      nntp_data->newsrc_len = 1;
-+      nntp_data->newsrc_ent[0].first = 1;
-+      nntp_data->newsrc_ent[0].last = 0;
-+    }
-+  }
-+  nntp_data->firstMessage = first;
-+  nntp_data->lastMessage = last;
-+  if (!update_stat)
-+    return 1;
++		notmuch_message_t *m = notmuch_messages_get(msgs);
++		append_message(ctx, q, m, dedup);
++		/* recurse through all the replies to this message too */
++		append_replies(ctx, q, m, dedup);
++		notmuch_message_destroy(m);
++	}
++}
 +
-+  /* update counters */
-+  else if (!last || (!nntp_data->newsrc_ent && !nntp_data->lastCached))
-+    nntp_data->unread = count;
-+  else
-+    nntp_group_unread_stat (nntp_data);
-+  return 1;
++/*
++ * add each top level reply in the thread, and then add each
++ * reply to the top level replies
++ */
++static void append_thread(CONTEXT *ctx,
++			  notmuch_query_t *q,
++			  notmuch_thread_t *thread,
++			  int dedup)
++{
++	notmuch_messages_t *msgs;
++
++	for (msgs = notmuch_thread_get_toplevel_messages(thread);
++	     notmuch_messages_valid(msgs);
++	     notmuch_messages_move_to_next(msgs)) {
++
++		notmuch_message_t *m = notmuch_messages_get(msgs);
++		append_message(ctx, q, m, dedup);
++		append_replies(ctx, q, m, dedup);
++		notmuch_message_destroy(m);
++	}
 +}
 +
-+/* Check current newsgroup for new articles:
-+ *  M_REOPENED	- articles have been renumbered or removed from server
-+ *  M_NEW_MAIL	- new articles found
-+ *  0		- no change
-+ * -1		- lost connection */
-+int nntp_check_mailbox (CONTEXT *ctx, int leave_lock)
++static void read_mesgs_query(CONTEXT *ctx, notmuch_query_t *q, int dedup)
 +{
-+  NNTP_DATA *nntp_data = ctx->data;
-+  NNTP_SERVER *nserv = nntp_data->nserv;
-+  time_t now = time (NULL);
-+  int i, j;
-+  int rc, ret = 0;
-+  void *hc = NULL;
++	struct nm_ctxdata *data = get_ctxdata(ctx);
++	int limit;
++	notmuch_messages_t *msgs;
 +
-+  if (nserv->check_time + NewsPollTimeout > now)
-+    return 0;
++	if (!data)
++		return;
 +
-+  mutt_message _("Checking for new messages...");
-+  if (nntp_newsrc_parse (nserv) < 0)
-+    return -1;
++	limit = get_limit(data);
 +
-+  nserv->check_time = now;
-+  rc = nntp_group_poll (nntp_data, 0);
-+  if (rc < 0)
-+  {
-+    nntp_newsrc_close (nserv);
-+    return -1;
-+  }
-+  if (rc)
-+    nntp_active_save_cache (nserv);
++#if LIBNOTMUCH_CHECK_VERSION(4,3,0)
++	if (notmuch_query_search_messages_st (q, &msgs) != NOTMUCH_STATUS_SUCCESS)
++		return;
++#else
++	msgs = notmuch_query_search_messages(q);
++#endif
 +
-+  /* articles have been renumbered, remove all headers */
-+  if (nntp_data->lastMessage < nntp_data->lastLoaded)
-+  {
-+    for (i = 0; i < ctx->msgcount; i++)
-+      mutt_free_header (&ctx->hdrs[i]);
-+    ctx->msgcount = 0;
-+    ctx->tagged = 0;
++	for (; notmuch_messages_valid(msgs) &&
++		(limit == 0 || ctx->msgcount < limit);
++	     notmuch_messages_move_to_next(msgs)) {
 +
-+    if (nntp_data->lastMessage < nntp_data->lastLoaded)
-+    {
-+      nntp_data->lastLoaded = nntp_data->firstMessage - 1;
-+      if (NntpContext && nntp_data->lastMessage - nntp_data->lastLoaded >
-+	  NntpContext)
-+	nntp_data->lastLoaded = nntp_data->lastMessage - NntpContext;
-+    }
-+    ret = M_REOPENED;
-+  }
++		notmuch_message_t *m = notmuch_messages_get(msgs);
++		append_message(ctx, q, m, dedup);
++		notmuch_message_destroy(m);
++	}
++}
 +
-+  /* .newsrc has been externally modified */
-+  if (nserv->newsrc_modified)
-+  {
-+    anum_t anum;
-+#ifdef USE_HCACHE
-+    unsigned char *messages;
-+    char buf[16];
-+    void *hdata;
-+    HEADER *hdr;
-+    anum_t first = nntp_data->firstMessage;
++static void read_threads_query(CONTEXT *ctx, notmuch_query_t *q, int dedup, int limit)
++{
++	struct nm_ctxdata *data = get_ctxdata(ctx);
++	notmuch_threads_t *threads;
 +
-+    if (NntpContext && nntp_data->lastMessage - first + 1 > NntpContext)
-+      first = nntp_data->lastMessage - NntpContext + 1;
-+    messages = safe_calloc (nntp_data->lastLoaded - first + 1,
-+			    sizeof (unsigned char));
-+    hc = nntp_hcache_open (nntp_data);
-+    nntp_hcache_update (nntp_data, hc);
++	if (!data)
++		return;
++
++#if LIBNOTMUCH_CHECK_VERSION(4,3,0)
++	if (notmuch_query_search_threads_st (q, &threads) != NOTMUCH_STATUS_SUCCESS)
++		return;
++#else
++	threads = notmuch_query_search_threads(q);
 +#endif
 +
-+    /* update flags according to .newsrc */
-+    for (i = j = 0; i < ctx->msgcount; i++)
-+    {
-+      int flagged = 0;
-+      anum = NHDR (ctx->hdrs[i])->article_num;
++	for (; notmuch_threads_valid(threads) &&
++		(limit == 0 || ctx->msgcount < limit);
++	     notmuch_threads_move_to_next(threads)) {
 +
-+#ifdef USE_HCACHE
-+      /* check hcache for flagged and deleted flags */
-+      if (hc)
-+      {
-+	if (anum >= first && anum <= nntp_data->lastLoaded)
-+	  messages[anum - first] = 1;
++		notmuch_thread_t *thread = notmuch_threads_get(threads);
++		append_thread(ctx, q, thread, dedup);
++		notmuch_thread_destroy(thread);
++	}
++}
 +
-+	snprintf (buf, sizeof (buf), "%d", anum);
-+	hdata = mutt_hcache_fetch (hc, buf, strlen);
-+	if (hdata)
-+	{
-+	  int deleted;
++int nm_read_query(CONTEXT *ctx)
++{
++	notmuch_query_t *q;
++	struct nm_ctxdata *data;
++	int rc = -1;
 +
-+	  dprint (2, (debugfile,
-+		      "nntp_check_mailbox: mutt_hcache_fetch %s\n", buf));
-+	  hdr = mutt_hcache_restore (hdata, NULL);
-+	  FREE (&hdata);
-+	  hdr->data = 0;
-+	  deleted = hdr->deleted;
-+	  flagged = hdr->flagged;
-+	  mutt_free_header (&hdr);
++	if (init_context(ctx) != 0)
++		return -1;
++
++	data = get_ctxdata(ctx);
++	if (!data)
++		return -1;
++
++	dprint(1, (debugfile, "nm: reading messages...[current count=%d]\n",
++				ctx->msgcount));
++
++	nm_progress_reset(ctx);
++
++	q = get_query(data, FALSE);
++	if (q) {
++		switch(get_query_type(data)) {
++		case NM_QUERY_TYPE_MESGS:
++			read_mesgs_query(ctx, q, 0);
++			break;
++		case NM_QUERY_TYPE_THREADS:
++			read_threads_query(ctx, q, 0, get_limit(data));
++			break;
++		}
++		notmuch_query_destroy(q);
++		rc = 0;
 +
-+	  /* header marked as deleted, removing from context */
-+	  if (deleted)
-+	  {
-+	    mutt_set_flag (ctx, ctx->hdrs[i], M_TAG, 0);
-+	    mutt_free_header (&ctx->hdrs[i]);
-+	    continue;
-+	  }
 +	}
-+      }
-+#endif
 +
-+      if (!ctx->hdrs[i]->changed)
-+      {
-+	ctx->hdrs[i]->flagged = flagged;
-+	ctx->hdrs[i]->read = 0;
-+	ctx->hdrs[i]->old = 0;
-+	nntp_article_status (ctx, ctx->hdrs[i], NULL, anum);
-+	if (!ctx->hdrs[i]->read)
-+	  nntp_parse_xref (ctx, ctx->hdrs[i]);
-+      }
-+      ctx->hdrs[j++] = ctx->hdrs[i];
-+    }
++	if (!is_longrun(data))
++		release_db(data);
 +
-+#ifdef USE_HCACHE
-+    ctx->msgcount = j;
++	ctx->mtime = time(NULL);
 +
-+    /* restore headers without "deleted" flag */
-+    for (anum = first; anum <= nntp_data->lastLoaded; anum++)
-+    {
-+      if (messages[anum - first])
-+	continue;
++	mx_update_context(ctx, ctx->msgcount);
++	data->oldmsgcount = 0;
 +
-+      snprintf (buf, sizeof (buf), "%d", anum);
-+      hdata = mutt_hcache_fetch (hc, buf, strlen);
-+      if (hdata)
-+      {
-+	dprint (2, (debugfile,
-+		    "nntp_check_mailbox: mutt_hcache_fetch %s\n", buf));
-+	if (ctx->msgcount >= ctx->hdrmax)
-+	  mx_alloc_memory (ctx);
++	dprint(1, (debugfile, "nm: reading messages... done [rc=%d, count=%d]\n",
++				rc, ctx->msgcount));
++	return rc;
++}
 +
-+	ctx->hdrs[ctx->msgcount] =
-+	hdr = mutt_hcache_restore (hdata, NULL);
-+	FREE (&hdata);
-+	hdr->data = 0;
-+	if (hdr->deleted)
-+	{
-+	  mutt_free_header (&hdr);
-+	  if (nntp_data->bcache)
-+	  {
-+	    dprint (2, (debugfile,
-+			"nntp_check_mailbox: mutt_bcache_del %s\n", buf));
-+	    mutt_bcache_del (nntp_data->bcache, buf);
-+	  }
-+	  continue;
-+	}
++int nm_read_entire_thread(CONTEXT *ctx, HEADER *h)
++{
++	struct nm_ctxdata *data = get_ctxdata(ctx);
++	const char *id;
++	char *qstr = NULL;
++	notmuch_query_t *q = NULL;
++	notmuch_database_t *db = NULL;
++	notmuch_message_t *msg = NULL;
++	int rc = -1;
 +
-+	ctx->msgcount++;
-+	hdr->read = 0;
-+	hdr->old = 0;
-+	hdr->data = safe_calloc (1, sizeof (NNTP_HEADER_DATA));
-+	NHDR (hdr)->article_num = anum;
-+	nntp_article_status (ctx, hdr, NULL, anum);
-+	if (!hdr->read)
-+	  nntp_parse_xref (ctx, hdr);
-+      }
-+    }
-+    FREE (&messages);
-+#endif
++	if (!data)
++		return -1;
++	if (!(db = get_db(data, FALSE)) || !(msg = get_nm_message(db, h)))
++		goto done;
 +
-+    nserv->newsrc_modified = 0;
-+    ret = M_REOPENED;
-+  }
++	dprint(1, (debugfile, "nm: reading entire-thread messages...[current count=%d]\n",
++				ctx->msgcount));
++
++	nm_progress_reset(ctx);
++	id = notmuch_message_get_thread_id(msg);
++	if (!id)
++		goto done;
++	append_str_item(&qstr, "thread:", 0);
++	append_str_item(&qstr, id, 0);
++
++	q = notmuch_query_create(db, qstr);
++	FREE(&qstr);
++	if (!q)
++		goto done;
++	apply_exclude_tags(q);
++	notmuch_query_set_sort(q, NOTMUCH_SORT_NEWEST_FIRST);
 +
-+  /* some headers were removed, context must be updated */
-+  if (ret == M_REOPENED)
-+  {
-+    if (ctx->subj_hash)
-+      hash_destroy (&ctx->subj_hash, NULL);
-+    if (ctx->id_hash)
-+      hash_destroy (&ctx->id_hash, NULL);
-+    mutt_clear_threads (ctx);
++	read_threads_query(ctx, q, 1, 0);
++	ctx->mtime = time(NULL);
++	rc = 0;
 +
-+    ctx->vcount = 0;
-+    ctx->deleted = 0;
-+    ctx->new = 0;
-+    ctx->unread = 0;
-+    ctx->flagged = 0;
-+    ctx->changed = 0;
-+    ctx->id_hash = NULL;
-+    ctx->subj_hash = NULL;
-+    mx_update_context (ctx, ctx->msgcount);
-+  }
++	if (ctx->msgcount > data->oldmsgcount)
++		mx_update_context(ctx, ctx->msgcount - data->oldmsgcount);
++done:
++	if (q)
++		notmuch_query_destroy(q);
++	if (!is_longrun(data))
++		release_db(data);
 +
-+  /* fetch headers of new articles */
-+  if (nntp_data->lastMessage > nntp_data->lastLoaded)
-+  {
-+    int oldmsgcount = ctx->msgcount;
-+    int quiet = ctx->quiet;
-+    ctx->quiet = 1;
-+#ifdef USE_HCACHE
-+    if (!hc)
-+    {
-+      hc = nntp_hcache_open (nntp_data);
-+      nntp_hcache_update (nntp_data, hc);
-+    }
-+#endif
-+    rc = nntp_fetch_headers (ctx, hc, nntp_data->lastLoaded + 1,
-+			     nntp_data->lastMessage, 0);
-+    ctx->quiet = quiet;
-+    if (rc >= 0)
-+      nntp_data->lastLoaded = nntp_data->lastMessage;
-+    if (ret == 0 && ctx->msgcount > oldmsgcount)
-+      ret = M_NEW_MAIL;
-+  }
++	if (ctx->msgcount == data->oldmsgcount)
++		mutt_message _("No more messages in the thread.");
 +
-+#ifdef USE_HCACHE
-+  mutt_hcache_close (hc);
-+#endif
-+  if (ret || !leave_lock)
-+    nntp_newsrc_close (nserv);
-+  mutt_clear_error ();
-+  return ret;
++	data->oldmsgcount = 0;
++	dprint(1, (debugfile, "nm: reading entire-thread messages... done [rc=%d, count=%d]\n",
++				rc, ctx->msgcount));
++	return rc;
 +}
 +
-+/* Check for new groups and new articles in subscribed groups:
-+ *  1 - new groups found
-+ *  0 - no new groups
-+ * -1 - error */
-+int nntp_check_new_groups (NNTP_SERVER *nserv)
++char *nm_uri_from_query(CONTEXT *ctx, char *buf, size_t bufsz)
 +{
-+  NNTP_DATA nntp_data;
-+  time_t now;
-+  struct tm *tm;
-+  char buf[LONG_STRING];
-+  char *msg = _("Checking for new newsgroups...");
-+  unsigned int i;
-+  int rc, update_active = FALSE;
-+
-+  if (!nserv || !nserv->newgroups_time)
-+    return -1;
++	struct nm_ctxdata *data = get_ctxdata(ctx);
++	char uri[_POSIX_PATH_MAX + LONG_STRING + 32];	/* path to DB + query + URI "decoration" */
 +
-+  /* check subscribed newsgroups for new articles */
-+  if (option (OPTSHOWNEWNEWS))
-+  {
-+    mutt_message _("Checking for new messages...");
-+    for (i = 0; i < nserv->groups_num; i++)
-+    {
-+      NNTP_DATA *nntp_data = nserv->groups_list[i];
++	if (data)
++		snprintf(uri, sizeof(uri), "notmuch://%s?query=%s",
++			 get_db_filename(data), buf);
++	else if (NotmuchDefaultUri)
++		snprintf(uri, sizeof(uri), "%s?query=%s", NotmuchDefaultUri, buf);
++	else if (Maildir)
++		snprintf(uri, sizeof(uri), "notmuch://%s?query=%s", Maildir, buf);
++	else
++		return NULL;
 +
-+      if (nntp_data && nntp_data->subscribed)
-+      {
-+	rc = nntp_group_poll (nntp_data, 1);
-+	if (rc < 0)
-+	  return -1;
-+	if (rc > 0)
-+	  update_active = TRUE;
-+      }
-+    }
-+    /* select current newsgroup */
-+    if (Context && Context->magic == M_NNTP)
-+    {
-+      buf[0] = '\0';
-+      if (nntp_query ((NNTP_DATA *)Context->data, buf, sizeof (buf)) < 0)
-+	return -1;
-+    }
-+  }
-+  else if (nserv->newgroups_time)
-+    return 0;
++	strncpy(buf, uri, bufsz);
++	buf[bufsz - 1] = '\0';
 +
-+  /* get list of new groups */
-+  mutt_message (msg);
-+  if (nntp_date (nserv, &now) < 0)
-+    return -1;
-+  nntp_data.nserv = nserv;
-+  if (Context && Context->magic == M_NNTP)
-+    nntp_data.group = ((NNTP_DATA *)Context->data)->group;
-+  else
-+    nntp_data.group = NULL;
-+  i = nserv->groups_num;
-+  tm = gmtime (&nserv->newgroups_time);
-+  snprintf (buf, sizeof (buf), "NEWGROUPS %02d%02d%02d %02d%02d%02d GMT\r\n",
-+	    tm->tm_year % 100, tm->tm_mon + 1, tm->tm_mday,
-+	    tm->tm_hour, tm->tm_min, tm->tm_sec);
-+  rc = nntp_fetch_lines (&nntp_data, buf, sizeof (buf), msg,
-+			 nntp_add_group, nserv);
-+  if (rc)
-+  {
-+    if (rc > 0)
-+    {
-+      mutt_error ("NEWGROUPS: %s", buf);
-+      mutt_sleep (2);
-+    }
-+    return -1;
-+  }
++	dprint(1, (debugfile, "nm: uri from query '%s'\n", buf));
++	return buf;
++}
 +
-+  /* new groups found */
-+  rc = 0;
-+  if (nserv->groups_num != i)
-+  {
-+    nserv->newgroups_time = now;
++/*
++ * returns message from notmuch database
++ */
++static notmuch_message_t *get_nm_message(notmuch_database_t *db, HEADER *hdr)
++{
++	notmuch_message_t *msg = NULL;
++	char *id = nm_header_get_id(hdr);
 +
-+    /* loading descriptions */
-+    if (option (OPTLOADDESC))
-+    {
-+      unsigned int count = 0;
-+      progress_t progress;
++	dprint(2, (debugfile, "nm: find message (%s)\n", id));
 +
-+      mutt_progress_init (&progress, _("Loading descriptions..."),
-+			  M_PROGRESS_MSG, ReadInc, nserv->groups_num - i);
-+      for (; i < nserv->groups_num; i++)
-+      {
-+	NNTP_DATA *nntp_data = nserv->groups_list[i];
++	if (id && db)
++		notmuch_database_find_message(db, id, &msg);
 +
-+	if (get_description (nntp_data, NULL, NULL) < 0)
-+	  return -1;
-+	mutt_progress_update (&progress, ++count, -1);
-+      }
-+    }
-+    update_active = TRUE;
-+    rc = 1;
-+  }
-+  if (update_active)
-+    nntp_active_save_cache (nserv);
-+  mutt_clear_error ();
-+  return rc;
++	return msg;
 +}
 +
-+/* Fetch article by Message-ID:
-+ *  0 - success
-+ *  1 - no such article
-+ * -1 - error */
-+int nntp_check_msgid (CONTEXT *ctx, const char *msgid)
++static int update_tags(notmuch_message_t *msg, const char *tags)
 +{
-+  NNTP_DATA *nntp_data = ctx->data;
-+  HEADER *hdr;
-+  FILE *fp;
-+  char tempfile[_POSIX_PATH_MAX];
-+  char buf[LONG_STRING];
-+  int rc;
-+
-+  mutt_mktemp (tempfile, sizeof (tempfile));
-+  fp = safe_fopen (tempfile, "w+");
-+  if (!fp)
-+  {
-+    mutt_perror (tempfile);
-+    unlink (tempfile);
-+    return -1;
-+  }
++	char *tag = NULL, *end = NULL, *p;
++	char *buf = safe_strdup(tags);
 +
-+  snprintf (buf, sizeof (buf), "HEAD %s\r\n", msgid);
-+  rc = nntp_fetch_lines (nntp_data, buf, sizeof (buf), NULL,
-+			 fetch_tempfile, fp);
-+  if (rc)
-+  {
-+    fclose (fp);
-+    unlink (tempfile);
-+    if (rc < 0)
-+      return -1;
-+    if (!mutt_strncmp ("430", buf, 3))
-+      return 1;
-+    mutt_error ("HEAD: %s", buf);
-+    return -1;
-+  }
++	if (!buf)
++		return -1;
 +
-+  /* parse header */
-+  if (ctx->msgcount == ctx->hdrmax)
-+    mx_alloc_memory (ctx);
-+  hdr = ctx->hdrs[ctx->msgcount] = mutt_new_header ();
-+  hdr->data = safe_calloc (1, sizeof (NNTP_HEADER_DATA));
-+  hdr->env = mutt_read_rfc822_header (fp, hdr, 0, 0);
-+  fclose (fp);
-+  unlink (tempfile);
++	notmuch_message_freeze(msg);
 +
-+  /* get article number */
-+  if (hdr->env->xref)
-+    nntp_parse_xref (ctx, hdr);
-+  else
-+  {
-+    snprintf (buf, sizeof (buf), "STAT %s\r\n", msgid);
-+    if (nntp_query (nntp_data, buf, sizeof (buf)) < 0)
-+    {
-+      mutt_free_header (&hdr);
-+      return -1;
-+    }
-+    sscanf (buf + 4, ANUM, &NHDR (hdr)->article_num);
-+  }
++	for (p = buf; p && *p; p++) {
++		if (!tag && isspace(*p))
++			continue;
++		if (!tag)
++			tag = p;		/* begin of the tag */
++		if (*p == ',' || *p == ' ')
++			end = p;		/* terminate the tag */
++		else if (*(p + 1) == '\0')
++			end = p + 1;		/* end of optstr */
++		if (!tag || !end)
++			continue;
++		if (tag >= end)
++			break;
 +
-+  /* reset flags */
-+  hdr->read = 0;
-+  hdr->old = 0;
-+  hdr->deleted = 0;
-+  hdr->changed = 1;
-+  hdr->received = hdr->date_sent;
-+  hdr->index = ctx->msgcount++;
-+  mx_update_context (ctx, 1);
-+  return 0;
++		*end = '\0';
++
++		if (*tag == '-') {
++			dprint(1, (debugfile, "nm: remove tag: '%s'\n", tag + 1));
++			notmuch_message_remove_tag(msg, tag + 1);
++		} else {
++			dprint(1, (debugfile, "nm: add tag: '%s'\n", *tag == '+' ? tag + 1 : tag));
++			notmuch_message_add_tag(msg, *tag == '+' ? tag + 1 : tag);
++		}
++		end = tag = NULL;
++	}
++
++	notmuch_message_thaw(msg);
++	FREE(&buf);
++	return 0;
 +}
 +
-+typedef struct
++int nm_modify_message_tags(CONTEXT *ctx, HEADER *hdr, char *buf)
 +{
-+  CONTEXT *ctx;
-+  unsigned int num;
-+  unsigned int max;
-+  anum_t *child;
-+} CHILD_CTX;
++	struct nm_ctxdata *data = get_ctxdata(ctx);
++	notmuch_database_t *db = NULL;
++	notmuch_message_t *msg = NULL;
++	int rc = -1;
 +
-+/* Parse XPAT line */
-+static int fetch_children (char *line, void *data)
-+{
-+  CHILD_CTX *cc = data;
-+  anum_t anum;
-+  unsigned int i;
++	if (!buf || !*buf || !data)
++		return -1;
 +
-+  if (!line || sscanf (line, ANUM, &anum) != 1)
-+    return 0;
-+  for (i = 0; i < cc->ctx->msgcount; i++)
-+    if (NHDR (cc->ctx->hdrs[i])->article_num == anum)
-+      return 0;
-+  if (cc->num >= cc->max)
-+  {
-+    cc->max *= 2;
-+    safe_realloc (&cc->child, sizeof (anum_t) * cc->max);
-+  }
-+  cc->child[cc->num++] = anum;
-+  return 0;
++	if (!(db = get_db(data, TRUE)) || !(msg = get_nm_message(db, hdr)))
++		goto done;
++
++	dprint(1, (debugfile, "nm: tags modify: '%s'\n", buf));
++
++	update_tags(msg, buf);
++	update_header_tags(hdr, msg);
++	mutt_set_header_color(ctx, hdr);
++
++	rc = 0;
++	hdr->changed = TRUE;
++done:
++	if (!is_longrun(data))
++		release_db(data);
++	if (hdr->changed)
++		ctx->mtime = time(NULL);
++	dprint(1, (debugfile, "nm: tags modify done [rc=%d]\n", rc));
++	return rc;
 +}
 +
-+/* Fetch children of article with the Message-ID */
-+int nntp_check_children (CONTEXT *ctx, const char *msgid)
++static int rename_maildir_filename(const char *old, char *newpath, size_t newsz, HEADER *h)
 +{
-+  NNTP_DATA *nntp_data = ctx->data;
-+  CHILD_CTX cc;
-+  char buf[STRING];
-+  int i, rc, quiet;
-+  void *hc = NULL;
++	char filename[_POSIX_PATH_MAX];
++	char suffix[_POSIX_PATH_MAX];
++	char folder[_POSIX_PATH_MAX];
++	char *p;
 +
-+  if (!nntp_data || !nntp_data->nserv)
-+    return -1;
-+  if (nntp_data->firstMessage > nntp_data->lastLoaded)
-+    return 0;
++	strfcpy(folder, old, sizeof(folder));
++	p = strrchr(folder, '/');
++	if (p)
++		*p = '\0';
 +
-+  /* init context */
-+  cc.ctx = ctx;
-+  cc.num = 0;
-+  cc.max = 10;
-+  cc.child = safe_malloc (sizeof (anum_t) * cc.max);
++	p++;
++	strfcpy(filename, p, sizeof(filename));
 +
-+  /* fetch numbers of child messages */
-+  snprintf (buf, sizeof (buf), "XPAT References %d-%d *%s*\r\n",
-+	    nntp_data->firstMessage, nntp_data->lastLoaded, msgid);
-+  rc = nntp_fetch_lines (nntp_data, buf, sizeof (buf), NULL,
-+			 fetch_children, &cc);
-+  if (rc)
-+  {
-+    FREE (&cc.child);
-+    if (rc > 0) {
-+      if (mutt_strncmp ("500", buf, 3))
-+	mutt_error ("XPAT: %s", buf);
-+      else
-+	mutt_error _("Unable to find child articles because server does not support XPAT command.");
-+    }
-+    return -1;
-+  }
++	/* remove (new,cur,...) from folder path */
++	p = strrchr(folder, '/');
++	if (p)
++		*p = '\0';
 +
-+  /* fetch all found messages */
-+  quiet = ctx->quiet;
-+  ctx->quiet = 1;
-+#ifdef USE_HCACHE
-+  hc = nntp_hcache_open (nntp_data);
-+#endif
-+  for (i = 0; i < cc.num; i++)
-+  {
-+    rc = nntp_fetch_headers (ctx, hc, cc.child[i], cc.child[i], 1);
-+    if (rc < 0)
-+      break;
-+  }
-+#ifdef USE_HCACHE
-+  mutt_hcache_close (hc);
-+#endif
-+  ctx->quiet = quiet;
-+  FREE (&cc.child);
-+  return rc < 0 ? -1 : 0;
-+}
-diff -urN mutt-1.6.1/nntp.h mutt-1.6.1-neomutt/nntp.h
---- mutt-1.6.1/nntp.h	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/nntp.h	2016-06-12 18:43:00.720452549 +0100
-@@ -0,0 +1,168 @@
-+/*
-+ * Copyright (C) 1998 Brandon Long <blong at fiction.net>
-+ * Copyright (C) 1999 Andrej Gritsenko <andrej at lucky.net>
-+ * Copyright (C) 2000-2012 Vsevolod Volkov <vvv at mutt.org.ua>
-+ *
-+ *     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., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ */
++	/* remove old flags from filename */
++	if ((p = strchr(filename, ':')))
++		*p = '\0';
 +
-+#ifndef _NNTP_H_
-+#define _NNTP_H_ 1
++	/* compose new flags */
++	maildir_flags(suffix, sizeof(suffix), h);
 +
-+#include "mutt_socket.h"
-+#include "mailbox.h"
-+#include "bcache.h"
++	snprintf(newpath, newsz, "%s/%s/%s%s",
++			folder,
++			(h->read || h->old) ? "cur" : "new",
++			filename,
++			suffix);
 +
-+#if USE_HCACHE
-+#include "hcache.h"
-+#endif
++	if (strcmp(old, newpath) == 0)
++		return 1;
 +
-+#include <time.h>
-+#include <sys/types.h>
-+#include <stdint.h>
++	if (rename(old, newpath) != 0) {
++		dprint(1, (debugfile, "nm: rename(2) failed %s -> %s\n", old, newpath));
++		return -1;
++	}
 +
-+#define NNTP_PORT 119
-+#define NNTP_SSL_PORT 563
++	return 0;
++}
 +
-+/* number of entries in article cache */
-+#define NNTP_ACACHE_LEN 10
++static int remove_filename(struct nm_ctxdata *data, const char *path)
++{
++	notmuch_status_t st;
++	notmuch_filenames_t *ls;
++	notmuch_message_t *msg = NULL;
++	notmuch_database_t *db = get_db(data, TRUE);
++	int trans;
 +
-+/* article number type and format */
-+#define anum_t uint32_t
-+#define ANUM "%u"
++	dprint(2, (debugfile, "nm: remove filename '%s'\n", path));
 +
-+enum
-+{
-+  NNTP_NONE = 0,
-+  NNTP_OK,
-+  NNTP_BYE
-+};
++	if (!db)
++		return -1;
++	st = notmuch_database_find_message_by_filename(db, path, &msg);
++	if (st || !msg)
++		return -1;
++	trans = db_trans_begin(data);
++	if (trans < 0)
++		return -1;
 +
-+typedef struct
-+{
-+  unsigned int hasCAPABILITIES : 1;
-+  unsigned int hasSTARTTLS : 1;
-+  unsigned int hasDATE : 1;
-+  unsigned int hasLIST_NEWSGROUPS : 1;
-+  unsigned int hasXGTITLE : 1;
-+  unsigned int hasLISTGROUP : 1;
-+  unsigned int hasLISTGROUPrange : 1;
-+  unsigned int hasOVER : 1;
-+  unsigned int hasXOVER : 1;
-+  unsigned int use_tls : 3;
-+  unsigned int status : 3;
-+  unsigned int cacheable : 1;
-+  unsigned int newsrc_modified : 1;
-+  FILE *newsrc_fp;
-+  char *newsrc_file;
-+  char *authenticators;
-+  char *overview_fmt;
-+  off_t size;
-+  time_t mtime;
-+  time_t newgroups_time;
-+  time_t check_time;
-+  unsigned int groups_num;
-+  unsigned int groups_max;
-+  void **groups_list;
-+  HASH *groups_hash;
-+  CONNECTION *conn;
-+} NNTP_SERVER;
++	/*
++	 * note that unlink() is probably unnecessary here, it's already removed
++	 * by mh_sync_mailbox_message(), but for sure...
++	 */
++	st = notmuch_database_remove_message(db, path);
++	switch (st) {
++	case NOTMUCH_STATUS_SUCCESS:
++		dprint(2, (debugfile, "nm: remove success, call unlink\n"));
++		unlink(path);
++		break;
++	case NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID:
++		dprint(2, (debugfile, "nm: remove success (duplicate), call unlink\n"));
++		unlink(path);
++		for (ls = notmuch_message_get_filenames(msg);
++		     ls && notmuch_filenames_valid(ls);
++		     notmuch_filenames_move_to_next(ls)) {
 +
-+typedef struct
-+{
-+  anum_t first;
-+  anum_t last;
-+} NEWSRC_ENTRY;
++			path = notmuch_filenames_get(ls);
 +
-+typedef struct
-+{
-+  unsigned int index;
-+  char *path;
-+} NNTP_ACACHE;
++			dprint(2, (debugfile, "nm: remove duplicate: '%s'\n", path));
++			unlink(path);
++			notmuch_database_remove_message(db, path);
++		}
++		break;
++	default:
++		dprint(1, (debugfile, "nm: failed to remove '%s' [st=%d]\n", path, (int) st));
++		break;
++	}
 +
-+typedef struct
-+{
-+  char *group;
-+  char *desc;
-+  anum_t firstMessage;
-+  anum_t lastMessage;
-+  anum_t lastLoaded;
-+  anum_t lastCached;
-+  anum_t unread;
-+  unsigned int subscribed : 1;
-+  unsigned int new : 1;
-+  unsigned int allowed : 1;
-+  unsigned int deleted : 1;
-+  unsigned int newsrc_len;
-+  NEWSRC_ENTRY *newsrc_ent;
-+  NNTP_SERVER *nserv;
-+  NNTP_ACACHE acache[NNTP_ACACHE_LEN];
-+  body_cache_t *bcache;
-+} NNTP_DATA;
++	notmuch_message_destroy(msg);
++	if (trans)
++		db_trans_end(data);
++	return 0;
++}
 +
-+typedef struct
++static int rename_filename(struct nm_ctxdata *data,
++			const char *old, const char *new, HEADER *h)
 +{
-+  anum_t article_num;
-+  unsigned int parsed : 1;
-+} NNTP_HEADER_DATA;
-+
-+#define NHDR(hdr) ((NNTP_HEADER_DATA*)((hdr)->data))
++	int rc = -1;
++	notmuch_status_t st;
++	notmuch_filenames_t *ls;
++	notmuch_message_t *msg;
++	notmuch_database_t *db = get_db(data, TRUE);
++	int trans;
 +
-+/* internal functions */
-+int nntp_add_group (char *, void *);
-+int nntp_active_save_cache (NNTP_SERVER *);
-+int nntp_check_new_groups (NNTP_SERVER *);
-+int nntp_fastclose_mailbox (CONTEXT *);
-+int nntp_open_connection (NNTP_SERVER *);
-+void nntp_newsrc_gen_entries (CONTEXT *);
-+void nntp_bcache_update (NNTP_DATA *);
-+void nntp_article_status (CONTEXT *, HEADER *, char *, anum_t);
-+void nntp_group_unread_stat (NNTP_DATA *);
-+void nntp_data_free (void *);
-+void nntp_acache_free (NNTP_DATA *);
-+void nntp_delete_group_cache (NNTP_DATA *);
++	if (!db || !new || !old || access(new, F_OK) != 0)
++		return -1;
 +
-+/* exposed interface */
-+NNTP_SERVER *nntp_select_server (char *, int);
-+NNTP_DATA *mutt_newsgroup_subscribe (NNTP_SERVER *, char *);
-+NNTP_DATA *mutt_newsgroup_unsubscribe (NNTP_SERVER *, char *);
-+NNTP_DATA *mutt_newsgroup_catchup (NNTP_SERVER *, char *);
-+NNTP_DATA *mutt_newsgroup_uncatchup (NNTP_SERVER *, char *);
-+int nntp_active_fetch (NNTP_SERVER *);
-+int nntp_newsrc_update (NNTP_SERVER *);
-+int nntp_open_mailbox (CONTEXT *);
-+int nntp_sync_mailbox (CONTEXT *);
-+int nntp_check_mailbox (CONTEXT *, int);
-+int nntp_fetch_message (MESSAGE *, CONTEXT *, int);
-+int nntp_post (const char *);
-+int nntp_check_msgid (CONTEXT *, const char *);
-+int nntp_check_children (CONTEXT *, const char *);
-+int nntp_newsrc_parse (NNTP_SERVER *);
-+void nntp_newsrc_close (NNTP_SERVER *);
-+void nntp_buffy (char *, size_t);
-+void nntp_expand_path (char *, size_t, ACCOUNT *);
-+void nntp_clear_cache (NNTP_SERVER *);
-+const char *nntp_format_str (char *, size_t, size_t, char, const char *,
-+			     const char *, const char *, const char *,
-+			     unsigned long, format_flag);
++	dprint(1, (debugfile, "nm: rename filename, %s -> %s\n", old, new));
++	trans = db_trans_begin(data);
++	if (trans < 0)
++		return -1;
 +
-+NNTP_SERVER *CurrentNewsSrv INITVAL (NULL);
++	dprint(2, (debugfile, "nm: rename: add '%s'\n", new));
++	st = notmuch_database_add_message(db, new, &msg);
 +
-+#ifdef USE_HCACHE
-+header_cache_t *nntp_hcache_open (NNTP_DATA *);
-+void nntp_hcache_update (NNTP_DATA *, header_cache_t *);
-+#endif
++	if (st != NOTMUCH_STATUS_SUCCESS &&
++	    st != NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID) {
++		dprint(1, (debugfile, "nm: failed to add '%s' [st=%d]\n", new, (int) st));
++		goto done;
++	}
 +
-+#endif /* _NNTP_H_ */
-diff -urN mutt-1.6.1/OPS mutt-1.6.1-neomutt/OPS
---- mutt-1.6.1/OPS	2016-06-12 18:43:00.389447388 +0100
-+++ mutt-1.6.1-neomutt/OPS	2016-06-12 18:43:00.663451660 +0100
-@@ -8,14 +8,16 @@
- OP_BROWSER_NEW_FILE "select a new file in this directory"
- OP_BROWSER_VIEW_FILE "view file"
- OP_BROWSER_TELL "display the currently selected file's name"
--OP_BROWSER_SUBSCRIBE "subscribe to current mailbox (IMAP only)"
--OP_BROWSER_UNSUBSCRIBE "unsubscribe from current mailbox (IMAP only)"
-+OP_BROWSER_SUBSCRIBE "subscribe to current mbox (IMAP/NNTP only)"
-+OP_BROWSER_UNSUBSCRIBE "unsubscribe from current mbox (IMAP/NNTP only)"
- OP_BROWSER_TOGGLE_LSUB "toggle view all/subscribed mailboxes (IMAP only)"
- OP_BUFFY_LIST "list mailboxes with new mail"
-+OP_CATCHUP "mark all articles in newsgroup as read"
- OP_CHANGE_DIRECTORY "change directories"
- OP_CHECK_NEW "check mailboxes for new mail"
- OP_COMPOSE_ATTACH_FILE "attach file(s) to this message"
- OP_COMPOSE_ATTACH_MESSAGE "attach message(s) to this message"
-+OP_COMPOSE_ATTACH_NEWS_MESSAGE "attach news article(s) to this message"
- OP_COMPOSE_EDIT_BCC "edit the BCC list"
- OP_COMPOSE_EDIT_CC "edit the CC list"
- OP_COMPOSE_EDIT_DESCRIPTION "edit attachment description"
-@@ -26,7 +28,10 @@
- OP_COMPOSE_EDIT_HEADERS "edit the message with headers"
- OP_COMPOSE_EDIT_MESSAGE "edit the message"
- OP_COMPOSE_EDIT_MIME "edit attachment using mailcap entry"
-+OP_COMPOSE_EDIT_NEWSGROUPS "edit the newsgroups list"
- OP_COMPOSE_EDIT_REPLY_TO "edit the Reply-To field"
-+OP_COMPOSE_EDIT_FOLLOWUP_TO "edit the Followup-To field"
-+OP_COMPOSE_EDIT_X_COMMENT_TO "edit the X-Comment-To field"
- OP_COMPOSE_EDIT_SUBJECT "edit the subject of this message"
- OP_COMPOSE_EDIT_TO "edit the TO list"
- OP_CREATE_MAILBOX "create a new mailbox (IMAP only)"
-@@ -56,6 +61,7 @@
- OP_DISPLAY_ADDRESS "display full address of sender"
- OP_DISPLAY_HEADERS "display message and toggle header weeding"
- OP_DISPLAY_MESSAGE "display a message"
-+OP_EDIT_LABEL "add, change, or delete a message's label"
- OP_EDIT_MESSAGE "edit the raw message"
- OP_EDITOR_BACKSPACE "delete the char in front of the cursor"
- OP_EDITOR_BACKWARD_CHAR "move the cursor one character to the left"
-@@ -85,8 +91,13 @@
- OP_FILTER "filter attachment through a shell command"
- OP_FIRST_ENTRY "move to the first entry"
- OP_FLAG_MESSAGE "toggle a message's 'important' flag"
-+OP_FOLLOWUP "followup to newsgroup"
-+OP_FORWARD_TO_GROUP "forward to newsgroup"
- OP_FORWARD_MESSAGE "forward a message with comments"
- OP_GENERIC_SELECT_ENTRY "select the current entry"
-+OP_GET_CHILDREN "get all children of the current message"
-+OP_GET_MESSAGE "get message with Message-Id"
-+OP_GET_PARENT "get parent of the current message"
- OP_GROUP_REPLY "reply to all recipients"
- OP_HALF_DOWN "scroll down 1/2 page"
- OP_HALF_UP "scroll up 1/2 page"
-@@ -94,11 +105,14 @@
- OP_JUMP "jump to an index number"
- OP_LAST_ENTRY "move to the last entry"
- OP_LIST_REPLY "reply to specified mailing list"
-+OP_LOAD_ACTIVE "load list of all newsgroups from NNTP server"
- OP_MACRO "execute a macro"
- OP_MAIL "compose a new mail message"
- OP_MAIN_BREAK_THREAD "break the thread in two"
- OP_MAIN_CHANGE_FOLDER "open a different folder"
- OP_MAIN_CHANGE_FOLDER_READONLY "open a different folder in read only mode"
-+OP_MAIN_CHANGE_GROUP "open a different newsgroup"
-+OP_MAIN_CHANGE_GROUP_READONLY "open a different newsgroup in read only mode"
- OP_MAIN_CLEAR_FLAG "clear a status flag from a message"
- OP_MAIN_DELETE_PATTERN "delete messages matching a pattern"
- OP_MAIN_IMAP_FETCH "force retrieval of mail from IMAP server"
-@@ -127,6 +141,7 @@
- OP_MAIN_SET_FLAG "set a status flag on a message"
- OP_MAIN_SYNC_FOLDER "save changes to mailbox"
- OP_MAIN_TAG_PATTERN "tag messages matching a pattern"
-+OP_MAIN_QUASI_DELETE "delete from mutt, don't touch on disk"
- OP_MAIN_UNDELETE_PATTERN "undelete messages matching a pattern"
- OP_MAIN_UNTAG_PATTERN "untag messages matching a pattern"
- OP_MIDDLE_PAGE "move to the middle of the page"
-@@ -138,14 +153,17 @@
- OP_PAGER_SKIP_QUOTED "skip beyond quoted text"
- OP_PAGER_TOP "jump to the top of the message"
- OP_PIPE "pipe message/attachment to a shell command"
-+OP_POST "post message to newsgroup"
- OP_PREV_ENTRY "move to the previous entry"
- OP_PREV_LINE "scroll up one line"
- OP_PREV_PAGE "move to the previous page"
- OP_PRINT "print the current entry"
-+OP_PURGE_MESSAGE "really delete the current entry, bypassing the trash folder"
- OP_QUERY "query external program for addresses"
- OP_QUERY_APPEND "append new query results to current results"
- OP_QUIT "save changes to mailbox and quit"
- OP_RECALL_MESSAGE "recall a postponed message"
-+OP_RECONSTRUCT_THREAD "reconstruct thread containing current message"
- OP_REDRAW "clear and redraw the screen"
- OP_REFORMAT_WINCH "{internal}"
- OP_RENAME_MAILBOX "rename the current mailbox (IMAP only)"
-@@ -160,22 +178,27 @@
- OP_SHELL_ESCAPE "invoke a command in a subshell"
- OP_SORT "sort messages"
- OP_SORT_REVERSE "sort messages in reverse order"
-+OP_SUBSCRIBE_PATTERN "subscribe to newsgroups matching a pattern"
- OP_TAG "tag the current entry"
- OP_TAG_PREFIX "apply next function to tagged messages"
- OP_TAG_PREFIX_COND "apply next function ONLY to tagged messages"
- OP_TAG_SUBTHREAD "tag the current subthread"
- OP_TAG_THREAD "tag the current thread"
- OP_TOGGLE_NEW "toggle a message's 'new' flag"
-+OP_TOGGLE_READ "toggle view of read messages"
- OP_TOGGLE_WRITE "toggle whether the mailbox will be rewritten"
- OP_TOGGLE_MAILBOXES "toggle whether to browse mailboxes or all files"
- OP_TOP_PAGE "move to the top of the page"
-+OP_UNCATCHUP "mark all articles in newsgroup as unread"
- OP_UNDELETE "undelete the current entry"
- OP_UNDELETE_THREAD "undelete all messages in thread"
- OP_UNDELETE_SUBTHREAD "undelete all messages in subthread"
-+OP_UNSUBSCRIBE_PATTERN "unsubscribe from newsgroups matching a pattern"
- OP_VERSION "show the Mutt version number and date"
- OP_VIEW_ATTACH "view attachment using mailcap entry if necessary"
- OP_VIEW_ATTACHMENTS "show MIME attachments"
- OP_WHAT_KEY "display the keycode for a key press"
-+OP_LIMIT_CURRENT_THREAD "limit view to current thread"
- OP_MAIN_SHOW_LIMIT "show currently active limit pattern"
- OP_MAIN_COLLAPSE_THREAD "collapse/uncollapse current thread"
- OP_MAIN_COLLAPSE_ALL "collapse/uncollapse all threads"
-diff -urN mutt-1.6.1/OPS.NOTMUCH mutt-1.6.1-neomutt/OPS.NOTMUCH
---- mutt-1.6.1/OPS.NOTMUCH	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/OPS.NOTMUCH	2016-06-12 18:43:00.664451676 +0100
-@@ -0,0 +1,5 @@
-+OP_MAIN_CHANGE_VFOLDER "open a different virtual folder"
-+OP_MAIN_VFOLDER_FROM_QUERY "generate virtual folder from query"
-+OP_MAIN_MODIFY_LABELS "modify (notmuch) tags"
-+OP_MAIN_MODIFY_LABELS_THEN_HIDE "modify labeld and then hide message"
-+OP_MAIN_ENTIRE_THREAD "read entire thread of the current message"
-diff -urN mutt-1.6.1/OPS.SIDEBAR mutt-1.6.1-neomutt/OPS.SIDEBAR
---- mutt-1.6.1/OPS.SIDEBAR	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/OPS.SIDEBAR	2016-06-12 18:43:00.664451676 +0100
-@@ -0,0 +1,9 @@
-+OP_SIDEBAR_NEXT "Move the highlight to next mailbox"
-+OP_SIDEBAR_NEXT_NEW "Move the highlight to next mailbox with new mail"
-+OP_SIDEBAR_OPEN "Open highlighted mailbox"
-+OP_SIDEBAR_PAGE_DOWN "Scroll the Sidebar down 1 page"
-+OP_SIDEBAR_PAGE_UP "Scroll the Sidebar up 1 page"
-+OP_SIDEBAR_PREV "Move the highlight to previous mailbox"
-+OP_SIDEBAR_PREV_NEW "Move the highlight to previous mailbox with new mail"
-+OP_SIDEBAR_TOGGLE_VIRTUAL "toggle between mailboxes and virtual mailboxes"
-+OP_SIDEBAR_TOGGLE_VISIBLE "Make the Sidebar (in)visible"
-diff -urN mutt-1.6.1/pager.c mutt-1.6.1-neomutt/pager.c
---- mutt-1.6.1/pager.c	2016-06-12 18:43:00.412447746 +0100
-+++ mutt-1.6.1-neomutt/pager.c	2016-06-12 18:43:00.721452565 +0100
-@@ -29,6 +29,9 @@
- #include "pager.h"
- #include "attach.h"
- #include "mbyte.h"
-+#ifdef USE_SIDEBAR
-+#include "sidebar.h"
-+#endif
- 
- #include "mutt_crypt.h"
- 
-@@ -1085,6 +1088,11 @@
-   return b_read;
- }
- 
-+#ifdef USE_NNTP
-+#include "mx.h"
-+#include "nntp.h"
-+#endif
++	dprint(2, (debugfile, "nm: rename: rem '%s'\n", old));
++	st = notmuch_database_remove_message(db, old);
++	switch (st) {
++	case NOTMUCH_STATUS_SUCCESS:
++		break;
++	case NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID:
++		dprint(2, (debugfile, "nm: rename: syncing duplicate filename\n"));
++		notmuch_message_destroy(msg);
++		msg = NULL;
++		notmuch_database_find_message_by_filename(db, new, &msg);
 +
- 
- static int format_line (struct line_t **lineInfo, int n, unsigned char *buf,
- 			int flags, ansi_attr *pa, int cnt,
-@@ -1491,7 +1499,7 @@
-    * a newline (grr!).
-    */
- #ifndef USE_SLANG_CURSES
--    if (col < COLS)
-+    if (col < (COLS - SidebarWidth))
- #endif
-       addch ('\n');
- 
-@@ -1542,6 +1550,16 @@
-   { NULL,	0 }
- };
- 
-+#ifdef USE_NNTP
-+static struct mapping_t PagerNewsHelpExtra[] = {
-+  { N_("Post"),     OP_POST },
-+  { N_("Followup"), OP_FOLLOWUP },
-+  { N_("Del"),      OP_DELETE },
-+  { N_("Next"),     OP_MAIN_NEXT_UNDELETED },
-+  { NULL,           0 }
-+};
-+#endif
++		for (ls = notmuch_message_get_filenames(msg);
++		     msg && ls && notmuch_filenames_valid(ls);
++		     notmuch_filenames_move_to_next(ls)) {
 +
- 
- 
- /* This pager is actually not so simple as it once was.  It now operates in
-@@ -1573,6 +1591,7 @@
- 
-   int bodyoffset = 1;			/* offset of first line of real text */
-   int statusoffset = 0; 		/* offset for the status bar */
-+  int statuswidth = COLS;
-   int helpoffset = LINES - 2;		/* offset for the help bar. */
-   int bodylen = LINES - 2 - bodyoffset; /* length of displayable area */
- 
-@@ -1583,6 +1602,10 @@
-   int old_PagerIndexLines;		/* some people want to resize it
-   					 * while inside the pager... */
- 
-+#ifdef USE_NNTP
-+  char *followup_to;
-+#endif
++			const char *path = notmuch_filenames_get(ls);
++			char newpath[_POSIX_PATH_MAX];
 +
-   if (!(flags & M_SHOWCOLOR))
-     flags |= M_SHOWFLAT;
- 
-@@ -1622,7 +1645,11 @@
-   if (IsHeader (extra))
-   {
-     strfcpy (tmphelp, helpstr, sizeof (tmphelp));
--    mutt_compile_help (buffer, sizeof (buffer), MENU_PAGER, PagerHelpExtra);
-+    mutt_compile_help (buffer, sizeof (buffer), MENU_PAGER,
-+#ifdef USE_NNTP
-+	(Context && (Context->magic == M_NNTP)) ? PagerNewsHelpExtra :
-+#endif
-+	PagerHelpExtra);
-     snprintf (helpstr, sizeof (helpstr), "%s %s", tmphelp, buffer);
-   }
-   if (!InHelp)
-@@ -1747,7 +1774,7 @@
-     if ((redraw & REDRAW_BODY) || topline != oldtopline)
-     {
-       do {
--	move (bodyoffset, 0);
-+	move (bodyoffset, SidebarWidth);
- 	curline = oldtopline = topline;
- 	lines = 0;
- 	force_redraw = 0;
-@@ -1760,6 +1787,9 @@
- 			    &QuoteList, &q_level, &force_redraw, &SearchRE) > 0)
- 	    lines++;
- 	  curline++;
-+#ifdef USE_SIDEBAR
-+	  move (lines + bodyoffset, SidebarWidth);
-+#endif
- 	}
- 	last_offset = lineInfo[curline].offset;
-       } while (force_redraw);
-@@ -1772,6 +1802,9 @@
- 	  addch ('~');
- 	addch ('\n');
- 	lines++;
-+#ifdef USE_SIDEBAR
-+	move (lines + bodyoffset, SidebarWidth);
-+#endif
-       }
-       NORMAL_COLOR;
- 
-@@ -1789,29 +1822,49 @@
-       hfi.ctx = Context;
-       hfi.pager_progress = pager_progress_str;
- 
-+#ifdef USE_SIDEBAR
-+      statuswidth = COLS;
-+      if (option (OPTSTATUSONTOP) && (PagerIndexLines > 0))
-+        statuswidth -= SidebarWidth;
-+#endif
++			if (strcmp(new, path) == 0)
++				continue;
 +
-       if (last_pos < sb.st_size - 1)
- 	snprintf(pager_progress_str, sizeof(pager_progress_str), OFF_T_FMT "%%", (100 * last_offset / sb.st_size));
-       else
- 	strfcpy(pager_progress_str, (topline == 0) ? "all" : "end", sizeof(pager_progress_str));
- 
-       /* print out the pager status bar */
--      move (statusoffset, 0);
-+      move (statusoffset, SidebarWidth);
-       SETCOLOR (MT_COLOR_STATUS);
-+#ifdef USE_SIDEBAR
-+      short sw = SidebarWidth;
-+      if (option (OPTSTATUSONTOP) && PagerIndexLines > 0) {
-+        CLEARLINE_WIN (statusoffset);
-+      } else {
-+        CLEARLINE (statusoffset);
-+        /* Temporarily lie about the sidebar width */
-+        SidebarWidth = 0;
-+      }
-+#endif
- 
-       if (IsHeader (extra) || IsMsgAttach (extra))
-       {
--	size_t l1 = COLS * MB_LEN_MAX;
-+	size_t l1 = statuswidth * MB_LEN_MAX;
- 	size_t l2 = sizeof (buffer);
- 	hfi.hdr = (IsHeader (extra)) ? extra->hdr : extra->bdy->hdr;
- 	mutt_make_string_info (buffer, l1 < l2 ? l1 : l2, NONULL (PagerFmt), &hfi, M_FORMAT_MAKEPRINT);
--	mutt_paddstr (COLS, buffer);
-+	mutt_draw_statusline (statuswidth, buffer);
-       }
-       else
-       {
- 	char bn[STRING];
- 	snprintf (bn, sizeof (bn), "%s (%s)", banner, pager_progress_str);
--	mutt_paddstr (COLS, bn);
-+	mutt_draw_statusline (statuswidth, bn);
-       }
-+#ifdef USE_SIDEBAR
-+      if (!option (OPTSTATUSONTOP) || PagerIndexLines == 0)
-+        SidebarWidth = sw; /* Restore the sidebar width */
-+#endif
-       NORMAL_COLOR;
-       if (option(OPTTSENABLED) && TSSupported)
-       {
-@@ -1827,16 +1880,26 @@
-       /* redraw the pager_index indicator, because the
-        * flags for this message might have changed. */
-       menu_redraw_current (index);
-+#ifdef USE_SIDEBAR
-+      mutt_sb_draw();
-+#endif
- 
-       /* print out the index status bar */
-       menu_status_line (buffer, sizeof (buffer), index, NONULL(Status));
-  
--      move (indexoffset + (option (OPTSTATUSONTOP) ? 0 : (indexlen - 1)), 0);
-+      move (indexoffset + (option (OPTSTATUSONTOP) ? 0 : (indexlen - 1)),
-+          (option(OPTSTATUSONTOP) ? 0: SidebarWidth));
-       SETCOLOR (MT_COLOR_STATUS);
--      mutt_paddstr (COLS, buffer);
-+      mutt_paddstr (COLS - (option(OPTSTATUSONTOP) ? 0 : SidebarWidth), buffer);
-       NORMAL_COLOR;
-     }
- 
-+#ifdef USE_SIDEBAR
-+    /* if we're not using the index, update every time */
-+    if (index == 0)
-+      mutt_sb_draw();
-+#endif
++			dprint(2, (debugfile, "nm: rename: syncing duplicate: %s\n", path));
 +
-     redraw = 0;
- 
-     if (option(OPTBRAILLEFRIENDLY)) {
-@@ -2249,11 +2312,11 @@
- 	  int dretval = 0;
- 	  int new_topline = topline;
- 
--	  while ((new_topline < lastLine ||
-+	  while (((new_topline + SkipQuotedOffset) < lastLine ||
- 		  (0 == (dretval = display_line (fp, &last_pos, &lineInfo,
- 			 new_topline, &lastLine, &maxLine, M_TYPES | (flags & M_PAGER_NOWRAP),
- 			 &QuoteList, &q_level, &force_redraw, &SearchRE))))
--		 && lineInfo[new_topline].type != MT_COLOR_QUOTED)
-+		 && lineInfo[new_topline + SkipQuotedOffset].type != MT_COLOR_QUOTED)
- 	    new_topline++;
- 
- 	  if (dretval < 0)
-@@ -2262,11 +2325,11 @@
- 	    break;
- 	  }
- 
--	  while ((new_topline < lastLine ||
-+	  while (((new_topline + SkipQuotedOffset) < lastLine ||
- 		  (0 == (dretval = display_line (fp, &last_pos, &lineInfo,
- 			 new_topline, &lastLine, &maxLine, M_TYPES | (flags & M_PAGER_NOWRAP),
- 			 &QuoteList, &q_level, &force_redraw, &SearchRE))))
--		 && lineInfo[new_topline].type == MT_COLOR_QUOTED)
-+		 && lineInfo[new_topline + SkipQuotedOffset].type == MT_COLOR_QUOTED)
- 	    new_topline++;
- 
- 	  if (dretval < 0)
-@@ -2351,6 +2414,7 @@
- 	MAYBE_REDRAW (redraw);
- 	break;
- 
-+      case OP_PURGE_MESSAGE:
-       case OP_DELETE:
- 	CHECK_MODE(IsHeader (extra));
- 	CHECK_READONLY;
-@@ -2358,6 +2422,8 @@
- 	CHECK_ACL(M_ACL_DELETE, _("Cannot delete message"));
- 
- 	mutt_set_flag (Context, extra->hdr, M_DELETE, 1);
-+	mutt_set_flag (Context, extra->hdr, M_PURGED,
-+		       ch != OP_PURGE_MESSAGE ? 0 : 1);
-         if (option (OPTDELETEUNTAG))
- 	  mutt_set_flag (Context, extra->hdr, M_TAG, 0);
- 	redraw = REDRAW_STATUS | REDRAW_INDEX;
-@@ -2498,8 +2564,12 @@
- 	  ch = 0;
- 	}
- 
--	if (option (OPTFORCEREDRAWPAGER))
-+	if (option (OPTFORCEREDRAWPAGER)) {
- 	  redraw = REDRAW_FULL;
-+#ifdef USE_SIDEBAR
-+	  mutt_sb_draw();
-+#endif
++			if (rename_maildir_filename(path, newpath, sizeof(newpath), h) == 0) {
++				dprint(2, (debugfile, "nm: rename dup %s -> %s\n", path, newpath));
++				notmuch_database_remove_message(db, path);
++				notmuch_database_add_message(db, newpath, NULL);
++			}
++		}
++		notmuch_message_destroy(msg);
++		msg = NULL;
++		notmuch_database_find_message_by_filename(db, new, &msg);
++		st = NOTMUCH_STATUS_SUCCESS;
++		break;
++	default:
++		dprint(1, (debugfile, "nm: failed to remove '%s' [st=%d]\n",
++					old, (int) st));
++		break;
++	}
++
++	if (st == NOTMUCH_STATUS_SUCCESS && h && msg) {
++		notmuch_message_maildir_flags_to_tags(msg);
++		update_header_tags(h, msg);
++		update_tags(msg, nm_header_get_tags(h));
 +	}
- 	unset_option (OPTFORCEREDRAWINDEX);
- 	unset_option (OPTFORCEREDRAWPAGER);
- 	break;
-@@ -2543,6 +2613,60 @@
- 	redraw = REDRAW_FULL;
- 	break;
- 
-+#ifdef USE_NNTP
-+      case OP_POST:
-+	CHECK_MODE(IsHeader (extra) && !IsAttach (extra));
-+	CHECK_ATTACH;
-+	if (extra->ctx && extra->ctx->magic == M_NNTP &&
-+	    !((NNTP_DATA *)extra->ctx->data)->allowed &&
-+	    query_quadoption (OPT_TOMODERATED,_("Posting to this group not allowed, may be moderated. Continue?")) != M_YES)
-+	  break;
-+	ci_send_message (SENDNEWS, NULL, NULL, extra->ctx, NULL);
-+	redraw = REDRAW_FULL;
-+	break;
 +
-+      case OP_FORWARD_TO_GROUP:
-+	CHECK_MODE(IsHeader (extra) || IsMsgAttach (extra));
-+	CHECK_ATTACH;
-+	if (extra->ctx && extra->ctx->magic == M_NNTP &&
-+	    !((NNTP_DATA *)extra->ctx->data)->allowed &&
-+	    query_quadoption (OPT_TOMODERATED,_("Posting to this group not allowed, may be moderated. Continue?")) != M_YES)
-+	  break;
-+	if (IsMsgAttach (extra))
-+	  mutt_attach_forward (extra->fp, extra->hdr, extra->idx,
-+			       extra->idxlen, extra->bdy, SENDNEWS);
-+	else
-+	  ci_send_message (SENDNEWS|SENDFORWARD, NULL, NULL, extra->ctx, extra->hdr);
-+	redraw = REDRAW_FULL;
-+	break;
++	rc = 0;
++done:
++	if (msg)
++		notmuch_message_destroy(msg);
++	if (trans)
++		db_trans_end(data);
++	return rc;
++}
 +
-+      case OP_FOLLOWUP:
-+	CHECK_MODE(IsHeader (extra) || IsMsgAttach (extra));
-+	CHECK_ATTACH;
++int nm_update_filename(CONTEXT *ctx, const char *old, const char *new, HEADER *h)
++{
++	char buf[PATH_MAX];
++	int rc;
++	struct nm_ctxdata *data = get_ctxdata(ctx);
 +
-+	if (IsMsgAttach (extra))
-+	  followup_to = extra->bdy->hdr->env->followup_to;
-+	else
-+	  followup_to = extra->hdr->env->followup_to;
++	if (!data || !new)
++		return -1;
 +
-+	if (!followup_to || mutt_strcasecmp (followup_to, "poster") ||
-+	    query_quadoption (OPT_FOLLOWUPTOPOSTER,_("Reply by mail as poster prefers?")) != M_YES)
-+	{
-+	  if (extra->ctx && extra->ctx->magic == M_NNTP &&
-+	      !((NNTP_DATA *)extra->ctx->data)->allowed &&
-+	      query_quadoption (OPT_TOMODERATED,_("Posting to this group not allowed, may be moderated. Continue?")) != M_YES)
-+	    break;
-+	  if (IsMsgAttach (extra))
-+	    mutt_attach_reply (extra->fp, extra->hdr, extra->idx,
-+			       extra->idxlen, extra->bdy, SENDNEWS|SENDREPLY);
-+	  else
-+	    ci_send_message (SENDNEWS|SENDREPLY, NULL, NULL,
-+			     extra->ctx, extra->hdr);
-+	  redraw = REDRAW_FULL;
-+	  break;
++	if (!old && h && h->data) {
++		nm_header_get_fullpath(h, buf, sizeof(buf));
++		old = buf;
 +	}
-+#endif
 +
-       case OP_REPLY:
- 	CHECK_MODE(IsHeader (extra) || IsMsgAttach (extra));
-         CHECK_ATTACH;      
-@@ -2589,7 +2713,7 @@
-         CHECK_ATTACH;
-         if (IsMsgAttach (extra))
- 	  mutt_attach_forward (extra->fp, extra->hdr, extra->idx,
--			       extra->idxlen, extra->bdy);
-+			       extra->idxlen, extra->bdy, 0);
-         else
- 	  ci_send_message (SENDFORWARD, NULL, NULL, extra->ctx, extra->hdr);
- 	redraw = REDRAW_FULL;
-@@ -2688,6 +2812,7 @@
- 	CHECK_ACL(M_ACL_DELETE, _("Cannot undelete message"));
- 
- 	mutt_set_flag (Context, extra->hdr, M_DELETE, 0);
-+	mutt_set_flag (Context, extra->hdr, M_PURGED, 0);
- 	redraw = REDRAW_STATUS | REDRAW_INDEX;
- 	if (option (OPTRESOLVE))
- 	{
-@@ -2704,9 +2829,11 @@
- 	CHECK_ACL(M_ACL_DELETE, _("Cannot undelete message(s)"));
- 
- 	r = mutt_thread_set_flag (extra->hdr, M_DELETE, 0,
-+				  ch == OP_UNDELETE_THREAD ? 0 : 1)
-+	  + mutt_thread_set_flag (extra->hdr, M_PURGED, 0,
- 				  ch == OP_UNDELETE_THREAD ? 0 : 1);
- 
--	if (r != -1)
-+	if (r > -1)
- 	{
- 	  if (option (OPTRESOLVE))
- 	  {
-@@ -2744,6 +2871,18 @@
- 	redraw = REDRAW_FULL;
- 	break;
- 
-+     case OP_EDIT_LABEL:
-+        CHECK_MODE(IsHeader (extra));
-+        rc = mutt_label_message(extra->hdr);
-+        if (rc > 0) {
-+          Context->changed = 1;
-+          redraw = REDRAW_FULL;
-+          mutt_message ("%d label%s changed.", rc, rc == 1 ? "" : "s");
-+        }
-+        else {
-+          mutt_message _("No labels changed.");
-+        }
-+        break;
- 
-       case OP_MAIL_KEY:
-         if (!(WithCrypto & APPLICATION_PGP))
-@@ -2777,6 +2916,22 @@
- 	mutt_what_key ();
- 	break;
- 
-+#ifdef USE_SIDEBAR
-+      case OP_SIDEBAR_NEXT:
-+      case OP_SIDEBAR_NEXT_NEW:
-+      case OP_SIDEBAR_PAGE_DOWN:
-+      case OP_SIDEBAR_PAGE_UP:
-+      case OP_SIDEBAR_PREV:
-+      case OP_SIDEBAR_PREV_NEW:
-+	mutt_sb_change_mailbox (ch);
-+	break;
++	rc = rename_filename(data, old, new, h);
 +
-+      case OP_SIDEBAR_TOGGLE_VISIBLE:
-+	toggle_option (OPTSIDEBAR);
-+	redraw = REDRAW_FULL;
-+	break;
-+#endif
++	if (!is_longrun(data))
++		release_db(data);
++	ctx->mtime = time(NULL);
++	return rc;
++}
 +
-       default:
- 	ch = -1;
- 	break;
-diff -urN mutt-1.6.1/parse.c mutt-1.6.1-neomutt/parse.c
---- mutt-1.6.1/parse.c	2016-06-12 18:43:00.412447746 +0100
-+++ mutt-1.6.1-neomutt/parse.c	2016-06-12 18:43:00.721452565 +0100
-@@ -94,7 +94,7 @@
-   /* not reached */
- }
- 
--static LIST *mutt_parse_references (char *s, int in_reply_to)
-+LIST *mutt_parse_references (char *s, int in_reply_to)
- {
-   LIST *t, *lst = NULL;
-   char *m;
-@@ -981,6 +981,7 @@
- {
-   int matched = 0;
-   LIST *last = NULL;
-+  int kwtype = 0;
-   
-   if (lastp)
-     last = *lastp;
-@@ -1077,6 +1078,17 @@
-       e->from = rfc822_parse_adrlist (e->from, p);
-       matched = 1;
-     }
-+#ifdef USE_NNTP
-+    else if (!mutt_strcasecmp (line+1, "ollowup-to"))
-+    {
-+      if (!e->followup_to)
-+      {
-+	mutt_remove_trailing_ws (p);
-+	e->followup_to = safe_strdup (mutt_skip_whitespace (p));
-+      }
-+      matched = 1;
-+    }
-+#endif
-     break;
-     
-     case 'i':
-@@ -1087,7 +1099,14 @@
-       matched = 1;
-     }
-     break;
--    
++int nm_sync(CONTEXT *ctx, int *index_hint)
++{
++	struct nm_ctxdata *data = get_ctxdata(ctx);
++	int i, rc = 0;
++	char msgbuf[STRING];
++	progress_t progress;
++	char *uri = ctx->path;
++	int changed = 0;
 +
-+    case 'k':
-+    if (!ascii_strcasecmp (line+1, "eywords"))
-+    {
-+      kwtype = M_KEYWORDS;
-+    }
-+    break;
++	if (!data)
++		return -1;
 +
-     case 'l':
-     if (!ascii_strcasecmp (line + 1, "ines"))
-     {
-@@ -1159,6 +1178,27 @@
-     }
-     break;
-     
-+#ifdef USE_NNTP
-+    case 'n':
-+    if (!mutt_strcasecmp (line + 1, "ewsgroups"))
-+    {
-+      FREE (&e->newsgroups);
-+      mutt_remove_trailing_ws (p);
-+      e->newsgroups = safe_strdup (mutt_skip_whitespace (p));
-+      matched = 1;
-+    }
-+    break;
-+#endif
++	dprint(1, (debugfile, "nm: sync start ...\n"));
 +
-+    case 'o':
-+    /* field `Organization:' saves only for pager! */
-+    if (!mutt_strcasecmp (line + 1, "rganization"))
-+    {
-+      if (!e->organization && mutt_strcasecmp (p, "unknown"))
-+	e->organization = safe_strdup (p);
-+    }
-+    break;
++	if (!ctx->quiet) {
++		/* all is in this function so we don't use data->progress here */
++		snprintf(msgbuf, sizeof (msgbuf), _("Writing %s..."), ctx->path);
++		mutt_progress_init(&progress, msgbuf, M_PROGRESS_MSG,
++				   WriteInc, ctx->msgcount);
++	}
 +
-     case 'r':
-     if (!ascii_strcasecmp (line + 1, "eferences"))
-     {
-@@ -1267,15 +1307,35 @@
-     }
-     else if (ascii_strcasecmp (line+1, "-label") == 0)
-     {
--      FREE(&e->x_label);
--      e->x_label = safe_strdup(p);
-+      kwtype = M_X_LABEL;
-+    }
-+    else if (!ascii_strcasecmp (line+1, "-keywords"))
-+    {
-+      kwtype = M_X_KEYWORDS;
-+    }
-+    else if (!ascii_strcasecmp (line+1, "-mozilla-keys"))
-+    {
-+      kwtype = M_X_MOZILLA_KEYS;
-+    }
-+#ifdef USE_NNTP
-+    else if (!mutt_strcasecmp (line + 1, "-comment-to"))
-+    {
-+      if (!e->x_comment_to)
-+	e->x_comment_to = safe_strdup (p);
-       matched = 1;
-     }
--    
-+    else if (!mutt_strcasecmp (line + 1, "ref"))
-+    {
-+      if (!e->xref)
-+	e->xref = safe_strdup (p);
-+      matched = 1;
-+    }
++	for (i = 0; i < ctx->msgcount; i++) {
++		char old[_POSIX_PATH_MAX], new[_POSIX_PATH_MAX];
++		HEADER *h = ctx->hdrs[i];
++		struct nm_hdrdata *hd = h->data;
++
++		if (!ctx->quiet)
++			mutt_progress_update(&progress, i, -1);
++
++		*old = *new = '\0';
++
++		if (hd->oldpath) {
++			strncpy(old, hd->oldpath, sizeof(old));
++			old[sizeof(old) - 1] = '\0';
++			dprint(2, (debugfile, "nm: fixing obsolete path '%s'\n", old));
++		} else
++			nm_header_get_fullpath(h, old, sizeof(old));
++
++		ctx->path = hd->folder;
++		ctx->magic = hd->magic;
++#if USE_HCACHE
++		rc = mh_sync_mailbox_message(ctx, i, NULL);
++#else
++		rc = mh_sync_mailbox_message(ctx, i);
 +#endif
++		ctx->path = uri;
++		ctx->magic = M_NOTMUCH;
 +
-     default:
-     break;
-   }
--  
++		if (rc)
++			break;
 +
-   /* Keep track of the user-defined headers */
-   if (!matched && user_hdrs)
-   {
-@@ -1298,12 +1358,59 @@
-       rfc2047_decode (&last->data);
-   }
- 
-+  if (kwtype)
-+  {
-+    char *last, *label;
-+    char *text = strdup(p);
-+    char *sep;
++		if (!h->deleted)
++			nm_header_get_fullpath(h, new, sizeof(new));
 +
-+    if (kwtype == M_KEYWORDS)
-+      sep = ",";
-+    else if (kwtype == M_X_LABEL)
-+      sep = XlabelDelim;
-+    else
-+      sep = " ";
++		if (h->deleted || strcmp(old, new) != 0) {
++			if (h->deleted && remove_filename(data, old) == 0)
++				changed = 1;
++			else if (*new && *old && rename_filename(data, old, new, h) == 0)
++				changed = 1;
++		}
 +
-+    rfc2047_decode(&text);
-+    if (sep == NULL || *sep == '\0')
-+    {
-+      SKIPWS(text);
-+      if (!mutt_find_list(e->labels, text))
-+      {
-+        if (e->labels)
-+          mutt_add_list(e->labels, text);
-+        else
-+        {
-+          e->labels = mutt_new_list();
-+          e->labels->data = safe_strdup(text);
-+        }
-+      }
-+    }
-+    else for (label = strtok_r(text, sep, &last); label;
-+              label = strtok_r(NULL, sep, &last))
-+    {
-+      SKIPWS(label);
-+      if (mutt_find_list(e->labels, label))
-+        continue;
-+      if (e->labels)
-+        mutt_add_list(e->labels, label);
-+      else
-+      {
-+        e->labels = mutt_new_list();
-+        e->labels->data = safe_strdup(label);
-+      }
-+    }
-+    e->kwtypes |= kwtype;
-+    kwtype = 0;
-+    matched = 1;
-+  }
++		FREE(&hd->oldpath);
++	}
 +
-   done:
-   
-   *lastp = last;
-   return matched;
- }
--  
++	ctx->path = uri;
++	ctx->magic = M_NOTMUCH;
 +
-   
- /* mutt_read_rfc822_header() -- parses a RFC822 header
-  *
-@@ -1441,7 +1548,6 @@
-     rfc2047_decode_adrlist (e->mail_followup_to);
-     rfc2047_decode_adrlist (e->return_path);
-     rfc2047_decode_adrlist (e->sender);
--    rfc2047_decode (&e->x_label);
- 
-     if (e->subject)
-     {
-diff -urN mutt-1.6.1/PATCHES mutt-1.6.1-neomutt/PATCHES
---- mutt-1.6.1/PATCHES	2016-06-12 18:43:00.395447481 +0100
-+++ mutt-1.6.1-neomutt/PATCHES	2016-06-12 18:43:00.669451754 +0100
-@@ -0,0 +1,17 @@
-+patch-quasi-delete-neo-20160612
-+patch-progress-neo-20160612
-+patch-status-color-neo-20160612
-+patch-index-color-neo-20160612
-+patch-nested-if-neo-20160612
-+patch-cond-date-neo-20160612
-+patch-tls-sni-neo-20160612
-+patch-sidebar-neo-20160612
-+patch-ifdef-neo-20160612
-+patch-fmemopen-neo-20160612
-+patch-initials-neo-20160612
-+patch-trash-neo-20160612
-+patch-limit-current-thread-neo-20160612
-+patch-skip-quoted-neo-20160612
-+patch-compress-neo-20160612
-+patch-keywords-neo-20160612
-+patch-nntp-neo-20160612
-diff -urN mutt-1.6.1/patchlist.sh mutt-1.6.1-neomutt/patchlist.sh
---- mutt-1.6.1/patchlist.sh	2016-06-12 18:43:00.412447746 +0100
-+++ mutt-1.6.1-neomutt/patchlist.sh	2016-06-12 18:43:00.721452565 +0100
-@@ -1,21 +1,5 @@
- #!/bin/sh --
- 
--list_patches_PATCHES () {
--	cat -
--}
--
--list_patches_mq () {
--	hg qapplied | sed -e 's/^/mq-/'
--}
--
--list_patches () {
--	if [ -f .hg/patches/series ]; then
--		list_patches_mq
--	else
--		list_patches_PATCHES
--	fi
--}
--
- cat <<EOF
- /* this is an autogenerated file.  edit patchlist.sh instead. */
- #include "config.h"
-@@ -29,7 +13,7 @@
- {
- EOF
- 
--list_patches | while read patch ; do
-+cat - | while read patch ; do
- 	echo "  puts (\"${patch}\");"
- done
- 
-diff -urN mutt-1.6.1/pattern.c mutt-1.6.1-neomutt/pattern.c
---- mutt-1.6.1/pattern.c	2016-06-12 18:43:00.413447762 +0100
-+++ mutt-1.6.1-neomutt/pattern.c	2016-06-12 18:43:00.721452565 +0100
-@@ -42,6 +42,10 @@
- #include "imap/imap.h"
- #endif
- 
-+#ifdef USE_NOTMUCH
-+#include "mutt_notmuch.h"
-+#endif
++	if (!is_longrun(data))
++		release_db(data);
++	if (changed)
++		ctx->mtime = time(NULL);
 +
- static int eat_regexp (pattern_t *pat, BUFFER *, BUFFER *);
- static int eat_date (pattern_t *pat, BUFFER *, BUFFER *);
- static int eat_range (pattern_t *pat, BUFFER *, BUFFER *);
-@@ -92,9 +96,15 @@
-   { 'U', M_UNREAD,		0,		NULL },
-   { 'v', M_COLLAPSED,		0,		NULL },
-   { 'V', M_CRYPT_VERIFIED,	0,		NULL },
-+#ifdef USE_NNTP
-+  { 'w', M_NEWSGROUPS,		0,		eat_regexp },
-+#endif
-   { 'x', M_REFERENCE,		0,		eat_regexp },
-   { 'X', M_MIMEATTACH,		0,		eat_range },
-   { 'y', M_XLABEL,		0,		eat_regexp },
-+#ifdef USE_NOTMUCH
-+  { 'Y', M_NOTMUCH_LABEL,	0,		eat_regexp },
-+#endif
-   { 'z', M_SIZE,		0,		eat_range },
-   { '=', M_DUPLICATED,		0,		NULL },
-   { '$', M_UNREFERENCED,	0,		NULL },
-@@ -144,16 +154,21 @@
- static int
- msg_search (CONTEXT *ctx, pattern_t* pat, int msgno)
- {
--  char tempfile[_POSIX_PATH_MAX];
-   MESSAGE *msg = NULL;
-   STATE s;
--  struct stat st;
-   FILE *fp = NULL;
-   long lng = 0;
-   int match = 0;
-   HEADER *h = ctx->hdrs[msgno];
-   char *buf;
-   size_t blen;
-+#ifdef HAVE_FMEMOPEN
-+  char *temp;
-+  size_t tempsize;
-+#else
-+  char tempfile[_POSIX_PATH_MAX];
-+  struct stat st;
-+#endif
- 
-   if ((msg = mx_open_message (ctx, msgno)) != NULL)
-   {
-@@ -163,12 +178,20 @@
-       memset (&s, 0, sizeof (s));
-       s.fpin = msg->fp;
-       s.flags = M_CHARCONV;
-+#ifdef HAVE_FMEMOPEN
-+      s.fpout = open_memstream (&temp, &tempsize);
-+      if (!s.fpout) {
-+	mutt_perror ("Error opening memstream");
-+	return 0;
-+      }
-+#else
-       mutt_mktemp (tempfile, sizeof (tempfile));
-       if ((s.fpout = safe_fopen (tempfile, "w+")) == NULL)
-       {
- 	mutt_perror (tempfile);
- 	return (0);
-       }
-+#endif
- 
-       if (pat->op != M_BODY)
- 	mutt_copy_header (msg->fp, h, s.fpout, CH_FROM | CH_DECODE, NULL);
-@@ -184,7 +207,11 @@
- 	  if (s.fpout)
- 	  {
- 	    safe_fclose (&s.fpout);
-+#ifdef HAVE_FMEMOPEN
-+            FREE(&temp);
-+#else
- 	    unlink (tempfile);
-+#endif
- 	  }
- 	  return (0);
- 	}
-@@ -193,11 +220,30 @@
- 	mutt_body_handler (h->content, &s);
-       }
- 
-+#ifdef HAVE_FMEMOPEN
-+      fclose (s.fpout);
-+      lng = tempsize;
++	dprint(1, (debugfile, "nm: .... sync done [rc=%d]\n", rc));
++	return rc;
++}
 +
-+      if (tempsize) {
-+        fp = fmemopen (temp, tempsize, "r");
-+        if (!fp) {
-+          mutt_perror ("Error re-opening memstream");
-+          return 0;
-+        }
-+      } else { /* fmemopen cannot handle empty buffers */
-+        fp = safe_fopen ("/dev/null", "r");
-+        if (!fp) {
-+          mutt_perror ("Error opening /dev/null");
-+          return 0;
-+        }
-+      }
-+#else
-       fp = s.fpout;
-       fflush (fp);
-       fseek (fp, 0, 0);
-       fstat (fileno (fp), &st);
-       lng = (long) st.st_size;
-+#endif
-     }
-     else
-     {
-@@ -244,7 +290,12 @@
-     if (option (OPTTHOROUGHSRC))
-     {
-       safe_fclose (&fp);
-+#ifdef HAVE_FMEMOPEN
-+      if (tempsize)
-+        FREE(&temp);
++static unsigned count_query(notmuch_database_t *db, const char *qstr)
++{
++	unsigned res = 0;
++	notmuch_query_t *q = notmuch_query_create(db, qstr);
++
++	if (q) {
++		apply_exclude_tags(q);
++#if LIBNOTMUCH_CHECK_VERSION(4,3,0)
++		if (notmuch_query_count_messages_st (q, &res) != NOTMUCH_STATUS_SUCCESS)
++			res = 0;	/* may not be defined on error */
 +#else
-       unlink (tempfile);
-+#endif
-     }
-   }
- 
-@@ -1209,7 +1260,26 @@
-        break;
-      return (pat->not ^ ((h->security & APPLICATION_PGP) && (h->security & PGPKEY)));
-     case M_XLABEL:
--      return (pat->not ^ (h->env->x_label && patmatch (pat, h->env->x_label) == 0));
-+      {
-+        LIST *label;
-+        int result = 0;
-+        for (label = h->env->labels; label; label = label->next)
-+        {
-+          if (label->data == NULL)
-+            continue;
-+          result = patmatch (pat, label->data) == 0;
-+          if (result)
-+            break;
-+        }
-+        return pat->not ^ result;
-+      }
-+#ifdef USE_NOTMUCH
-+    case M_NOTMUCH_LABEL:
-+      {
-+      char *tags = nm_header_get_tags(h);
-+      return (pat->not ^ (tags && patmatch (pat, tags) == 0));
-+      }
++		res = notmuch_query_count_messages(q);
 +#endif
-     case M_HORMEL:
-       return (pat->not ^ (h->env->spam && h->env->spam->data && patmatch (pat, h->env->spam->data) == 0));
-     case M_DUPLICATED:
-@@ -1222,6 +1292,10 @@
-       }
-     case M_UNREFERENCED:
-       return (pat->not ^ (h->thread && !h->thread->child));
-+#ifdef USE_NNTP
-+    case M_NEWSGROUPS:
-+      return (pat->not ^ (h->env->newsgroups && patmatch (pat, h->env->newsgroups) == 0));
++		notmuch_query_destroy(q);
++		dprint(1, (debugfile, "nm: count '%s', result=%d\n", qstr, res));
++	}
++	return res;
++}
++
++int nm_nonctx_get_count(char *path, int *all, int *new)
++{
++	struct uri_tag *query_items = NULL, *item;
++	char *db_filename = NULL, *db_query = NULL;
++	notmuch_database_t *db = NULL;
++	int rc = -1, dflt = 0;
++
++	dprint(1, (debugfile, "nm: count\n"));
++
++	if (url_parse_query(path, &db_filename, &query_items)) {
++		mutt_error(_("failed to parse notmuch uri: %s"), path);
++		goto done;
++	}
++	if (!query_items)
++		goto done;
++
++	for (item = query_items; item; item = item->next) {
++		if (item->value && strcmp(item->name, "query") == 0) {
++			db_query = item->value;
++			break;
++		}
++	}
++
++	if (!db_query)
++		goto done;
++
++	if (!db_filename) {
++		if (NotmuchDefaultUri) {
++			if (strncmp(NotmuchDefaultUri, "notmuch://", 10) == 0)
++				db_filename = NotmuchDefaultUri + 10;
++			else
++				db_filename = NotmuchDefaultUri;
++		} else if (Maildir)
++			db_filename = Maildir;
++		dflt = 1;
++	}
++
++	/* don't be verbose about connection, as we're called from
++	 * sidebar/buffy very often */
++	db = do_database_open(db_filename, FALSE, FALSE);
++	if (!db)
++		goto done;
++
++	/* all emails */
++	if (all)
++		*all = count_query(db, db_query);
++
++	/* new messages */
++	if (new) {
++		char *qstr;
++
++		safe_asprintf(&qstr, "( %s ) tag:%s",
++				db_query, NotmuchUnreadTag);
++		*new = count_query(db, qstr);
++		FREE(&qstr);
++	}
++
++	rc = 0;
++done:
++	if (db) {
++#ifdef NOTMUCH_API_3
++		notmuch_database_destroy(db);
++#else
++		notmuch_database_close(db);
 +#endif
-   }
-   mutt_error (_("error: unknown op %d (report this error)."), pat->op);
-   return (-1);
-@@ -1294,6 +1368,74 @@
-   }
- }
- 
-+/**
-+ * top_of_thread - Find the first email in the current thread
-+ * @h: Header of current email
-+ *
-+ * Returns:
-+ *	THREAD*: success, email found
-+ *	NULL:    on error
++		dprint(1, (debugfile, "nm: count close DB\n"));
++	}
++	if (!dflt)
++		FREE(&db_filename);
++	url_free_tags(query_items);
++
++	dprint(1, (debugfile, "nm: count done [rc=%d]\n", rc));
++	return rc;
++}
++
++char *nm_get_description(CONTEXT *ctx)
++{
++	BUFFY *p;
++
++	for (p = VirtIncoming; p; p = p->next)
++		if (p->desc && strcmp(p->path, ctx->path) == 0)
++			return p->desc;
++
++	return NULL;
++}
++
++int nm_description_to_path(const char *desc, char *buf, size_t bufsz)
++{
++	BUFFY *p;
++
++	if (!desc || !buf || !bufsz)
++		return -EINVAL;
++
++	for (p = VirtIncoming; p; p = p->next)
++		if (p->desc && strcmp(desc, p->desc) == 0) {
++			strncpy(buf, p->path, bufsz);
++			buf[bufsz - 1] = '\0';
++			return 0;
++		}
++
++	return -1;
++}
++
++/*
++ * returns header from mutt context
 + */
-+static THREAD *
-+top_of_thread (HEADER *h)
++static HEADER *get_mutt_header(CONTEXT *ctx, notmuch_message_t *msg)
 +{
-+	THREAD *t;
++	char *mid;
++	const char *id;
++	HEADER *h;
 +
-+	if (!h)
++	if (!ctx || !msg)
++		return NULL;
++
++	id = notmuch_message_get_message_id(msg);
++	if (!id)
 +		return NULL;
 +
-+	t = h->thread;
++	dprint(2, (debugfile, "nm: mutt header, id='%s'\n", id));
++
++	if (!ctx->id_hash) {
++		dprint(2, (debugfile, "nm: init hash\n"));
++		ctx->id_hash = mutt_make_id_hash(ctx);
++		if (!ctx->id_hash)
++			return NULL;
++	}
++
++	mid = nm2mutt_message_id( id );
++	dprint(2, (debugfile, "nm: mutt id='%s'\n", mid));
++
++	h = hash_find(ctx->id_hash, mid);
++	FREE(&mid);
++	return h;
++}
++
++int nm_check_database(CONTEXT *ctx, int *index_hint)
++{
++	struct nm_ctxdata *data = get_ctxdata(ctx);
++	time_t mtime = 0;
++	notmuch_query_t *q;
++	notmuch_messages_t *msgs;
++	int i, limit, occult = 0, new_flags = 0;
++
++	if (!data || get_database_mtime(data, &mtime) != 0)
++		return -1;
++
++	if (ctx->mtime >= mtime) {
++		dprint(2, (debugfile, "nm: check unnecessary (db=%d ctx=%d)\n", mtime, ctx->mtime));
++		return 0;
++	}
++
++	dprint(1, (debugfile, "nm: checking (db=%d ctx=%d)\n", mtime, ctx->mtime));
++
++	q = get_query(data, FALSE);
++	if (!q)
++		goto done;
++
++	dprint(1, (debugfile, "nm: start checking (count=%d)\n", ctx->msgcount));
++	data->oldmsgcount = ctx->msgcount;
++	data->noprogress = 1;
++
++	for (i = 0; i < ctx->msgcount; i++)
++		ctx->hdrs[i]->active = 0;
++
++	limit = get_limit(data);
++
++#if LIBNOTMUCH_CHECK_VERSION(4,3,0)
++	if (notmuch_query_search_messages_st (q, &msgs) != NOTMUCH_STATUS_SUCCESS)
++		goto done;
++#else
++	msgs = notmuch_query_search_messages(q);
++#endif
++
++	for (i = 0;
++	     notmuch_messages_valid(msgs) && (limit == 0 || i < limit);
++	     notmuch_messages_move_to_next(msgs), i++) {
++
++		char old[_POSIX_PATH_MAX];
++		const char *new;
++
++		notmuch_message_t *m = notmuch_messages_get(msgs);
++		HEADER *h = get_mutt_header(ctx, m);
++
++		if (!h) {
++			/* new email */
++			append_message(ctx, NULL, m, 0);
++			notmuch_message_destroy(m);
++			continue;
++		}
++
++		/* message already exists, merge flags */
++		h->active = 1;
++
++		/* check to see if the message has moved to a different
++		 * subdirectory.  If so, update the associated filename.
++		 */
++		new = get_message_last_filename(m);
++		nm_header_get_fullpath(h, old, sizeof(old));
++
++		if (mutt_strcmp(old, new) != 0)
++			update_message_path(h, new);
 +
-+	while (t && t->parent)
-+		t = t->parent;
++		if (!h->changed) {
++			/* if the user hasn't modified the flags on
++			 * this message, update the flags we just
++			 * detected.
++			 */
++			HEADER tmp;
++			memset(&tmp, 0, sizeof(tmp));
++			maildir_parse_flags(&tmp, new);
++			maildir_update_flags(ctx, h, &tmp);
++		}
 +
-+	return t;
-+}
++		if (update_header_tags(h, m) == 0)
++			new_flags++;
 +
-+/**
-+ * mutt_limit_current_thread - Limit the email view to the current thread
-+ * @h: Header of current email
-+ *
-+ * Returns:
-+ *	1: Success
-+ *	0: Failure
-+ */
-+int
-+mutt_limit_current_thread (HEADER *h)
-+{
-+	int i;
-+	THREAD *me;
++		notmuch_message_destroy(m);
++	}
 +
-+	if (!h)
-+		return 0;
++	for (i = 0; i < ctx->msgcount; i++) {
++		if (ctx->hdrs[i]->active == 0) {
++			occult = 1;
++			break;
++		}
++	}
 +
-+	me = top_of_thread (h);
-+	if (!me)
-+		return 0;
++	if (ctx->msgcount > data->oldmsgcount)
++		mx_update_context(ctx, ctx->msgcount - data->oldmsgcount);
++done:
++	if (q)
++		notmuch_query_destroy(q);
 +
-+	Context->vcount    = 0;
-+	Context->vsize     = 0;
-+	Context->collapsed = 0;
++	if (!is_longrun(data))
++		release_db(data);
 +
-+	for (i = 0; i < Context->msgcount; i++) {
-+		Context->hdrs[i]->virtual    = -1;
-+		Context->hdrs[i]->limited    = 0;
-+		Context->hdrs[i]->collapsed  = 0;
-+		Context->hdrs[i]->num_hidden = 0;
++	ctx->mtime = time(NULL);
 +
-+		if (top_of_thread (Context->hdrs[i]) == me) {
-+			BODY *body = Context->hdrs[i]->content;
++	dprint(1, (debugfile, "nm: ... check done [count=%d, new_flags=%d, occult=%d]\n",
++				ctx->msgcount, new_flags, occult));
 +
-+			Context->hdrs[i]->virtual = Context->vcount;
-+			Context->hdrs[i]->limited = 1;
-+			Context->v2r[Context->vcount] = i;
-+			Context->vcount++;
-+			Context->vsize += (body->length + body->offset - body->hdr_offset);
-+		}
-+	}
-+	return 1;
++	return occult ? M_REOPENED :
++	       ctx->msgcount > data->oldmsgcount ? M_NEW_MAIL :
++	       new_flags ? M_FLAGS : 0;
 +}
 +
- int mutt_pattern_func (int op, char *prompt)
- {
-   pattern_t *pat;
-@@ -1303,6 +1445,7 @@
-   progress_t progress;
- 
-   strfcpy (buf, NONULL (Context->pattern), sizeof (buf));
-+  if (prompt || op != M_LIMIT)
-   if (mutt_get_field (prompt, buf, sizeof (buf), M_PATTERN | M_CLEAR) != 0 || !buf[0])
-     return (-1);
- 
-@@ -1367,8 +1510,9 @@
-       {
- 	switch (op)
- 	{
--	  case M_DELETE:
- 	  case M_UNDELETE:
-+	    mutt_set_flag (Context, Context->hdrs[Context->v2r[i]], M_PURGED, 0);
-+	  case M_DELETE:
- 	    mutt_set_flag (Context, Context->hdrs[Context->v2r[i]], M_DELETE, 
- 			  (op == M_DELETE));
- 	    break;
-diff -urN mutt-1.6.1/po/de.po mutt-1.6.1-neomutt/po/de.po
---- mutt-1.6.1/po/de.po	2016-06-12 18:43:00.413447762 +0100
-+++ mutt-1.6.1-neomutt/po/de.po	2016-06-12 18:43:00.730452705 +0100
-@@ -2141,6 +2141,10 @@
- msgid "Bad history file format (line %d)"
- msgstr "Falsches Format der Datei fr�herer Eingaben (Zeile %d)"
- 
-+#: hook.c:96
-+msgid "badly formatted command string"
-+msgstr "Hook enth�lt nicht die Muster %f und %t"
-+
- #: hook.c:93
- msgid "current mailbox shortcut '^' is unset"
- msgstr ""
-@@ -2922,7 +2926,7 @@
- msgid "Mailbox is corrupt!"
- msgstr "Mailbox fehlerhaft!"
- 
--#: mbox.c:670
-+#: compress.c:203 mbox.c:661
- msgid "Mailbox was corrupted!"
- msgstr "Mailbox wurde zerst�rt!"
- 
-@@ -2930,7 +2934,7 @@
- msgid "Fatal error!  Could not reopen mailbox!"
- msgstr "Fataler Fehler, konnte Mailbox nicht erneut �ffnen!"
- 
--#: mbox.c:760
-+#: compress.c:246 compress.c:367 compress.c:443 mbox.c:706
- msgid "Unable to lock mailbox!"
- msgstr "Kann Mailbox nicht f�r exklusiven Zugriff sperren!"
- 
-@@ -5394,6 +5398,40 @@
- #~ msgid "Warning: Intermediate certificate not found."
- #~ msgstr "Warnung: Zwischenzertifikat nicht gefunden."
- 
-+#: compress.c:228 compress.c:253
-+#, c-format
-+msgid "Decompressing %s...\n"
-+msgstr "Entpacke %s...\n"
-+
-+#: compress.c:264
-+#, c-format
-+msgid "Error executing: %s : unable to open the mailbox!\n"
-+msgstr "Fehler beim Ausf�hren von %s : Kann die Mailbox nicht �ffnen!\n"
-+
-+#: compress.c:350 compress.c:377 compress.c:423 compress.c:454
-+#, c-format
-+msgid "Compressing %s...\n"
-+msgstr "Komprimiere %s...\n"
-+
-+#: compress.c:381
-+#, c-format
-+msgid ""
-+"%s: Error compressing mailbox! Original mailbox deleted, uncompressed one "
-+"kept!\n"
-+msgstr ""
-+"%s: Fehler beim Komprimieren der Mailbox! Urspr�ngliche Mailbox gel�scht, "
-+"entpackte gespeichert!\n"
-+
-+#: compress.c:425 compress.c:456
-+#, c-format
-+msgid "Compressed-appending to %s...\n"
-+msgstr "H�nge komprimiert an %s... an\n"
-+
-+#: compress.c:461
-+#, c-format
-+msgid " %s: Error compressing mailbox!  Uncompressed one kept!\n"
-+msgstr " %s: Fehler beim packen der Mailbox! Entpackte Mailbox gespeichert!\n"
-+
- #~ msgid "Clear"
- #~ msgstr "Klartext"
- 
-diff -urN mutt-1.6.1/po/POTFILES.in mutt-1.6.1-neomutt/po/POTFILES.in
---- mutt-1.6.1/po/POTFILES.in	2016-06-12 18:43:00.413447762 +0100
-+++ mutt-1.6.1-neomutt/po/POTFILES.in	2016-06-12 18:43:00.723452596 +0100
-@@ -8,6 +8,7 @@
- color.c
- commands.c
- compose.c
-+compress.c
- crypt-gpgme.c
- crypt.c
- cryptglue.c
-@@ -46,6 +47,8 @@
- mutt_tunnel.c
- muttlib.c
- mx.c
-+newsrc.c
-+nntp.c
- pager.c
- parse.c
- pattern.c
-diff -urN mutt-1.6.1/postpone.c mutt-1.6.1-neomutt/postpone.c
---- mutt-1.6.1/postpone.c	2016-06-12 18:43:00.414447777 +0100
-+++ mutt-1.6.1-neomutt/postpone.c	2016-06-12 18:43:00.745452939 +0100
-@@ -125,15 +125,26 @@
- 
-   if (LastModify < st.st_mtime)
-   {
-+#ifdef USE_NNTP
-+    int optnews = option (OPTNEWS);
-+#endif
-     LastModify = st.st_mtime;
- 
-     if (access (Postponed, R_OK | F_OK) != 0)
-       return (PostCount = 0);
-+#ifdef USE_NNTP
-+    if (optnews)
-+	unset_option (OPTNEWS);
-+#endif
-     if (mx_open_mailbox (Postponed, M_NOSORT | M_QUIET, &ctx) == NULL)
-       PostCount = 0;
-     else
-       PostCount = ctx.msgcount;
-     mx_fastclose_mailbox (&ctx);
-+#ifdef USE_NNTP
-+    if (optnews)
-+	set_option (OPTNEWS);
-+#endif
-   }
- 
-   return (PostCount);
-@@ -277,6 +288,9 @@
-   /* finished with this message, so delete it. */
-   mutt_set_flag (PostContext, h, M_DELETE, 1);
- 
-+  /* and consider it saved, so that it won't be moved to the trash folder */
-+  mutt_set_flag (PostContext, h, M_APPENDED, 1);
-+
-   /* update the count for the status display */
-   PostCount = PostContext->msgcount - PostContext->deleted;
- 
-diff -urN mutt-1.6.1/protos.h mutt-1.6.1-neomutt/protos.h
---- mutt-1.6.1/protos.h	2016-06-12 18:43:00.414447777 +0100
-+++ mutt-1.6.1-neomutt/protos.h	2016-06-12 18:43:00.745452939 +0100
-@@ -1,5 +1,6 @@
- /*
-  * Copyright (C) 1996-2000,2007,2010,2013 Michael R. Elkins <me at mutt.org>
-+ * Copyright (C) 2013 Karel Zak <kzak at redhat.com>
-  * 
-  *     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
-@@ -79,6 +80,9 @@
- void mutt_delete_parameter (const char *attribute, PARAMETER **p);
- void mutt_set_parameter (const char *, const char *, PARAMETER **);
- 
-+#ifdef USE_NOTMUCH
-+int mutt_parse_virtual_mailboxes (BUFFER *path, BUFFER *s, unsigned long data, BUFFER *err);
-+#endif
- 
- FILE *mutt_open_read (const char *, pid_t *);
- 
-@@ -111,6 +115,7 @@
- HASH *mutt_make_subj_hash (CONTEXT *);
- 
- LIST *mutt_make_references(ENVELOPE *e);
-+LIST *mutt_parse_references (char *, int);
- 
- char *mutt_read_rfc822_line (FILE *, char *, size_t *);
- ENVELOPE *mutt_read_rfc822_header (FILE *, HEADER *, short, short);
-@@ -180,10 +185,17 @@
- void mutt_default_save (char *, size_t, HEADER *);
- void mutt_display_address (ENVELOPE *);
- void mutt_display_sanitize (char *);
-+void mutt_draw_statusline (int n, char *);
- void mutt_edit_content_type (HEADER *, BODY *, FILE *);
- void mutt_edit_file (const char *, const char *);
- void mutt_edit_headers (const char *, const char *, HEADER *, char *, size_t);
- int mutt_filter_unprintable (char **);
-+void mutt_label_ref_dec(ENVELOPE *);
-+void mutt_label_ref_inc(ENVELOPE *);
-+int mutt_label_message (HEADER *);
-+void mutt_scan_labels (CONTEXT *);
-+int mutt_label_complete (char *, size_t, int, int);
-+char *mutt_labels(char *, int, ENVELOPE *, char *);
- void mutt_curses_error (const char *, ...);
- void mutt_curses_message (const char *, ...);
- void mutt_encode_descriptions (BODY *, short);
-@@ -284,6 +296,10 @@
- int mutt_check_traditional_pgp (HEADER *, int *);
- int mutt_command_complete (char *, size_t, int, int);
- int mutt_var_value_complete (char *, size_t, int);
-+#if USE_NOTMUCH
-+int mutt_nm_query_complete (char *buffer, size_t len, int pos, int numtabs);
-+int mutt_nm_tag_complete (char *buffer, size_t len, int pos, int numtabs);
-+#endif
- int mutt_complete (char *, size_t);
- int mutt_compose_attachment (BODY *a);
- int mutt_copy_body (FILE *, BODY **, BODY *);
-@@ -299,8 +315,10 @@
- int mutt_parent_message (CONTEXT *, HEADER *);
- int mutt_prepare_template(FILE*, CONTEXT *, HEADER *, HEADER *, short);
- int mutt_resend_message (FILE *, CONTEXT *, HEADER *);
--#define mutt_enter_fname(A,B,C,D,E) _mutt_enter_fname(A,B,C,D,E,0,NULL,NULL)
--int _mutt_enter_fname (const char *, char *, size_t, int *, int, int, char ***, int *);
-+#define mutt_enter_fname(A,B,C,D,E) _mutt_enter_fname(A,B,C,D,E,0,NULL,NULL,0)
-+#define mutt_enter_vfolder(A,B,C,D,E) _mutt_enter_fname(A,B,C,D,E,0,NULL,NULL,M_SEL_VFOLDER)
++int nm_record_message(CONTEXT *ctx, char *path, HEADER *h)
++{
++	notmuch_database_t *db;
++	notmuch_status_t st;
++	notmuch_message_t *msg = NULL;
++	int rc = -1, trans;
++	struct nm_ctxdata *data = get_ctxdata(ctx);
 +
-+int _mutt_enter_fname (const char *, char *, size_t, int *, int, int, char ***, int *, int);
- int  mutt_enter_string (char *buf, size_t buflen, int y, int x, int flags);
- int _mutt_enter_string (char *, size_t, int, int, int, int, char ***, int *, ENTER_STATE *);
- #define mutt_get_field(A,B,C,D) _mutt_get_field(A,B,C,D,0,NULL,NULL)
-@@ -365,7 +383,7 @@
- void mutt_update_num_postponed (void);
- int mutt_wait_filter (pid_t);
- int mutt_which_case (const char *);
--int mutt_write_fcc (const char *path, HEADER *hdr, const char *msgid, int, char *);
-+int mutt_write_fcc (const char *path, HEADER *hdr, const char *msgid, int, char *, char **);
- int mutt_write_mime_body (BODY *, FILE *);
- int mutt_write_mime_header (BODY *, FILE *);
- int mutt_write_one_header (FILE *fp, const char *tag, const char *value, const char *pfx, int wraplen, int flags);
-@@ -375,6 +393,11 @@
- void mutt_set_header_color(CONTEXT *, HEADER *);
- void mutt_sleep (short);
- int mutt_save_confirm (const char  *, struct stat *);
-+void mutt_randbuf(void *out, size_t len);
-+#define MUTT_RANDTAG_LEN (16)
-+void mutt_rand_base32(void *out, size_t len);
-+uint32_t mutt_rand32(void);
-+uint64_t mutt_rand64(void);
- 
- int mh_valid_message (const char *);
- 
-@@ -422,16 +445,6 @@
- #define LONGLONG long
- #endif
- 
--#ifdef HAVE_SRAND48
--#define LRAND lrand48
--#define SRAND srand48
--#define DRAND drand48
--#else
--#define LRAND rand
--#define SRAND srand
--#define DRAND (double)rand
--#endif /* HAVE_SRAND48 */
--
- /* HP-UX, ConvexOS and UNIXware don't have this macro */
- #ifndef S_ISLNK
- #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK ? 1 : 0)
-@@ -565,3 +578,11 @@
- #ifndef HAVE_MKDTEMP
- char *mkdtemp (char *tmpl);
- #endif
++	if (!path || !data || access(path, F_OK) != 0)
++		return 0;
++	db = get_db(data, TRUE);
++	if (!db)
++		return -1;
 +
-+#ifndef HAVE_STRNLEN
-+size_t strnlen(const char *s, size_t maxlen);
-+#endif
++	dprint(1, (debugfile, "nm: record message: %s\n", path));
++	trans = db_trans_begin(data);
++	if (trans < 0)
++		goto done;
 +
-+#ifndef strndup
-+char *strndup(const char *s, size_t n);
-+#endif
-diff -urN mutt-1.6.1/README.compress mutt-1.6.1-neomutt/README.compress
---- mutt-1.6.1/README.compress	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/README.compress	2016-06-12 18:43:00.669451754 +0100
-@@ -0,0 +1,165 @@
-+Compressed Folders Patch
-+========================
++	st = notmuch_database_add_message(db, path, &msg);
 +
-+    Read from/write to compressed mailboxes
++	if (st != NOTMUCH_STATUS_SUCCESS &&
++	    st != NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID) {
++		dprint(1, (debugfile, "nm: failed to add '%s' [st=%d]\n", path, (int) st));
++		goto done;
++	}
 +
-+Patch
-+-----
++	if (st == NOTMUCH_STATUS_SUCCESS && msg) {
++		notmuch_message_maildir_flags_to_tags(msg);
++		if (h)
++			update_tags(msg, nm_header_get_tags(h));
++		if (NotmuchRecordTags)
++			update_tags(msg, NotmuchRecordTags);
++	}
 +
-+    To check if Mutt supports "Compress Folders", look for "+USE_COMPRESSED" in
-+    the mutt version.
++	rc = 0;
++done:
++	if (msg)
++		notmuch_message_destroy(msg);
++	if (trans == 1)
++		db_trans_end(data);
++	if (!is_longrun(data))
++		release_db(data);
++	return rc;
++}
 +
-+    Dependencies
-+    * mutt-1.5.24
++/*
++ * Fill a list with all notmuch tags.
++ *
++ * If tag_list is NULL, just count the tags.
++ */
++int nm_get_all_tags(CONTEXT *ctx, char **tag_list, int *tag_count)
++{
++	struct nm_ctxdata *data = get_ctxdata(ctx);
++	notmuch_database_t *db = NULL;
++	notmuch_tags_t *tags = NULL;
++	int rc = -1;
 +
-+Introduction
-+------------
++	if (!data)
++		return -1;
 +
-+    The Compressed Folder patch allows Mutt to read mailbox files that are
-+    compressed. But it isn't limited to compressed files. It works well with
-+    encrypted files, too. In fact, if you can create a program/script to
-+    convert to and from your format, then Mutt can read it.
++	if (!(db = get_db(data, FALSE)) ||
++			!(tags = notmuch_database_get_all_tags(db)))
++		goto done;
 +
-+    The patch adds three hooks to Mutt: 'open-hook', 'close-hook' and
-+    'append-hook'. They define commands to: uncompress a file; compress a file;
-+    append messages to an already compressed file.
++	*tag_count = 0;
++	dprint(1, (debugfile, "nm: get all tags\n"));
 +
-+    There are some examples of both compressed and encrypted files, later. For
-+    now, the documentation will just concentrate on compressed files.
++	while (notmuch_tags_valid(tags)) {
++		if (tag_list != NULL) {
++			tag_list[*tag_count] = safe_strdup(notmuch_tags_get(tags));
++		}
++		(*tag_count)++;
++		notmuch_tags_move_to_next(tags);
++	}
 +
-+Commands
-+--------
++	rc = 0;
++done:
++	if (tags)
++		notmuch_tags_destroy(tags);
 +
-+        open-hook   pattern shell-command
-+        close-hook  pattern shell-command
-+        append-hook pattern shell-command
++	if (!is_longrun(data))
++		release_db(data);
 +
-+    The shell-command must contain two placeholders for filenames: '%f' and
-+    '%t'. These represent "from" and "to" filenames. It's a good idea to put
-+    quotes around these placeholders.
++	dprint(1, (debugfile, "nm: get all tags done [rc=%d tag_count=%u]\n", rc,
++						 *tag_count));
++	return rc;
++}
+diff --git a/mutt_notmuch.h b/mutt_notmuch.h
+new file mode 100644
+index 0000000..df4baa2
+--- /dev/null
++++ b/mutt_notmuch.h
+@@ -0,0 +1,39 @@
++/*
++ * Copyright (C) 2011 Karel Zak <kzak at redhat.com>
++ */
++#ifndef _MUTT_NOTMUCH_H_
++#define _MUTT_NOTMUCH_H_ 1
 +
-+    If you need the exact string "%f" or "%t" in your command, simply double up
-+    the "%" character, e.g. "%%f" or "%%t".
++int nm_read_query(CONTEXT *ctx);
++int nm_read_entire_thread(CONTEXT *ctx, HEADER *h);
 +
-+    Not all Hooks are Required
++int nm_sync(CONTEXT * ctx, int *index_hint);
++int nm_check_database(CONTEXT * ctx, int *index_hint);
++char *nm_header_get_folder(HEADER *h);
++int nm_header_get_magic(HEADER *h);
++char *nm_header_get_fullpath(HEADER *h, char *buf, size_t bufsz);
++int nm_update_filename(CONTEXT *ctx, const char *o, const char *n, HEADER *h);
++char *nm_uri_from_query(CONTEXT *ctx, char *buf, size_t bufsz);
++int nm_modify_message_tags(CONTEXT *ctx, HEADER *hdr, char *tags);
 +
-+    | Open | Close | Append | Effect                                      | Useful if                                       |
-+    |------|-------|--------|---------------------------------------------|-------------------------------------------------|
-+    | Open | -     | -      | Folder is readonly                          | Folder is just a backup                         |
-+    | Open | Close | -      | Folder is read/write, but the entire folder | Compression format doesn't support appending    |
-+    |      |       |        |     must be written if anything is changed  | Compression format doesn't support appending    |
-+    | Open | Close | Append | Folder is read/write and emails can be      | Compression format supports appending           |
-+    |      |       |        |     efficiently added to the end            | Compression format supports appending           |
-+    | Open | -     | Append | Folder is readonly, but can be appended to  | You want to store emails, but never change them |
++void nm_longrun_init(CONTEXT *cxt, int writable);
++void nm_longrun_done(CONTEXT *cxt);
 +
-+    > Note
-+    >
-+    > The command:
-+    > -   should return a non-zero exit status on failure
-+    > -   should not delete any files
++char *nm_get_description(CONTEXT *ctx);
++int nm_description_to_path(const char *desc, char *buf, size_t bufsz);
 +
-+### Read from compressed mailbox
++int nm_record_message(CONTEXT *ctx, char *path, HEADER *h);
 +
-+        open-hook regexp shell-command
++void nm_debug_check(CONTEXT *ctx);
++int nm_get_all_tags(CONTEXT *ctx, char **tag_list, int *tag_count);
 +
-+    If Mutt is unable to open a file, it then looks for 'open-hook' that
-+    matches the filename.
++/*
++ * functions usable outside notmuch CONTEXT
++ */
++int nm_nonctx_get_count(char *path, int *all, int *new);
++
++char *nm_header_get_tag_transformed(char *tag, HEADER *h);
++char *nm_header_get_tags_transformed(HEADER *h);
++char *nm_header_get_tags(HEADER *h);
++
++#endif /* _MUTT_NOTMUCH_H_ */
+diff --git a/mutt_sasl.c b/mutt_sasl.c
+index 0a00c81..1da5ea5 100644
+--- a/mutt_sasl.c
++++ b/mutt_sasl.c
+@@ -190,6 +190,11 @@ int mutt_sasl_client_new (CONNECTION* conn, sasl_conn_t** saslconn)
+     case M_ACCT_TYPE_SMTP:
+       service = "smtp";
+       break;
++#ifdef USE_NNTP
++    case M_ACCT_TYPE_NNTP:
++      service = "nntp";
++      break;
++#endif
+     default:
+       mutt_error (_("Unknown SASL profile"));
+       return -1;
+diff --git a/mutt_ssl.c b/mutt_ssl.c
+index a6cdd10..44ee99b 100644
+--- a/mutt_ssl.c
++++ b/mutt_ssl.c
+@@ -401,6 +401,18 @@ static int ssl_negotiate (CONNECTION *conn, sslsockdata* ssldata)
+   SSL_set_mode (ssldata->ssl, SSL_MODE_AUTO_RETRY);
+ #endif
+ 
++#if (OPENSSL_VERSION_NUMBER >= 0x0090806fL) && !defined(OPENSSL_NO_TLSEXT)
++  /* TLS Virtual-hosting requires that the server present the correct
++   * certificate; to do this, the ServerNameIndication TLS extension is used.
++   * If TLS is negotiated, and OpenSSL is recent enough that it might have
++   * support, and support was enabled when OpenSSL was built, mutt supports
++   * sending the hostname we think we're connecting to, so a server can send
++   * back the correct certificate.
++   * This has been tested over SMTP against Exim 4.80.
++   * Not yet found an IMAP server which supports this. */
++  SSL_set_tlsext_host_name (ssldata->ssl, conn->account.host);
++#endif
++
+   if ((err = SSL_connect (ssldata->ssl)) != 1)
+   {
+     switch (SSL_get_error (ssldata->ssl, err))
+@@ -432,14 +444,6 @@ static int ssl_negotiate (CONNECTION *conn, sslsockdata* ssldata)
+   if (!ssl_check_certificate (conn, ssldata))
+     return -1;
+ 
+-  /* L10N:
+-     %1$s is version (e.g. "TLSv1.2")
+-     %2$s is cipher_version (e.g. "TLSv1/SSLv3")
+-     %3$s is cipher_name (e.g. "ECDHE-RSA-AES128-GCM-SHA256") */
+-  mutt_message (_("%s connection using %s (%s)"),
+-    SSL_get_version(ssldata->ssl), SSL_get_cipher_version (ssldata->ssl), SSL_get_cipher_name (ssldata->ssl));
+-  mutt_sleep (0);
+-
+   return 0;
+ }
+ 
+diff --git a/muttlib.c b/muttlib.c
+index a57dbf4..3e7a2c3 100644
+--- a/muttlib.c
++++ b/muttlib.c
+@@ -32,11 +32,18 @@
+ #include "imap.h"
+ #endif
+ 
++#ifdef USE_NOTMUCH
++#include "mutt_notmuch.h"
++#endif
++
+ #include "mutt_crypt.h"
+ 
+ #include <string.h>
+ #include <ctype.h>
+ #include <unistd.h>
++#ifdef HAVE_SYS_SYSCALL_H
++#include <sys/syscall.h>
++#endif
+ #include <stdlib.h>
+ #include <sys/wait.h>
+ #include <errno.h>
+@@ -329,7 +336,9 @@ void mutt_free_header (HEADER **h)
+ #ifdef MIXMASTER
+   mutt_free_list (&(*h)->chain);
+ #endif
+-#if defined USE_POP || defined USE_IMAP
++#if defined USE_POP || defined USE_IMAP || defined USE_NOTMUCH || defined USE_NNTP
++  if ((*h)->free_cb)
++    (*h)->free_cb(*h);
+   FREE (&(*h)->data);
+ #endif
+   FREE (h);		/* __FREE_CHECKED__ */
+@@ -440,6 +449,11 @@ char *_mutt_expand_path (char *s, size_t slen, int rx)
+ 	  strfcpy (p, NONULL (Maildir), sizeof (p));
+ 	else
+ #endif
++#ifdef USE_NOTMUCH
++	if (mx_is_notmuch (NONULL (Maildir)))
++	  strfcpy (p, NONULL (Maildir), sizeof (p));
++	else
++#endif
+ 	if (Maildir && *Maildir && Maildir[strlen (Maildir) - 1] == '/')
+ 	  strfcpy (p, NONULL (Maildir), sizeof (p));
+ 	else
+@@ -714,12 +728,21 @@ void mutt_free_envelope (ENVELOPE **p)
+   FREE (&(*p)->supersedes);
+   FREE (&(*p)->date);
+   FREE (&(*p)->x_label);
++  FREE (&(*p)->organization);
++#ifdef USE_NNTP
++  FREE (&(*p)->newsgroups);
++  FREE (&(*p)->xref);
++  FREE (&(*p)->followup_to);
++  FREE (&(*p)->x_comment_to);
++#endif
+ 
+   mutt_buffer_free (&(*p)->spam);
+ 
+   mutt_free_list (&(*p)->references);
+   mutt_free_list (&(*p)->in_reply_to);
+   mutt_free_list (&(*p)->userhdrs);
++  mutt_label_ref_dec ((*p));
++  mutt_free_list (&(*p)->labels);
+   FREE (p);		/* __FREE_CHECKED__ */
+ }
+ 
+@@ -742,7 +765,7 @@ void mutt_merge_envelopes(ENVELOPE* base, ENVELOPE** extra)
+   MOVE_ELEM(message_id);
+   MOVE_ELEM(supersedes);
+   MOVE_ELEM(date);
+-  MOVE_ELEM(x_label);
++  MOVE_ELEM(labels);
+   if (!base->refs_changed)
+   {
+     MOVE_ELEM(references);
+@@ -771,12 +794,79 @@ void mutt_merge_envelopes(ENVELOPE* base, ENVELOPE** extra)
+   mutt_free_envelope(extra);
+ }
+ 
++static FILE *frandom;
 +
-+    If your compression program doesn't have a well-defined extension, then you
-+    can use '.' as the regexp.
++void mutt_randbuf(void *out, size_t len)
++{
++  if (len > 1048576) {
++    mutt_error (_("mutt_randbuf len=%zu"), len);
++    exit(1);
++  }
++  /* XXX switch to HAVE_GETRANDOM and getrandom() in about 2017 */
++#if defined(SYS_getrandom) && defined(__linux__)
++  static int whined;
++  long ret;
++  do {
++    ret = syscall(SYS_getrandom, out, len, 0, 0, 0, 0);
++  } while ((ret == -1) && (errno == EINTR));
++  if (ret == len) return;
++  if (!whined) {
++    mutt_error (_("getrandom failed: %s"), strerror(errno));
++    mutt_sleep (1);
++    whined = 1;
++  }
++  /* let's try urandom in case user has configured selinux or something
++   * to not allow getrandom */
++#endif
++  if (frandom == NULL) {
++    frandom = fopen("/dev/urandom", "rb");
++    if (frandom == NULL) {
++      mutt_error (_("open /dev/urandom: %s"), strerror(errno));
++      exit(1);
++    }
++    setbuf(frandom, NULL);
++  }
++  if (fread(out, 1, len, frandom) != len) {
++    mutt_error (_("read /dev/urandom: %s"), strerror(errno));
++    exit(1);
++  }
++}
 +
-+#### Example of open-hook
++static const unsigned char base32[] = "abcdefghijklmnopqrstuvwxyz234567";
 +
-+        open-hook '.gz$' "gzip -cd '%f' > '%t'"
++void mutt_rand_base32(void *out, size_t len)
++{
++  size_t pos;
++  uint8_t *p = out;
 +
-+    * Mutt finds a file, "example.gz", that it can't read
-+    * Mutt has an 'open-hook' whose regexp matches the filename: '.gz$'
-+    * Mutt uses the command 'gzip -cd' to create a temporary file that it *can*
-+    read
++  mutt_randbuf(p, len);
++  for (pos = 0; pos < len; pos++)
++    p[pos] = base32[p[pos] % 32];
++}
 +
-+### Write to a compressed mailbox
++uint32_t mutt_rand32(void)
++{
++  uint32_t ret;
 +
-+        close-hook regexp shell-command
++  mutt_randbuf(&ret, sizeof(ret));
++  return ret;
++}
 +
-+    When Mutt has finished with a compressed mail folder, it will look for a
-+    matching 'close-hook' to recompress the file. This hook is optional.
++uint64_t mutt_rand64(void)
++{
++  uint64_t ret;
 +
-+    > Note
-+    >
-+    > If the folder has not been modifed, the
-+    > close-hook
-+    > will not be called.
++  mutt_randbuf(&ret, sizeof(ret));
++  return ret;
++}
 +
-+#### Example of close-hook
 +
-+        close-hook '.gz$' "gzip -c '%t' > '%f'"
+ void _mutt_mktemp (char *s, size_t slen, const char *prefix, const char *suffix,
+                    const char *src, int line)
+ {
+-  size_t n = snprintf (s, slen, "%s/%s-%s-%d-%d-%ld%ld%s%s",
++  size_t n = snprintf (s, slen, "%s/%s-%s-%d-%d-%" PRIu64 "%s%s",
+       NONULL (Tempdir), NONULL (prefix), NONULL (Hostname),
+-      (int) getuid (), (int) getpid (), random (), random (),
++      (int) getuid (), (int) getpid (), mutt_rand64(),
+       suffix ? "." : "", NONULL (suffix));
+   if (n >= slen)
+     dprint (1, (debugfile, "%s:%d: ERROR: insufficient buffer space to hold temporary filename! slen=%zu but need %zu\n",
+@@ -819,6 +909,11 @@ void mutt_pretty_mailbox (char *s, size_t buflen)
+   }
+ #endif
+ 
++#ifdef USE_NOTMUCH
++  if (scheme == U_NOTMUCH)
++    return;
++#endif
 +
-+    * Mutt has finished with a folder, "example.gz", that it opened with
-+    'open-hook'
-+    * The folder has been modified
-+    * Mutt has a 'close-hook' whose regexp matches the filename: '.gz$'
-+    * Mutt uses the command 'gzip -c' to create a new compressed file
+   /* if s is an url, only collapse path component */
+   if (scheme != U_UNKNOWN)
+   {
+@@ -1053,6 +1148,7 @@ void mutt_safe_path (char *s, size_t l, ADDRESS *a)
+ void mutt_FormatString (char *dest,		/* output buffer */
+ 			size_t destlen,		/* output buffer len */
+ 			size_t col,		/* starting column (nonzero when called recursively) */
++                        int cols,               /* maximum columns */
+ 			const char *src,	/* template string */
+ 			format_t *callback,	/* callback for processing */
+ 			unsigned long data,	/* callback data */
+@@ -1117,7 +1213,7 @@ void mutt_FormatString (char *dest,		/* output buffer */
+         mutt_extract_token(word, srcbuf, 0);
+         dprint(3, (debugfile, "fmtpipe %2d: %s\n", i++, word->data));
+         mutt_buffer_addch(command, '\'');
+-        mutt_FormatString(buf, sizeof(buf), 0, word->data, callback, data,
++        mutt_FormatString(buf, sizeof(buf), 0, cols, word->data, callback, data,
+                           flags | M_FORMAT_NOFILTER);
+         for (p = buf; p && *p; p++)
+         {
+@@ -1172,7 +1268,7 @@ void mutt_FormatString (char *dest,		/* output buffer */
+ 		 * it back for the recursive call since the expansion of
+ 		 * format pipes does not try to append a nul itself.
+ 		 */
+-		mutt_FormatString(dest, destlen+1, col, recycler, callback, data, flags);
++		mutt_FormatString(dest, destlen+1, col, cols, recycler, callback, data, flags);
+ 		FREE(&recycler);
+ 	      }
+ 	    }
+@@ -1213,8 +1309,34 @@ void mutt_FormatString (char *dest,		/* output buffer */
+ 
+       if (*src == '?')
+       {
++	/* change original %? to new %< notation */
++	/* %?x?y&z? to %<x?y&z> where y and z are nestable */
++	char *p = (char *) src;
++	*p = '<';
++	for ( ; *p && *p != '?'; p++);
++	  /* nothing */
++	if (*p == '?') {
++	  p++;
++	}
++	for ( ; *p && *p != '?'; p++);
++	  /* nothing */
++	if (*p == '?') {
++	  *p = '>';
++	}
++      }
 +
-+### Append to a compressed mailbox
++      if (*src == '<')
++      {
+ 	flags |= M_FORMAT_OPTIONAL;
++	ch = *(++src); /* save the character to switch on */
+ 	src++;
++	cp = prefix;
++	count = 0;
++	while ((count < sizeof (prefix)) && (*src != '?')) {
++	  *cp++ = *src++;
++	  count++;
++	}
++	*cp = 0;
+       }
+       else
+       {
+@@ -1230,15 +1352,17 @@ void mutt_FormatString (char *dest,		/* output buffer */
+ 	  count++;
+ 	}
+ 	*cp = 0;
+-      }
+ 
+-      if (!*src)
+-	break; /* bad format */
++	if (!*src)
++	  break; /* bad format */
+ 
+-      ch = *src++; /* save the character to switch on */
++	ch = *src++; /* save the character to switch on */
++      }
+ 
+       if (flags & M_FORMAT_OPTIONAL)
+       {
++	int lrbalance;
 +
-+        append-hook regexp shell-command
+         if (*src != '?')
+           break; /* bad format */
+         src++;
+@@ -1246,8 +1370,20 @@ void mutt_FormatString (char *dest,		/* output buffer */
+         /* eat the `if' part of the string */
+         cp = ifstring;
+ 	count = 0;
+-        while (count < sizeof (ifstring) && *src && *src != '?' && *src != '&')
+-	{
++	lrbalance = 1;
++        while ((lrbalance > 0) && (count < sizeof (ifstring)) && *src) {
++	  if (*src == '\\') {
++	    src++;
++	    *cp++ = *src++;
++	  } else if ((src[0] == '%') && (src[1] == '<')) {
++	    lrbalance++;
++	  } else if (src[0] == '>') {
++	    lrbalance--;
++	  }
++	  if (lrbalance == 0)
++	    break;
++	  if ((lrbalance == 1) && (src[0] == '&'))
++	    break;
+           *cp++ = *src++;
+ 	  count++;
+ 	}
+@@ -1258,9 +1394,20 @@ void mutt_FormatString (char *dest,		/* output buffer */
+ 	  src++; /* skip the & */
+ 	cp = elsestring;
+ 	count = 0;
+-	while (count < sizeof (elsestring) && *src && *src != '?')
+-	{
+-	  *cp++ = *src++;
++	while ((lrbalance > 0) && (count < sizeof (elsestring)) && *src) {
++	  if (*src == '\\') {
++	    src++;
++	    *cp++ = *src++;
++	  } else if ((src[0] == '%') && (src[1] == '<')) {
++	    lrbalance++;
++	  } else if (src[0] == '>') {
++	    lrbalance--;
++	  }
++	  if (lrbalance == 0)
++	    break;
++	  if ((lrbalance == 1) && (src[0] == '&'))
++	    break;
++          *cp++ = *src++;
+ 	  count++;
+ 	}
+ 	*cp = 0;
+@@ -1268,7 +1415,7 @@ void mutt_FormatString (char *dest,		/* output buffer */
+ 	if (!*src)
+ 	  break; /* bad format */
+ 
+-        src++; /* move past the trailing `?' */
++        src++; /* move past the trailing `>' (formerly '?') */
+       }
+ 
+       /* handle generic cases first */
+@@ -1282,23 +1429,35 @@ void mutt_FormatString (char *dest,		/* output buffer */
+ 	  pl = pw = 1;
+ 
+ 	/* see if there's room to add content, else ignore */
+-	if ((col < COLS && wlen < destlen) || soft)
++	if ((col < cols && wlen < destlen) || soft)
+ 	{
+ 	  int pad;
+ 
+ 	  /* get contents after padding */
+-	  mutt_FormatString (buf, sizeof (buf), 0, src + pl, callback, data, flags);
++	  mutt_FormatString (buf, sizeof (buf), 0, cols, src + pl, callback, data, flags);
+ 	  len = mutt_strlen (buf);
+ 	  wid = mutt_strwidth (buf);
+ 
+-	  /* try to consume as many columns as we can, if we don't have
+-	   * memory for that, use as much memory as possible */
+-	  pad = (COLS - col - wid) / pw;
+-	  if (pad > 0 && wlen + (pad * pl) + len > destlen)
+-	    pad = ((signed)(destlen - wlen - len)) / pl;
+-	  if (pad > 0)
++	  pad = (cols - col - wid) / pw;
++	  if (pad >= 0)
+ 	  {
+-	    while (pad--)
++            /* try to consume as many columns as we can, if we don't have
++             * memory for that, use as much memory as possible */
++            if (wlen + (pad * pl) + len > destlen)
++              pad = (destlen > wlen + len) ? ((destlen - wlen - len) / pl) : 0;
++            else
++            {
++              /* Add pre-spacing to make multi-column pad characters and
++               * the contents after padding line up */
++              while ((col + (pad * pw) + wid < cols) &&
++                     (wlen + (pad * pl) + len < destlen))
++              {
++                *wptr++ = ' ';
++                wlen++;
++                col++;
++              }
++            }
++	    while (pad-- > 0)
+ 	    {
+ 	      memcpy (wptr, src, pl);
+ 	      wptr += pl;
+@@ -1312,13 +1471,13 @@ void mutt_FormatString (char *dest,		/* output buffer */
+ 	    /* \0-terminate dest for length computation in mutt_wstr_trunc() */
+ 	    *wptr = 0;
+ 	    /* make sure right part is at most as wide as display */
+-	    len = mutt_wstr_trunc (buf, destlen, COLS-offset, &wid);
++	    len = mutt_wstr_trunc (buf, destlen, COLS - offset - SidebarWidth, &wid);
+ 	    /* truncate left so that right part fits completely in */
+ 	    wlen = mutt_wstr_trunc (dest, destlen - len, col + pad*pw -offset, &col);
+ 	    wptr = dest + wlen;
+ 	  }
+ 	  if (len + wlen > destlen)
+-	    len = mutt_wstr_trunc (buf, destlen - wlen, COLS - col, NULL);
++	    len = mutt_wstr_trunc (buf, destlen - wlen, cols - col, NULL);
+ 	  memcpy (wptr, buf, len);
+ 	  wptr += len;
+ 	  wlen += len;
+@@ -1335,9 +1494,9 @@ void mutt_FormatString (char *dest,		/* output buffer */
+ 	  pl = pw = 1;
+ 
+ 	/* see if there's room to add content, else ignore */
+-	if (col < COLS && wlen < destlen)
++	if (col < cols && wlen < destlen)
+ 	{
+-	  c = (COLS - col) / pw;
++	  c = (cols - col) / pw;
+ 	  if (c > 0 && wlen + (c * pl) > destlen)
+ 	    c = ((signed)(destlen - wlen)) / pl;
+ 	  while (c > 0)
+@@ -1368,7 +1527,7 @@ void mutt_FormatString (char *dest,		/* output buffer */
+ 	}
+ 	
+ 	/* use callback function to handle this case */
+-	src = callback (buf, sizeof (buf), col, ch, src, prefix, ifstring, elsestring, data, flags);
++	src = callback (buf, sizeof (buf), col, cols, ch, src, prefix, ifstring, elsestring, data, flags);
+ 
+ 	if (tolower)
+ 	  mutt_strlower (buf);
+@@ -1381,7 +1540,7 @@ void mutt_FormatString (char *dest,		/* output buffer */
+ 	}
+ 	
+ 	if ((len = mutt_strlen (buf)) + wlen > destlen)
+-	  len = mutt_wstr_trunc (buf, destlen - wlen, COLS - col, NULL);
++	  len = mutt_wstr_trunc (buf, destlen - wlen, cols - col, NULL);
+ 
+ 	memcpy (wptr, buf, len);
+ 	wptr += len;
+@@ -1511,7 +1670,9 @@ int mutt_save_confirm (const char *s, struct stat *st)
+ 
+   if (magic > 0 && !mx_access (s, W_OK))
+   {
+-    if (option (OPTCONFIRMAPPEND))
++    if (option (OPTCONFIRMAPPEND) &&
++       (!TrashPath || (mutt_strcmp (s, TrashPath) != 0)))
++       /* if we're appending to the trash, there's no point in asking */
+     {
+       snprintf (tmp, sizeof (tmp), _("Append messages to %s?"), s);
+       if ((rc = mutt_yesorno (tmp, M_YES)) == M_NO)
+@@ -1521,6 +1682,14 @@ int mutt_save_confirm (const char *s, struct stat *st)
+     }
+   }
+ 
++#ifdef USE_NNTP
++  if (magic == M_NNTP)
++  {
++    mutt_error _("Can't save message to news server.");
++    return 0;
++  }
++#endif
 +
-+    When Mutt wants to append an email to a compressed mail folder, it will
-+    look for a matching 'append-hook'. This hook is optional.
+   if (stat (s, st) != -1)
+   {
+     if (magic == -1)
+diff --git a/mx.c b/mx.c
+index acc81d4..7299ba0 100644
+--- a/mx.c
++++ b/mx.c
+@@ -29,6 +29,13 @@
+ #include "copy.h"
+ #include "keymap.h"
+ #include "url.h"
++#ifdef USE_SIDEBAR
++#include "sidebar.h"
++#endif
 +
-+    Using the 'append-hook' will save time, but Mutt won't be able to determine
-+    the type of the mail folder inside the compressed file.
++#ifdef USE_COMPRESSED
++#include "compress.h"
++#endif
+ 
+ #ifdef USE_IMAP
+ #include "imap.h"
+@@ -38,6 +45,14 @@
+ #include "pop.h"
+ #endif
+ 
++#ifdef USE_NOTMUCH
++#include "mutt_notmuch.h"
++#endif
 +
-+    Mutt will *assume* the type to be that of the '$mbox_type' variable. Mutt
-+    also uses this type for temporary files.
++#ifdef USE_NNTP
++#include "nntp.h"
++#endif
 +
-+    Mutt will only use the 'append-hook' for existing files. The 'close-hook'
-+    will be used for empty, or missing files.
+ #include "buffy.h"
+ 
+ #ifdef USE_DOTLOCK
+@@ -57,6 +72,10 @@
+ #include <ctype.h>
+ #include <utime.h>
+ 
++#if USE_NOTMUCH
++#include "mutt_notmuch.h"
++#endif
 +
-+#### Example of append-hook
+ 
+ #define mutt_is_spool(s)  (mutt_strcmp (Spoolfile, s) == 0)
+ 
+@@ -343,6 +362,40 @@ int mx_is_pop (const char *p)
+ }
+ #endif
+ 
++#ifdef USE_NNTP
++int mx_is_nntp (const char *p)
++{
++  url_scheme_t scheme;
 +
-+        append-hook '.gz$' "gzip -c '%t' >> '%f'"
++  if (!p)
++    return 0;
 +
-+    * Mutt wants to append an email to a folder, "example.gz", that it opened
-+      with 'open-hook'
-+    * Mutt has an 'append-hook' whose regexp matches the filename: '.gz$'
-+    * Mutt knows the mailbox type from the '$mbox' variable
-+    * Mutt uses the command 'gzip -c' to append to an existing compressed file
++  scheme = url_check_scheme (p);
++  if (scheme == U_NNTP || scheme == U_NNTPS)
++    return 1;
 +
-+### Empty Files
++  return 0;
++}
++#endif
 +
-+    Mutt assumes that an empty file is not compressed. In this situation, unset
-+    $save_empty, so that the compressed file will be removed if you delete all
-+    of the messages.
++#ifdef USE_NOTMUCH
 +
-+### Security
++int mx_is_notmuch(const char *p)
++{
++  url_scheme_t scheme;
 +
-+    Encrypted files are decrypted into temporary files which are stored in the
-+    $tmpdir directory. This could be a security risk.
++  if (!p)
++    return 0;
 +
-+See Also
-+--------
++  scheme = url_check_scheme (p);
++  if (scheme == U_NOTMUCH)
++    return 1;
 +
-+    * NeoMutt project
-+    * Compile-Time Features
-+    * Regular Expressions
-+    * $tmpdir
-+    * $mbox_type
-+    * $save_empty
-+    * folder-hook
++  return 0;
++}
 +
-+Known Bugs
-+----------
++#endif
 +
-+    * The Compressed Folder hooks cannot deal with filenames that contains
-+      quotes/apostrophes.
+ int mx_get_magic (const char *path)
+ {
+   struct stat st;
+@@ -360,6 +413,16 @@ int mx_get_magic (const char *path)
+     return M_POP;
+ #endif /* USE_POP */
+ 
++#ifdef USE_NOTMUCH
++  if (mx_is_notmuch(path))
++    return M_NOTMUCH;
++#endif
 +
-+Credits
-+-------
++#ifdef USE_NNTP
++  if (mx_is_nntp (path))
++    return M_NNTP;
++#endif /* USE_NNTP */
 +
-+    * Roland Rosenfeld <roland at spinnaker.de>
-+    * Alain Penders <Alain at Finale-Dev.com>
-+    * Christoph "Myon" Berg <myon at debian.org>
-+    * Evgeni Golov <evgeni at debian.org>
-+    * Richard Russon <rich at flatcap.org>
+   if (stat (path, &st) == -1)
+   {
+     dprint (1, (debugfile, "mx_get_magic(): unable to stat %s: %s (errno %d).\n",
+@@ -414,6 +477,10 @@ int mx_get_magic (const char *path)
+     return (-1);
+   }
+ 
++#ifdef USE_COMPRESSED
++  if (magic == 0 && comp_can_read (path))
++    return M_COMPRESSED;
++#endif
+   return (magic);
+ }
+ 
+@@ -453,6 +520,13 @@ 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 (comp_can_append (ctx->path))
++    comp_open_append (ctx);
++#endif
 +
-diff -urN mutt-1.6.1/README.cond-date mutt-1.6.1-neomutt/README.cond-date
---- mutt-1.6.1/README.cond-date	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/README.cond-date	2016-06-12 18:43:00.669451754 +0100
-@@ -0,0 +1,163 @@
-+Conditional Dates Patch
-+=======================
+   ctx->append = 1;
+ 
+ #ifdef USE_IMAP
+@@ -580,6 +654,7 @@ static int mx_open_mailbox_append (CONTEXT *ctx, int flags)
+  *		M_APPEND	open mailbox for appending
+  *		M_READONLY	open mailbox in read-only mode
+  *		M_QUIET		only print error messages
++ *		M_PEEK		revert atime where applicable
+  *	ctx	if non-null, context struct to use
+  */
+ CONTEXT *mx_open_mailbox (const char *path, int flags, CONTEXT *pctx)
+@@ -591,6 +666,8 @@ CONTEXT *mx_open_mailbox (const char *path, int flags, CONTEXT *pctx)
+     ctx = safe_malloc (sizeof (CONTEXT));
+   memset (ctx, 0, sizeof (CONTEXT));
+   ctx->path = safe_strdup (path);
++  if (! (ctx->realpath = realpath (ctx->path, NULL)) )
++    ctx->realpath = safe_strdup (ctx->path);
+ 
+   ctx->msgnotreadyet = -1;
+   ctx->collapsed = 0;
+@@ -602,6 +679,8 @@ CONTEXT *mx_open_mailbox (const char *path, int flags, CONTEXT *pctx)
+     ctx->quiet = 1;
+   if (flags & M_READONLY)
+     ctx->readonly = 1;
++  if (flags & M_PEEK)
++    ctx->peekonly = 1;
+ 
+   if (flags & (M_APPEND|M_NEWFOLDER))
+   {
+@@ -616,7 +695,12 @@ CONTEXT *mx_open_mailbox (const char *path, int flags, CONTEXT *pctx)
+   }
+ 
+   ctx->magic = mx_get_magic (path);
+-  
 +
-+    Use rules to choose date format
++#ifdef USE_COMPRESSED
++  if (ctx->magic == M_COMPRESSED)
++    comp_open_read (ctx);
++#endif
 +
-+Patch
-+-----
+   if(ctx->magic == 0)
+     mutt_error (_("%s is not a mailbox."), path);
+ 
+@@ -668,6 +752,18 @@ CONTEXT *mx_open_mailbox (const char *path, int flags, CONTEXT *pctx)
+       break;
+ #endif /* USE_POP */
+ 
++#ifdef USE_NOTMUCH
++    case M_NOTMUCH:
++      rc = nm_read_query (ctx);
++      break;
++#endif /* USE_IMAP */
 +
-+    To check if Mutt supports "Conditional Dates", look for "patch-cond-date"
-+    in the mutt version.
++#ifdef USE_NNTP
++    case M_NNTP:
++      rc = nntp_open_mailbox (ctx);
++      break;
++#endif /* USE_NNTP */
 +
-+    Dependencies
-+    * mutt-1.6.1
-+    * nested-if patch
+     default:
+       rc = -1;
+       break;
+@@ -701,13 +797,22 @@ CONTEXT *mx_open_mailbox (const char *path, int flags, CONTEXT *pctx)
+ void mx_fastclose_mailbox (CONTEXT *ctx)
+ {
+   int i;
++  struct utimbuf ut;
+ 
+   if(!ctx) 
+     return;
+ 
++  /* fix up the times so buffy won't get confused */
++  if (ctx->peekonly && ctx->path && (ctx->mtime > ctx->atime)) {
++    ut.actime  = ctx->atime;
++    ut.modtime = ctx->mtime;
++    utime (ctx->path, &ut);
++  }
 +
-+Introduction
-+------------
+   /* never announce that a mailbox we've just left has new mail. #3290
+    * XXX: really belongs in mx_close_mailbox, but this is a nice hook point */
+-  mutt_buffy_setnotified(ctx->path);
++  if (!ctx->peekonly)
++    mutt_buffy_setnotified(ctx->path);
+ 
+   if (ctx->mx_close)
+     ctx->mx_close (ctx);
+@@ -721,7 +826,12 @@ void mx_fastclose_mailbox (CONTEXT *ctx)
+     mutt_free_header (&ctx->hdrs[i]);
+   FREE (&ctx->hdrs);
+   FREE (&ctx->v2r);
++#ifdef USE_COMPRESSED
++  if (ctx->compress_info)
++    comp_fast_close (ctx);
++#endif
+   FREE (&ctx->path);
++  FREE (&ctx->realpath);
+   FREE (&ctx->pattern);
+   if (ctx->limit_pattern) 
+     mutt_pattern_free (&ctx->limit_pattern);
+@@ -764,6 +874,18 @@ static int sync_mailbox (CONTEXT *ctx, int *index_hint)
+       rc = pop_sync_mailbox (ctx, index_hint);
+       break;
+ #endif /* USE_POP */
 +
-+    The "cond-date" patch allows you to construct $index_format expressions
-+    based on the age of the email.
++#ifdef USE_NOTMUCH
++    case M_NOTMUCH:
++      rc = nm_sync (ctx, index_hint);
++      break;
++#endif /* USE_NOTMUCH */
 +
-+    Mutt's default '$index_format' displays email dates in the form:
-+    abbreviated-month day-of-month — "Jan 14".
++#ifdef USE_NNTP
++    case M_NNTP:
++      rc = nntp_sync_mailbox (ctx);
++      break;
++#endif /* USE_NNTP */
+   }
+ 
+ #if 0
+@@ -773,9 +895,71 @@ static int sync_mailbox (CONTEXT *ctx, int *index_hint)
+   
+   if (tmp && tmp->new == 0)
+     mutt_update_mailbox (tmp);
 +
-+    The format is configurable but only per-mailbox. This patch allows you to
-+    configure the display depending on the age of the email.
++#ifdef USE_COMPRESSED
++  if (rc == 0 && ctx->compress_info)
++    return comp_sync (ctx);
++#endif
 +
-+    Potential Formatting Scheme
+   return rc;
+ }
+ 
++/**
++ * trash_append - XXX
++ *
++ * move deleted mails to the trash folder
++ */
++static int trash_append (CONTEXT *ctx)
++{
++	CONTEXT *ctx_trash;
++	int i = 0;
++	struct stat st, stc;
 +
-+    | Email Sent        | Format  | Example |
-+    |-------------------|---------|---------|
-+    | Today             | '%H:%M' | 13:23   |
-+    | This Month        | '%a %d' | Thu 17  |
-+    | This Year         | '%b %d' | Dec 10  |
-+    | Older than 1 Year | '%m/%y' | 06/14   |
++	if (!TrashPath || !ctx->deleted ||
++	   ((ctx->magic == M_MAILDIR) && option (OPTMAILDIRTRASH))) {
++		return 0;
++	}
 +
-+    For an explanation of the date formatting strings, see 'strftime(3).'
++	for (; i < ctx->msgcount && (!ctx->hdrs[i]->deleted || ctx->hdrs[i]->appended); i++);
++		/* nothing */
 +
-+    By carefully picking your formats, the dates can remain unambiguous and
-+    compact.
++	if (i == ctx->msgcount)
++		return 0; /* nothing to be done */
 +
-+    Mutt's conditional format strings have the form: (whitespace introduced for
-+    clarity)
++	if (mutt_save_confirm (TrashPath, &st) != 0) {
++		mutt_error _("message(s) not deleted");
++		return -1;
++	}
 +
-+        %? TEST ? TRUE & FALSE ?
++	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 */
++	}
 +
-+    The examples below use the test "%[" — the date of the message in the local
-+    timezone. They will also work with "%(" — the local time that the message
-+    arrived.
++#ifdef USE_IMAP
++	if (!imap_fast_trash())
++		return 0;
++#endif
 +
-+    The date tests are of the form:
++	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;
++			}
++		}
 +
-+        %[nX? TRUE & FALSE ?
++		mx_close_mailbox (ctx_trash, NULL);
++	} else {
++		mutt_error _("Can't open trash folder");
++		return -1;
++	}
 +
-+    * "n" is an optional count (defaults to 1 if missing)
-+    * "X" is the time period
++	return 0;
++}
 +
-+    Date Formatting Codes
+ /* save changes and close mailbox */
+ int mx_close_mailbox (CONTEXT *ctx, int *index_hint)
+ {
+@@ -807,13 +991,44 @@ int mx_close_mailbox (CONTEXT *ctx, int *index_hint)
+     return 0;
+   }
+ 
++#ifdef USE_NNTP
++  if (ctx->unread && ctx->magic == M_NNTP)
++  {
++    NNTP_DATA *nntp_data = ctx->data;
 +
-+    | Letter | Time Period |
-+    |--------|-------------|
-+    | y      | Years       |
-+    | m      | Months      |
-+    | w      | Weeks       |
-+    | d      | Days        |
-+    | H      | Hours       |
-+    | M      | Minutes     |
++    if (nntp_data && nntp_data->nserv && nntp_data->group)
++    {
++      int rc = query_quadoption (OPT_CATCHUP, _("Mark all articles read?"));
++      if (rc < 0)
++      {
++	ctx->closing = 0;
++	return -1;
++      }
++      else if (rc == M_YES)
++	mutt_newsgroup_catchup (nntp_data->nserv, nntp_data->group);
++    }
++  }
++#endif
 +
-+    Date Tests
+   for (i = 0; i < ctx->msgcount; i++)
+   {
+     if (!ctx->hdrs[i]->deleted && ctx->hdrs[i]->read 
+         && !(ctx->hdrs[i]->flagged && option (OPTKEEPFLAGGED)))
+       read_msgs++;
++#ifdef USE_SIDEBAR
++    if (ctx->hdrs[i]->deleted && !ctx->hdrs[i]->read)
++      ctx->unread--;
++    if (ctx->hdrs[i]->deleted && ctx->hdrs[i]->flagged)
++      ctx->flagged--;
++#endif
+   }
+ 
++#ifdef USE_NNTP
++  /* don't need to move articles from newsgroup */
++  if (ctx->magic == M_NNTP)
++    read_msgs = 0;
++#endif
 +
-+    | Test   | Meaning              |
-+    |--------|----------------------|
-+    | '%[y'  | This year            |
-+    | '%[1y' | This year            |
-+    | '%[6m' | In the last 6 months |
-+    | '%[w'  | This week            |
-+    | '%[d'  | Today                |
-+    | '%[4H' | In the last 4 hours  |
+   if (read_msgs && quadoption (OPT_MOVE) != M_NO)
+   {
+     char *p;
+@@ -912,6 +1127,7 @@ int mx_close_mailbox (CONTEXT *ctx, int *index_hint)
+ 	  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
+ 	  {
+@@ -936,6 +1152,14 @@ int mx_close_mailbox (CONTEXT *ctx, int *index_hint)
+     return 0;
+   }
+   
++  /* copy mails to the trash before expunging */
++  if (purge && ctx->deleted && mutt_strcmp (ctx->path, TrashPath)) {
++    if (trash_append (ctx) != 0) {
++      ctx->closing = 0;
++      return -1;
++    }
++  }
 +
-+### Example 1
+ #ifdef USE_IMAP
+   /* allow IMAP to preserve the deleted flag across sessions */
+   if (ctx->magic == M_IMAP)
+@@ -981,6 +1205,15 @@ int mx_close_mailbox (CONTEXT *ctx, int *index_hint)
+       !mutt_is_spool(ctx->path) && !option (OPTSAVEEMPTY))
+     mx_unlink_empty (ctx->path);
+ 
++#ifdef USE_COMPRESSED
++  if (ctx->compress_info && comp_slow_close (ctx))
++    return (-1);
++#endif
++#ifdef USE_SIDEBAR
++  ctx->msgcount -= ctx->deleted;
++  mutt_sb_set_buffystats (ctx);
++#endif
 +
-+    We start with a one-condition test.
+   mx_fastclose_mailbox (ctx);
+ 
+   return 0;
+@@ -1005,9 +1238,10 @@ void mx_update_tables(CONTEXT *ctx, int committing)
+ #define this_body ctx->hdrs[j]->content
+   for (i = 0, j = 0; i < ctx->msgcount; i++)
+   {
+-    if ((committing && (!ctx->hdrs[i]->deleted || 
++    if (!ctx->hdrs[i]->quasi_deleted &&
++	((committing && (!ctx->hdrs[i]->deleted ||
+ 			(ctx->magic == M_MAILDIR && option (OPTMAILDIRTRASH)))) ||
+-	(!committing && ctx->hdrs[i]->active))
++	(!committing && ctx->hdrs[i]->active)))
+     {
+       if (i != j)
+       {
+@@ -1140,6 +1374,12 @@ int mx_sync_mailbox (CONTEXT *ctx, int *index_hint)
+   msgcount = ctx->msgcount;
+   deleted = ctx->deleted;
+ 
++  if (purge && ctx->deleted && mutt_strcmp (ctx->path, TrashPath)) {
++    if (trash_append (ctx) == -1) {
++      return -1;
++    }
++  }
 +
-+    Example 1
+ #ifdef USE_IMAP
+   if (ctx->magic == M_IMAP)
+     rc = imap_sync_mailbox (ctx, purge, index_hint);
+@@ -1301,6 +1541,11 @@ int mx_check_mailbox (CONTEXT *ctx, int *index_hint, int lock)
+ {
+   int rc;
+ 
++#ifdef USE_COMPRESSED
++  if (ctx->compress_info)
++    return comp_check_mailbox (ctx);
++#endif
 +
-+    | Test   | Date Range | Format String | Example    |
-+    |--------|------------|---------------|------------|
-+    | '%[1m' | This month | '%[%b %d]'    | Dec 10     |
-+    |        | Older      | '%[%Y-%m-%d]' | 2015-04-23 |
+   if (ctx)
+   {
+     if (ctx->locked) lock = 0;
+@@ -1349,6 +1594,16 @@ int mx_check_mailbox (CONTEXT *ctx, int *index_hint, int lock)
+       case M_POP:
+ 	return (pop_check_mailbox (ctx, index_hint));
+ #endif /* USE_POP */
 +
-+    The $index_format string would contain:
++#ifdef USE_NOTMUCH
++      case M_NOTMUCH:
++	return nm_check_database(ctx, index_hint);
++#endif
 +
-+        %?[1m?%[%b %d]&%[%Y-%m-%d]?
++#ifdef USE_NNTP
++      case M_NNTP:
++	return (nntp_check_mailbox (ctx, 0));
++#endif /* USE_NNTP */
+     }
+   }
+ 
+@@ -1360,7 +1615,7 @@ int mx_check_mailbox (CONTEXT *ctx, int *index_hint, int lock)
+ MESSAGE *mx_open_message (CONTEXT *ctx, int msgno)
+ {
+   MESSAGE *msg;
+-  
 +
-+    Reparsed a little, for clarity, you can see the test condition and the two
-+    format strings.
+   msg = safe_calloc (1, sizeof (MESSAGE));
+   switch (msg->magic = ctx->magic)
+   {
+@@ -1371,15 +1626,24 @@ MESSAGE *mx_open_message (CONTEXT *ctx, int msgno)
+ 
+     case M_MH:
+     case M_MAILDIR:
++#ifdef USE_NOTMUCH
++    case M_NOTMUCH:
++#endif
+     {
+       HEADER *cur = ctx->hdrs[msgno];
+       char path[_POSIX_PATH_MAX];
+-      
+-      snprintf (path, sizeof (path), "%s/%s", ctx->path, cur->path);
+-      
++      char *folder = ctx->path;
++#ifdef USE_NOTMUCH
++      if (ctx->magic == M_NOTMUCH) {
++	msg->magic = nm_header_get_magic(cur);
++	folder = nm_header_get_folder(cur);
++      }
++#endif
++      snprintf (path, sizeof (path), "%s/%s", folder, cur->path);
 +
-+        %?[1m?        &           ?
-+              %[%b %d] %[%Y-%m-%d]
+       if ((msg->fp = fopen (path, "r")) == NULL && errno == ENOENT &&
+-	  ctx->magic == M_MAILDIR)
+-	msg->fp = maildir_open_find_message (ctx->path, cur->path);
++	  (ctx->magic == M_MAILDIR || ctx->magic == M_NOTMUCH))
++	msg->fp = maildir_open_find_message (folder, cur->path, NULL);
+       
+       if (msg->fp == NULL)
+       {
+@@ -1409,6 +1673,15 @@ MESSAGE *mx_open_message (CONTEXT *ctx, int msgno)
+     }
+ #endif /* USE_POP */
+ 
++#ifdef USE_NNTP
++    case M_NNTP:
++    {
++      if (nntp_fetch_message (msg, ctx, msgno) != 0)
++	FREE (&msg);
++      break;
++    }
++#endif /* USE_NNTP */
 +
-+### Example 2
+     default:
+       dprint (1, (debugfile, "mx_open_message(): function not implemented for mailbox type %d.\n", ctx->magic));
+       FREE (&msg);
+@@ -1454,13 +1727,17 @@ int mx_commit_message (MESSAGE *msg, CONTEXT *ctx)
+       break;
+     }
+ #endif
+-    
 +
-+    This example contains three test conditions and four date formats.
+     case M_MAILDIR:
+     {
+       r = maildir_commit_message (ctx, msg, NULL);
+       break;
+     }
+-    
 +
-+    Example 2
++    case M_NOTMUCH:
++      mutt_perror _("Can't write to virtual folder.");
++      break;
 +
-+    | Test  | Date Range | Format String | Example |
-+    |-------|------------|---------------|---------|
-+    | '%[d' | Today      | '%[%H:%M ] '  | 12:34   |
-+    | '%[m' | This month | '%[%a %d]'    | Thu 12  |
-+    | '%[y' | This year  | '%[%b %d]'    | Dec 10  |
-+    |       | Older      | '%[%m/%y ]'   | 06/15   |
+     case M_MH:
+     {
+       r = mh_commit_message (ctx, msg, NULL);
+@@ -1474,7 +1751,7 @@ int mx_commit_message (MESSAGE *msg, CONTEXT *ctx)
+     mutt_perror _("Can't write message");
+     r = -1;
+   }
+- 
 +
-+    The $index_format string would contain:
+   return r;
+ }
+ 
+@@ -1484,6 +1761,10 @@ int mx_close_message (MESSAGE **msg)
+   int r = 0;
+ 
+   if ((*msg)->magic == M_MH || (*msg)->magic == M_MAILDIR
++#ifdef USE_NNTP
++      || (*msg)->magic == M_NNTP
++#endif
++      || (*msg)->magic == M_NOTMUCH
+       || (*msg)->magic == M_IMAP || (*msg)->magic == M_POP)
+   {
+     r = safe_fclose (&(*msg)->fp);
+@@ -1491,7 +1772,10 @@ int mx_close_message (MESSAGE **msg)
+   else
+     (*msg)->fp = NULL;
+ 
+-  if ((*msg)->path)
++  dprint (2, (debugfile, "mx_close_message (): close: path=%s, commited=%s\n",
++	(*msg)->path, (*msg)->commited_path));
 +
-+        %<[y?%<[m?%<[d?%[%H:%M ]&%[%a %d]>&%[%b %d]>&%[%m/%y ]>
++  if ((*msg)->path && (*msg)->magic != M_NOTMUCH)
+   {
+     dprint (1, (debugfile, "mx_close_message (): unlinking %s\n",
+ 		(*msg)->path));
+@@ -1499,6 +1783,7 @@ int mx_close_message (MESSAGE **msg)
+     FREE (&(*msg)->path);
+   }
+ 
++  FREE (&(*msg)->commited_path);
+   FREE (msg);		/* __FREE_CHECKED__ */
+   return (r);
+ }
+diff --git a/mx.h b/mx.h
+index dd77ba4..5d65b52 100644
+--- a/mx.h
++++ b/mx.h
+@@ -26,6 +26,7 @@
+ #define _MX_H
+ 
+ #include "mailbox.h"
++#include "buffy.h"
+ 
+ /* supported mailbox formats */
+ enum
+@@ -34,8 +35,15 @@ enum
+   M_MMDF,
+   M_MH,
+   M_MAILDIR,
++#ifdef USE_NNTP
++  M_NNTP,
++#endif
+   M_IMAP,
++  M_NOTMUCH,
+   M_POP
++#ifdef USE_COMPRESSED
++  , M_COMPRESSED
++#endif
+ };
+ 
+ WHERE short DefaultMagic INITVAL (M_MBOX);
+@@ -63,13 +71,30 @@ int maildir_read_dir (CONTEXT *);
+ int maildir_check_mailbox (CONTEXT *, int *);
+ int maildir_check_empty (const char *);
+ 
++HEADER *maildir_parse_message (int magic, const char *fname, int is_old, HEADER * _h);
++HEADER *maildir_parse_stream (int magic, FILE *f, const char *fname, int is_old, HEADER * _h);
++void maildir_parse_flags (HEADER * h, const char *path);
++void maildir_update_flags (CONTEXT *ctx, HEADER *o, HEADER *n);
++void maildir_flags(char *dest, size_t destlen, HEADER * hdr);
 +
-+    Reparsed a little, for clarity, you can see the test conditions and the
-+    four format strings.
++#if USE_HCACHE
++#include <hcache.h>
++int mh_sync_mailbox_message (CONTEXT * ctx, int msgno, header_cache_t *hc);
++#else
++int mh_sync_mailbox_message (CONTEXT * ctx, int msgno);
++#endif
 +
-+        %<[y?                                       &%[%m/%y ]>  Older
-+             %<[m?                        &%[%b %d]>             This year
-+                  %<[d?         &%[%a %d]>                       This month
-+                       %[%H:%M ]                                 Today
++#ifdef USE_NOTMUCH
++int mx_is_notmuch(const char *p);
++#endif
 +
-+    This a another view of the same example, with some whitespace for clarity.
+ int maildir_commit_message (CONTEXT *, MESSAGE *, HEADER *);
+ int mh_commit_message (CONTEXT *, MESSAGE *, HEADER *);
+ 
+ int maildir_open_new_message (MESSAGE *, CONTEXT *, HEADER *);
+ int mh_open_new_message (MESSAGE *, CONTEXT *, HEADER *);
+ 
+-FILE *maildir_open_find_message (const char *, const char *);
++FILE *maildir_open_find_message (const char *, const char *, char **);
+ 
+ int mbox_strict_cmp_headers (const HEADER *, const HEADER *);
+ int mutt_reopen_mailbox (CONTEXT *, int *);
+diff --git a/newsrc.c b/newsrc.c
+new file mode 100644
+index 0000000..e0fbdce
+--- /dev/null
++++ b/newsrc.c
+@@ -0,0 +1,1262 @@
++/*
++ * Copyright (C) 1998 Brandon Long <blong at fiction.net>
++ * Copyright (C) 1999 Andrej Gritsenko <andrej at lucky.net>
++ * Copyright (C) 2000-2012 Vsevolod Volkov <vvv at mutt.org.ua>
++ *
++ *     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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
 +
-+        %<[y? %<[m? %<[d? AAA & BBB > & CCC > & DDD >
++#if HAVE_CONFIG_H
++#include "config.h"
++#endif
 +
-+        AAA = %[%H:%M ]
-+        BBB = %[%a %d]
-+        CCC = %[%b %d]
-+        DDD = %[%m/%y ]
++#include "mutt.h"
++#include "mutt_curses.h"
++#include "sort.h"
++#include "mx.h"
++#include "mime.h"
++#include "mailbox.h"
++#include "nntp.h"
++#include "rfc822.h"
++#include "rfc1524.h"
++#include "rfc2047.h"
++#include "bcache.h"
 +
++#if USE_HCACHE
++#include "hcache.h"
++#endif
 +
-+Variables
-+---------
++#include <unistd.h>
++#include <string.h>
++#include <ctype.h>
++#include <stdlib.h>
++#include <sys/stat.h>
++#include <sys/types.h>
++#include <dirent.h>
++#include <errno.h>
 +
-+    The "cond-date" patch doesn't have any config of its own. It modifies the
-+    behavior of the format strings.
++/* Find NNTP_DATA for given newsgroup or add it */
++static NNTP_DATA *nntp_data_find (NNTP_SERVER *nserv, const char *group)
++{
++  NNTP_DATA *nntp_data = hash_find (nserv->groups_hash, group);
 +
-+See Also
-+--------
++  if (!nntp_data)
++  {
++    /* create NNTP_DATA structure and add it to hash */
++    nntp_data = safe_calloc (1, sizeof (NNTP_DATA) + strlen (group) + 1);
++    nntp_data->group = (char *)nntp_data + sizeof (NNTP_DATA);
++    strcpy (nntp_data->group, group);
++    nntp_data->nserv = nserv;
++    nntp_data->deleted = 1;
++    if (nserv->groups_hash->nelem < nserv->groups_hash->curnelem * 2)
++      nserv->groups_hash = hash_resize (nserv->groups_hash,
++			   nserv->groups_hash->nelem * 2, 0);
++    hash_insert (nserv->groups_hash, nntp_data->group, nntp_data, 0);
 +
-+    * NeoMutt project
-+    * $index_format
-+    * nested-if patch
-+    * 'strftime(3)'
++    /* add NNTP_DATA to list */
++    if (nserv->groups_num >= nserv->groups_max)
++    {
++      nserv->groups_max *= 2;
++      safe_realloc (&nserv->groups_list,
++		    nserv->groups_max * sizeof (nntp_data));
++    }
++    nserv->groups_list[nserv->groups_num++] = nntp_data;
++  }
++  return nntp_data;
++}
 +
-+Known Bugs
-+----------
++/* Remove all temporarily cache files */
++void nntp_acache_free (NNTP_DATA *nntp_data)
++{
++  int i;
 +
-+    Date parsing doesn't quite do what you expect. "1w" doesn't mean the "in
-+    the last 7 days", but "*this* week". This doesn't match the normal Mutt
-+    behaviour: for example '~d>1w' means emails dated in the last 7 days.
++  for (i = 0; i < NNTP_ACACHE_LEN; i++)
++  {
++    if (nntp_data->acache[i].path)
++    {
++      unlink (nntp_data->acache[i].path);
++      FREE (&nntp_data->acache[i].path);
++    }
++  }
++}
 +
-+Credits
-+-------
++/* Free NNTP_DATA, used to destroy hash elements */
++void nntp_data_free (void *data)
++{
++  NNTP_DATA *nntp_data = data;
 +
-+    * Aaron Schrab <aaron at schrab.com>
-+    * Eric Davis <edavis at insanum.com>
-+    * Richard Russon <rich at flatcap.org>
++  if (!nntp_data)
++    return;
++  nntp_acache_free (nntp_data);
++  mutt_bcache_close (&nntp_data->bcache);
++  FREE (&nntp_data->newsrc_ent);
++  FREE (&nntp_data->desc);
++  FREE (&data);
++}
 +
-diff -urN mutt-1.6.1/README.fmemopen mutt-1.6.1-neomutt/README.fmemopen
---- mutt-1.6.1/README.fmemopen	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/README.fmemopen	2016-06-12 18:43:00.670451770 +0100
-@@ -0,0 +1,47 @@
-+Fmemopen Patch
-+==============
++/* Unlock and close .newsrc file */
++void nntp_newsrc_close (NNTP_SERVER *nserv)
++{
++  if (!nserv->newsrc_fp)
++    return;
 +
-+    Replace some temporary files with memory buffers
++  dprint (1, (debugfile, "Unlocking %s\n", nserv->newsrc_file));
++  mx_unlock_file (nserv->newsrc_file, fileno (nserv->newsrc_fp), 0);
++  safe_fclose (&nserv->newsrc_fp);
++}
 +
-+Patch
-+-----
++/* Parse .newsrc file:
++ *  0 - not changed
++ *  1 - parsed
++ * -1 - error */
++int nntp_newsrc_parse (NNTP_SERVER *nserv)
++{
++  unsigned int i;
++  char *line;
++  struct stat sb;
 +
-+    To check if Mutt supports "fmemopen", look for "patch-fmemopen" in the mutt
-+    version.
++  /* if file doesn't exist, create it */
++  nserv->newsrc_fp = safe_fopen (nserv->newsrc_file, "a");
++  safe_fclose (&nserv->newsrc_fp);
 +
-+    Dependencies
-+    * mutt-1.6.1
-+    * 'open_memstream()', 'fmemopen()' from glibc
++  /* open .newsrc */
++  nserv->newsrc_fp = safe_fopen (nserv->newsrc_file, "r");
++  if (!nserv->newsrc_fp)
++  {
++    mutt_perror (nserv->newsrc_file);
++    mutt_sleep (2);
++    return -1;
++  }
 +
-+Introduction
-+------------
++  /* lock it */
++  dprint (1, (debugfile, "Locking %s\n", nserv->newsrc_file));
++  if (mx_lock_file (nserv->newsrc_file, fileno (nserv->newsrc_fp), 0, 0, 1))
++  {
++    safe_fclose (&nserv->newsrc_fp);
++    return -1;
++  }
 +
-+    The "fmemopen" patch speeds up some searches.
++  if (stat (nserv->newsrc_file, &sb))
++  {
++    mutt_perror (nserv->newsrc_file);
++    nntp_newsrc_close (nserv);
++    mutt_sleep (2);
++    return -1;
++  }
 +
-+    This patch changes a few places where Mutt creates temporary files. It
-+    replaces them with in-memory buffers. This should improve the performance
-+    when searching the header or body using the $thorough_search option.
++  if (nserv->size == sb.st_size && nserv->mtime == sb.st_mtime)
++    return 0;
 +
-+    There are no user-configurable parts.
++  nserv->size = sb.st_size;
++  nserv->mtime = sb.st_mtime;
++  nserv->newsrc_modified = 1;
++  dprint (1, (debugfile, "Parsing %s\n", nserv->newsrc_file));
 +
-+    This patch depends on 'open_memstream()' and 'fmemopen()'. They are
-+    provided by glibc. Without them, Mutt will simply create temporary files.
++  /* .newsrc has been externally modified or hasn't been loaded yet */
++  for (i = 0; i < nserv->groups_num; i++)
++  {
++    NNTP_DATA *nntp_data = nserv->groups_list[i];
 +
-+See Also
-+--------
++    if (!nntp_data)
++      continue;
 +
-+    * NeoMutt project
-+    * Compile-Time Features
-+    * 'fmemopen(3)'
++    nntp_data->subscribed = 0;
++    nntp_data->newsrc_len = 0;
++    FREE (&nntp_data->newsrc_ent);
++  }
 +
-+Known Bugs
-+----------
++  line = safe_malloc (sb.st_size + 1);
++  while (sb.st_size && fgets (line, sb.st_size + 1, nserv->newsrc_fp))
++  {
++    char *b, *h, *p;
++    unsigned int subs = 0, i = 1;
++    NNTP_DATA *nntp_data;
 +
-+    None
++    /* find end of newsgroup name */
++    p = strpbrk (line, ":!");
++    if (!p)
++      continue;
 +
-+Credits
-+-------
++    /* ":" - subscribed, "!" - unsubscribed */
++    if (*p == ':')
++      subs++;
++    *p++ = '\0';
 +
-+    * Julius Plenz <plenz at cis.fu-berlin.de>
-+    * Richard Russon <rich at flatcap.org>
++    /* get newsgroup data */
++    nntp_data = nntp_data_find (nserv, line);
++    FREE (&nntp_data->newsrc_ent);
 +
-diff -urN mutt-1.6.1/README.ifdef mutt-1.6.1-neomutt/README.ifdef
---- mutt-1.6.1/README.ifdef	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/README.ifdef	2016-06-12 18:43:00.670451770 +0100
-@@ -0,0 +1,57 @@
-+Ifdef Patch
-+===========
++    /* count number of entries */
++    b = p;
++    while (*b)
++      if (*b++ == ',')
++	i++;
++    nntp_data->newsrc_ent = safe_calloc (i, sizeof (NEWSRC_ENTRY));
++    nntp_data->subscribed = subs;
 +
-+    Conditional config options
++    /* parse entries */
++    i = 0;
++    while (p)
++    {
++      b = p;
 +
-+Patch
-+-----
++      /* find end of entry */
++      p = strchr (p, ',');
++      if (p)
++	*p++ = '\0';
 +
-+    To check if Mutt supports "ifdef", look for "patch-ifdef" in the mutt
-+    version.
++      /* first-last or single number */
++      h = strchr (b, '-');
++      if (h)
++	*h++ = '\0';
++      else
++	h = b;
 +
-+    Dependencies
-+    * mutt-1.6.1
++      if (sscanf (b, ANUM, &nntp_data->newsrc_ent[i].first) == 1 &&
++	  sscanf (h, ANUM, &nntp_data->newsrc_ent[i].last) == 1)
++	i++;
++    }
++    if (i == 0)
++    {
++	nntp_data->newsrc_ent[i].first = 1;
++	nntp_data->newsrc_ent[i].last = 0;
++	i++;
++    }
++    if (nntp_data->lastMessage == 0)
++      nntp_data->lastMessage = nntp_data->newsrc_ent[i - 1].last;
++    nntp_data->newsrc_len = i;
++    safe_realloc (&nntp_data->newsrc_ent, i * sizeof (NEWSRC_ENTRY));
++    nntp_group_unread_stat (nntp_data);
++    dprint (2, (debugfile, "nntp_newsrc_parse: %s\n", nntp_data->group));
++  }
++  FREE (&line);
++  return 1;
++}
 +
-+Introduction
-+------------
++/* Generate array of .newsrc entries */
++void nntp_newsrc_gen_entries (CONTEXT *ctx)
++{
++  NNTP_DATA *nntp_data = ctx->data;
++  anum_t last = 0, first = 1;
++  int series, i;
++  int save_sort = SORT_ORDER;
++  unsigned int entries;
 +
-+    The "ifdef" patch introduces three new commands to Mutt and allow you to
-+    share one config file between versions of Mutt that may have different
-+    features compiled in.
++  if (Sort != SORT_ORDER)
++  {
++    save_sort = Sort;
++    Sort = SORT_ORDER;
++    mutt_sort_headers (ctx, 0);
++  }
 +
-+        ifdef  symbol config-command [args...]  # If a symbol is defined
-+        ifndef symbol config-command [args...]  # If a symbol is not defined
-+        finish                                  # Finish reading the current file
++  entries = nntp_data->newsrc_len;
++  if (!entries)
++  {
++    entries = 5;
++    nntp_data->newsrc_ent = safe_calloc (entries, sizeof (NEWSRC_ENTRY));
++  }
 +
-+    Here a symbol can be a $variable, <function>, command or compile-time
-+    symbol, such as "USE_IMAP".
++  /* Set up to fake initial sequence from 1 to the article before the
++   * first article in our list */
++  nntp_data->newsrc_len = 0;
++  series = 1;
++  for (i = 0; i < ctx->msgcount; i++)
++  {
++    /* search for first unread */
++    if (series)
++    {
++      /* We don't actually check sequential order, since we mark
++       * "missing" entries as read/deleted */
++      last = NHDR (ctx->hdrs[i])->article_num;
++      if (last >= nntp_data->firstMessage && !ctx->hdrs[i]->deleted &&
++	  !ctx->hdrs[i]->read)
++      {
++	if (nntp_data->newsrc_len >= entries)
++	{
++	  entries *= 2;
++	  safe_realloc (&nntp_data->newsrc_ent, entries * sizeof (NEWSRC_ENTRY));
++	}
++	nntp_data->newsrc_ent[nntp_data->newsrc_len].first = first;
++	nntp_data->newsrc_ent[nntp_data->newsrc_len].last = last - 1;
++	nntp_data->newsrc_len++;
++	series = 0;
++      }
++    }
 +
-+    'finish' is particularly useful when combined with 'ifndef'. e.g.
++    /* search for first read */
++    else
++    {
++      if (ctx->hdrs[i]->deleted || ctx->hdrs[i]->read)
++      {
++	first = last + 1;
++	series = 1;
++      }
++      last = NHDR (ctx->hdrs[i])->article_num;
++    }
++  }
++
++  if (series && first <= nntp_data->lastLoaded)
++  {
++    if (nntp_data->newsrc_len >= entries)
++    {
++      entries++;
++      safe_realloc (&nntp_data->newsrc_ent, entries * sizeof (NEWSRC_ENTRY));
++    }
++    nntp_data->newsrc_ent[nntp_data->newsrc_len].first = first;
++    nntp_data->newsrc_ent[nntp_data->newsrc_len].last = nntp_data->lastLoaded;
++    nntp_data->newsrc_len++;
++  }
++  safe_realloc (&nntp_data->newsrc_ent,
++		nntp_data->newsrc_len * sizeof (NEWSRC_ENTRY));
 +
-+        # Sidebar config file
-+        ifndef USE_SIDEBAR finish
++  if (save_sort != Sort)
++  {
++    Sort = save_sort;
++    mutt_sort_headers (ctx, 0);
++  }
++}
 +
-+Commands
-+--------
++/* Update file with new contents */
++static int update_file (char *filename, char *buf)
++{
++  FILE *fp;
++  char tmpfile[_POSIX_PATH_MAX];
++  int rc = -1;
 +
-+        ifdef  symbol "config-command [args]"
-+        ifndef symbol "config-command [args]"
-+        finish
++  while (1)
++  {
++    snprintf (tmpfile, sizeof (tmpfile), "%s.tmp", filename);
++    fp = fopen (tmpfile, "w");
++    if (!fp)
++    {
++      mutt_perror (tmpfile);
++      *tmpfile = '\0';
++      break;
++    }
++    if (fputs (buf, fp) == EOF)
++    {
++      mutt_perror (tmpfile);
++      break;
++    }
++    if (fclose (fp) == EOF)
++    {
++      mutt_perror (tmpfile);
++      fp = NULL;
++      break;
++    }
++    fp = NULL;
++    if (rename (tmpfile, filename) < 0)
++    {
++      mutt_perror (filename);
++      break;
++    }
++    *tmpfile = '\0';
++    rc = 0;
++    break;
++  }
++  if (fp)
++    fclose (fp);
++  if (*tmpfile)
++    unlink (tmpfile);
++  if (rc)
++    mutt_sleep (2);
++  return rc;
++}
 +
-+See Also
-+--------
++/* Update .newsrc file */
++int nntp_newsrc_update (NNTP_SERVER *nserv)
++{
++  char *buf;
++  size_t buflen, off;
++  unsigned int i;
++  int rc = -1;
 +
-+    * NeoMutt project
++  if (!nserv)
++    return -1;
 +
-+Known Bugs
-+----------
++  buflen = 10 * LONG_STRING;
++  buf = safe_calloc (1, buflen);
++  off = 0;
 +
-+    None
++  /* we will generate full newsrc here */
++  for (i = 0; i < nserv->groups_num; i++)
++  {
++    NNTP_DATA *nntp_data = nserv->groups_list[i];
++    unsigned int n;
 +
-+Credits
-+-------
++    if (!nntp_data || !nntp_data->newsrc_ent)
++      continue;
 +
-+    * Cedric Duval <cedricduval at free.fr>
-+    * Matteo F. Vescovi <mfvescovi at gmail.com>
-+    * Richard Russon <rich at flatcap.org>
++    /* write newsgroup name */
++    if (off + strlen (nntp_data->group) + 3 > buflen)
++    {
++      buflen *= 2;
++      safe_realloc (&buf, buflen);
++    }
++    snprintf (buf + off, buflen - off, "%s%c ", nntp_data->group,
++	      nntp_data->subscribed ? ':' : '!');
++    off += strlen (buf + off);
 +
-diff -urN mutt-1.6.1/README.index-color mutt-1.6.1-neomutt/README.index-color
---- mutt-1.6.1/README.index-color	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/README.index-color	2016-06-12 18:43:00.670451770 +0100
-@@ -0,0 +1,82 @@
-+Index Color Patch
-+=================
++    /* write entries */
++    for (n = 0; n < nntp_data->newsrc_len; n++)
++    {
++      if (off + LONG_STRING > buflen)
++      {
++	buflen *= 2;
++	safe_realloc (&buf, buflen);
++      }
++      if (n)
++	buf[off++] = ',';
++      if (nntp_data->newsrc_ent[n].first == nntp_data->newsrc_ent[n].last)
++	snprintf (buf + off, buflen - off, "%d", nntp_data->newsrc_ent[n].first);
++      else if (nntp_data->newsrc_ent[n].first < nntp_data->newsrc_ent[n].last)
++	snprintf (buf + off, buflen - off, "%d-%d",
++		  nntp_data->newsrc_ent[n].first, nntp_data->newsrc_ent[n].last);
++      off += strlen (buf + off);
++    }
++    buf[off++] = '\n';
++  }
++  buf[off] = '\0';
 +
-+    Custom rules for theming the email index
++  /* newrc being fully rewritten */
++  dprint (1, (debugfile, "Updating %s\n", nserv->newsrc_file));
++  if (nserv->newsrc_file && update_file (nserv->newsrc_file, buf) == 0)
++  {
++    struct stat sb;
 +
-+Patch
-+-----
++    rc = stat (nserv->newsrc_file, &sb);
++    if (rc == 0)
++    {
++      nserv->size = sb.st_size;
++      nserv->mtime = sb.st_mtime;
++    }
++    else
++    {
++      mutt_perror (nserv->newsrc_file);
++      mutt_sleep (2);
++    }
++  }
++  FREE (&buf);
++  return rc;
++}
 +
-+    To check if Mutt supports "Index Color", look for "patch-index-color" in
-+    the mutt version.
++/* Make fully qualified cache file name */
++static void cache_expand (char *dst, size_t dstlen, ACCOUNT *acct, char *src)
++{
++  char *c;
++  char file[_POSIX_PATH_MAX];
 +
-+    Dependencies
-+    * mutt-1.6.1
-+    * status-color patch
++  /* server subdirectory */
++  if (acct)
++  {
++    ciss_url_t url;
 +
-+Introduction
-+------------
++    mutt_account_tourl (acct, &url);
++    url.path = src;
++    url_ciss_tostring (&url, file, sizeof (file), U_PATH);
++  }
++  else
++    strfcpy (file, src ? src : "", sizeof (file));
 +
-+    The "index-color" patch allows you to specify colors for individual parts
-+    of the email index. e.g. Subject, Author, Flags.
++  snprintf (dst, dstlen, "%s/%s", NewsCacheDir, file);
 +
-+    First choose which part of the index you'd like to color. Then, if needed,
-+    pick a pattern to match.
++  /* remove trailing slash */
++  c = dst + strlen (dst) - 1;
++  if (*c == '/')
++    *c = '\0';
++  mutt_expand_path (dst, dstlen);
++}
 +
-+    Note: The pattern does not have to refer to the object you wish to color.
-+    e.g.
++/* Make fully qualified url from newsgroup name */
++void nntp_expand_path (char *line, size_t len, ACCOUNT *acct)
++{
++  ciss_url_t url;
 +
-+        color index_author red default "~smutt"
++  url.path = safe_strdup (line);
++  mutt_account_tourl (acct, &url);
++  url_ciss_tostring (&url, line, len, 0);
++  FREE (&url.path);
++}
 +
-+    The author appears red when the subject (~s) contains "mutt".
++/* Parse newsgroup */
++int nntp_add_group (char *line, void *data)
++{
++  NNTP_SERVER *nserv = data;
++  NNTP_DATA *nntp_data;
++  char group[LONG_STRING];
++  char desc[HUGE_STRING] = "";
++  char mod;
++  anum_t first, last;
 +
-+Colors
-+------
++  if (!nserv || !line)
++    return 0;
 +
-+    All the colors default to 'default', i.e. unset.
++  if (sscanf (line, "%s " ANUM " " ANUM " %c %[^\n]", group,
++	      &last, &first, &mod, desc) < 4)
++    return 0;
 +
-+    The index objects can be themed using the 'color' command. Some objects
-+    require a pattern.
++  nntp_data = nntp_data_find (nserv, group);
++  nntp_data->deleted = 0;
++  nntp_data->firstMessage = first;
++  nntp_data->lastMessage = last;
++  nntp_data->allowed = mod == 'y' || mod == 'm' ? 1 : 0;
++  mutt_str_replace (&nntp_data->desc, desc);
++  if (nntp_data->newsrc_ent || nntp_data->lastCached)
++    nntp_group_unread_stat (nntp_data);
++  else if (nntp_data->lastMessage &&
++	   nntp_data->firstMessage <= nntp_data->lastMessage)
++    nntp_data->unread = nntp_data->lastMessage - nntp_data->firstMessage + 1;
++  else
++    nntp_data->unread = 0;
++  return 0;
++}
 +
-+        color index-object foreground background
-+        color index-object foreground background pattern
++/* Load list of all newsgroups from cache */
++static int active_get_cache (NNTP_SERVER *nserv)
++{
++  char buf[HUGE_STRING];
++  char file[_POSIX_PATH_MAX];
++  time_t t;
++  FILE *fp;
 +
-+    Index Colors
++  cache_expand (file, sizeof (file), &nserv->conn->account, ".active");
++  dprint (1, (debugfile, "Parsing %s\n", file));
++  fp = safe_fopen (file, "r");
++  if (!fp)
++    return -1;
 +
-+    | Object            | Pattern | Highlights                                   |
-+    |-------------------|---------|----------------------------------------------|
-+    | 'index'           | yes     | Entire index line                            |
-+    | 'index_author'    | yes     | Author name, %A %a %F %L %n                  |
-+    | 'index_collapsed' | no      | Number of messages in a collapsed thread, %M |
-+    | 'index_date'      | no      | Date field                                   |
-+    | 'index_flags'     | yes     | Message flags, %S %Z                         |
-+    | 'index_label'     | no      | Message label, %y %Y                         |
-+    | 'index_number'    | no      | Message number, %C                           |
-+    | 'index_size'      | no      | Message size, %c %l                          |
-+    | 'index_subject'   | yes     | Subject, %s                                  |
++  if (fgets (buf, sizeof (buf), fp) == NULL ||
++      sscanf (buf, "%ld%s", &t, file) != 1 || t == 0)
++  {
++    fclose (fp);
++    return -1;
++  }
++  nserv->newgroups_time = t;
 +
-+See Also
-+--------
++  mutt_message _("Loading list of groups from cache...");
++  while (fgets (buf, sizeof (buf), fp))
++    nntp_add_group (buf, nserv);
++  nntp_add_group (NULL, NULL);
++  fclose (fp);
++  mutt_clear_error ();
++  return 0;
++}
 +
-+    * NeoMutt project
-+    * Regular Expressions
-+    * Patterns
-+    * $index_format
-+    * Color command
-+    * Status-Color patch
-+    * Keywords patch
++/* Save list of all newsgroups to cache */
++int nntp_active_save_cache (NNTP_SERVER *nserv)
++{
++  char file[_POSIX_PATH_MAX];
++  char *buf;
++  size_t buflen, off;
++  unsigned int i;
++  int rc;
 +
-+Known Bugs
-+----------
++  if (!nserv->cacheable)
++    return 0;
 +
-+    None
++  buflen = 10 * LONG_STRING;
++  buf = safe_calloc (1, buflen);
++  snprintf (buf, buflen, "%lu\n", (unsigned long)nserv->newgroups_time);
++  off = strlen (buf);
 +
-+Credits
-+-------
++  for (i = 0; i < nserv->groups_num; i++)
++  {
++    NNTP_DATA *nntp_data = nserv->groups_list[i];
 +
-+    * Christian Aichinger <Greek0 at gmx.net>
-+    * Christoph "Myon" Berg <myon at debian.org>
-+    * Elimar Riesebieter <riesebie at lxtec.de>
-+    * Eric Davis <edavis at insanum.com>
-+    * Vladimir Marek <Vladimir.Marek at oracle.com>
-+    * Richard Russon <rich at flatcap.org>
++    if (!nntp_data || nntp_data->deleted)
++      continue;
 +
-diff -urN mutt-1.6.1/README.initials mutt-1.6.1-neomutt/README.initials
---- mutt-1.6.1/README.initials	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/README.initials	2016-06-12 18:43:00.670451770 +0100
-@@ -0,0 +1,48 @@
-+Initials Expando Patch
-+======================
++    if (off + strlen (nntp_data->group) +
++	(nntp_data->desc ? strlen (nntp_data->desc) : 0) + 50 > buflen)
++    {
++      buflen *= 2;
++      safe_realloc (&buf, buflen);
++    }
++    snprintf (buf + off, buflen - off, "%s %d %d %c%s%s\n", nntp_data->group,
++	      nntp_data->lastMessage, nntp_data->firstMessage,
++	      nntp_data->allowed ? 'y' : 'n', nntp_data->desc ? " " : "",
++	      nntp_data->desc ? nntp_data->desc : "");
++    off += strlen (buf + off);
++  }
 +
-+    Expando for author's initials
++  cache_expand (file, sizeof (file), &nserv->conn->account, ".active");
++  dprint (1, (debugfile, "Updating %s\n", file));
++  rc = update_file (file, buf);
++  FREE (&buf);
++  return rc;
++}
 +
-+Patch
-+-----
++#ifdef USE_HCACHE
++/* Used by mutt_hcache_open() to compose hcache file name */
++static int nntp_hcache_namer (const char *path, char *dest, size_t destlen)
++{
++  return snprintf (dest, destlen, "%s.hcache", path);
++}
 +
-+    To check if Mutt supports "Initials", look for "patch-initials" in the mutt
-+    version.
++/* Open newsgroup hcache */
++header_cache_t *nntp_hcache_open (NNTP_DATA *nntp_data)
++{
++  ciss_url_t url;
++  char file[_POSIX_PATH_MAX];
 +
-+    Dependencies
-+    * mutt-1.6.1
++  if (!nntp_data->nserv || !nntp_data->nserv->cacheable ||
++      !nntp_data->nserv->conn || !nntp_data->group ||
++      !(nntp_data->newsrc_ent || nntp_data->subscribed ||
++      option (OPTSAVEUNSUB)))
++    return NULL;
 +
-+Introduction
-+------------
++  mutt_account_tourl (&nntp_data->nserv->conn->account, &url);
++  url.path = nntp_data->group;
++  url_ciss_tostring (&url, file, sizeof (file), U_PATH);
++  return mutt_hcache_open (NewsCacheDir, file, nntp_hcache_namer);
++}
 +
-+    The "initials" patch adds an expando (%I) for an author's initials.
++/* Remove stale cached headers */
++void nntp_hcache_update (NNTP_DATA *nntp_data, header_cache_t *hc)
++{
++  char buf[16];
++  int old = 0;
++  void *hdata;
++  anum_t first, last, current;
 +
-+    The index panel displays a list of emails. Its layout is controlled by the
-+    $index_format variable. Using this expando saves space in the index panel.
-+    This can be useful if you are regularly working with a small set of people.
++  if (!hc)
++    return;
 +
-+Variables
-+---------
++  /* fetch previous values of first and last */
++  hdata = mutt_hcache_fetch_raw (hc, "index", strlen);
++  if (hdata)
++  {
++    dprint (2, (debugfile,
++		"nntp_hcache_update: mutt_hcache_fetch index: %s\n", hdata));
++    if (sscanf (hdata, ANUM " " ANUM, &first, &last) == 2)
++    {
++      old = 1;
++      nntp_data->lastCached = last;
 +
-+    This patch has no config of its own. It adds an expando which can be used
-+    in the $index_format variable.
++      /* clean removed headers from cache */
++      for (current = first; current <= last; current++)
++      {
++	if (current >= nntp_data->firstMessage &&
++	    current <= nntp_data->lastMessage)
++	  continue;
 +
-+See Also
-+--------
++	snprintf (buf, sizeof (buf), "%d", current);
++	dprint (2, (debugfile,
++		    "nntp_hcache_update: mutt_hcache_delete %s\n", buf));
++	mutt_hcache_delete (hc, buf, strlen);
++      }
++    }
++    FREE (&hdata);
++  }
 +
-+    * NeoMutt project
-+    * $index_format
-+    * index-color patch
-+    * folder-hook
++  /* store current values of first and last */
++  if (!old || nntp_data->firstMessage != first ||
++	      nntp_data->lastMessage != last)
++  {
++    snprintf (buf, sizeof (buf), "%u %u", nntp_data->firstMessage,
++					  nntp_data->lastMessage);
++    dprint (2, (debugfile,
++		"nntp_hcache_update: mutt_hcache_store index: %s\n", buf));
++    mutt_hcache_store_raw (hc, "index", buf, strlen (buf) + 1, strlen);
++  }
++}
++#endif
 +
-+Known Bugs
-+----------
++/* Remove bcache file */
++static int nntp_bcache_delete (const char *id, body_cache_t *bcache, void *data)
++{
++  NNTP_DATA *nntp_data = data;
++  anum_t anum;
++  char c;
 +
-+    None
++  if (!nntp_data || sscanf (id, ANUM "%c", &anum, &c) != 1 ||
++      anum < nntp_data->firstMessage || anum > nntp_data->lastMessage)
++  {
++    if (nntp_data)
++      dprint (2, (debugfile, "nntp_bcache_delete: mutt_bcache_del %s\n", id));
++    mutt_bcache_del (bcache, id);
++  }
++  return 0;
++}
 +
-+Credits
-+-------
++/* Remove stale cached messages */
++void nntp_bcache_update (NNTP_DATA *nntp_data)
++{
++  mutt_bcache_list (nntp_data->bcache, nntp_bcache_delete, nntp_data);
++}
 +
-+    * Vsevolod Volkov <vvv at mutt.org.ua>
-+    * Richard Russon <rich at flatcap.org>
++/* Remove hcache and bcache of newsgroup */
++void nntp_delete_group_cache (NNTP_DATA *nntp_data)
++{
++  char file[_POSIX_PATH_MAX];
 +
-diff -urN mutt-1.6.1/README.keywords mutt-1.6.1-neomutt/README.keywords
---- mutt-1.6.1/README.keywords	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/README.keywords	2016-06-12 18:43:00.670451770 +0100
-@@ -0,0 +1,105 @@
-+Keywords Patch
-+==============
++  if (!nntp_data || !nntp_data->nserv || !nntp_data->nserv->cacheable)
++    return;
 +
-+    Labels/Tagging for emails
++#ifdef USE_HCACHE
++  nntp_hcache_namer (nntp_data->group, file, sizeof (file));
++  cache_expand (file, sizeof (file), &nntp_data->nserv->conn->account, file);
++  unlink (file);
++  nntp_data->lastCached = 0;
++  dprint (2, (debugfile, "nntp_delete_group_cache: %s\n", file));
++#endif
 +
-+Patch
-+-----
++  if (!nntp_data->bcache)
++    nntp_data->bcache = mutt_bcache_open (&nntp_data->nserv->conn->account,
++			nntp_data->group);
++  if (nntp_data->bcache)
++  {
++    dprint (2, (debugfile, "nntp_delete_group_cache: %s/*\n", nntp_data->group));
++    mutt_bcache_list (nntp_data->bcache, nntp_bcache_delete, NULL);
++    mutt_bcache_close (&nntp_data->bcache);
++  }
++}
 +
-+    To check if Mutt supports "Keywords", look for "patch-keywords" in the mutt
-+    version.
++/* Remove hcache and bcache of all unexistent and unsubscribed newsgroups */
++void nntp_clear_cache (NNTP_SERVER *nserv)
++{
++  char file[_POSIX_PATH_MAX];
++  char *fp;
++  struct dirent *entry;
++  DIR *dp;
 +
-+    Dependencies
-+    * mutt-1.5.24
++  if (!nserv || !nserv->cacheable)
++    return;
 +
-+Introduction
-+------------
++  cache_expand (file, sizeof (file), &nserv->conn->account, NULL);
++  dp = opendir (file);
++  if (dp)
++  {
++    safe_strncat (file, sizeof (file), "/", 1);
++    fp = file + strlen (file);
++    while ((entry = readdir (dp)))
++    {
++      char *group = entry->d_name;
++      struct stat sb;
++      NNTP_DATA *nntp_data;
++      NNTP_DATA nntp_tmp;
++
++      if (mutt_strcmp (group, ".") == 0 ||
++	  mutt_strcmp (group, "..") == 0)
++	continue;
++      *fp = '\0';
++      safe_strncat (file, sizeof (file), group, strlen (group));
++      if (stat (file, &sb))
++	continue;
++
++#ifdef USE_HCACHE
++      if (S_ISREG (sb.st_mode))
++      {
++	char *ext = group + strlen (group) - 7;
++	if (strlen (group) < 8 || mutt_strcmp (ext, ".hcache"))
++	  continue;
++	*ext = '\0';
++      }
++      else
++#endif
++      if (!S_ISDIR (sb.st_mode))
++	continue;
 +
-+    Unify label/keyword handling.
++      nntp_data = hash_find (nserv->groups_hash, group);
++      if (!nntp_data)
++      {
++	nntp_data = &nntp_tmp;
++	nntp_data->nserv = nserv;
++	nntp_data->group = group;
++	nntp_data->bcache = NULL;
++      }
++      else if (nntp_data->newsrc_ent || nntp_data->subscribed ||
++	       option (OPTSAVEUNSUB))
++	continue;
 +
-+    Since x-labels were added to mutt in 2000, a number of other approaches to
-+    what we now call "tagging" have also emerged. One of them was even made
-+    standard in RFC 2822. This update unifies the handling of all these
-+    strategies.
++      nntp_delete_group_cache (nntp_data);
++      if (S_ISDIR (sb.st_mode))
++      {
++	rmdir (file);
++	dprint (2, (debugfile, "nntp_clear_cache: %s\n", file));
++      }
++    }
++    closedir (dp);
++  }
++  return;
++}
 +
-+    We start by changing mutt's internal keyword storage from a single string
-+    which may contain whitespace to a list of discrete keywords. This has
-+    advantages for keyword completion as well as for portabilty among varying
-+    "standards" for keyword storage. This may represent a significant change
-+    for existing mutt users who have set x-labels containing spaces, and should
-+    be regarded with suspicion. The advantages are significant, though.
++/* %a = account url
++ * %p = port
++ * %P = port if specified
++ * %s = news server name
++ * %S = url schema
++ * %u = username */
++const char *
++nntp_format_str (char *dest, size_t destlen, size_t col, int cols, char op, const char *src,
++		const char *fmt, const char *ifstring, const char *elsestring,
++		unsigned long data, format_flag flags)
++{
++  NNTP_SERVER *nserv = (NNTP_SERVER *)data;
++  ACCOUNT *acct = &nserv->conn->account;
++  ciss_url_t url;
++  char fn[SHORT_STRING], tmp[SHORT_STRING], *p;
 +
-+    Next we allow mutt to parse keywords into this internal list from any of
-+    the following headers: X-Label (freeform), X-Keywords (space-delimited),
-+    X-Mozilla-Keys (space-delimited), and Keywords (RFC 2822,
-+    comma-space-delimited). Mutt remembers which headers it sourced keywords
-+    from, and can rewrite those headers when saving messages for compatibility
-+    with the mailer of origin.
++  switch (op)
++  {
++    case 'a':
++      mutt_account_tourl (acct, &url);
++      url_ciss_tostring (&url, fn, sizeof (fn), U_PATH);
++      p = strchr (fn, '/');
++      if (p)
++	*p = '\0';
++      snprintf (tmp, sizeof (tmp), "%%%ss", fmt);
++      snprintf (dest, destlen, tmp, fn);
++      break;
++    case 'p':
++      snprintf (tmp, sizeof (tmp), "%%%su", fmt);
++      snprintf (dest, destlen, tmp, acct->port);
++      break;
++    case 'P':
++      *dest = '\0';
++      if (acct->flags & M_ACCT_PORT)
++      {
++	snprintf (tmp, sizeof (tmp), "%%%su", fmt);
++	snprintf (dest, destlen, tmp, acct->port);
++      }
++      break;
++    case 's':
++      strncpy (fn, acct->host, sizeof (fn) - 1);
++      mutt_strlower (fn);
++      snprintf (tmp, sizeof (tmp), "%%%ss", fmt);
++      snprintf (dest, destlen, tmp, fn);
++      break;
++    case 'S':
++      mutt_account_tourl (acct, &url);
++      url_ciss_tostring (&url, fn, sizeof (fn), U_PATH);
++      p = strchr (fn, ':');
++      if (p)
++	*p = '\0';
++      snprintf (tmp, sizeof (tmp), "%%%ss", fmt);
++      snprintf (dest, destlen, tmp, fn);
++      break;
++    case 'u':
++      snprintf (tmp, sizeof (tmp), "%%%ss", fmt);
++      snprintf (dest, destlen, tmp, acct->user);
++      break;
++  }
++  return (src);
++}
 +
-+    (X-Label was specified as freeform text by mutt, its only known
-+    implementation. X-Labels have been used both as a "tagging" device,
-+    probably with space delimiting, and as a "memo" field, where
-+    space-delimited parsing would ruin the semantics of the memo. By default
-+    mutt will not split X-Labels at all. Set $xlabel_delimiter if your needs
-+    vary.)
++/* Automatically loads a newsrc into memory, if necessary.
++ * Checks the size/mtime of a newsrc file, if it doesn't match, load
++ * again.  Hmm, if a system has broken mtimes, this might mean the file
++ * is reloaded every time, which we'd have to fix. */
++NNTP_SERVER *nntp_select_server (char *server, int leave_lock)
++{
++  char file[_POSIX_PATH_MAX];
++  char *p;
++  int rc;
++  struct stat sb;
++  ACCOUNT acct;
++  NNTP_SERVER *nserv;
++  NNTP_DATA *nntp_data;
++  CONNECTION *conn;
++  ciss_url_t url;
 +
-+    Finally we add two booleans: $keywords_legacy=true and
-+    $keywords_standard=FALSE. When $keywords_legacy is true, mutt will always
-+    save keyword to whatever original header it came from. When
-+    $keywords_standard=true, mutt will save to the Keywords: header. If both
-+    are true mutt saves to both; if neither is true, mutt saves only to legacy
-+    headers to avoid complete loss of keywords.
++  if (!server || !*server)
++  {
++    mutt_error _("No news server defined!");
++    mutt_sleep (2);
++    return NULL;
++  }
 +
-+    Overall this represents convergence path for all competing
-+    labelling/tagging/keywording systems toward one that is specified by RFC.
++  /* create account from news server url */
++  acct.flags = 0;
++  acct.port = NNTP_PORT;
++  acct.type = M_ACCT_TYPE_NNTP;
++  snprintf (file, sizeof (file), "%s%s",
++	    strstr (server, "://") ? "" : "news://", server);
++  if (url_parse_ciss (&url, file) < 0 ||
++      (url.path && *url.path) ||
++      !(url.scheme == U_NNTP || url.scheme == U_NNTPS) ||
++      mutt_account_fromurl (&acct, &url) < 0)
++  {
++    mutt_error (_("%s is an invalid news server specification!"), server);
++    mutt_sleep (2);
++    return NULL;
++  }
++  if (url.scheme == U_NNTPS)
++  {
++    acct.flags |= M_ACCT_SSL;
++    acct.port = NNTP_SSL_PORT;
++  }
 +
-+    You can change or delete the X-Label: field within Mutt using the
-+    edit-label command, bound to the y key by default. This works for tagged
-+    messages, too.
++  /* find connection by account */
++  conn = mutt_conn_find (NULL, &acct);
++  if (!conn)
++    return NULL;
++  if (!(conn->account.flags & M_ACCT_USER) && acct.flags & M_ACCT_USER)
++  {
++    conn->account.flags |= M_ACCT_USER;
++    conn->account.user[0] = '\0';
++  }
 +
-+Variables
-+---------
++  /* news server already exists */
++  nserv = conn->data;
++  if (nserv)
++  {
++    if (nserv->status == NNTP_BYE)
++      nserv->status = NNTP_NONE;
++    if (nntp_open_connection (nserv) < 0)
++      return NULL;
 +
-+    Keyword Variables
++    rc = nntp_newsrc_parse (nserv);
++    if (rc < 0)
++      return NULL;
 +
-+    | Name                | Type    | Default |
-+    |---------------------|---------|---------|
-+    | 'keywords_legacy'   | boolean | 'yes'   |
-+    | 'keywords_standard' | boolean | 'no'    |
-+    | 'xlabel_delimiter'  | string  | (empty) |
++    /* check for new newsgroups */
++    if (!leave_lock && nntp_check_new_groups (nserv) < 0)
++      rc = -1;
 +
-+Functions
-+---------
++    /* .newsrc has been externally modified */
++    if (rc > 0)
++      nntp_clear_cache (nserv);
++    if (rc < 0 || !leave_lock)
++      nntp_newsrc_close (nserv);
++    return rc < 0 ? NULL : nserv;
++  }
 +
-+    Keyword Functions
++  /* new news server */
++  nserv = safe_calloc (1, sizeof (NNTP_SERVER));
++  nserv->conn = conn;
++  nserv->groups_hash = hash_create (1009, 0);
++  nserv->groups_max = 16;
++  nserv->groups_list = safe_malloc (nserv->groups_max * sizeof (nntp_data));
 +
-+    | Menus       | Default Key | Function       | Description                              |
-+    |-------------|-------------|----------------|------------------------------------------|
-+    | index,pager | y           | '<edit-label>' | add, change, or delete a message's label |
++  rc = nntp_open_connection (nserv);
 +
-+Sort
-+----
++  /* try to create cache directory and enable caching */
++  nserv->cacheable = 0;
++  if (rc >= 0 && NewsCacheDir && *NewsCacheDir)
++  {
++    cache_expand (file, sizeof (file), &conn->account, NULL);
++    p = *file == '/' ? file + 1 : file;
++    while (1)
++    {
++      p = strchr (p, '/');
++      if (p)
++	*p = '\0';
++      if ((stat (file, &sb) || (sb.st_mode & S_IFDIR) == 0) &&
++	  mkdir (file, 0700))
++      {
++	mutt_error (_("Can't create %s: %s."), file, strerror (errno));
++	mutt_sleep (2);
++	break;
++      }
++      if (!p)
++      {
++	nserv->cacheable = 1;
++	break;
++      }
++      *p++ = '/';
++    }
++  }
 +
-+    Keywords Sort
++  /* load .newsrc */
++  if (rc >= 0)
++  {
++    mutt_FormatString (file, sizeof (file), 0, COLS - SidebarWidth, NONULL (NewsRc),
++		       nntp_format_str, (unsigned long)nserv, 0);
++    mutt_expand_path (file, sizeof (file));
++    nserv->newsrc_file = safe_strdup (file);
++    rc = nntp_newsrc_parse (nserv);
++  }
++  if (rc >= 0)
++  {
++    /* try to load list of newsgroups from cache */
++    if (nserv->cacheable && active_get_cache (nserv) == 0)
++      rc = nntp_check_new_groups (nserv);
 +
-+    | Sort    | Description   |
-+    |---------|---------------|
-+    | 'label' | Sort by label |
++    /* load list of newsgroups from server */
++    else
++      rc = nntp_active_fetch (nserv);
++  }
 +
-+See Also
-+--------
++  if (rc >= 0)
++    nntp_clear_cache (nserv);
 +
-+    * NeoMutt project
-+    * $index_format
-+    * index-color patch
-+    * folder-hook
++#ifdef USE_HCACHE
++  /* check cache files */
++  if (rc >= 0 && nserv->cacheable)
++  {
++    struct dirent *entry;
++    DIR *dp = opendir (file);
 +
-+Known Bugs
-+----------
++    if (dp)
++    {
++      while ((entry = readdir (dp)))
++      {
++	header_cache_t *hc;
++	void *hdata;
++	char *group = entry->d_name;
 +
-+Credits
-+-------
++	p = group + strlen (group) - 7;
++	if (strlen (group) < 8 || strcmp (p, ".hcache"))
++	  continue;
++	*p = '\0';
++	nntp_data = hash_find (nserv->groups_hash, group);
++	if (!nntp_data)
++	  continue;
 +
-+    * David Champion <dgc at uchicago.edu>
-+    * Richard Russon <rich at flatcap.org>
++	hc = nntp_hcache_open (nntp_data);
++	if (!hc)
++	  continue;
 +
-diff -urN mutt-1.6.1/README.limit-current-thread mutt-1.6.1-neomutt/README.limit-current-thread
---- mutt-1.6.1/README.limit-current-thread	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/README.limit-current-thread	2016-06-12 18:43:00.670451770 +0100
-@@ -0,0 +1,45 @@
-+Limit-Current-Thread Patch
-+==========================
++	/* fetch previous values of first and last */
++	hdata = mutt_hcache_fetch_raw (hc, "index", strlen);
++	if (hdata)
++	{
++	  anum_t first, last;
 +
-+    Focus on one Email Thread
++	  if (sscanf (hdata, ANUM " " ANUM, &first, &last) == 2)
++	  {
++	    if (nntp_data->deleted)
++	    {
++	      nntp_data->firstMessage = first;
++	      nntp_data->lastMessage = last;
++	    }
++	    if (last >= nntp_data->firstMessage &&
++		last <= nntp_data->lastMessage)
++	    {
++	      nntp_data->lastCached = last;
++	      dprint (2, (debugfile, "nntp_select_server: %s lastCached=%u\n",
++			  nntp_data->group, last));
++	    }
++	  }
++	  FREE (&hdata);
++	}
++	mutt_hcache_close (hc);
++      }
++      closedir (dp);
++    }
++  }
++#endif
 +
-+Patch
-+-----
++  if (rc < 0 || !leave_lock)
++    nntp_newsrc_close (nserv);
 +
-+    To check if Mutt supports "limit-current-thread", look for
-+    "patch-limit-current-thread" in the mutt version.
++  if (rc < 0)
++  {
++    hash_destroy (&nserv->groups_hash, nntp_data_free);
++    FREE (&nserv->groups_list);
++    FREE (&nserv->newsrc_file);
++    FREE (&nserv->authenticators);
++    FREE (&nserv);
++    mutt_socket_close (conn);
++    mutt_socket_free (conn);
++    return NULL;
++  }
 +
-+    Dependencies
-+    * mutt-1.6.1
++  conn->data = nserv;
++  return nserv;
++}
 +
-+Introduction
-+------------
++/* Full status flags are not supported by nntp, but we can fake some of them:
++ * Read = a read message number is in the .newsrc
++ * New = not read and not cached
++ * Old = not read but cached */
++void nntp_article_status (CONTEXT *ctx, HEADER *hdr, char *group, anum_t anum)
++{
++  NNTP_DATA *nntp_data = ctx->data;
++  unsigned int i;
 +
-+    This patch adds a new way of using the Limit Command. The
-+    '<limit-current-thread>' function restricts the view to just the current
-+    thread.
-+    Setting the limit (the 'l' key) to "all" will restore the full email list.
++  if (group)
++    nntp_data = hash_find (nntp_data->nserv->groups_hash, group);
 +
-+Functions
-+---------
++  if (!nntp_data)
++    return;
 +
-+    | Menus | Default Key | Function                 | Description                  |
-+    |-------|-------------|--------------------------|------------------------------|
-+    | index | '<Esc> L'   | '<limit-current-thread>' | Limit view to current thread |
++  for (i = 0; i < nntp_data->newsrc_len; i++)
++  {
++    if ((anum >= nntp_data->newsrc_ent[i].first) &&
++	(anum <= nntp_data->newsrc_ent[i].last))
++    {
++      /* can't use mutt_set_flag() because mx_update_context()
++	 didn't called yet */
++      hdr->read = 1;
++      return;
++    }
++  }
 +
-+See Also
-+--------
++  /* article was not cached yet, it's new */
++  if (anum > nntp_data->lastCached)
++    return;
 +
-+    * NeoMutt project
++  /* article isn't read but cached, it's old */
++  if (option (OPTMARKOLD))
++    hdr->old = 1;
++}
 +
-+Known Bugs
-+----------
++/* calculate number of unread articles using .newsrc data */
++void nntp_group_unread_stat (NNTP_DATA *nntp_data)
++{
++  unsigned int i;
++  anum_t first, last;
 +
-+    None
++  nntp_data->unread = 0;
++  if (nntp_data->lastMessage == 0 ||
++      nntp_data->firstMessage > nntp_data->lastMessage)
++    return;
 +
-+Credits
-+-------
++  nntp_data->unread = nntp_data->lastMessage - nntp_data->firstMessage + 1;
++  for (i = 0; i < nntp_data->newsrc_len; i++)
++  {
++    first = nntp_data->newsrc_ent[i].first;
++    if (first < nntp_data->firstMessage)
++      first = nntp_data->firstMessage;
++    last = nntp_data->newsrc_ent[i].last;
++    if (last > nntp_data->lastMessage)
++      last = nntp_data->lastMessage;
++    if (first <= last)
++      nntp_data->unread -= last - first + 1;
++  }
++}
 +
-+    * David Sterba <dsterba at suse.cz>
-+    * Richard Russon <rich at flatcap.org>
++/* Subscribe newsgroup */
++NNTP_DATA *mutt_newsgroup_subscribe (NNTP_SERVER *nserv, char *group)
++{
++  NNTP_DATA *nntp_data;
 +
-diff -urN mutt-1.6.1/README.md mutt-1.6.1-neomutt/README.md
---- mutt-1.6.1/README.md	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/README.md	2016-06-12 18:43:00.670451770 +0100
-@@ -0,0 +1,79 @@
-+# This is the NeoMutt Project
++  if (!nserv || !nserv->groups_hash || !group || !*group)
++    return NULL;
 +
-+## What is NeoMutt?
++  nntp_data = nntp_data_find (nserv, group);
++  nntp_data->subscribed = 1;
++  if (!nntp_data->newsrc_ent)
++  {
++    nntp_data->newsrc_ent = safe_calloc (1, sizeof (NEWSRC_ENTRY));
++    nntp_data->newsrc_len = 1;
++    nntp_data->newsrc_ent[0].first = 1;
++    nntp_data->newsrc_ent[0].last = 0;
++  }
++  return nntp_data;
++}
 +
-+* NeoMutt is a project of projects.
-+* A place to gather all the patches against Mutt.
-+* A place for all the developers to gather.
++/* Unsubscribe newsgroup */
++NNTP_DATA *mutt_newsgroup_unsubscribe (NNTP_SERVER *nserv, char *group)
++{
++  NNTP_DATA *nntp_data;
 +
-+Hopefully this will build the community and reduce duplicated effort.
++  if (!nserv || !nserv->groups_hash || !group || !*group)
++    return NULL;
 +
-+NeoMutt was created when Richard Russon (FlatCap) took all the old Mutt patches,
-+sorted through them, fixed them up and documented them.
++  nntp_data = hash_find (nserv->groups_hash, group);
++  if (!nntp_data)
++    return NULL;
 +
-+## What Features does NeoMutt have?
++  nntp_data->subscribed = 0;
++  if (!option (OPTSAVEUNSUB))
++  {
++    nntp_data->newsrc_len = 0;
++    FREE (&nntp_data->newsrc_ent);
++  }
++  return nntp_data;
++}
 +
-+| Name                 | Description
-+|----------------------|-------------------------------------------------------
-+| Compressed Folders   | Read from/write to compressed mailboxes
-+| Conditional Dates    | Conditional Date Formatting
-+| Fmemopen             | Use fmemopen(3) for speedier temporary files
-+| Ifdef                | Conditional config options
-+| Index Color          | Theming of the Index List
-+| Initials Expando     | Expando for Author's Initials
-+| Keywords             | Labels/Tagging for emails
-+| Limit-Current-Thread | Limit Index View to Current Thread
-+| Nested If            | Allow deeply nested conditionals in format strings
-+| NNTP                 | Talk to a Usenet news server
-+| Notmuch              | Powerful email search engine
-+| Progress Bar         | Colourful Progress Bar
-+| Quasi-Delete         | Hide emails from view, but don't delete them
-+| Sidebar              | Panel containing list of Mailboxes
-+| Skip-Quoted          | Skip Quoted Text
-+| Status Color         | Theming of the Status Bar
-+| TLS-SNI              | Negotiate with a Server for a Certificate
-+| Trash Folder         | Move 'deleted' emails to a trash folder
++/* Catchup newsgroup */
++NNTP_DATA *mutt_newsgroup_catchup (NNTP_SERVER *nserv, char *group)
++{
++  NNTP_DATA *nntp_data;
 +
-+## Where is NeoMutt?
++  if (!nserv || !nserv->groups_hash || !group || !*group)
++    return NULL;
 +
-+- Source Code:     https://github.com/neomutt/neomutt
-+- Releases:        https://github.com/neomutt/neomutt/releases/latest
-+- Questions/Bugs:  https://github.com/neomutt/neomutt/issues
-+- Website:         http://www.neomutt.org/
-+- Development:     http://www.neomutt.org/devel/
++  nntp_data = hash_find (nserv->groups_hash, group);
++  if (!nntp_data)
++    return NULL;
 +
-+## NeoMutt Developers
++  if (nntp_data->newsrc_ent)
++  {
++    safe_realloc (&nntp_data->newsrc_ent, sizeof (NEWSRC_ENTRY));
++    nntp_data->newsrc_len = 1;
++    nntp_data->newsrc_ent[0].first = 1;
++    nntp_data->newsrc_ent[0].last = nntp_data->lastMessage;
++  }
++  nntp_data->unread = 0;
++  if (Context && Context->data == nntp_data)
++  {
++    unsigned int i;
 +
-+Here's a list of everyone who's helped NeoMutt:
++    for (i = 0; i < Context->msgcount; i++)
++      mutt_set_flag (Context, Context->hdrs[i], M_READ, 1);
++  }
++  return nntp_data;
++}
 +
-+Alex Pearce, Antonio Radici, Christoph Berg, Chris Salzberg, David Sterba,
-+Evgeni Golov, Fabian Groffen, Fabio Alessandro Locati, Faidon Liambotis,
-+Karel Zak, Kurt Jaeger, Matteo Vescovi, Richard Hartmann, Richard Russon,
-+Udo Schweigert, Werner Fink.
++/* Uncatchup newsgroup */
++NNTP_DATA *mutt_newsgroup_uncatchup (NNTP_SERVER *nserv, char *group)
++{
++  NNTP_DATA *nntp_data;
 +
-+## Original Patch Authors
++  if (!nserv || !nserv->groups_hash || !group || !*group)
++    return NULL;
 +
-+Without the original patch authors, there would be nothing.
-+So, a Big Thank You to:
++  nntp_data = hash_find (nserv->groups_hash, group);
++  if (!nntp_data)
++    return NULL;
 +
-+Aaron Schrab, Alain Penders, Benjamin Kuperman, Cedric Duval, Chris Mason,
-+Christian Aichinger, Christoph Berg, Christoph Rissner, David Champion,
-+David Riebenbauer, David Sterba, David Wilson, Don Zickus, Elimar Riesebieter,
-+Eric Davis, Evgeni Golov, Fabian Groffen, Felix von Leitner, Jan Synacek,
-+Jason DeTiberus, Jeremiah Foster, Jeremy Katz, Josh Poimboeuf, Julius Plenz,
-+Justin Hibbits, Karel Zak, Kirill Shutemov, Luke Macken, Mantas Mikulenas,
-+Matteo Vescovi, Patrick Brisbin, Paul Miller, Phil Pennock,
-+Philippe Le Brouster, Richard Russon, Rocco Rutte, Roland Rosenfeld, Sami Farin,
-+Stefan Assmann, Stefan Kuhn, Steve Kemp, Terry Chan, Thomas Glanzmann,
-+Thomer Gil, Tim Stoakes, Tyler Earnest, Victor Manuel Jaquez Leal,
-+Vincent Lefevre, Vladimir Marek, Vsevolod Volkov.
++  if (nntp_data->newsrc_ent)
++  {
++    safe_realloc (&nntp_data->newsrc_ent, sizeof (NEWSRC_ENTRY));
++    nntp_data->newsrc_len = 1;
++    nntp_data->newsrc_ent[0].first = 1;
++    nntp_data->newsrc_ent[0].last = nntp_data->firstMessage - 1;
++  }
++  if (Context && Context->data == nntp_data)
++  {
++    unsigned int i;
 +
-+## Original Mutt Authors
++    nntp_data->unread = Context->msgcount;
++    for (i = 0; i < Context->msgcount; i++)
++      mutt_set_flag (Context, Context->hdrs[i], M_READ, 0);
++  }
++  else
++    nntp_data->unread = nntp_data->lastMessage - nntp_data->newsrc_ent[0].last;
++  return nntp_data;
++}
 +
-+And of course, we should thank the original Mutt authors, including the original
-+author Michael Elkins and all the people that have contributed to Mutt during
-+its long history, see the Acknowledgements section of the user manual for a
-+detailed list.
++/* Get first newsgroup with new messages */
++void nntp_buffy (char *buf, size_t len)
++{
++  unsigned int i;
 +
-+http://www.neomutt.org/manual/miscellany.html#acknowledgements
++  for (i = 0; i < CurrentNewsSrv->groups_num; i++)
++  {
++    NNTP_DATA *nntp_data = CurrentNewsSrv->groups_list[i];
 +
-diff -urN mutt-1.6.1/README.neomutt mutt-1.6.1-neomutt/README.neomutt
---- mutt-1.6.1/README.neomutt	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/README.neomutt	2016-06-12 18:43:00.670451770 +0100
-@@ -0,0 +1,79 @@
-+# This is the NeoMutt Project
++    if (!nntp_data || !nntp_data->subscribed || !nntp_data->unread)
++      continue;
 +
-+## What is NeoMutt?
++    if (Context && Context->magic == M_NNTP &&
++	!mutt_strcmp (nntp_data->group, ((NNTP_DATA *)Context->data)->group))
++    {
++      unsigned int i, unread = 0;
 +
-+* NeoMutt is a project of projects.
-+* A place to gather all the patches against Mutt.
-+* A place for all the developers to gather.
++      for (i = 0; i < Context->msgcount; i++)
++	if (!Context->hdrs[i]->read && !Context->hdrs[i]->deleted)
++	  unread++;
++      if (!unread)
++	continue;
++    }
++    strfcpy (buf, nntp_data->group, len);
++    break;
++  }
++}
+diff --git a/nntp.c b/nntp.c
+new file mode 100644
+index 0000000..9ec5ced
+--- /dev/null
++++ b/nntp.c
+@@ -0,0 +1,2434 @@
++/*
++ * Copyright (C) 1998 Brandon Long <blong at fiction.net>
++ * Copyright (C) 1999 Andrej Gritsenko <andrej at lucky.net>
++ * Copyright (C) 2000-2012 Vsevolod Volkov <vvv at mutt.org.ua>
++ *
++ *     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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
 +
-+Hopefully this will build the community and reduce duplicated effort.
++#if HAVE_CONFIG_H
++#include "config.h"
++#endif
 +
-+NeoMutt was created when Richard Russon (FlatCap) took all the old Mutt patches,
-+sorted through them, fixed them up and documented them.
++#include "mutt.h"
++#include "mutt_curses.h"
++#include "sort.h"
++#include "mx.h"
++#include "mime.h"
++#include "rfc1524.h"
++#include "rfc2047.h"
++#include "mailbox.h"
++#include "mutt_crypt.h"
++#include "nntp.h"
 +
-+## What Features does NeoMutt have?
++#if defined(USE_SSL)
++#include "mutt_ssl.h"
++#endif
 +
-+| Name                 | Description
-+|----------------------|-------------------------------------------------------
-+| Compressed Folders   | Read from/write to compressed mailboxes
-+| Conditional Dates    | Conditional Date Formatting
-+| Fmemopen             | Use fmemopen(3) for speedier temporary files
-+| Ifdef                | Conditional config options
-+| Index Color          | Theming of the Index List
-+| Initials Expando     | Expando for Author's Initials
-+| Keywords             | Labels/Tagging for emails
-+| Limit-Current-Thread | Limit Index View to Current Thread
-+| Nested If            | Allow deeply nested conditionals in format strings
-+| NNTP                 | Talk to a Usenet news server
-+| Notmuch              | Powerful email search engine
-+| Progress Bar         | Colourful Progress Bar
-+| Quasi-Delete         | Hide emails from view, but don't delete them
-+| Sidebar              | Panel containing list of Mailboxes
-+| Skip-Quoted          | Skip Quoted Text
-+| Status Color         | Theming of the Status Bar
-+| TLS-SNI              | Negotiate with a Server for a Certificate
-+| Trash Folder         | Move 'deleted' emails to a trash folder
++#ifdef HAVE_PGP
++#include "pgp.h"
++#endif
 +
-+## Where is NeoMutt?
++#ifdef HAVE_SMIME
++#include "smime.h"
++#endif
 +
-+- Source Code:     https://github.com/neomutt/neomutt
-+- Releases:        https://github.com/neomutt/neomutt/releases/latest
-+- Questions/Bugs:  https://github.com/neomutt/neomutt/issues
-+- Website:         http://www.neomutt.org/
-+- Development:     http://www.neomutt.org/devel/
++#if USE_HCACHE
++#include "hcache.h"
++#endif
 +
-+## NeoMutt Developers
++#include <unistd.h>
++#include <string.h>
++#include <ctype.h>
++#include <stdlib.h>
 +
-+Here's a list of everyone who's helped NeoMutt:
++#ifdef USE_SASL
++#include <sasl/sasl.h>
++#include <sasl/saslutil.h>
 +
-+Alex Pearce, Antonio Radici, Christoph Berg, Chris Salzberg, David Sterba,
-+Evgeni Golov, Fabian Groffen, Fabio Alessandro Locati, Faidon Liambotis,
-+Karel Zak, Kurt Jaeger, Matteo Vescovi, Richard Hartmann, Richard Russon,
-+Udo Schweigert, Werner Fink.
++#include "mutt_sasl.h"
++#endif
 +
-+## Original Patch Authors
++static int nntp_connect_error (NNTP_SERVER *nserv)
++{
++  nserv->status = NNTP_NONE;
++  mutt_error _("Server closed connection!");
++  mutt_sleep (2);
++  return -1;
++}
 +
-+Without the original patch authors, there would be nothing.
-+So, a Big Thank You to:
++/* Get capabilities:
++ * -1 - error, connection is closed
++ *  0 - mode is reader, capabilities setted up
++ *  1 - need to switch to reader mode */
++static int nntp_capabilities (NNTP_SERVER *nserv)
++{
++  CONNECTION *conn = nserv->conn;
++  unsigned int mode_reader = 0;
++  char buf[LONG_STRING];
++  char authinfo[LONG_STRING] = "";
 +
-+Aaron Schrab, Alain Penders, Benjamin Kuperman, Cedric Duval, Chris Mason,
-+Christian Aichinger, Christoph Berg, Christoph Rissner, David Champion,
-+David Riebenbauer, David Sterba, David Wilson, Don Zickus, Elimar Riesebieter,
-+Eric Davis, Evgeni Golov, Fabian Groffen, Felix von Leitner, Jan Synacek,
-+Jason DeTiberus, Jeremiah Foster, Jeremy Katz, Josh Poimboeuf, Julius Plenz,
-+Justin Hibbits, Karel Zak, Kirill Shutemov, Luke Macken, Mantas Mikulenas,
-+Matteo Vescovi, Patrick Brisbin, Paul Miller, Phil Pennock,
-+Philippe Le Brouster, Richard Russon, Rocco Rutte, Roland Rosenfeld, Sami Farin,
-+Stefan Assmann, Stefan Kuhn, Steve Kemp, Terry Chan, Thomas Glanzmann,
-+Thomer Gil, Tim Stoakes, Tyler Earnest, Victor Manuel Jaquez Leal,
-+Vincent Lefevre, Vladimir Marek, Vsevolod Volkov.
++  nserv->hasCAPABILITIES = 0;
++  nserv->hasSTARTTLS = 0;
++  nserv->hasDATE = 0;
++  nserv->hasLIST_NEWSGROUPS = 0;
++  nserv->hasLISTGROUP = 0;
++  nserv->hasLISTGROUPrange = 0;
++  nserv->hasOVER = 0;
++  FREE (&nserv->authenticators);
 +
-+## Original Mutt Authors
++  if (mutt_socket_write (conn, "CAPABILITIES\r\n") < 0 ||
++      mutt_socket_readln (buf, sizeof (buf), conn) < 0)
++    return nntp_connect_error (nserv);
 +
-+And of course, we should thank the original Mutt authors, including the original
-+author Michael Elkins and all the people that have contributed to Mutt during
-+its long history, see the Acknowledgements section of the user manual for a
-+detailed list.
++  /* no capabilities */
++  if (mutt_strncmp ("101", buf, 3))
++    return 1;
++  nserv->hasCAPABILITIES = 1;
 +
-+http://www.neomutt.org/manual/miscellany.html#acknowledgements
++  /* parse capabilities */
++  do
++  {
++    if (mutt_socket_readln (buf, sizeof (buf), conn) < 0)
++      return nntp_connect_error (nserv);
++    if (!mutt_strcmp ("STARTTLS", buf))
++      nserv->hasSTARTTLS = 1;
++    else if (!mutt_strcmp ("MODE-READER", buf))
++      mode_reader = 1;
++    else if (!mutt_strcmp ("READER", buf))
++    {
++      nserv->hasDATE = 1;
++      nserv->hasLISTGROUP = 1;
++      nserv->hasLISTGROUPrange = 1;
++    }
++    else if (!mutt_strncmp ("AUTHINFO ", buf, 9))
++    {
++      safe_strcat (buf, sizeof (buf), " ");
++      strfcpy (authinfo, buf + 8, sizeof (authinfo));
++    }
++#ifdef USE_SASL
++    else if (!mutt_strncmp ("SASL ", buf, 5))
++    {
++      char *p = buf + 5;
++      while (*p == ' ')
++	p++;
++      nserv->authenticators = safe_strdup (p);
++    }
++#endif
++    else if (!mutt_strcmp ("OVER", buf))
++      nserv->hasOVER = 1;
++    else if (!mutt_strncmp ("LIST ", buf, 5))
++    {
++      char *p = strstr (buf, " NEWSGROUPS");
++      if (p)
++      {
++	p += 11;
++	if (*p == '\0' || *p == ' ')
++	  nserv->hasLIST_NEWSGROUPS = 1;
++      }
++    }
++  } while (mutt_strcmp (".", buf));
++  *buf = '\0';
++#ifdef USE_SASL
++  if (nserv->authenticators && strcasestr (authinfo, " SASL "))
++    strfcpy (buf, nserv->authenticators, sizeof (buf));
++#endif
++  if (strcasestr (authinfo, " USER "))
++  {
++    if (*buf)
++      safe_strcat (buf, sizeof (buf), " ");
++    safe_strcat (buf, sizeof (buf), "USER");
++  }
++  mutt_str_replace (&nserv->authenticators, buf);
 +
-diff -urN mutt-1.6.1/README.nested-if mutt-1.6.1-neomutt/README.nested-if
---- mutt-1.6.1/README.nested-if	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/README.nested-if	2016-06-12 18:43:00.670451770 +0100
-@@ -0,0 +1,125 @@
-+Nested If Patch
-+===============
++  /* current mode is reader */
++  if (nserv->hasDATE)
++    return 0;
 +
-+    Allow complex nested conditions in format strings
++  /* server is mode-switching, need to switch to reader mode */
++  if (mode_reader)
++    return 1;
 +
-+Patch
-+-----
++  mutt_socket_close (conn);
++  nserv->status = NNTP_BYE;
++  mutt_error _("Server doesn't support reader mode.");
++  mutt_sleep (2);
++  return -1;
++}
 +
-+    To check if Mutt supports "Nested If", look for "patch-nested-if" in the
-+    mutt version.
++char *OverviewFmt =
++	"Subject:\0"
++	"From:\0"
++	"Date:\0"
++	"Message-ID:\0"
++	"References:\0"
++	"Content-Length:\0"
++	"Lines:\0"
++	"\0";
 +
-+    Dependencies
-+    * mutt-1.6.1
++/* Detect supported commands */
++static int nntp_attempt_features (NNTP_SERVER *nserv)
++{
++  CONNECTION *conn = nserv->conn;
++  char buf[LONG_STRING];
 +
-+Introduction
-+------------
++  /* no CAPABILITIES, trying DATE, LISTGROUP, LIST NEWSGROUPS */
++  if (!nserv->hasCAPABILITIES)
++  {
++    if (mutt_socket_write (conn, "DATE\r\n") < 0 ||
++	mutt_socket_readln (buf, sizeof (buf), conn) < 0)
++      return nntp_connect_error (nserv);
++    if (mutt_strncmp ("500", buf, 3))
++      nserv->hasDATE = 1;
 +
-+    Mutt's format strings can contain embedded if-then-else conditions. They
-+    are of the form:
++    if (mutt_socket_write (conn, "LISTGROUP\r\n") < 0 ||
++	mutt_socket_readln (buf, sizeof (buf), conn) < 0)
++      return nntp_connect_error (nserv);
++    if (mutt_strncmp ("500", buf, 3))
++      nserv->hasLISTGROUP = 1;
 +
-+        %?VAR?TRUE&FALSE?
++    if (mutt_socket_write (conn, "LIST NEWSGROUPS +\r\n") < 0 ||
++	mutt_socket_readln (buf, sizeof (buf), conn) < 0)
++      return nntp_connect_error (nserv);
++    if (mutt_strncmp ("500", buf, 3))
++      nserv->hasLIST_NEWSGROUPS = 1;
++    if (!mutt_strncmp ("215", buf, 3))
++    {
++      do
++      {
++	if (mutt_socket_readln (buf, sizeof (buf), conn) < 0)
++	  return nntp_connect_error (nserv);
++      } while (mutt_strcmp (".", buf));
++    }
++  }
 +
-+    If the variable "VAR" has a value greater than zero, print the "TRUE"
-+    string, otherwise print the "FALSE" string.
++  /* no LIST NEWSGROUPS, trying XGTITLE */
++  if (!nserv->hasLIST_NEWSGROUPS)
++  {
++    if (mutt_socket_write (conn, "XGTITLE\r\n") < 0 ||
++	mutt_socket_readln (buf, sizeof (buf), conn) < 0)
++      return nntp_connect_error (nserv);
++    if (mutt_strncmp ("500", buf, 3))
++      nserv->hasXGTITLE = 1;
++  }
 +
-+    e.g. '%?S?Size: %S&Empty?'
++  /* no OVER, trying XOVER */
++  if (!nserv->hasOVER)
++  {
++    if (mutt_socket_write (conn, "XOVER\r\n") < 0 ||
++	mutt_socket_readln (buf, sizeof (buf), conn) < 0)
++      return nntp_connect_error (nserv);
++    if (mutt_strncmp ("500", buf, 3))
++      nserv->hasXOVER = 1;
++  }
 +
-+    Which can be read as:
++  /* trying LIST OVERVIEW.FMT */
++  if (nserv->hasOVER || nserv->hasXOVER)
++  {
++    if (mutt_socket_write (conn, "LIST OVERVIEW.FMT\r\n") < 0 ||
++	mutt_socket_readln (buf, sizeof (buf), conn) < 0)
++      return nntp_connect_error (nserv);
++    if (mutt_strncmp ("215", buf, 3))
++      nserv->overview_fmt = OverviewFmt;
++    else
++    {
++      int chunk, cont = 0;
++      size_t buflen = 2 * LONG_STRING, off = 0, b = 0;
 +
-+        if (%S > 0) {
-+            print "Size: %S"
-+        } else {
-+            print "Empty"
-+        }
++      if (nserv->overview_fmt)
++	FREE (&nserv->overview_fmt);
++      nserv->overview_fmt = safe_malloc (buflen);
 +
++      while (1)
++      {
++	if (buflen - off < LONG_STRING)
++	{
++	  buflen *= 2;
++	  safe_realloc (&nserv->overview_fmt, buflen);
++	}
 +
-+    These conditions are useful, but in Mutt they cannot be nested within one
-+    another. This patch uses the notation '%<VAR?TRUE&FALSE>' and allows them
-+    to be nested.
++	chunk = mutt_socket_readln (nserv->overview_fmt + off,
++				    buflen - off, conn);
++	if (chunk < 0)
++	{
++	  FREE (&nserv->overview_fmt);
++	  return nntp_connect_error (nserv);
++	}
 +
-+    The '%<...>' notation was used to format the current local time. but that's
-+    not really very useful since mutt has no means of refreshing the screen
-+    periodically.
++	if (!cont && !mutt_strcmp (".", nserv->overview_fmt + off))
++	  break;
 +
-+    A simple nested condition might be: (Some whitespace has been introduced
-+    for clarity)
++	cont = chunk >= buflen - off ? 1 : 0;
++	off += strlen (nserv->overview_fmt + off);
++	if (!cont)
++	{
++	  char *colon;
 +
-+        %<x? %<y? XY & X > & %<y? Y & NONE > >  Conditions
-+             %<y? XY & X >                      x>0
-+                  XY                            x>0,y>0
-+                       X                        x>0,y=0
++	  if (nserv->overview_fmt[b] == ':')
++	  {
++	    memmove (nserv->overview_fmt + b,
++		     nserv->overview_fmt + b + 1, off - b - 1);
++	    nserv->overview_fmt[off - 1] = ':';
++	  }
++	  colon = strchr (nserv->overview_fmt + b, ':');
++	  if (!colon)
++	    nserv->overview_fmt[off++] = ':';
++	  else if (strcmp (colon + 1, "full"))
++	    off = colon + 1 - nserv->overview_fmt;
++	  if (!strcasecmp (nserv->overview_fmt + b, "Bytes:"))
++	  {
++	    strcpy (nserv->overview_fmt + b, "Content-Length:");
++	    off = b + strlen (nserv->overview_fmt + b);
++	  }
++	  nserv->overview_fmt[off++] = '\0';
++	  b = off;
++	}
++      }
++      nserv->overview_fmt[off++] = '\0';
++      safe_realloc (&nserv->overview_fmt, off);
++    }
++  }
++  return 0;
++}
 +
++/* Get login, password and authenticate */
++static int nntp_auth (NNTP_SERVER *nserv)
++{
++  CONNECTION *conn = nserv->conn;
++  char buf[LONG_STRING];
++  char authenticators[LONG_STRING] = "USER";
++  char *method, *a, *p;
++  unsigned char flags = conn->account.flags;
 +
-+        %<x? %<y? XY & X > & %<y? Y & NONE > >  Conditions
-+                             %<y? Y & NONE >    x=0
-+                                  Y             x=0,y>0
-+                                      NONE      x=0,y=0
++  while (1)
++  {
++    /* get login and password */
++    if (mutt_account_getuser (&conn->account) || !conn->account.user[0] ||
++	mutt_account_getpass (&conn->account) || !conn->account.pass[0])
++      break;
 +
++    /* get list of authenticators */
++    if (NntpAuthenticators && *NntpAuthenticators)
++      strfcpy (authenticators, NntpAuthenticators, sizeof (authenticators));
++    else if (nserv->hasCAPABILITIES)
++    {
++      strfcpy (authenticators, NONULL (nserv->authenticators),
++	       sizeof (authenticators));
++      p = authenticators;
++      while (*p)
++      {
++	if (*p == ' ')
++	  *p = ':';
++	p++;
++      }
++    }
++    p = authenticators;
++    while (*p)
++    {
++      *p = ascii_toupper (*p);
++      p++;
++    }
 +
-+    Equivalent to:
++    dprint (1, (debugfile,
++		"nntp_auth: available methods: %s\n", nserv->authenticators));
++    a = authenticators;
++    while (1)
++    {
++      if (!a)
++      {
++	mutt_error _("No authenticators available");
++	mutt_sleep (2);
++	break;
++      }
 +
-+        if (x > 0) {
-+            if (y > 0) {
-+                print 'XY'
-+            } else {
-+                print 'X'
-+            }
-+        } else {
-+            if (y > 0) {
-+                print 'Y'
-+            } else {
-+                print 'NONE'
-+            }
-+        }
++      method = a;
++      a = strchr (a, ':');
++      if (a)
++	*a++ = '\0';
 +
++      /* check authenticator */
++      if (nserv->hasCAPABILITIES)
++      {
++	char *m;
 +
-+    Examples:
++	if (!nserv->authenticators)
++	  continue;
++	m = strcasestr (nserv->authenticators, method);
++	if (!m)
++	  continue;
++	if (m > nserv->authenticators && *(m - 1) != ' ')
++	  continue;
++	m += strlen (method);
++	if (*m != '\0' && *m != ' ')
++	  continue;
++      }
++      dprint (1, (debugfile, "nntp_auth: trying method %s\n", method));
 +
-+        set index_format='%4C %Z %{%b %d} %-25.25n %s%> %<M?%M Msgs &%<l?%l Lines&%c Bytes>>'
++      /* AUTHINFO USER authentication */
++      if (!strcmp (method, "USER"))
++      {
++	mutt_message (_("Authenticating (%s)..."), method);
++	snprintf (buf, sizeof (buf), "AUTHINFO USER %s\r\n", conn->account.user);
++	if (mutt_socket_write (conn, buf) < 0 ||
++	    mutt_socket_readln (buf, sizeof (buf), conn) < 0)
++	  break;
 +
-+        if a thread is folded
-+            display the number of messages (%M)
-+        else if we know how many lines in the message
-+            display lines in message (%l)
-+        else
-+            display the size of the message in bytes (%c)
++	/* authenticated, password is not required */
++	if (!mutt_strncmp ("281", buf, 3))
++	  return 0;
 +
++	/* username accepted, sending password */
++	if (!mutt_strncmp ("381", buf, 3))
++	{
++#ifdef DEBUG
++	  if (debuglevel < M_SOCK_LOG_FULL)
++	    dprint (M_SOCK_LOG_CMD, (debugfile,
++		    "%d> AUTHINFO PASS *\n", conn->fd));
++#endif
++	  snprintf (buf, sizeof (buf), "AUTHINFO PASS %s\r\n",
++		    conn->account.pass);
++	  if (mutt_socket_write_d (conn, buf, -1, M_SOCK_LOG_FULL) < 0 ||
++	      mutt_socket_readln (buf, sizeof (buf), conn) < 0)
++	  break;
 +
-+        set index_format='%4C %Z %{%b %d} %-25.25n %<M?[%M] %s&%s%* %<l?%l&%c>>'
++	  /* authenticated */
++	  if (!mutt_strncmp ("281", buf, 3))
++	    return 0;
++	}
 +
-+        if a thread is folded
-+            display the number of messages (%M)
-+            display the subject (%s)
-+        else if we know how many lines in the message
-+            display lines in message (%l)
-+        else
-+            display the size of the message in bytes (%c)
++	/* server doesn't support AUTHINFO USER, trying next method */
++	if (*buf == '5')
++	  continue;
++      }
 +
++      else
++      {
++#ifdef USE_SASL
++	sasl_conn_t *saslconn;
++	sasl_interact_t *interaction = NULL;
++	int rc;
++	char inbuf[LONG_STRING] = "";
++	const char *mech;
++	const char *client_out = NULL;
++	unsigned int client_len, len;
 +
-+Variables
-+---------
++	if (mutt_sasl_client_new (conn, &saslconn) < 0)
++	{
++	  dprint (1, (debugfile,
++		  "nntp_auth: error allocating SASL connection.\n"));
++	  continue;
++	}
 +
-+    The nested-if patch doesn't have any config of its own. It modifies the behavior of the
-+    format strings.
++	while (1)
++	{
++	  rc = sasl_client_start (saslconn, method, &interaction,
++				  &client_out, &client_len, &mech);
++	  if (rc != SASL_INTERACT)
++	    break;
++	  mutt_sasl_interact (interaction);
++	}
++	if (rc != SASL_OK && rc != SASL_CONTINUE)
++	{
++	  sasl_dispose (&saslconn);
++	  dprint (1, (debugfile,
++		  "nntp_auth: error starting SASL authentication exchange.\n"));
++	  continue;
++	}
 +
-+See Also
-+--------
++	mutt_message (_("Authenticating (%s)..."), method);
++	snprintf (buf, sizeof (buf), "AUTHINFO SASL %s", method);
 +
-+    * NeoMutt project
-+    * cond-date patch
-+    * $index_format
-+    * $status_format
++	/* looping protocol */
++	while (rc == SASL_CONTINUE || (rc == SASL_OK && client_len))
++	{
++	  /* send out client response */
++	  if (client_len)
++	  {
++#ifdef DEBUG
++	    if (debuglevel >= M_SOCK_LOG_FULL)
++	    {
++	      char tmp[LONG_STRING];
++	      memcpy (tmp, client_out, client_len);
++	      for (p = tmp; p < tmp + client_len; p++)
++	      {
++		if (*p == '\0')
++		  *p = '.';
++	      }
++	      *p = '\0';
++	      dprint (1, (debugfile, "SASL> %s\n", tmp));
++	    }
++#endif
 +
-+Known Bugs
-+----------
++	    if (*buf)
++	      safe_strcat (buf, sizeof (buf), " ");
++	    len = strlen (buf);
++	    if (sasl_encode64 (client_out, client_len,
++		buf + len, sizeof (buf) - len, &len) != SASL_OK)
++	    {
++	      dprint (1, (debugfile,
++		      "nntp_auth: error base64-encoding client response.\n"));
++	      break;
++	    }
++	  }
 +
-+    Patch overwrites $<fmt> handler in
-+    $index_format
++	  safe_strcat (buf, sizeof (buf), "\r\n");
++#ifdef DEBUG
++	  if (debuglevel < M_SOCK_LOG_FULL)
++	  {
++	    if (strchr (buf, ' '))
++	      dprint (M_SOCK_LOG_CMD, (debugfile, "%d> AUTHINFO SASL %s%s\n",
++		      conn->fd, method, client_len ? " sasl_data" : ""));
++	    else
++	      dprint (M_SOCK_LOG_CMD, (debugfile, "%d> sasl_data\n", conn->fd));
++	  }
++#endif
++	  client_len = 0;
++	  if (mutt_socket_write_d (conn, buf, -1, M_SOCK_LOG_FULL) < 0 ||
++	      mutt_socket_readln_d (inbuf, sizeof (inbuf), conn, M_SOCK_LOG_FULL) < 0)
++	    break;
++	  if (mutt_strncmp (inbuf, "283 ", 4) &&
++	      mutt_strncmp (inbuf, "383 ", 4))
++	  {
++#ifdef DEBUG
++	    if (debuglevel < M_SOCK_LOG_FULL)
++	      dprint (M_SOCK_LOG_CMD, (debugfile, "%d< %s\n", conn->fd, inbuf));
++#endif
++	    break;
++	  }
++#ifdef DEBUG
++	  if (debuglevel < M_SOCK_LOG_FULL)
++	  {
++	    inbuf[3] = '\0';
++	    dprint (M_SOCK_LOG_CMD, (debugfile,
++		    "%d< %s sasl_data\n", conn->fd, inbuf));
++	  }
++#endif
 +
-+Credits
-+-------
++	  if (!strcmp ("=", inbuf + 4))
++	    len = 0;
++	  else if (sasl_decode64 (inbuf + 4, strlen (inbuf + 4),
++		   buf, sizeof (buf) - 1, &len) != SASL_OK)
++	  {
++	    dprint (1, (debugfile,
++		    "nntp_auth: error base64-decoding server response.\n"));
++	    break;
++	  }
++#ifdef DEBUG
++	  else if (debuglevel >= M_SOCK_LOG_FULL)
++	  {
++	    char tmp[LONG_STRING];
++	    memcpy (tmp, buf, len);
++	    for (p = tmp; p < tmp + len; p++)
++	    {
++	      if (*p == '\0')
++		*p = '.';
++	    }
++	    *p = '\0';
++	    dprint (1, (debugfile, "SASL< %s\n", tmp));
++	  }
++#endif
 +
-+    * David Champion <dgc at uchicago.edu>
-+    * Richard Russon <rich at flatcap.org>
++	  while (1)
++	  {
++	    rc = sasl_client_step (saslconn, buf, len,
++				   &interaction, &client_out, &client_len);
++	    if (rc != SASL_INTERACT)
++	      break;
++	    mutt_sasl_interact (interaction);
++	  }
++	  if (*inbuf != '3')
++	    break;
 +
-diff -urN mutt-1.6.1/README.nntp mutt-1.6.1-neomutt/README.nntp
---- mutt-1.6.1/README.nntp	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/README.nntp	2016-06-12 18:43:00.671451785 +0100
-@@ -0,0 +1,122 @@
-+NNTP Patch
-+==========
++	  *buf = '\0';
++	} /* looping protocol */
 +
-+    Talk to a Usenet news server
++	if (rc == SASL_OK && client_len == 0 && *inbuf == '2')
++	{
++	  mutt_sasl_setup_conn (conn, saslconn);
++	  return 0;
++	}
 +
-+Patch
-+-----
++	/* terminate SASL sessoin */
++	sasl_dispose (&saslconn);
++	if (conn->fd < 0)
++	  break;
++	if (!mutt_strncmp (inbuf, "383 ", 4))
++	{
++	  if (mutt_socket_write (conn, "*\r\n") < 0 ||
++	      mutt_socket_readln (inbuf, sizeof (inbuf), conn) < 0)
++	    break;
++	}
 +
-+    To check if Mutt supports "NNTP", look for "+USE_NNTP" in the mutt version.
++	/* server doesn't support AUTHINFO SASL, trying next method */
++	if (*inbuf == '5')
++	  continue;
++#else
++	continue;
++#endif /* USE_SASL */
++      }
 +
-+    Dependencies
-+    * mutt-1.5.24
++      mutt_error (_("%s authentication failed."), method);
++      mutt_sleep (2);
++      break;
++    }
++    break;
++  }
++
++  /* error */
++  nserv->status = NNTP_BYE;
++  conn->account.flags = flags;
++  if (conn->fd < 0)
++  {
++    mutt_error _("Server closed connection!");
++    mutt_sleep (2);
++  }
++  else
++    mutt_socket_close (conn);
++  return -1;
++}
 +
-+Introduction
-+------------
++/* Connect to server, authenticate and get capabilities */
++int nntp_open_connection (NNTP_SERVER *nserv)
++{
++  CONNECTION *conn = nserv->conn;
++  char buf[STRING];
++  int cap;
++  unsigned int posting = 0, auth = 1;
 +
-+    Reading news via NNTP
++  if (nserv->status == NNTP_OK)
++    return 0;
++  if (nserv->status == NNTP_BYE)
++    return -1;
++  nserv->status = NNTP_NONE;
 +
-+    If compiled with *--enable-nntp* option, Mutt can read news from news
-+    server via NNTP. You can open a newsgroup with function
-+    ''change-newsgroup'' (default: ''i''). Default news server can be obtained
-+    from '$NNTPSERVER' environment variable or from '/etc/nntpserver' file.
-+    Like other news readers, info about subscribed newsgroups is saved in file
-+    by $newsrc variable. The variable $news_cache_dir can be used to point to a
-+    directory. Mutt will create a hierarchy of subdirectories named like the
-+    account and newsgroup the cache is for. Also the hierarchy is used to store
-+    header cache if Mutt was compiled with header cache support.
++  if (mutt_socket_open (conn) < 0)
++    return -1;
 +
-+Variables
-+---------
++  if (mutt_socket_readln (buf, sizeof (buf), conn) < 0)
++    return nntp_connect_error (nserv);
 +
-+    NNTP Variables
++  if (!mutt_strncmp ("200", buf, 3))
++    posting = 1;
++  else if (mutt_strncmp ("201", buf, 3))
++  {
++    mutt_socket_close (conn);
++    mutt_remove_trailing_ws (buf);
++    mutt_error ("%s", buf);
++    mutt_sleep (2);
++    return -1;
++  }
 +
-+    | Name                    | Type    | Default                     |
-+    |-------------------------|---------|-----------------------------|
-+    | 'ask_follow_up'         | boolean | 'no'                        |
-+    | 'ask_x_comment_to'      | boolean | 'no'                        |
-+    | 'catchup_newsgroup'     | quad    | 'ask-yes'                   |
-+    | 'followup_to_poster'    | quad    | 'ask-yes'                   |
-+    | 'group_index_format'    | string  | '%4C %M%N %5s  %-45.45f %d' |
-+    | 'inews'                 | string  | (empty)                     |
-+    | 'mime_subject'          | boolean | 'yes'                       |
-+    | 'newsgroups_charset'    | string  | 'utf-8'                     |
-+    | 'newsrc'                | string  | '~/.newsrc'                 |
-+    | 'news_cache_dir'        | string  | '~/.mutt'                   |
-+    | 'news_server'           | string  | (empty)                     |
-+    | 'nntp_authenticators'   | string  | (empty)                     |
-+    | 'nntp_context'          | number  | '1000'                      |
-+    | 'nntp_listgroup'        | boolean | 'yes'                       |
-+    | 'nntp_load_description' | boolean | 'yes'                       |
-+    | 'nntp_pass'             | string  | (empty)                     |
-+    | 'nntp_poll'             | number  | '60'                        |
-+    | 'nntp_user'             | string  | (empty)                     |
-+    | 'post_moderated'        | quad    | 'ask-yes'                   |
-+    | 'save_unsubscribed'     | boolean | 'no'                        |
-+    | 'show_new_news'         | boolean | 'yes'                       |
-+    | 'show_only_unread'      | boolean | 'no'                        |
-+    | 'x_comment_to'          | boolean | 'no'                        |
++  /* get initial capabilities */
++  cap = nntp_capabilities (nserv);
++  if (cap < 0)
++    return -1;
 +
-+Functions
-+---------
++  /* tell news server to switch to mode reader if it isn't so */
++  if (cap > 0)
++  {
++    if (mutt_socket_write (conn, "MODE READER\r\n") < 0 ||
++	mutt_socket_readln (buf, sizeof (buf), conn) < 0)
++      return nntp_connect_error (nserv);
 +
-+    NNTP Functions
++    if (!mutt_strncmp ("200", buf, 3))
++      posting = 1;
++    else if (!mutt_strncmp ("201", buf, 3))
++      posting = 0;
++    /* error if has capabilities, ignore result if no capabilities */
++    else if (nserv->hasCAPABILITIES)
++    {
++      mutt_socket_close (conn);
++      mutt_error _("Could not switch to reader mode.");
++      mutt_sleep (2);
++      return -1;
++    }
 +
-+    | Menus                  | Default Key | Function                      | Description                                    |
-+    |------------------------|-------------|-------------------------------|------------------------------------------------|
-+    | browser,index          | y           | '<catchup>'                   | mark all articles in newsgroup as read         |
-+    | index,pager            | i           | '<change-newsgroup>'          | open a different newsgroup                     |
-+    | pager                  | X           | '<change-vfolder>'            | open a different virtual folder                |
-+    | compose                | o           | '<edit-followup-to>'          | edit the Followup-To field                     |
-+    | compose                | N           | '<edit-newsgroups>'           | edit the newsgroups list                       |
-+    | compose                | x           | '<edit-x-comment-to>'         | edit the X-Comment-To field                    |
-+    | pager                  | +           | '<entire-thread>'             | read entire thread of the current message      |
-+    | attachment,index,pager | F           | '<followup-message>'          | followup to newsgroup                          |
-+    | pager                  | `           | '<modify-labels>'             | modify (notmuch) tags                          |
-+    | index,pager            | P           | '<post-message>'              | post message to newsgroup                      |
-+    | browser                | g           | '<reload-active>'             | load list of all newsgroups from NNTP server   |
-+    | browser                | s           | '<subscribe>'                 | subscribe to current mbox (IMAP/NNTP only)     |
-+    | browser                | S           | '<subscribe-pattern>'         | subscribe to newsgroups matching a pattern     |
-+    | browser                | Y           | '<uncatchup>'                 | mark all articles in newsgroup as unread       |
-+    | browser                | u           | '<unsubscribe>'               | unsubscribe from current mbox (IMAP/NNTP only) |
-+    | browser                | U           | '<unsubscribe-pattern>'       | unsubscribe from newsgroups matching a pattern |
-+    | index,pager            | Alt-i       | '<change-newsgroup-readonly>' | open a different newsgroup in read only mode   |
-+    | attachment,index,pager | Alt-F       | '<forward-to-group>'          | forward to newsgroup                           |
-+    | index                  | (none)      | '<get-children>'              | get all children of the current message        |
-+    | index                  | Alt-G       | '<get-parent>'                | get parent of the current message              |
-+    | index,pager            | (none)      | '<imap-fetch-mail>'           | force retrieval of mail from IMAP server       |
-+    | index,pager            | (none)      | '<imap-logout-all>'           | logout from all IMAP servers                   |
-+    | pager                  | (none)      | '<modify-labels-then-hide>'   | modify labeld and then hide message            |
-+    | index                  | (none)      | '<reconstruct-thread>'        | reconstruct thread containing current message  |
-+    | pager                  | Alt-X       | '<vfolder-from-query>'        | generate virtual folder from query             |
-+    | index                  | Ctrl-G      | '<get-message>'               | get message with Message-Id                    |
++    /* recheck capabilities after MODE READER */
++    if (nserv->hasCAPABILITIES)
++    {
++      cap = nntp_capabilities (nserv);
++      if (cap < 0)
++	return -1;
++    }
++  }
 +
-+Commands
-+--------
++  mutt_message (_("Connected to %s. %s"), conn->account.host,
++		posting ? _("Posting is ok.") : _("Posting is NOT ok."));
++  mutt_sleep (1);
 +
-+Colors
-+------
++#if defined(USE_SSL)
++  /* Attempt STARTTLS if available and desired. */
++  if (nserv->use_tls != 1 && (nserv->hasSTARTTLS || option (OPTSSLFORCETLS)))
++  {
++    if (nserv->use_tls == 0)
++      nserv->use_tls = option (OPTSSLFORCETLS) ||
++			query_quadoption (OPT_SSLSTARTTLS,
++			_("Secure connection with TLS?")) == M_YES ? 2 : 1;
++    if (nserv->use_tls == 2)
++    {
++      if (mutt_socket_write (conn, "STARTTLS\r\n") < 0 ||
++	  mutt_socket_readln (buf, sizeof (buf), conn) < 0)
++	return nntp_connect_error (nserv);
++      if (mutt_strncmp ("382", buf, 3))
++      {
++	nserv->use_tls = 0;
++	mutt_error ("STARTTLS: %s", buf);
++	mutt_sleep (2);
++      }
++      else if (mutt_ssl_starttls (conn))
++      {
++	nserv->use_tls = 0;
++	nserv->status = NNTP_NONE;
++	mutt_socket_close (nserv->conn);
++	mutt_error _("Could not negotiate TLS connection");
++	mutt_sleep (2);
++	return -1;
++      }
++      else
++      {
++	/* recheck capabilities after STARTTLS */
++	cap = nntp_capabilities (nserv);
++	if (cap < 0)
++	  return -1;
++      }
++    }
++  }
++#endif
 +
-+    None
++  /* authentication required? */
++  if (conn->account.flags & M_ACCT_USER)
++  {
++    if (!conn->account.user[0])
++      auth = 0;
++  }
++  else
++  {
++    if (mutt_socket_write (conn, "STAT\r\n") < 0 ||
++	mutt_socket_readln (buf, sizeof (buf), conn) < 0)
++      return nntp_connect_error (nserv);
++    if (mutt_strncmp ("480", buf, 3))
++      auth = 0;
++  }
 +
-+Sort
-+----
++  /* authenticate */
++  if (auth && nntp_auth (nserv) < 0)
++      return -1;
 +
-+    None
++  /* get final capabilities after authentication */
++  if (nserv->hasCAPABILITIES && (auth || cap > 0))
++  {
++    cap = nntp_capabilities (nserv);
++    if (cap < 0)
++      return -1;
++    if (cap > 0)
++    {
++      mutt_socket_close (conn);
++      mutt_error _("Could not switch to reader mode.");
++      mutt_sleep (2);
++      return -1;
++    }
++  }
 +
-+See Also
-+--------
++  /* attempt features */
++  if (nntp_attempt_features (nserv) < 0)
++    return -1;
 +
-+    * NeoMutt project
-+    * Compile-Time Features
++  nserv->status = NNTP_OK;
++  return 0;
++}
 +
-+Known Bugs
-+----------
++/* Send data from buffer and receive answer to same buffer */
++static int nntp_query (NNTP_DATA *nntp_data, char *line, size_t linelen)
++{
++  NNTP_SERVER *nserv = nntp_data->nserv;
++  char buf[LONG_STRING];
 +
-+Credits
-+-------
++  if (nserv->status == NNTP_BYE)
++    return -1;
 +
-+    * Vsevolod Volkov <vvv at mutt.org.ua>
-+    * Felix von Leitner <leitner at fefe.de>
-+    * Richard Russon <rich at flatcap.org>
++  while (1)
++  {
++    if (nserv->status == NNTP_OK)
++    {
++      int rc = 0;
 +
-diff -urN mutt-1.6.1/README.notmuch mutt-1.6.1-neomutt/README.notmuch
---- mutt-1.6.1/README.notmuch	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/README.notmuch	2016-06-12 18:43:00.671451785 +0100
-@@ -0,0 +1,402 @@
-+notmuch support for mutt
-+------------------------
++      if (*line)
++	rc = mutt_socket_write (nserv->conn, line);
++      else if (nntp_data->group)
++      {
++	snprintf (buf, sizeof (buf), "GROUP %s\r\n", nntp_data->group);
++	rc = mutt_socket_write (nserv->conn, buf);
++      }
++      if (rc >= 0)
++	rc = mutt_socket_readln (buf, sizeof (buf), nserv->conn);
++      if (rc >= 0)
++	break;
++    }
 +
-+ * notmuch is e-mail fulltext indexing and tagging engine; see
-+   http://notmuchmail.org/ for more information.
++    /* reconnect */
++    while (1)
++    {
++      nserv->status = NNTP_NONE;
++      if (nntp_open_connection (nserv) == 0)
++	break;
 +
-+ * home page (wiki) and git:
++      snprintf (buf, sizeof (buf), _("Connection to %s lost. Reconnect?"),
++		nserv->conn->account.host);
++      if (mutt_yesorno (buf, M_YES) != M_YES)
++      {
++	nserv->status = NNTP_BYE;
++	return -1;
++      }
++    }
 +
-+   https://github.com/karelzak/mutt-kz
++    /* select newsgroup after reconnection */
++    if (nntp_data->group)
++    {
++      snprintf (buf, sizeof (buf), "GROUP %s\r\n", nntp_data->group);
++      if (mutt_socket_write (nserv->conn, buf) < 0 ||
++	  mutt_socket_readln (buf, sizeof (buf), nserv->conn) < 0)
++	return nntp_connect_error (nserv);
++    }
++    if (!*line)
++      break;
++  }
 +
-+   Note that the master branch is rebased to be up to date with mutt upstream. Use
-+   stable/v<version> branches for downstream packaging.
++  strfcpy (line, buf, linelen);
++  return 0;
++}
 +
-+ * mailing list:
++/* This function calls funct(*line, *data) for each received line,
++ * funct(NULL, *data) if rewind(*data) needs, exits when fail or done:
++ *  0 - success
++ *  1 - bad response (answer in query buffer)
++ * -1 - conection lost
++ * -2 - error in funct(*line, *data) */
++static int nntp_fetch_lines (NNTP_DATA *nntp_data, char *query, size_t qlen,
++			char *msg, int (*funct) (char *, void *), void *data)
++{
++  int done = FALSE;
++  int rc;
 +
-+   https://admin.fedoraproject.org/mailman/listinfo/mutt-kz
++  while (!done)
++  {
++    char buf[LONG_STRING];
++    char *line;
++    unsigned int lines = 0;
++    size_t off = 0;
++    progress_t progress;
 +
-+ * requirements:
++    if (msg)
++      mutt_progress_init (&progress, msg, M_PROGRESS_MSG, ReadInc, -1);
 +
-+   notmuch >= 0.9
++    strfcpy (buf, query, sizeof (buf));
++    if (nntp_query (nntp_data, buf, sizeof (buf)) < 0)
++      return -1;
++    if (buf[0] != '2')
++    {
++      strfcpy (query, buf, qlen);
++      return 1;
++    }
 +
-+ * compile:
++    line = safe_malloc (sizeof (buf));
++    rc = 0;
 +
-+  $ git clone git://github.com/karelzak/mutt-kz.git
-+  $ cd mutt-kz
-+  $ ./prepare
-+  $ ./configure --enable-notmuch [--enable-debug]
-+  $ make
++    while (1)
++    {
++      char *p;
++      int chunk = mutt_socket_readln_d (buf, sizeof (buf),
++		  nntp_data->nserv->conn, M_SOCK_LOG_HDR);
++      if (chunk < 0)
++      {
++	nntp_data->nserv->status = NNTP_NONE;
++	break;
++      }
 +
-+ * Folders URI
++      p = buf;
++      if (!off && buf[0] == '.')
++      {
++	if (buf[1] == '\0')
++	{
++	  done = TRUE;
++	  break;
++	}
++	if (buf[1] == '.')
++	  p++;
++      }
 +
-+   notmuch://[<path>][?<item>=<name>[& ...]]
++      strfcpy (line + off, p, sizeof (buf));
 +
-+   The <path> is an absolute path to the directory where the notmuch database
-+   is found as returned by 'notmuch config get database.path' command. Note that
-+   the <path> should NOT include .notmuch directory name.
++      if (chunk >= sizeof (buf))
++	off += strlen (p);
++      else
++      {
++	if (msg)
++	  mutt_progress_update (&progress, ++lines, -1);
 +
-+   If the "<path>" is not defined then $nm_default_uri or $folder is used,
-+   for example:
++	if (rc == 0 && funct (line, data) < 0)
++	  rc = -2;
++	off = 0;
++      }
 +
-+	set nm_default_uri = "notmuch:///home/foo/maildir"
-+	virtual-mailboxes "My INBOX" "notmuch://?query=tag:inbox"
++      safe_realloc (&line, off + sizeof (buf));
++    }
++    FREE (&line);
++    funct (NULL, data);
++  }
++  return rc;
++}
 +
-+   Items:
++/* Parse newsgroup description */
++static int fetch_description (char *line, void *data)
++{
++  NNTP_SERVER *nserv = data;
++  NNTP_DATA *nntp_data;
++  char *desc;
 +
-+      query=<string>
++  if (!line)
++    return 0;
 +
-+	 See SEARCH SYNTAX in notmuch man page. Don't forget to use "and" and
-+         "or" operators in your queries.
++  desc = strpbrk (line, " \t");
++  if (desc)
++  {
++    *desc++ = '\0';
++    desc += strspn (desc, " \t");
++  }
++  else
++    desc = strchr (line, '\0');
 +
-+      Note that proper URI should not contain blank space and all "bad" chars
-+      should be encoded, for example
++  nntp_data = hash_find (nserv->groups_hash, line);
++  if (nntp_data && mutt_strcmp (desc, nntp_data->desc))
++  {
++    mutt_str_replace (&nntp_data->desc, desc);
++    dprint (2, (debugfile, "group: %s, desc: %s\n", line, desc));
++  }
++  return 0;
++}
 +
-+	 "tag:AAA and tag:BBB" --encoding-> tag:AAA%20and%20tag:BBB
++/* Fetch newsgroups descriptions.
++ * Returns the same code as nntp_fetch_lines() */
++static int get_description (NNTP_DATA *nntp_data, char *wildmat, char *msg)
++{
++  NNTP_SERVER *nserv;
++  char buf[STRING];
++  char *cmd;
++  int rc;
 +
-+      but mutt config file parser is smart enough to accept space in quoted
-+      strings. It means that you can use
++  /* get newsgroup description, if possible */
++  nserv = nntp_data->nserv;
++  if (!wildmat)
++    wildmat = nntp_data->group;
++  if (nserv->hasLIST_NEWSGROUPS)
++    cmd = "LIST NEWSGROUPS";
++  else if (nserv->hasXGTITLE)
++    cmd = "XGTITLE";
++  else
++    return 0;
 +
-+         "notmuch:///foo?query=tag:AAA and tag:BBB"
++  snprintf (buf, sizeof (buf), "%s %s\r\n", cmd, wildmat);
++  rc = nntp_fetch_lines (nntp_data, buf, sizeof (buf), msg,
++			 fetch_description, nserv);
++  if (rc > 0)
++  {
++    mutt_error ("%s: %s", cmd, buf);
++    mutt_sleep (2);
++  }
++  return rc;
++}
 +
-+      in your config files to keep things readable.
++/* Update read flag and set article number if empty */
++static void nntp_parse_xref (CONTEXT *ctx, HEADER *hdr)
++{
++  NNTP_DATA *nntp_data = ctx->data;
++  char *buf, *p;
 +
-+      See http://xapian.org/docs/queryparser.html for more details about Xapian
-+      queries.
++  buf = p = safe_strdup (hdr->env->xref);
++  while (p)
++  {
++    char *grp, *colon;
++    anum_t anum;
 +
++    /* skip to next word */
++    p += strspn (p, " \t");
++    grp = p;
 +
-+      limit=<number>
++    /* skip to end of word */
++    p = strpbrk (p, " \t");
++    if (p)
++      *p++ = '\0';
 +
-+         Restricts number of messages/threads in the result. The default limit
-+         is nm_db_limit.
++    /* find colon */
++    colon = strchr (grp, ':');
++    if (!colon)
++      continue;
++    *colon++ = '\0';
++    if (sscanf (colon, ANUM, &anum) != 1)
++      continue;
 +
-+      type=<threads|messages>
++    nntp_article_status (ctx, hdr, grp, anum);
++    if (hdr && !NHDR (hdr)->article_num && !mutt_strcmp (nntp_data->group, grp))
++      NHDR (hdr)->article_num = anum;
++  }
++  FREE (&buf);
++}
 +
-+         Reads all matching messages or whole-threads. The default is 'messages'
-+         or nm_query_type.
++/* Write line to temporarily file */
++static int fetch_tempfile (char *line, void *data)
++{
++  FILE *fp = data;
 +
++  if (!line)
++    rewind (fp);
++  else if (fputs (line, fp) == EOF || fputc ('\n', fp) == EOF)
++    return -1;
++  return 0;
++}
 +
-+ * commands:
++typedef struct
++{
++  CONTEXT *ctx;
++  anum_t first;
++  anum_t last;
++  int restore;
++  unsigned char *messages;
++  progress_t progress;
++#ifdef USE_HCACHE
++  header_cache_t *hc;
++#endif
++} FETCH_CTX;
 +
-+   change-vfolder:
-+      - switch to another virtual folder, a new folder maybe be specified by
-+        vfolder description (see virtual-mailboxes) or URI
-+      - the default is next vfolder with unread messages
-+      - default key: X
++/* Parse article number */
++static int fetch_numbers (char *line, void *data)
++{
++  FETCH_CTX *fc = data;
++  anum_t anum;
 +
-+   vfolder-from-query:
-+      - generate new virtual folder from notmuch search query
-+      - default key: <Esc>X
-+      - note: TAB completion of 'tag:' names is available
++  if (!line)
++    return 0;
++  if (sscanf (line, ANUM, &anum) != 1)
++    return 0;
++  if (anum < fc->first || anum > fc->last)
++    return 0;
++  fc->messages[anum - fc->first] = 1;
++  return 0;
++}
 +
-+   modify-labels:
-+      - add or remove notmuch tags; [+]<tag> to add, -<tag> to remove
-+      - default key: `
-+      - note: TAB completion of tag names is available
-+      - example: "+AAA +BBB -CCC"
++/* Parse overview line */
++static int parse_overview_line (char *line, void *data)
++{
++  FETCH_CTX *fc = data;
++  CONTEXT *ctx = fc->ctx;
++  NNTP_DATA *nntp_data = ctx->data;
++  HEADER *hdr;
++  FILE *fp;
++  char tempfile[_POSIX_PATH_MAX];
++  char *header, *field;
++  int save = 1;
++  anum_t anum;
 +
-+   modify-labels-then-hide:
-+      - same as <modify-labels> but message is marked by <quasi-delete>
-+      - not mapped to any key
-+      - note: TAB completion of tag names is available
-+      - example (add "archive" notmuch tag and remove message from screen):
++  if (!line)
++    return 0;
 +
-+       macro index A "<modify-labels-then-hide>+archive -inbox\n<sync-mailbox>"
-+       macro index I "<modify-labels-then-hide>-inbox\n<sync-mailbox>"
++  /* parse article number */
++  field = strchr (line, '\t');
++  if (field)
++    *field++ = '\0';
++  if (sscanf (line, ANUM, &anum) != 1)
++    return 0;
++  dprint (2, (debugfile, "parse_overview_line: " ANUM "\n", anum));
 +
-+   quasi-delete:
-+      - delete message from mutt (usually after <sync-mailbox> function), but
-+        don't touch message on disk
++  /* out of bounds */
++  if (anum < fc->first || anum > fc->last)
++    return 0;
 +
-+   entire-thread:
-+      - add to the current list of the messages all messages that belongs to the same thread
-+        as the current message. This command is useful when you have a new email in your INBOX
-+        and you want to see the rest of the archived thread.
-+      - default key: +
++  /* not in LISTGROUP */
++  if (!fc->messages[anum - fc->first])
++  {
++    /* progress */
++    if (!ctx->quiet)
++      mutt_progress_update (&fc->progress, anum - fc->first + 1, -1);
++    return 0;
++  }
 +
-+ * Pattern modifiers:
++  /* convert overview line to header */
++  mutt_mktemp (tempfile, sizeof (tempfile));
++  fp = safe_fopen (tempfile, "w+");
++  if (!fp)
++    return -1;
 +
-+   Many of Mutt's commands allow you to specify a pattern to match (limit,
-+   tag-pattern, delete-pattern, color, etc.). The following notmuch specific
-+   mutt pattern modifiers are available:
++  header = nntp_data->nserv->overview_fmt;
++  while (field)
++  {
++    char *b = field;
 +
-+   - '~Y EXPR': Messages which contain EXPR in the list of labels.
-+     Example:
-+        # Color red all messages labeled as 'spam'.
-+        color index    red      default        "~Y '\W?spam\W?'"
++    if (*header)
++    {
++      if (strstr (header, ":full") == NULL && fputs (header, fp) == EOF)
++      {
++	fclose (fp);
++	unlink (tempfile);
++	return -1;
++      }
++      header = strchr (header, '\0') + 1;
++    }
 +
-+ * muttrc:
++    field = strchr (field, '\t');
++    if (field)
++      *field++ = '\0';
++    if (fputs (b, fp) == EOF || fputc ('\n', fp) == EOF)
++    {
++      fclose (fp);
++      unlink (tempfile);
++      return -1;
++    }
++  }
++  rewind (fp);
 +
-+   Note that you can use notmuch specific mutt config file, see -F <config> in
-+   mutt docs.
++  /* allocate memory for headers */
++  if (ctx->msgcount >= ctx->hdrmax)
++    mx_alloc_memory (ctx);
 +
++  /* parse header */
++  hdr = ctx->hdrs[ctx->msgcount] = mutt_new_header ();
++  hdr->env = mutt_read_rfc822_header (fp, hdr, 0, 0);
++  hdr->env->newsgroups = safe_strdup (nntp_data->group);
++  hdr->received = hdr->date_sent;
++  fclose (fp);
++  unlink (tempfile);
 +
-+   virtual-mailboxes <description> <uri> [ ...]
++#ifdef USE_HCACHE
++  if (fc->hc)
++  {
++    void *hdata;
++    char buf[16];
 +
-+      This command specifies one or more virtual folder. The folders are
-+      accessible by command 'X'. It's possible to use the virtual mailbox
-+      description as a sort key (e.g set sort_sidebar=desc)
++    /* try to replace with header from cache */
++    snprintf (buf, sizeof (buf), "%d", anum);
++    hdata = mutt_hcache_fetch (fc->hc, buf, strlen);
++    if (hdata)
++    {
++      dprint (2, (debugfile,
++		  "parse_overview_line: mutt_hcache_fetch %s\n", buf));
++      mutt_free_header (&hdr);
++      ctx->hdrs[ctx->msgcount] =
++      hdr = mutt_hcache_restore (hdata, NULL);
++      FREE (&hdata);
++      hdr->data = 0;
++      hdr->read = 0;
++      hdr->old = 0;
 +
-+      example:
++      /* skip header marked as deleted in cache */
++      if (hdr->deleted && !fc->restore)
++      {
++	if (nntp_data->bcache)
++	{
++	  dprint (2, (debugfile,
++		      "parse_overview_line: mutt_bcache_del %s\n", buf));
++	  mutt_bcache_del (nntp_data->bcache, buf);
++	}
++	save = 0;
++      }
++    }
 +
-+      virtual-mailboxes "Linux Kernel" "notmuch:///whereis/db?query=tag:lkml&limit=1000" \
-+                        "Filesystems"  "notmuch:///whereis/db?query=tag:fs" \
-+                        "Music"        "notmuch:///another/db?query=tag:hard and tag:heavy"
++    /* not chached yet, store header */
++    else
++    {
++      dprint (2, (debugfile,
++		  "parse_overview_line: mutt_hcache_store %s\n", buf));
++      mutt_hcache_store (fc->hc, buf, hdr, 0, strlen, M_GENERATE_UIDVALIDITY);
++    }
++  }
++#endif
 +
-+      The folder description is used for status line, folders browser, sidebar
-+      and <change-vfolder> command (this command also accepts vfolder URI). The
-+      folder-hook regex uses the URI.
++  if (save)
++  {
++    hdr->index = ctx->msgcount++;
++    hdr->read = 0;
++    hdr->old = 0;
++    hdr->deleted = 0;
++    hdr->data = safe_calloc (1, sizeof (NNTP_HEADER_DATA));
++    NHDR (hdr)->article_num = anum;
++    if (fc->restore)
++      hdr->changed = 1;
++    else
++    {
++      nntp_article_status (ctx, hdr, NULL, anum);
++      if (!hdr->read)
++	nntp_parse_xref (ctx, hdr);
++    }
++    if (anum > nntp_data->lastLoaded)
++      nntp_data->lastLoaded = anum;
++  }
++  else
++    mutt_free_header (&hdr);
 +
-+   virtual_spoolfile = <boolean>
++  /* progress */
++  if (!ctx->quiet)
++    mutt_progress_update (&fc->progress, anum - fc->first + 1, -1);
++  return 0;
++}
 +
-+      When set, mutt will use the first virtual mailbox (see virtual-mailboxes)
-+      as a spoolfile.
++/* Fetch headers */
++static int nntp_fetch_headers (CONTEXT *ctx, void *hc,
++			       anum_t first, anum_t last, int restore)
++{
++  NNTP_DATA *nntp_data = ctx->data;
++  FETCH_CTX fc;
++  HEADER *hdr;
++  char buf[HUGE_STRING];
++  int rc = 0;
++  int oldmsgcount = ctx->msgcount;
++  anum_t current;
++  anum_t first_over = first;
++#ifdef USE_HCACHE
++  void *hdata;
++#endif
 +
-+      When set together with sidebar, mutt will use list of virtual folders in
-+      the sidebar. It's possible to toggle between virtual and normal folders by
-+      sidebar-toggle command.
++  /* if empty group or nothing to do */
++  if (!last || first > last)
++    return 0;
 +
-+   tag-transforms <tag> <transform> [ ...]
++  /* init fetch context */
++  fc.ctx = ctx;
++  fc.first = first;
++  fc.last = last;
++  fc.restore = restore;
++  fc.messages = safe_calloc (last - first + 1, sizeof (unsigned char));
++#ifdef USE_HCACHE
++  fc.hc = hc;
++#endif
 +
-+      This command specifies text transforms to be shown instead of the actual
-+      tag names with '%g' in the index and pager formats. Note that Unicode
-+      symbols can be used for transforms.
++  /* fetch list of articles */
++  if (option (OPTLISTGROUP) && nntp_data->nserv->hasLISTGROUP &&
++      !nntp_data->deleted)
++  {
++    if (!ctx->quiet)
++      mutt_message _("Fetching list of articles...");
++    if (nntp_data->nserv->hasLISTGROUPrange)
++      snprintf (buf, sizeof (buf), "LISTGROUP %s %d-%d\r\n", nntp_data->group,
++		first, last);
++    else
++      snprintf (buf, sizeof (buf), "LISTGROUP %s\r\n", nntp_data->group);
++    rc = nntp_fetch_lines (nntp_data, buf, sizeof (buf), NULL,
++			   fetch_numbers, &fc);
++    if (rc > 0)
++    {
++      mutt_error ("LISTGROUP: %s", buf);
++      mutt_sleep (2);
++    }
++    if (rc == 0)
++    {
++      for (current = first; current <= last && rc == 0; current++)
++      {
++	if (fc.messages[current - first])
++	  continue;
 +
-+      example:
++	snprintf (buf, sizeof (buf), "%d", current);
++	if (nntp_data->bcache)
++	{
++	  dprint (2, (debugfile,
++		      "nntp_fetch_headers: mutt_bcache_del %s\n", buf));
++	  mutt_bcache_del (nntp_data->bcache, buf);
++	}
 +
-+      tag-transforms "inbox"   "i"   \
-+                     "unread"  "u"   \
-+                     "replied" "↻ "  \
-+                     "sent"    "➥ "  \
-+                     "todo"    "T"   \
-+                     "deleted" "DEL" \
-+                     "invites" "CAL"
++#ifdef USE_HCACHE
++	if (fc.hc)
++	{
++	  dprint (2, (debugfile,
++		      "nntp_fetch_headers: mutt_hcache_delete %s\n", buf));
++	  mutt_hcache_delete (fc.hc, buf, strlen);
++	}
++#endif
++      }
++    }
++  }
++  else
++    for (current = first; current <= last; current++)
++      fc.messages[current - first] = 1;
 +
-+   tag-formats <tag> <format sequence> [ ...]
++  /* fetching header from cache or server, or fallback to fetch overview */
++  if (!ctx->quiet)
++    mutt_progress_init (&fc.progress, _("Fetching message headers..."),
++			M_PROGRESS_MSG, ReadInc, last - first + 1);
++  for (current = first; current <= last && rc == 0; current++)
++  {
++    if (!ctx->quiet)
++      mutt_progress_update (&fc.progress, current - first + 1, -1);
 +
-+      Specify index formatting sequences for individual tags for direct
-+      placement in the $index_format. The formats must start with 'G' and
-+      the entire sequence is case sensitive.
++#ifdef USE_HCACHE
++    snprintf (buf, sizeof (buf), "%d", current);
++#endif
 +
-+      example:
++    /* delete header from cache that does not exist on server */
++    if (!fc.messages[current - first])
++      continue;
 +
-+      tag-formats "inbox"   "GI" \
-+                  "unread"  "GU" \
-+                  "replied" "GR" \
-+                  "sent"    "GS" \
-+                  "todo"    "Gt" \
-+                  "deleted" "GD" \
-+                  "invites" "Gi"
++    /* allocate memory for headers */
++    if (ctx->msgcount >= ctx->hdrmax)
++      mx_alloc_memory (ctx);
 +
-+      Now instead of using '%g' in your $index_format, which lists all tags
-+      in a non-deterministic order, you can something like the following which puts
-+      a transformed tag name in a specific spot on the index line:
++#ifdef USE_HCACHE
++    /* try to fetch header from cache */
++    hdata = mutt_hcache_fetch (fc.hc, buf, strlen);
++    if (hdata)
++    {
++      dprint (2, (debugfile,
++		  "nntp_fetch_headers: mutt_hcache_fetch %s\n", buf));
++      ctx->hdrs[ctx->msgcount] =
++      hdr = mutt_hcache_restore (hdata, NULL);
++      FREE (&hdata);
++      hdr->data = 0;
 +
-+      set index_format='4C %S %[%y.%m.%d] %-18.18n %?GU?%GU& ? %?GR?%GR& ? %?GI?%GI& ? %s'
++      /* skip header marked as deleted in cache */
++      if (hdr->deleted && !restore)
++      {
++	mutt_free_header (&hdr);
++	if (nntp_data->bcache)
++	{
++	  dprint (2, (debugfile,
++		      "nntp_fetch_headers: mutt_bcache_del %s\n", buf));
++	  mutt_bcache_del (nntp_data->bcache, buf);
++	}
++	continue;
++      }
 +
-+      The %G formatting sequence may display all tags including tags hidden by
-+      nm_hidden_tags.
++      hdr->read = 0;
++      hdr->old = 0;
++    }
++    else
++#endif
 +
-+   nm_record = <boolean>
++    /* don't try to fetch header from removed newsgroup */
++    if (nntp_data->deleted)
++      continue;
 +
-+      Add messages stored to the mutt record (see $record in the mutt docs)
-+      also to notmuch DB. If you reply to an email then the new email inherits
-+      tags from the original email.
++    /* fallback to fetch overview */
++    else if (nntp_data->nserv->hasOVER || nntp_data->nserv->hasXOVER)
++      if (option (OPTLISTGROUP) && nntp_data->nserv->hasLISTGROUP)
++	break;
++      else
++	continue;
 +
-+   nm_record_tags = <comma delimited list>
++    /* fetch header from server */
++    else
++    {
++      FILE *fp;
++      char tempfile[_POSIX_PATH_MAX];
 +
-+      Tags that should be removed or added to the to the messages stored in the mutt record.
++      mutt_mktemp (tempfile, sizeof (tempfile));
++      fp = safe_fopen (tempfile, "w+");
++      if (!fp)
++      {
++	mutt_perror (tempfile);
++	mutt_sleep (2);
++	unlink (tempfile);
++	rc = -1;
++	break;
++      }
 +
-+      example:
++      snprintf (buf, sizeof (buf), "HEAD %d\r\n", current);
++      rc = nntp_fetch_lines (nntp_data, buf, sizeof (buf), NULL,
++			     fetch_tempfile, fp);
++      if (rc)
++      {
++	fclose (fp);
++	unlink (tempfile);
++	if (rc < 0)
++	  break;
 +
-+      set record = "~/sent-mails"
-+      set nm_record = yes
-+      set nm_record_tags = "-inbox,archive,me"
++	/* invalid response */
++	if (mutt_strncmp ("423", buf, 3))
++	{
++	  mutt_error ("HEAD: %s", buf);
++	  mutt_sleep (2);
++	  break;
++	}
 +
-+   nm_open_timeout = <seconds>
++	/* no such article */
++	if (nntp_data->bcache)
++	{
++	  snprintf (buf, sizeof (buf), "%d", current);
++	  dprint (2, (debugfile,
++		      "nntp_fetch_headers: mutt_bcache_del %s\n", buf));
++	  mutt_bcache_del (nntp_data->bcache, buf);
++	}
++	rc = 0;
++	continue;
++      }
 +
-+      This option specifies timeout for Notmuch database. Default is 5 seconds.
++      /* parse header */
++      hdr = ctx->hdrs[ctx->msgcount] = mutt_new_header ();
++      hdr->env = mutt_read_rfc822_header (fp, hdr, 0, 0);
++      hdr->received = hdr->date_sent;
++      fclose (fp);
++      unlink (tempfile);
++    }
 +
-+   nm_default_uri = <uri>
++    /* save header in context */
++    hdr->index = ctx->msgcount++;
++    hdr->read = 0;
++    hdr->old = 0;
++    hdr->deleted = 0;
++    hdr->data = safe_calloc (1, sizeof (NNTP_HEADER_DATA));
++    NHDR (hdr)->article_num = current;
++    if (restore)
++      hdr->changed = 1;
++    else
++    {
++      nntp_article_status (ctx, hdr, NULL, NHDR (hdr)->article_num);
++      if (!hdr->read)
++	nntp_parse_xref (ctx, hdr);
++    }
++    if (current > nntp_data->lastLoaded)
++      nntp_data->lastLoaded = current;
++    first_over = current + 1;
++  }
 +
-+      This variable specifies the default Notmuch database in format
-+      notmuch://<absolute path>, the URI is used for notmuch queries (ESC+X) when the
-+      current folder is not based on notmuch. If the default URI is not specified
-+      then mutt will try to use $folder variable (see mutt manual for more details).
++  if (!option (OPTLISTGROUP) || !nntp_data->nserv->hasLISTGROUP)
++    current = first_over;
 +
-+   nm_hidden_tags = <comma delimited list>
++  /* fetch overview information */
++  if (current <= last && rc == 0 && !nntp_data->deleted) {
++    char *cmd = nntp_data->nserv->hasOVER ? "OVER" : "XOVER";
++    snprintf (buf, sizeof (buf), "%s %d-%d\r\n", cmd, current, last);
++    rc = nntp_fetch_lines (nntp_data, buf, sizeof (buf), NULL,
++	 parse_overview_line, &fc);
++    if (rc > 0)
++    {
++      mutt_error ("%s: %s", cmd, buf);
++      mutt_sleep (2);
++    }
++  }
 +
-+      This variable specifies private notmuch tags which should not be printed
-+      on screen (index, pager).
++  if (ctx->msgcount > oldmsgcount)
++    mx_update_context (ctx, ctx->msgcount - oldmsgcount);
 +
-+      Default is "unread,draft,flagged,passed,replied,attachment".
++  FREE (&fc.messages);
++  if (rc != 0)
++    return -1;
++  mutt_clear_error ();
++  return 0;
++}
 +
-+   nm_exclude_tags = <comma delimited list>
++/* Open newsgroup */
++int nntp_open_mailbox (CONTEXT *ctx)
++{
++  NNTP_SERVER *nserv;
++  NNTP_DATA *nntp_data;
++  char buf[HUGE_STRING];
++  char server[LONG_STRING];
++  char *group;
++  int rc;
++  void *hc = NULL;
++  anum_t first, last, count = 0;
++  ciss_url_t url;
 +
-+      The messages tagged with these tags are excluded and not loaded
-+      from notmuch DB to mutt unless specified explicitly.
++  strfcpy (buf, ctx->path, sizeof (buf));
++  if (url_parse_ciss (&url, buf) < 0 || !url.path ||
++     !(url.scheme == U_NNTP || url.scheme == U_NNTPS))
++  {
++    mutt_error (_("%s is an invalid newsgroup specification!"), ctx->path);
++    mutt_sleep (2);
++    return -1;
++  }
 +
-+      Not set by default.
++  group = url.path;
++  url.path = strchr (url.path, '\0');
++  url_ciss_tostring (&url, server, sizeof (server), 0);
++  nserv = nntp_select_server (server, 1);
++  if (!nserv)
++    return -1;
++  CurrentNewsSrv = nserv;
 +
-+   nm_unread_tag = <name>
++  /* find news group data structure */
++  nntp_data = hash_find (nserv->groups_hash, group);
++  if (!nntp_data)
++  {
++    nntp_newsrc_close (nserv);
++    mutt_error (_("Newsgroup %s not found on the server."), group);
++    mutt_sleep (2);
++    return -1;
++  }
 +
-+      This variable specifies notmuch tag which is used for unread messages. The
-+      variable is used to count unread messages in DB only. All other mutt
-+      commands use standard (e.g. maildir) flags.
++  mutt_bit_unset (ctx->rights, M_ACL_INSERT);
++  if (!nntp_data->newsrc_ent && !nntp_data->subscribed &&
++      !option (OPTSAVEUNSUB))
++    ctx->readonly = 1;
 +
-+      Default is "unread".
++  /* select newsgroup */
++  mutt_message (_("Selecting %s..."), group);
++  buf[0] = '\0';
++  if (nntp_query (nntp_data, buf, sizeof (buf)) < 0)
++  {
++    nntp_newsrc_close (nserv);
++    return -1;
++  }
 +
-+   nm_db_limit = <num>
++  /* newsgroup not found, remove it */
++  if (!mutt_strncmp ("411", buf, 3))
++  {
++    mutt_error (_("Newsgroup %s has been removed from the server."),
++		nntp_data->group);
++    if (!nntp_data->deleted)
++    {
++      nntp_data->deleted = 1;
++      nntp_active_save_cache (nserv);
++    }
++    if (nntp_data->newsrc_ent && !nntp_data->subscribed &&
++	!option (OPTSAVEUNSUB))
++    {
++      FREE (&nntp_data->newsrc_ent);
++      nntp_data->newsrc_len = 0;
++      nntp_delete_group_cache (nntp_data);
++      nntp_newsrc_update (nserv);
++    }
++    mutt_sleep (2);
++  }
 +
-+     This variable specifies notmuch query limit.
++  /* parse newsgroup info */
++  else {
++    if (sscanf (buf, "211 " ANUM " " ANUM " " ANUM, &count, &first, &last) != 3)
++    {
++      nntp_newsrc_close (nserv);
++      mutt_error ("GROUP: %s", buf);
++      mutt_sleep (2);
++      return -1;
++    }
++    nntp_data->firstMessage = first;
++    nntp_data->lastMessage = last;
++    nntp_data->deleted = 0;
 +
-+     Default is unlimited.
++    /* get description if empty */
++    if (option (OPTLOADDESC) && !nntp_data->desc)
++    {
++      if (get_description (nntp_data, NULL, NULL) < 0)
++      {
++	nntp_newsrc_close (nserv);
++	return -1;
++      }
++      if (nntp_data->desc)
++	nntp_active_save_cache (nserv);
++    }
++  }
 +
-+   nm_query_type = <threads|messages>
++  time (&nserv->check_time);
++  ctx->data = nntp_data;
++  ctx->mx_close = nntp_fastclose_mailbox;
++  if (!nntp_data->bcache && (nntp_data->newsrc_ent ||
++      nntp_data->subscribed || option (OPTSAVEUNSUB)))
++    nntp_data->bcache = mutt_bcache_open (&nserv->conn->account,
++			nntp_data->group);
 +
-+     This variable specifies notmuch query type, supported types: 'threads' and
-+     'messages'.
++  /* strip off extra articles if adding context is greater than $nntp_context */
++  first = nntp_data->firstMessage;
++  if (NntpContext && nntp_data->lastMessage - first + 1 > NntpContext)
++    first = nntp_data->lastMessage - NntpContext + 1;
++  nntp_data->lastLoaded = first ? first - 1 : 0;
++  count = nntp_data->firstMessage;
++  nntp_data->firstMessage = first;
++  nntp_bcache_update (nntp_data);
++  nntp_data->firstMessage = count;
++#ifdef USE_HCACHE
++  hc = nntp_hcache_open (nntp_data);
++  nntp_hcache_update (nntp_data, hc);
++#endif
++  if (!hc)
++  {
++    mutt_bit_unset (ctx->rights, M_ACL_WRITE);
++    mutt_bit_unset (ctx->rights, M_ACL_DELETE);
++  }
++  nntp_newsrc_close (nserv);
++  rc = nntp_fetch_headers (ctx, hc, first, nntp_data->lastMessage, 0);
++#ifdef USE_HCACHE
++  mutt_hcache_close (hc);
++#endif
++  if (rc < 0)
++    return -1;
++  nntp_data->lastLoaded = nntp_data->lastMessage;
++  nserv->newsrc_modified = 0;
++  return 0;
++}
 +
-+     Default is 'messages'.
++/* Fetch message */
++int nntp_fetch_message (MESSAGE *msg, CONTEXT *ctx, int msgno)
++{
++  NNTP_DATA *nntp_data = ctx->data;
++  NNTP_ACACHE *acache;
++  HEADER *hdr = ctx->hdrs[msgno];
++  char buf[_POSIX_PATH_MAX];
++  char article[16];
++  char *fetch_msg = _("Fetching message...");
++  int rc;
 +
-+   vfolder_format = <string>
++  /* try to get article from cache */
++  acache = &nntp_data->acache[hdr->index % NNTP_ACACHE_LEN];
++  if (acache->path)
++  {
++    if (acache->index == hdr->index)
++    {
++      msg->fp = fopen (acache->path, "r");
++      if (msg->fp)
++	return 0;
++    }
++    /* clear previous entry */
++    else
++    {
++      unlink (acache->path);
++      FREE (&acache->path);
++    }
++  }
++  snprintf (article, sizeof (article), "%d", NHDR (hdr)->article_num);
++  msg->fp = mutt_bcache_get (nntp_data->bcache, article);
++  if (msg->fp)
++  {
++    if (NHDR (hdr)->parsed)
++      return 0;
++  }
++  else
++  {
++    /* don't try to fetch article from removed newsgroup */
++    if (nntp_data->deleted)
++      return -1;
 +
-+      This variable allows you to customize the file browser display for virtual
-+      folders to your personal taste.  This string is similar to $index_format,
-+      but has its own set of printf(3)-like sequences:
++    /* create new cache file */
++    mutt_message (fetch_msg);
++    msg->fp = mutt_bcache_put (nntp_data->bcache, article, 1);
++    if (!msg->fp)
++    {
++      mutt_mktemp (buf, sizeof (buf));
++      acache->path = safe_strdup (buf);
++      acache->index = hdr->index;
++      msg->fp = safe_fopen (acache->path, "w+");
++      if (!msg->fp)
++      {
++	mutt_perror (acache->path);
++	unlink (acache->path);
++	FREE (&acache->path);
++	return -1;
++      }
++    }
 +
-+	%f   folder name (description)
-+	%n   number of all messages
-+	%N   number of new messages
-+	%>X  right justify the rest of the string and pad with character ``X''
-+	%|X  pad to the end of the line with character ``X''
-+	%*X  soft-fill with character ``X'' as pad
++    /* fetch message to cache file */
++    snprintf (buf, sizeof (buf), "ARTICLE %s\r\n",
++	      NHDR (hdr)->article_num ? article : hdr->env->message_id);
++    rc = nntp_fetch_lines (nntp_data, buf, sizeof (buf), fetch_msg,
++			   fetch_tempfile, msg->fp);
++    if (rc)
++    {
++      safe_fclose (&msg->fp);
++      if (acache->path)
++      {
++	unlink (acache->path);
++	FREE (&acache->path);
++      }
++      if (rc > 0)
++      {
++	if (!mutt_strncmp (NHDR (hdr)->article_num ? "423" : "430", buf, 3))
++	  mutt_error (_("Article %d not found on the server."),
++		      NHDR (hdr)->article_num ? article : hdr->env->message_id);
++	else
++	  mutt_error ("ARTICLE: %s", buf);
++      }
++      return -1;
++    }
 +
-+      Default is "%6n(%6N) %f ".
++    if (!acache->path)
++      mutt_bcache_commit (nntp_data->bcache, article);
++  }
 +
-+   index_format and pager_format
++  /* replace envelope with new one
++   * hash elements must be updated because pointers will be changed */
++  if (ctx->id_hash && hdr->env->message_id)
++    hash_delete (ctx->id_hash, hdr->env->message_id, hdr, NULL);
++  if (ctx->subj_hash && hdr->env->real_subj)
++    hash_delete (ctx->subj_hash, hdr->env->real_subj, hdr, NULL);
 +
-+        %g   notmuch tags (labels)
-+        %Gx  specific notmuch tag defined by tag-formats (see above)
++  mutt_free_envelope (&hdr->env);
++  hdr->env = mutt_read_rfc822_header (msg->fp, hdr, 0, 0);
 +
-+        for example:
++  if (ctx->id_hash && hdr->env->message_id)
++    hash_insert (ctx->id_hash, hdr->env->message_id, hdr, 0);
++  if (ctx->subj_hash && hdr->env->real_subj)
++    hash_insert (ctx->subj_hash, hdr->env->real_subj, hdr, 1);
 +
-+        tag-formats "inbox" "GI"
-+        set index_format = "%4C %Z %?GI?%GI? ?  %[%d/%b]  %-16.15F %s %> %?g?(%g)?"
-+        set pager_format = "-%Z- %C/%m: %-20.20n   %s%*  -- %?g?(%g)? - (%P)"
++  /* fix content length */
++  fseek (msg->fp, 0, SEEK_END);
++  hdr->content->length = ftell (msg->fp) - hdr->content->offset;
 +
++  /* this is called in mutt before the open which fetches the message,
++   * which is probably wrong, but we just call it again here to handle
++   * the problem instead of fixing it */
++  NHDR (hdr)->parsed = 1;
++  mutt_parse_mime_message (ctx, hdr);
 +
-+* .muttrc example:
++  /* these would normally be updated in mx_update_context(), but the
++   * full headers aren't parsed with overview, so the information wasn't
++   * available then */
++  if (WithCrypto)
++    hdr->security = crypt_query (hdr->content);
 +
-+	set record="~/Mail/Maildir/sent-mail"
-+	set nm_record = yes
-+	set nm_record_tags ="-inbox me archive"
++  rewind (msg->fp);
++  mutt_clear_error();
++  return 0;
++}
 +
-+	set nm_default_uri="notmuch:///home/kzak/Mail/Maildir"
-+	set virtual_spoolfile	= yes
-+	set sort_browser        = unsorted
++/* Post article */
++int nntp_post (const char *msg) {
++  NNTP_DATA *nntp_data, nntp_tmp;
++  FILE *fp;
++  char buf[LONG_STRING];
++  size_t len;
 +
-+	# normal folders
-+	set mbox_type=Maildir
-+	set folder="~/Mail/Maildir"
-+	mailboxes =rh =fedora =misc
++  if (Context && Context->magic == M_NNTP)
++    nntp_data = Context->data;
++  else
++  {
++    CurrentNewsSrv = nntp_select_server (NewsServer, 0);
++    if (!CurrentNewsSrv)
++      return -1;
 +
-+	set sidebar_width	 = 35
-+	set sidebar_visible	 = yes
-+	set sidebar_sort_method  = unsorted
-+	set sidebar_divider_char = │
++    nntp_data = &nntp_tmp;
++    nntp_data->nserv = CurrentNewsSrv;
++    nntp_data->group = NULL;
++  }
 +
-+	color sidebar_new yellow default
-+	color progress default magenta
++  fp = safe_fopen (msg, "r");
++  if (!fp)
++  {
++    mutt_perror (msg);
++    return -1;
++  }
 +
-+	bind index <left> sidebar-prev
-+	bind index <right> sidebar-next
-+	bind index <space> sidebar-open
-+	bind index <Esc>S sidebar-toggle-virtual
++  strfcpy (buf, "POST\r\n", sizeof (buf));
++  if (nntp_query (nntp_data, buf, sizeof (buf)) < 0)
++    return -1;
++  if (buf[0] != '3')
++  {
++    mutt_error (_("Can't post article: %s"), buf);
++    return -1;
++  }
 +
-+	set index_format="%4C %Z %?GI?%GI& ? %[%d/%b]  %-16.15F %?M?(%3M)&     ? %s %> %?g?%g?"
++  buf[0] = '.';
++  buf[1] = '\0';
++  while (fgets (buf + 1, sizeof (buf) - 2, fp))
++  {
++    len = strlen (buf);
++    if (buf[len - 1] == '\n')
++    {
++      buf[len - 1] = '\r';
++      buf[len] = '\n';
++      len++;
++      buf[len] = '\0';
++    }
++    if (mutt_socket_write_d (nntp_data->nserv->conn,
++	buf[1] == '.' ? buf : buf + 1, -1, M_SOCK_LOG_HDR) < 0)
++      return nntp_connect_error (nntp_data->nserv);
++  }
++  fclose (fp);
 +
-+        # virtual folders
-+	virtual-mailboxes \
-+	   "INBOX"                "notmuch://?query=tag:inbox and NOT tag:archive" \
-+	   "Util-linux"           "notmuch://?query=tag:ul and NOT tag:archive" \
-+	   "Bugs"                 "notmuch://?query=tag:bug NOT tag:archive" \
-+	   "RH"                   "notmuch://?query=tag:rh and NOT tag:archive" \
-+	   "Fedora"               "notmuch://?query=tag:fed and NOT tag:archive" \
-+	   "Linux"                "notmuch://?query=tag:lk and NOT tag:archive" \
-+	   "NFS"                  "notmuch://?query=tag:nfs and NOT tag:archive" \
-+	   "Filesystems"          "notmuch://?query=tag:fs and NOT tag:archive" \
-+	   "Security"             "notmuch://?query=tag:sec" \
-+	   "Partitioning"         "notmuch://?query=tag:part" \
-+	   "GNU"                  "notmuch://?query=tag:gnu" \
-+	   "udev"                 "notmuch://?query=tag:udev" \
-+	   "initrd"               "notmuch://?query=tag:initrd" \
-+	   "Linux CZ"             "notmuch://?query=tag:cz" \
-+	   "Notmuch"              "notmuch://?query=tag:nm" \
-+	   "Procps"               "notmuch://?query=tag:proc" \
-+	\
-+	   " Util-linux  [archive]" "notmuch://?query=tag:ul and tag:archive" \
-+	   " Bugs        [archive]" "notmuch://?query=tag:bug and tag:archive" \
-+	   " RH          [archive]" "notmuch://?query=tag:rh and tag:archive" \
-+	   " Fedora      [archive]" "notmuch://?query=tag:fed and tag:archive" \
-+	   " Linux       [archive]" "notmuch://?query=tag:lk and tag:archive" \
-+	   " Filesystems [archive]" "notmuch://?query=tag:fs and tag:archive" \
++  if ((buf[strlen (buf) - 1] != '\n' &&
++      mutt_socket_write_d (nntp_data->nserv->conn, "\r\n", -1, M_SOCK_LOG_HDR) < 0) ||
++      mutt_socket_write_d (nntp_data->nserv->conn, ".\r\n", -1, M_SOCK_LOG_HDR) < 0 ||
++      mutt_socket_readln (buf, sizeof (buf), nntp_data->nserv->conn) < 0)
++    return nntp_connect_error (nntp_data->nserv);
++  if (buf[0] != '2')
++  {
++    mutt_error (_("Can't post article: %s"), buf);
++    return -1;
++  }
++  return 0;
++}
 +
-+	# move message to archive
-+	macro index A "<modify-labels-then-hide>+archive -inbox\n<sync-mailbox>"
++/* Save changes to .newsrc and cache */
++int nntp_sync_mailbox (CONTEXT *ctx)
++{
++  NNTP_DATA *nntp_data = ctx->data;
++  int rc, i;
++#ifdef USE_HCACHE
++  header_cache_t *hc;
++#endif
 +
-+	# remove message from inbox
-+	macro index I "<modify-labels-then-hide>-inbox\n<sync-mailbox>"
++  /* check for new articles */
++  nntp_data->nserv->check_time = 0;
++  rc = nntp_check_mailbox (ctx, 1);
++  if (rc)
++    return rc;
 +
-+	# mark emails for git-am
-+	# (e.g. "git am -i -3 $(notmuch search --output=files tag:PATCH)"
-+	#
-+	macro index P "<modify-labels>PATCH\n"
-+	macro index <Esc>P "<modify-labels>-PATCH\n"
++#ifdef USE_HCACHE
++  nntp_data->lastCached = 0;
++  hc = nntp_hcache_open (nntp_data);
++#endif
 +
++  nntp_data->unread = ctx->unread;
++  for (i = 0; i < ctx->msgcount; i++)
++  {
++    HEADER *hdr = ctx->hdrs[i];
++    char buf[16];
 +
-+* .procmailrc example:
-+
-+	NOINBOX="-r inbox"
-+
-+	### Add 'kw' (keyword) tag to all interesting e-mails and make the emails
-+	### visible in inbox.
-+	:0
-+	* ^Subject:.*(mount|umount|libmount|losetup|util-linux|blkid|hwclock|mkswap|fdisk|parted|partition|gpt|topology)
-+	{
-+		TAGS="-t kw"
-+		NOINBOX=""
-+	}
++    snprintf (buf, sizeof (buf), "%d", NHDR (hdr)->article_num);
++    if (nntp_data->bcache && hdr->deleted)
++    {
++      dprint (2, (debugfile, "nntp_sync_mailbox: mutt_bcache_del %s\n", buf));
++      mutt_bcache_del (nntp_data->bcache, buf);
++    }
 +
-+	### Deliver emails to maildirs by notmuch-deliver
-+	### from notmuch contrib/
-+	###
-+	###    notmuch-deliver -t <tags> [-t ...] <maildir>
++#ifdef USE_HCACHE
++    if (hc && (hdr->changed || hdr->deleted))
++    {
++      if (hdr->deleted && !hdr->read)
++	nntp_data->unread--;
++      dprint (2, (debugfile, "nntp_sync_mailbox: mutt_hcache_store %s\n", buf));
++      mutt_hcache_store (hc, buf, hdr, 0, strlen, M_GENERATE_UIDVALIDITY);
++    }
++#endif
++  }
 +
-+	:0:notmuch.lock
-+	* ^List-Id:.*linux.linux.cz
-+	| notmuch-deliver $NOINBOX -t cz $TAGS linux.cz
++#ifdef USE_HCACHE
++  if (hc)
++  {
++    mutt_hcache_close (hc);
++    nntp_data->lastCached = nntp_data->lastLoaded;
++  }
++#endif
 +
-+	:0:notmuch.lock
-+	* ^X-Mailing-List:.*util-linux at vger.kernel.org
-+	| notmuch-deliver -t ul $TAGS util-linux
++  /* save .newsrc entries */
++  nntp_newsrc_gen_entries (ctx);
++  nntp_newsrc_update (nntp_data->nserv);
++  nntp_newsrc_close (nntp_data->nserv);
++  return 0;
++}
 +
-+	:0:notmuch.lock
-+	* ^List-Id:.*parted-devel.lists.alioth.debian.org
-+	| notmuch-deliver $NOINBOX -t part $TAGS parted
++/* Free up memory associated with the newsgroup context */
++int nntp_fastclose_mailbox (CONTEXT *ctx)
++{
++  NNTP_DATA *nntp_data = ctx->data, *nntp_tmp;
 +
-+	### [...cut to make the example short...] ###
++  if (!nntp_data)
++    return 0;
 +
-+	### All unmatched mails
-+	:0:notmuch.lock
-+	* ^From
-+	| notmuch-deliver $TAGS misc
++  nntp_acache_free (nntp_data);
++  if (!nntp_data->nserv || !nntp_data->nserv->groups_hash || !nntp_data->group)
++    return 0;
 +
-+	### fallback if notmuch does not work
-+	:0:
-+	* ^From
-+	Mail/Maildir/misc/
++  nntp_tmp = hash_find (nntp_data->nserv->groups_hash, nntp_data->group);
++  if (nntp_tmp == NULL || nntp_tmp != nntp_data)
++    nntp_data_free (nntp_data);
++  return 0;
++}
 +
++/* Get date and time from server */
++int nntp_date (NNTP_SERVER *nserv, time_t *now)
++{
++  if (nserv->hasDATE)
++  {
++    NNTP_DATA nntp_data;
++    char buf[LONG_STRING];
++    struct tm tm;
 +
-+* another example:
++    nntp_data.nserv = nserv;
++    nntp_data.group = NULL;
++    strfcpy (buf, "DATE\r\n", sizeof (buf));
++    if (nntp_query (&nntp_data, buf, sizeof (buf)) < 0)
++      return -1;
 +
-+  http://notmuchmail.org/mutttips/
-diff -urN mutt-1.6.1/README.progress mutt-1.6.1-neomutt/README.progress
---- mutt-1.6.1/README.progress	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/README.progress	2016-06-12 18:43:00.671451785 +0100
-@@ -0,0 +1,49 @@
-+Progress Bar Patch
-+==================
++    if (sscanf (buf, "111 %4d%2d%2d%2d%2d%2d%*s", &tm.tm_year, &tm.tm_mon,
++		&tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec) == 6)
++    {
++      tm.tm_year -= 1900;
++      tm.tm_mon--;
++      *now = timegm (&tm);
++      if (*now >= 0)
++      {
++	dprint (1, (debugfile, "nntp_date: server time is %d\n", *now));
++	return 0;
++      }
++    }
++  }
++  time (now);
++  return 0;
++}
 +
-+    Show a visual progress bar on slow operations
++/* Fetch list of all newsgroups from server */
++int nntp_active_fetch (NNTP_SERVER *nserv)
++{
++  NNTP_DATA nntp_data;
++  char msg[SHORT_STRING];
++  char buf[LONG_STRING];
++  unsigned int i;
++  int rc;
 +
-+Patch
-+-----
++  snprintf (msg, sizeof (msg), _("Loading list of groups from server %s..."),
++	    nserv->conn->account.host);
++  mutt_message (msg);
++  if (nntp_date (nserv, &nserv->newgroups_time) < 0)
++    return -1;
 +
-+    To check if Mutt supports "Progress Bar", look for "patch-progress" in the
-+    mutt version.
++  nntp_data.nserv = nserv;
++  nntp_data.group = NULL;
++  strfcpy (buf, "LIST\r\n", sizeof (buf));
++  rc = nntp_fetch_lines (&nntp_data, buf, sizeof (buf), msg,
++			 nntp_add_group, nserv);
++  if (rc)
++  {
++    if (rc > 0)
++    {
++      mutt_error ("LIST: %s", buf);
++      mutt_sleep (2);
++    }
++    return -1;
++  }
 +
-+    Dependencies
-+    * mutt-1.6.1
++  if (option (OPTLOADDESC) &&
++      get_description (&nntp_data, "*", _("Loading descriptions...")) < 0)
++    return -1;
 +
-+Introduction
-+------------
++  for (i = 0; i < nserv->groups_num; i++)
++  {
++    NNTP_DATA *nntp_data = nserv->groups_list[i];
 +
-+    The "progress" patch shows a visual progress bar on slow tasks, such as
-+    indexing a large folder over the net.
++    if (nntp_data && nntp_data->deleted && !nntp_data->newsrc_ent)
++    {
++      nntp_delete_group_cache (nntp_data);
++      hash_delete (nserv->groups_hash, nntp_data->group, NULL, nntp_data_free);
++      nserv->groups_list[i] = NULL;
++    }
++  }
++  nntp_active_save_cache (nserv);
++  mutt_clear_error ();
++  return 0;
++}
 +
-+Colors
-+------
++/* Check newsgroup for new articles:
++ *  1 - new articles found
++ *  0 - no change
++ * -1 - lost connection */
++static int nntp_group_poll (NNTP_DATA *nntp_data, int update_stat)
++{
++  char buf[LONG_STRING] = "";
++  anum_t count, first, last;
 +
-+    Progress Colors
++  /* use GROUP command to poll newsgroup */
++  if (nntp_query (nntp_data, buf, sizeof (buf)) < 0)
++    return -1;
++  if (sscanf (buf, "211 " ANUM " " ANUM " " ANUM, &count, &first, &last) != 3)
++    return 0;
++  if (first == nntp_data->firstMessage && last == nntp_data->lastMessage)
++    return 0;
 +
-+    | Name       | Default Color | Description         |
-+    |------------|---------------|---------------------|
-+    | 'progress' | default       | Visual progress bar |
++  /* articles have been renumbered */
++  if (last < nntp_data->lastMessage)
++  {
++    nntp_data->lastCached = 0;
++    if (nntp_data->newsrc_len)
++    {
++      safe_realloc (&nntp_data->newsrc_ent, sizeof (NEWSRC_ENTRY));
++      nntp_data->newsrc_len = 1;
++      nntp_data->newsrc_ent[0].first = 1;
++      nntp_data->newsrc_ent[0].last = 0;
++    }
++  }
++  nntp_data->firstMessage = first;
++  nntp_data->lastMessage = last;
++  if (!update_stat)
++    return 1;
 +
-+See Also
-+--------
++  /* update counters */
++  else if (!last || (!nntp_data->newsrc_ent && !nntp_data->lastCached))
++    nntp_data->unread = count;
++  else
++    nntp_group_unread_stat (nntp_data);
++  return 1;
++}
 +
-+    * NeoMutt project
-+    * Color command
++/* Check current newsgroup for new articles:
++ *  M_REOPENED	- articles have been renumbered or removed from server
++ *  M_NEW_MAIL	- new articles found
++ *  0		- no change
++ * -1		- lost connection */
++int nntp_check_mailbox (CONTEXT *ctx, int leave_lock)
++{
++  NNTP_DATA *nntp_data = ctx->data;
++  NNTP_SERVER *nserv = nntp_data->nserv;
++  time_t now = time (NULL);
++  int i, j;
++  int rc, ret = 0;
++  void *hc = NULL;
 +
-+Known Bugs
-+----------
++  if (nserv->check_time + NewsPollTimeout > now)
++    return 0;
 +
-+    None
++  mutt_message _("Checking for new messages...");
++  if (nntp_newsrc_parse (nserv) < 0)
++    return -1;
 +
-+Credits
-+-------
++  nserv->check_time = now;
++  rc = nntp_group_poll (nntp_data, 0);
++  if (rc < 0)
++  {
++    nntp_newsrc_close (nserv);
++    return -1;
++  }
++  if (rc)
++    nntp_active_save_cache (nserv);
 +
-+    * Rocco Rutte <pdmef at gmx.net>
-+    * Vincent Lefevre <vincent at vinc17.org>
-+    * Stefan Kuhn <wuodan at hispeed.ch>
-+    * Karel Zak <kzak at redhat.com>
-+    * Richard Russon <rich at flatcap.org>
++  /* articles have been renumbered, remove all headers */
++  if (nntp_data->lastMessage < nntp_data->lastLoaded)
++  {
++    for (i = 0; i < ctx->msgcount; i++)
++      mutt_free_header (&ctx->hdrs[i]);
++    ctx->msgcount = 0;
++    ctx->tagged = 0;
 +
-diff -urN mutt-1.6.1/README.quasi-delete mutt-1.6.1-neomutt/README.quasi-delete
---- mutt-1.6.1/README.quasi-delete	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/README.quasi-delete	2016-06-12 18:43:00.671451785 +0100
-@@ -0,0 +1,49 @@
-+Quasi-Delete Patch
-+==================
++    if (nntp_data->lastMessage < nntp_data->lastLoaded)
++    {
++      nntp_data->lastLoaded = nntp_data->firstMessage - 1;
++      if (NntpContext && nntp_data->lastMessage - nntp_data->lastLoaded >
++	  NntpContext)
++	nntp_data->lastLoaded = nntp_data->lastMessage - NntpContext;
++    }
++    ret = M_REOPENED;
++  }
 +
-+    Mark emails that should be hidden, but not deleted
++  /* .newsrc has been externally modified */
++  if (nserv->newsrc_modified)
++  {
++    anum_t anum;
++#ifdef USE_HCACHE
++    unsigned char *messages;
++    char buf[16];
++    void *hdata;
++    HEADER *hdr;
++    anum_t first = nntp_data->firstMessage;
 +
-+Patch
-+-----
++    if (NntpContext && nntp_data->lastMessage - first + 1 > NntpContext)
++      first = nntp_data->lastMessage - NntpContext + 1;
++    messages = safe_calloc (nntp_data->lastLoaded - first + 1,
++			    sizeof (unsigned char));
++    hc = nntp_hcache_open (nntp_data);
++    nntp_hcache_update (nntp_data, hc);
++#endif
 +
-+    To check if Mutt supports "Quasi-Delete", look for "patch-quasi-delete" in
-+    the mutt version.
++    /* update flags according to .newsrc */
++    for (i = j = 0; i < ctx->msgcount; i++)
++    {
++      int flagged = 0;
++      anum = NHDR (ctx->hdrs[i])->article_num;
 +
-+    Dependencies
-+    * mutt-1.6.1
++#ifdef USE_HCACHE
++      /* check hcache for flagged and deleted flags */
++      if (hc)
++      {
++	if (anum >= first && anum <= nntp_data->lastLoaded)
++	  messages[anum - first] = 1;
 +
-+Introduction
-+------------
++	snprintf (buf, sizeof (buf), "%d", anum);
++	hdata = mutt_hcache_fetch (hc, buf, strlen);
++	if (hdata)
++	{
++	  int deleted;
 +
-+    The "quasi-delete" function marks an email that should be hidden from the
-+    index, but NOT deleted.
++	  dprint (2, (debugfile,
++		      "nntp_check_mailbox: mutt_hcache_fetch %s\n", buf));
++	  hdr = mutt_hcache_restore (hdata, NULL);
++	  FREE (&hdata);
++	  hdr->data = 0;
++	  deleted = hdr->deleted;
++	  flagged = hdr->flagged;
++	  mutt_free_header (&hdr);
 +
-+    On its own, this patch isn't very useful. It forms a useful part of the
-+    notmuch plugin.
++	  /* header marked as deleted, removing from context */
++	  if (deleted)
++	  {
++	    mutt_set_flag (ctx, ctx->hdrs[i], M_TAG, 0);
++	    mutt_free_header (&ctx->hdrs[i]);
++	    continue;
++	  }
++	}
++      }
++#endif
 +
-+Functions
-+---------
++      if (!ctx->hdrs[i]->changed)
++      {
++	ctx->hdrs[i]->flagged = flagged;
++	ctx->hdrs[i]->read = 0;
++	ctx->hdrs[i]->old = 0;
++	nntp_article_status (ctx, ctx->hdrs[i], NULL, anum);
++	if (!ctx->hdrs[i]->read)
++	  nntp_parse_xref (ctx, ctx->hdrs[i]);
++      }
++      ctx->hdrs[j++] = ctx->hdrs[i];
++    }
 +
-+    Quasi-Delete Functions
++#ifdef USE_HCACHE
++    ctx->msgcount = j;
 +
-+    | Menus       | Default Key | Function         | Description                           |
-+    |-------------|-------------|------------------|---------------------------------------|
-+    | index,pager | (none)      | '<quasi-delete>' | delete from mutt, don't touch on disk |
++    /* restore headers without "deleted" flag */
++    for (anum = first; anum <= nntp_data->lastLoaded; anum++)
++    {
++      if (messages[anum - first])
++	continue;
 +
-+See Also
-+--------
++      snprintf (buf, sizeof (buf), "%d", anum);
++      hdata = mutt_hcache_fetch (hc, buf, strlen);
++      if (hdata)
++      {
++	dprint (2, (debugfile,
++		    "nntp_check_mailbox: mutt_hcache_fetch %s\n", buf));
++	if (ctx->msgcount >= ctx->hdrmax)
++	  mx_alloc_memory (ctx);
 +
-+    * NeoMutt project
-+    * notmuch patch
++	ctx->hdrs[ctx->msgcount] =
++	hdr = mutt_hcache_restore (hdata, NULL);
++	FREE (&hdata);
++	hdr->data = 0;
++	if (hdr->deleted)
++	{
++	  mutt_free_header (&hdr);
++	  if (nntp_data->bcache)
++	  {
++	    dprint (2, (debugfile,
++			"nntp_check_mailbox: mutt_bcache_del %s\n", buf));
++	    mutt_bcache_del (nntp_data->bcache, buf);
++	  }
++	  continue;
++	}
 +
-+Known Bugs
-+----------
++	ctx->msgcount++;
++	hdr->read = 0;
++	hdr->old = 0;
++	hdr->data = safe_calloc (1, sizeof (NNTP_HEADER_DATA));
++	NHDR (hdr)->article_num = anum;
++	nntp_article_status (ctx, hdr, NULL, anum);
++	if (!hdr->read)
++	  nntp_parse_xref (ctx, hdr);
++      }
++    }
++    FREE (&messages);
++#endif
 +
-+    None
++    nserv->newsrc_modified = 0;
++    ret = M_REOPENED;
++  }
 +
-+Credits
-+-------
++  /* some headers were removed, context must be updated */
++  if (ret == M_REOPENED)
++  {
++    if (ctx->subj_hash)
++      hash_destroy (&ctx->subj_hash, NULL);
++    if (ctx->id_hash)
++      hash_destroy (&ctx->id_hash, NULL);
++    mutt_clear_threads (ctx);
 +
-+    * Karel Zak <kzak at redhat.com>
-+    * Richard Russon <rich at flatcap.org>
++    ctx->vcount = 0;
++    ctx->deleted = 0;
++    ctx->new = 0;
++    ctx->unread = 0;
++    ctx->flagged = 0;
++    ctx->changed = 0;
++    ctx->id_hash = NULL;
++    ctx->subj_hash = NULL;
++    mx_update_context (ctx, ctx->msgcount);
++  }
 +
-diff -urN mutt-1.6.1/README.sidebar mutt-1.6.1-neomutt/README.sidebar
---- mutt-1.6.1/README.sidebar	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/README.sidebar	2016-06-12 18:43:00.671451785 +0100
-@@ -0,0 +1,145 @@
-+Sidebar Patch
-+=============
++  /* fetch headers of new articles */
++  if (nntp_data->lastMessage > nntp_data->lastLoaded)
++  {
++    int oldmsgcount = ctx->msgcount;
++    int quiet = ctx->quiet;
++    ctx->quiet = 1;
++#ifdef USE_HCACHE
++    if (!hc)
++    {
++      hc = nntp_hcache_open (nntp_data);
++      nntp_hcache_update (nntp_data, hc);
++    }
++#endif
++    rc = nntp_fetch_headers (ctx, hc, nntp_data->lastLoaded + 1,
++			     nntp_data->lastMessage, 0);
++    ctx->quiet = quiet;
++    if (rc >= 0)
++      nntp_data->lastLoaded = nntp_data->lastMessage;
++    if (ret == 0 && ctx->msgcount > oldmsgcount)
++      ret = M_NEW_MAIL;
++  }
 +
-+    Overview of mailboxes
++#ifdef USE_HCACHE
++  mutt_hcache_close (hc);
++#endif
++  if (ret || !leave_lock)
++    nntp_newsrc_close (nserv);
++  mutt_clear_error ();
++  return ret;
++}
 +
-+    NOTES:
++/* Check for new groups and new articles in subscribed groups:
++ *  1 - new groups found
++ *  0 - no new groups
++ * -1 - error */
++int nntp_check_new_groups (NNTP_SERVER *nserv)
++{
++  NNTP_DATA nntp_data;
++  time_t now;
++  struct tm *tm;
++  char buf[LONG_STRING];
++  char *msg = _("Checking for new newsgroups...");
++  unsigned int i;
++  int rc, update_active = FALSE;
 +
-+    If you haven't used the sidebar before, you might like to read the
-+    Sidebar Introduction:
++  if (!nserv || !nserv->newgroups_time)
++    return -1;
 +
-+        http://www.neomutt.org/sidebar-intro.html
++  /* check subscribed newsgroups for new articles */
++  if (option (OPTSHOWNEWNEWS))
++  {
++    mutt_message _("Checking for new messages...");
++    for (i = 0; i < nserv->groups_num; i++)
++    {
++      NNTP_DATA *nntp_data = nserv->groups_list[i];
 +
-+    If you have used an older version of the Sidebar, please note that some
-+    of the configuration has changed.
++      if (nntp_data && nntp_data->subscribed)
++      {
++	rc = nntp_group_poll (nntp_data, 1);
++	if (rc < 0)
++	  return -1;
++	if (rc > 0)
++	  update_active = TRUE;
++      }
++    }
++    /* select current newsgroup */
++    if (Context && Context->magic == M_NNTP)
++    {
++      buf[0] = '\0';
++      if (nntp_query ((NNTP_DATA *)Context->data, buf, sizeof (buf)) < 0)
++	return -1;
++    }
++  }
++  else if (nserv->newgroups_time)
++    return 0;
 +
-+        http://www.neomutt.org/sidebar-intro.html#intro-sidebar-config-changes
++  /* get list of new groups */
++  mutt_message (msg);
++  if (nntp_date (nserv, &now) < 0)
++    return -1;
++  nntp_data.nserv = nserv;
++  if (Context && Context->magic == M_NNTP)
++    nntp_data.group = ((NNTP_DATA *)Context->data)->group;
++  else
++    nntp_data.group = NULL;
++  i = nserv->groups_num;
++  tm = gmtime (&nserv->newgroups_time);
++  snprintf (buf, sizeof (buf), "NEWGROUPS %02d%02d%02d %02d%02d%02d GMT\r\n",
++	    tm->tm_year % 100, tm->tm_mon + 1, tm->tm_mday,
++	    tm->tm_hour, tm->tm_min, tm->tm_sec);
++  rc = nntp_fetch_lines (&nntp_data, buf, sizeof (buf), msg,
++			 nntp_add_group, nserv);
++  if (rc)
++  {
++    if (rc > 0)
++    {
++      mutt_error ("NEWGROUPS: %s", buf);
++      mutt_sleep (2);
++    }
++    return -1;
++  }
 +
-+Patch
-+-----
++  /* new groups found */
++  rc = 0;
++  if (nserv->groups_num != i)
++  {
++    nserv->newgroups_time = now;
 +
-+    To check if Mutt supports "Sidebar", look for "+USE_SIDEBAR" in the mutt
-+    version.
++    /* loading descriptions */
++    if (option (OPTLOADDESC))
++    {
++      unsigned int count = 0;
++      progress_t progress;
 +
-+    Dependencies
-+    * mutt-1.6.1
++      mutt_progress_init (&progress, _("Loading descriptions..."),
++			  M_PROGRESS_MSG, ReadInc, nserv->groups_num - i);
++      for (; i < nserv->groups_num; i++)
++      {
++	NNTP_DATA *nntp_data = nserv->groups_list[i];
 +
-+Introduction
-+------------
++	if (get_description (nntp_data, NULL, NULL) < 0)
++	  return -1;
++	mutt_progress_update (&progress, ++count, -1);
++      }
++    }
++    update_active = TRUE;
++    rc = 1;
++  }
++  if (update_active)
++    nntp_active_save_cache (nserv);
++  mutt_clear_error ();
++  return rc;
++}
 +
-+    The Sidebar shows a list of all your mailboxes. The list can be turned on
-+    and off, it can be themed and the list style can be configured.
++/* Fetch article by Message-ID:
++ *  0 - success
++ *  1 - no such article
++ * -1 - error */
++int nntp_check_msgid (CONTEXT *ctx, const char *msgid)
++{
++  NNTP_DATA *nntp_data = ctx->data;
++  HEADER *hdr;
++  FILE *fp;
++  char tempfile[_POSIX_PATH_MAX];
++  char buf[LONG_STRING];
++  int rc;
 +
-+    This part of the manual is a reference guide. If you want a simple
-+    introduction with examples see the Sidebar Howto. If you just want to get
-+    started, you could use the sample Sidebar muttrc.
++  mutt_mktemp (tempfile, sizeof (tempfile));
++  fp = safe_fopen (tempfile, "w+");
++  if (!fp)
++  {
++    mutt_perror (tempfile);
++    unlink (tempfile);
++    return -1;
++  }
 +
-+    This version of Sidebar is based on Terry Chan's [2015-11-11
-+    release](http://www.lunar-linux.org/mutt-sidebar/). It contains many new
-+    features, lots of bugfixes.
++  snprintf (buf, sizeof (buf), "HEAD %s\r\n", msgid);
++  rc = nntp_fetch_lines (nntp_data, buf, sizeof (buf), NULL,
++			 fetch_tempfile, fp);
++  if (rc)
++  {
++    fclose (fp);
++    unlink (tempfile);
++    if (rc < 0)
++      return -1;
++    if (!mutt_strncmp ("430", buf, 3))
++      return 1;
++    mutt_error ("HEAD: %s", buf);
++    return -1;
++  }
 +
-+Variables
-+---------
++  /* parse header */
++  if (ctx->msgcount == ctx->hdrmax)
++    mx_alloc_memory (ctx);
++  hdr = ctx->hdrs[ctx->msgcount] = mutt_new_header ();
++  hdr->data = safe_calloc (1, sizeof (NNTP_HEADER_DATA));
++  hdr->env = mutt_read_rfc822_header (fp, hdr, 0, 0);
++  fclose (fp);
++  unlink (tempfile);
 +
-+    Sidebar Variables
++  /* get article number */
++  if (hdr->env->xref)
++    nntp_parse_xref (ctx, hdr);
++  else
++  {
++    snprintf (buf, sizeof (buf), "STAT %s\r\n", msgid);
++    if (nntp_query (nntp_data, buf, sizeof (buf)) < 0)
++    {
++      mutt_free_header (&hdr);
++      return -1;
++    }
++    sscanf (buf + 4, ANUM, &NHDR (hdr)->article_num);
++  }
 +
-+    | Name                    | Type    | Default                     |
-+    |-------------------------|---------|-----------------------------|
-+    | 'sidebar_delim_chars'   | string  | '/.'                        |
-+    | 'sidebar_divider_char'  | string  | '|'                         |
-+    | 'sidebar_folder_indent' | boolean | 'no'                        |
-+    | 'sidebar_format'        | string  | '%B%?F? [%F]?%* %?N?%N/?%S' |
-+    | 'sidebar_indent_string' | string  | '  ' (two spaces)           |
-+    | 'sidebar_new_mail_only' | boolean | 'no'                        |
-+    | 'sidebar_next_new_wrap' | boolean | 'no'                        |
-+    | 'sidebar_refresh_time'  | number  | '60'                        |
-+    | 'sidebar_short_path'    | boolean | 'no'                        |
-+    | 'sidebar_sort_method'   | enum    | 'SORT_ORDER'                |
-+    | 'sidebar_visible'       | boolean | 'no'                        |
-+    | 'sidebar_whitelist'     | list    | (empty)                     |
-+    | 'sidebar_width'         | number  | '20'                        |
++  /* reset flags */
++  hdr->read = 0;
++  hdr->old = 0;
++  hdr->deleted = 0;
++  hdr->changed = 1;
++  hdr->received = hdr->date_sent;
++  hdr->index = ctx->msgcount++;
++  mx_update_context (ctx, 1);
++  return 0;
++}
 +
-+Functions
-+---------
++typedef struct
++{
++  CONTEXT *ctx;
++  unsigned int num;
++  unsigned int max;
++  anum_t *child;
++} CHILD_CTX;
 +
-+    Sidebar Functions
++/* Parse XPAT line */
++static int fetch_children (char *line, void *data)
++{
++  CHILD_CTX *cc = data;
++  anum_t anum;
++  unsigned int i;
 +
-+    Sidebar adds the following functions to Mutt. By default, none of them are
-+    bound to keys.
++  if (!line || sscanf (line, ANUM, &anum) != 1)
++    return 0;
++  for (i = 0; i < cc->ctx->msgcount; i++)
++    if (NHDR (cc->ctx->hdrs[i])->article_num == anum)
++      return 0;
++  if (cc->num >= cc->max)
++  {
++    cc->max *= 2;
++    safe_realloc (&cc->child, sizeof (anum_t) * cc->max);
++  }
++  cc->child[cc->num++] = anum;
++  return 0;
++}
 +
-+    | Menus       | Function                   | Description                                          |
-+    |-------------|----------------------------|------------------------------------------------------|
-+    | index,pager | '<sidebar-next>'           | Move the highlight to next mailbox                   |
-+    | index,pager | '<sidebar-next-new>'       | Move the highlight to next mailbox with new mail     |
-+    | index,pager | '<sidebar-open>'           | Open highlighted mailbox                             |
-+    | index,pager | '<sidebar-page-down>'      | Scroll the Sidebar down 1 page                       |
-+    | index,pager | '<sidebar-page-up>'        | Scroll the Sidebar up 1 page                         |
-+    | index,pager | '<sidebar-prev>'           | Move the highlight to previous mailbox               |
-+    | index,pager | '<sidebar-prev-new>'       | Move the highlight to previous mailbox with new mail |
-+    | index,pager | '<sidebar-toggle-visible>' | Make the Sidebar (in)visible                         |
++/* Fetch children of article with the Message-ID */
++int nntp_check_children (CONTEXT *ctx, const char *msgid)
++{
++  NNTP_DATA *nntp_data = ctx->data;
++  CHILD_CTX cc;
++  char buf[STRING];
++  int i, rc, quiet;
++  void *hc = NULL;
 +
-+Commands
-+--------
++  if (!nntp_data || !nntp_data->nserv)
++    return -1;
++  if (nntp_data->firstMessage > nntp_data->lastLoaded)
++    return 0;
 +
-+        sidebar_whitelist mailbox [ mailbox... ]
++  /* init context */
++  cc.ctx = ctx;
++  cc.num = 0;
++  cc.max = 10;
++  cc.child = safe_malloc (sizeof (anum_t) * cc.max);
 +
-+Colors
-+------
++  /* fetch numbers of child messages */
++  snprintf (buf, sizeof (buf), "XPAT References %d-%d *%s*\r\n",
++	    nntp_data->firstMessage, nntp_data->lastLoaded, msgid);
++  rc = nntp_fetch_lines (nntp_data, buf, sizeof (buf), NULL,
++			 fetch_children, &cc);
++  if (rc)
++  {
++    FREE (&cc.child);
++    if (rc > 0) {
++      if (mutt_strncmp ("500", buf, 3))
++	mutt_error ("XPAT: %s", buf);
++      else
++	mutt_error _("Unable to find child articles because server does not support XPAT command.");
++    }
++    return -1;
++  }
 +
-+    Sidebar Colors
++  /* fetch all found messages */
++  quiet = ctx->quiet;
++  ctx->quiet = 1;
++#ifdef USE_HCACHE
++  hc = nntp_hcache_open (nntp_data);
++#endif
++  for (i = 0; i < cc.num; i++)
++  {
++    rc = nntp_fetch_headers (ctx, hc, cc.child[i], cc.child[i], 1);
++    if (rc < 0)
++      break;
++  }
++#ifdef USE_HCACHE
++  mutt_hcache_close (hc);
++#endif
++  ctx->quiet = quiet;
++  FREE (&cc.child);
++  return rc < 0 ? -1 : 0;
++}
+diff --git a/nntp.h b/nntp.h
+new file mode 100644
+index 0000000..2f37793
+--- /dev/null
++++ b/nntp.h
+@@ -0,0 +1,168 @@
++/*
++ * Copyright (C) 1998 Brandon Long <blong at fiction.net>
++ * Copyright (C) 1999 Andrej Gritsenko <andrej at lucky.net>
++ * Copyright (C) 2000-2012 Vsevolod Volkov <vvv at mutt.org.ua>
++ *
++ *     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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
 +
-+    | Name                | Default Color    | Description                                                      |
-+    |---------------------|------------------|------------------------------------------------------------------|
-+    | 'sidebar_divider'   | default          | The dividing line between the Sidebar and the Index/Pager panels |
-+    | 'sidebar_flagged'   | default          | Mailboxes containing flagged mail                                |
-+    | 'sidebar_highlight' | underline        | Cursor to select a mailbox                                       |
-+    | 'sidebar_indicator' | mutt 'indicator' | The mailbox open in the Index panel                              |
-+    | 'sidebar_new'       | default          | Mailboxes containing new mail                                    |
-+    | 'sidebar_spoolfile' | default          | Mailbox that receives incoming mail                              |
++#ifndef _NNTP_H_
++#define _NNTP_H_ 1
 +
-+    If the sidebar_indicator color isn't set, then the default Mutt indicator
-+    color will be used (the color used in the index panel).
++#include "mutt_socket.h"
++#include "mailbox.h"
++#include "bcache.h"
 +
-+Sort
-+----
++#if USE_HCACHE
++#include "hcache.h"
++#endif
 +
-+    Sidebar Sort
++#include <time.h>
++#include <sys/types.h>
++#include <stdint.h>
 +
-+    | Sort       | Description                |
-+    |------------|----------------------------|
-+    | 'alpha'    | Alphabetically by path     |
-+    | 'count'    | Total number of messages   |
-+    | 'flagged'  | Number of flagged messages |
-+    | 'name'     | Alphabetically by path     |
-+    | 'new'      | Number of new messages     |
-+    | 'path'     | Alphabetically by path     |
-+    | 'unsorted' | Do not resort the paths    |
++#define NNTP_PORT 119
++#define NNTP_SSL_PORT 563
 +
-+See Also
-+--------
++/* number of entries in article cache */
++#define NNTP_ACACHE_LEN 10
 +
-+    * Regular Expressions
-+    * Patterns
-+    * Color command
-+    * notmuch patch
++/* article number type and format */
++#define anum_t uint32_t
++#define ANUM "%u"
 +
-+Known Bugs
-+----------
++enum
++{
++  NNTP_NONE = 0,
++  NNTP_OK,
++  NNTP_BYE
++};
++
++typedef struct
++{
++  unsigned int hasCAPABILITIES : 1;
++  unsigned int hasSTARTTLS : 1;
++  unsigned int hasDATE : 1;
++  unsigned int hasLIST_NEWSGROUPS : 1;
++  unsigned int hasXGTITLE : 1;
++  unsigned int hasLISTGROUP : 1;
++  unsigned int hasLISTGROUPrange : 1;
++  unsigned int hasOVER : 1;
++  unsigned int hasXOVER : 1;
++  unsigned int use_tls : 3;
++  unsigned int status : 3;
++  unsigned int cacheable : 1;
++  unsigned int newsrc_modified : 1;
++  FILE *newsrc_fp;
++  char *newsrc_file;
++  char *authenticators;
++  char *overview_fmt;
++  off_t size;
++  time_t mtime;
++  time_t newgroups_time;
++  time_t check_time;
++  unsigned int groups_num;
++  unsigned int groups_max;
++  void **groups_list;
++  HASH *groups_hash;
++  CONNECTION *conn;
++} NNTP_SERVER;
 +
-+    Unsorted isn't
++typedef struct
++{
++  anum_t first;
++  anum_t last;
++} NEWSRC_ENTRY;
 +
-+Credits
-+-------
++typedef struct
++{
++  unsigned int index;
++  char *path;
++} NNTP_ACACHE;
 +
-+    * Justin Hibbits <jrh29 at po.cwru.edu>
-+    * Thomer M. Gil <mutt at thomer.com>
-+    * David Sterba <dsterba at suse.cz>
-+    * Evgeni Golov <evgeni at debian.org>
-+    * Fabian Groffen <grobian at gentoo.org>
-+    * Jason DeTiberus <jdetiber at redhat.com>
-+    * Stefan Assmann <sassmann at kpanic.de>
-+    * Steve Kemp <steve at steve.org.uk>
-+    * Terry Chan <tchan at lunar-linux.org>
-+    * Tyler Earnest <tylere at rne.st>
-+    * Richard Russon <rich at flatcap.org>
++typedef struct
++{
++  char *group;
++  char *desc;
++  anum_t firstMessage;
++  anum_t lastMessage;
++  anum_t lastLoaded;
++  anum_t lastCached;
++  anum_t unread;
++  unsigned int subscribed : 1;
++  unsigned int new : 1;
++  unsigned int allowed : 1;
++  unsigned int deleted : 1;
++  unsigned int newsrc_len;
++  NEWSRC_ENTRY *newsrc_ent;
++  NNTP_SERVER *nserv;
++  NNTP_ACACHE acache[NNTP_ACACHE_LEN];
++  body_cache_t *bcache;
++} NNTP_DATA;
 +
-diff -urN mutt-1.6.1/README.skip-quoted mutt-1.6.1-neomutt/README.skip-quoted
---- mutt-1.6.1/README.skip-quoted	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/README.skip-quoted	2016-06-12 18:43:00.671451785 +0100
-@@ -0,0 +1,47 @@
-+Skip-Quoted Patch
-+=================
++typedef struct
++{
++  anum_t article_num;
++  unsigned int parsed : 1;
++} NNTP_HEADER_DATA;
 +
-+    Leave some context visible
++#define NHDR(hdr) ((NNTP_HEADER_DATA*)((hdr)->data))
 +
-+Patch
-+-----
++/* internal functions */
++int nntp_add_group (char *, void *);
++int nntp_active_save_cache (NNTP_SERVER *);
++int nntp_check_new_groups (NNTP_SERVER *);
++int nntp_fastclose_mailbox (CONTEXT *);
++int nntp_open_connection (NNTP_SERVER *);
++void nntp_newsrc_gen_entries (CONTEXT *);
++void nntp_bcache_update (NNTP_DATA *);
++void nntp_article_status (CONTEXT *, HEADER *, char *, anum_t);
++void nntp_group_unread_stat (NNTP_DATA *);
++void nntp_data_free (void *);
++void nntp_acache_free (NNTP_DATA *);
++void nntp_delete_group_cache (NNTP_DATA *);
 +
-+    To check if Mutt supports "Skip-Quoted", look for "patch-skip-quoted" in
-+    the mutt version.
++/* exposed interface */
++NNTP_SERVER *nntp_select_server (char *, int);
++NNTP_DATA *mutt_newsgroup_subscribe (NNTP_SERVER *, char *);
++NNTP_DATA *mutt_newsgroup_unsubscribe (NNTP_SERVER *, char *);
++NNTP_DATA *mutt_newsgroup_catchup (NNTP_SERVER *, char *);
++NNTP_DATA *mutt_newsgroup_uncatchup (NNTP_SERVER *, char *);
++int nntp_active_fetch (NNTP_SERVER *);
++int nntp_newsrc_update (NNTP_SERVER *);
++int nntp_open_mailbox (CONTEXT *);
++int nntp_sync_mailbox (CONTEXT *);
++int nntp_check_mailbox (CONTEXT *, int);
++int nntp_fetch_message (MESSAGE *, CONTEXT *, int);
++int nntp_post (const char *);
++int nntp_check_msgid (CONTEXT *, const char *);
++int nntp_check_children (CONTEXT *, const char *);
++int nntp_newsrc_parse (NNTP_SERVER *);
++void nntp_newsrc_close (NNTP_SERVER *);
++void nntp_buffy (char *, size_t);
++void nntp_expand_path (char *, size_t, ACCOUNT *);
++void nntp_clear_cache (NNTP_SERVER *);
++const char *nntp_format_str (char *, size_t, size_t, int, char, const char *,
++			     const char *, const char *, const char *,
++			     unsigned long, format_flag);
 +
-+    Dependencies
-+    * mutt-1.6.1
++NNTP_SERVER *CurrentNewsSrv INITVAL (NULL);
 +
-+Introduction
-+------------
++#ifdef USE_HCACHE
++header_cache_t *nntp_hcache_open (NNTP_DATA *);
++void nntp_hcache_update (NNTP_DATA *, header_cache_t *);
++#endif
++
++#endif /* _NNTP_H_ */
+diff --git a/pager.c b/pager.c
+index 8bfe72c..21dda91 100644
+--- a/pager.c
++++ b/pager.c
+@@ -29,6 +29,9 @@
+ #include "pager.h"
+ #include "attach.h"
+ #include "mbyte.h"
++#ifdef USE_SIDEBAR
++#include "sidebar.h"
++#endif
+ 
+ #include "mutt_crypt.h"
+ 
+@@ -1085,6 +1088,11 @@ fill_buffer (FILE *f, LOFF_T *last_pos, LOFF_T offset, unsigned char **buf,
+   return b_read;
+ }
+ 
++#ifdef USE_NNTP
++#include "mx.h"
++#include "nntp.h"
++#endif
 +
-+    When viewing an email, the '<skip-to-quoted>' function (by default the 'S'
-+    key) will scroll past any quoted text. Sometimes, a little context is
-+    useful.
+ 
+ static int format_line (struct line_t **lineInfo, int n, unsigned char *buf,
+ 			int flags, ansi_attr *pa, int cnt,
+@@ -1491,7 +1499,7 @@ display_line (FILE *f, LOFF_T *last_pos, struct line_t **lineInfo, int n,
+    * a newline (grr!).
+    */
+ #ifndef USE_SLANG_CURSES
+-    if (col < COLS)
++    if (col < (COLS - SidebarWidth))
+ #endif
+       addch ('\n');
+ 
+@@ -1542,6 +1550,16 @@ static const struct mapping_t PagerHelpExtra[] = {
+   { NULL,	0 }
+ };
+ 
++#ifdef USE_NNTP
++static struct mapping_t PagerNewsHelpExtra[] = {
++  { N_("Post"),     OP_POST },
++  { N_("Followup"), OP_FOLLOWUP },
++  { N_("Del"),      OP_DELETE },
++  { N_("Next"),     OP_MAIN_NEXT_UNDELETED },
++  { NULL,           0 }
++};
++#endif
 +
-+    By setting the '$skip_quoted_offset' variable, you can select how much of
-+    the quoted text is left visible.
+ 
+ 
+ /* This pager is actually not so simple as it once was.  It now operates in
+@@ -1573,6 +1591,7 @@ mutt_pager (const char *banner, const char *fname, int flags, pager_t *extra)
+ 
+   int bodyoffset = 1;			/* offset of first line of real text */
+   int statusoffset = 0; 		/* offset for the status bar */
++  int statuswidth = COLS;
+   int helpoffset = LINES - 2;		/* offset for the help bar. */
+   int bodylen = LINES - 2 - bodyoffset; /* length of displayable area */
+ 
+@@ -1583,6 +1602,10 @@ mutt_pager (const char *banner, const char *fname, int flags, pager_t *extra)
+   int old_PagerIndexLines;		/* some people want to resize it
+   					 * while inside the pager... */
+ 
++#ifdef USE_NNTP
++  char *followup_to;
++#endif
 +
-+Variables
-+---------
+   if (!(flags & M_SHOWCOLOR))
+     flags |= M_SHOWFLAT;
+ 
+@@ -1622,7 +1645,11 @@ mutt_pager (const char *banner, const char *fname, int flags, pager_t *extra)
+   if (IsHeader (extra))
+   {
+     strfcpy (tmphelp, helpstr, sizeof (tmphelp));
+-    mutt_compile_help (buffer, sizeof (buffer), MENU_PAGER, PagerHelpExtra);
++    mutt_compile_help (buffer, sizeof (buffer), MENU_PAGER,
++#ifdef USE_NNTP
++	(Context && (Context->magic == M_NNTP)) ? PagerNewsHelpExtra :
++#endif
++	PagerHelpExtra);
+     snprintf (helpstr, sizeof (helpstr), "%s %s", tmphelp, buffer);
+   }
+   if (!InHelp)
+@@ -1726,6 +1753,9 @@ mutt_pager (const char *banner, const char *fname, int flags, pager_t *extra)
+       }
+ 
+       redraw |= REDRAW_BODY | REDRAW_INDEX | REDRAW_STATUS;
++#ifdef USE_SIDEBAR
++      redraw |= REDRAW_SIDEBAR;
++#endif
+       mutt_show_error ();
+     }
+ 
+@@ -1744,10 +1774,18 @@ mutt_pager (const char *banner, const char *fname, int flags, pager_t *extra)
+ 	}
+     }
+ 
++#ifdef USE_SIDEBAR
++    if ((redraw & REDRAW_SIDEBAR) || SidebarNeedsRedraw)
++    {
++      SidebarNeedsRedraw = 0;
++      mutt_sb_draw ();
++    }
++#endif
 +
-+    | Name                 | Type   | Default |
-+    |----------------------|--------|---------|
-+    | 'skip_quoted_offset' | number | 0       |
+     if ((redraw & REDRAW_BODY) || topline != oldtopline)
+     {
+       do {
+-	move (bodyoffset, 0);
++	move (bodyoffset, SidebarWidth);
+ 	curline = oldtopline = topline;
+ 	lines = 0;
+ 	force_redraw = 0;
+@@ -1760,6 +1798,9 @@ mutt_pager (const char *banner, const char *fname, int flags, pager_t *extra)
+ 			    &QuoteList, &q_level, &force_redraw, &SearchRE) > 0)
+ 	    lines++;
+ 	  curline++;
++#ifdef USE_SIDEBAR
++	  move (lines + bodyoffset, SidebarWidth);
++#endif
+ 	}
+ 	last_offset = lineInfo[curline].offset;
+       } while (force_redraw);
+@@ -1772,6 +1813,9 @@ mutt_pager (const char *banner, const char *fname, int flags, pager_t *extra)
+ 	  addch ('~');
+ 	addch ('\n');
+ 	lines++;
++#ifdef USE_SIDEBAR
++	move (lines + bodyoffset, SidebarWidth);
++#endif
+       }
+       NORMAL_COLOR;
+ 
+@@ -1789,29 +1833,49 @@ mutt_pager (const char *banner, const char *fname, int flags, pager_t *extra)
+       hfi.ctx = Context;
+       hfi.pager_progress = pager_progress_str;
+ 
++#ifdef USE_SIDEBAR
++      statuswidth = COLS;
++      if (option (OPTSTATUSONTOP) && (PagerIndexLines > 0))
++        statuswidth -= SidebarWidth;
++#endif
 +
-+See Also
-+--------
+       if (last_pos < sb.st_size - 1)
+ 	snprintf(pager_progress_str, sizeof(pager_progress_str), OFF_T_FMT "%%", (100 * last_offset / sb.st_size));
+       else
+ 	strfcpy(pager_progress_str, (topline == 0) ? "all" : "end", sizeof(pager_progress_str));
+ 
+       /* print out the pager status bar */
+-      move (statusoffset, 0);
++      move (statusoffset, SidebarWidth);
+       SETCOLOR (MT_COLOR_STATUS);
++#ifdef USE_SIDEBAR
++      short sw = SidebarWidth;
++      if (option (OPTSTATUSONTOP) && PagerIndexLines > 0) {
++        CLEARLINE_WIN (statusoffset);
++      } else {
++        CLEARLINE (statusoffset);
++        /* Temporarily lie about the sidebar width */
++        SidebarWidth = 0;
++      }
++#endif
+ 
+       if (IsHeader (extra) || IsMsgAttach (extra))
+       {
+-	size_t l1 = COLS * MB_LEN_MAX;
++	size_t l1 = statuswidth * MB_LEN_MAX;
+ 	size_t l2 = sizeof (buffer);
+ 	hfi.hdr = (IsHeader (extra)) ? extra->hdr : extra->bdy->hdr;
+ 	mutt_make_string_info (buffer, l1 < l2 ? l1 : l2, NONULL (PagerFmt), &hfi, M_FORMAT_MAKEPRINT);
+-	mutt_paddstr (COLS, buffer);
++	mutt_draw_statusline (statuswidth, buffer, l2);
+       }
+       else
+       {
+ 	char bn[STRING];
+ 	snprintf (bn, sizeof (bn), "%s (%s)", banner, pager_progress_str);
+-	mutt_paddstr (COLS, bn);
++	mutt_draw_statusline (statuswidth, bn, sizeof (bn));
+       }
++#ifdef USE_SIDEBAR
++      if (!option (OPTSTATUSONTOP) || PagerIndexLines == 0)
++        SidebarWidth = sw; /* Restore the sidebar width */
++#endif
+       NORMAL_COLOR;
+       if (option(OPTTSENABLED) && TSSupported)
+       {
+@@ -1827,16 +1891,26 @@ mutt_pager (const char *banner, const char *fname, int flags, pager_t *extra)
+       /* redraw the pager_index indicator, because the
+        * flags for this message might have changed. */
+       menu_redraw_current (index);
++#ifdef USE_SIDEBAR
++      mutt_sb_draw();
++#endif
+ 
+       /* print out the index status bar */
+       menu_status_line (buffer, sizeof (buffer), index, NONULL(Status));
+  
+-      move (indexoffset + (option (OPTSTATUSONTOP) ? 0 : (indexlen - 1)), 0);
++      move (indexoffset + (option (OPTSTATUSONTOP) ? 0 : (indexlen - 1)),
++          (option(OPTSTATUSONTOP) ? 0: SidebarWidth));
+       SETCOLOR (MT_COLOR_STATUS);
+-      mutt_paddstr (COLS, buffer);
++      mutt_paddstr (COLS - (option(OPTSTATUSONTOP) ? 0 : SidebarWidth), buffer);
+       NORMAL_COLOR;
+     }
+ 
++#ifdef USE_SIDEBAR
++    /* if we're not using the index, update every time */
++    if (index == 0)
++      mutt_sb_draw();
++#endif
 +
-+    * NeoMutt project
+     redraw = 0;
+ 
+     if (option(OPTBRAILLEFRIENDLY)) {
+@@ -2249,11 +2323,11 @@ search_next:
+ 	  int dretval = 0;
+ 	  int new_topline = topline;
+ 
+-	  while ((new_topline < lastLine ||
++	  while (((new_topline + SkipQuotedOffset) < lastLine ||
+ 		  (0 == (dretval = display_line (fp, &last_pos, &lineInfo,
+ 			 new_topline, &lastLine, &maxLine, M_TYPES | (flags & M_PAGER_NOWRAP),
+ 			 &QuoteList, &q_level, &force_redraw, &SearchRE))))
+-		 && lineInfo[new_topline].type != MT_COLOR_QUOTED)
++		 && lineInfo[new_topline + SkipQuotedOffset].type != MT_COLOR_QUOTED)
+ 	    new_topline++;
+ 
+ 	  if (dretval < 0)
+@@ -2262,11 +2336,11 @@ search_next:
+ 	    break;
+ 	  }
+ 
+-	  while ((new_topline < lastLine ||
++	  while (((new_topline + SkipQuotedOffset) < lastLine ||
+ 		  (0 == (dretval = display_line (fp, &last_pos, &lineInfo,
+ 			 new_topline, &lastLine, &maxLine, M_TYPES | (flags & M_PAGER_NOWRAP),
+ 			 &QuoteList, &q_level, &force_redraw, &SearchRE))))
+-		 && lineInfo[new_topline].type == MT_COLOR_QUOTED)
++		 && lineInfo[new_topline + SkipQuotedOffset].type == MT_COLOR_QUOTED)
+ 	    new_topline++;
+ 
+ 	  if (dretval < 0)
+@@ -2351,6 +2425,7 @@ search_next:
+ 	MAYBE_REDRAW (redraw);
+ 	break;
+ 
++      case OP_PURGE_MESSAGE:
+       case OP_DELETE:
+ 	CHECK_MODE(IsHeader (extra));
+ 	CHECK_READONLY;
+@@ -2358,6 +2433,8 @@ search_next:
+ 	CHECK_ACL(M_ACL_DELETE, _("Cannot delete message"));
+ 
+ 	mutt_set_flag (Context, extra->hdr, M_DELETE, 1);
++	mutt_set_flag (Context, extra->hdr, M_PURGED,
++		       ch != OP_PURGE_MESSAGE ? 0 : 1);
+         if (option (OPTDELETEUNTAG))
+ 	  mutt_set_flag (Context, extra->hdr, M_TAG, 0);
+ 	redraw = REDRAW_STATUS | REDRAW_INDEX;
+@@ -2543,6 +2620,60 @@ search_next:
+ 	redraw = REDRAW_FULL;
+ 	break;
+ 
++#ifdef USE_NNTP
++      case OP_POST:
++	CHECK_MODE(IsHeader (extra) && !IsAttach (extra));
++	CHECK_ATTACH;
++	if (extra->ctx && extra->ctx->magic == M_NNTP &&
++	    !((NNTP_DATA *)extra->ctx->data)->allowed &&
++	    query_quadoption (OPT_TOMODERATED,_("Posting to this group not allowed, may be moderated. Continue?")) != M_YES)
++	  break;
++	ci_send_message (SENDNEWS, NULL, NULL, extra->ctx, NULL);
++	redraw = REDRAW_FULL;
++	break;
 +
-+Known Bugs
-+----------
++      case OP_FORWARD_TO_GROUP:
++	CHECK_MODE(IsHeader (extra) || IsMsgAttach (extra));
++	CHECK_ATTACH;
++	if (extra->ctx && extra->ctx->magic == M_NNTP &&
++	    !((NNTP_DATA *)extra->ctx->data)->allowed &&
++	    query_quadoption (OPT_TOMODERATED,_("Posting to this group not allowed, may be moderated. Continue?")) != M_YES)
++	  break;
++	if (IsMsgAttach (extra))
++	  mutt_attach_forward (extra->fp, extra->hdr, extra->idx,
++			       extra->idxlen, extra->bdy, SENDNEWS);
++	else
++	  ci_send_message (SENDNEWS|SENDFORWARD, NULL, NULL, extra->ctx, extra->hdr);
++	redraw = REDRAW_FULL;
++	break;
 +
-+    None
++      case OP_FOLLOWUP:
++	CHECK_MODE(IsHeader (extra) || IsMsgAttach (extra));
++	CHECK_ATTACH;
 +
-+Credits
-+-------
++	if (IsMsgAttach (extra))
++	  followup_to = extra->bdy->hdr->env->followup_to;
++	else
++	  followup_to = extra->hdr->env->followup_to;
 +
-+    * David Sterba <dsterba at suse.cz>
-+    * Richard Russon <rich at flatcap.org>
++	if (!followup_to || mutt_strcasecmp (followup_to, "poster") ||
++	    query_quadoption (OPT_FOLLOWUPTOPOSTER,_("Reply by mail as poster prefers?")) != M_YES)
++	{
++	  if (extra->ctx && extra->ctx->magic == M_NNTP &&
++	      !((NNTP_DATA *)extra->ctx->data)->allowed &&
++	      query_quadoption (OPT_TOMODERATED,_("Posting to this group not allowed, may be moderated. Continue?")) != M_YES)
++	    break;
++	  if (IsMsgAttach (extra))
++	    mutt_attach_reply (extra->fp, extra->hdr, extra->idx,
++			       extra->idxlen, extra->bdy, SENDNEWS|SENDREPLY);
++	  else
++	    ci_send_message (SENDNEWS|SENDREPLY, NULL, NULL,
++			     extra->ctx, extra->hdr);
++	  redraw = REDRAW_FULL;
++	  break;
++	}
++#endif
 +
-diff -urN mutt-1.6.1/README.SSL mutt-1.6.1-neomutt/README.SSL
---- mutt-1.6.1/README.SSL	2016-06-12 18:43:00.395447481 +0100
-+++ mutt-1.6.1-neomutt/README.SSL	2016-06-12 18:43:00.669451754 +0100
-@@ -5,7 +5,7 @@
- -----------
- If you want to have SSL support in mutt, you need to install OpenSSL
- (http://www.openssl.org) libraries and headers before compiling.
--OpenSSL versions 0.9.3 through 0.9.6a have been tested.
-+OpenSSL versions 0.9.3 through 1.0.1c have been tested.
+       case OP_REPLY:
+ 	CHECK_MODE(IsHeader (extra) || IsMsgAttach (extra));
+         CHECK_ATTACH;      
+@@ -2589,7 +2720,7 @@ search_next:
+         CHECK_ATTACH;
+         if (IsMsgAttach (extra))
+ 	  mutt_attach_forward (extra->fp, extra->hdr, extra->idx,
+-			       extra->idxlen, extra->bdy);
++			       extra->idxlen, extra->bdy, 0);
+         else
+ 	  ci_send_message (SENDFORWARD, NULL, NULL, extra->ctx, extra->hdr);
+ 	redraw = REDRAW_FULL;
+@@ -2688,6 +2819,7 @@ search_next:
+ 	CHECK_ACL(M_ACL_DELETE, _("Cannot undelete message"));
  
- For SSL support to be enabled, you need to run the ``configure''
- script with ``--enable-imap --with-ssl[=PFX]'' parameters.  If the
-@@ -65,6 +65,12 @@
- can also be saved so that further connections to the server are
- automatically accepted. 
+ 	mutt_set_flag (Context, extra->hdr, M_DELETE, 0);
++	mutt_set_flag (Context, extra->hdr, M_PURGED, 0);
+ 	redraw = REDRAW_STATUS | REDRAW_INDEX;
+ 	if (option (OPTRESOLVE))
+ 	{
+@@ -2704,9 +2836,11 @@ search_next:
+ 	CHECK_ACL(M_ACL_DELETE, _("Cannot undelete message(s)"));
  
-+If OpenSSL was built with support for ServerNameIndication (SNI) and TLS
-+is used in the negotiation, mutt will send its idea of the server-name
-+as part of the TLS negotiation.  This allows the server to select an
-+appropriate certificate, in the event that one server handles multiple
-+hostnames with different certificates.
-+
- If your organization has several equivalent IMAP-servers, each of them
- should have a unique certificate which is signed with a common
- certificate.  If you want to use all of those servers, you don't need to
-@@ -102,9 +108,15 @@
- protocols to know.  The variables for the protocols are ssl_use_tlsv1, 
- ssl_use_sslv2, and ssl_use_sslv3.
+ 	r = mutt_thread_set_flag (extra->hdr, M_DELETE, 0,
++				  ch == OP_UNDELETE_THREAD ? 0 : 1)
++	  + mutt_thread_set_flag (extra->hdr, M_PURGED, 0,
+ 				  ch == OP_UNDELETE_THREAD ? 0 : 1);
  
-+To verify TLS SNI support by a server, you can use:
-+    openssl s_client -host <imap server> -port <port> \
-+        -tls1 -servername <imap server>
-+
-+
- -- 
- Tommi Komulainen
- Tommi.Komulainen at iki.fi
+-	if (r != -1)
++	if (r > -1)
+ 	{
+ 	  if (option (OPTRESOLVE))
+ 	  {
+@@ -2744,6 +2878,18 @@ search_next:
+ 	redraw = REDRAW_FULL;
+ 	break;
  
--Updated by Jeremy Katz
--katzj at linuxpower.org
-+Updated by:
-+  Jeremy Katz <katzj at linuxpower.org>
-+  Phil Pennock <mutt-dev at spodhuis.org>
-diff -urN mutt-1.6.1/README.status-color mutt-1.6.1-neomutt/README.status-color
---- mutt-1.6.1/README.status-color	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/README.status-color	2016-06-12 18:43:00.671451785 +0100
-@@ -0,0 +1,67 @@
-+Status Color Patch
-+==================
-+
-+    Custom rules for theming the status bar
-+
-+Patch
-+-----
-+
-+    To check if Mutt supports "Status Color", look for "patch-status-color" in
-+    the mutt version.
-+
-+    Dependencies
-+    * mutt-1.6.1
-+
-+Introduction
-+------------
-+
-+    The "status-color" patch allows you to theme different parts of the status
-+    bar (also when it's used by the index).
-+
-+    Unlike normal color commands, 'color status' can now take up to 2 extra
-+    parameters (regex, num).
-+
-+Commands
-+--------
-+
-+        color status foreground background [ regex [ num ]]
-+
-+    With zero parameters, Mutt will set the default color for the entire status
-+    bar.
-+
-+    With one parameter, Mutt will only color the parts matching the regex.
-+
-+    With two parameters, Mutt will only color the num'th sub-match of the regex.
-+
-+Colors
-+------
-+
-+    Status Colors
-+
-+    | Name   | Default Color | Description |
-+    |--------|---------------|-------------|
-+    | status | 'reverse'     | Status bar  |
-+
-+See Also
-+--------
-+
-+    * NeoMutt project
-+    * Compile-Time Features
-+    * Regular Expressions
-+    * Patterns
-+    * index-color patch
-+    * Color command
-+
-+Known Bugs
-+----------
-+
-+    None
-+
-+Credits
-+-------
-+
-+    * David Sterba <dsterba at suse.cz>
-+    * Thomas Glanzmann <thomas at glanzmann.de>
-+    * Kirill A. Shutemov <kirill at shutemov.name>
-+    * Richard Russon <rich at flatcap.org>
-+
-diff -urN mutt-1.6.1/README.tls-sni mutt-1.6.1-neomutt/README.tls-sni
---- mutt-1.6.1/README.tls-sni	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/README.tls-sni	2016-06-12 18:43:00.672451801 +0100
-@@ -0,0 +1,51 @@
-+TLS-SNI Patch
-+=============
-+
-+    Negotiate with a server for a TSL/SSL certificate
-+
-+Patch
-+-----
-+
-+    To check if Mutt supports "TLS-SNI", look for "patch-tls-sni" in the mutt
-+    version.
-+
-+    Dependencies
-+    * mutt-1.6.1
-+    * OpenSSL
-+
-+Introduction
-+------------
-+
-+    The "TLS-SNI" patch adds support for TLS virtual hosting. If your mail
-+    server doesn't support this everything will still work normally.
-+
-+    TLS supports sending the expected server hostname during the handshake, via
-+    the SNI extension. This can be used to select a server certificate to issue
-+    to the client, permitting virtual-hosting without requiring multiple IP
-+    addresses.
-+
-+    This has been tested against Exim 4.80, which optionally logs SNI and can
-+    perform vhosting.
-+
-+    To verify TLS SNI support by a server, you can use:
-+
-+        openssl s_client -host <imap server> -port <port> -tls1 -servername
-+    <imap server>
-+
-+See Also
-+--------
++     case OP_EDIT_LABEL:
++        CHECK_MODE(IsHeader (extra));
++        rc = mutt_label_message(extra->hdr);
++        if (rc > 0) {
++          Context->changed = 1;
++          redraw = REDRAW_FULL;
++          mutt_message ("%d label%s changed.", rc, rc == 1 ? "" : "s");
++        }
++        else {
++          mutt_message _("No labels changed.");
++        }
++        break;
+ 
+       case OP_MAIL_KEY:
+         if (!(WithCrypto & APPLICATION_PGP))
+@@ -2777,6 +2923,22 @@ search_next:
+ 	mutt_what_key ();
+ 	break;
+ 
++#ifdef USE_SIDEBAR
++      case OP_SIDEBAR_NEXT:
++      case OP_SIDEBAR_NEXT_NEW:
++      case OP_SIDEBAR_PAGE_DOWN:
++      case OP_SIDEBAR_PAGE_UP:
++      case OP_SIDEBAR_PREV:
++      case OP_SIDEBAR_PREV_NEW:
++	mutt_sb_change_mailbox (ch);
++	break;
 +
-+    * NeoMutt project
++      case OP_SIDEBAR_TOGGLE_VISIBLE:
++	toggle_option (OPTSIDEBAR);
++	redraw = REDRAW_FULL;
++	break;
++#endif
 +
-+Known Bugs
-+----------
+       default:
+ 	ch = -1;
+ 	break;
+diff --git a/parse.c b/parse.c
+index 6a802ba..afee665 100644
+--- a/parse.c
++++ b/parse.c
+@@ -94,7 +94,7 @@ char *mutt_read_rfc822_line (FILE *f, char *line, size_t *linelen)
+   /* not reached */
+ }
+ 
+-static LIST *mutt_parse_references (char *s, int in_reply_to)
++LIST *mutt_parse_references (char *s, int in_reply_to)
+ {
+   LIST *t, *lst = NULL;
+   char *m;
+@@ -981,6 +981,7 @@ int mutt_parse_rfc822_line (ENVELOPE *e, HEADER *hdr, char *line, char *p, short
+ {
+   int matched = 0;
+   LIST *last = NULL;
++  int kwtype = 0;
+   
+   if (lastp)
+     last = *lastp;
+@@ -1077,6 +1078,17 @@ int mutt_parse_rfc822_line (ENVELOPE *e, HEADER *hdr, char *line, char *p, short
+       e->from = rfc822_parse_adrlist (e->from, p);
+       matched = 1;
+     }
++#ifdef USE_NNTP
++    else if (!mutt_strcasecmp (line+1, "ollowup-to"))
++    {
++      if (!e->followup_to)
++      {
++	mutt_remove_trailing_ws (p);
++	e->followup_to = safe_strdup (mutt_skip_whitespace (p));
++      }
++      matched = 1;
++    }
++#endif
+     break;
+     
+     case 'i':
+@@ -1087,7 +1099,14 @@ int mutt_parse_rfc822_line (ENVELOPE *e, HEADER *hdr, char *line, char *p, short
+       matched = 1;
+     }
+     break;
+-    
 +
-+    None
++    case 'k':
++    if (!ascii_strcasecmp (line+1, "eywords"))
++    {
++      kwtype = M_KEYWORDS;
++    }
++    break;
 +
-+Credits
-+-------
+     case 'l':
+     if (!ascii_strcasecmp (line + 1, "ines"))
+     {
+@@ -1159,6 +1178,27 @@ int mutt_parse_rfc822_line (ENVELOPE *e, HEADER *hdr, char *line, char *p, short
+     }
+     break;
+     
++#ifdef USE_NNTP
++    case 'n':
++    if (!mutt_strcasecmp (line + 1, "ewsgroups"))
++    {
++      FREE (&e->newsgroups);
++      mutt_remove_trailing_ws (p);
++      e->newsgroups = safe_strdup (mutt_skip_whitespace (p));
++      matched = 1;
++    }
++    break;
++#endif
 +
-+    * Jeremy Katz <katzj at linuxpower.org>
-+    * Phil Pennock <mutt-dev at spodhuis.demon.nl>
-+    * Richard Russon <rich at flatcap.org>
++    case 'o':
++    /* field `Organization:' saves only for pager! */
++    if (!mutt_strcasecmp (line + 1, "rganization"))
++    {
++      if (!e->organization && mutt_strcasecmp (p, "unknown"))
++	e->organization = safe_strdup (p);
++    }
++    break;
 +
-diff -urN mutt-1.6.1/README.trash mutt-1.6.1-neomutt/README.trash
---- mutt-1.6.1/README.trash	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/README.trash	2016-06-12 18:43:00.672451801 +0100
-@@ -0,0 +1,74 @@
-+Trash Folder Patch
-+==================
+     case 'r':
+     if (!ascii_strcasecmp (line + 1, "eferences"))
+     {
+@@ -1267,15 +1307,35 @@ int mutt_parse_rfc822_line (ENVELOPE *e, HEADER *hdr, char *line, char *p, short
+     }
+     else if (ascii_strcasecmp (line+1, "-label") == 0)
+     {
+-      FREE(&e->x_label);
+-      e->x_label = safe_strdup(p);
++      kwtype = M_X_LABEL;
++    }
++    else if (!ascii_strcasecmp (line+1, "-keywords"))
++    {
++      kwtype = M_X_KEYWORDS;
++    }
++    else if (!ascii_strcasecmp (line+1, "-mozilla-keys"))
++    {
++      kwtype = M_X_MOZILLA_KEYS;
++    }
++#ifdef USE_NNTP
++    else if (!mutt_strcasecmp (line + 1, "-comment-to"))
++    {
++      if (!e->x_comment_to)
++	e->x_comment_to = safe_strdup (p);
+       matched = 1;
+     }
+-    
++    else if (!mutt_strcasecmp (line + 1, "ref"))
++    {
++      if (!e->xref)
++	e->xref = safe_strdup (p);
++      matched = 1;
++    }
++#endif
 +
-+    Automatically move "deleted" emails to a trash bin
+     default:
+     break;
+   }
+-  
 +
-+Patch
-+-----
+   /* Keep track of the user-defined headers */
+   if (!matched && user_hdrs)
+   {
+@@ -1298,12 +1358,59 @@ int mutt_parse_rfc822_line (ENVELOPE *e, HEADER *hdr, char *line, char *p, short
+       rfc2047_decode (&last->data);
+   }
+ 
++  if (kwtype)
++  {
++    char *last, *label;
++    char *text = strdup(p);
++    char *sep;
 +
-+    To check if Mutt supports "Trash Folder", look for "patch-trash" in the
-+    mutt version.
++    if (kwtype == M_KEYWORDS)
++      sep = ",";
++    else if (kwtype == M_X_LABEL)
++      sep = XlabelDelim;
++    else
++      sep = " ";
 +
-+    If IMAP is enabled, this patch will use it
++    rfc2047_decode(&text);
++    if (sep == NULL || *sep == '\0')
++    {
++      SKIPWS(text);
++      if (!mutt_find_list(e->labels, text))
++      {
++        if (e->labels)
++          mutt_add_list(e->labels, text);
++        else
++        {
++          e->labels = mutt_new_list();
++          e->labels->data = safe_strdup(text);
++        }
++      }
++    }
++    else for (label = strtok_r(text, sep, &last); label;
++              label = strtok_r(NULL, sep, &last))
++    {
++      SKIPWS(label);
++      if (mutt_find_list(e->labels, label))
++        continue;
++      if (e->labels)
++        mutt_add_list(e->labels, label);
++      else
++      {
++        e->labels = mutt_new_list();
++        e->labels->data = safe_strdup(label);
++      }
++    }
++    e->kwtypes |= kwtype;
++    kwtype = 0;
++    matched = 1;
++  }
 +
-+    Dependencies
-+    * mutt-1.6.1
-+    * IMAP support
+   done:
+   
+   *lastp = last;
+   return matched;
+ }
+-  
 +
-+Introduction
-+------------
+   
+ /* mutt_read_rfc822_header() -- parses a RFC822 header
+  *
+@@ -1441,7 +1548,6 @@ ENVELOPE *mutt_read_rfc822_header (FILE *f, HEADER *hdr, short user_hdrs,
+     rfc2047_decode_adrlist (e->mail_followup_to);
+     rfc2047_decode_adrlist (e->return_path);
+     rfc2047_decode_adrlist (e->sender);
+-    rfc2047_decode (&e->x_label);
+ 
+     if (e->subject)
+     {
+diff --git a/patchlist.sh b/patchlist.sh
+index 2914b87..8565e09 100755
+--- a/patchlist.sh
++++ b/patchlist.sh
+@@ -1,21 +1,5 @@
+ #!/bin/sh --
+ 
+-list_patches_PATCHES () {
+-	cat -
+-}
+-
+-list_patches_mq () {
+-	hg qapplied | sed -e 's/^/mq-/'
+-}
+-
+-list_patches () {
+-	if [ -f .hg/patches/series ]; then
+-		list_patches_mq
+-	else
+-		list_patches_PATCHES
+-	fi
+-}
+-
+ cat <<EOF
+ /* this is an autogenerated file.  edit patchlist.sh instead. */
+ #include "config.h"
+@@ -29,7 +13,7 @@ void mutt_print_patchlist (void)
+ {
+ EOF
+ 
+-list_patches | while read patch ; do
++cat - | while read patch ; do
+ 	echo "  puts (\"${patch}\");"
+ done
+ 
+diff --git a/pattern.c b/pattern.c
+index d954cdc..8dc7fb4 100644
+--- a/pattern.c
++++ b/pattern.c
+@@ -42,6 +42,10 @@
+ #include "imap/imap.h"
+ #endif
+ 
++#ifdef USE_NOTMUCH
++#include "mutt_notmuch.h"
++#endif
 +
-+    In Mutt, when you "delete" an email it is first marked deleted. The email
-+    isn't really gone until <sync-mailbox> is called. This happens when the
-+    user leaves the folder, or the function is called manually.
+ static int eat_regexp (pattern_t *pat, BUFFER *, BUFFER *);
+ static int eat_date (pattern_t *pat, BUFFER *, BUFFER *);
+ static int eat_range (pattern_t *pat, BUFFER *, BUFFER *);
+@@ -92,9 +96,15 @@ Flags[] =
+   { 'U', M_UNREAD,		0,		NULL },
+   { 'v', M_COLLAPSED,		0,		NULL },
+   { 'V', M_CRYPT_VERIFIED,	0,		NULL },
++#ifdef USE_NNTP
++  { 'w', M_NEWSGROUPS,		0,		eat_regexp },
++#endif
+   { 'x', M_REFERENCE,		0,		eat_regexp },
+   { 'X', M_MIMEATTACH,		0,		eat_range },
+   { 'y', M_XLABEL,		0,		eat_regexp },
++#ifdef USE_NOTMUCH
++  { 'Y', M_NOTMUCH_LABEL,	0,		eat_regexp },
++#endif
+   { 'z', M_SIZE,		0,		eat_range },
+   { '=', M_DUPLICATED,		0,		NULL },
+   { '$', M_UNREFERENCED,	0,		NULL },
+@@ -144,16 +154,21 @@ int mutt_which_case (const char *s)
+ static int
+ msg_search (CONTEXT *ctx, pattern_t* pat, int msgno)
+ {
+-  char tempfile[_POSIX_PATH_MAX];
+   MESSAGE *msg = NULL;
+   STATE s;
+-  struct stat st;
+   FILE *fp = NULL;
+   long lng = 0;
+   int match = 0;
+   HEADER *h = ctx->hdrs[msgno];
+   char *buf;
+   size_t blen;
++#ifdef HAVE_FMEMOPEN
++  char *temp;
++  size_t tempsize;
++#else
++  char tempfile[_POSIX_PATH_MAX];
++  struct stat st;
++#endif
+ 
+   if ((msg = mx_open_message (ctx, msgno)) != NULL)
+   {
+@@ -163,12 +178,20 @@ msg_search (CONTEXT *ctx, pattern_t* pat, int msgno)
+       memset (&s, 0, sizeof (s));
+       s.fpin = msg->fp;
+       s.flags = M_CHARCONV;
++#ifdef HAVE_FMEMOPEN
++      s.fpout = open_memstream (&temp, &tempsize);
++      if (!s.fpout) {
++	mutt_perror ("Error opening memstream");
++	return 0;
++      }
++#else
+       mutt_mktemp (tempfile, sizeof (tempfile));
+       if ((s.fpout = safe_fopen (tempfile, "w+")) == NULL)
+       {
+ 	mutt_perror (tempfile);
+ 	return (0);
+       }
++#endif
+ 
+       if (pat->op != M_BODY)
+ 	mutt_copy_header (msg->fp, h, s.fpout, CH_FROM | CH_DECODE, NULL);
+@@ -184,7 +207,11 @@ msg_search (CONTEXT *ctx, pattern_t* pat, int msgno)
+ 	  if (s.fpout)
+ 	  {
+ 	    safe_fclose (&s.fpout);
++#ifdef HAVE_FMEMOPEN
++            FREE(&temp);
++#else
+ 	    unlink (tempfile);
++#endif
+ 	  }
+ 	  return (0);
+ 	}
+@@ -193,11 +220,30 @@ msg_search (CONTEXT *ctx, pattern_t* pat, int msgno)
+ 	mutt_body_handler (h->content, &s);
+       }
+ 
++#ifdef HAVE_FMEMOPEN
++      fclose (s.fpout);
++      lng = tempsize;
 +
-+    After '<sync-mailbox>' has been called the email is gone forever.
++      if (tempsize) {
++        fp = fmemopen (temp, tempsize, "r");
++        if (!fp) {
++          mutt_perror ("Error re-opening memstream");
++          return 0;
++        }
++      } else { /* fmemopen cannot handle empty buffers */
++        fp = safe_fopen ("/dev/null", "r");
++        if (!fp) {
++          mutt_perror ("Error opening /dev/null");
++          return 0;
++        }
++      }
++#else
+       fp = s.fpout;
+       fflush (fp);
+       fseek (fp, 0, 0);
+       fstat (fileno (fp), &st);
+       lng = (long) st.st_size;
++#endif
+     }
+     else
+     {
+@@ -244,7 +290,12 @@ msg_search (CONTEXT *ctx, pattern_t* pat, int msgno)
+     if (option (OPTTHOROUGHSRC))
+     {
+       safe_fclose (&fp);
++#ifdef HAVE_FMEMOPEN
++      if (tempsize)
++        FREE(&temp);
++#else
+       unlink (tempfile);
++#endif
+     }
+   }
+ 
+@@ -1209,7 +1260,26 @@ mutt_pattern_exec (struct pattern_t *pat, pattern_exec_flag flags, CONTEXT *ctx,
+        break;
+      return (pat->not ^ ((h->security & APPLICATION_PGP) && (h->security & PGPKEY)));
+     case M_XLABEL:
+-      return (pat->not ^ (h->env->x_label && patmatch (pat, h->env->x_label) == 0));
++      {
++        LIST *label;
++        int result = 0;
++        for (label = h->env->labels; label; label = label->next)
++        {
++          if (label->data == NULL)
++            continue;
++          result = patmatch (pat, label->data) == 0;
++          if (result)
++            break;
++        }
++        return pat->not ^ result;
++      }
++#ifdef USE_NOTMUCH
++    case M_NOTMUCH_LABEL:
++      {
++      char *tags = nm_header_get_tags(h);
++      return (pat->not ^ (tags && patmatch (pat, tags) == 0));
++      }
++#endif
+     case M_HORMEL:
+       return (pat->not ^ (h->env->spam && h->env->spam->data && patmatch (pat, h->env->spam->data) == 0));
+     case M_DUPLICATED:
+@@ -1222,6 +1292,10 @@ mutt_pattern_exec (struct pattern_t *pat, pattern_exec_flag flags, CONTEXT *ctx,
+       }
+     case M_UNREFERENCED:
+       return (pat->not ^ (h->thread && !h->thread->child));
++#ifdef USE_NNTP
++    case M_NEWSGROUPS:
++      return (pat->not ^ (h->env->newsgroups && patmatch (pat, h->env->newsgroups) == 0));
++#endif
+   }
+   mutt_error (_("error: unknown op %d (report this error)."), pat->op);
+   return (-1);
+@@ -1294,6 +1368,74 @@ void mutt_check_simple (char *s, size_t len, const char *simple)
+   }
+ }
+ 
++/**
++ * top_of_thread - Find the first email in the current thread
++ * @h: Header of current email
++ *
++ * Returns:
++ *	THREAD*: success, email found
++ *	NULL:    on error
++ */
++static THREAD *
++top_of_thread (HEADER *h)
++{
++	THREAD *t;
 +
-+    The $trash variable defines a folder in which to keep old emails. As
-+    before, first you mark emails for deletion. When <sync-mailbox> is called
-+    the emails are moved to the trash folder.
++	if (!h)
++		return NULL;
 +
-+    The '$trash' path can be either a full directory, or be relative to the
-+    $folder variable, like the 'mailboxes' command.
++	t = h->thread;
 +
-+    > Note
-+    >
-+    > Emails deleted from the trash folder are gone forever.
++	while (t && t->parent)
++		t = t->parent;
 +
-+Variables
-+---------
++	return t;
++}
 +
-+    Trash Variables
++/**
++ * mutt_limit_current_thread - Limit the email view to the current thread
++ * @h: Header of current email
++ *
++ * Returns:
++ *	1: Success
++ *	0: Failure
++ */
++int
++mutt_limit_current_thread (HEADER *h)
++{
++	int i;
++	THREAD *me;
 +
-+    | Name  | Type   | Default |
-+    |-------|--------|---------|
-+    | trash | string | (none)  |
++	if (!h)
++		return 0;
 +
-+Functions
-+---------
++	me = top_of_thread (h);
++	if (!me)
++		return 0;
 +
-+    Trash Functions
++	Context->vcount    = 0;
++	Context->vsize     = 0;
++	Context->collapsed = 0;
 +
-+    | Menus       | Default Key | Function          | Description                                                 |
-+    |-------------|-------------|-------------------|-------------------------------------------------------------|
-+    | index,pager | (none)      | '<purge-message>' | really delete the current entry, bypassing the trash folder |
++	for (i = 0; i < Context->msgcount; i++) {
++		Context->hdrs[i]->virtual    = -1;
++		Context->hdrs[i]->limited    = 0;
++		Context->hdrs[i]->collapsed  = 0;
++		Context->hdrs[i]->num_hidden = 0;
 +
-+See Also
-+--------
++		if (top_of_thread (Context->hdrs[i]) == me) {
++			BODY *body = Context->hdrs[i]->content;
 +
-+    * NeoMutt project
-+    * folder-hook
++			Context->hdrs[i]->virtual = Context->vcount;
++			Context->hdrs[i]->limited = 1;
++			Context->v2r[Context->vcount] = i;
++			Context->vcount++;
++			Context->vsize += (body->length + body->offset - body->hdr_offset);
++		}
++	}
++	return 1;
++}
 +
-+Known Bugs
-+----------
+ int mutt_pattern_func (int op, char *prompt)
+ {
+   pattern_t *pat;
+@@ -1303,6 +1445,7 @@ int mutt_pattern_func (int op, char *prompt)
+   progress_t progress;
+ 
+   strfcpy (buf, NONULL (Context->pattern), sizeof (buf));
++  if (prompt || op != M_LIMIT)
+   if (mutt_get_field (prompt, buf, sizeof (buf), M_PATTERN | M_CLEAR) != 0 || !buf[0])
+     return (-1);
+ 
+@@ -1367,8 +1510,9 @@ int mutt_pattern_func (int op, char *prompt)
+       {
+ 	switch (op)
+ 	{
+-	  case M_DELETE:
+ 	  case M_UNDELETE:
++	    mutt_set_flag (Context, Context->hdrs[Context->v2r[i]], M_PURGED, 0);
++	  case M_DELETE:
+ 	    mutt_set_flag (Context, Context->hdrs[Context->v2r[i]], M_DELETE, 
+ 			  (op == M_DELETE));
+ 	    break;
+diff --git a/pgpinvoke.c b/pgpinvoke.c
+index 7334192..a108b4e 100644
+--- a/pgpinvoke.c
++++ b/pgpinvoke.c
+@@ -59,6 +59,7 @@ struct pgp_command_context {
+ const char *_mutt_fmt_pgp_command (char *dest,
+ 				   size_t destlen,
+ 				   size_t col,
++                                   int cols,
+ 				   char op,
+ 				   const char *src,
+ 				   const char *prefix,
+@@ -140,16 +141,16 @@ const char *_mutt_fmt_pgp_command (char *dest,
+   }
+ 
+   if (optional)
+-    mutt_FormatString (dest, destlen, col, ifstring, _mutt_fmt_pgp_command, data, 0);
++    mutt_FormatString (dest, destlen, col, cols, ifstring, _mutt_fmt_pgp_command, data, 0);
+   else if (flags & M_FORMAT_OPTIONAL)
+-    mutt_FormatString (dest, destlen, col, elsestring, _mutt_fmt_pgp_command, data, 0);
++    mutt_FormatString (dest, destlen, col, cols, elsestring, _mutt_fmt_pgp_command, data, 0);
+ 
+   return (src);
+ }
+ 
+ void mutt_pgp_command (char *d, size_t dlen, struct pgp_command_context *cctx, const char *fmt)
+ {
+-  mutt_FormatString (d, dlen, 0, NONULL (fmt), _mutt_fmt_pgp_command, (unsigned long) cctx, 0);
++  mutt_FormatString (d, dlen, 0, COLS - SidebarWidth, NONULL (fmt), _mutt_fmt_pgp_command, (unsigned long) cctx, 0);
+   dprint (2, (debugfile, "mutt_pgp_command: %s\n", d));
+ }
+ 
+diff --git a/pgpkey.c b/pgpkey.c
+index 80bd7de..849fa49 100644
+--- a/pgpkey.c
++++ b/pgpkey.c
+@@ -122,6 +122,7 @@ typedef struct pgp_entry
+ static const char *pgp_entry_fmt (char *dest,
+ 				  size_t destlen,
+ 				  size_t col,
++                                  int cols,
+ 				  char op,
+ 				  const char *src,
+ 				  const char *prefix,
+@@ -278,9 +279,9 @@ static const char *pgp_entry_fmt (char *dest,
+   }
+ 
+   if (optional)
+-    mutt_FormatString (dest, destlen, col, ifstring, mutt_attach_fmt, data, 0);
++    mutt_FormatString (dest, destlen, col, cols, ifstring, mutt_attach_fmt, data, 0);
+   else if (flags & M_FORMAT_OPTIONAL)
+-    mutt_FormatString (dest, destlen, col, elsestring, mutt_attach_fmt, data, 0);
++    mutt_FormatString (dest, destlen, col, cols, elsestring, mutt_attach_fmt, data, 0);
+   return (src);
+ }
+ 
+@@ -292,7 +293,7 @@ static void pgp_entry (char *s, size_t l, MUTTMENU * menu, int num)
+   entry.uid = KeyTable[num];
+   entry.num = num + 1;
+ 
+-  mutt_FormatString (s, l, 0, NONULL (PgpEntryFormat), pgp_entry_fmt, 
++  mutt_FormatString (s, l, 0, COLS - SidebarWidth, NONULL (PgpEntryFormat), pgp_entry_fmt, 
+ 		     (unsigned long) &entry, M_FORMAT_ARROWCURSOR);
+ }
+ 
+diff --git a/po/POTFILES.in b/po/POTFILES.in
+index 2d01add..1e499ec 100644
+--- a/po/POTFILES.in
++++ b/po/POTFILES.in
+@@ -8,6 +8,7 @@ charset.c
+ color.c
+ commands.c
+ compose.c
++compress.c
+ crypt-gpgme.c
+ crypt.c
+ cryptglue.c
+@@ -46,6 +47,8 @@ mutt_ssl_gnutls.c
+ mutt_tunnel.c
+ muttlib.c
+ mx.c
++newsrc.c
++nntp.c
+ pager.c
+ parse.c
+ pattern.c
+diff --git a/pop.c b/pop.c
+index 11af0ab..4ef0e11 100644
+--- a/pop.c
++++ b/pop.c
+@@ -421,7 +421,9 @@ int pop_open_mailbox (CONTEXT *ctx)
+     return -1;
+ 
+   FREE (&ctx->path);
++  FREE (&ctx->realpath);
+   ctx->path = safe_strdup (buf);
++  ctx->realpath = safe_strdup (ctx->path);
+ 
+   pop_data = safe_calloc (1, sizeof (POP_DATA));
+   pop_data->conn = conn;
+diff --git a/postpone.c b/postpone.c
+index cec150f..7c62c96 100644
+--- a/postpone.c
++++ b/postpone.c
+@@ -125,15 +125,26 @@ int mutt_num_postponed (int force)
+ 
+   if (LastModify < st.st_mtime)
+   {
++#ifdef USE_NNTP
++    int optnews = option (OPTNEWS);
++#endif
+     LastModify = st.st_mtime;
+ 
+     if (access (Postponed, R_OK | F_OK) != 0)
+       return (PostCount = 0);
++#ifdef USE_NNTP
++    if (optnews)
++	unset_option (OPTNEWS);
++#endif
+     if (mx_open_mailbox (Postponed, M_NOSORT | M_QUIET, &ctx) == NULL)
+       PostCount = 0;
+     else
+       PostCount = ctx.msgcount;
+     mx_fastclose_mailbox (&ctx);
++#ifdef USE_NNTP
++    if (optnews)
++	set_option (OPTNEWS);
++#endif
+   }
+ 
+   return (PostCount);
+@@ -277,6 +288,9 @@ int mutt_get_postponed (CONTEXT *ctx, HEADER *hdr, HEADER **cur, char *fcc, size
+   /* finished with this message, so delete it. */
+   mutt_set_flag (PostContext, h, M_DELETE, 1);
+ 
++  /* and consider it saved, so that it won't be moved to the trash folder */
++  mutt_set_flag (PostContext, h, M_APPENDED, 1);
 +
-+    None
+   /* update the count for the status display */
+   PostCount = PostContext->msgcount - PostContext->deleted;
+ 
+diff --git a/protos.h b/protos.h
+index 8e5f7aa..7dcb689 100644
+--- a/protos.h
++++ b/protos.h
+@@ -1,5 +1,6 @@
+ /*
+  * Copyright (C) 1996-2000,2007,2010,2013 Michael R. Elkins <me at mutt.org>
++ * Copyright (C) 2013 Karel Zak <kzak at redhat.com>
+  * 
+  *     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
+@@ -71,14 +72,17 @@ int _mutt_traverse_thread (CONTEXT *ctx, HEADER *hdr, int flag);
+ #define mutt_new_envelope() safe_calloc (1, sizeof (ENVELOPE))
+ #define mutt_new_enter_state() safe_calloc (1, sizeof (ENTER_STATE))
+ 
+-typedef const char * format_t (char *, size_t, size_t, char, const char *, const char *, const char *, const char *, unsigned long, format_flag);
++typedef const char * format_t (char *, size_t, size_t, int, char, const char *, const char *, const char *, const char *, unsigned long, format_flag);
+ 
+-void mutt_FormatString (char *, size_t, size_t, const char *, format_t *, unsigned long, format_flag);
++void mutt_FormatString (char *, size_t, size_t, int, const char *, format_t *, unsigned long, format_flag);
+ void mutt_parse_content_type (char *, BODY *);
+ void mutt_generate_boundary (PARAMETER **);
+ void mutt_delete_parameter (const char *attribute, PARAMETER **p);
+ void mutt_set_parameter (const char *, const char *, PARAMETER **);
+ 
++#ifdef USE_NOTMUCH
++int mutt_parse_virtual_mailboxes (BUFFER *path, BUFFER *s, unsigned long data, BUFFER *err);
++#endif
+ 
+ FILE *mutt_open_read (const char *, pid_t *);
+ 
+@@ -111,6 +115,7 @@ HASH *mutt_make_id_hash (CONTEXT *);
+ HASH *mutt_make_subj_hash (CONTEXT *);
+ 
+ LIST *mutt_make_references(ENVELOPE *e);
++LIST *mutt_parse_references (char *, int);
+ 
+ char *mutt_read_rfc822_line (FILE *, char *, size_t *);
+ ENVELOPE *mutt_read_rfc822_header (FILE *, HEADER *, short, short);
+@@ -127,6 +132,7 @@ const char *mutt_attach_fmt (
+ 	char *dest,
+ 	size_t destlen,
+ 	size_t col,
++        int cols,
+ 	char op,
+ 	const char *src,
+ 	const char *prefix,
+@@ -180,10 +186,17 @@ void mutt_decode_base64 (STATE *s, long len, int istext, iconv_t cd);
+ void mutt_default_save (char *, size_t, HEADER *);
+ void mutt_display_address (ENVELOPE *);
+ void mutt_display_sanitize (char *);
++void mutt_draw_statusline (int cols, const char *buf, int buflen);
+ void mutt_edit_content_type (HEADER *, BODY *, FILE *);
+ void mutt_edit_file (const char *, const char *);
+ void mutt_edit_headers (const char *, const char *, HEADER *, char *, size_t);
+ int mutt_filter_unprintable (char **);
++void mutt_label_ref_dec(ENVELOPE *);
++void mutt_label_ref_inc(ENVELOPE *);
++int mutt_label_message (HEADER *);
++void mutt_scan_labels (CONTEXT *);
++int mutt_label_complete (char *, size_t, int, int);
++char *mutt_labels(char *, int, ENVELOPE *, char *);
+ void mutt_curses_error (const char *, ...);
+ void mutt_curses_message (const char *, ...);
+ void mutt_encode_descriptions (BODY *, short);
+@@ -284,6 +297,10 @@ int mutt_check_overwrite (const char *, const char *, char *, size_t, int *, cha
+ int mutt_check_traditional_pgp (HEADER *, int *);
+ int mutt_command_complete (char *, size_t, int, int);
+ int mutt_var_value_complete (char *, size_t, int);
++#if USE_NOTMUCH
++int mutt_nm_query_complete (char *buffer, size_t len, int pos, int numtabs);
++int mutt_nm_tag_complete (char *buffer, size_t len, int pos, int numtabs);
++#endif
+ int mutt_complete (char *, size_t);
+ int mutt_compose_attachment (BODY *a);
+ int mutt_copy_body (FILE *, BODY **, BODY *);
+@@ -299,8 +316,10 @@ int mutt_chscmp (const char *s, const char *chs);
+ int mutt_parent_message (CONTEXT *, HEADER *);
+ int mutt_prepare_template(FILE*, CONTEXT *, HEADER *, HEADER *, short);
+ int mutt_resend_message (FILE *, CONTEXT *, HEADER *);
+-#define mutt_enter_fname(A,B,C,D,E) _mutt_enter_fname(A,B,C,D,E,0,NULL,NULL)
+-int _mutt_enter_fname (const char *, char *, size_t, int *, int, int, char ***, int *);
++#define mutt_enter_fname(A,B,C,D,E) _mutt_enter_fname(A,B,C,D,E,0,NULL,NULL,0)
++#define mutt_enter_vfolder(A,B,C,D,E) _mutt_enter_fname(A,B,C,D,E,0,NULL,NULL,M_SEL_VFOLDER)
 +
-+Credits
-+-------
++int _mutt_enter_fname (const char *, char *, size_t, int *, int, int, char ***, int *, int);
+ int  mutt_enter_string (char *buf, size_t buflen, int y, int x, int flags);
+ int _mutt_enter_string (char *, size_t, int, int, int, int, char ***, int *, ENTER_STATE *);
+ #define mutt_get_field(A,B,C,D) _mutt_get_field(A,B,C,D,0,NULL,NULL)
+@@ -365,7 +384,7 @@ int mutt_user_is_recipient (HEADER *);
+ void mutt_update_num_postponed (void);
+ int mutt_wait_filter (pid_t);
+ int mutt_which_case (const char *);
+-int mutt_write_fcc (const char *path, HEADER *hdr, const char *msgid, int, char *);
++int mutt_write_fcc (const char *path, HEADER *hdr, const char *msgid, int, char *, char **);
+ int mutt_write_mime_body (BODY *, FILE *);
+ int mutt_write_mime_header (BODY *, FILE *);
+ int mutt_write_one_header (FILE *fp, const char *tag, const char *value, const char *pfx, int wraplen, int flags);
+@@ -375,6 +394,11 @@ int mutt_yesorno (const char *, int);
+ void mutt_set_header_color(CONTEXT *, HEADER *);
+ void mutt_sleep (short);
+ int mutt_save_confirm (const char  *, struct stat *);
++void mutt_randbuf(void *out, size_t len);
++#define MUTT_RANDTAG_LEN (16)
++void mutt_rand_base32(void *out, size_t len);
++uint32_t mutt_rand32(void);
++uint64_t mutt_rand64(void);
+ 
+ int mh_valid_message (const char *);
+ 
+@@ -422,16 +446,6 @@ void mutt_pattern_free (pattern_t **pat);
+ #define LONGLONG long
+ #endif
+ 
+-#ifdef HAVE_SRAND48
+-#define LRAND lrand48
+-#define SRAND srand48
+-#define DRAND drand48
+-#else
+-#define LRAND rand
+-#define SRAND srand
+-#define DRAND (double)rand
+-#endif /* HAVE_SRAND48 */
+-
+ /* HP-UX, ConvexOS and UNIXware don't have this macro */
+ #ifndef S_ISLNK
+ #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK ? 1 : 0)
+@@ -565,3 +579,11 @@ char *strcasestr (const char *, const char *);
+ #ifndef HAVE_MKDTEMP
+ char *mkdtemp (char *tmpl);
+ #endif
 +
-+    * Cedric Duval <cedricduval at free.fr>
-+    * Benjamin Kuperman <kuperman at acm.org>
-+    * Paul Miller <paul at voltar.org>
-+    * Richard Russon <rich at flatcap.org>
++#ifndef HAVE_STRNLEN
++size_t strnlen(const char *s, size_t maxlen);
++#endif
 +
-diff -urN mutt-1.6.1/recvattach.c mutt-1.6.1-neomutt/recvattach.c
---- mutt-1.6.1/recvattach.c	2016-06-12 18:43:00.414447777 +0100
-+++ mutt-1.6.1-neomutt/recvattach.c	2016-06-12 18:43:00.745452939 +0100
-@@ -1120,6 +1120,15 @@
++#ifndef strndup
++char *strndup(const char *s, size_t n);
++#endif
+diff --git a/query.c b/query.c
+index 8bcffbd..605b823 100644
+--- a/query.c
++++ b/query.c
+@@ -24,6 +24,7 @@
+ #include "mutt_menu.h"
+ #include "mutt_idna.h"
+ #include "mapping.h"
++#include "mutt_curses.h"
+ 
+ #include <string.h>
+ #include <stdlib.h>
+@@ -183,7 +184,7 @@ static int query_search (MUTTMENU *m, regex_t *re, int n)
+   return REG_NOMATCH;
+ }
+ 
+-static const char * query_format_str (char *dest, size_t destlen, size_t col,
++static const char * query_format_str (char *dest, size_t destlen, size_t col, int cols,
+ 				      char op, const char *src,
+ 				      const char *fmt, const char *ifstring,
+ 				      const char *elsestring,
+@@ -230,9 +231,9 @@ static const char * query_format_str (char *dest, size_t destlen, size_t col,
+   }
+ 
+   if (optional)
+-    mutt_FormatString (dest, destlen, col, ifstring, query_format_str, data, 0);
++    mutt_FormatString (dest, destlen, col, cols, ifstring, query_format_str, data, 0);
+   else if (flags & M_FORMAT_OPTIONAL)
+-    mutt_FormatString (dest, destlen, col, elsestring, query_format_str, data, 0);
++    mutt_FormatString (dest, destlen, col, cols, elsestring, query_format_str, data, 0);
+ 
+   return src;
+ }
+@@ -242,7 +243,7 @@ static void query_entry (char *s, size_t slen, MUTTMENU *m, int num)
+   ENTRY *entry = &((ENTRY *) m->data)[num];
+ 
+   entry->data->num = num;
+-  mutt_FormatString (s, slen, 0, NONULL (QueryFormat), query_format_str,
++  mutt_FormatString (s, slen, 0, COLS - SidebarWidth, NONULL (QueryFormat), query_format_str,
+ 		     (unsigned long) entry, M_FORMAT_ARROWCURSOR);
+ }
+ 
+diff --git a/recvattach.c b/recvattach.c
+index 5424eda..9553a9a 100644
+--- a/recvattach.c
++++ b/recvattach.c
+@@ -173,6 +173,7 @@ ATTACHPTR **mutt_gen_attach_list (BODY *m,
+ const char *mutt_attach_fmt (char *dest,
+     size_t destlen,
+     size_t col,
++    int cols,
+     char op,
+     const char *src,
+     const char *prefix,
+@@ -365,15 +366,15 @@ const char *mutt_attach_fmt (char *dest,
+   }
+   
+   if (optional)
+-    mutt_FormatString (dest, destlen, col, ifstring, mutt_attach_fmt, data, 0);
++    mutt_FormatString (dest, destlen, col, cols, ifstring, mutt_attach_fmt, data, 0);
+   else if (flags & M_FORMAT_OPTIONAL)
+-    mutt_FormatString (dest, destlen, col, elsestring, mutt_attach_fmt, data, 0);
++    mutt_FormatString (dest, destlen, col, cols, elsestring, mutt_attach_fmt, data, 0);
+   return (src);
+ }
+ 
+ static void attach_entry (char *b, size_t blen, MUTTMENU *menu, int num)
+ {
+-  mutt_FormatString (b, blen, 0, NONULL (AttachFormat), mutt_attach_fmt, (unsigned long) (((ATTACHPTR **)menu->data)[num]), M_FORMAT_ARROWCURSOR);
++  mutt_FormatString (b, blen, 0, COLS - SidebarWidth, NONULL (AttachFormat), mutt_attach_fmt, (unsigned long) (((ATTACHPTR **)menu->data)[num]), M_FORMAT_ARROWCURSOR);
+ }
+ 
+ int mutt_tag_attach (MUTTMENU *menu, int n, int m)
+@@ -1120,6 +1121,15 @@ void mutt_view_attachments (HEADER *hdr)
  	}
  #endif
  
@@ -27432,7 +29631,7 @@ diff -urN mutt-1.6.1/recvattach.c mutt-1.6.1-neomutt/recvattach.c
          if (WithCrypto && (hdr->security & ENCRYPT))
          {
            mutt_message _(
-@@ -1214,10 +1223,33 @@
+@@ -1214,10 +1224,33 @@ void mutt_view_attachments (HEADER *hdr)
        case OP_FORWARD_MESSAGE:
          CHECK_ATTACH;
          mutt_attach_forward (fp, hdr, idx, idxlen,
@@ -27467,10 +29666,11 @@ diff -urN mutt-1.6.1/recvattach.c mutt-1.6.1-neomutt/recvattach.c
        case OP_REPLY:
        case OP_GROUP_REPLY:
        case OP_LIST_REPLY:
-diff -urN mutt-1.6.1/recvcmd.c mutt-1.6.1-neomutt/recvcmd.c
---- mutt-1.6.1/recvcmd.c	2016-06-12 18:43:00.414447777 +0100
-+++ mutt-1.6.1-neomutt/recvcmd.c	2016-06-12 18:43:00.746452955 +0100
-@@ -401,7 +401,7 @@
+diff --git a/recvcmd.c b/recvcmd.c
+index 13cb3a6..6e02437 100644
+--- a/recvcmd.c
++++ b/recvcmd.c
+@@ -401,7 +401,7 @@ static BODY ** copy_problematic_attachments (FILE *fp,
  static void attach_forward_bodies (FILE * fp, HEADER * hdr,
  				   ATTACHPTR ** idx, short idxlen,
  				   BODY * cur,
@@ -27479,7 +29679,7 @@ diff -urN mutt-1.6.1/recvcmd.c mutt-1.6.1-neomutt/recvcmd.c
  {
    short i;
    short mime_fwd_all = 0;
-@@ -547,7 +547,7 @@
+@@ -547,7 +547,7 @@ _("Can't decode all tagged attachments.  MIME-forward the others?"))) == -1)
    tmpfp = NULL;
  
    /* now that we have the template, send it. */
@@ -27488,7 +29688,7 @@ diff -urN mutt-1.6.1/recvcmd.c mutt-1.6.1-neomutt/recvcmd.c
    return;
    
    bail:
-@@ -574,7 +574,7 @@
+@@ -574,7 +574,7 @@ _("Can't decode all tagged attachments.  MIME-forward the others?"))) == -1)
   */
  
  static void attach_forward_msgs (FILE * fp, HEADER * hdr, 
@@ -27497,7 +29697,7 @@ diff -urN mutt-1.6.1/recvcmd.c mutt-1.6.1-neomutt/recvcmd.c
  {
    HEADER *curhdr = NULL;
    HEADER *tmphdr;
-@@ -679,23 +679,23 @@
+@@ -679,23 +679,23 @@ static void attach_forward_msgs (FILE * fp, HEADER * hdr,
    else
      mutt_free_header (&tmphdr);
  
@@ -27525,7 +29725,7 @@ diff -urN mutt-1.6.1/recvcmd.c mutt-1.6.1-neomutt/recvcmd.c
    }
  }
  
-@@ -753,28 +753,40 @@
+@@ -753,28 +753,40 @@ attach_reply_envelope_defaults (ENVELOPE *env, ATTACHPTR **idx, short idxlen,
      return -1;
    }
  
@@ -27580,7 +29780,7 @@ diff -urN mutt-1.6.1/recvcmd.c mutt-1.6.1-neomutt/recvcmd.c
    mutt_make_misc_reply_headers (env, Context, curhdr, curenv);
  
    if (parent)
-@@ -835,6 +847,13 @@
+@@ -835,6 +847,13 @@ void mutt_attach_reply (FILE * fp, HEADER * hdr,
    char prefix[SHORT_STRING];
    int rc;
    
@@ -27594,9 +29794,58 @@ diff -urN mutt-1.6.1/recvcmd.c mutt-1.6.1-neomutt/recvcmd.c
    if (check_all_msg (idx, idxlen, cur, 0) == -1)
    {
      nattach = count_tagged (idx, idxlen);
-diff -urN mutt-1.6.1/send.c mutt-1.6.1-neomutt/send.c
---- mutt-1.6.1/send.c	2016-06-12 18:43:00.414447777 +0100
-+++ mutt-1.6.1-neomutt/send.c	2016-06-12 18:43:00.749453002 +0100
+diff --git a/regex.c b/regex.c
+index f46c806..40979af 100644
+--- a/regex.c
++++ b/regex.c
+@@ -381,7 +381,9 @@ typedef char boolean;
+ #define false 0
+ #define true 1
+ 
+-static int re_match_2_internal ();
++static int re_match_2_internal (struct re_pattern_buffer *bufp,
++	const char *string1, int size1, const char *string2, int size2, int pos,
++	struct re_registers *regs, int stop);
+ 

+ /* These are the command codes that appear in compiled regular
+    expressions.  Some opcodes are followed by argument bytes.  A
+diff --git a/remailer.c b/remailer.c
+index fe9c7f2..3f665af 100644
+--- a/remailer.c
++++ b/remailer.c
+@@ -375,6 +375,7 @@ static const char *mix_format_caps (REMAILER *r)
+ static const char *mix_entry_fmt (char *dest,
+ 				  size_t destlen,
+ 				  size_t col,
++                                  int cols,
+ 				  char op,
+ 				  const char *src,
+ 				  const char *prefix,
+@@ -427,9 +428,9 @@ static const char *mix_entry_fmt (char *dest,
+   }
+ 
+   if (optional)
+-    mutt_FormatString (dest, destlen, col, ifstring, mutt_attach_fmt, data, 0);
++    mutt_FormatString (dest, destlen, col, cols, ifstring, mutt_attach_fmt, data, 0);
+   else if (flags & M_FORMAT_OPTIONAL)
+-    mutt_FormatString (dest, destlen, col, elsestring, mutt_attach_fmt, data, 0);
++    mutt_FormatString (dest, destlen, col, cols, elsestring, mutt_attach_fmt, data, 0);
+   return (src);
+ }
+ 
+@@ -438,7 +439,7 @@ static const char *mix_entry_fmt (char *dest,
+ static void mix_entry (char *b, size_t blen, MUTTMENU *menu, int num)
+ {
+   REMAILER **type2_list = (REMAILER **) menu->data;
+-  mutt_FormatString (b, blen, 0, NONULL (MixEntryFormat), mix_entry_fmt,
++  mutt_FormatString (b, blen, 0, COLS - SidebarWidth, NONULL (MixEntryFormat), mix_entry_fmt,
+ 		     (unsigned long) type2_list[num], M_FORMAT_ARROWCURSOR);
+ }
+ 
+diff --git a/send.c b/send.c
+index 8b71ea5..43c6476 100644
+--- a/send.c
++++ b/send.c
 @@ -44,10 +44,18 @@
  #include <sys/types.h>
  #include <utime.h>
@@ -27616,7 +29865,7 @@ diff -urN mutt-1.6.1/send.c mutt-1.6.1-neomutt/send.c
  
  static void append_signature (FILE *f)
  {
-@@ -213,17 +221,51 @@
+@@ -213,17 +221,51 @@ static int edit_address (ADDRESS **a, /* const */ char *field)
    return 0;
  }
  
@@ -27675,7 +29924,7 @@ diff -urN mutt-1.6.1/send.c mutt-1.6.1-neomutt/send.c
  
    if (en->subject)
    {
-@@ -258,6 +300,14 @@
+@@ -258,6 +300,14 @@ static int edit_envelope (ENVELOPE *en)
    return 0;
  }
  
@@ -27690,7 +29939,7 @@ diff -urN mutt-1.6.1/send.c mutt-1.6.1-neomutt/send.c
  static void process_user_recips (ENVELOPE *env)
  {
    LIST *uh = UserHeader;
-@@ -270,6 +320,14 @@
+@@ -270,6 +320,14 @@ static void process_user_recips (ENVELOPE *env)
        env->cc = rfc822_parse_adrlist (env->cc, uh->data + 3);
      else if (ascii_strncasecmp ("bcc:", uh->data, 4) == 0)
        env->bcc = rfc822_parse_adrlist (env->bcc, uh->data + 4);
@@ -27705,7 +29954,7 @@ diff -urN mutt-1.6.1/send.c mutt-1.6.1-neomutt/send.c
    }
  }
  
-@@ -308,6 +366,12 @@
+@@ -308,6 +366,12 @@ static void process_user_header (ENVELOPE *env)
      else if (ascii_strncasecmp ("to:", uh->data, 3) != 0 &&
  	     ascii_strncasecmp ("cc:", uh->data, 3) != 0 &&
  	     ascii_strncasecmp ("bcc:", uh->data, 4) != 0 &&
@@ -27718,7 +29967,7 @@ diff -urN mutt-1.6.1/send.c mutt-1.6.1-neomutt/send.c
  	     ascii_strncasecmp ("subject:", uh->data, 8) != 0 &&
  	     ascii_strncasecmp ("return-path:", uh->data, 12) != 0)
      {
-@@ -659,6 +723,10 @@
+@@ -659,6 +723,10 @@ void mutt_add_to_reference_headers (ENVELOPE *env, ENVELOPE *curenv, LIST ***pp,
    if (pp) *pp = p;
    if (qq) *qq = q;
    
@@ -27729,7 +29978,7 @@ diff -urN mutt-1.6.1/send.c mutt-1.6.1-neomutt/send.c
  }
  
  static void 
-@@ -721,6 +789,16 @@
+@@ -721,6 +789,16 @@ envelope_defaults (ENVELOPE *env, CONTEXT *ctx, HEADER *cur, int flags)
  
    if (flags & SENDREPLY)
    {
@@ -27746,7 +29995,7 @@ diff -urN mutt-1.6.1/send.c mutt-1.6.1-neomutt/send.c
      if (tag)
      {
        HEADER *h;
-@@ -867,7 +945,18 @@
+@@ -867,7 +945,18 @@ void mutt_set_followup_to (ENVELOPE *e)
     * it hasn't already been set
     */
  
@@ -27766,7 +30015,7 @@ diff -urN mutt-1.6.1/send.c mutt-1.6.1-neomutt/send.c
    {
      if (mutt_is_list_cc (0, e->to, e->cc))
      {
-@@ -1029,6 +1118,9 @@
+@@ -1029,6 +1118,9 @@ static int send_message (HEADER *msg)
  #endif
  
  #if USE_SMTP
@@ -27776,7 +30025,7 @@ diff -urN mutt-1.6.1/send.c mutt-1.6.1-neomutt/send.c
    if (SmtpUrl)
        return mutt_smtp_send (msg->env->from, msg->env->to, msg->env->cc,
                               msg->env->bcc, tempfile,
-@@ -1164,9 +1256,17 @@
+@@ -1164,9 +1256,17 @@ ci_send_message (int flags,		/* send mode */
    char *smime_default_key = NULL;
    char *tag = NULL, *err = NULL;
    char *ctype;
@@ -27794,7 +30043,7 @@ diff -urN mutt-1.6.1/send.c mutt-1.6.1-neomutt/send.c
    if (!flags && !msg && quadoption (OPT_RECALL) != M_NO &&
        mutt_num_postponed (1))
    {
-@@ -1202,6 +1302,22 @@
+@@ -1202,6 +1302,22 @@ ci_send_message (int flags,		/* send mode */
      {
        if ((flags = mutt_get_postponed (ctx, msg, &cur, fcc, sizeof (fcc))) < 0)
  	goto cleanup;
@@ -27817,7 +30066,7 @@ diff -urN mutt-1.6.1/send.c mutt-1.6.1-neomutt/send.c
      }
  
      if (flags & (SENDPOSTPONED|SENDRESEND))
-@@ -1303,11 +1419,16 @@
+@@ -1303,11 +1419,16 @@ ci_send_message (int flags,		/* send mode */
      if (flags & SENDREPLY)
        mutt_fix_reply_recipients (msg->env);
  
@@ -27835,7 +30084,7 @@ diff -urN mutt-1.6.1/send.c mutt-1.6.1-neomutt/send.c
  	goto cleanup;
      }
  
-@@ -1605,6 +1726,11 @@
+@@ -1606,6 +1727,11 @@ main_loop:
      if (i == -1)
      {
        /* abort */
@@ -27847,7 +30096,7 @@ diff -urN mutt-1.6.1/send.c mutt-1.6.1-neomutt/send.c
        mutt_message _("Mail not sent.");
        goto cleanup;
      }
-@@ -1646,7 +1772,9 @@
+@@ -1647,7 +1773,9 @@ main_loop:
        mutt_prepare_envelope (msg->env, 0);
        mutt_env_to_intl (msg->env, NULL, NULL);	/* Handle bad IDNAs the next time. */
  
@@ -27858,7 +30107,7 @@ diff -urN mutt-1.6.1/send.c mutt-1.6.1-neomutt/send.c
        {
  	msg->content = mutt_remove_multipart (msg->content);
  	decode_descriptions (msg->content);
-@@ -1660,6 +1788,9 @@
+@@ -1661,6 +1789,9 @@ main_loop:
      }
    }
  
@@ -27868,7 +30117,7 @@ diff -urN mutt-1.6.1/send.c mutt-1.6.1-neomutt/send.c
    if (!has_recips (msg->env->to) && !has_recips (msg->env->cc) &&
        !has_recips (msg->env->bcc))
    {
-@@ -1693,6 +1824,19 @@
+@@ -1694,6 +1825,19 @@ main_loop:
        mutt_error _("No subject specified.");
      goto main_loop;
    }
@@ -27888,7 +30137,7 @@ diff -urN mutt-1.6.1/send.c mutt-1.6.1-neomutt/send.c
  
    if (msg->content->next)
      msg->content = mutt_make_multipart (msg->content);
-@@ -1830,7 +1974,7 @@
+@@ -1831,7 +1975,7 @@ full_fcc:
         * message was first postponed.
         */
        msg->received = time (NULL);
@@ -27897,7 +30146,7 @@ diff -urN mutt-1.6.1/send.c mutt-1.6.1-neomutt/send.c
        {
  	/*
  	 * Error writing FCC, we should abort sending.
-@@ -1891,6 +2035,7 @@
+@@ -1892,6 +2036,7 @@ full_fcc:
        msg->content = mutt_remove_multipart (msg->content);
        decode_descriptions (msg->content);
        mutt_unprepare_envelope (msg->env);
@@ -27905,7 +30154,7 @@ diff -urN mutt-1.6.1/send.c mutt-1.6.1-neomutt/send.c
        goto main_loop;
      }
      else
-@@ -1899,8 +2044,18 @@
+@@ -1900,8 +2045,18 @@ full_fcc:
        goto cleanup;
      }
    }
@@ -27926,7 +30175,7 @@ diff -urN mutt-1.6.1/send.c mutt-1.6.1-neomutt/send.c
  
    if (WithCrypto && (msg->security & ENCRYPT))
      FREE (&pgpkeylist);
-@@ -1945,7 +2100,8 @@
+@@ -1946,7 +2101,8 @@ cleanup:
    safe_fclose (&tempfp);
    if (! (flags & SENDNOFREEHEADER))
      mutt_free_header (&msg);
@@ -27936,9 +30185,10 @@ diff -urN mutt-1.6.1/send.c mutt-1.6.1-neomutt/send.c
    return rv;
  }
  
-diff -urN mutt-1.6.1/sendlib.c mutt-1.6.1-neomutt/sendlib.c
---- mutt-1.6.1/sendlib.c	2016-06-12 18:43:00.415447793 +0100
-+++ mutt-1.6.1-neomutt/sendlib.c	2016-06-12 18:43:00.749453002 +0100
+diff --git a/sendlib.c b/sendlib.c
+index e6b6a79..449bf0b 100644
+--- a/sendlib.c
++++ b/sendlib.c
 @@ -46,6 +46,10 @@
  #include <sys/wait.h>
  #include <fcntl.h>
@@ -27950,7 +30200,7 @@ diff -urN mutt-1.6.1/sendlib.c mutt-1.6.1-neomutt/sendlib.c
  #ifdef HAVE_SYSEXITS_H
  #include <sysexits.h>
  #else /* Make sure EX_OK is defined <philiph at pobox.com> */
-@@ -73,8 +77,6 @@
+@@ -73,8 +77,6 @@ const char B64Chars[64] = {
    '8', '9', '+', '/'
  };
  
@@ -27959,7 +30209,7 @@ diff -urN mutt-1.6.1/sendlib.c mutt-1.6.1-neomutt/sendlib.c
  static void transform_to_7bit (BODY *a, FILE *fpin);
  
  static void encode_quoted (FGETCONV * fc, FILE *fout, int istext)
-@@ -480,18 +482,12 @@
+@@ -480,18 +482,12 @@ int mutt_write_mime_body (BODY *a, FILE *f)
  
  #undef write_as_text_part
  
@@ -27981,7 +30231,7 @@ diff -urN mutt-1.6.1/sendlib.c mutt-1.6.1-neomutt/sendlib.c
    mutt_set_parameter ("boundary", rs, parm);
  }
  
-@@ -1543,6 +1539,14 @@
+@@ -1543,6 +1539,14 @@ void mutt_write_references (LIST *r, FILE *f, int trim)
  {
    LIST **ref = NULL;
    int refcnt = 0, refmax = 0;
@@ -27996,7 +30246,7 @@ diff -urN mutt-1.6.1/sendlib.c mutt-1.6.1-neomutt/sendlib.c
  
    for ( ; (trim == 0 || refcnt < trim) && r ; r = r->next)
    {
-@@ -1553,9 +1557,11 @@
+@@ -1553,9 +1557,11 @@ void mutt_write_references (LIST *r, FILE *f, int trim)
  
    while (refcnt-- > 0)
    {
@@ -28010,7 +30260,7 @@ diff -urN mutt-1.6.1/sendlib.c mutt-1.6.1-neomutt/sendlib.c
        fputc ('\n', f);
    }
  
-@@ -1969,6 +1975,9 @@
+@@ -1969,6 +1975,9 @@ int mutt_write_rfc822_header (FILE *fp, ENVELOPE *env, BODY *attach,
      mutt_write_address_list (env->to, fp, 4, 0);
    }
    else if (mode > 0)
@@ -28020,7 +30270,7 @@ diff -urN mutt-1.6.1/sendlib.c mutt-1.6.1-neomutt/sendlib.c
      fputs ("To: \n", fp);
  
    if (env->cc)
-@@ -1977,6 +1986,9 @@
+@@ -1977,6 +1986,9 @@ int mutt_write_rfc822_header (FILE *fp, ENVELOPE *env, BODY *attach,
      mutt_write_address_list (env->cc, fp, 4, 0);
    }
    else if (mode > 0)
@@ -28030,7 +30280,7 @@ diff -urN mutt-1.6.1/sendlib.c mutt-1.6.1-neomutt/sendlib.c
      fputs ("Cc: \n", fp);
  
    if (env->bcc)
-@@ -1988,8 +2000,28 @@
+@@ -1988,8 +2000,28 @@ int mutt_write_rfc822_header (FILE *fp, ENVELOPE *env, BODY *attach,
      }
    }
    else if (mode > 0)
@@ -28059,7 +30309,7 @@ diff -urN mutt-1.6.1/sendlib.c mutt-1.6.1-neomutt/sendlib.c
    if (env->subject)
      mutt_write_one_header (fp, "Subject", env->subject, NULL, 0, 0);
    else if (mode == 1)
-@@ -2008,6 +2040,9 @@
+@@ -2008,6 +2040,9 @@ int mutt_write_rfc822_header (FILE *fp, ENVELOPE *env, BODY *attach,
      fputs ("Reply-To: \n", fp);
  
    if (env->mail_followup_to)
@@ -28069,7 +30319,7 @@ diff -urN mutt-1.6.1/sendlib.c mutt-1.6.1-neomutt/sendlib.c
    {
      fputs ("Mail-Followup-To: ", fp);
      mutt_write_address_list (env->mail_followup_to, fp, 18, 0);
-@@ -2133,16 +2168,18 @@
+@@ -2133,16 +2168,18 @@ char *mutt_gen_msgid (void)
    time_t now;
    struct tm *tm;
    const char *fqdn;
@@ -28091,7 +30341,7 @@ diff -urN mutt-1.6.1/sendlib.c mutt-1.6.1-neomutt/sendlib.c
    return (safe_strdup (buf));
  }
  
-@@ -2351,6 +2388,23 @@
+@@ -2351,6 +2388,23 @@ mutt_invoke_sendmail (ADDRESS *from,	/* the sender */
    size_t argslen = 0, argsmax = 0;
    int i;
  
@@ -28100,7 +30350,7 @@ diff -urN mutt-1.6.1/sendlib.c mutt-1.6.1-neomutt/sendlib.c
 +  {
 +    char cmd[LONG_STRING];
 +
-+    mutt_FormatString (cmd, sizeof (cmd), 0, NONULL (Inews), nntp_format_str, 0, 0);
++    mutt_FormatString (cmd, sizeof (cmd), 0, COLS - SidebarWidth, NONULL (Inews), nntp_format_str, 0, 0);
 +    if (!*cmd)
 +    {
 +      i = nntp_post (msg);
@@ -28115,7 +30365,7 @@ diff -urN mutt-1.6.1/sendlib.c mutt-1.6.1-neomutt/sendlib.c
    /* ensure that $sendmail is set to avoid a crash. http://dev.mutt.org/trac/ticket/3548 */
    if (!s)
    {
-@@ -2381,6 +2435,10 @@
+@@ -2381,6 +2435,10 @@ mutt_invoke_sendmail (ADDRESS *from,	/* the sender */
      i++;
    }
  
@@ -28126,7 +30376,7 @@ diff -urN mutt-1.6.1/sendlib.c mutt-1.6.1-neomutt/sendlib.c
    if (eightbit && option (OPTUSE8BITMIME))
      args = add_option (args, &argslen, &argsmax, "-B8BITMIME");
  
-@@ -2412,6 +2470,9 @@
+@@ -2412,6 +2470,9 @@ mutt_invoke_sendmail (ADDRESS *from,	/* the sender */
    args = add_args (args, &argslen, &argsmax, to);
    args = add_args (args, &argslen, &argsmax, cc);
    args = add_args (args, &argslen, &argsmax, bcc);
@@ -28136,7 +30386,7 @@ diff -urN mutt-1.6.1/sendlib.c mutt-1.6.1-neomutt/sendlib.c
  
    if (argslen == argsmax)
      safe_realloc (&args, sizeof (char *) * (++argsmax));
-@@ -2489,9 +2550,11 @@
+@@ -2489,9 +2550,11 @@ void mutt_prepare_envelope (ENVELOPE *env, int final)
    rfc2047_encode_adrlist (env->from, "From");
    rfc2047_encode_adrlist (env->mail_followup_to, "Mail-Followup-To");
    rfc2047_encode_adrlist (env->reply_to, "Reply-To");
@@ -28149,7 +30399,7 @@ diff -urN mutt-1.6.1/sendlib.c mutt-1.6.1-neomutt/sendlib.c
    {
      rfc2047_encode_string (&env->subject);
    }
-@@ -2514,7 +2577,6 @@
+@@ -2514,7 +2577,6 @@ void mutt_unprepare_envelope (ENVELOPE *env)
    rfc2047_decode_adrlist (env->from);
    rfc2047_decode_adrlist (env->reply_to);
    rfc2047_decode (&env->subject);
@@ -28157,7 +30407,7 @@ diff -urN mutt-1.6.1/sendlib.c mutt-1.6.1-neomutt/sendlib.c
  }
  
  static int _mutt_bounce_message (FILE *fp, HEADER *h, ADDRESS *to, const char *resent_from,
-@@ -2559,9 +2621,12 @@
+@@ -2559,9 +2621,12 @@ static int _mutt_bounce_message (FILE *fp, HEADER *h, ADDRESS *to, const char *r
      mutt_copy_header (fp, h, f, ch_flags, NULL);
      fputc ('\n', f);
      mutt_copy_bytes (fp, f, h->content->length);
@@ -28172,7 +30422,7 @@ diff -urN mutt-1.6.1/sendlib.c mutt-1.6.1-neomutt/sendlib.c
  #if USE_SMTP
      if (SmtpUrl)
        ret = mutt_smtp_send (env_from, to, NULL, NULL, tempfile,
-@@ -2612,6 +2677,10 @@
+@@ -2612,6 +2677,10 @@ int mutt_bounce_message (FILE *fp, HEADER *h, ADDRESS *to)
    }
    rfc822_write_address (resent_from, sizeof (resent_from), from, 0);
  
@@ -28183,7 +30433,7 @@ diff -urN mutt-1.6.1/sendlib.c mutt-1.6.1-neomutt/sendlib.c
    /*
     * prepare recipient list. idna conversion appears to happen before this
     * function is called, since the user receives confirmation of the address
-@@ -2687,7 +2756,8 @@
+@@ -2687,7 +2756,8 @@ static void set_noconv_flags (BODY *b, short flag)
    }
  }
  
@@ -28193,7 +30443,7 @@ diff -urN mutt-1.6.1/sendlib.c mutt-1.6.1-neomutt/sendlib.c
  {
    CONTEXT f;
    MESSAGE *msg;
-@@ -2876,6 +2946,8 @@
+@@ -2876,6 +2946,8 @@ int mutt_write_fcc (const char *path, HEADER *hdr, const char *msgid, int post,
  
    if (mx_commit_message (msg, &f) != 0)
      r = -1;
@@ -28202,10 +30452,12 @@ diff -urN mutt-1.6.1/sendlib.c mutt-1.6.1-neomutt/sendlib.c
    mx_close_message (&msg);
    mx_close_mailbox (&f, NULL);
  
-diff -urN mutt-1.6.1/sidebar.c mutt-1.6.1-neomutt/sidebar.c
---- mutt-1.6.1/sidebar.c	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/sidebar.c	2016-06-12 18:43:00.749453002 +0100
-@@ -0,0 +1,1155 @@
+diff --git a/sidebar.c b/sidebar.c
+new file mode 100644
+index 0000000..1cbdbfb
+--- /dev/null
++++ b/sidebar.c
+@@ -0,0 +1,1162 @@
 +/* Copyright (C) 2004 Justin Hibbits <jrh29 at po.cwru.edu>
 + * Copyright (C) 2004 Thomer M. Gil <mutt at thomer.com>
 + * Copyright (C) 2015-2016 Richard Russon <rich at flatcap.org>
@@ -28236,30 +30488,31 @@ diff -urN mutt-1.6.1/sidebar.c mutt-1.6.1-neomutt/sidebar.c
 +#include "mutt_menu.h"
 +#include "mx.h"
 +#include "sort.h"
++#include "sidebar.h"
 +
 +/* Previous values for some sidebar config */
 +static short  OldVisible;	/* sidebar_visible */
 +static short  OldWidth;		/* sidebar_width */
-+static short  PreviousSort;	/* sidebar_sort_method */
-+static time_t LastRefresh;	/* Time of last refresh */
-+
-+/* Keep track of various BUFFYs */
-+static BUFFY *TopBuffy;		/* First mailbox visible in sidebar */
-+static BUFFY *OpnBuffy;		/* Current (open) mailbox */
-+static BUFFY *HilBuffy;		/* Highlighted mailbox */
-+static BUFFY *BotBuffy;		/* Last mailbox visible in sidebar */
-+static BUFFY *Outgoing;		/* Last mailbox in the linked list */
++static short PreviousSort = SORT_ORDER;  /* sidebar_sort_method */
 +
 +/**
 + * struct sidebar_entry - Info about folders in the sidebar
-+ *
-+ * Used in the mutt_FormatString callback
 + */
-+struct sidebar_entry
++typedef struct sidebar_entry
 +{
-+  char         box[STRING];
++  char         box[STRING];     /* formatted mailbox name */
 +  BUFFY       *buffy;
-+};
++  short        is_hidden;
++} SBENTRY;
++
++static int EntryCount = 0;
++static int EntryLen   = 0;
++static SBENTRY **Entries = NULL;
++
++static int TopIndex = -1;    /* First mailbox visible in sidebar */
++static int OpnIndex = -1;    /* Current (open) mailbox */
++static int HilIndex = -1;    /* Highlighted mailbox */
++static int BotIndex = -1;    /* Last mailbox visible in sidebar */
 +
 +enum {
 +	SB_SRC_NONE = 0,
@@ -28295,66 +30548,6 @@ diff -urN mutt-1.6.1/sidebar.c mutt-1.6.1-neomutt/sidebar.c
 +}
 +
 +/**
-+ * find_next_new - Find the next folder that contains new mail
-+ * @wrap: Wrap around to the beginning if the end is reached
-+ *
-+ * Search down the list of mail folders for one containing new mail.
-+ *
-+ * Returns:
-+ *	BUFFY*: Success
-+ *	NULL:   Failure
-+ */
-+static BUFFY *find_next_new (int wrap)
-+{
-+  BUFFY *b = HilBuffy;
-+  if (!b)
-+    return NULL;
-+
-+  do
-+  {
-+    b = b->next;
-+    if (!b && wrap)
-+      b = get_incoming();
-+    if (!b || (b == HilBuffy))
-+      break;
-+    if (b->msg_unread > 0)
-+      return b;
-+  } while (b);
-+
-+  return NULL;
-+}
-+
-+/**
-+ * find_prev_new - Find the previous folder that contains new mail
-+ * @wrap: Wrap around to the beginning if the end is reached
-+ *
-+ * Search up the list of mail folders for one containing new mail.
-+ *
-+ * Returns:
-+ *	BUFFY*: Success
-+ *	NULL:   Failure
-+ */
-+static BUFFY *find_prev_new (int wrap)
-+{
-+  BUFFY *b = HilBuffy;
-+  if (!b)
-+    return NULL;
-+
-+  do
-+  {
-+    b = b->prev;
-+    if (!b && wrap)
-+      b = Outgoing;
-+    if (!b || (b == HilBuffy))
-+      break;
-+    if (b->msg_unread > 0)
-+      return b;
-+  } while (b);
-+
-+  return NULL;
-+}
-+
-+/**
 + * cb_format_str - Create the string to show in the sidebar
 + * @dest:        Buffer in which to save string
 + * @destlen:     Buffer length
@@ -28368,17 +30561,18 @@ diff -urN mutt-1.6.1/sidebar.c mutt-1.6.1-neomutt/sidebar.c
 + * @flags:       Format flags, e.g. M_FORMAT_OPTIONAL
 + *
 + * cb_format_str is a callback function for mutt_FormatString.  It understands
-+ * five operators. '%B' : Mailbox name, '%F' : Number of flagged messages,
++ * six operators. '%B' : Mailbox name, '%F' : Number of flagged messages,
 + * '%N' : Number of new messages, '%S' : Size (total number of messages),
 + * '%!' : Icon denoting number of flagged messages.
++ * '%n' : N if folder has new mail, blank otherwise.
 + *
 + * Returns: src (unchanged)
 + */
-+static const char *cb_format_str(char *dest, size_t destlen, size_t col, char op,
++static const char *cb_format_str(char *dest, size_t destlen, size_t col, int cols, char op,
 +                                 const char *src, const char *prefix, const char *ifstring,
 +                                 const char *elsestring, unsigned long data, format_flag flags)
 +{
-+  struct sidebar_entry *sbe = (struct sidebar_entry *) data;
++  SBENTRY *sbe = (SBENTRY *) data;
 +  unsigned int optional;
 +  char fmt[STRING];
 +
@@ -28391,7 +30585,7 @@ diff -urN mutt-1.6.1/sidebar.c mutt-1.6.1-neomutt/sidebar.c
 +  if (!b)
 +    return src;
 +
-+  int c = Context && (mutt_strcmp (Context->path, b->path) == 0);
++  int c = Context && (mutt_strcmp (Context->realpath, b->realpath) == 0);
 +
 +  optional = flags & M_FORMAT_OPTIONAL;
 +
@@ -28441,6 +30635,16 @@ diff -urN mutt-1.6.1/sidebar.c mutt-1.6.1-neomutt/sidebar.c
 +        optional = 0;
 +      break;
 +
++    case 'n':
++      if (!optional)
++      {
++        snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
++        snprintf (dest, destlen, fmt, b->new ? 'N' : ' ');
++      }
++      else if (b->new == 0)
++        optional = 0;
++      break;
++
 +    case 'S':
 +      if (!optional)
 +      {
@@ -28477,9 +30681,9 @@ diff -urN mutt-1.6.1/sidebar.c mutt-1.6.1-neomutt/sidebar.c
 +  }
 +
 +  if (optional)
-+    mutt_FormatString (dest, destlen, col, ifstring,   cb_format_str, (unsigned long) sbe, flags);
++    mutt_FormatString (dest, destlen, col, cols, ifstring,   cb_format_str, (unsigned long) sbe, flags);
 +  else if (flags & M_FORMAT_OPTIONAL)
-+    mutt_FormatString (dest, destlen, col, elsestring, cb_format_str, (unsigned long) sbe, flags);
++    mutt_FormatString (dest, destlen, col, cols, elsestring, cb_format_str, (unsigned long) sbe, flags);
 +
 +  /* We return the format string, unchanged */
 +  return src;
@@ -28500,21 +30704,14 @@ diff -urN mutt-1.6.1/sidebar.c mutt-1.6.1-neomutt/sidebar.c
 + * us using cb_format_str() for the sidebar specific formatting characters.
 + */
 +static void make_sidebar_entry (char *buf, unsigned int buflen, int width, char *box,
-+                                BUFFY *b)
++                                SBENTRY *sbe)
 +{
-+  struct sidebar_entry sbe;
-+
-+  if (!buf || !box || !b)
++  if (!buf || !box || !sbe)
 +    return;
 +
-+  sbe.buffy = b;
-+  strfcpy (sbe.box, box, sizeof (sbe.box));
++  strfcpy (sbe->box, box, sizeof (sbe->box));
 +
-+  /* Temporarily lie about the screen width */
-+  int oc = COLS;
-+  COLS = width + SidebarWidth;
-+  mutt_FormatString (buf, buflen, 0, NONULL(SidebarFormat), cb_format_str, (unsigned long) &sbe, 0);
-+  COLS = oc;
++  mutt_FormatString (buf, buflen, 0, width, NONULL(SidebarFormat), cb_format_str, (unsigned long) sbe, 0);
 +
 +  /* Force string to be exactly the right width */
 +  int w = mutt_strwidth (buf);
@@ -28535,30 +30732,21 @@ diff -urN mutt-1.6.1/sidebar.c mutt-1.6.1-neomutt/sidebar.c
 +}
 +
 +/**
-+ * cb_qsort_buffy - qsort callback to sort BUFFYs
-+ * @a: First  BUFFY to compare
-+ * @b: Second BUFFY to compare
-+ *
-+ * Compare the paths of two BUFFYs taking the locale into account.
++ * cb_qsort_sbe - qsort callback to sort SBENTRYs
++ * @a: First  SBENTRY to compare
++ * @b: Second SBENTRY to compare
 + *
 + * Returns:
 + *	-1: a precedes b
 + *	 0: a and b are identical
 + *	 1: b precedes a
 + */
-+static int cb_qsort_buffy (const void *a, const void *b)
++static int cb_qsort_sbe (const void *a, const void *b)
 +{
-+  const BUFFY *b1 = *(const BUFFY **) a;
-+  const BUFFY *b2 = *(const BUFFY **) b;
-+
-+  /* Special case -- move hidden BUFFYs to the end */
-+  if (b1->is_hidden != b2->is_hidden)
-+  {
-+    if (b1->is_hidden)
-+      return 1;
-+    else
-+      return -1;
-+  }
++  const SBENTRY *sbe1 = *(const SBENTRY **) a;
++  const SBENTRY *sbe2 = *(const SBENTRY **) b;
++  BUFFY *b1 = sbe1->buffy;
++  BUFFY *b2 = sbe2->buffy;
 +
 +  int result = 0;
 +
@@ -28567,64 +30755,30 @@ diff -urN mutt-1.6.1/sidebar.c mutt-1.6.1-neomutt/sidebar.c
 +    case SORT_COUNT:
 +      result = (b2->msg_count - b1->msg_count);
 +      break;
-+    case SORT_COUNT_NEW:
-+      result = (b2->msg_unread - b1->msg_unread);
-+      break;
-+    case SORT_DESC:
-+      result = mutt_strcmp (b1->desc, b2->desc);
-+      break;
-+    case SORT_FLAGGED:
-+      result = (b2->msg_flagged - b1->msg_flagged);
-+      break;
-+    case SORT_PATH:
-+      result = mutt_strcasecmp (b1->path, b2->path);
-+      break;
-+  }
-+
-+  if (SidebarSortMethod & SORT_REVERSE)
-+    result = -result;
-+
-+  return result;
-+}
-+
-+/**
-+ * buffy_going - Prevent our pointers becoming invalid
-+ * @b: BUFFY about to be deleted
-+ *
-+ * If we receive a delete-notification for a BUFFY, we need to change any
-+ * pointers we have to reference a different BUFFY, or set them to NULL.
-+ *
-+ * We don't update the prev/next pointers, they'll be fixed on the next
-+ * call to prepare_sidebar().
-+ *
-+ * Returns:
-+ *	A valid alternative BUFFY, or NULL
-+ */
-+static BUFFY *buffy_going (const BUFFY *b)
-+{
-+  if (!b)
-+    return NULL;
-+
-+  if (b->prev)
-+  {
-+    b->prev->next = NULL;
++    case SORT_COUNT_NEW:
++      result = (b2->msg_unread - b1->msg_unread);
++      break;
++    case SORT_DESC:
++      result = mutt_strcmp (b1->desc, b2->desc);
++      break;
++    case SORT_FLAGGED:
++      result = (b2->msg_flagged - b1->msg_flagged);
++      break;
++    case SORT_PATH:
++      result = mutt_strcasecmp (b1->path, b2->path);
++      break;
 +  }
 +
-+  if (b->next)
-+  {
-+    b->next->prev = NULL;
-+    return b->next;
-+  }
++  if (SidebarSortMethod & SORT_REVERSE)
++    result = -result;
 +
-+  return b->prev;
++  return result;
 +}
 +
 +/**
-+ * update_buffy_visibility - Should a BUFFY be displayed in the sidebar
-+ * @arr:     array of BUFFYs
-+ * @arr_len: number of BUFFYs in array
++ * update_entries_visibility - Should a sidebar_entry be displayed in the sidebar
 + *
-+ * For each BUFFY in the array, check whether we should display it.
++ * For each SBENTRY in the Entries array, check whether we should display it.
 + * This is determined by several criteria.  If the BUFFY:
 + *	is the currently open mailbox
 + *	is the currently highlighted mailbox
@@ -28632,81 +30786,96 @@ diff -urN mutt-1.6.1/sidebar.c mutt-1.6.1-neomutt/sidebar.c
 + *	has flagged messages
 + *	is whitelisted
 + */
-+static void update_buffy_visibility (BUFFY **arr, int arr_len)
++static void update_entries_visibility (void)
 +{
-+  if (!arr)
-+    return;
-+
 +  short new_only = option (OPTSIDEBARNEWMAILONLY);
-+
-+  BUFFY *b;
++  SBENTRY *sbe;
 +  int i;
-+  for (i = 0; i < arr_len; i++)
++
++  for (i = 0; i < EntryCount; i++)
 +  {
-+    b = arr[i];
++    sbe = Entries[i];
 +
-+    b->is_hidden = 0;
++    sbe->is_hidden = 0;
 +
 +    if (!new_only)
 +      continue;
 +
-+    if ((b == OpnBuffy) || (b->msg_unread  > 0) ||
-+        (b == HilBuffy) || (b->msg_flagged > 0))
++    if ((i == OpnIndex) || (sbe->buffy->msg_unread  > 0) || sbe->buffy->new ||
++        (i == HilIndex) || (sbe->buffy->msg_flagged > 0))
 +      continue;
 +
-+    if (Context && (strcmp (b->path, Context->path) == 0))
++    if (Context && (mutt_strcmp (sbe->buffy->realpath, Context->realpath) == 0))
 +      /* Spool directory */
 +      continue;
 +
-+    if (mutt_find_list (SidebarWhitelist, b->path))
++    if (mutt_find_list (SidebarWhitelist, sbe->buffy->path))
 +      /* Explicitly asked to be visible */
 +      continue;
 +
-+    b->is_hidden = 1;
++    sbe->is_hidden = 1;
++  }
++}
++
++/**
++ * unsort_entries - Restore Entries array order to match Buffy list order
++ */
++static void unsort_entries (void)
++{
++  BUFFY *cur = get_incoming();
++  int i = 0, j;
++  SBENTRY *tmp;
++
++  while (cur && (i < EntryCount))
++  {
++    j = i;
++    while ((j < EntryCount) &&
++           (Entries[j]->buffy != cur))
++      j++;
++    if (j < EntryCount)
++    {
++      if (j != i)
++      {
++        tmp = Entries[i];
++        Entries[i] = Entries[j];
++        Entries[j] = tmp;
++      }
++      i++;
++    }
++    cur = cur->next;
 +  }
 +}
 +
 +/**
-+ * sort_buffy_array - Sort an array of BUFFY pointers
-+ * @arr:     array of BUFFYs
-+ * @arr_len: number of BUFFYs in array
++ * sort_entries - Sort Entries array.
 + *
-+ * Sort an array of BUFFY pointers according to the current sort config
++ * Sort the Entries array according to the current sort config
 + * option "sidebar_sort_method". This calls qsort to do the work which calls our
-+ * callback function "cb_qsort_buffy".
++ * callback function "cb_qsort_sbe".
 + *
 + * Once sorted, the prev/next links will be reconstructed.
 + */
-+static void sort_buffy_array (BUFFY **arr, int arr_len)
++static void sort_entries (void)
 +{
-+  if (!arr)
-+    return;
++  short ssm = (SidebarSortMethod & SORT_MASK);
 +
 +  /* These are the only sort methods we understand */
-+  short ssm = (SidebarSortMethod & SORT_MASK);
 +  if ((ssm == SORT_COUNT)     ||
 +      (ssm == SORT_COUNT_NEW) ||
-+      (ssm == SORT_DESC)      ||
 +      (ssm == SORT_FLAGGED)   ||
 +      (ssm == SORT_PATH))
-+    qsort (arr, arr_len, sizeof (*arr), cb_qsort_buffy);
-+
-+  int i;
-+  for (i = 0; i < (arr_len - 1); i++)
-+    arr[i]->next = arr[i + 1];
-+  arr[arr_len - 1]->next = NULL;
-+
-+  for (i = 1; i < arr_len; i++)
-+    arr[i]->prev = arr[i - 1];
-+  arr[0]->prev = NULL;
++    qsort (Entries, EntryCount, sizeof (*Entries), cb_qsort_sbe);
++  else if ((ssm == SORT_ORDER) &&
++           (SidebarSortMethod != PreviousSort))
++    unsort_entries ();
 +}
 +
 +/**
-+ * prepare_sidebar - Prepare the list of BUFFYs for the sidebar display
++ * prepare_sidebar - Prepare the list of SBENTRYs for the sidebar display
 + * @page_size:  The number of lines on a page
 + *
-+ * Before painting the sidebar, we count the BUFFYs, determine which are
-+ * visible, sort them and set up our page pointers.
++ * Before painting the sidebar, we determine which are visible, sort
++ * them and set up our page pointers.
 + *
 + * This is a lot of work to do each refresh, but there are many things that
 + * can change outside of the sidebar that we don't hear about.
@@ -28717,70 +30886,49 @@ diff -urN mutt-1.6.1/sidebar.c mutt-1.6.1-neomutt/sidebar.c
 + */
 +static int prepare_sidebar (int page_size)
 +{
-+  BUFFY *b = get_incoming();
-+  if (!b)
-+    return 0;
-+
-+  int count = 0;
-+  for (; b; b = b->next)
-+    count++;
-+
-+  BUFFY **arr = safe_malloc (count * sizeof (*arr));
-+
-+  int i = 0;
-+  for (b = get_incoming(); b; b = b->next, i++)
-+    arr[i] = b;
++  int i;
++  SBENTRY *opn_entry = NULL, *hil_entry = NULL;
 +
-+  update_buffy_visibility (arr, count);
-+  sort_buffy_array        (arr, count);
++  if (!EntryCount)
++    return 0;
 +
-+  if (sidebar_source == SB_SRC_INCOMING)
-+    Incoming = arr[0];
++  if (OpnIndex >= 0)
++    opn_entry = Entries[OpnIndex];
++  if (HilIndex >= 0)
++    hil_entry = Entries[HilIndex];
 +
-+  int top_index =  0;
-+  int opn_index = -1;
-+  int hil_index = -1;
-+  int bot_index = -1;
++  update_entries_visibility ();
++  sort_entries ();
 +
-+  for (i = 0; i < count; i++)
++  for (i = 0; i < EntryCount; i++)
 +  {
-+    if (OpnBuffy == arr[i])
-+      opn_index = i;
-+    if (HilBuffy == arr[i])
-+      hil_index = i;
++    if (opn_entry == Entries[i])
++      OpnIndex = i;
++    if (hil_entry == Entries[i])
++      HilIndex = i;
 +  }
 +
-+  if (!HilBuffy || (SidebarSortMethod != PreviousSort))
++  if ((HilIndex < 0) || (SidebarSortMethod != PreviousSort))
 +  {
-+    if (OpnBuffy)
-+    {
-+      HilBuffy  = OpnBuffy;
-+      hil_index = opn_index;
-+    }
++    if (OpnIndex >= 0)
++      HilIndex  = OpnIndex;
 +    else
-+    {
-+      HilBuffy  = arr[0];
-+      hil_index = 0;
-+    }
++      HilIndex  = 0;
 +  }
-+  if (TopBuffy)
-+    top_index = (hil_index / page_size) * page_size;
++  if (TopIndex >= 0)
++    TopIndex = (HilIndex / page_size) * page_size;
 +  else
-+    top_index = hil_index;
-+  TopBuffy = arr[top_index];
-+
-+  bot_index = top_index + page_size - 1;
-+  if (bot_index > (count - 1))
-+    bot_index = count - 1;
-+  BotBuffy  = arr[bot_index];
++    TopIndex = HilIndex;
 +
-+  Outgoing = arr[count - 1];
++  BotIndex = TopIndex + page_size - 1;
++  if (BotIndex > (EntryCount - 1))
++    BotIndex = EntryCount - 1;
 +
 +  PreviousSort = SidebarSortMethod;
-+  FREE (&arr);
 +  return 1;
 +}
 +
++
 +/**
 + * visible - Should we display the sidebar?
 + *
@@ -28927,30 +31075,34 @@ diff -urN mutt-1.6.1/sidebar.c mutt-1.6.1-neomutt/sidebar.c
 + */
 +static void draw_sidebar (int first_row, int num_rows, int div_width)
 +{
-+  BUFFY *b = TopBuffy;
-+  if (!b)
++  int entryidx;
++  SBENTRY *entry;
++  BUFFY *b;
++  if (TopIndex < 0)
 +    return;
 +
 +  int w = MIN(COLS, (SidebarWidth - div_width));
 +  int row = 0;
-+  for (b = TopBuffy; b && (row < num_rows); b = b->next)
++  for (entryidx = TopIndex; (entryidx < EntryCount) && (row < num_rows); entryidx++)
 +  {
-+    if (b->is_hidden)
++    entry = Entries[entryidx];
++    if (entry->is_hidden)
 +      continue;
++    b = entry->buffy;
 +
-+    if (b == OpnBuffy)
++    if (entryidx == OpnIndex)
 +    {
 +      if ((ColorDefs[MT_COLOR_SB_INDICATOR] != 0))
 +        SETCOLOR(MT_COLOR_SB_INDICATOR);
 +      else
 +        SETCOLOR(MT_COLOR_INDICATOR);
 +    }
-+    else if (b == HilBuffy)
++    else if (entryidx == HilIndex)
 +      SETCOLOR(MT_COLOR_HIGHLIGHT);
 +    else if ((ColorDefs[MT_COLOR_SB_SPOOLFILE] != 0) &&
 +               (mutt_strcmp (b->path, Spoolfile) == 0))
 +      SETCOLOR(MT_COLOR_SB_SPOOLFILE);
-+    else if (b->msg_unread > 0)
++    else if ((b->msg_unread > 0) || (b->new))
 +      SETCOLOR(MT_COLOR_NEW);
 +    else if (b->msg_flagged > 0)
 +      SETCOLOR(MT_COLOR_FLAGGED);
@@ -28958,9 +31110,8 @@ diff -urN mutt-1.6.1/sidebar.c mutt-1.6.1-neomutt/sidebar.c
 +      SETCOLOR(MT_COLOR_NORMAL);
 +
 +    move (first_row + row, 0);
-+    if (Context && Context->path &&
-+        (!strcmp (b->path, Context->path)||
-+         !strcmp (b->realpath, Context->path)))
++    if (Context && Context->realpath &&
++        !mutt_strcmp (b->realpath, Context->realpath))
 +    {
 +      b->msg_unread  = Context->unread;
 +      b->msg_count   = Context->msgcount;
@@ -29017,10 +31168,12 @@ diff -urN mutt-1.6.1/sidebar.c mutt-1.6.1-neomutt/sidebar.c
 +        if (option (OPTSIDEBARSHORTPATH))
 +          tmp_folder_name += lastsep;  /* basename */
 +        sidebar_folder_name = malloc (strlen (tmp_folder_name) + sidebar_folder_depth*strlen (NONULL(SidebarIndentString)) + 1);
++        int sfn_len = strlen (tmp_folder_name) + sidebar_folder_depth*strlen (NONULL(SidebarIndentString)) + 1;
++        sidebar_folder_name = safe_malloc (sfn_len);
 +        sidebar_folder_name[0]=0;
 +        for (i=0; i < sidebar_folder_depth; i++)
-+          strncat (sidebar_folder_name, NONULL(SidebarIndentString), strlen (NONULL(SidebarIndentString)));
-+        strncat (sidebar_folder_name, tmp_folder_name, strlen (tmp_folder_name));
++          safe_strcat (sidebar_folder_name, sfn_len, NONULL(SidebarIndentString));
++        safe_strcat (sidebar_folder_name, sfn_len, tmp_folder_name);
 +      }
 +    }
 +#ifdef USE_NOTMUCH
@@ -29030,7 +31183,7 @@ diff -urN mutt-1.6.1/sidebar.c mutt-1.6.1-neomutt/sidebar.c
 +    }
 +#endif
 +    char str[STRING];
-+    make_sidebar_entry (str, sizeof (str), w, sidebar_folder_name, b);
++    make_sidebar_entry (str, sizeof (str), w, sidebar_folder_name, entry);
 +    printw ("%s", str);
 +    if (sidebar_folder_depth > 0)
 +      FREE (&sidebar_folder_name);
@@ -29077,6 +31230,19 @@ diff -urN mutt-1.6.1/sidebar.c mutt-1.6.1-neomutt/sidebar.c
 +  /* if (OldVisible == 0) */
 +  /* 	mutt_buffy_check (1); we probably have bad or no numbers */
 +
++  BUFFY *b;
++  if (Entries == NULL)
++    for (b = get_incoming(); b; b = b->next)
++      mutt_sb_notify_mailbox (b, 1);
++
++#ifdef USE_SLANG_CURSES
++  int x = SLsmg_get_column();
++  int y = SLsmg_get_row();
++#else
++  int x = getcurx (stdscr);
++  int y = getcury (stdscr);
++#endif
++
 +  int first_row = 0;
 +  int num_rows  = LINES - 2;
 +
@@ -29101,29 +31267,127 @@ diff -urN mutt-1.6.1/sidebar.c mutt-1.6.1-neomutt/sidebar.c
 +    return;
 +
 +  draw_sidebar (first_row, num_rows, div_width);
++  move (y, x);
++}
++
++/**
++ * select_next - Selects the next unhidden mailbox
++ *
++ * Returns:
++ *      1: Success
++ *      0: Failure
++ */
++static int select_next (void)
++{
++  int entry = HilIndex;
++
++  if (!EntryCount || HilIndex < 0)
++    return 0;
++
++  do
++  {
++    entry++;
++    if (entry == EntryCount)
++      return 0;
++  } while (Entries[entry]->is_hidden);
++
++  HilIndex = entry;
++  return 1;
 +}
 +
 +/**
-+ * mutt_sb_should_refresh - Check if the sidebar is due to be refreshed
++ * select_next_new - Selects the next new mailbox
 + *
-+ * The "sidebar_refresh_time" config option allows the user to limit the frequency
-+ * with which the sidebar is refreshed.
++ * Search down the list of mail folders for one containing new mail.
 + *
 + * Returns:
-+ *	1  Yes, refresh is due
-+ *	0  No,  refresh happened recently
++ *	1: Success
++ *	0: Failure
 + */
-+int mutt_sb_should_refresh (void)
++static int select_next_new (void)
 +{
-+  if (!option (OPTSIDEBAR))
++  int entry = HilIndex;
++
++  if (!EntryCount || HilIndex < 0)
++    return 0;
++
++  do
++  {
++    entry++;
++    if (entry == EntryCount)
++    {
++      if (option (OPTSIDEBARNEXTNEWWRAP))
++        entry = 0;
++      else
++        return 0;
++    }
++    if (entry == HilIndex)
++      return 0;
++  } while (!Entries[entry]->buffy->new &&
++           !Entries[entry]->buffy->msg_unread);
++
++  HilIndex = entry;
++  return 1;
++}
++
++/**
++ * select_prev - Selects the previous unhidden mailbox
++ *
++ * Returns:
++ *      1: Success
++ *      0: Failure
++ */
++static int select_prev (void)
++{
++  int entry = HilIndex;
++
++  if (!EntryCount || HilIndex < 0)
 +    return 0;
 +
-+  if (SidebarRefreshTime == 0)
++  do
++  {
++    entry--;
++    if (entry < 0)
++      return 0;
++  } while (Entries[entry]->is_hidden);
++
++  HilIndex = entry;
++  return 1;
++}
++
++/**
++ * select_prev_new - Selects the previous new mailbox
++ *
++ * Search up the list of mail folders for one containing new mail.
++ *
++ * Returns:
++ *	1: Success
++ *	0: Failure
++ */
++static int select_prev_new (void)
++{
++  int entry = HilIndex;
++
++  if (!EntryCount || HilIndex < 0)
 +    return 0;
 +
-+  time_t diff = (time (NULL) - LastRefresh);
++  do
++  {
++    entry--;
++    if (entry < 0)
++    {
++      if (option (OPTSIDEBARNEXTNEWWRAP))
++        entry = EntryCount - 1;
++      else
++        return 0;
++    }
++    if (entry == HilIndex)
++      return 0;
++  } while (!Entries[entry]->buffy->new &&
++           !Entries[entry]->buffy->msg_unread);
 +
-+  return (diff >= SidebarRefreshTime);
++  HilIndex = entry;
++  return 1;
 +}
 +
 +/**
@@ -29143,57 +31407,42 @@ diff -urN mutt-1.6.1/sidebar.c mutt-1.6.1-neomutt/sidebar.c
 + */
 +void mutt_sb_change_mailbox (int op)
 +{
-+  BUFFY *b;
-+  if (!HilBuffy)	/* It'll get reset on the next draw */
++  if (!option (OPTSIDEBAR))
++    return;
++
++  if (HilIndex < 0)	/* It'll get reset on the next draw */
 +    return;
 +
 +  switch (op)
 +  {
 +    case OP_SIDEBAR_NEXT:
-+      if (!HilBuffy->next)
-+        return;
-+      if (HilBuffy->next->is_hidden)
++      if (! select_next ())
 +        return;
-+      HilBuffy = HilBuffy->next;
 +      break;
 +    case OP_SIDEBAR_NEXT_NEW:
-+      b = find_next_new (option (OPTSIDEBARNEXTNEWWRAP));
-+      if (!b)
++      if (! select_next_new ())
 +        return;
-+      else
-+        HilBuffy = b;
 +      break;
 +    case OP_SIDEBAR_PAGE_DOWN:
-+      HilBuffy = BotBuffy;
-+      if (HilBuffy->next)
-+        HilBuffy = HilBuffy->next;
++      HilIndex = BotIndex;
++      select_next ();
 +      break;
 +    case OP_SIDEBAR_PAGE_UP:
-+      HilBuffy = TopBuffy;
-+      if (HilBuffy != get_incoming())
-+        HilBuffy = HilBuffy->prev;
++      HilIndex = TopIndex;
++      select_prev ();
 +      break;
 +    case OP_SIDEBAR_PREV:
-+      if (!HilBuffy->prev)
-+        return;
-+      if (HilBuffy->prev->is_hidden)	/* Can't happen, we've sorted the hidden to the end */
++      if (! select_prev ())
 +        return;
-+      HilBuffy = HilBuffy->prev;
 +      break;
 +    case OP_SIDEBAR_PREV_NEW:
-+      b = find_prev_new (option (OPTSIDEBARNEXTNEWWRAP));
-+      if (!b)
++      if (! select_prev_new ())
 +        return;
-+      else
-+        HilBuffy = b;
 +      break;
 +    default:
 +      return;
 +  }
-+
-+  /* We can change folder even if the sidebar is hidden */
-+  if (option (OPTSIDEBAR))
-+    mutt_sb_draw();
++  SidebarNeedsRedraw = 1;
 +}
 +
 +/**
@@ -29213,8 +31462,7 @@ diff -urN mutt-1.6.1/sidebar.c mutt-1.6.1-neomutt/sidebar.c
 +
 +  for (; b; b = b->next)
 +  {
-+    if (!strcmp (b->path,     ctx->path) ||
-+        !strcmp (b->realpath, ctx->path))
++    if (!mutt_strcmp (b->realpath, ctx->realpath))
 +    {
 +      b->msg_unread  = ctx->unread;
 +      b->msg_count   = ctx->msgcount;
@@ -29234,55 +31482,39 @@ diff -urN mutt-1.6.1/sidebar.c mutt-1.6.1-neomutt/sidebar.c
 + */
 +const char *mutt_sb_get_highlight (void)
 +{
-+  if (!HilBuffy)
++  if (!option (OPTSIDEBAR))
++    return NULL;
++
++  if (!EntryCount || HilIndex < 0)
 +    return NULL;
 +
-+  return HilBuffy->path;
++  return Entries[HilIndex]->buffy->path;
 +}
 +
 +/**
-+ * mutt_sb_set_open_buffy - Set the OpnBuffy based on a mailbox path
-+ * @path: Mailbox path
++ * mutt_sb_set_open_buffy - Set the OpnBuffy based on the global Context
 + *
 + * Search through the list of mailboxes.  If a BUFFY has a matching path, set
 + * OpnBuffy to it.
 + */
-+BUFFY *mutt_sb_set_open_buffy (const char *path)
++void mutt_sb_set_open_buffy (void)
 +{
-+  /* Even if the sidebar is hidden */
-+
-+  BUFFY *b = get_incoming();
++  int entry;
 +
-+  if (!path || !b)
-+    return NULL;
++  OpnIndex = -1;
 +
-+  OpnBuffy = NULL;
++  if (!Context)
++    return;
 +
-+  for (; b; b = b->next)
++  for (entry = 0; entry < EntryCount; entry++)
 +  {
-+    if (!strcmp (b->path,     path) ||
-+        !strcmp (b->realpath, path))
++    if (!mutt_strcmp (Entries[entry]->buffy->realpath, Context->realpath))
 +    {
-+      OpnBuffy = b;
-+      HilBuffy = b;
++      OpnIndex = entry;
++      HilIndex = entry;
 +      break;
 +    }
 +  }
-+
-+  return OpnBuffy;
-+}
-+
-+/**
-+ * mutt_sb_set_update_time - Note the time that the sidebar was updated
-+ *
-+ * Update the timestamp representing the last sidebar update.  If the user
-+ * configures "sidebar_refresh_time", this will help to reduce traffic.
-+ */
-+void mutt_sb_set_update_time (void)
-+{
-+  /* XXX - should this be public? */
-+
-+  LastRefresh = time (NULL);
 +}
 +
 +/**
@@ -29296,48 +31528,69 @@ diff -urN mutt-1.6.1/sidebar.c mutt-1.6.1-neomutt/sidebar.c
 + */
 +void mutt_sb_notify_mailbox (BUFFY *b, int created)
 +{
++  int del_index;
++
 +  if (!b)
 +    return;
 +
++  if (sidebar_source == SB_SRC_NONE)
++    return;
++
 +  /* Any new/deleted mailboxes will cause a refresh.  As long as
 +   * they're valid, our pointers will be updated in prepare_sidebar() */
 +
 +  if (created)
 +  {
-+    if (!TopBuffy)
-+      TopBuffy = b;
-+    if (!HilBuffy)
-+      HilBuffy = b;
-+    if (!BotBuffy)
-+      BotBuffy = b;
-+    if (!Outgoing)
-+      Outgoing = b;
-+    if (!OpnBuffy && Context)
++    if (EntryCount >= EntryLen)
 +    {
-+      /* This might happen if the user "unmailboxes *", then
-+       * "mailboxes" our current mailbox back again */
-+      if (mutt_strcmp (b->path, Context->path) == 0)
-+        OpnBuffy = b;
++      EntryLen += 10;
++      safe_realloc (&Entries, EntryLen * sizeof (SBENTRY *));
 +    }
++    Entries[EntryCount] = safe_calloc (1, sizeof(SBENTRY));
++    Entries[EntryCount]->buffy = b;
++
++    if (TopIndex < 0)
++      TopIndex = EntryCount;
++    if (HilIndex < 0)
++      HilIndex = EntryCount;
++    if (BotIndex < 0)
++      BotIndex = EntryCount;
++    if ((OpnIndex < 0) && Context &&
++        (mutt_strcmp (b->realpath, Context->realpath) == 0))
++      OpnIndex = EntryCount;
++
++    EntryCount++;
 +  }
 +  else
 +  {
-+    BUFFY *replacement = buffy_going (b);
-+    if (TopBuffy == b)
-+      TopBuffy = replacement;
-+    if (OpnBuffy == b)
-+      OpnBuffy = NULL;
-+    if (HilBuffy == b)
-+      HilBuffy = replacement;
-+    if (BotBuffy == b)
-+      BotBuffy = replacement;
-+    if (Outgoing == b)
-+      Outgoing = replacement;
++    for (del_index = 0; del_index < EntryCount; del_index++)
++      if (Entries[del_index]->buffy == b)
++        break;
++    if (del_index == EntryCount)
++      return;
++    FREE (&Entries[del_index]);
++    EntryCount--;
++
++    if (TopIndex > del_index || TopIndex == EntryCount)
++      TopIndex--;
++    if (OpnIndex == del_index)
++      OpnIndex = -1;
++    else if (OpnIndex > del_index)
++      OpnIndex--;
++    if (HilIndex > del_index || HilIndex == EntryCount)
++      HilIndex--;
++    if (BotIndex > del_index || BotIndex == EntryCount)
++      BotIndex--;
++
++    for (; del_index < EntryCount; del_index++)
++      Entries[del_index] = Entries[del_index + 1];
 +  }
++
++  SidebarNeedsRedraw = 1;
 +}
 +
 +/**
-+ * sb_toggle_virtual - Switch between regular and virtual folders
++ * mutt_sb_toggle_virtual - Switch between regular and virtual folders
 + */
 +void
 +mutt_sb_toggle_virtual (void)
@@ -29352,19 +31605,27 @@ diff -urN mutt-1.6.1/sidebar.c mutt-1.6.1-neomutt/sidebar.c
 +#endif
 +		sidebar_source = SB_SRC_INCOMING;
 +
-+	TopBuffy = NULL;
-+	OpnBuffy = NULL;
-+	HilBuffy = NULL;
-+	BotBuffy = NULL;
-+	Outgoing = NULL;
++	TopIndex = -1;
++	OpnIndex = -1;
++	HilIndex = -1;
++	BotIndex = -1;
 +
-+	mutt_sb_draw();
++	BUFFY *b;
++
++	EntryCount = 0;
++	FREE(Entries);
++	for (b = get_incoming(); b; b = b->next)
++		mutt_sb_notify_mailbox (b, 1);
++
++	SidebarNeedsRedraw = 1;
 +}
 +
-diff -urN mutt-1.6.1/sidebar.h mutt-1.6.1-neomutt/sidebar.h
---- mutt-1.6.1/sidebar.h	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/sidebar.h	2016-06-12 18:43:00.750453017 +0100
-@@ -0,0 +1,37 @@
+diff --git a/sidebar.h b/sidebar.h
+new file mode 100644
+index 0000000..f1ffcb1
+--- /dev/null
++++ b/sidebar.h
+@@ -0,0 +1,35 @@
 +/* Copyright (C) 2004 Justin Hibbits <jrh29 at po.cwru.edu>
 + * Copyright (C) 2004 Thomer M. Gil <mutt at thomer.com>
 + * Copyright (C) 2015-2016 Richard Russon <rich at flatcap.org>
@@ -29396,15 +31657,48 @@ diff -urN mutt-1.6.1/sidebar.h mutt-1.6.1-neomutt/sidebar.h
 +void         mutt_sb_init (void);
 +void         mutt_sb_notify_mailbox (BUFFY *b, int created);
 +void         mutt_sb_set_buffystats (const CONTEXT *ctx);
-+BUFFY *      mutt_sb_set_open_buffy (const char *path);
-+void         mutt_sb_set_update_time (void);
-+int          mutt_sb_should_refresh (void);
++void         mutt_sb_set_open_buffy (void);
 +void         mutt_sb_toggle_virtual (void);
 +
 +#endif /* SIDEBAR_H */
-diff -urN mutt-1.6.1/sort.c mutt-1.6.1-neomutt/sort.c
---- mutt-1.6.1/sort.c	2016-06-12 18:43:00.415447793 +0100
-+++ mutt-1.6.1-neomutt/sort.c	2016-06-12 18:43:00.751453033 +0100
+diff --git a/smime.c b/smime.c
+index 7f9a8b5..c6b96b7 100644
+--- a/smime.c
++++ b/smime.c
+@@ -159,6 +159,7 @@ int smime_valid_passphrase (void)
+ static const char *_mutt_fmt_smime_command (char *dest,
+ 					    size_t destlen,
+ 					    size_t col,
++                                            int cols,
+ 					    char op,
+ 					    const char *src,
+ 					    const char *prefix,
+@@ -284,10 +285,10 @@ static const char *_mutt_fmt_smime_command (char *dest,
+   }
+ 
+   if (optional)
+-    mutt_FormatString (dest, destlen, col, ifstring, _mutt_fmt_smime_command,
++    mutt_FormatString (dest, destlen, col, cols, ifstring, _mutt_fmt_smime_command,
+ 		       data, 0);
+   else if (flags & M_FORMAT_OPTIONAL)
+-    mutt_FormatString (dest, destlen, col, elsestring, _mutt_fmt_smime_command,
++    mutt_FormatString (dest, destlen, col, cols, elsestring, _mutt_fmt_smime_command,
+ 		       data, 0);
+ 
+   return (src);
+@@ -298,7 +299,7 @@ static const char *_mutt_fmt_smime_command (char *dest,
+ static void mutt_smime_command (char *d, size_t dlen,
+ 				struct smime_command_context *cctx, const char *fmt)
+ {
+-  mutt_FormatString (d, dlen, 0, NONULL(fmt), _mutt_fmt_smime_command,
++  mutt_FormatString (d, dlen, 0, COLS - SidebarWidth, NONULL(fmt), _mutt_fmt_smime_command,
+ 		    (unsigned long) cctx, 0);
+   dprint (2,(debugfile, "mutt_smime_command: %s\n", d));
+ }
+diff --git a/sort.c b/sort.c
+index 76e9e79..f3967f9 100644
+--- a/sort.c
++++ b/sort.c
 @@ -24,6 +24,11 @@
  #include "sort.h"
  #include "mutt_idna.h"
@@ -29417,7 +31711,7 @@ diff -urN mutt-1.6.1/sort.c mutt-1.6.1-neomutt/sort.c
  #include <stdlib.h>
  #include <string.h>
  #include <ctype.h>
-@@ -151,6 +156,17 @@
+@@ -151,6 +156,17 @@ static int compare_order (const void *a, const void *b)
    HEADER **ha = (HEADER **) a;
    HEADER **hb = (HEADER **) b;
  
@@ -29435,7 +31729,7 @@ diff -urN mutt-1.6.1/sort.c mutt-1.6.1-neomutt/sort.c
    /* no need to auxsort because you will never have equality here */
    return (SORTCODE ((*ha)->index - (*hb)->index));
  }
-@@ -210,6 +226,46 @@
+@@ -210,6 +226,46 @@ static int compare_spam (const void *a, const void *b)
    return (SORTCODE(result));
  }
  
@@ -29482,7 +31776,7 @@ diff -urN mutt-1.6.1/sort.c mutt-1.6.1-neomutt/sort.c
  sort_t *mutt_get_sort_func (int method)
  {
    switch (method & SORT_MASK)
-@@ -232,6 +288,8 @@
+@@ -232,6 +288,8 @@ sort_t *mutt_get_sort_func (int method)
        return (compare_score);
      case SORT_SPAM:
        return (compare_spam);
@@ -29491,24 +31785,25 @@ diff -urN mutt-1.6.1/sort.c mutt-1.6.1-neomutt/sort.c
      default:
        return (NULL);
    }
-diff -urN mutt-1.6.1/sort.h mutt-1.6.1-neomutt/sort.h
---- mutt-1.6.1/sort.h	2016-06-12 18:43:00.415447793 +0100
-+++ mutt-1.6.1-neomutt/sort.h	2016-06-12 18:43:00.751453033 +0100
+diff --git a/sort.h b/sort.h
+index f2832b2..c969c09 100644
+--- a/sort.h
++++ b/sort.h
 @@ -31,6 +31,13 @@
  #define SORT_KEYID	12
  #define SORT_TRUST	13
  #define SORT_SPAM	14
-+#define SORT_DESC	15
-+#define SORT_COUNT	16
-+#define SORT_COUNT_NEW	17
-+#define SORT_FLAGGED	18
-+#define SORT_PATH	19
++#define SORT_COUNT	15
++#define SORT_COUNT_NEW	16
++#define SORT_FLAGGED	17
++#define SORT_PATH	18
++#define SORT_DESC	19
 +#define SORT_LABEL	20
 +
  /* dgc: Sort & SortAux are shorts, so I'm bumping these bitflags up from
   * bits 4 & 5 to bits 8 & 9 to make room for more sort keys in the future. */
  #define SORT_MASK	0xff
-@@ -50,6 +57,7 @@
+@@ -50,6 +57,7 @@ WHERE short BrowserSort INITVAL (SORT_SUBJECT);
  WHERE short Sort INITVAL (SORT_DATE);
  WHERE short SortAux INITVAL (SORT_DATE); /* auxiliary sorting method */
  WHERE short SortAlias INITVAL (SORT_ALIAS);
@@ -29516,9 +31811,10 @@ diff -urN mutt-1.6.1/sort.h mutt-1.6.1-neomutt/sort.h
  
  /* FIXME: This one does not belong to here */
  WHERE short PgpSortKeys INITVAL (SORT_ADDRESS);
-diff -urN mutt-1.6.1/status.c mutt-1.6.1-neomutt/status.c
---- mutt-1.6.1/status.c	2016-06-12 18:43:00.415447793 +0100
-+++ mutt-1.6.1-neomutt/status.c	2016-06-12 18:43:00.751453033 +0100
+diff --git a/status.c b/status.c
+index 6051e3a..dd8cf04 100644
+--- a/status.c
++++ b/status.c
 @@ -27,6 +27,10 @@
  #include "mapping.h"
  #include "mx.h"
@@ -29530,7 +31826,25 @@ diff -urN mutt-1.6.1/status.c mutt-1.6.1-neomutt/status.c
  #include <string.h>
  #include <ctype.h>
  #include <unistd.h>
-@@ -95,7 +99,20 @@
+@@ -40,7 +44,7 @@ static char *get_sort_str (char *buf, size_t buflen, int method)
+   return buf;
+ }
+ 
+-static void _menu_status_line (char *buf, size_t buflen, size_t col, MUTTMENU *menu, const char *p);
++static void _menu_status_line (char *buf, size_t buflen, size_t col, int cols, MUTTMENU *menu, const char *p);
+ 
+ /* %b = number of incoming folders with unread messages [option]
+  * %d = number of deleted messages [option]
+@@ -62,7 +66,7 @@ static void _menu_status_line (char *buf, size_t buflen, size_t col, MUTTMENU *m
+  * %v = Mutt version 
+  * %V = currently active limit pattern [option] */
+ static const char *
+-status_format_str (char *buf, size_t buflen, size_t col, char op, const char *src,
++status_format_str (char *buf, size_t buflen, size_t col, int cols, char op, const char *src,
+ 		   const char *prefix, const char *ifstring,
+ 		   const char *elsestring,
+ 		   unsigned long data, format_flag flags)
+@@ -95,7 +99,20 @@ status_format_str (char *buf, size_t buflen, size_t col, char op, const char *sr
        break;
  
      case 'f':
@@ -29552,7 +31866,7 @@ diff -urN mutt-1.6.1/status.c mutt-1.6.1-neomutt/status.c
        if (Context && Context->path)
        {
  	strfcpy (tmp, Context->path, sizeof (tmp));
-@@ -103,9 +120,11 @@
+@@ -103,9 +120,11 @@ status_format_str (char *buf, size_t buflen, size_t col, char op, const char *sr
        }
        else
  	strfcpy (tmp, _("(no mailbox)"), sizeof (tmp));
@@ -29565,9 +31879,36 @@ diff -urN mutt-1.6.1/status.c mutt-1.6.1-neomutt/status.c
      case 'F':
        if (!optional)
        {
-diff -urN mutt-1.6.1/strndup.c mutt-1.6.1-neomutt/strndup.c
---- mutt-1.6.1/strndup.c	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/strndup.c	2016-06-12 18:43:00.751453033 +0100
+@@ -290,19 +309,19 @@ status_format_str (char *buf, size_t buflen, size_t col, char op, const char *sr
+   }
+ 
+   if (optional)
+-    _menu_status_line (buf, buflen, col, menu, ifstring);
++    _menu_status_line (buf, buflen, col, cols, menu, ifstring);
+   else if (flags & M_FORMAT_OPTIONAL)
+-    _menu_status_line (buf, buflen, col, menu, elsestring);
++    _menu_status_line (buf, buflen, col, cols, menu, elsestring);
+ 
+   return (src);
+ }
+ 
+-static void _menu_status_line (char *buf, size_t buflen, size_t col, MUTTMENU *menu, const char *p)
++static void _menu_status_line (char *buf, size_t buflen, size_t col, int cols, MUTTMENU *menu, const char *p)
+ {
+-  mutt_FormatString (buf, buflen, col, p, status_format_str, (unsigned long) menu, 0);
++  mutt_FormatString (buf, buflen, col, cols, p, status_format_str, (unsigned long) menu, 0);
+ }
+ 
+ void menu_status_line (char *buf, size_t buflen, MUTTMENU *menu, const char *p)
+ {
+-  mutt_FormatString (buf, buflen, 0, p, status_format_str, (unsigned long) menu, 0);
++  mutt_FormatString (buf, buflen, 0, COLS - SidebarWidth, p, status_format_str, (unsigned long) menu, 0);
+ }
+diff --git a/strndup.c b/strndup.c
+new file mode 100644
+index 0000000..67c1a5e
+--- /dev/null
++++ b/strndup.c
 @@ -0,0 +1,19 @@
 +/*
 + * Copyright (C) 2013 Karel Zak <kzak at redhat.com>
@@ -29588,9 +31929,11 @@ diff -urN mutt-1.6.1/strndup.c mutt-1.6.1-neomutt/strndup.c
 +	new[len] = '\0';
 +	return (char *) memcpy(new, s, len);
 +}
-diff -urN mutt-1.6.1/strnlen.c mutt-1.6.1-neomutt/strnlen.c
---- mutt-1.6.1/strnlen.c	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/strnlen.c	2016-06-12 18:43:00.751453033 +0100
+diff --git a/strnlen.c b/strnlen.c
+new file mode 100644
+index 0000000..278a988
+--- /dev/null
++++ b/strnlen.c
 @@ -0,0 +1,20 @@
 +/*
 + * Copyright (C) 2013 Karel Zak <kzak at redhat.com>
@@ -29612,82 +31955,11 @@ diff -urN mutt-1.6.1/strnlen.c mutt-1.6.1-neomutt/strnlen.c
 +        }
 +        return maxlen;
 +}
-diff -urN mutt-1.6.1/UPDATING.kz mutt-1.6.1-neomutt/UPDATING.kz
---- mutt-1.6.1/UPDATING.kz	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/UPDATING.kz	2016-06-12 18:43:00.672451801 +0100
-@@ -0,0 +1,68 @@
-+1.6.0.1:
-+
-++ rebase to mutt upstream 1.6.0
-++ update to the new sidebar implementation. Note that all .muttrc options 
-+  are prefixed by "sidebar_" now.
-+
-++ rebase is based on neomutt project (see https://github.com/neomutt) where are
-+  maintained all non-upstream mutt changes, so it's easy to merge another
-+  features like "trash", "ifdef", ... to mutt-kz.
-+
-++ the stable mutt-kz releases and tags are maintained in stable/v<version> branches, 
-+  the master branch is going to be *rebased*. This development model help us to be 
-+  up to date with mutt upstream.
-+
-+
-+1.5.23.1:
-+
-++ integrated color status patch (original from Thomas Glanzmann)
-+  https://thomas.glanzmann.de//mutt/#cstatus
-++ integrated TLS Server Name Indication support patch (original from Phil Pennock)
-++ improved sidebar functionality to optinaly show only folders with new emails
-+  (sidebar-new, sitebar-next, ...)
-+
-++ fix notmuch DB usage
-++ use unlocked libc IO in improve performance
-++ security bug fix from original mutt
-+
-++ sync with the original mutt upstream
-++ add sidebar_whitelist option
-++ oppenc & pgp upstream sync and improvements
-+
-+
-+1.5.22.1:
-+
-++ use git and github rather than hg to maintain source code
-+
-++ virtual folders based on notmuch queries
-++ merge sidebar patch
-++ merge index-color patch
-+
-++ <change-vfolder> command
-++ <vfolder-from-query> command
-++ <modify-labels> command to set/unset notmuch tags
-++ <modify-labels-then-hide> command to set/unset notmuch tags and hide email
-+  from the current view
-++ <quasi-delete> command to delete message from mutt, but don't touch message
-+  on the disk
-++ <entire-thread> command to add to the current list of the messages all
-+  messages that belongs to the same thread as the current message
-++ ~Y EXPR  pattern modifier for notmuch labels for limit, tag-pattern,
-+  delete-pattern, color etc.
-++ virtual-mailboxes <desc> <uri> [...]  to specify list of the virtual mailboxes
-++ virtual_spoolfile = <boolean> to use the first virtual mailbox as a spoolfile
-++ tag-transforms <tag> <transform> to transform tag name to another name
-++ tag-formats <tag> <format sequence> [ ...] to define tag specific formatting
-+  sequence for $index_format
-++ nm_record = <boolean> to add sent emails (mutt record) to notmuch DB
-++ nm_record_tags = <comma delimited list> to specify tags for nm_record
-++ nm_open_timeout = <seconds> to specify timeout for notmuch database
-++ nm_default_uri = <uri>  the default URI to connect notmuch
-++ nm_hidden_tags = <comma delimited list> to make some tags invisible for mutt user
-++ nm_exclude_tags = <comma delimited list> - messages tagged with these tags
-+  are excluded and not loaded from notmuch DB to mutt unless specified explicitly
-++ nm_unread_tag = <name> to specify unread messages
-++ nm_db_limit = <num> to specify notmuch query limit
-++ nm_query_type = <threads|messages> to specify what to load from DB
-++ vfolder_format = <string> to specify vfolders browser entry format
-++ %g and %Gx index_format and pager_format formatting sequences
-diff -urN mutt-1.6.1/url.c mutt-1.6.1-neomutt/url.c
---- mutt-1.6.1/url.c	2016-06-12 18:43:00.415447793 +0100
-+++ mutt-1.6.1-neomutt/url.c	2016-06-12 18:43:00.752453048 +0100
-@@ -39,13 +39,18 @@
+diff --git a/url.c b/url.c
+index 42a6e09..d11b8d7 100644
+--- a/url.c
++++ b/url.c
+@@ -39,13 +39,18 @@ static const struct mapping_t UrlMap[] =
    { "imaps", 	U_IMAPS },
    { "pop",  	U_POP },
    { "pops", 	U_POPS },
@@ -29707,7 +31979,7 @@ diff -urN mutt-1.6.1/url.c mutt-1.6.1-neomutt/url.c
  {
    char *d;
  
-@@ -214,7 +219,7 @@
+@@ -214,7 +219,7 @@ int url_ciss_tostring (ciss_url_t* ciss, char* dest, size_t len, int flags)
        safe_strcat (dest, len, "//");
      len -= (l = strlen (dest)); dest += l;
  
@@ -29716,10 +31988,11 @@ diff -urN mutt-1.6.1/url.c mutt-1.6.1-neomutt/url.c
      {
        char u[STRING];
        url_pct_encode (u, sizeof (u), ciss->user);
-diff -urN mutt-1.6.1/url.h mutt-1.6.1-neomutt/url.h
---- mutt-1.6.1/url.h	2016-06-12 18:43:00.415447793 +0100
-+++ mutt-1.6.1-neomutt/url.h	2016-06-12 18:43:00.752453048 +0100
-@@ -8,9 +8,14 @@
+diff --git a/url.h b/url.h
+index 926416e..d07150f 100644
+--- a/url.h
++++ b/url.h
+@@ -8,9 +8,14 @@ typedef enum url_scheme
    U_POPS,
    U_IMAP,
    U_IMAPS,
@@ -29734,16 +32007,18 @@ diff -urN mutt-1.6.1/url.h mutt-1.6.1-neomutt/url.h
    U_UNKNOWN
  }
  url_scheme_t;
-@@ -34,5 +39,6 @@
+@@ -34,5 +39,6 @@ int url_parse_file (char *d, const char *src, size_t dl);
  int url_parse_ciss (ciss_url_t *ciss, char *src);
  int url_ciss_tostring (ciss_url_t* ciss, char* dest, size_t len, int flags);
  int url_parse_mailto (ENVELOPE *e, char **body, const char *src);
 +int url_pct_decode (char *s);
  
  #endif
-diff -urN mutt-1.6.1/version.c mutt-1.6.1-neomutt/version.c
---- mutt-1.6.1/version.c	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/version.c	2016-06-12 18:43:00.752453048 +0100
+diff --git a/version.c b/version.c
+new file mode 100644
+index 0000000..bc3546f
+--- /dev/null
++++ b/version.c
 @@ -0,0 +1,516 @@
 +/**
 + * Copyright (C) 1996-2007 Michael R. Elkins <me at mutt.org>
@@ -30261,9 +32536,11 @@ diff -urN mutt-1.6.1/version.c mutt-1.6.1-neomutt/version.c
 +	return 0;
 +}
 +
-diff -urN mutt-1.6.1/version.h mutt-1.6.1-neomutt/version.h
---- mutt-1.6.1/version.h	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/version.h	2016-06-12 18:43:00.752453048 +0100
+diff --git a/version.h b/version.h
+new file mode 100644
+index 0000000..b46ebf8
+--- /dev/null
++++ b/version.h
 @@ -0,0 +1,26 @@
 +/**
 + * Copyright (C) 2016 Richard Russon
@@ -30291,25 +32568,21 @@ diff -urN mutt-1.6.1/version.h mutt-1.6.1-neomutt/version.h
 +int feature_enabled (const char *name);
 +
 +#endif /* _VERSION_H_ */
-diff -urN mutt-1.6.1/VERSION.neo mutt-1.6.1-neomutt/VERSION.neo
---- mutt-1.6.1/VERSION.neo	1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-neomutt/VERSION.neo	2016-06-12 18:43:00.672451801 +0100
-@@ -0,0 +1 @@
-+-neo
-diff -urN mutt-1.6.1/version.sh mutt-1.6.1-neomutt/version.sh
---- mutt-1.6.1/version.sh	2016-06-12 18:43:00.415447793 +0100
-+++ mutt-1.6.1-neomutt/version.sh	2016-06-12 18:43:00.752453048 +0100
-@@ -1,68 +1,4 @@
+diff --git a/version.sh b/version.sh
+old mode 100644
+new mode 100755
+--- a/version.sh
++++ b/version.sh
+@@ -1,68 +1,9 @@
  #!/bin/sh
  
 -HG=hg
-+cat VERSION* | tr -d \\n
- 
--# Switch to directory where this script lives so that further commands are run
--# from the root directory of the source.  The script path and srcdir are double
--# quoted to allow the space character to appear in the path.
--srcdir=`dirname "$0"` && cd "$srcdir" || exit 1
 -
+ # Switch to directory where this script lives so that further commands are run
+ # from the root directory of the source.  The script path and srcdir are double
+ # quoted to allow the space character to appear in the path.
+ srcdir=`dirname "$0"` && cd "$srcdir" || exit 1
+ 
 -# Ensure that we have a repo here and that mercurial is installed.  If
 -# not, just cat the VERSION file; it contains the latest release number.
 -{ [ -d ".hg" ] && $HG >/dev/null 2>&1; } \
@@ -30366,6 +32639,7 @@ diff -urN mutt-1.6.1/version.sh mutt-1.6.1-neomutt/version.sh
 -else
 -	qdist=",mq+$qdelta"
 -fi
--
++cat VERSION* | tr -d \\n
+ 
 -echo "$tag$dist$qdist ($node)"
 -exit 0
diff --git a/debian/patches/series b/debian/patches/series
index f7b089a..548e4ba 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1,6 +1,5 @@
-neomutt-20160611.patch
+neomutt-20160723.patch
 neomutt-devel/sensible-browser.patch
-upstream/fix-version-sh.patch
 features/809802_timeout_hook.patch
 features/multiple-fcc.patch
 debian-specific/Muttrc.patch
diff --git a/debian/patches/upstream/fix-version-sh.patch b/debian/patches/upstream/fix-version-sh.patch
deleted file mode 100644
index 8de7e2a..0000000
--- a/debian/patches/upstream/fix-version-sh.patch
+++ /dev/null
@@ -1,15 +0,0 @@
-Introduced by neomutt. Forwarded and fixed upstream, cf.
-https://github.com/neomutt/neomutt/issues/74
-
---- a/version.sh
-+++ b/version.sh
-@@ -1,4 +1,9 @@
- #!/bin/sh
- 
-+# Switch to directory where this script lives so that further commands are run
-+# from the root directory of the source.  The script path and srcdir are double
-+# quoted to allow the space character to appear in the path.
-+srcdir=`dirname "$0"` && cd "$srcdir" || exit 1
-+
- cat VERSION* | tr -d \\n
- 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-mutt/mutt.git



More information about the pkg-mutt-commits mailing list