[mutt] 10/16: Update and enable all of neomutt
Faidon Liambotis
paravoid at moszumanska.debian.org
Mon Jul 4 15:51:49 UTC 2016
This is an automated email from the git hooks/post-receive script.
paravoid pushed a commit to branch experimental
in repository mutt.
commit 3ddd5e84c13de648e04dc46975454b9d7ffff28a
Author: Faidon Liambotis <paravoid at debian.org>
Date: Mon Jul 4 01:39:07 2016 +0300
Update and enable all of neomutt
Update neomutt to a newer version, 20160611.
- Enable *all* the neomutt patches now, not just a hand-picked selection.
- Use the single patch, as the broken out patches conflict with each
other.
- Drop the compressed-folders, NNTP and path_max patches, as they are now
part of neomutt.
- Update sensible-browser and multiple-fcc patches to adjusted versions
from the neomutt-upstream.
---
debian/changelog | 8 +
.../Md.etc_mailname_gethostbyname.patch | 10 +-
debian/patches/debian-specific/Muttrc.patch | 11 +-
debian/patches/features/compressed-folders.patch | 1179 -
debian/patches/features/multiple-fcc.patch | 41 +-
debian/patches/neomutt-20160611.patch | 30371 +++++++++++++++++++
debian/patches/neomutt-devel/nntp.patch | 8990 ------
.../patches/neomutt-devel/sensible-browser.patch | 43 +-
debian/patches/neomutt/01-bug-fixes.patch | 848 -
debian/patches/neomutt/02-quasi-delete.patch | 289 -
debian/patches/neomutt/03-progress.patch | 319 -
debian/patches/neomutt/04-status-color.patch | 612 -
debian/patches/neomutt/05-index-color.patch | 1119 -
debian/patches/neomutt/06-nested-if.patch | 500 -
debian/patches/neomutt/07-cond-date.patch | 789 -
debian/patches/neomutt/08-tls-sni.patch | 242 -
debian/patches/neomutt/09-sidebar.patch | 4317 ---
debian/patches/neomutt/10-notmuch.patch | 5819 ----
debian/patches/neomutt/11-ifdef.patch | 1526 -
debian/patches/neomutt/12-fmemopen.patch | 366 -
debian/patches/neomutt/13-initials.patch | 264 -
debian/patches/neomutt/14-trash.patch | 780 -
.../patches/neomutt/15-limit-current-thread.patch | 322 -
debian/patches/neomutt/16-skip-quoted.patch | 259 -
debian/patches/neomutt/README.md | 31 -
debian/patches/series | 7 +-
debian/patches/upstream/path_max.patch | 24 -
27 files changed, 30436 insertions(+), 28650 deletions(-)
diff --git a/debian/changelog b/debian/changelog
index 141aae7..32924ca 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -21,6 +21,14 @@ mutt (1.6.1-2) UNRELEASED; urgency=medium
* Migrate from our own -dbg package to the automatic -dbgsym package.
* Migrate to dh, instead of our hand-crafted old-style debhelper d/rules.
* Migrate to dh-autoreconf instead of autotools-dev.
+ * Update neomutt to a newer version, 20160611.
+ - Enable *all* the neomutt patches now, not just a hand-picked selection.
+ - Use the single patch, as the broken out patches conflict with each
+ other.
+ - Drop the compressed-folders, NNTP and path_max patches, as they are now
+ part of neomutt.
+ - Update sensible-browser and multiple-fcc patches to adjusted versions
+ from the neomutt-upstream.
-- Faidon Liambotis <paravoid at debian.org> Sun, 03 Jul 2016 22:32:37 +0200
diff --git a/debian/patches/debian-specific/Md.etc_mailname_gethostbyname.patch b/debian/patches/debian-specific/Md.etc_mailname_gethostbyname.patch
index fc33b9b..e0ff650 100644
--- a/debian/patches/debian-specific/Md.etc_mailname_gethostbyname.patch
+++ b/debian/patches/debian-specific/Md.etc_mailname_gethostbyname.patch
@@ -8,11 +8,9 @@ used, rather than calling gethostbyname() on the actual hostname.
init.c | 32 ++++++++++++++++++++++++++++++--
1 file changed, 30 insertions(+), 2 deletions(-)
-diff --git a/init.c b/init.c
-index 16b19a9..a23d861 100644
--- a/init.c
+++ b/init.c
-@@ -48,6 +48,7 @@
+@@ -51,6 +51,7 @@
#include <unistd.h>
#include <string.h>
#include <sys/utsname.h>
@@ -20,8 +18,8 @@ index 16b19a9..a23d861 100644
#include <errno.h>
#include <sys/wait.h>
#include <sys/time.h>
-@@ -2943,6 +2944,31 @@ static void mutt_srandom (void)
- srandom(seed);
+@@ -3164,6 +3165,31 @@ static int mutt_execute_commands (LIST *
+ return 0;
}
+int getmailname(char *s, size_t l)
@@ -52,7 +50,7 @@ index 16b19a9..a23d861 100644
void mutt_init (int skip_sys_rc, LIST *commands)
{
struct passwd *pw;
-@@ -3036,8 +3062,10 @@ void mutt_init (int skip_sys_rc, LIST *commands)
+@@ -3257,8 +3283,10 @@ void mutt_init (int skip_sys_rc, LIST *commands)
else
Hostname = safe_strdup (utsname.nodename);
diff --git a/debian/patches/debian-specific/Muttrc.patch b/debian/patches/debian-specific/Muttrc.patch
index 0850ed6..aee3d06 100644
--- a/debian/patches/debian-specific/Muttrc.patch
+++ b/debian/patches/debian-specific/Muttrc.patch
@@ -49,7 +49,7 @@ index 1f7012e..477c4b6 100644
# imitate the old search-body function
macro index \eb "<search>~b " "search in message bodies"
-@@ -23,14 +51,14 @@ macro index,pager,attach,compose \cb "\
+@@ -23,7 +51,7 @@ macro index,pager,attach,compose \cb "\
"call urlview to extract URLs out of a message"
# Show documentation when pressing F1
@@ -58,15 +58,16 @@ index 1f7012e..477c4b6 100644
# show the incoming mailboxes list (just like "mutt -y") and back when pressing "y"
macro index,pager y "<change-folder>?<toggle-mailboxes>" "show incoming mailboxes list"
- bind browser y exit
-
+@@ -35,7 +63,7 @@ bind browser y exit
+ # append-hook \\.gz$ "gzip -c %t >> %f"
+
# If Mutt is unable to determine your site's domain name correctly, you can
-# set the default here.
+# set the default here. (better: fix /etc/mailname)
#
# set hostname=cs.hmc.edu
-
-@@ -42,6 +70,10 @@ bind browser y exit
+
+@@ -47,6 +75,10 @@ bind browser y exit
# be undone with unmime_lookup.
mime_lookup application/octet-stream
diff --git a/debian/patches/features/compressed-folders.patch b/debian/patches/features/compressed-folders.patch
deleted file mode 100644
index 1d1a9c6..0000000
--- a/debian/patches/features/compressed-folders.patch
+++ /dev/null
@@ -1,1179 +0,0 @@
-From: Roland Rosenfeld <roland at spinnaker.de>
-Date: Tue, 15 Sep 2015 22:50:21 +0200
-Subject: compressed-folders
-
-The home page for this patch is:
-
- http://www.spinnaker.de/mutt/compressed/
-
-* Patch last synced with upstream:
- - Date: 2008-05-20
- - File: http://www.spinnaker.de/mutt/compressed/patch-1.5.18.rr.compressed.1.gz
-
-* Changes made:
- - 2008-05-20 myon: refreshed to remove hunks in auto* files
- - 2009-09-15 myon: refreshed for mutt-1.5.19
- status.c:103: add sizeof (tmp) to mutt_pretty_mailbox
- - 2009-09-15 scotton: removed doc/Muttrc for mutt-1.5.19 (only patch doc/Muttrc.head)
- - 2009-09-11 antonio: removed DefaultMagic, see 541360
- - 2010-05-31 myon: remove commented paragraph "Use folders..." in
- doc/Muttrc.head, see #578096
- - 2014-03-17 evgeni: move remove_file and restore_path declaration before
- their first use
-
-Signed-off-by: Matteo F. Vescovi <mfv at debian.org>
----
- Makefile.am | 4 +-
- compress.c | 499 ++++++++++++++++++++++++++++++++++++++++++++++++++++
- compress.h | 27 +++
- configure.ac | 5 +
- curs_main.c | 5 +
- doc/manual.xml.head | 199 +++++++++++++++++++++
- doc/muttrc.man.head | 18 ++
- hook.c | 14 ++
- init.h | 5 +
- mbox.c | 10 ++
- mutt.h | 10 ++
- mx.c | 40 +++++
- mx.h | 3 +
- po/POTFILES.in | 1 +
- po/de.po | 29 +++
- status.c | 8 +
- 17 files changed, 881 insertions(+), 2 deletions(-)
- create mode 100644 compress.c
- create mode 100644 compress.h
-
-diff --git a/Makefile.am b/Makefile.am
-index c689fb5..9475381 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -23,7 +23,7 @@ BUILT_SOURCES = keymap_defs.h patchlist.c reldate.h conststrings.c $(HCVERSION)
- bin_PROGRAMS = mutt $(DOTLOCK_TARGET) $(PGPAUX_TARGET)
- mutt_SOURCES = \
- addrbook.c alias.c attach.c base64.c browser.c buffy.c color.c \
-- crypt.c cryptglue.c \
-+ crypt.c cryptglue.c compress.c \
- commands.c complete.c compose.c copy.c curs_lib.c curs_main.c date.c \
- edit.c enter.c flags.c init.c filter.c from.c \
- getdomain.c group.c \
-@@ -60,7 +60,7 @@ EXTRA_mutt_SOURCES = account.c bcache.c crypt-gpgme.c crypt-mod-pgp-classic.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 \
-+ configure account.h compress.h \
- attach.h buffy.h charset.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 \
-diff --git a/compress.c b/compress.c
-new file mode 100644
-index 0000000..9bbf211
---- /dev/null
-+++ b/compress.c
-@@ -0,0 +1,499 @@
-+/*
-+ * Copyright (C) 1997 Alain Penders <Alain at Finale-Dev.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
-+ * 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.
-+ */
-+
-+#if HAVE_CONFIG_H
-+# include "config.h"
-+#endif
-+
-+#include "mutt.h"
-+
-+#ifdef USE_COMPRESSED
-+
-+#include "mx.h"
-+#include "mailbox.h"
-+#include "mutt_curses.h"
-+
-+#include <errno.h>
-+#include <string.h>
-+#include <unistd.h>
-+#include <sys/stat.h>
-+
-+typedef struct
-+{
-+ const char *close; /* close-hook command */
-+ const char *open; /* open-hook command */
-+ const char *append; /* append-hook command */
-+ off_t size; /* size of real folder */
-+} COMPRESS_INFO;
-+
-+
-+/*
-+ * ctx - context to lock
-+ * excl - exclusive lock?
-+ * retry - should retry if unable to lock?
-+ */
-+int mbox_lock_compressed (CONTEXT *ctx, FILE *fp, int excl, int retry)
-+{
-+ int r;
-+
-+ if ((r = mx_lock_file (ctx->realpath, fileno (fp), excl, 1, retry)) == 0)
-+ ctx->locked = 1;
-+ else if (retry && !excl)
-+ {
-+ ctx->readonly = 1;
-+ return 0;
-+ }
-+
-+ return (r);
-+}
-+
-+void mbox_unlock_compressed (CONTEXT *ctx, FILE *fp)
-+{
-+ if (ctx->locked)
-+ {
-+ fflush (fp);
-+
-+ mx_unlock_file (ctx->realpath, fileno (fp), 1);
-+ ctx->locked = 0;
-+ }
-+}
-+
-+static int is_new (const char *path)
-+{
-+ return (access (path, W_OK) != 0 && errno == ENOENT) ? 1 : 0;
-+}
-+
-+static const char* find_compress_hook (int type, const char *path)
-+{
-+ const char* c = mutt_find_hook (type, path);
-+ return (!c || !*c) ? NULL : c;
-+}
-+
-+int mutt_can_read_compressed (const char *path)
-+{
-+ return find_compress_hook (M_OPENHOOK, path) ? 1 : 0;
-+}
-+
-+/*
-+ * if the file is new, we really do not append, but create, and so use
-+ * close-hook, and not append-hook
-+ */
-+static const char* get_append_command (const char *path, const CONTEXT* ctx)
-+{
-+ COMPRESS_INFO *ci = (COMPRESS_INFO *) ctx->compressinfo;
-+ return (is_new (path)) ? ci->close : ci->append;
-+}
-+
-+int mutt_can_append_compressed (const char *path)
-+{
-+ int magic;
-+
-+ if (is_new (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;
-+ }
-+ safe_free((void**)&dir_path);
-+ return dir_valid && (find_compress_hook (M_CLOSEHOOK, path) ? 1 : 0);
-+ }
-+
-+ magic = mx_get_magic (path);
-+
-+ if (magic != 0 && magic != M_COMPRESSED)
-+ return 0;
-+
-+ return (find_compress_hook (M_APPENDHOOK, path)
-+ || (find_compress_hook (M_OPENHOOK, path)
-+ && find_compress_hook (M_CLOSEHOOK, path))) ? 1 : 0;
-+}
-+
-+/* open a compressed mailbox */
-+static COMPRESS_INFO *set_compress_info (CONTEXT *ctx)
-+{
-+ COMPRESS_INFO *ci;
-+
-+ /* Now lets uncompress this thing */
-+ ci = safe_malloc (sizeof (COMPRESS_INFO));
-+ ctx->compressinfo = (void*) ci;
-+ ci->append = find_compress_hook (M_APPENDHOOK, ctx->path);
-+ ci->open = find_compress_hook (M_OPENHOOK, ctx->path);
-+ ci->close = find_compress_hook (M_CLOSEHOOK, ctx->path);
-+ return ci;
-+}
-+
-+static void set_path (CONTEXT* ctx)
-+{
-+ char tmppath[_POSIX_PATH_MAX];
-+
-+ /* Setup the right paths */
-+ ctx->realpath = ctx->path;
-+
-+ /* Uncompress to /tmp */
-+ mutt_mktemp (tmppath, sizeof(tmppath));
-+ ctx->path = safe_malloc (strlen (tmppath) + 1);
-+ strcpy (ctx->path, tmppath);
-+}
-+
-+static int get_size (const char* path)
-+{
-+ struct stat sb;
-+ if (stat (path, &sb) != 0)
-+ return 0;
-+ return (sb.st_size);
-+}
-+
-+static void store_size (CONTEXT* ctx)
-+{
-+ COMPRESS_INFO *ci = (COMPRESS_INFO *) ctx->compressinfo;
-+ ci->size = get_size (ctx->realpath);
-+}
-+
-+static const char *
-+compresshook_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 tmp[SHORT_STRING];
-+
-+ CONTEXT *ctx = (CONTEXT *) data;
-+ switch (op)
-+ {
-+ case 'f':
-+ snprintf (tmp, sizeof (tmp), "%%%ss", fmt);
-+ snprintf (dest, destlen, tmp, ctx->realpath);
-+ break;
-+ case 't':
-+ snprintf (tmp, sizeof (tmp), "%%%ss", fmt);
-+ snprintf (dest, destlen, tmp, ctx->path);
-+ break;
-+ }
-+ return (src);
-+}
-+
-+/*
-+ * check that the command has both %f and %t
-+ * 0 means OK, -1 means error
-+ */
-+int mutt_test_compress_command (const char* cmd)
-+{
-+ return (strstr (cmd, "%f") && strstr (cmd, "%t")) ? 0 : -1;
-+}
-+
-+static char *get_compression_cmd (const char* cmd, const CONTEXT* ctx)
-+{
-+ char expanded[_POSIX_PATH_MAX];
-+ mutt_FormatString (expanded, sizeof (expanded), 0, cmd,
-+ compresshook_format_str, (unsigned long) ctx, 0);
-+ return safe_strdup (expanded);
-+}
-+
-+int mutt_check_mailbox_compressed (CONTEXT* ctx)
-+{
-+ COMPRESS_INFO *ci = (COMPRESS_INFO *) ctx->compressinfo;
-+ if (ci->size != get_size (ctx->realpath))
-+ {
-+ FREE (&ctx->compressinfo);
-+ FREE (&ctx->realpath);
-+ mutt_error _("Mailbox was corrupted!");
-+ return (-1);
-+ }
-+ return (0);
-+}
-+
-+void restore_path (CONTEXT* ctx)
-+{
-+ FREE (&ctx->path);
-+ ctx->path = ctx->realpath;
-+}
-+
-+/* remove the temporary mailbox */
-+void remove_file (CONTEXT* ctx)
-+{
-+ if (ctx->magic == M_MBOX || ctx->magic == M_MMDF)
-+ remove (ctx->path);
-+}
-+
-+int mutt_open_read_compressed (CONTEXT *ctx)
-+{
-+ char *cmd;
-+ FILE *fp;
-+ int rc;
-+
-+ COMPRESS_INFO *ci = set_compress_info (ctx);
-+ if (!ci->open) {
-+ ctx->magic = 0;
-+ FREE (&ctx->compressinfo);
-+ return (-1);
-+ }
-+ if (!ci->close || access (ctx->path, W_OK) != 0)
-+ ctx->readonly = 1;
-+
-+ set_path (ctx);
-+ store_size (ctx);
-+
-+ if (!ctx->quiet)
-+ mutt_message (_("Decompressing %s..."), ctx->realpath);
-+
-+ cmd = get_compression_cmd (ci->open, ctx);
-+ if (cmd == NULL)
-+ return (-1);
-+ dprint (2, (debugfile, "DecompressCmd: '%s'\n", cmd));
-+
-+ if ((fp = fopen (ctx->realpath, "r")) == NULL)
-+ {
-+ mutt_perror (ctx->realpath);
-+ FREE (&cmd);
-+ return (-1);
-+ }
-+ mutt_block_signals ();
-+ if (mbox_lock_compressed (ctx, fp, 0, 1) == -1)
-+ {
-+ fclose (fp);
-+ mutt_unblock_signals ();
-+ mutt_error _("Unable to lock mailbox!");
-+ FREE (&cmd);
-+ return (-1);
-+ }
-+
-+ endwin ();
-+ fflush (stdout);
-+ fprintf (stderr, _("Decompressing %s...\n"),ctx->realpath);
-+ rc = mutt_system (cmd);
-+ mbox_unlock_compressed (ctx, fp);
-+ mutt_unblock_signals ();
-+ fclose (fp);
-+
-+ if (rc)
-+ {
-+ mutt_any_key_to_continue (NULL);
-+ ctx->magic = 0;
-+ FREE (&ctx->compressinfo);
-+ 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)
-+ return (-1);
-+
-+ if (mutt_check_mailbox_compressed (ctx))
-+ return (-1);
-+
-+ ctx->magic = mx_get_magic (ctx->path);
-+
-+ return (0);
-+}
-+
-+int mutt_open_append_compressed (CONTEXT *ctx)
-+{
-+ FILE *fh;
-+ COMPRESS_INFO *ci = set_compress_info (ctx);
-+
-+ if (!get_append_command (ctx->path, ctx))
-+ {
-+ if (ci->open && ci->close)
-+ return (mutt_open_read_compressed (ctx));
-+
-+ ctx->magic = 0;
-+ FREE (&ctx->compressinfo);
-+ return (-1);
-+ }
-+
-+ set_path (ctx);
-+
-+ if (!is_new (ctx->realpath))
-+ if ((fh = fopen (ctx->path, "w")))
-+ fclose (fh);
-+ /* No error checking - the parent function will catch it */
-+
-+ return (0);
-+}
-+
-+/* close a compressed mailbox */
-+void mutt_fast_close_compressed (CONTEXT *ctx)
-+{
-+ dprint (2, (debugfile, "mutt_fast_close_compressed called on '%s'\n",
-+ ctx->path));
-+
-+ if (ctx->compressinfo)
-+ {
-+ 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);
-+
-+ restore_path (ctx);
-+ FREE (&ctx->compressinfo);
-+ }
-+}
-+
-+/* return 0 on success, -1 on failure */
-+int mutt_sync_compressed (CONTEXT* ctx)
-+{
-+ char *cmd;
-+ int rc = 0;
-+ FILE *fp;
-+ COMPRESS_INFO *ci = (COMPRESS_INFO *) ctx->compressinfo;
-+
-+ if (!ctx->quiet)
-+ mutt_message (_("Compressing %s..."), ctx->realpath);
-+
-+ cmd = get_compression_cmd (ci->close, ctx);
-+ if (cmd == NULL)
-+ return (-1);
-+
-+ if ((fp = fopen (ctx->realpath, "a")) == NULL)
-+ {
-+ mutt_perror (ctx->realpath);
-+ FREE (&cmd);
-+ return (-1);
-+ }
-+ mutt_block_signals ();
-+ if (mbox_lock_compressed (ctx, fp, 1, 1) == -1)
-+ {
-+ fclose (fp);
-+ mutt_unblock_signals ();
-+ mutt_error _("Unable to lock mailbox!");
-+ store_size (ctx);
-+ FREE (&cmd);
-+ return (-1);
-+ }
-+
-+ dprint (2, (debugfile, "CompressCommand: '%s'\n", cmd));
-+
-+ endwin ();
-+ fflush (stdout);
-+ fprintf (stderr, _("Compressing %s...\n"), ctx->realpath);
-+ if (mutt_system (cmd))
-+ {
-+ mutt_any_key_to_continue (NULL);
-+ mutt_error (_("%s: Error compressing mailbox! Original mailbox deleted, uncompressed one kept!\n"), ctx->path);
-+ rc = -1;
-+ }
-+
-+ mbox_unlock_compressed (ctx, fp);
-+ mutt_unblock_signals ();
-+ fclose (fp);
-+
-+ FREE (&cmd);
-+
-+ store_size (ctx);
-+
-+ return (rc);
-+}
-+
-+int mutt_slow_close_compressed (CONTEXT *ctx)
-+{
-+ FILE *fp;
-+ const char *append;
-+ char *cmd;
-+ COMPRESS_INFO *ci = (COMPRESS_INFO *) ctx->compressinfo;
-+
-+ dprint (2, (debugfile, "mutt_slow_close_compressed called on '%s'\n",
-+ ctx->path));
-+
-+ if (! (ctx->append
-+ && ((append = get_append_command (ctx->realpath, ctx))
-+ || (append = ci->close))))
-+ {
-+ /* if we can not or should not append, we only have to remove the */
-+ /* compressed info, because sync was already called */
-+ mutt_fast_close_compressed (ctx);
-+ return (0);
-+ }
-+
-+ if (ctx->fp)
-+ fclose (ctx->fp);
-+ ctx->fp = NULL;
-+
-+ if (!ctx->quiet)
-+ {
-+ if (append == ci->close)
-+ mutt_message (_("Compressing %s..."), ctx->realpath);
-+ else
-+ mutt_message (_("Compressed-appending to %s..."), ctx->realpath);
-+ }
-+
-+ cmd = get_compression_cmd (append, ctx);
-+ if (cmd == NULL)
-+ return (-1);
-+
-+ if ((fp = fopen (ctx->realpath, "a")) == NULL)
-+ {
-+ mutt_perror (ctx->realpath);
-+ FREE (&cmd);
-+ return (-1);
-+ }
-+ mutt_block_signals ();
-+ if (mbox_lock_compressed (ctx, fp, 1, 1) == -1)
-+ {
-+ fclose (fp);
-+ mutt_unblock_signals ();
-+ mutt_error _("Unable to lock mailbox!");
-+ FREE (&cmd);
-+ return (-1);
-+ }
-+
-+ dprint (2, (debugfile, "CompressCmd: '%s'\n", cmd));
-+
-+ endwin ();
-+ fflush (stdout);
-+
-+ if (append == ci->close)
-+ fprintf (stderr, _("Compressing %s...\n"), ctx->realpath);
-+ else
-+ fprintf (stderr, _("Compressed-appending to %s...\n"), ctx->realpath);
-+
-+ if (mutt_system (cmd))
-+ {
-+ mutt_any_key_to_continue (NULL);
-+ mutt_error (_(" %s: Error compressing mailbox! Uncompressed one kept!\n"),
-+ ctx->path);
-+ FREE (&cmd);
-+ mbox_unlock_compressed (ctx, fp);
-+ mutt_unblock_signals ();
-+ fclose (fp);
-+ return (-1);
-+ }
-+
-+ mbox_unlock_compressed (ctx, fp);
-+ mutt_unblock_signals ();
-+ fclose (fp);
-+ remove_file (ctx);
-+ restore_path (ctx);
-+ FREE (&cmd);
-+ FREE (&ctx->compressinfo);
-+
-+ return (0);
-+}
-+
-+#endif /* USE_COMPRESSED */
-diff --git a/compress.h b/compress.h
-new file mode 100644
-index 0000000..9dbf027
---- /dev/null
-+++ b/compress.h
-@@ -0,0 +1,27 @@
-+/*
-+ * Copyright (C) 1997 Alain Penders <Alain at Finale-Dev.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
-+ * 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.
-+ */
-+
-+int mutt_can_read_compressed (const char *);
-+int mutt_can_append_compressed (const char *);
-+int mutt_open_read_compressed (CONTEXT *);
-+int mutt_open_append_compressed (CONTEXT *);
-+int mutt_slow_close_compressed (CONTEXT *);
-+int mutt_sync_compressed (CONTEXT *);
-+int mutt_test_compress_command (const char *);
-+int mutt_check_mailbox_compressed (CONTEXT *);
-+void mutt_fast_close_compressed (CONTEXT *);
-diff --git a/configure.ac b/configure.ac
-index 18ba5bf..6c579dd 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -830,6 +830,11 @@ AC_ARG_ENABLE(locales-fix, AS_HELP_STRING([--enable-locales-fix],[The result of
- AC_DEFINE(LOCALES_HACK,1,[ Define if the result of isprint() is unreliable. ])
- fi])
-
-+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 support compressed folders. ])
-+ fi])
-+
- AC_ARG_WITH(exec-shell, AS_HELP_STRING([--with-exec-shell=SHELL],[Specify alternate shell (ONLY if /bin/sh is broken)]),
- [if test $withval != yes; then
- AC_DEFINE_UNQUOTED(EXECSHELL, "$withval",
-diff --git a/curs_main.c b/curs_main.c
-index 74879a5..3c253e1 100644
---- a/curs_main.c
-+++ b/curs_main.c
-@@ -1291,6 +1291,11 @@ int mutt_index_menu (void)
- {
- int check;
-
-+#ifdef USE_COMPRESSED
-+ if (Context->compressinfo && Context->realpath)
-+ mutt_str_replace (&LastFolder, Context->realpath);
-+ else
-+#endif
- mutt_str_replace (&LastFolder, Context->path);
- oldcount = Context ? Context->msgcount : 0;
-
-diff --git a/doc/manual.xml.head b/doc/manual.xml.head
-index 8840980..033abf9 100644
---- a/doc/manual.xml.head
-+++ b/doc/manual.xml.head
-@@ -6283,6 +6283,205 @@ selection. Highest priority has the mailbox given with the
-
- </chapter>
-
-+<sect1 id="compressedfolders">
-+<title>Compressed folders Support (OPTIONAL)</title>
-+
-+<para>
-+If Mutt was compiled with compressed folders support (by running the
-+<emphasis>configure</emphasis> script with the
-+<emphasis>--enable-compressed</emphasis> flag), Mutt can open folders
-+stored in an arbitrary format, provided that the user has a script to
-+convert from/to this format to one of the accepted.
-+
-+The most common use is to open compressed archived folders e.g. with
-+gzip.
-+
-+In addition, the user can provide a script that gets a folder in an
-+accepted format and appends its context to the folder in the
-+user-defined format, which may be faster than converting the entire
-+folder to the accepted format, appending to it and converting back to
-+the user-defined format.
-+
-+There are three hooks defined (<link
-+linkend="open-hook">open-hook</link>, <link
-+linkend="close-hook">close-hook</link> and <link
-+linkend="append-hook">append-hook</link>) which define commands to
-+uncompress and compress a folder and to append messages to an existing
-+compressed folder respectively.
-+
-+For example:
-+
-+<screen>
-+open-hook \\.gz$ "gzip -cd %f > %t"
-+close-hook \\.gz$ "gzip -c %t > %f"
-+append-hook \\.gz$ "gzip -c %t >> %f"
-+</screen>
-+
-+You do not have to specify all of the commands. If you omit <link
-+linkend="append-hook">append-hook</link>, the folder will be open and
-+closed again each time you will add to it. If you omit <link
-+linkend="close-hook">close-hook</link> (or give empty command) , the
-+folder will be open in the mode. If you specify <link
-+linkend="append-hook">append-hook</link> though you'll be able to
-+append to the folder.
-+
-+Note that Mutt will only try to use hooks if the file is not in one of
-+the accepted formats. In particular, if the file is empty, mutt
-+supposes it is not compressed. This is important because it allows the
-+use of programs that do not have well defined extensions. Just use
-+"." as a regexp. But this may be surprising if your
-+compressing script produces empty files. 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>
-+
-+<sect2 id="open-hook">
-+<title>Open a compressed mailbox for reading</title>
-+
-+<para>
-+Usage: <literal>open-hook</literal> <emphasis>regexp</emphasis> "<emphasis>command</emphasis>"
-+
-+The <emphasis>command</emphasis> is the command that can be used for
-+opening the folders whose names match <emphasis>regexp</emphasis>.
-+
-+The <emphasis>command</emphasis> string is the printf-like format
-+string, and it should accept two parameters: %f, which is
-+replaced with the (compressed) folder name, and %t which is
-+replaced with the name of the temporary folder to which to write.
-+
-+%f and %t can be repeated any number of times in the
-+command string, and all of the entries are replaced with the
-+appropriate folder name. In addition, %% is replaced by
-+%, as in printf, and any other %anything is left as is.
-+
-+The <emphasis>command</emphasis> should <emphasis
-+role="bold">not</emphasis> remove the original compressed file. The
-+<emphasis>command</emphasis> should return non-zero exit status if it
-+fails, so mutt knows something's wrong.
-+
-+Example:
-+
-+<screen>
-+open-hook \\.gz$ "gzip -cd %f > %t"
-+</screen>
-+
-+If the <emphasis>command</emphasis> is empty, this operation is
-+disabled for this file type.
-+</para>
-+</sect2>
-+
-+<sect2 id="close-hook">
-+<title>Write a compressed mailbox</title>
-+
-+<para>
-+Usage: <literal>close-hook</literal> <emphasis>regexp</emphasis> "<emphasis>command</emphasis>"
-+
-+This is used to close the folder that was open with the <link
-+linkend="open-hook">open-hook</link> command after some changes were
-+made to it.
-+
-+The <emphasis>command</emphasis> string is the command that can be
-+used for closing the folders whose names match
-+<emphasis>regexp</emphasis>. It has the same format as in the <link
-+linkend="open-hook">open-hook</link> command. Temporary folder in this
-+case is the folder previously produced by the <link
-+linkend="open-hook">open-hook</link> command.
-+
-+The <emphasis>command</emphasis> should <emphasis
-+role="bold">not</emphasis> remove the decompressed file. The
-+<emphasis>command</emphasis> should return non-zero exit status if it
-+fails, so mutt knows something's wrong.
-+
-+Example:
-+
-+<screen>
-+close-hook \\.gz$ "gzip -c %t > %f"
-+</screen>
-+
-+If the <emphasis>command</emphasis> is empty, this operation is
-+disabled for this file type, and the file can only be open in the
-+read-only mode.
-+
-+<link linkend="close-hook">close-hook</link> is not called when you
-+exit from the folder if the folder was not changed.
-+</para>
-+</sect2>
-+
-+<sect2 id="append-hook">
-+<title>Append a message to a compressed mailbox</title>
-+
-+<para>
-+Usage: <literal>append-hook</literal> <emphasis>regexp</emphasis> "<emphasis>command</emphasis>"
-+
-+This command is used for saving to an existing compressed folder. The
-+<emphasis>command</emphasis> is the command that can be used for
-+appending to the folders whose names match
-+<emphasis>regexp</emphasis>. It has the same format as in the <link
-+linkend="open-hook">open-hook</link> command. The temporary folder in
-+this case contains the messages that are being appended.
-+
-+The <emphasis>command</emphasis> should <emphasis
-+role="bold">not</emphasis> remove the decompressed file. The
-+<emphasis>command</emphasis> should return non-zero exit status if it
-+fails, so mutt knows something's wrong.
-+
-+Example:
-+
-+<screen>
-+append-hook \\.gz$ "gzip -c %t >> %f"
-+</screen>
-+
-+When <link linkend="append-hook">append-hook</link> is used, the folder
-+is not opened, which saves time, but this means that we can not find
-+out what the folder type is. Thus the default (<link
-+linkend="mbox-type">$mbox_type</link>) type is always
-+supposed (i.e. this is the format used for the temporary folder).
-+
-+If the file does not exist when you save to it, <link
-+linkend="close-hook">close-hook</link> is called, and not <link
-+linkend="append-hook">append-hook</link>. <link
-+linkend="append-hook">append-hook</link> is only for appending to
-+existing folders.
-+
-+If the <emphasis>command</emphasis> is empty, this operation is
-+disabled for this file type. In this case, the folder will be open and
-+closed again (using <link linkend="open-hook">open-hook</link> and
-+<link linkend="close-hook">close-hook</link>respectively) each time you
-+will add to it.
-+</para>
-+</sect2>
-+
-+<sect2>
-+<title>Encrypted folders</title>
-+
-+<para>
-+The compressed folders support can also be used to handle encrypted
-+folders. If you want to encrypt a folder with PGP, you may want to use
-+the following hooks:
-+
-+<screen>
-+open-hook \\.pgp$ "pgp -f < %f > %t"
-+close-hook \\.pgp$ "pgp -fe YourPgpUserIdOrKeyId < %t > %f"
-+</screen>
-+
-+Please note, that PGP does not support appending to an encrypted
-+folder, so there is no append-hook defined.
-+
-+If you are using GnuPG instead of PGP, you may use the following hooks
-+instead:
-+
-+<screen>
-+open-hook \\.gpg$ "gpg --decrypt < %f > %t"
-+close-hook \\.gpg$ "gpg --encrypt --recipient YourGpgUserIdOrKeyId < %t > %f"
-+</screen>
-+
-+<emphasis role="bold">Note:</emphasis> the folder is temporary stored
-+decrypted in the /tmp directory, where it can be read by your system
-+administrator. So think about the security aspects of this.
-+</para>
-+</sect2>
-+</sect1>
-+
- <chapter id="mimesupport">
- <title>Mutt's MIME Support</title>
-
-diff --git a/doc/muttrc.man.head b/doc/muttrc.man.head
-index b237c5a..90e99e6 100644
---- a/doc/muttrc.man.head
-+++ b/doc/muttrc.man.head
-@@ -354,6 +354,24 @@ specify the ID of the public key to be used when encrypting messages
- to a certain recipient. The meaning of "key ID" is to be taken
- broadly: This can be a different e-mail address, a numerical key ID,
- or even just an arbitrary search string.
-+.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.
- 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
-diff --git a/hook.c b/hook.c
-index a89b615..06f7c8e 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
-+
- #include <limits.h>
- #include <string.h>
- #include <stdlib.h>
-@@ -109,6 +113,16 @@ 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 (mutt_test_compress_command (command.data))
-+ {
-+ 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))
- )
-diff --git a/init.h b/init.h
-index 49a35fb..18fd040 100644
---- a/init.h
-+++ b/init.h
-@@ -3723,6 +3723,11 @@ 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 },
-diff --git a/mbox.c b/mbox.c
-index 95cba65..9ff8512 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
-+
- #include <sys/stat.h>
- #include <dirent.h>
- #include <string.h>
-@@ -1073,6 +1077,12 @@ bail: /* Come here in case of disaster */
- int mbox_close_mailbox (CONTEXT *ctx)
- {
- mx_unlock_file (ctx->path, fileno (ctx->fp), 1);
-+
-+#ifdef USE_COMPRESSED
-+ if (ctx->compressinfo)
-+ mutt_slow_close_compressed (ctx);
-+#endif
-+
- mutt_unblock_signals ();
- mx_fastclose_mailbox (ctx);
- return 0;
-diff --git a/mutt.h b/mutt.h
-index dfc834e..a6320d5 100644
---- a/mutt.h
-+++ b/mutt.h
-@@ -141,6 +141,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
-@@ -899,6 +904,11 @@ typedef struct _context
- int flagged; /* how many flagged messages */
- int msgnotreadyet; /* which msg "new" in pager, -1 if none */
-
-+#ifdef USE_COMPRESSED
-+ void *compressinfo; /* compressed mbox module private data */
-+ char *realpath; /* path to compressed mailbox */
-+#endif /* USE_COMPRESSED */
-+
- short magic; /* mailbox type */
-
- unsigned char rights[(RIGHTSMAX + 7)/8]; /* ACL bits */
-diff --git a/mx.c b/mx.c
-index 4d1101f..be2d0e9 100644
---- a/mx.c
-+++ b/mx.c
-@@ -30,6 +30,10 @@
- #include "keymap.h"
- #include "url.h"
-
-+#ifdef USE_COMPRESSED
-+#include "compress.h"
-+#endif
-+
- #ifdef USE_IMAP
- #include "imap.h"
- #endif
-@@ -414,6 +418,10 @@ int mx_get_magic (const char *path)
- return (-1);
- }
-
-+#ifdef USE_COMPRESSED
-+ if (magic == 0 && mutt_can_read_compressed (path))
-+ return M_COMPRESSED;
-+#endif
- return (magic);
- }
-
-@@ -453,6 +461,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 (mutt_can_append_compressed (ctx->path))
-+ mutt_open_append_compressed (ctx);
-+#endif
-+
- ctx->append = 1;
-
- #ifdef USE_IMAP
-@@ -617,6 +632,11 @@ CONTEXT *mx_open_mailbox (const char *path, int flags, CONTEXT *pctx)
-
- ctx->magic = mx_get_magic (path);
-
-+#ifdef USE_COMPRESSED
-+ if (ctx->magic == M_COMPRESSED)
-+ mutt_open_read_compressed (ctx);
-+#endif
-+
- if(ctx->magic == 0)
- mutt_error (_("%s is not a mailbox."), path);
-
-@@ -721,6 +741,10 @@ void mx_fastclose_mailbox (CONTEXT *ctx)
- mutt_free_header (&ctx->hdrs[i]);
- FREE (&ctx->hdrs);
- FREE (&ctx->v2r);
-+#ifdef USE_COMPRESSED
-+ if (ctx->compressinfo)
-+ mutt_fast_close_compressed (ctx);
-+#endif
- FREE (&ctx->path);
- FREE (&ctx->pattern);
- if (ctx->limit_pattern)
-@@ -773,6 +797,12 @@ static int sync_mailbox (CONTEXT *ctx, int *index_hint)
-
- if (tmp && tmp->new == 0)
- mutt_update_mailbox (tmp);
-+
-+#ifdef USE_COMPRESSED
-+ if (rc == 0 && ctx->compressinfo)
-+ return mutt_sync_compressed (ctx);
-+#endif
-+
- return rc;
- }
-
-@@ -1043,6 +1073,11 @@ 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->compressinfo && mutt_slow_close_compressed (ctx))
-+ return (-1);
-+#endif
-+
- mx_fastclose_mailbox (ctx);
-
- return 0;
-@@ -1369,6 +1404,11 @@ int mx_check_mailbox (CONTEXT *ctx, int *index_hint, int lock)
- {
- int rc;
-
-+#ifdef USE_COMPRESSED
-+ if (ctx->compressinfo)
-+ return mutt_check_mailbox_compressed (ctx);
-+#endif
-+
- if (ctx)
- {
- if (ctx->locked) lock = 0;
-diff --git a/mx.h b/mx.h
-index dd77ba4..d926cf6 100644
---- a/mx.h
-+++ b/mx.h
-@@ -36,6 +36,9 @@ enum
- M_MAILDIR,
- M_IMAP,
- M_POP
-+#ifdef USE_COMPRESSED
-+ , M_COMPRESSED
-+#endif
- };
-
- WHERE short DefaultMagic INITVAL (M_MBOX);
-diff --git a/po/POTFILES.in b/po/POTFILES.in
-index 2d01add..3654ad1 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
-diff --git a/po/de.po b/po/de.po
-index 4518c40..79ae088 100644
---- a/po/de.po
-+++ b/po/de.po
-@@ -5337,6 +5337,35 @@ msgstr "Extrahiere unterst
- msgid "show S/MIME options"
- msgstr "Zeige S/MIME Optionen"
-
-+#: compress.c:228 compress.c:253
-+#, c-format
-+msgid "Decompressing %s...\n"
-+msgstr "Entpacke %s...\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 "delete message(s)"
- #~ msgstr "Nachricht(en) l�schen"
-
-diff --git a/status.c b/status.c
-index 6051e3a..e8693c8 100644
---- a/status.c
-+++ b/status.c
-@@ -96,6 +96,14 @@ status_format_str (char *buf, size_t buflen, size_t col, char op, const char *sr
-
- case 'f':
- snprintf (fmt, sizeof(fmt), "%%%ss", prefix);
-+#ifdef USE_COMPRESSED
-+ if (Context && Context->compressinfo && Context->realpath)
-+ {
-+ strfcpy (tmp, Context->realpath, sizeof (tmp));
-+ mutt_pretty_mailbox (tmp, sizeof (tmp));
-+ }
-+ else
-+#endif
- if (Context && Context->path)
- {
- strfcpy (tmp, Context->path, sizeof (tmp));
---- a/version.c
-+++ b/version.c
-@@ -231,6 +231,11 @@ static struct compile_options comp_opts[
- #else
- { "ICONV_NONTRANS", 0 },
- #endif
-+#ifdef USE_COMPRESSED
-+ { "COMPRESSED", 1 },
-+#else
-+ { "COMPRESSED", 0 },
-+#endif
- #ifdef USE_DOTLOCK
- { "USE_DOTLOCK", 1 },
- #else
diff --git a/debian/patches/features/multiple-fcc.patch b/debian/patches/features/multiple-fcc.patch
index a12a338..c6d93a8 100644
--- a/debian/patches/features/multiple-fcc.patch
+++ b/debian/patches/features/multiple-fcc.patch
@@ -7,47 +7,51 @@ written by Omen Wild.
Original website: http://www.mandarb.com/mutt/
Bug asking for the inclusion: #586454
+
+Changed by Richard Russon <rich at flatcap.org> to apply on top of neomutt.
---
protos.h | 1 +
send.c | 2 +-
- sendlib.c | 30 ++++++++++++++++++++++++++++++
- 3 files changed, 32 insertions(+), 1 deletion(-)
+ sendlib.c | 32 ++++++++++++++++++++++++++++++++
+ 3 files changed, 34 insertions(+), 1 deletion(-)
diff --git a/protos.h b/protos.h
-index 5c83f82..382f9ad 100644
+index 21a3b3f..5c51adf 100644
--- a/protos.h
+++ b/protos.h
-@@ -373,6 +373,7 @@ int mutt_user_is_recipient (HEADER *);
+@@ -384,6 +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_multiple_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 *);
++int mutt_write_multiple_fcc (const char *path, HEADER *hdr, const char *msgid, int, char *, 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 *);
diff --git a/send.c b/send.c
-index 15fabe5..6a503b1 100644
+index 1a0b35d..e79c1f7 100644
--- a/send.c
+++ b/send.c
-@@ -1829,7 +1829,7 @@ full_fcc:
+@@ -1974,7 +1974,7 @@ full_fcc:
* message was first postponed.
*/
msg->received = time (NULL);
-- if (mutt_write_fcc (fcc, msg, NULL, 0, NULL) == -1)
-+ if (mutt_write_multiple_fcc (fcc, msg, NULL, 0, NULL) == -1)
+- if (mutt_write_fcc (fcc, msg, NULL, 0, NULL, &finalpath) == -1)
++ if (mutt_write_multiple_fcc (fcc, msg, NULL, 0, NULL, &finalpath) == -1)
{
/*
* Error writing FCC, we should abort sending.
diff --git a/sendlib.c b/sendlib.c
-index ffe26a8..2128de3 100644
+index 247b33a..59c48fe 100644
--- a/sendlib.c
+++ b/sendlib.c
-@@ -2687,6 +2687,36 @@ static void set_noconv_flags (BODY *b, short flag)
+@@ -2756,6 +2756,38 @@ static void set_noconv_flags (BODY *b, short flag)
}
}
+/* Handle a Fcc with multiple, comma separated entries. */
-+int mutt_write_multiple_fcc (const char *path, HEADER *hdr, const char *msgid, int post, char *fcc) {
++int mutt_write_multiple_fcc (const char *path, HEADER *hdr, const char *msgid,
++ int post, char *fcc, char **finalpath)
++{
+ char fcc_tok[_POSIX_PATH_MAX];
+ char fcc_expanded[_POSIX_PATH_MAX];
+ char *tok = NULL;
@@ -58,7 +62,7 @@ index ffe26a8..2128de3 100644
+ tok = strtok(fcc_tok, ",");
+ dprint(1, (debugfile, "Fcc: initial mailbox = '%s'\n", tok));
+ /* mutt_expand_path already called above for the first token */
-+ if((status = mutt_write_fcc (tok, hdr, NULL, 0, NULL)) != 0)
++ if((status = mutt_write_fcc (tok, hdr, NULL, 0, NULL, finalpath)) != 0)
+ return status;
+
+ while((tok = strtok(NULL, ",")) != NULL) {
@@ -68,7 +72,7 @@ index ffe26a8..2128de3 100644
+ strfcpy(fcc_expanded, tok, sizeof(fcc_expanded));
+ mutt_expand_path(fcc_expanded, sizeof(fcc_expanded));
+ dprint(1, (debugfile, " Additional mailbox expanded = '%s'\n", fcc_expanded));
-+ if((status = mutt_write_fcc (fcc_expanded, hdr, NULL, 0, NULL)) != 0)
++ if((status = mutt_write_fcc (fcc_expanded, hdr, NULL, 0, NULL, finalpath)) != 0)
+ return status;
+ }
+ }
@@ -76,6 +80,9 @@ index ffe26a8..2128de3 100644
+ return 0;
+}
+
- int mutt_write_fcc (const char *path, HEADER *hdr, const char *msgid, int post, char *fcc)
+ int mutt_write_fcc (const char *path, HEADER *hdr, const char *msgid,
+ int post, char *fcc, char **finalpath)
{
- CONTEXT f;
+--
+2.8.2
+
diff --git a/debian/patches/neomutt-20160611.patch b/debian/patches/neomutt-20160611.patch
new file mode 100644
index 0000000..9820b96
--- /dev/null
+++ b/debian/patches/neomutt-20160611.patch
@@ -0,0 +1,30371 @@
+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
++
+ 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
++
+ 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
++
+ 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;
++
++ int r = mutt_strcoll (pa->desc, pb->desc);
++
++ return ((BrowserSort & SORT_REVERSE) ? -r : r);
++}
++
+ 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;
++
++ int r = pa->all - pb->all;
++
++ return ((BrowserSort & SORT_REVERSE) ? -r : r);
++}
++
++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;
++
++ int r = pa->new - pb->new;
++
++ return ((BrowserSort & SORT_REVERSE) ? -r : r);
++}
++
+ 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;
++
++#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;
+-
++
++ 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;
++
+ 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;
++
++ switch (op)
++ {
++ case 'C':
++ snprintf (tmp, sizeof (tmp), "%%%sd", fmt);
++ snprintf (dest, destlen, tmp, folder->num + 1);
++ break;
++
++ case 'f':
++ strncpy (fn, folder->ff->name, sizeof(fn) - 1);
++ snprintf (tmp, sizeof (tmp), "%%%ss", fmt);
++ snprintf (dest, destlen, tmp, fn);
++ break;
++
++ 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;
++
++ 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, 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;
++
++ 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;
++
++ 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);
++
++ 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 @@
+ }
+
+ (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;
++
++/* mutt_buffy_check (0); */
++ init_state (state, menu);
++
++ 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;
++
++ if (!VirtIncoming)
++ return (-1);
++ mutt_buffy_check (0);
++
++ init_state (state, menu);
++
++ 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
++
++/* get list of mailboxes/subscribed newsgroups */
+ static int examine_mailboxes (MUTTMENU *menu, struct browser_state *state)
+ {
+ struct stat s;
+ char buffer[LONG_STRING];
++
++#ifdef USE_NNTP
++ if (option (OPTNEWS))
++ {
++ NNTP_SERVER *nserv = CurrentNewsSrv;
++ unsigned int i;
++
++/* mutt_buffy_check (0); */
++ init_state (state, menu);
++
++ 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
++
+ 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;
++
++ folder.ff = &((struct folder_file *) menu->data)[num];
++ folder.num = num;
++
++ mutt_FormatString (s, slen, 0, NONULL(VirtFolderFormat), folder_format_str,
++ (unsigned long) &folder, M_FORMAT_ARROWCURSOR);
++}
++#endif
++
+ 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;
+-
++
+ 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;
++
++ /* 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));
+-
++
+ #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;
++
+ 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
+-
++
+ case OP_CHANGE_DIRECTORY:
+
++#ifdef USE_NNTP
++ if (option (OPTNEWS))
++ break;
++#endif
++
+ 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;
++
++ case 5: /* (c)ount */
++ BrowserSort = SORT_COUNT;
++ break;
++
++ case 6: /* ne(w) count */
++ BrowserSort = SORT_COUNT_NEW;
++ break;
++
++ 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;
++
++#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;
++
++ rc = nntp_newsrc_parse (CurrentNewsSrv);
++ if (rc < 0)
++ break;
++
++ if (i == OP_CATCHUP)
++ nntp_data = mutt_newsgroup_catchup (CurrentNewsSrv, f->name);
++ else
++ nntp_data = mutt_newsgroup_uncatchup (CurrentNewsSrv, f->name);
++
++ if (nntp_data)
++ {
++/* FOLDER folder;
++ struct folder_file ff;
++ char buffer[_POSIX_PATH_MAX + SHORT_STRING];
++
++ 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;
++
++ case OP_LOAD_ACTIVE:
++ if (option (OPTNEWS))
++ {
++ NNTP_SERVER *nserv = CurrentNewsSrv;
++ unsigned int i;
++
++ if (nntp_newsrc_parse (nserv) < 0)
++ break;
++
++ 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);
++
++ 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;
++ }
++
++ rc = nntp_newsrc_parse (nserv);
++ if (rc < 0)
++ break;
++
++ for ( ; j < state.entrylen; j++)
++ {
++ struct folder_file *f = &state.entry[j];
++
++ 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;
++ }
++ }
++ if (i == OP_SUBSCRIBE_PATTERN)
++ {
++ unsigned int i;
++
++ 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
++
+ struct folder_file
+ {
+ mode_t mode;
+@@ -30,6 +34,8 @@
+ char *desc;
+
+ unsigned int new;
++ unsigned int all;
++
+ #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
++
+ #ifdef USE_IMAP
+ #include "imap.h"
+ #endif
+
++#ifdef USE_NOTMUCH
++#include "mutt_notmuch.h"
++#endif
++
+ #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
++
+ 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" */
++
++ while (MoreArgs (s))
++ {
++ char *desc;
++
++ mutt_extract_token (path, s, 0);
++ if (path->data && *path->data)
++ desc = safe_strdup( path->data);
++ else
++ continue;
++
++ 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;
++ }
++ return 0;
++}
++#endif
++
+ /* returns 1 if maildir has new mail */
+ static int buffy_maildir_hasnew (BUFFY* mailbox)
+ {
+@@ -357,6 +448,92 @@
+
+ return 0;
+ }
++
++#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;
++
++ snprintf (path, sizeof (path), "%s/%s", mailbox->path, dir);
++
++ dirp = opendir (path);
++ if (!dirp)
++ {
++ mailbox->magic = 0;
++ return;
++ }
++
++ while ((de = readdir (dirp)) != NULL)
++ {
++ if (*de->d_name == '.')
++ continue;
++
++ /* 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++;
++ }
++ }
++
++ closedir (dirp);
++}
++
++/**
++ * 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;
++
++ mailbox->msg_count = 0;
++ mailbox->msg_unread = 0;
++ mailbox->msg_flagged = 0;
++
++ buffy_maildir_update_dir (mailbox, "new");
++ if (mailbox->msg_count) {
++ mailbox->new = 1;
++ }
++ buffy_maildir_update_dir (mailbox, "cur");
++
++ mailbox->sb_last_checked = time (NULL);
++
++ /* make sure the updates are actually put on screen */
++ mutt_sb_draw();
++}
++
++#endif
++
+ /* 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);
++ }
++
++ /* 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;
++
++ 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++;
++}
++
++int mutt_buffy_check (int force)
++{
++ BUFFY *tmp;
++ struct stat contex_sb;
++ time_t t;
++
++ 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;
++
++ BuffyTime = t;
++ BuffyCount = 0;
++ BuffyNotify = 0;
++
++#ifdef USE_IMAP
++ BuffyCount += imap_buffy_check (force);
++#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);
++
++#ifdef USE_NOTMUCH
++ for (tmp = VirtIncoming; tmp; tmp = tmp->next)
++ buffy_check(tmp, &contex_sb);
++#endif
++
+ 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;
++
++ 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 -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
++
+ /*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
++
+ 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 *);
++
++#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_*
++
++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
++
++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
++
++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
++
++2016-04-04 Richard Russon <rich at flatcap.org>
++* Update for Mutt-1.6.0
++* No other changes in this release
++
++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).
++
++2016-03-20 Richard Russon <rich at flatcap.org>
++* Numerous small bugfixes
++* TravisCI integration
++
++2016-03-17 Richard Russon <rich at flatcap.org>
++* New Features
++ - notmuch - email search support
++ - ifdef - improvements
++
++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
++
+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
++
++* Wed Nov 25 2015 Vsevolod Volkov <vvv at mutt.org.ua>
++- fixed memory leaks
++- fixed SIGSEGV when reading hcache in some cases
++
++* 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>
++
++* 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
++
++* Thu Nov 6 2003 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.5.5.1
++
++* Wed Nov 5 2003 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.5.5
++- added space after newsgroup name in .newsrc file
++
++* 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
++
++* Thu Oct 12 2000 Vsevolod Volkov <vvv at mutt.org.ua>
++- update to 1.3.10
++- hotkey 'G' (get-message) replaced with '^G'
++
++* 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()
++
++* 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
++
++* 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
++
++* Sat Jul 29 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- update to 1.3.6
++
++* 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
++
++* Wed Jun 21 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- update to 1.3.4
++
++* Wed Jun 14 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- don't substitute current newsgroup with deleted new messages
++
++* 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
++
++* Wed May 24 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- update to 1.3.2
++
++* Sat May 20 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- update to 1.3.1
++
++* Fri May 12 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- update to 1.3
++
++* Thu May 11 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- update to 1.2
++
++* Thu May 4 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- update to 1.1.14
++
++* Sun Apr 23 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- update to 1.1.12
++
++* Fri Apr 7 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- add substitution of newsgroup with new messages by default
++
++* 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
++
++* 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
++
++* Sat Apr 1 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- remove 'X-FTN-Origin' header processing
++
++* Thu Mar 30 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- update to 1.1.11
++- update to 1.1.10
++
++* Thu Mar 23 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- fix mutt_select_newsserver()
++- remove 'toggle-mode' function
++- add 'change-newsgroup' function
++
++* Wed Mar 22 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- fix server-hook
++
++* Tue Mar 21 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- fix error 'bounce' function after 'post'
++- add 'forward to newsgroup' function
++
++* 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
++
++* Tue Mar 14 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- update to 1.1.9
++- remove deleted newsgroups from list
++
++* Mon Mar 13 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- update .newsrc in browser
++
++* Sun Mar 12 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- reload .newsrc if externally modified
++- fix active cache update
++
++* Sun Mar 5 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- update to 1.1.8
++
++* 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
++
++* Thu Mar 2 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- load list of newsgroups from cache faster
++
++* Wed Mar 1 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- update to 1.1.7
++
++* Tue Feb 29 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- fix unread messages in browser
++- fix newsrc_gen_entries()
++
++* 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()
++
++* Fri Feb 25 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- update to 1.1.5
++
++* Thu Feb 24 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- fix updating new messages in cache
++
++* Mon Feb 21 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- change default cache filenames
++- fix updating new messages in cache
++
++* Fri Feb 18 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- fix segmentation fault in news groups browser
++
++* Tue Feb 15 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- update to 1.1.4
++
++* Thu Feb 10 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
++- update to 1.1.3
++
++* 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
++
++* 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;
++
++ 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;
+
+ 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;
++ }
++
++ 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);
++
++ if (MoreArgs (s)) {
++ BUFFER temporary;
++ memset (&temporary, 0, sizeof (BUFFER));
++ mutt_extract_token (&temporary, s, 0);
++ match = atoi (temporary.data);
++ FREE(&temporary.data);
++ }
++
++ if (MoreArgs (s)) {
++ strfcpy (err->data, _("too many arguments"), err->dsize);
++ return -1;
++ }
++
++ 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
++
+ #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);
++
+ 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;
++
++ 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;
++
++#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;
++
++ strfcpy (filepart, s, sizeof (filepart));
++
++ /* 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;
++ }
++ }
++ }
++
++ for (; n < nserv->groups_num; n++)
++ {
++ NNTP_DATA *nntp_data = nserv->groups_list[n];
++
++ 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;
++ }
++ }
++ }
++
++ strcpy (s, filepart);
++ return (init ? 0 : -1);
++ }
++#endif
++
++#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
++
+ #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
++
+ 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
++
+ 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 ? */
++
++ 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);
+-
++
+ 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;
++
++ 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 @@
+ 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.
++ */
++
++#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
++ */
++
++/**
++ * 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;
++
++char echo_cmd[HUGE_STRING];
++
++/**
++ * 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;
++
++ int r = mx_lock_file (ctx->realpath, fileno (fp), excl, 1, 1);
++
++ if (r == 0) {
++ ctx->locked = 1;
++ } else if (excl == 0) {
++ ctx->readonly = 1;
++ return 0;
++ }
++
++ return r;
++}
++
++/**
++ * 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;
++
++ FREE(&ctx->path);
++ ctx->path = ctx->realpath;
++}
++
++/**
++ * 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;
++
++ if ((ctx->magic == M_MBOX) || (ctx->magic == M_MMDF)) {
++ remove (ctx->path);
++ }
++}
++
++/**
++ * 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;
++
++ if (ctx->locked) {
++ fflush (fp);
++
++ mx_unlock_file (ctx->realpath, fileno (fp), 1);
++ ctx->locked = 0;
++ }
++}
++
++/**
++ * 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;
++
++ return (access (path, W_OK) != 0 && errno == ENOENT) ? 1 : 0;
++}
++
++/**
++ * 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;
++
++ const char *c = mutt_find_hook (type, path);
++ return (!c || !*c) ? NULL : c;
++}
++
++/**
++ * 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;
++
++ COMPRESS_INFO *ci = (COMPRESS_INFO *) ctx->compress_info;
++
++ return (file_exists (path)) ? ci->append : ci->close;
++}
++
++/**
++ * 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;
++
++ COMPRESS_INFO *ci;
++
++ /* 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;
++}
++
++/**
++ * 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;
++
++ char tmppath[_POSIX_PATH_MAX];
++
++ /* Setup the right paths */
++ ctx->realpath = ctx->path;
++
++ /* Uncompress to /tmp */
++ mutt_mktemp (tmppath, sizeof(tmppath));
++ ctx->path = safe_strdup (tmppath);
++}
++
++/**
++ * 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;
++
++ struct stat sb;
++ if (stat (path, &sb) != 0)
++ return 0;
++
++ return sb.st_size;
++}
++
++/**
++ * 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;
++
++ COMPRESS_INFO *ci = (COMPRESS_INFO *) ctx->compress_info;
++ ci->size = get_size (ctx->realpath);
++}
++
++/**
++ * 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;
++
++ char tmp[SHORT_STRING];
++
++ CONTEXT *ctx = (CONTEXT *) data;
++
++ 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;
++}
++
++/**
++ * 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;
++
++ char expanded[_POSIX_PATH_MAX];
++
++ mutt_FormatString (expanded, sizeof (expanded), 0, cmd, cb_format_str, (unsigned long) ctx, 0);
++ return safe_strdup (expanded);
++}
++
++
++/**
++ * 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;
++
++ return find_hook (M_OPENHOOK, path) ? 1 : 0;
++}
++
++/**
++ * 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;
++
++ int magic;
++
++ 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);
++ }
++
++ magic = mx_get_magic (path);
++
++ if (magic != 0 && magic != M_COMPRESSED)
++ return 0;
++
++ return (find_hook (M_APPENDHOOK, path)
++ || (find_hook (M_OPENHOOK, path)
++ && find_hook (M_CLOSEHOOK, path))) ? 1 : 0;
++}
++
++/**
++ * 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;
++
++ return (strstr (cmd, "%f") && strstr (cmd, "%t")) ? 1 : 0;
++}
++
++/**
++ * 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;
++
++ COMPRESS_INFO *ci = (COMPRESS_INFO *) ctx->compress_info;
++
++ if (get_size (ctx->realpath) != ci->size) {
++ FREE(&ctx->compress_info);
++ FREE(&ctx->realpath);
++ mutt_error _("Mailbox was corrupted!");
++ return -1;
++ }
++ return 0;
++}
++
++/**
++ * comp_open_read - XXX
++ * @ctx: Mailbox to open
++ *
++ * Returns:
++ * 0: Success
++ * -1: Failure
++ */
++int
++comp_open_read (CONTEXT *ctx)
++{
++ if (!ctx)
++ return 0;
++
++ char *cmd;
++ FILE *fp;
++ int rc;
++
++ COMPRESS_INFO *ci = set_compress_info (ctx);
++ if (!ci->open) {
++ ctx->magic = 0;
++ FREE(&ctx->compress_info);
++ return -1;
++ }
++
++ if (!ci->close || access (ctx->path, W_OK) != 0)
++ ctx->readonly = 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;
++}
++
++/**
++ * comp_open_append - XXX
++ * @ctx: Mailbox to append to
++ *
++ * Returns:
++ * 0: Success
++ * -1: Failure
++ */
++int
++comp_open_append (CONTEXT *ctx)
++{
++ if (!ctx)
++ return 0;
++
++ FILE *fh;
++ COMPRESS_INFO *ci = set_compress_info (ctx);
++
++ if (!get_append_command (ctx, ctx->path)) {
++ if (ci->open && ci->close) {
++ return (comp_open_read (ctx));
++ }
++
++ ctx->magic = 0;
++ FREE(&ctx->compress_info);
++ return -1;
++ }
++
++ setup_paths (ctx);
++
++ ctx->magic = DefaultMagic;
++
++ 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 */
++
++ return 0;
++}
++
++/**
++ * comp_sync - XXX
++ * @ctx: Mailbox to sync
++ *
++ * Returns:
++ * 0: Success
++ * -1: Failure
++ */
++int
++comp_sync (CONTEXT *ctx)
++{
++ if (!ctx)
++ return 0;
++
++ char *cmd;
++ int rc = 0;
++ FILE *fp;
++ COMPRESS_INFO *ci = (COMPRESS_INFO *) ctx->compress_info;
++
++ if (!ctx->quiet)
++ mutt_message (_("Compressing %s..."), ctx->realpath);
++
++ cmd = get_compression_cmd (ctx, ci->close);
++ if (!cmd)
++ return -1;
++
++ fp = fopen (ctx->realpath, "a");
++ if (!fp) {
++ mutt_perror (ctx->realpath);
++ FREE(&cmd);
++ return -1;
++ }
++
++ 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;
++ }
++
++ dprint (2, (debugfile, "CompressCommand: '%s'\n", cmd));
++
++ 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;
++ }
++
++ unlock_mailbox (ctx, fp);
++ mutt_unblock_signals();
++ fclose (fp);
++
++ FREE(&cmd);
++
++ store_size (ctx);
++
++ return rc;
++}
++
++/**
++ * comp_fast_close - XXX
++ * @ctx: Mailbox to close
++ *
++ * close a compressed mailbox
++ */
++void
++comp_fast_close (CONTEXT *ctx)
++{
++ if (!ctx)
++ return;
++
++ dprint (2, (debugfile, "comp_fast_close called on '%s'\n",
++ ctx->path));
++
++ 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);
++
++ restore_path (ctx);
++ FREE(&ctx->compress_info);
++ }
++}
++
++/**
++ * comp_slow_close - XXX
++ * @ctx: Mailbox to close (slowly)
++ *
++ * Returns:
++ * 0: Success
++ * -1: Failure
++ */
++int
++comp_slow_close (CONTEXT *ctx)
++{
++ if (!ctx)
++ return -1;
++
++ FILE *fp;
++ const char *append;
++ char *cmd;
++ COMPRESS_INFO *ci = (COMPRESS_INFO *) ctx->compress_info;
++
++ dprint (2, (debugfile, "comp_slow_close called on '%s'\n", ctx->path));
++
++ 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;
++ }
++
++ if (ctx->fp) {
++ fclose (ctx->fp);
++ ctx->fp = NULL;
++ }
++
++ if (!ctx->quiet) {
++ if (append == ci->close) {
++ mutt_message (_("Compressing %s..."), ctx->realpath);
++ } else {
++ mutt_message (_("Compressed-appending to %s..."), ctx->realpath);
++ }
++ }
++
++ cmd = get_compression_cmd (ctx, append);
++ if (!cmd)
++ return -1;
++
++ fp = fopen (ctx->realpath, "a");
++ if (!fp) {
++ mutt_perror (ctx->realpath);
++ FREE(&cmd);
++ return -1;
++ }
++
++ 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;
++ }
++
++ dprint (2, (debugfile, "CompressCmd: '%s'\n", cmd));
++
++ endwin();
++ fflush (stdout);
++
++ 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);
++
++ 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;
++ }
++
++ unlock_mailbox (ctx, fp);
++ mutt_unblock_signals();
++ fclose (fp);
++ remove_file (ctx);
++ restore_path (ctx);
++ FREE(&cmd);
++ FREE(&ctx->compress_info);
++
++ return 0;
++}
++
+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.
++ */
++
++#ifndef _COMPRESS_H_
++#define _COMPRESS_H_
++
++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);
++
++#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
++])
++
++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"
++
++ 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)
++
++
++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)
++
+ 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
++])
++
+ 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)
++
+ 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)
++
+ 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
++
+ #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;
++ }
++
+ 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);
+-
++
+ 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
++
++ 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_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 @@
+ {
+ MESSAGE *msg;
+ int r;
+-
++
+ 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;
+-
++
+ 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
++
+ 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
++
+ /* 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;
++
++ 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 @@
+
+ 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);
++
++ _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;
++ }
++
+ 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
++
+ #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 @@
+ {
+ 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;
++
++ do {
++ found = 0;
++ null_rx = 0;
++ COLOR_LINE *color_line = ColorStatusList;
++
++ if (!buf[offset])
++ break;
++
++ while (color_line) {
++ regmatch_t pmatch[color_line->match + 1];
++
++ 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;
++ }
++
++ 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
++ }
++
++ safe_free (&lineInfo.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);
++#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);
++
++ /* 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;
++
++ 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 +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
++
+ /* 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
++
+ 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
++
++#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;
++
++ 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 +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];
++
++ 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;
++
++ if ((Sort & SORT_MASK) == SORT_THREADS)
++ mutt_sort_headers (Context, 0);
++ menu->current = oldcur->virtual;
++ menu->redraw = REDRAW_STATUS | REDRAW_INDEX;
++
++ 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;
++ }
++ 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,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;
++
+ 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:
++
++ 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)
++ {
++ 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
++
+ 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;
++
++ 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>
++
+ <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>
++
++<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>
++
++<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>
++
++<screen>
++%<x?true&false>
++%<x?%<y?%<z?xyz&xy>&x>&none>
++</screen>
++
++<para>For more examples, see <xref linkend="nested-if"/></para>
++
+ </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>
++
++<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>
+
+ <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>
++
++<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>
++
++<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>
++
++<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>
++
++<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>
++
++<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>
++
++<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>
++
++<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>
++
++</sect1>
++
+ <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>
++
++<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 +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>
++
+ <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>
++
++ <sect2 id="quasi-delete-patch">
++ <title>Patch</title>
++
++ <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>
++
++ <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="quasi-delete-intro">
++ <title>Introduction</title>
++
++ <para>
++ The <quote>quasi-delete</quote> function marks an email that should be
++ hidden from the index, but NOT deleted.
++ </para>
++
++ <para>
++ On its own, this patch isn't very useful. It forms a useful part of
++ the notmuch plugin.
++ </para>
++ </sect2>
++
++<!--
++ <sect2 id="quasi-delete-variables">
++ <title>Variables</title>
++ <para>None</para>
++ </sect2>
++-->
++
++ <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>
++
++<!--
++ <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>
++-->
++
++ <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>
++
++<sect1 id="progress">
++ <title>Progress Bar Patch</title>
++ <subtitle>Show a visual progress bar on slow operations</subtitle>
++
++ <sect2 id="progress-patch">
++ <title>Patch</title>
++
++ <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>
++
++ <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="progress-intro">
++ <title>Introduction</title>
++
++ <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>
++
++<!--
++ <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>
++-->
++
++ <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>
++
++<!--
++ <sect2 id="progress-sort">
++ <title>Sort</title>
++ <para>None</para>
++ </sect2>
++-->
++
++ <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>
++
++<sect1 id="status-color">
++ <title>Status Color Patch</title>
++ <subtitle>Custom rules for theming the status bar</subtitle>
++
++ <sect2 id="status-color-patch">
++ <title>Patch</title>
++
++ <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>
++
++ <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="status-color-intro">
++ <title>Introduction</title>
++
++ <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>
++
++ <para>
++ Unlike normal color commands, <literal>color status</literal> can now
++ take up to 2 extra parameters (regex, num).
++ </para>
++ </sect2>
++
++<!--
++ <sect2 id="status-color-variables">
++ <title>Variables</title>
++ <para>None</para>
++ </sect2>
++
++ <sect2 id="status-color-functions">
++ <title>Functions</title>
++ <para>None</para>
++ </sect2>
++-->
++
++ <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>
++
++<!--
++ <sect2 id="status-color-sort">
++ <title>Sort</title>
++ <para>None</para>
++ </sect2>
++-->
++
++ <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>
++
++<sect1 id="index-color">
++ <title>Index Color Patch</title>
++ <subtitle>Custom rules for theming the email index</subtitle>
++
++ <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>
++
++ <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>
++
++ <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="nested-if">
++ <title>Nested If Patch</title>
++ <subtitle>Allow complex nested conditions in format strings</subtitle>
++
++ <sect2 id="nested-if-patch">
++ <title>Patch</title>
++
++ <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>
++
++ <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="nested-if-intro">
++ <title>Introduction</title>
++
++ <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>
++
++ <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>
++
++<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>
++
++<screen>
++set index_format='%4C %Z %{%b %d} %-25.25n %<M?[%M] %s&%s%* %<l?%l&%c>>'
++</screen>
++
++ <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>
++
++ </sect2>
++
++ <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>
++
++<!--
++ <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>
++-->
++
++ <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>
++
++<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>
++
++ <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="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>
++
++ <para>
++ To verify TLS SNI support by a server, you can use:
++ </para>
++
++<screen>
++openssl s_client -host <imap server> -port <port> -tls1 -servername <imap server>
++</screen>
++ </sect2>
++
++<!--
++ <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>
++-->
++
++ <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>
++
++<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>
++
++<sect1 id="ifdef">
++ <title>Ifdef Patch</title>
++ <subtitle>Conditional config options</subtitle>
++
++ <sect2 id="ifdef-patch">
++ <title>Patch</title>
++
++ <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>
++
++ <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="ifdef-intro">
++ <title>Introduction</title>
++
++ <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>
++
++<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>
++
++ <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>
++
++<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.1</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="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.1</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="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>
++
++<!--
++ <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>
++-->
++
++ <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>
++
++<sect1 id="limit-current-thread">
++ <title>Limit-Current-Thread Patch</title>
++ <subtitle>Focus on one Email Thread</subtitle>
++
++ <sect2 id="limit-current-thread-patch">
++ <title>Patch</title>
++
++ <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>
++
++ <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="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>
++
++<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>
++
++<!--
++ <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>
++-->
++
++ <sect2 id="skip-quoted-muttrc">
++ <title>Muttrc</title>
++
++<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>
++
++<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>
++
++<!--
++ <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>
++ 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>
++
++<!--
++ <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="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>
++
++<!--
++ <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>
++ </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>
++
++<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>
++
+ </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>
++
++<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>
++
++<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>
++
++<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>
++
++<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.
++
++# 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
++open-hook '\.gz$' "gzip -cd '%f' > '%t'"
++close-hook '\.gz$' "gzip -c '%t' > '%f'"
++append-hook '\.gz$' "gzip -c '%t' >> '%f'"
++
++# 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'"
++
++# 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'"
++
++# 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'"
++
++# 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'"
++
++# 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'
++
++# 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
+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"
++
+ # 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.
++
++# 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.
++ifdef trash 'set trash=~/Mail/trash'
++
++# If the 'tag-pattern' function exists, bind a key to it.
++ifdef tag-pattern 'bind index <F6> tag-pattern'
++
++# If the 'imap-fetch-mail' command exists, read my IMAP config.
++ifdef imap-fetch-mail 'source ~/.mutt/imap.rc'
++
++# If the compile-time symbol 'USE_SIDEBAR' does not exist, then
++# stop reading the current config file.
++ifndef USE_SIDEBAR finish
++
++# 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.
++
++# Entire index line
++color index white black '.*'
++
++# Author name, %A %a %F %L %n
++
++# Give the author column a dark grey background
++color index_author default color234 '.*'
++
++# Highlight a particular from (~f)
++color index_author brightyellow color234 '~fRay Charles'
++
++# Message flags, %S %Z
++# Highlight the flags for flagged (~F) emails
++color index_flags default red '~F'
++
++# Subject, %s
++# Look for a particular subject (~s)
++color index_subject brightcyan default '~s\(closes #[0-9]+\)'
++
++# Number of messages in a collapsed thread, %M
++color index_collapsed default brightblue
++
++# Date field
++color index_date green default
++
++# Message label, %y %Y
++color index_label default brightgreen
++
++# Message number, %C
++color index_number red default
++
++# Message size, %c %l
++color index_size cyan default
++
++# 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.
++
++# 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)
++set index_format='%4C %Z %{%b %d} %-25.25n %s%> %<M?%M Msgs &%<l?%l Lines&%c Bytes>>'
++
++# 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>>'
++
++# 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.
++
++# 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
++color progress white red
++
++# 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.
++
++# The 'quasi-delete' function marks an email that should be hidden
++# from the index, but NOT deleted.
++bind index,pager Q quasi-delete
++
++# 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.
++
++# --------------------------------------------------------------------------
++# VARIABLES - shown with their default values
++# --------------------------------------------------------------------------
++
++# Should the Sidebar be shown?
++set sidebar_visible = no
++
++# How wide should the Sidebar be in screen columns?
++# Note: Some characters, e.g. Chinese, take up two columns each.
++set sidebar_width = 20
++
++# Should the mailbox paths be abbreviated?
++set sidebar_short_path = no
++
++# 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 the mailbox path is abbreviated, should it be indented?
++set sidebar_folder_indent = no
++
++# 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
++
++# 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'
++
++# 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
++
++# 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 = '|'
++
++# 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
++
++# 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'
++
++# --------------------------------------------------------------------------
++# 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
++
++# 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
++
++# Move the highlight to the previous mailbox containing new, or flagged,
++# mail.
++bind index,pager <F5> sidebar-prev-new
++
++# Move the highlight to the next mailbox containing new, or flagged, mail.
++bind index,pager <F6> sidebar-next-new
++
++# Toggle the visibility of the Sidebar.
++bind index,pager B sidebar-toggle-visible
++
++# --------------------------------------------------------------------------
++# 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.
++color indicator cyan black
++
++# Color of the highlighted, but not open, mailbox.
++color sidebar_highlight black color8
++
++# Color of the divider separating the Sidebar from Mutt panels
++color sidebar_divider color8 black
++
++# Color to give mailboxes containing flagged mail
++color sidebar_flagged red black
++
++# Color to give mailboxes containing new mail
++color sidebar_new green black
++
++# --------------------------------------------------------------------------
++
++# 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).
++
++# 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
++
++# '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
++color status blue white
++
++# 1 extra parameter
++# Set the color for a matching pattern
++# color status foreground background regexp
++
++# Highlight New, Deleted, or Flagged emails
++color status brightred white '(New|Del|Flag):[0-9]+'
++
++# Highlight mailbox ordering if it's different from the default
++# First, highlight anything (*/*)
++color status brightred default '\([^)]+/[^)]+\)'
++
++# Then override the color for one specific case
++color status default default '\(threads/last-date-received\)'
++
++# 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
++color status red default '\[([^]]+)\]' 1
++
++# The '1' refers to the first regex submatch, which is the inner
++# part in ()s
++
++# Highlight the mailbox
++color status brightwhite default 'Mutt: ([^ ]+)' 1
++
++# Search for 'Mutt: ' but only highlight what comes after it
++
++# 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
++
++syntax keyword muttrcCommand ifdef
++syntax keyword muttrcCommand ifndef
++syntax keyword muttrcCommand finish
++
++" 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
++
++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
++
++" 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
++
++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
++
++syntax keyword muttrcVarStr contained skipwhite xlabel_delimiter nextgroup=muttrcVarEqualsIdxFmt
++
++syntax match muttrcFunction contained "\<edit-label\>"
++
++" 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
++
++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
++
++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
++
++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
++
++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
++
++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
++
++syntax keyword muttrcColorField contained progress
++
++" 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
++
++syntax match muttrcFunction contained "\<quasi-delete\>"
++
++" 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
++
++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
++
++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
++
++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
++
++syntax keyword muttrcCommand sidebar_whitelist
++
++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\>"
++
++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
++
++" 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
++
++syntax keyword muttrcVarStr contained skipwhite trash nextgroup=muttrcVarEqualsIdxFmt
++
++syntax match muttrcFunction contained "\<purge-message\>"
++
++" 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 = 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 @@
+ 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 ();
++
++ 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 ();
++
++ replace_part (state, 0, buf);
++ }
++
++#endif
+ else
+ goto self_insert;
+ break;
+@@ -677,12 +741,6 @@
+ /* 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 -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 @@
+ #endif
+
+ #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);
+ }
+
++ 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"
+
++#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;
+
++ 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;
++
+ case M_NEW:
+
+ 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
+ }
+
+ 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 },
+
+
+ { "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 },
+
++#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 @@
+ { "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" },
++#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 },
+
+
+
+@@ -271,6 +325,27 @@
+ { "decrypt-save", OP_DECRYPT_SAVE, NULL },
+
+ { "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
++
++#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 @@
+
+ #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
+
+ 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;
+
+ WHERE char *CurrentFolder;
+ WHERE char *LastFolder;
+@@ -154,7 +174,12 @@
+ 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 +219,11 @@
+
+ WHERE unsigned short Counter INITVAL (0);
+
++#ifdef USE_NNTP
++WHERE short NewsPollTimeout;
++WHERE short NntpContext;
++#endif
++
+ 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;
+
++/* 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
++
+ #ifdef USE_IMAP
+ WHERE short ImapKeepalive;
+ WHERE short ImapPipelineDepth;
+@@ -269,6 +308,17 @@
+ 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 -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_
+
+- 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
++
++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
++
++**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:
+
+- 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 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
++
++**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.
+
+- 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.
+
+- 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.
+
+- 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 @@
+
+ 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
++
++**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.
+
+- 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 @@
+ 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 @@
+ 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
++
++### 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.
+
+ <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 @@
+ 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 -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 @@
+
+ fseeko (s->fpin, b->offset, 0);
+
++#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);
+-
++#endif
+ /* restore the prefix */
+ s->prefix = savePrefix;
+ }
+@@ -1680,6 +1707,10 @@
+
+ /* restore the original source stream */
+ safe_fclose (&s->fpin);
++#ifdef HAVE_FMEMOPEN
++ if (tempsize)
++ FREE(&temp);
++#endif
+ s->fpin = fp;
+ }
+ }
+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)
+ {
+@@ -71,6 +72,29 @@
+ return table;
+ }
+
++HASH *hash_resize (HASH *ptr, int nelem, int lower)
++{
++ HASH *table;
++ struct hash_elem *elem, *tmp;
++ int i;
++
++ table = hash_create (nelem, lower);
++
++ 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;
++}
++
+ /* table hash table to update
+ * key key to hash on
+ * data data to associate with `key'
+@@ -90,6 +114,7 @@
+ {
+ ptr->next = table->table[h];
+ table->table[h] = ptr;
++ table->curnelem++;
+ }
+ else
+ {
+@@ -112,6 +137,7 @@
+ else
+ table->table[h] = ptr;
+ ptr->next = tmp;
++ table->curnelem++;
+ }
+ 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)
++ {
++ state->last = state->last->next;
++ return state->last;
++ }
++
++ 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 *));
+
++struct hash_walk_state {
++ int index;
++ struct hash_elem *last;
++};
++
++struct hash_elem *hash_walk(const HASH *table, struct hash_walk_state *state);
++
+ #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);
+
+ 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);
++
++#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 +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);
++
++#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
+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>
+ #endif
+
++#ifdef USE_NOTMUCH
++#include "mutt_notmuch.h"
++#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;
++
++ /* only add color markers if we are operating on main index entries. */
++ if (!(flags & M_FORMAT_INDEX))
++ return 0;
++
++ if (color == MT_COLOR_INDEX) { /* buf might be uninitialized other cases */
++ len = mutt_strlen (buf);
++ buf += len;
++ buflen -= len;
++ }
++
++ if (buflen < 2)
++ return 0;
++
++ buf[0] = M_SPECIAL_INDEX;
++ buf[1] = color;
++ buf[2] = '\0';
++
++ return 2;
++}
++
+ 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;
+
+ 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 +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;
++
++ if (((T > i) || (T < (-1*i))) ^ invert)
++ optional = 0;
++ break;
++ }
+
+ p = dest;
+
+@@ -410,7 +552,10 @@
+ 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);
++
+ 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;
+
++#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
++
+ case 'H':
+ /* (Hormel) spam score */
+ if (optional)
+@@ -459,15 +619,45 @@
+
+ break;
+
++#ifdef USE_NNTP
++ case 'q':
++ mutt_format_s (dest, destlen, prefix, hdr->env->newsgroups ? hdr->env->newsgroups : "");
++ break;
++#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;
+
+ 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 +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;
+
+ case 'S':
+@@ -603,8 +807,11 @@
+
+ /* 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 +862,22 @@
+ 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
++
+ 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;
+
+ case 'X':
+@@ -694,40 +919,100 @@
+
+ case 'y':
+ if (optional)
+- optional = hdr->env->x_label ? 1 : 0;
++ optional = hdr->env->labels ? 1 : 0;
+
+- 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;
+
+- 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;
++ }
+
+ break;
++ }
++#endif
+
+ 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 @@
+ }
+ }
+ }
++
++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;
++}
++
++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;
++
++ 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"
++#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;
++ }
++ }
++#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)
+ {
+ 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;
++ }
++#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);
++ 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"));
++ }
++
++ 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 @@
+
+ int imap_account_match (const ACCOUNT* a1, const ACCOUNT* a2);
+
++/* 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;
+
+@@ -406,6 +406,7 @@
+ IMAP_CACHE *cache;
+ int read;
+ int rc;
++
+ /* 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"
+
+ #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 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
++
++
+ 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.
++ *
++ * 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;
++ }
++
++ return 1;
++}
++
++/**
++ * 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;
++
++ memset (&token, 0, sizeof (token));
++ mutt_extract_token (tmp, s, 0);
++
++ /* is the item defined as a variable? */
++ res = (mutt_option_index (tmp->data) != -1);
++
++ /* is the item a compiled-in feature? */
++ if (!res) {
++ res = feature_enabled (tmp->data);
++ }
++
++ /* 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;
++
++ for (j = 0; b[j].name; j++) {
++ if (mutt_strcmp (tmp->data, b[j].name) == 0) {
++ res = 1;
++ break;
++ }
++ }
++ }
++ }
++
++ /* 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 (!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;
++}
++
+ 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(¤tline);
+ 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.
++ */
++static int complete_all_nm_tags (const char *pt)
++{
++ 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));
++
++ nm_longrun_init(Context, FALSE);
++
++ /* 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;
++
++ /* 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;
++ }
++
++ /* 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;
++}
++
++/* 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)
++{
++ int needle_length = strlen(needle);
++ const char* haystack_end = haystack + haystack_length - needle_length;
++ const char* p;
++
++ 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;
++
++ next:;
++ }
++ return NULL;
++}
++
++/* Complete the nearest "tag:"-prefixed string previous to pos. */
++int mutt_nm_query_complete (char *buffer, size_t len, int pos, int numtabs)
++{
++ char *pt = buffer;
++ int spaces;
++
++ SKIPWS (buffer);
++ spaces = buffer - pt;
++
++ 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);
++
++ /* 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 (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);
++ }
++ 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)
++ {
++ /* 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;
++ }
++
++ 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);
++ }
++ else
++ return 0;
++
++ return 1;
++}
++#endif
++
+ 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
++
+ #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)
++{
++ char *tmp;
++
++ while (MoreArgs (s))
++ {
++ char *tag, *transform;
++
++ mutt_extract_token (b, s, 0);
++ if (b->data && *b->data)
++ tag = safe_strdup (b->data);
++ else
++ continue;
++
++ 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;
++ }
++
++ hash_insert(TagTransforms, tag, transform, 0);
++ }
++ return 0;
++}
++
++int parse_tag_formats (BUFFER *b, BUFFER *s, unsigned long data, BUFFER *err)
++{
++ char *tmp;
++
++ while (MoreArgs (s))
++ {
++ char *tag, *format;
++
++ mutt_extract_token (b, s, 0);
++ if (b->data && *b->data)
++ tag = safe_strdup (b->data);
++ else
++ continue;
++
++ mutt_extract_token (b, s, 0);
++ format = safe_strdup (b->data);
++
++ /* 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;
++ }
++
++ hash_insert(TagFormats, format, tag, 0);
++ }
++ return 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)
++{
++ char *pt = buffer;
++ int spaces; /* keep track of the number of leading spaces on the line */
++ int prefix;
++
++ SKIPWS (buffer);
++ spaces = buffer - pt;
++
++ for (pt = buffer; pt && *pt && *(pt+1); pt++);
++ for (; pt > buffer && !isspace(*(pt-1)); pt--);
++ prefix = pt - buffer;
++
++ /* first TAB. Collect all the matches */
++ if (numtabs == 1)
++ {
++ struct hash_elem *entry;
++ struct hash_walk_state state;
++
++ 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;
++
++ /* 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;
++ }
++
++ 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 label */
++ strncpy (&buffer[prefix], Completed, len - spaces);
++
++ return 1;
++}
++
+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.
++ */
++
++ { "nm_default_uri", DT_STR, R_NONE, UL &NotmuchDefaultUri, 0 },
++ /*
++ ** .pp
++ ** This variable specifies the default Notmuch database in format
++ ** notmuch://<absolute path>.
++ */
++
++ { "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
++==========================
++
++_Version 2, June 1991_
++_Copyright © 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.
++
++### Preamble
++
++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.
++
++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
++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
++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,
++distribute and/or modify the software.
++
++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
++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
++modification follow.
++
++### TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
++
++**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”.
++
++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.
++
++**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.
++
++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
++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.)
++
++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.
++
++**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.)
++
++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.
++
++**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.
++
++**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.
++
++**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.
++
++**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.
++
++**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.
++
++**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
++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
++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.
++
++### 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
++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
++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.
++
++END OF TERMS AND CONDITIONS
++
++### How to Apply These Terms to Your New Programs
++
++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 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.
++
++ <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.
++
++Also add information on how to contact you by electronic and paper mail.
++
++If the program is interactive, make it output a short notice like this
++when it starts in an interactive mode:
++
++ 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.
++
++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.
++
++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
++
++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
+
+ /* 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
+
+ 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"
+
+ #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 @@
+ -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);
+ }
+
+-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 @@
+ 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 */
++#ifdef USE_NNTP
++#define M_NEWS (1<<5) /* -g and -G */
++#endif
+
+ int main (int argc, char **argv)
+ {
++#ifdef USE_SIDEBAR
++ char folder[PATH_MAX] = "";
++#else
+ char folder[_POSIX_PATH_MAX] = "";
++#endif
+ char *subject = NULL;
+ char *includeFile = NULL;
+ char *draftFile = NULL;
+@@ -598,7 +223,7 @@
+
+ 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 +252,11 @@
+ 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 +357,20 @@
+ flags |= M_SELECT;
+ break;
+
++#ifdef USE_NNTP
++ case 'g': /* Specify a news server */
++ {
++ char buf[LONG_STRING];
++
++ snprintf (buf, sizeof (buf), "set news_server=%s", optarg);
++ commands = mutt_add_list (commands, buf);
++ }
++
++ case 'G': /* List of newsgroups */
++ flags |= M_SELECT | M_NEWS;
++ break;
++#endif
++
+ case 'z':
+ flags |= M_IGNORE;
+ 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
+ }
+
+ /* 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)))
++ {
++ mutt_endwin (Errorbuf);
++ exit (1);
++ }
++ }
++ 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
+
+-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
++
++# kz
++EXTRA_DIST += UPDATING.kz README.notmuch OPS.NOTMUCH
++
++
+ 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
+
+-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 @@
+ 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 -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"
+
++#ifdef USE_COMPRESSED
++#include "compress.h"
++#endif
++
+ #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 @@
+
+ ctx->size = sb.st_size;
+ ctx->mtime = sb.st_mtime;
++#ifdef USE_SIDEBAR
++ ctx->atime = sb.st_atime;
++#endif
+
+ #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
++
+ 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;
+
+ 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
+
+ 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;
++
++ 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];
++ }
++
++ for (; color; color = color->next)
++ if (mutt_pattern_exec (color->color_pattern, M_MATCH_FULL_ADDRESS,
++ Context, hdr))
++ return color->pair;
++
++ return 0;
++}
++
++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));
+
+ 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);
+ }
+
+ /* 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 +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));
+
+@@ -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
+
++#ifdef USE_NOTMUCH
++#include "mutt_notmuch.h"
++#endif
++
+ #define INS_SORT_THRESHOLD 6
+
+ struct maildir
+@@ -295,6 +299,48 @@
+ mhs_free_sequences (&mhs);
+ }
+
++#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;
++
++ if (!mailbox)
++ return;
++
++ if (!option (OPTSIDEBAR))
++ return;
++
++ memset (&mhs, 0, sizeof (mhs));
++
++ if (mh_read_sequences (&mhs, mailbox->path) < 0)
++ return;
++
++ mailbox->msg_count = 0;
++ mailbox->msg_unread = 0;
++ mailbox->msg_flagged = 0;
++
++ 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
++
+ 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);
+
+- 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)
++ {
++ /*
++ * 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 h;
++}
++
++/*
++ * 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;
++
++ 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);
++
+ return 0;
++
++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);
+ }
+
+-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;
++}
++
++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;
++
++ 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);
++
++#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);
++
+ 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
++
+ #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
++
++#ifdef HAVE_FGETC_UNLOCKED
++# define fgetc fgetc_unlocked
++#endif
++
+ /* 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
++
+ #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 */
++
+ /* 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 */
++
++#ifdef USE_NNTP
++ OPTSHOWNEWNEWS,
++ OPTSHOWONLYUNREAD,
++ OPTSAVEUNSUB,
++ OPTLISTGROUP,
++ OPTLOADDESC,
++ OPTXCOMMENTTO,
++#endif
++
+ /* 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
++
+ 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 */
++
+ 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
++
+ #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;
++
++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);
++ }
++}
++
++static const unsigned char base32[] = "abcdefghijklmnopqrstuvwxyz234567";
++
++void mutt_rand_base32(void *out, size_t len)
++{
++ size_t pos;
++ uint8_t *p = out;
++
++ mutt_randbuf(p, len);
++ for (pos = 0; pos < len; pos++)
++ p[pos] = base32[p[pos] % 32];
++}
++
++uint32_t mutt_rand32(void)
++{
++ uint32_t ret;
++
++ mutt_randbuf(&ret, sizeof(ret));
++ return ret;
++}
++
++uint64_t mutt_rand64(void)
++{
++ uint64_t ret;
++
++ mutt_randbuf(&ret, sizeof(ret));
++ return ret;
++}
++
++
+ 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
++
+ /* 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 = '>';
++ }
++ }
++
++ 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;
++
+ 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
++
+ 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);
++
+ #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
++
++#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"
++
++#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>
++
++#include <notmuch.h>
++
++#include "mutt_notmuch.h"
++#include "mutt_curses.h"
++
++#ifdef LIBNOTMUCH_CHECK_VERSION
++#undef LIBNOTMUCH_CHECK_VERSION
++#endif
++
++/* 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)))
++
++
++/* read whole-thread or matching messages only? */
++enum {
++ NM_QUERY_TYPE_MESGS = 1, /* default */
++ NM_QUERY_TYPE_THREADS
++};
++
++/*
++ * Parsed URI arguments
++ */
++struct uri_tag {
++ char *name;
++ char *value;
++ struct uri_tag *next;
++};
++
++/*
++ * HEADER->(nm_hdrdata *)data->tag_list node
++ */
++struct nm_hdrtag
++{
++ char *tag;
++ char *transformed;
++ struct nm_hdrtag *next;
++};
++
++/*
++ * HEADER->data
++ */
++struct nm_hdrdata {
++ char *folder;
++ char *tags;
++ char *tags_transformed;
++ struct nm_hdrtag *tag_list;
++ char *oldpath;
++ char *virtual_id;
++ int magic;
++};
++
++/*
++ * CONTEXT->data
++ */
++struct nm_ctxdata {
++ notmuch_database_t *db;
++
++ char *db_filename;
++ char *db_query;
++ int db_limit;
++ int query_type;
++
++ struct uri_tag *query_items;
++
++ progress_t progress;
++ int oldmsgcount;
++ int ignmsgcount; /* ingored messages */
++
++ unsigned int noprogress : 1,
++ longrun : 1,
++ trans : 1,
++ progress_ready : 1;
++
++};
++
++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;
++ }
++}
++
++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;
++
++ *filename = NULL;
++ *tags = NULL;
++
++ if (!p || !*(p + 3))
++ return -1;
++
++ p += 3;
++ *filename = p;
++
++ e = strchr(p, '?');
++
++ *filename = e ? e == p ? NULL : strndup(p, e - p) : safe_strdup(p);
++ if (!e)
++ return 0;
++
++ if (*filename && url_pct_decode(*filename) < 0)
++ goto err;
++ if (!e)
++ return 0; /* only filename */
++
++ ++e; /* skip '?' */
++ p = e;
++
++ while (p && *p) {
++ tag = safe_calloc(1, sizeof(struct uri_tag));
++ if (!tag)
++ goto err;
++
++ 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;
++
++ 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;
++ }
++
++ return 0;
++err:
++ FREE(&(*filename));
++ url_free_tags(*tags);
++ return -1;
++}
++
++static void free_tag_list(struct nm_hdrtag **tag_list)
++{
++ struct nm_hdrtag *tmp;
++
++ while ((tmp = *tag_list) != NULL)
++ {
++ *tag_list = tmp->next;
++ FREE(&tmp->tag);
++ FREE(&tmp->transformed);
++ FREE(&tmp);
++ }
++
++ *tag_list = 0;
++}
++
++static void free_hdrdata(struct nm_hdrdata *data)
++{
++ if (!data)
++ return;
++
++ 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);
++}
++
++static void free_ctxdata(struct nm_ctxdata *data)
++{
++ if (!data)
++ return;
++
++ dprint(1, (debugfile, "nm: freeing context data %p\n", data));
++
++ if (data->db)
++#ifdef NOTMUCH_API_3
++ notmuch_database_destroy(data->db);
++#else
++ notmuch_database_close(data->db);
++#endif
++ data->db = NULL;
++
++ FREE(&data->db_filename);
++ FREE(&data->db_query);
++ url_free_tags(data->query_items);
++ FREE(&data);
++}
++
++static struct nm_ctxdata *new_ctxdata(char *uri)
++{
++ struct nm_ctxdata *data;
++
++ if (!uri)
++ return NULL;
++
++ data = safe_calloc(1, sizeof(struct nm_ctxdata));
++ dprint(1, (debugfile, "nm: initialize context data %p\n", data));
++
++ data->db_limit = NotmuchDBLimit;
++
++ 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;
++ }
++
++ return data;
++}
++
++static int deinit_context(CONTEXT *ctx)
++{
++ int i;
++
++ if (!ctx || ctx->magic != M_NOTMUCH)
++ return -1;
++
++ for (i = 0; i < ctx->msgcount; i++) {
++ HEADER *h = ctx->hdrs[i];
++
++ if (h) {
++ free_hdrdata(h->data);
++ h->data = NULL;
++ }
++ }
++
++ free_ctxdata(ctx->data);
++ ctx->data = NULL;
++ return 0;
++}
++
++static int init_context(CONTEXT *ctx)
++{
++ if (!ctx || ctx->magic != M_NOTMUCH)
++ return -1;
++
++ if (ctx->data)
++ return 0;
++
++ ctx->data = new_ctxdata(ctx->path);
++ if (!ctx->data)
++ return -1;
++
++ ctx->mx_close = deinit_context;
++ return 0;
++}
++
++char *nm_header_get_folder(HEADER *h)
++{
++ return h && h->data ? ((struct nm_hdrdata *) h->data)->folder : NULL;
++}
++
++/* returns all unhidden tags */
++char *nm_header_get_tags(HEADER *h)
++{
++ return h && h->data ? ((struct nm_hdrdata *) h->data)->tags : NULL;
++}
++
++char *nm_header_get_tags_transformed(HEADER *h)
++{
++ return h && h->data ? ((struct nm_hdrdata *) h->data)->tags_transformed : NULL;
++}
++
++char *nm_header_get_tag_transformed(char *tag, HEADER *h)
++{
++ struct nm_hdrtag *tmp;
++
++ if (!h || !h->data)
++ return NULL;
++
++ for (tmp = ((struct nm_hdrdata *) h->data)->tag_list;
++ tmp != NULL;
++ tmp = tmp->next)
++ {
++ if (strcmp(tag, tmp->tag) == 0)
++ return tmp->transformed;
++ }
++
++ return NULL;
++}
++
++int nm_header_get_magic(HEADER *h)
++{
++ return h && h->data ? ((struct nm_hdrdata *) h->data)->magic : 0;
++}
++
++/*
++ * Returns notmuch message Id.
++ */
++static char *nm_header_get_id(HEADER *h)
++{
++ return h && h->data ? ((struct nm_hdrdata *) h->data)->virtual_id : NULL;
++}
++
++
++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;
++}
++
++
++static struct nm_ctxdata *get_ctxdata(CONTEXT *ctx)
++{
++ if (ctx && ctx->magic == M_NOTMUCH)
++ return ctx->data;
++
++ return NULL;
++}
++
++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;
++}
++
++static char *get_query_string(struct nm_ctxdata *data)
++{
++ struct uri_tag *item;
++
++ if (!data)
++ return NULL;
++ if (data->db_query)
++ return data->db_query;
++
++ for (item = data->query_items; item; item = item->next) {
++ if (!item->value || !item->name)
++ continue;
++
++ if (strcmp(item->name, "limit") == 0) {
++ if (mutt_atoi(item->value, &data->db_limit))
++ mutt_error (_("failed to parse notmuch limit: %s"), item->value);
++
++ } else if (strcmp(item->name, "type") == 0)
++ data->query_type = string_to_guery_type(item->value);
++
++ else if (strcmp(item->name, "query") == 0)
++ data->db_query = safe_strdup(item->value);
++ }
++
++ if (!data->query_type)
++ data->query_type = string_to_guery_type(NULL);
++
++ dprint(2, (debugfile, "nm: query '%s'\n", data->db_query));
++
++ return data->db_query;
++}
++
++static int get_limit(struct nm_ctxdata *data)
++{
++ return data ? data->db_limit : 0;
++}
++
++static int get_query_type(struct nm_ctxdata *data)
++{
++ return (data && data->query_type) ? data->query_type : string_to_guery_type(NULL);
++}
++
++static const char *get_db_filename(struct nm_ctxdata *data)
++{
++ char *db_filename;
++
++ if (!data)
++ return NULL;
++
++ 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;
++}
++
++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;
++
++ 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;
++
++ if (verbose && ct && ct % 2 == 0)
++ mutt_error(_("Waiting for notmuch DB... (%d sec)"), ct / 2);
++ usleep(500000);
++ ct++;
++ } while (1);
++
++ 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;
++}
++
++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);
++
++ if (db_filename)
++ data->db = do_database_open(db_filename, writable, TRUE);
++ }
++ return data->db;
++}
++
++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;
++ }
++
++ return -1;
++}
++
++/* 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;
++
++ 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;
++}
++
++static int db_trans_end(struct nm_ctxdata *data)
++{
++ if (!data || !data->db)
++ return -1;
++
++ if (data->trans) {
++ dprint(2, (debugfile, "nm: db trans end\n"));
++ data->trans = 0;
++ if (notmuch_database_end_atomic(data->db))
++ return -1;
++ }
++
++ return 0;
++}
++
++void nm_longrun_init(CONTEXT *ctx, int writable)
++{
++ struct nm_ctxdata *data = get_ctxdata(ctx);
++
++ if (data && get_db(data, writable)) {
++ data->longrun = 1;
++ dprint(2, (debugfile, "nm: long run initialized\n"));
++ }
++}
++
++void nm_longrun_done(CONTEXT *ctx)
++{
++ struct nm_ctxdata *data = get_ctxdata(ctx);
++
++ if (data && release_db(data) == 0)
++ dprint(2, (debugfile, "nm: long run deinitialized\n"));
++}
++
++static int is_longrun(struct nm_ctxdata *data)
++{
++ return data && data->longrun;
++}
++
++void nm_debug_check(CONTEXT *ctx)
++{
++ struct nm_ctxdata *data = get_ctxdata(ctx);
++
++ if (!data)
++ return;
++
++ if (data->db) {
++ dprint(1, (debugfile, "nm: ERROR: db is open, closing\n"));
++ release_db(data);
++ }
++}
++
++static int get_database_mtime(struct nm_ctxdata *data, time_t *mtime)
++{
++ char path[_POSIX_PATH_MAX];
++ struct stat st;
++
++ if (!data)
++ return -1;
++
++ snprintf(path, sizeof(path), "%s/.notmuch/xapian", get_db_filename(data));
++ dprint(2, (debugfile, "nm: checking '%s' mtime\n", path));
++
++ if (stat(path, &st))
++ return -1;
++
++ if (mtime)
++ *mtime = st.st_mtime;
++
++ return 0;
++}
++
++static void apply_exclude_tags(notmuch_query_t *query)
++{
++ char *buf, *p, *end = NULL, *tag = NULL;
++
++ if (!NotmuchExcludeTags || !*NotmuchExcludeTags)
++ return;
++ buf = safe_strdup(NotmuchExcludeTags);
++
++ 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';
++
++ 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);
++}
++
++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;
++
++ if (!data)
++ return NULL;
++
++ db = get_db(data, writable);
++ str = get_query_string(data);
++
++ if (!db || !str)
++ goto err;
++
++ q = notmuch_query_create(db, str);
++ if (!q)
++ goto err;
++
++ 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;
++}
++
++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;
++
++ safe_realloc(str, ssz + (ssz && sep ? 1 : 0) + sz + 1);
++ p = *str + ssz;
++ if (sep && ssz)
++ *p++ = sep;
++ memcpy(p, item, sz + 1);
++}
++
++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;
++
++ dprint(2, (debugfile, "nm: tags update requested (%s)\n", data->virtual_id));
++
++ for (tags = notmuch_message_get_tags(msg);
++ tags && notmuch_tags_valid(tags);
++ notmuch_tags_move_to_next(tags)) {
++
++ const char *t = notmuch_tags_get(tags);
++ const char *tt = NULL;
++
++ if (!t || !*t)
++ continue;
++
++ tt = hash_find(TagTransforms, t);
++ if (!tt)
++ tt = t;
++
++ /* 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;
++
++ /* filter out hidden tags */
++ if (NotmuchHiddenTags) {
++ char *p = strstr(NotmuchHiddenTags, t);
++ size_t xsz = p ? strlen(t) : 0;
++
++ 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, ' ');
++
++ /* expand the un-transformed tag string */
++ append_str_item(&tstr, t, ' ');
++ }
++
++ free_tag_list(&data->tag_list);
++ data->tag_list = tag_list;
++
++ if (data->tags && tstr && strcmp(data->tags, tstr) == 0) {
++ FREE(&tstr);
++ FREE(&ttstr);
++ dprint(2, (debugfile, "nm: tags unchanged\n"));
++ return 1;
++ }
++
++ /* 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;
++}
++
++/*
++ * 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;
++
++ dprint(2, (debugfile, "nm: path update requested path=%s, (%s)\n",
++ path, data->virtual_id));
++
++ 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)) {
++
++ data->magic = M_MAILDIR;
++
++ FREE(&h->path);
++ FREE(&data->folder);
++
++ p -= 3; /* skip subfolder (e.g. "new") */
++ h->path = safe_strdup(p);
++
++ for (; p > path && *(p - 1) == '/'; p--);
++
++ data->folder = strndup(path, p - path);
++
++ dprint(2, (debugfile, "nm: folder='%s', file='%s'\n", data->folder, h->path));
++ return 0;
++ }
++
++ return 1;
++}
++
++static char *get_folder_from_path(const char *path)
++{
++ char *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)) {
++
++ 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;
++ }
++}
++
++/* converts notmuch message Id to mutt message <Id> */
++static char *nm2mutt_message_id(const char *id)
++{
++ size_t sz;
++ char *mid;
++
++ if (!id)
++ return NULL;
++ sz = strlen(id) + 3;
++ mid = safe_malloc(sz);
++
++ snprintf(mid, sz, "<%s>", id);
++ return mid;
++}
++
++static int init_header(HEADER *h, const char *path, notmuch_message_t *msg)
++{
++ const char *id;
++
++ if (h->data)
++ return 0;
++
++ id = notmuch_message_get_message_id(msg);
++
++ h->data = safe_calloc(1, sizeof(struct nm_hdrdata));
++ h->free_cb = deinit_header;
++
++ /*
++ * 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 );
++
++ dprint(2, (debugfile, "nm: initialize header data: [hdr=%p, data=%p] (%s)\n",
++ h, h->data, id));
++
++ if (!h->env->message_id)
++ h->env->message_id = nm2mutt_message_id( id );
++
++ if (update_message_path(h, path))
++ return -1;
++
++ update_header_tags(h, msg);
++
++ return 0;
++}
++
++/**
++static void debug_print_filenames(notmuch_message_t *msg)
++{
++ notmuch_filenames_t *ls;
++ const char *id = notmuch_message_get_message_id(msg);
++
++ for (ls = notmuch_message_get_filenames(msg);
++ ls && notmuch_filenames_valid(ls);
++ notmuch_filenames_move_to_next(ls)) {
++
++ dprint(2, (debugfile, "nm: %s: %s\n", id, notmuch_filenames_get(ls)));
++ }
++}
++
++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)));
++ }
++}
++***/
++
++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)) {
++
++ name = notmuch_filenames_get(ls);
++ }
++
++ return name;
++}
++
++static void nm_progress_reset(CONTEXT *ctx)
++{
++ struct nm_ctxdata *data;
++
++ if (ctx->quiet)
++ return;
++
++ data = get_ctxdata(ctx);
++
++ memset(&data->progress, 0, sizeof(data->progress));
++ data->oldmsgcount = ctx->msgcount;
++ data->ignmsgcount = 0;
++ data->noprogress = 0;
++ data->progress_ready = 0;
++}
++
++static void nm_progress_update(CONTEXT *ctx, notmuch_query_t *q)
++{
++ struct nm_ctxdata *data = get_ctxdata(ctx);
++
++ if (ctx->quiet || data->noprogress)
++ return;
++
++ if (!data->progress_ready && q) {
++ unsigned count;
++ static char msg[STRING];
++ snprintf(msg, sizeof(msg), _("Reading messages..."));
++
++#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);
++}
++
++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;
++
++ /* 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;
++ }
++
++ path = get_message_last_filename(msg);
++ if (!path)
++ return;
++
++ dprint(2, (debugfile, "nm: appending message, i=%d, id=%s, path=%s\n",
++ ctx->msgcount,
++ notmuch_message_get_message_id(msg),
++ path));
++
++ 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);
++
++ 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);
++
++ dprint(1, (debugfile, "nm: not up-to-date: %s -> %s\n",
++ path, newpath));
++ }
++ }
++ FREE(&folder);
++ }
++
++ 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;
++ }
++
++ 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);
++}
++
++/*
++ * 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;
++
++ 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);
++ }
++}
++
++/*
++ * 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);
++ }
++}
++
++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;
++
++ if (!data)
++ return;
++
++ limit = get_limit(data);
++
++#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
++
++ for (; notmuch_messages_valid(msgs) &&
++ (limit == 0 || ctx->msgcount < limit);
++ notmuch_messages_move_to_next(msgs)) {
++
++ notmuch_message_t *m = notmuch_messages_get(msgs);
++ append_message(ctx, q, m, dedup);
++ notmuch_message_destroy(m);
++ }
++}
++
++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 (!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
++
++ for (; notmuch_threads_valid(threads) &&
++ (limit == 0 || ctx->msgcount < limit);
++ notmuch_threads_move_to_next(threads)) {
++
++ notmuch_thread_t *thread = notmuch_threads_get(threads);
++ append_thread(ctx, q, thread, dedup);
++ notmuch_thread_destroy(thread);
++ }
++}
++
++int nm_read_query(CONTEXT *ctx)
++{
++ notmuch_query_t *q;
++ struct nm_ctxdata *data;
++ int rc = -1;
++
++ 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;
++
++ }
++
++ if (!is_longrun(data))
++ release_db(data);
++
++ ctx->mtime = time(NULL);
++
++ mx_update_context(ctx, ctx->msgcount);
++ data->oldmsgcount = 0;
++
++ dprint(1, (debugfile, "nm: reading messages... done [rc=%d, count=%d]\n",
++ rc, ctx->msgcount));
++ return rc;
++}
++
++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;
++
++ if (!data)
++ return -1;
++ if (!(db = get_db(data, FALSE)) || !(msg = get_nm_message(db, h)))
++ goto done;
++
++ 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);
++
++ read_threads_query(ctx, q, 1, 0);
++ ctx->mtime = time(NULL);
++ rc = 0;
++
++ 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);
++
++ if (ctx->msgcount == data->oldmsgcount)
++ mutt_message _("No more messages in the thread.");
++
++ 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" */
++
++ 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;
++
++ strncpy(buf, uri, bufsz);
++ buf[bufsz - 1] = '\0';
++
++ dprint(1, (debugfile, "nm: uri from query '%s'\n", buf));
++ return buf;
++}
++
++/*
++ * 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);
++
++ dprint(2, (debugfile, "nm: find message (%s)\n", id));
++
++ if (id && db)
++ notmuch_database_find_message(db, id, &msg);
++
++ return msg;
++}
++
++static int update_tags(notmuch_message_t *msg, const char *tags)
++{
++ char *tag = NULL, *end = NULL, *p;
++ char *buf = safe_strdup(tags);
++
++ if (!buf)
++ return -1;
++
++ notmuch_message_freeze(msg);
++
++ 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';
++
++ 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;
++}
++
++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;
++
++ if (!buf || !*buf || !data)
++ return -1;
++
++ 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;
++}
++
++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;
++
++ strfcpy(folder, old, sizeof(folder));
++ p = strrchr(folder, '/');
++ if (p)
++ *p = '\0';
++
++ p++;
++ strfcpy(filename, p, sizeof(filename));
++
++ /* remove (new,cur,...) from folder path */
++ p = strrchr(folder, '/');
++ if (p)
++ *p = '\0';
++
++ /* remove old flags from filename */
++ if ((p = strchr(filename, ':')))
++ *p = '\0';
++
++ /* compose new flags */
++ maildir_flags(suffix, sizeof(suffix), h);
++
++ snprintf(newpath, newsz, "%s/%s/%s%s",
++ folder,
++ (h->read || h->old) ? "cur" : "new",
++ filename,
++ suffix);
++
++ if (strcmp(old, newpath) == 0)
++ return 1;
++
++ if (rename(old, newpath) != 0) {
++ dprint(1, (debugfile, "nm: rename(2) failed %s -> %s\n", old, newpath));
++ return -1;
++ }
++
++ return 0;
++}
++
++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;
++
++ dprint(2, (debugfile, "nm: remove filename '%s'\n", path));
++
++ 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;
++
++ /*
++ * 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)) {
++
++ path = notmuch_filenames_get(ls);
++
++ 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;
++ }
++
++ notmuch_message_destroy(msg);
++ if (trans)
++ db_trans_end(data);
++ return 0;
++}
++
++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;
++
++ if (!db || !new || !old || access(new, F_OK) != 0)
++ return -1;
++
++ dprint(1, (debugfile, "nm: rename filename, %s -> %s\n", old, new));
++ trans = db_trans_begin(data);
++ if (trans < 0)
++ return -1;
++
++ dprint(2, (debugfile, "nm: rename: add '%s'\n", new));
++ st = notmuch_database_add_message(db, new, &msg);
++
++ 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;
++ }
++
++ 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);
++
++ for (ls = notmuch_message_get_filenames(msg);
++ msg && ls && notmuch_filenames_valid(ls);
++ notmuch_filenames_move_to_next(ls)) {
++
++ const char *path = notmuch_filenames_get(ls);
++ char newpath[_POSIX_PATH_MAX];
++
++ if (strcmp(new, path) == 0)
++ continue;
++
++ dprint(2, (debugfile, "nm: rename: syncing duplicate: %s\n", path));
++
++ 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));
++ }
++
++ rc = 0;
++done:
++ if (msg)
++ notmuch_message_destroy(msg);
++ if (trans)
++ db_trans_end(data);
++ return rc;
++}
++
++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 (!data || !new)
++ return -1;
++
++ if (!old && h && h->data) {
++ nm_header_get_fullpath(h, buf, sizeof(buf));
++ old = buf;
++ }
++
++ rc = rename_filename(data, old, new, h);
++
++ if (!is_longrun(data))
++ release_db(data);
++ ctx->mtime = time(NULL);
++ return rc;
++}
++
++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;
++
++ if (!data)
++ return -1;
++
++ dprint(1, (debugfile, "nm: sync start ...\n"));
++
++ 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);
++ }
++
++ 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;
++
++ 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;
++}
++
++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
++ res = notmuch_query_count_messages(q);
++#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);
++#else
++ notmuch_database_close(db);
++#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)
++{
++ BUFFY *p;
++
++ for (p = VirtIncoming; p; p = p->next)
++ if (p->path && 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->path && 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 HEADER *get_mutt_header(CONTEXT *ctx, notmuch_message_t *msg)
++{
++ 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 (!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);
++
++ 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);
++ }
++
++ if (update_header_tags(h, m) == 0)
++ new_flags++;
++
++ notmuch_message_destroy(m);
++ }
++
++ for (i = 0; i < ctx->msgcount; i++) {
++ if (ctx->hdrs[i]->active == 0) {
++ occult = 1;
++ break;
++ }
++ }
++
++ 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);
++
++ ctx->mtime = time(NULL);
++
++ dprint(1, (debugfile, "nm: ... check done [count=%d, new_flags=%d, occult=%d]\n",
++ ctx->msgcount, new_flags, occult));
++
++ return occult ? M_REOPENED :
++ ctx->msgcount > data->oldmsgcount ? M_NEW_MAIL :
++ new_flags ? M_FLAGS : 0;
++}
++
++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);
++
++ 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);
++ }
++
++ 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;
++}
++
++/*
++ * 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;
++
++ 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"));
++
++ 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);
++ }
++
++ rc = 0;
++done:
++ if (tags)
++ notmuch_tags_destroy(tags);
++
++ if (!is_longrun(data))
++ release_db(data);
++
++ dprint(1, (debugfile, "nm: get all tags done [rc=%d tag_count=%u]\n", rc,
++ *tag_count));
++ 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;
+
+- /* 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 -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"
++#endif
+
+ #ifdef USE_IMAP
+ #include "imap.h"
+@@ -38,6 +45,14 @@
+ #include "pop.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 @@
+ }
+ #endif
+
++#ifdef USE_NNTP
++int mx_is_nntp (const char *p)
++{
++ url_scheme_t scheme;
++
++ if (!p)
++ return 0;
++
++ scheme = url_check_scheme (p);
++ if (scheme == U_NNTP || scheme == U_NNTPS)
++ return 1;
++
++ return 0;
++}
++#endif
++
++#ifdef USE_NOTMUCH
++
++int mx_is_notmuch(const char *p)
++{
++ url_scheme_t scheme;
++
++ if (!p)
++ return 0;
++
++ scheme = url_check_scheme (p);
++ if (scheme == U_NOTMUCH)
++ return 1;
++
++ return 0;
++}
++
++#endif
++
+ 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
++
++#ifdef USE_NNTP
++ if (mx_is_nntp (path))
++ return M_NNTP;
++#endif /* USE_NNTP */
++
+ if (stat (path, &st) == -1)
+ {
+ dprint (1, (debugfile, "mx_get_magic(): unable to stat %s: %s (errno %d).\n",
+@@ -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
++
+ 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);
+-
++
++#ifdef USE_COMPRESSED
++ if (ctx->magic == M_COMPRESSED)
++ comp_open_read (ctx);
++#endif
++
+ if(ctx->magic == 0)
+ mutt_error (_("%s is not a mailbox."), path);
+
+@@ -668,6 +752,18 @@
+ break;
+ #endif /* USE_POP */
+
++#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 */
++
+ default:
+ rc = -1;
+ 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);
++ }
++#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);
+
+ 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);
++ 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;
+ }
+
++/**
++ * 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;
++ }
++ }
++
++ mx_close_mailbox (ctx_trash, NULL);
++ } else {
++ mutt_error _("Can't open trash folder");
++ return -1;
++ }
++
++ return 0;
++}
++
+ /* save changes and close mailbox */
+ int mx_close_mailbox (CONTEXT *ctx, int *index_hint)
+ {
+@@ -807,13 +994,44 @@
+ return 0;
+ }
+
++#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;
++ }
++ 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
+ }
+
++#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);
+
++#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
++
+ mx_fastclose_mailbox (ctx);
+
+ 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;
+
++ 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;
+
++#ifdef USE_COMPRESSED
++ if (ctx->compress_info)
++ return comp_check_mailbox (ctx);
++#endif
++
+ if (ctx)
+ {
+ if (ctx->locked) lock = 0;
+@@ -1349,6 +1597,16 @@
+ case M_POP:
+ return (pop_check_mailbox (ctx, index_hint));
+ #endif /* USE_POP */
++
++#ifdef USE_NOTMUCH
++ case M_NOTMUCH:
++ return nm_check_database(ctx, index_hint);
++#endif
++
++#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;
+-
++
+ 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 ((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 */
+
++#ifdef USE_NNTP
++ case M_NNTP:
++ {
++ 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
+-
++
+ case M_MAILDIR:
+ {
+ r = maildir_commit_message (ctx, msg, NULL);
+ break;
+ }
+-
++
++ case M_NOTMUCH:
++ mutt_perror _("Can't write to virtual folder.");
++ break;
++
+ case M_MH:
+ {
+ r = mh_commit_message (ctx, msg, NULL);
+@@ -1474,7 +1754,7 @@
+ mutt_perror _("Can't write message");
+ r = -1;
+ }
+-
++
+ return r;
+ }
+
+@@ -1484,6 +1764,10 @@
+ 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 +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);
+ }
+
++ 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
+
+ #include "mailbox.h"
++#include "buffy.h"
+
+ /* 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
+ };
+
+ 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);
++#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 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
++
++#ifdef USE_NOTMUCH
++int mx_is_notmuch(const char *p);
++#endif
++
+ 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.
++ */
++
++#if HAVE_CONFIG_H
++#include "config.h"
++#endif
++
++#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
++
++#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>
++
++/* 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);
++
++ 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);
++
++ /* 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;
++}
++
++/* Remove all temporarily cache files */
++void nntp_acache_free (NNTP_DATA *nntp_data)
++{
++ int i;
++
++ 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);
++ }
++ }
++}
++
++/* 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);
++}
++
++/* 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;
++
++ /* if file doesn't exist, create it */
++ nserv->newsrc_fp = safe_fopen (nserv->newsrc_file, "a");
++ safe_fclose (&nserv->newsrc_fp);
++
++ /* 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;
++ }
++
++ /* 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;
++ }
++
++ if (stat (nserv->newsrc_file, &sb))
++ {
++ mutt_perror (nserv->newsrc_file);
++ nntp_newsrc_close (nserv);
++ mutt_sleep (2);
++ return -1;
++ }
++
++ if (nserv->size == sb.st_size && nserv->mtime == sb.st_mtime)
++ return 0;
++
++ nserv->size = sb.st_size;
++ nserv->mtime = sb.st_mtime;
++ nserv->newsrc_modified = 1;
++ dprint (1, (debugfile, "Parsing %s\n", nserv->newsrc_file));
++
++ /* .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];
++
++ if (!nntp_data)
++ continue;
++
++ nntp_data->subscribed = 0;
++ nntp_data->newsrc_len = 0;
++ FREE (&nntp_data->newsrc_ent);
++ }
++
++ 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;
++
++ /* find end of newsgroup name */
++ p = strpbrk (line, ":!");
++ if (!p)
++ continue;
++
++ /* ":" - subscribed, "!" - unsubscribed */
++ if (*p == ':')
++ subs++;
++ *p++ = '\0';
++
++ /* get newsgroup data */
++ nntp_data = nntp_data_find (nserv, line);
++ FREE (&nntp_data->newsrc_ent);
++
++ /* 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;
++
++ /* parse entries */
++ i = 0;
++ while (p)
++ {
++ b = p;
++
++ /* find end of entry */
++ p = strchr (p, ',');
++ if (p)
++ *p++ = '\0';
++
++ /* first-last or single number */
++ h = strchr (b, '-');
++ if (h)
++ *h++ = '\0';
++ else
++ h = b;
++
++ 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;
++}
++
++/* 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;
++
++ if (Sort != SORT_ORDER)
++ {
++ save_sort = Sort;
++ Sort = SORT_ORDER;
++ mutt_sort_headers (ctx, 0);
++ }
++
++ entries = nntp_data->newsrc_len;
++ if (!entries)
++ {
++ entries = 5;
++ nntp_data->newsrc_ent = safe_calloc (entries, sizeof (NEWSRC_ENTRY));
++ }
++
++ /* 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;
++ }
++ }
++
++ /* 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));
++
++ if (save_sort != Sort)
++ {
++ Sort = save_sort;
++ mutt_sort_headers (ctx, 0);
++ }
++}
++
++/* Update file with new contents */
++static int update_file (char *filename, char *buf)
++{
++ FILE *fp;
++ char tmpfile[_POSIX_PATH_MAX];
++ int rc = -1;
++
++ 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;
++}
++
++/* Update .newsrc file */
++int nntp_newsrc_update (NNTP_SERVER *nserv)
++{
++ char *buf;
++ size_t buflen, off;
++ unsigned int i;
++ int rc = -1;
++
++ if (!nserv)
++ return -1;
++
++ buflen = 10 * LONG_STRING;
++ buf = safe_calloc (1, buflen);
++ off = 0;
++
++ /* 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;
++
++ if (!nntp_data || !nntp_data->newsrc_ent)
++ continue;
++
++ /* 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);
++
++ /* 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';
++
++ /* 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;
++
++ 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;
++}
++
++/* 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];
++
++ /* server subdirectory */
++ if (acct)
++ {
++ 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));
++
++ snprintf (dst, dstlen, "%s/%s", NewsCacheDir, file);
++
++ /* remove trailing slash */
++ c = dst + strlen (dst) - 1;
++ if (*c == '/')
++ *c = '\0';
++ mutt_expand_path (dst, dstlen);
++}
++
++/* Make fully qualified url from newsgroup name */
++void nntp_expand_path (char *line, size_t len, ACCOUNT *acct)
++{
++ ciss_url_t url;
++
++ url.path = safe_strdup (line);
++ mutt_account_tourl (acct, &url);
++ url_ciss_tostring (&url, line, len, 0);
++ FREE (&url.path);
++}
++
++/* 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;
++
++ if (!nserv || !line)
++ return 0;
++
++ if (sscanf (line, "%s " ANUM " " ANUM " %c %[^\n]", group,
++ &last, &first, &mod, desc) < 4)
++ return 0;
++
++ 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;
++}
++
++/* 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;
++
++ 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;
++
++ if (fgets (buf, sizeof (buf), fp) == NULL ||
++ sscanf (buf, "%ld%s", &t, file) != 1 || t == 0)
++ {
++ fclose (fp);
++ return -1;
++ }
++ 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;
++}
++
++/* 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];
++
++ if (!nntp_data || nntp_data->deleted)
++ continue;
++
++ 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);
++ }
++
++ 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;
++}
++
++#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);
++}
++
++/* Open newsgroup hcache */
++header_cache_t *nntp_hcache_open (NNTP_DATA *nntp_data)
++{
++ ciss_url_t url;
++ char file[_POSIX_PATH_MAX];
++
++ 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;
++
++ 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);
++}
++
++/* 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;
++
++ if (!hc)
++ return;
++
++ /* 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;
++
++ /* clean removed headers from cache */
++ for (current = first; current <= last; current++)
++ {
++ if (current >= nntp_data->firstMessage &&
++ current <= nntp_data->lastMessage)
++ continue;
++
++ 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);
++ }
++
++ /* 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
++
++/* 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));
++#endif
++
++ 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;
++
++ 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;
++
++ 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;
++
++ 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;
++}
++
++/* %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';
++ }
++
++ /* 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;
++
++ rc = nntp_newsrc_parse (nserv);
++ if (rc < 0)
++ return NULL;
++
++ /* check for new newsgroups */
++ if (!leave_lock && nntp_check_new_groups (nserv) < 0)
++ rc = -1;
++
++ /* .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;
++ }
++
++ /* 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));
++
++ rc = nntp_open_connection (nserv);
++
++ /* 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++ = '/';
++ }
++ }
++
++ /* 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);
++ }
++
++ if (rc >= 0)
++ nntp_clear_cache (nserv);
++
++#ifdef USE_HCACHE
++ /* check cache files */
++ if (rc >= 0 && nserv->cacheable)
++ {
++ 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);
++ }
++ }
++#endif
++
++ if (rc < 0 || !leave_lock)
++ nntp_newsrc_close (nserv);
++
++ 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;
++ }
++
++ 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 ((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;
++ }
++ }
++
++ /* 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)
++ {
++ 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;
++}
++
++/* Unsubscribe newsgroup */
++NNTP_DATA *mutt_newsgroup_unsubscribe (NNTP_SERVER *nserv, char *group)
++{
++ NNTP_DATA *nntp_data;
++
++ if (!nserv || !nserv->groups_hash || !group || !*group)
++ return NULL;
++
++ nntp_data = hash_find (nserv->groups_hash, group);
++ if (!nntp_data)
++ return NULL;
++
++ nntp_data->subscribed = 0;
++ if (!option (OPTSAVEUNSUB))
++ {
++ nntp_data->newsrc_len = 0;
++ FREE (&nntp_data->newsrc_ent);
++ }
++ return nntp_data;
++}
++
++/* Catchup newsgroup */
++NNTP_DATA *mutt_newsgroup_catchup (NNTP_SERVER *nserv, char *group)
++{
++ NNTP_DATA *nntp_data;
++
++ if (!nserv || !nserv->groups_hash || !group || !*group)
++ return NULL;
++
++ nntp_data = hash_find (nserv->groups_hash, group);
++ if (!nntp_data)
++ return NULL;
++
++ 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;
++
++ for (i = 0; i < Context->msgcount; i++)
++ mutt_set_flag (Context, Context->hdrs[i], M_READ, 1);
++ }
++ return nntp_data;
++}
++
++/* Uncatchup newsgroup */
++NNTP_DATA *mutt_newsgroup_uncatchup (NNTP_SERVER *nserv, char *group)
++{
++ NNTP_DATA *nntp_data;
++
++ if (!nserv || !nserv->groups_hash || !group || !*group)
++ return NULL;
++
++ nntp_data = hash_find (nserv->groups_hash, group);
++ if (!nntp_data)
++ return NULL;
++
++ 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;
++
++ 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;
++}
++
++/* Get first newsgroup with new messages */
++void nntp_buffy (char *buf, size_t len)
++{
++ unsigned int i;
++
++ for (i = 0; i < CurrentNewsSrv->groups_num; i++)
++ {
++ NNTP_DATA *nntp_data = CurrentNewsSrv->groups_list[i];
++
++ if (!nntp_data || !nntp_data->subscribed || !nntp_data->unread)
++ continue;
++
++ if (Context && Context->magic == M_NNTP &&
++ !mutt_strcmp (nntp_data->group, ((NNTP_DATA *)Context->data)->group))
++ {
++ unsigned int i, unread = 0;
++
++ 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 @@
++/*
++ * 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.
++ */
++
++#if HAVE_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 "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 <unistd.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);
++
++ if (mutt_socket_write (conn, "CAPABILITIES\r\n") < 0 ||
++ mutt_socket_readln (buf, sizeof (buf), conn) < 0)
++ return nntp_connect_error (nserv);
++
++ /* no capabilities */
++ if (mutt_strncmp ("101", buf, 3))
++ return 1;
++ nserv->hasCAPABILITIES = 1;
++
++ /* 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);
++
++ /* 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";
++
++/* 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;
++
++ 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;
++
++ 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));
++ }
++ }
++
++ /* 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;
++ }
++
++ /* 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;
++ }
++
++ /* 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 (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);
++ }
++
++ chunk = mutt_socket_readln (nserv->overview_fmt + off,
++ buflen - off, conn);
++ if (chunk < 0)
++ {
++ FREE (&nserv->overview_fmt);
++ return nntp_connect_error (nserv);
++ }
++
++ 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;
++
++ 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;
++
++ 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++;
++ }
++
++ 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;
++ }
++
++ method = a;
++ a = strchr (a, ':');
++ if (a)
++ *a++ = '\0';
++
++ /* check authenticator */
++ if (nserv->hasCAPABILITIES)
++ {
++ char *m;
++
++ 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));
++
++ /* 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;
++
++ /* 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;
++
++ /* authenticated */
++ if (!mutt_strncmp ("281", buf, 3))
++ return 0;
++ }
++
++ /* 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;
++
++ if (mutt_sasl_client_new (conn, &saslconn) < 0)
++ {
++ dprint (1, (debugfile,
++ "nntp_auth: error allocating SASL connection.\n"));
++ continue;
++ }
++
++ 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;
++ }
++
++ mutt_message (_("Authenticating (%s)..."), method);
++ snprintf (buf, sizeof (buf), "AUTHINFO SASL %s", method);
++
++ /* 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
++
++ 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;
++ }
++ }
++
++ 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
++
++ 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
++
++ 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;
++
++ *buf = '\0';
++ } /* looping protocol */
++
++ if (rc == SASL_OK && client_len == 0 && *inbuf == '2')
++ {
++ mutt_sasl_setup_conn (conn, saslconn);
++ return 0;
++ }
++
++ /* 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;
++ }
++
++ /* server doesn't support AUTHINFO SASL, trying next method */
++ if (*inbuf == '5')
++ continue;
++#else
++ continue;
++#endif /* USE_SASL */
++ }
++
++ 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;
++}
++
++/* 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;
++
++ if (nserv->status == NNTP_OK)
++ return 0;
++ if (nserv->status == NNTP_BYE)
++ return -1;
++ nserv->status = NNTP_NONE;
++
++ if (mutt_socket_open (conn) < 0)
++ return -1;
++
++ if (mutt_socket_readln (buf, sizeof (buf), conn) < 0)
++ return nntp_connect_error (nserv);
++
++ 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;
++ }
++
++ /* get initial capabilities */
++ cap = nntp_capabilities (nserv);
++ if (cap < 0)
++ 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 (!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;
++ }
++
++ /* recheck capabilities after MODE READER */
++ if (nserv->hasCAPABILITIES)
++ {
++ cap = nntp_capabilities (nserv);
++ if (cap < 0)
++ return -1;
++ }
++ }
++
++ mutt_message (_("Connected to %s. %s"), conn->account.host,
++ posting ? _("Posting is ok.") : _("Posting is NOT ok."));
++ mutt_sleep (1);
++
++#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
++
++ /* 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;
++ }
++
++ /* authenticate */
++ if (auth && nntp_auth (nserv) < 0)
++ return -1;
++
++ /* 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;
++ }
++ }
++
++ /* attempt features */
++ if (nntp_attempt_features (nserv) < 0)
++ return -1;
++
++ nserv->status = NNTP_OK;
++ return 0;
++}
++
++/* 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];
++
++ if (nserv->status == NNTP_BYE)
++ return -1;
++
++ 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;
++ }
++
++ /* 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;
++ }
++ }
++
++ /* 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;
++ }
++
++ strfcpy (line, buf, linelen);
++ return 0;
++}
++
++/* 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;
++
++ while (!done)
++ {
++ char buf[LONG_STRING];
++ char *line;
++ unsigned int lines = 0;
++ size_t off = 0;
++ progress_t progress;
++
++ if (msg)
++ mutt_progress_init (&progress, msg, M_PROGRESS_MSG, ReadInc, -1);
++
++ 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;
++ }
++
++ line = safe_malloc (sizeof (buf));
++ rc = 0;
++
++ 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;
++ }
++
++ p = buf;
++ if (!off && buf[0] == '.')
++ {
++ if (buf[1] == '\0')
++ {
++ done = TRUE;
++ break;
++ }
++ 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 (rc == 0 && funct (line, data) < 0)
++ rc = -2;
++ off = 0;
++ }
++
++ safe_realloc (&line, off + sizeof (buf));
++ }
++ FREE (&line);
++ funct (NULL, data);
++ }
++ return rc;
++}
++
++/* Parse newsgroup description */
++static int fetch_description (char *line, void *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');
++
++ 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;
++}
++
++/* 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;
++
++ /* 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;
++
++ 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;
++}
++
++/* 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;
++
++ 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;
++
++ /* skip to end of word */
++ p = strpbrk (p, " \t");
++ if (p)
++ *p++ = '\0';
++
++ /* find colon */
++ colon = strchr (grp, ':');
++ if (!colon)
++ continue;
++ *colon++ = '\0';
++ if (sscanf (colon, ANUM, &anum) != 1)
++ continue;
++
++ 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);
++}
++
++/* 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;
++}
++
++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;
++
++/* Parse article number */
++static int fetch_numbers (char *line, void *data)
++{
++ FETCH_CTX *fc = data;
++ anum_t anum;
++
++ 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;
++}
++
++/* 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;
++
++ if (!line)
++ return 0;
++
++ /* 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));
++
++ /* out of bounds */
++ if (anum < fc->first || anum > fc->last)
++ return 0;
++
++ /* 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;
++ }
++
++ /* convert overview line to header */
++ mutt_mktemp (tempfile, sizeof (tempfile));
++ fp = safe_fopen (tempfile, "w+");
++ if (!fp)
++ return -1;
++
++ header = nntp_data->nserv->overview_fmt;
++ while (field)
++ {
++ char *b = field;
++
++ if (*header)
++ {
++ if (strstr (header, ":full") == NULL && fputs (header, fp) == EOF)
++ {
++ fclose (fp);
++ unlink (tempfile);
++ return -1;
++ }
++ header = strchr (header, '\0') + 1;
++ }
++
++ 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);
++
++ /* 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);
++
++#ifdef USE_HCACHE
++ if (fc->hc)
++ {
++ void *hdata;
++ char buf[16];
++
++ /* 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;
++
++ /* 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;
++ }
++ }
++
++ /* 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 (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);
++
++ /* progress */
++ if (!ctx->quiet)
++ mutt_progress_update (&fc->progress, anum - fc->first + 1, -1);
++ return 0;
++}
++
++/* 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
++
++ /* if empty group or nothing to do */
++ if (!last || first > last)
++ return 0;
++
++ /* 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
++
++ /* 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;
++
++ 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);
++ }
++
++#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;
++
++ /* 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);
++
++#ifdef USE_HCACHE
++ snprintf (buf, sizeof (buf), "%d", current);
++#endif
++
++ /* delete header from cache that does not exist on server */
++ if (!fc.messages[current - first])
++ continue;
++
++ /* allocate memory for headers */
++ if (ctx->msgcount >= ctx->hdrmax)
++ mx_alloc_memory (ctx);
++
++#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;
++
++ /* 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;
++ }
++
++ hdr->read = 0;
++ hdr->old = 0;
++ }
++ else
++#endif
++
++ /* don't try to fetch header from removed newsgroup */
++ if (nntp_data->deleted)
++ continue;
++
++ /* fallback to fetch overview */
++ else if (nntp_data->nserv->hasOVER || nntp_data->nserv->hasXOVER)
++ if (option (OPTLISTGROUP) && nntp_data->nserv->hasLISTGROUP)
++ break;
++ else
++ continue;
++
++ /* fetch header from server */
++ else
++ {
++ FILE *fp;
++ char tempfile[_POSIX_PATH_MAX];
++
++ mutt_mktemp (tempfile, sizeof (tempfile));
++ fp = safe_fopen (tempfile, "w+");
++ if (!fp)
++ {
++ mutt_perror (tempfile);
++ mutt_sleep (2);
++ unlink (tempfile);
++ rc = -1;
++ break;
++ }
++
++ 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;
++
++ /* invalid response */
++ if (mutt_strncmp ("423", buf, 3))
++ {
++ mutt_error ("HEAD: %s", buf);
++ mutt_sleep (2);
++ break;
++ }
++
++ /* 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;
++ }
++
++ /* 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);
++ }
++
++ /* 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 (!option (OPTLISTGROUP) || !nntp_data->nserv->hasLISTGROUP)
++ current = first_over;
++
++ /* 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);
++ }
++ }
++
++ if (ctx->msgcount > oldmsgcount)
++ mx_update_context (ctx, ctx->msgcount - oldmsgcount);
++
++ FREE (&fc.messages);
++ if (rc != 0)
++ return -1;
++ mutt_clear_error ();
++ return 0;
++}
++
++/* 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;
++
++ 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;
++ }
++
++ 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;
++
++ /* 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;
++ }
++
++ mutt_bit_unset (ctx->rights, M_ACL_INSERT);
++ if (!nntp_data->newsrc_ent && !nntp_data->subscribed &&
++ !option (OPTSAVEUNSUB))
++ ctx->readonly = 1;
++
++ /* 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;
++ }
++
++ /* 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);
++ }
++
++ /* 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;
++
++ /* 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);
++ }
++ }
++
++ 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);
++
++ /* 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;
++}
++
++/* 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;
++
++ /* 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;
++
++ /* 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;
++ }
++ }
++
++ /* 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 (!acache->path)
++ mutt_bcache_commit (nntp_data->bcache, article);
++ }
++
++ /* 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);
++
++ mutt_free_envelope (&hdr->env);
++ hdr->env = mutt_read_rfc822_header (msg->fp, hdr, 0, 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);
++
++ /* 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);
++
++ /* 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);
++
++ rewind (msg->fp);
++ mutt_clear_error();
++ return 0;
++}
++
++/* Post article */
++int nntp_post (const char *msg) {
++ NNTP_DATA *nntp_data, nntp_tmp;
++ FILE *fp;
++ char buf[LONG_STRING];
++ size_t len;
++
++ if (Context && Context->magic == M_NNTP)
++ nntp_data = Context->data;
++ else
++ {
++ CurrentNewsSrv = nntp_select_server (NewsServer, 0);
++ if (!CurrentNewsSrv)
++ return -1;
++
++ nntp_data = &nntp_tmp;
++ nntp_data->nserv = CurrentNewsSrv;
++ nntp_data->group = NULL;
++ }
++
++ fp = safe_fopen (msg, "r");
++ if (!fp)
++ {
++ mutt_perror (msg);
++ return -1;
++ }
++
++ 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;
++ }
++
++ 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);
++
++ 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;
++}
++
++/* 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
++
++ /* check for new articles */
++ nntp_data->nserv->check_time = 0;
++ rc = nntp_check_mailbox (ctx, 1);
++ if (rc)
++ return rc;
++
++#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];
++
++ 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);
++ }
++
++#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
++ }
++
++#ifdef USE_HCACHE
++ if (hc)
++ {
++ mutt_hcache_close (hc);
++ nntp_data->lastCached = nntp_data->lastLoaded;
++ }
++#endif
++
++ /* save .newsrc entries */
++ nntp_newsrc_gen_entries (ctx);
++ nntp_newsrc_update (nntp_data->nserv);
++ nntp_newsrc_close (nntp_data->nserv);
++ return 0;
++}
++
++/* Free up memory associated with the newsgroup context */
++int nntp_fastclose_mailbox (CONTEXT *ctx)
++{
++ NNTP_DATA *nntp_data = ctx->data, *nntp_tmp;
++
++ if (!nntp_data)
++ return 0;
++
++ nntp_acache_free (nntp_data);
++ if (!nntp_data->nserv || !nntp_data->nserv->groups_hash || !nntp_data->group)
++ return 0;
++
++ 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;
++
++ 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;
++
++ 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;
++}
++
++/* 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;
++
++ 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;
++
++ 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 (option (OPTLOADDESC) &&
++ get_description (&nntp_data, "*", _("Loading descriptions...")) < 0)
++ return -1;
++
++ for (i = 0; i < nserv->groups_num; i++)
++ {
++ NNTP_DATA *nntp_data = nserv->groups_list[i];
++
++ 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;
++}
++
++/* 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;
++
++ /* 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;
++
++ /* 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;
++
++ /* 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;
++}
++
++/* 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;
++
++ if (nserv->check_time + NewsPollTimeout > now)
++ return 0;
++
++ mutt_message _("Checking for new messages...");
++ if (nntp_newsrc_parse (nserv) < 0)
++ return -1;
++
++ 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);
++
++ /* 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;
++
++ 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;
++ }
++
++ /* .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;
++
++ 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
++
++ /* update flags according to .newsrc */
++ for (i = j = 0; i < ctx->msgcount; i++)
++ {
++ int flagged = 0;
++ anum = NHDR (ctx->hdrs[i])->article_num;
++
++#ifdef USE_HCACHE
++ /* check hcache for flagged and deleted flags */
++ if (hc)
++ {
++ if (anum >= first && anum <= nntp_data->lastLoaded)
++ messages[anum - first] = 1;
++
++ snprintf (buf, sizeof (buf), "%d", anum);
++ hdata = mutt_hcache_fetch (hc, buf, strlen);
++ if (hdata)
++ {
++ int 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);
++
++ /* 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];
++ }
++
++#ifdef USE_HCACHE
++ ctx->msgcount = j;
++
++ /* restore headers without "deleted" flag */
++ for (anum = first; anum <= nntp_data->lastLoaded; anum++)
++ {
++ if (messages[anum - first])
++ continue;
++
++ 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);
++
++ 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;
++ }
++
++ 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
++
++ nserv->newsrc_modified = 0;
++ ret = M_REOPENED;
++ }
++
++ /* 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);
++
++ 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);
++ }
++
++ /* 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;
++ }
++
++#ifdef USE_HCACHE
++ mutt_hcache_close (hc);
++#endif
++ if (ret || !leave_lock)
++ nntp_newsrc_close (nserv);
++ mutt_clear_error ();
++ return ret;
++}
++
++/* 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 (!nserv || !nserv->newgroups_time)
++ return -1;
++
++ /* 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 (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;
++
++ /* 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;
++ }
++
++ /* new groups found */
++ rc = 0;
++ if (nserv->groups_num != i)
++ {
++ nserv->newgroups_time = now;
++
++ /* loading descriptions */
++ if (option (OPTLOADDESC))
++ {
++ unsigned int count = 0;
++ progress_t progress;
++
++ 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 (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;
++}
++
++/* 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;
++
++ mutt_mktemp (tempfile, sizeof (tempfile));
++ fp = safe_fopen (tempfile, "w+");
++ if (!fp)
++ {
++ mutt_perror (tempfile);
++ unlink (tempfile);
++ return -1;
++ }
++
++ 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;
++ }
++
++ /* 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);
++
++ /* 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);
++ }
++
++ /* 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;
++}
++
++typedef struct
++{
++ CONTEXT *ctx;
++ unsigned int num;
++ unsigned int max;
++ anum_t *child;
++} CHILD_CTX;
++
++/* Parse XPAT line */
++static int fetch_children (char *line, void *data)
++{
++ CHILD_CTX *cc = data;
++ anum_t anum;
++ unsigned int i;
++
++ 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;
++}
++
++/* 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;
++
++ if (!nntp_data || !nntp_data->nserv)
++ return -1;
++ if (nntp_data->firstMessage > nntp_data->lastLoaded)
++ return 0;
++
++ /* init context */
++ cc.ctx = ctx;
++ cc.num = 0;
++ cc.max = 10;
++ cc.child = safe_malloc (sizeof (anum_t) * cc.max);
++
++ /* 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;
++ }
++
++ /* 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.
++ */
++
++#ifndef _NNTP_H_
++#define _NNTP_H_ 1
++
++#include "mutt_socket.h"
++#include "mailbox.h"
++#include "bcache.h"
++
++#if USE_HCACHE
++#include "hcache.h"
++#endif
++
++#include <time.h>
++#include <sys/types.h>
++#include <stdint.h>
++
++#define NNTP_PORT 119
++#define NNTP_SSL_PORT 563
++
++/* number of entries in article cache */
++#define NNTP_ACACHE_LEN 10
++
++/* article number type and format */
++#define anum_t uint32_t
++#define ANUM "%u"
++
++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;
++
++typedef struct
++{
++ anum_t first;
++ anum_t last;
++} NEWSRC_ENTRY;
++
++typedef struct
++{
++ unsigned int index;
++ char *path;
++} NNTP_ACACHE;
++
++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;
++
++typedef struct
++{
++ anum_t article_num;
++ unsigned int parsed : 1;
++} NNTP_HEADER_DATA;
++
++#define NHDR(hdr) ((NNTP_HEADER_DATA*)((hdr)->data))
++
++/* 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 *);
++
++/* 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);
++
++NNTP_SERVER *CurrentNewsSrv INITVAL (NULL);
++
++#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 -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
++
+
+ 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
++
+
+
+ /* 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
++
+ 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 (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
++
+ 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
++ }
+ 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;
++
++ case OP_FOLLOWUP:
++ CHECK_MODE(IsHeader (extra) || IsMsgAttach (extra));
++ CHECK_ATTACH;
++
++ if (IsMsgAttach (extra))
++ followup_to = extra->bdy->hdr->env->followup_to;
++ else
++ followup_to = extra->hdr->env->followup_to;
++
++ 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
++
+ 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;
++
++ case OP_SIDEBAR_TOGGLE_VISIBLE:
++ toggle_option (OPTSIDEBAR);
++ redraw = REDRAW_FULL;
++ break;
++#endif
++
+ 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;
+-
++
++ case 'k':
++ if (!ascii_strcasecmp (line+1, "eywords"))
++ {
++ kwtype = M_KEYWORDS;
++ }
++ break;
++
+ 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
++
++ 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;
++
+ 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;
++ }
++#endif
++
+ default:
+ 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 (kwtype == M_KEYWORDS)
++ sep = ",";
++ else if (kwtype == M_X_LABEL)
++ sep = XlabelDelim;
++ else
++ sep = " ";
++
++ 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;
++ }
++
+ done:
+
+ *lastp = last;
+ return matched;
+ }
+-
++
+
+ /* 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
++
+ 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;
++
++ 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);
++#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));
++ }
++#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));
++#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
++ */
++static THREAD *
++top_of_thread (HEADER *h)
++{
++ THREAD *t;
++
++ if (!h)
++ return NULL;
++
++ t = h->thread;
++
++ while (t && t->parent)
++ t = t->parent;
++
++ return t;
++}
++
++/**
++ * 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;
++
++ if (!h)
++ return 0;
++
++ me = top_of_thread (h);
++ if (!me)
++ return 0;
++
++ Context->vcount = 0;
++ Context->vsize = 0;
++ Context->collapsed = 0;
++
++ 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;
++
++ if (top_of_thread (Context->hdrs[i]) == me) {
++ BODY *body = Context->hdrs[i]->content;
++
++ 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;
++}
++
+ 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 _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
++
++#ifndef HAVE_STRNLEN
++size_t strnlen(const char *s, size_t maxlen);
++#endif
++
++#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
++========================
++
++ Read from/write to compressed mailboxes
++
++Patch
++-----
++
++ To check if Mutt supports "Compress Folders", look for "+USE_COMPRESSED" in
++ the mutt version.
++
++ Dependencies
++ * mutt-1.5.24
++
++Introduction
++------------
++
++ 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.
++
++ 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.
++
++ There are some examples of both compressed and encrypted files, later. For
++ now, the documentation will just concentrate on compressed files.
++
++Commands
++--------
++
++ open-hook pattern shell-command
++ close-hook pattern shell-command
++ append-hook pattern shell-command
++
++ 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.
++
++ If you need the exact string "%f" or "%t" in your command, simply double up
++ the "%" character, e.g. "%%f" or "%%t".
++
++ Not all Hooks are Required
++
++ | 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 |
++
++ > Note
++ >
++ > The command:
++ > - should return a non-zero exit status on failure
++ > - should not delete any files
++
++### Read from compressed mailbox
++
++ open-hook regexp shell-command
++
++ If Mutt is unable to open a file, it then looks for 'open-hook' that
++ matches the filename.
++
++ If your compression program doesn't have a well-defined extension, then you
++ can use '.' as the regexp.
++
++#### Example of open-hook
++
++ open-hook '.gz$' "gzip -cd '%f' > '%t'"
++
++ * 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
++
++### Write to a compressed mailbox
++
++ close-hook regexp shell-command
++
++ 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.
++
++ > Note
++ >
++ > If the folder has not been modifed, the
++ > close-hook
++ > will not be called.
++
++#### Example of close-hook
++
++ close-hook '.gz$' "gzip -c '%t' > '%f'"
++
++ * 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
++
++### Append to a compressed mailbox
++
++ append-hook regexp shell-command
++
++ When Mutt wants to append an email to a compressed mail folder, it will
++ look for a matching 'append-hook'. This hook is optional.
++
++ 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.
++
++ Mutt will *assume* the type to be that of the '$mbox_type' variable. Mutt
++ also uses this type for temporary files.
++
++ Mutt will only use the 'append-hook' for existing files. The 'close-hook'
++ will be used for empty, or missing files.
++
++#### Example of append-hook
++
++ append-hook '.gz$' "gzip -c '%t' >> '%f'"
++
++ * 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
++
++### Empty Files
++
++ 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.
++
++### Security
++
++ Encrypted files are decrypted into temporary files which are stored in the
++ $tmpdir directory. This could be a security risk.
++
++See Also
++--------
++
++ * NeoMutt project
++ * Compile-Time Features
++ * Regular Expressions
++ * $tmpdir
++ * $mbox_type
++ * $save_empty
++ * folder-hook
++
++Known Bugs
++----------
++
++ * The Compressed Folder hooks cannot deal with filenames that contains
++ quotes/apostrophes.
++
++Credits
++-------
++
++ * 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>
++
+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
++=======================
++
++ Use rules to choose date format
++
++Patch
++-----
++
++ To check if Mutt supports "Conditional Dates", look for "patch-cond-date"
++ in the mutt version.
++
++ Dependencies
++ * mutt-1.6.1
++ * nested-if patch
++
++Introduction
++------------
++
++ The "cond-date" patch allows you to construct $index_format expressions
++ based on the age of the email.
++
++ Mutt's default '$index_format' displays email dates in the form:
++ abbreviated-month day-of-month — "Jan 14".
++
++ The format is configurable but only per-mailbox. This patch allows you to
++ configure the display depending on the age of the email.
++
++ Potential Formatting Scheme
++
++ | 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 |
++
++ For an explanation of the date formatting strings, see 'strftime(3).'
++
++ By carefully picking your formats, the dates can remain unambiguous and
++ compact.
++
++ Mutt's conditional format strings have the form: (whitespace introduced for
++ clarity)
++
++ %? TEST ? TRUE & FALSE ?
++
++ 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.
++
++ The date tests are of the form:
++
++ %[nX? TRUE & FALSE ?
++
++ * "n" is an optional count (defaults to 1 if missing)
++ * "X" is the time period
++
++ Date Formatting Codes
++
++ | Letter | Time Period |
++ |--------|-------------|
++ | y | Years |
++ | m | Months |
++ | w | Weeks |
++ | d | Days |
++ | H | Hours |
++ | M | Minutes |
++
++ Date Tests
++
++ | 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 |
++
++### Example 1
++
++ We start with a one-condition test.
++
++ Example 1
++
++ | Test | Date Range | Format String | Example |
++ |--------|------------|---------------|------------|
++ | '%[1m' | This month | '%[%b %d]' | Dec 10 |
++ | | Older | '%[%Y-%m-%d]' | 2015-04-23 |
++
++ The $index_format string would contain:
++
++ %?[1m?%[%b %d]&%[%Y-%m-%d]?
++
++ Reparsed a little, for clarity, you can see the test condition and the two
++ format strings.
++
++ %?[1m? & ?
++ %[%b %d] %[%Y-%m-%d]
++
++### Example 2
++
++ This example contains three test conditions and four date formats.
++
++ Example 2
++
++ | 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 |
++
++ The $index_format string would contain:
++
++ %<[y?%<[m?%<[d?%[%H:%M ]&%[%a %d]>&%[%b %d]>&%[%m/%y ]>
++
++ Reparsed a little, for clarity, you can see the test conditions and the
++ four format strings.
++
++ %<[y? &%[%m/%y ]> Older
++ %<[m? &%[%b %d]> This year
++ %<[d? &%[%a %d]> This month
++ %[%H:%M ] Today
++
++ This a another view of the same example, with some whitespace for clarity.
++
++ %<[y? %<[m? %<[d? AAA & BBB > & CCC > & DDD >
++
++ AAA = %[%H:%M ]
++ BBB = %[%a %d]
++ CCC = %[%b %d]
++ DDD = %[%m/%y ]
++
++
++Variables
++---------
++
++ The "cond-date" patch doesn't have any config of its own. It modifies the
++ behavior of the format strings.
++
++See Also
++--------
++
++ * NeoMutt project
++ * $index_format
++ * nested-if patch
++ * 'strftime(3)'
++
++Known Bugs
++----------
++
++ 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.
++
++Credits
++-------
++
++ * Aaron Schrab <aaron at schrab.com>
++ * Eric Davis <edavis at insanum.com>
++ * Richard Russon <rich at flatcap.org>
++
+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
++==============
++
++ Replace some temporary files with memory buffers
++
++Patch
++-----
++
++ To check if Mutt supports "fmemopen", look for "patch-fmemopen" in the mutt
++ version.
++
++ Dependencies
++ * mutt-1.6.1
++ * 'open_memstream()', 'fmemopen()' from glibc
++
++Introduction
++------------
++
++ The "fmemopen" patch speeds up some searches.
++
++ 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.
++
++ There are no user-configurable parts.
++
++ This patch depends on 'open_memstream()' and 'fmemopen()'. They are
++ provided by glibc. Without them, Mutt will simply create temporary files.
++
++See Also
++--------
++
++ * NeoMutt project
++ * Compile-Time Features
++ * 'fmemopen(3)'
++
++Known Bugs
++----------
++
++ None
++
++Credits
++-------
++
++ * Julius Plenz <plenz at cis.fu-berlin.de>
++ * Richard Russon <rich at flatcap.org>
++
+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
++===========
++
++ Conditional config options
++
++Patch
++-----
++
++ To check if Mutt supports "ifdef", look for "patch-ifdef" in the mutt
++ version.
++
++ Dependencies
++ * mutt-1.6.1
++
++Introduction
++------------
++
++ 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.
++
++ 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
++
++ Here a symbol can be a $variable, <function>, command or compile-time
++ symbol, such as "USE_IMAP".
++
++ 'finish' is particularly useful when combined with 'ifndef'. e.g.
++
++ # Sidebar config file
++ ifndef USE_SIDEBAR finish
++
++Commands
++--------
++
++ ifdef symbol "config-command [args]"
++ ifndef symbol "config-command [args]"
++ finish
++
++See Also
++--------
++
++ * NeoMutt project
++
++Known Bugs
++----------
++
++ None
++
++Credits
++-------
++
++ * Cedric Duval <cedricduval at free.fr>
++ * Matteo F. Vescovi <mfvescovi at gmail.com>
++ * Richard Russon <rich at flatcap.org>
++
+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
++=================
++
++ Custom rules for theming the email index
++
++Patch
++-----
++
++ To check if Mutt supports "Index Color", look for "patch-index-color" in
++ the mutt version.
++
++ Dependencies
++ * mutt-1.6.1
++ * status-color patch
++
++Introduction
++------------
++
++ The "index-color" patch allows you to specify colors for individual parts
++ of the email index. e.g. Subject, Author, Flags.
++
++ First choose which part of the index you'd like to color. Then, if needed,
++ pick a pattern to match.
++
++ Note: The pattern does not have to refer to the object you wish to color.
++ e.g.
++
++ color index_author red default "~smutt"
++
++ The author appears red when the subject (~s) contains "mutt".
++
++Colors
++------
++
++ All the colors default to 'default', i.e. unset.
++
++ The index objects can be themed using the 'color' command. Some objects
++ require a pattern.
++
++ color index-object foreground background
++ color index-object foreground background pattern
++
++ Index Colors
++
++ | 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 |
++
++See Also
++--------
++
++ * NeoMutt project
++ * Regular Expressions
++ * Patterns
++ * $index_format
++ * Color command
++ * Status-Color patch
++ * Keywords patch
++
++Known Bugs
++----------
++
++ None
++
++Credits
++-------
++
++ * 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>
++
+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
++======================
++
++ Expando for author's initials
++
++Patch
++-----
++
++ To check if Mutt supports "Initials", look for "patch-initials" in the mutt
++ version.
++
++ Dependencies
++ * mutt-1.6.1
++
++Introduction
++------------
++
++ The "initials" patch adds an expando (%I) for an author's initials.
++
++ 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.
++
++Variables
++---------
++
++ This patch has no config of its own. It adds an expando which can be used
++ in the $index_format variable.
++
++See Also
++--------
++
++ * NeoMutt project
++ * $index_format
++ * index-color patch
++ * folder-hook
++
++Known Bugs
++----------
++
++ None
++
++Credits
++-------
++
++ * Vsevolod Volkov <vvv at mutt.org.ua>
++ * Richard Russon <rich at flatcap.org>
++
+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
++==============
++
++ Labels/Tagging for emails
++
++Patch
++-----
++
++ To check if Mutt supports "Keywords", look for "patch-keywords" in the mutt
++ version.
++
++ Dependencies
++ * mutt-1.5.24
++
++Introduction
++------------
++
++ Unify label/keyword handling.
++
++ 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.
++
++ 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.
++
++ 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.
++
++ (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.)
++
++ 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.
++
++ Overall this represents convergence path for all competing
++ labelling/tagging/keywording systems toward one that is specified by RFC.
++
++ 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.
++
++Variables
++---------
++
++ Keyword Variables
++
++ | Name | Type | Default |
++ |---------------------|---------|---------|
++ | 'keywords_legacy' | boolean | 'yes' |
++ | 'keywords_standard' | boolean | 'no' |
++ | 'xlabel_delimiter' | string | (empty) |
++
++Functions
++---------
++
++ Keyword Functions
++
++ | Menus | Default Key | Function | Description |
++ |-------------|-------------|----------------|------------------------------------------|
++ | index,pager | y | '<edit-label>' | add, change, or delete a message's label |
++
++Sort
++----
++
++ Keywords Sort
++
++ | Sort | Description |
++ |---------|---------------|
++ | 'label' | Sort by label |
++
++See Also
++--------
++
++ * NeoMutt project
++ * $index_format
++ * index-color patch
++ * folder-hook
++
++Known Bugs
++----------
++
++Credits
++-------
++
++ * David Champion <dgc at uchicago.edu>
++ * Richard Russon <rich at flatcap.org>
++
+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
++==========================
++
++ Focus on one Email Thread
++
++Patch
++-----
++
++ To check if Mutt supports "limit-current-thread", look for
++ "patch-limit-current-thread" in the mutt version.
++
++ Dependencies
++ * mutt-1.6.1
++
++Introduction
++------------
++
++ 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.
++
++Functions
++---------
++
++ | Menus | Default Key | Function | Description |
++ |-------|-------------|--------------------------|------------------------------|
++ | index | '<Esc> L' | '<limit-current-thread>' | Limit view to current thread |
++
++See Also
++--------
++
++ * NeoMutt project
++
++Known Bugs
++----------
++
++ None
++
++Credits
++-------
++
++ * David Sterba <dsterba at suse.cz>
++ * Richard Russon <rich at flatcap.org>
++
+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
++
++## What is NeoMutt?
++
++* NeoMutt is a project of projects.
++* A place to gather all the patches against Mutt.
++* A place for all the developers to gather.
++
++Hopefully this will build the community and reduce duplicated effort.
++
++NeoMutt was created when Richard Russon (FlatCap) took all the old Mutt patches,
++sorted through them, fixed them up and documented them.
++
++## What Features does NeoMutt have?
++
++| 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
++
++## Where is NeoMutt?
++
++- 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/
++
++## NeoMutt Developers
++
++Here's a list of everyone who's helped NeoMutt:
++
++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.
++
++## Original Patch Authors
++
++Without the original patch authors, there would be nothing.
++So, a Big Thank You to:
++
++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.
++
++## Original Mutt Authors
++
++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.
++
++http://www.neomutt.org/manual/miscellany.html#acknowledgements
++
+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
++
++## What is NeoMutt?
++
++* NeoMutt is a project of projects.
++* A place to gather all the patches against Mutt.
++* A place for all the developers to gather.
++
++Hopefully this will build the community and reduce duplicated effort.
++
++NeoMutt was created when Richard Russon (FlatCap) took all the old Mutt patches,
++sorted through them, fixed them up and documented them.
++
++## What Features does NeoMutt have?
++
++| 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
++
++## Where is NeoMutt?
++
++- 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/
++
++## NeoMutt Developers
++
++Here's a list of everyone who's helped NeoMutt:
++
++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.
++
++## Original Patch Authors
++
++Without the original patch authors, there would be nothing.
++So, a Big Thank You to:
++
++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.
++
++## Original Mutt Authors
++
++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.
++
++http://www.neomutt.org/manual/miscellany.html#acknowledgements
++
+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
++===============
++
++ 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.1
++
++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"
++ }
++
++
++ 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'
++ }
++ }
++
++
++ Examples:
++
++ set index_format='%4C %Z %{%b %d} %-25.25n %s%> %<M?%M Msgs &%<l?%l Lines&%c Bytes>>'
++
++ 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 %<M?[%M] %s&%s%* %<l?%l&%c>>'
++
++ 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)
++
++
++Variables
++---------
++
++ The nested-if patch doesn't have any config of its own. It modifies the behavior of the
++ format strings.
++
++See Also
++--------
++
++ * NeoMutt project
++ * cond-date patch
++ * $index_format
++ * $status_format
++
++Known Bugs
++----------
++
++ Patch overwrites $<fmt> handler in
++ $index_format
++
++Credits
++-------
++
++ * David Champion <dgc at uchicago.edu>
++ * Richard Russon <rich at flatcap.org>
++
+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
++==========
++
++ Talk to a Usenet news server
++
++Patch
++-----
++
++ To check if Mutt supports "NNTP", look for "+USE_NNTP" in the mutt version.
++
++ Dependencies
++ * mutt-1.5.24
++
++Introduction
++------------
++
++ Reading news via NNTP
++
++ 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.
++
++Variables
++---------
++
++ NNTP Variables
++
++ | 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' |
++
++Functions
++---------
++
++ NNTP Functions
++
++ | 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 |
++
++Commands
++--------
++
++Colors
++------
++
++ None
++
++Sort
++----
++
++ None
++
++See Also
++--------
++
++ * NeoMutt project
++ * Compile-Time Features
++
++Known Bugs
++----------
++
++Credits
++-------
++
++ * Vsevolod Volkov <vvv at mutt.org.ua>
++ * Felix von Leitner <leitner at fefe.de>
++ * Richard Russon <rich at flatcap.org>
++
+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
++------------------------
++
++ * notmuch is e-mail fulltext indexing and tagging engine; see
++ http://notmuchmail.org/ for more information.
++
++ * home page (wiki) and git:
++
++ https://github.com/karelzak/mutt-kz
++
++ Note that the master branch is rebased to be up to date with mutt upstream. Use
++ stable/v<version> branches for downstream packaging.
++
++ * mailing list:
++
++ https://admin.fedoraproject.org/mailman/listinfo/mutt-kz
++
++ * requirements:
++
++ notmuch >= 0.9
++
++ * compile:
++
++ $ git clone git://github.com/karelzak/mutt-kz.git
++ $ cd mutt-kz
++ $ ./prepare
++ $ ./configure --enable-notmuch [--enable-debug]
++ $ make
++
++ * Folders URI
++
++ notmuch://[<path>][?<item>=<name>[& ...]]
++
++ 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 the "<path>" is not defined then $nm_default_uri or $folder is used,
++ for example:
++
++ set nm_default_uri = "notmuch:///home/foo/maildir"
++ virtual-mailboxes "My INBOX" "notmuch://?query=tag:inbox"
++
++ Items:
++
++ query=<string>
++
++ See SEARCH SYNTAX in notmuch man page. Don't forget to use "and" and
++ "or" operators in your queries.
++
++ Note that proper URI should not contain blank space and all "bad" chars
++ should be encoded, for example
++
++ "tag:AAA and tag:BBB" --encoding-> tag:AAA%20and%20tag:BBB
++
++ but mutt config file parser is smart enough to accept space in quoted
++ strings. It means that you can use
++
++ "notmuch:///foo?query=tag:AAA and tag:BBB"
++
++ in your config files to keep things readable.
++
++ See http://xapian.org/docs/queryparser.html for more details about Xapian
++ queries.
++
++
++ limit=<number>
++
++ Restricts number of messages/threads in the result. The default limit
++ is nm_db_limit.
++
++ type=<threads|messages>
++
++ Reads all matching messages or whole-threads. The default is 'messages'
++ or nm_query_type.
++
++
++ * commands:
++
++ 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
++
++ vfolder-from-query:
++ - generate new virtual folder from notmuch search query
++ - default key: <Esc>X
++ - note: TAB completion of 'tag:' names is available
++
++ 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"
++
++ 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):
++
++ macro index A "<modify-labels-then-hide>+archive -inbox\n<sync-mailbox>"
++ macro index I "<modify-labels-then-hide>-inbox\n<sync-mailbox>"
++
++ quasi-delete:
++ - delete message from mutt (usually after <sync-mailbox> function), but
++ don't touch message on disk
++
++ 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: +
++
++ * Pattern modifiers:
++
++ 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:
++
++ - '~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?'"
++
++ * muttrc:
++
++ Note that you can use notmuch specific mutt config file, see -F <config> in
++ mutt docs.
++
++
++ virtual-mailboxes <description> <uri> [ ...]
++
++ 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)
++
++ example:
++
++ 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"
++
++ 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.
++
++ virtual_spoolfile = <boolean>
++
++ When set, mutt will use the first virtual mailbox (see virtual-mailboxes)
++ as a spoolfile.
++
++ 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.
++
++ tag-transforms <tag> <transform> [ ...]
++
++ 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.
++
++ example:
++
++ tag-transforms "inbox" "i" \
++ "unread" "u" \
++ "replied" "↻ " \
++ "sent" "➥ " \
++ "todo" "T" \
++ "deleted" "DEL" \
++ "invites" "CAL"
++
++ tag-formats <tag> <format sequence> [ ...]
++
++ 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.
++
++ example:
++
++ tag-formats "inbox" "GI" \
++ "unread" "GU" \
++ "replied" "GR" \
++ "sent" "GS" \
++ "todo" "Gt" \
++ "deleted" "GD" \
++ "invites" "Gi"
++
++ 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:
++
++ set index_format='4C %S %[%y.%m.%d] %-18.18n %?GU?%GU& ? %?GR?%GR& ? %?GI?%GI& ? %s'
++
++ The %G formatting sequence may display all tags including tags hidden by
++ nm_hidden_tags.
++
++ nm_record = <boolean>
++
++ 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.
++
++ nm_record_tags = <comma delimited list>
++
++ Tags that should be removed or added to the to the messages stored in the mutt record.
++
++ example:
++
++ set record = "~/sent-mails"
++ set nm_record = yes
++ set nm_record_tags = "-inbox,archive,me"
++
++ nm_open_timeout = <seconds>
++
++ This option specifies timeout for Notmuch database. Default is 5 seconds.
++
++ nm_default_uri = <uri>
++
++ 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).
++
++ nm_hidden_tags = <comma delimited list>
++
++ This variable specifies private notmuch tags which should not be printed
++ on screen (index, pager).
++
++ Default is "unread,draft,flagged,passed,replied,attachment".
++
++ nm_exclude_tags = <comma delimited list>
++
++ The messages tagged with these tags are excluded and not loaded
++ from notmuch DB to mutt unless specified explicitly.
++
++ Not set by default.
++
++ nm_unread_tag = <name>
++
++ 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.
++
++ Default is "unread".
++
++ nm_db_limit = <num>
++
++ This variable specifies notmuch query limit.
++
++ Default is unlimited.
++
++ nm_query_type = <threads|messages>
++
++ This variable specifies notmuch query type, supported types: 'threads' and
++ 'messages'.
++
++ Default is 'messages'.
++
++ vfolder_format = <string>
++
++ 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:
++
++ %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
++
++ Default is "%6n(%6N) %f ".
++
++ index_format and pager_format
++
++ %g notmuch tags (labels)
++ %Gx specific notmuch tag defined by tag-formats (see above)
++
++ for example:
++
++ 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)"
++
++
++* .muttrc example:
++
++ set record="~/Mail/Maildir/sent-mail"
++ set nm_record = yes
++ set nm_record_tags ="-inbox me archive"
++
++ set nm_default_uri="notmuch:///home/kzak/Mail/Maildir"
++ set virtual_spoolfile = yes
++ set sort_browser = unsorted
++
++ # normal folders
++ set mbox_type=Maildir
++ set folder="~/Mail/Maildir"
++ mailboxes =rh =fedora =misc
++
++ set sidebar_width = 35
++ set sidebar_visible = yes
++ set sidebar_sort_method = unsorted
++ set sidebar_divider_char = │
++
++ color sidebar_new yellow default
++ color progress default magenta
++
++ bind index <left> sidebar-prev
++ bind index <right> sidebar-next
++ bind index <space> sidebar-open
++ bind index <Esc>S sidebar-toggle-virtual
++
++ set index_format="%4C %Z %?GI?%GI& ? %[%d/%b] %-16.15F %?M?(%3M)& ? %s %> %?g?%g?"
++
++ # 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" \
++
++ # move message to archive
++ macro index A "<modify-labels-then-hide>+archive -inbox\n<sync-mailbox>"
++
++ # remove message from inbox
++ macro index I "<modify-labels-then-hide>-inbox\n<sync-mailbox>"
++
++ # 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"
++
++
++* .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=""
++ }
++
++ ### Deliver emails to maildirs by notmuch-deliver
++ ### from notmuch contrib/
++ ###
++ ### notmuch-deliver -t <tags> [-t ...] <maildir>
++
++ :0:notmuch.lock
++ * ^List-Id:.*linux.linux.cz
++ | notmuch-deliver $NOINBOX -t cz $TAGS linux.cz
++
++ :0:notmuch.lock
++ * ^X-Mailing-List:.*util-linux at vger.kernel.org
++ | notmuch-deliver -t ul $TAGS util-linux
++
++ :0:notmuch.lock
++ * ^List-Id:.*parted-devel.lists.alioth.debian.org
++ | notmuch-deliver $NOINBOX -t part $TAGS parted
++
++ ### [...cut to make the example short...] ###
++
++ ### All unmatched mails
++ :0:notmuch.lock
++ * ^From
++ | notmuch-deliver $TAGS misc
++
++ ### fallback if notmuch does not work
++ :0:
++ * ^From
++ Mail/Maildir/misc/
++
++
++* another example:
++
++ 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
++==================
++
++ Show a visual progress bar on slow operations
++
++Patch
++-----
++
++ To check if Mutt supports "Progress Bar", look for "patch-progress" in the
++ mutt version.
++
++ Dependencies
++ * mutt-1.6.1
++
++Introduction
++------------
++
++ The "progress" patch shows a visual progress bar on slow tasks, such as
++ indexing a large folder over the net.
++
++Colors
++------
++
++ Progress Colors
++
++ | Name | Default Color | Description |
++ |------------|---------------|---------------------|
++ | 'progress' | default | Visual progress bar |
++
++See Also
++--------
++
++ * NeoMutt project
++ * Color command
++
++Known Bugs
++----------
++
++ None
++
++Credits
++-------
++
++ * 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>
++
+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
++==================
++
++ Mark emails that should be hidden, but not deleted
++
++Patch
++-----
++
++ To check if Mutt supports "Quasi-Delete", look for "patch-quasi-delete" in
++ the mutt version.
++
++ Dependencies
++ * mutt-1.6.1
++
++Introduction
++------------
++
++ The "quasi-delete" function marks an email that should be hidden from the
++ index, but NOT deleted.
++
++ On its own, this patch isn't very useful. It forms a useful part of the
++ notmuch plugin.
++
++Functions
++---------
++
++ Quasi-Delete Functions
++
++ | Menus | Default Key | Function | Description |
++ |-------------|-------------|------------------|---------------------------------------|
++ | index,pager | (none) | '<quasi-delete>' | delete from mutt, don't touch on disk |
++
++See Also
++--------
++
++ * NeoMutt project
++ * notmuch patch
++
++Known Bugs
++----------
++
++ None
++
++Credits
++-------
++
++ * Karel Zak <kzak at redhat.com>
++ * Richard Russon <rich at flatcap.org>
++
+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
++=============
++
++ Overview of mailboxes
++
++ NOTES:
++
++ If you haven't used the sidebar before, you might like to read the
++ Sidebar Introduction:
++
++ http://www.neomutt.org/sidebar-intro.html
++
++ If you have used an older version of the Sidebar, please note that some
++ of the configuration has changed.
++
++ http://www.neomutt.org/sidebar-intro.html#intro-sidebar-config-changes
++
++Patch
++-----
++
++ To check if Mutt supports "Sidebar", look for "+USE_SIDEBAR" in the mutt
++ version.
++
++ Dependencies
++ * mutt-1.6.1
++
++Introduction
++------------
++
++ 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.
++
++ 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.
++
++ 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.
++
++Variables
++---------
++
++ Sidebar Variables
++
++ | 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' |
++
++Functions
++---------
++
++ Sidebar Functions
++
++ Sidebar adds the following functions to Mutt. By default, none of them are
++ bound to keys.
++
++ | 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 |
++
++Commands
++--------
++
++ sidebar_whitelist mailbox [ mailbox... ]
++
++Colors
++------
++
++ Sidebar Colors
++
++ | 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 |
++
++ If the sidebar_indicator color isn't set, then the default Mutt indicator
++ color will be used (the color used in the index panel).
++
++Sort
++----
++
++ Sidebar Sort
++
++ | 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 |
++
++See Also
++--------
++
++ * Regular Expressions
++ * Patterns
++ * Color command
++ * notmuch patch
++
++Known Bugs
++----------
++
++ Unsorted isn't
++
++Credits
++-------
++
++ * 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>
++
+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
++=================
++
++ Leave some context visible
++
++Patch
++-----
++
++ To check if Mutt supports "Skip-Quoted", look for "patch-skip-quoted" in
++ the mutt version.
++
++ Dependencies
++ * mutt-1.6.1
++
++Introduction
++------------
++
++ 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.
++
++ By setting the '$skip_quoted_offset' variable, you can select how much of
++ the quoted text is left visible.
++
++Variables
++---------
++
++ | Name | Type | Default |
++ |----------------------|--------|---------|
++ | 'skip_quoted_offset' | number | 0 |
++
++See Also
++--------
++
++ * NeoMutt project
++
++Known Bugs
++----------
++
++ None
++
++Credits
++-------
++
++ * David Sterba <dsterba at suse.cz>
++ * Richard Russon <rich at flatcap.org>
++
+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.
+
+ 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.
+
++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.
+
++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
+
+-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
++--------
++
++ * NeoMutt project
++
++Known Bugs
++----------
++
++ None
++
++Credits
++-------
++
++ * Jeremy Katz <katzj at linuxpower.org>
++ * Phil Pennock <mutt-dev at spodhuis.demon.nl>
++ * Richard Russon <rich at flatcap.org>
++
+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
++==================
++
++ Automatically move "deleted" emails to a trash bin
++
++Patch
++-----
++
++ To check if Mutt supports "Trash Folder", look for "patch-trash" in the
++ mutt version.
++
++ If IMAP is enabled, this patch will use it
++
++ Dependencies
++ * mutt-1.6.1
++ * IMAP support
++
++Introduction
++------------
++
++ 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.
++
++ After '<sync-mailbox>' has been called the email is gone forever.
++
++ 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.
++
++ The '$trash' path can be either a full directory, or be relative to the
++ $folder variable, like the 'mailboxes' command.
++
++ > Note
++ >
++ > Emails deleted from the trash folder are gone forever.
++
++Variables
++---------
++
++ Trash Variables
++
++ | Name | Type | Default |
++ |-------|--------|---------|
++ | trash | string | (none) |
++
++Functions
++---------
++
++ Trash Functions
++
++ | Menus | Default Key | Function | Description |
++ |-------------|-------------|-------------------|-------------------------------------------------------------|
++ | index,pager | (none) | '<purge-message>' | really delete the current entry, bypassing the trash folder |
++
++See Also
++--------
++
++ * NeoMutt project
++ * folder-hook
++
++Known Bugs
++----------
++
++ None
++
++Credits
++-------
++
++ * Cedric Duval <cedricduval at free.fr>
++ * Benjamin Kuperman <kuperman at acm.org>
++ * Paul Miller <paul at voltar.org>
++ * Richard Russon <rich at flatcap.org>
++
+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 @@
+ }
+ #endif
+
++#ifdef USE_NNTP
++ if (Context->magic == M_NNTP)
++ {
++ mutt_flushinp ();
++ mutt_error _("Can't delete attachment from news server.");
++ break;
++ }
++#endif
++
+ if (WithCrypto && (hdr->security & ENCRYPT))
+ {
+ mutt_message _(
+@@ -1214,10 +1223,33 @@
+ case OP_FORWARD_MESSAGE:
+ CHECK_ATTACH;
+ mutt_attach_forward (fp, hdr, idx, idxlen,
+- menu->tagprefix ? NULL : idx[menu->current]->content);
++ menu->tagprefix ? NULL : idx[menu->current]->content, 0);
+ menu->redraw = REDRAW_FULL;
+ break;
+
++#ifdef USE_NNTP
++ case OP_FORWARD_TO_GROUP:
++ CHECK_ATTACH;
++ mutt_attach_forward (fp, hdr, idx, idxlen,
++ menu->tagprefix ? NULL : idx[menu->current]->content, SENDNEWS);
++ menu->redraw = REDRAW_FULL;
++ break;
++
++ case OP_FOLLOWUP:
++ CHECK_ATTACH;
++
++ if (!idx[menu->current]->content->hdr->env->followup_to ||
++ mutt_strcasecmp (idx[menu->current]->content->hdr->env->followup_to, "poster") ||
++ query_quadoption (OPT_FOLLOWUPTOPOSTER,_("Reply by mail as poster prefers?")) != M_YES)
++ {
++ mutt_attach_reply (fp, hdr, idx, idxlen,
++ menu->tagprefix ? NULL : idx[menu->current]->content,
++ SENDNEWS|SENDREPLY);
++ menu->redraw = REDRAW_FULL;
++ break;
++ }
++#endif
++
+ 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 @@
+ static void attach_forward_bodies (FILE * fp, HEADER * hdr,
+ ATTACHPTR ** idx, short idxlen,
+ BODY * cur,
+- short nattach)
++ short nattach, int flags)
+ {
+ short i;
+ short mime_fwd_all = 0;
+@@ -547,7 +547,7 @@
+ tmpfp = NULL;
+
+ /* now that we have the template, send it. */
+- ci_send_message (0, tmphdr, tmpbody, NULL, parent);
++ ci_send_message (flags, tmphdr, tmpbody, NULL, parent);
+ return;
+
+ bail:
+@@ -574,7 +574,7 @@
+ */
+
+ static void attach_forward_msgs (FILE * fp, HEADER * hdr,
+- ATTACHPTR ** idx, short idxlen, BODY * cur)
++ ATTACHPTR ** idx, short idxlen, BODY * cur, int flags)
+ {
+ HEADER *curhdr = NULL;
+ HEADER *tmphdr;
+@@ -679,23 +679,23 @@
+ else
+ mutt_free_header (&tmphdr);
+
+- ci_send_message (0, tmphdr, *tmpbody ? tmpbody : NULL,
++ ci_send_message (flags, tmphdr, *tmpbody ? tmpbody : NULL,
+ NULL, curhdr);
+
+ }
+
+ void mutt_attach_forward (FILE * fp, HEADER * hdr,
+- ATTACHPTR ** idx, short idxlen, BODY * cur)
++ ATTACHPTR ** idx, short idxlen, BODY * cur, int flags)
+ {
+ short nattach;
+
+
+ if (check_all_msg (idx, idxlen, cur, 0) == 0)
+- attach_forward_msgs (fp, hdr, idx, idxlen, cur);
++ attach_forward_msgs (fp, hdr, idx, idxlen, cur, flags);
+ else
+ {
+ nattach = count_tagged (idx, idxlen);
+- attach_forward_bodies (fp, hdr, idx, idxlen, cur, nattach);
++ attach_forward_bodies (fp, hdr, idx, idxlen, cur, nattach, flags);
+ }
+ }
+
+@@ -753,28 +753,40 @@
+ return -1;
+ }
+
+- if (parent)
++#ifdef USE_NNTP
++ if ((flags & SENDNEWS))
+ {
+- if (mutt_fetch_recips (env, curenv, flags) == -1)
+- return -1;
++ /* in case followup set Newsgroups: with Followup-To: if it present */
++ if (!env->newsgroups && curenv &&
++ mutt_strcasecmp (curenv->followup_to, "poster"))
++ env->newsgroups = safe_strdup (curenv->followup_to);
+ }
+ else
++#endif
+ {
+- for (i = 0; i < idxlen; i++)
++ if (parent)
+ {
+- if (idx[i]->content->tagged
+- && mutt_fetch_recips (env, idx[i]->content->hdr->env, flags) == -1)
++ if (mutt_fetch_recips (env, curenv, flags) == -1)
+ return -1;
+ }
++ else
++ {
++ for (i = 0; i < idxlen; i++)
++ {
++ if (idx[i]->content->tagged
++ && mutt_fetch_recips (env, idx[i]->content->hdr->env, flags) == -1)
++ return -1;
++ }
++ }
++
++ if ((flags & SENDLISTREPLY) && !env->to)
++ {
++ mutt_error _("No mailing lists found!");
++ return (-1);
++ }
++
++ mutt_fix_reply_recipients (env);
+ }
+-
+- if ((flags & SENDLISTREPLY) && !env->to)
+- {
+- mutt_error _("No mailing lists found!");
+- return (-1);
+- }
+-
+- mutt_fix_reply_recipients (env);
+ mutt_make_misc_reply_headers (env, Context, curhdr, curenv);
+
+ if (parent)
+@@ -835,6 +847,13 @@
+ char prefix[SHORT_STRING];
+ int rc;
+
++#ifdef USE_NNTP
++ if (flags & SENDNEWS)
++ set_option (OPTNEWSSEND);
++ else
++ unset_option (OPTNEWSSEND);
++#endif
++
+ 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
+@@ -44,10 +44,18 @@
+ #include <sys/types.h>
+ #include <utime.h>
+
++#ifdef USE_NNTP
++#include "nntp.h"
++#include "mx.h"
++#endif
++
+ #ifdef MIXMASTER
+ #include "remailer.h"
+ #endif
+
++#ifdef USE_NOTMUCH
++#include "mutt_notmuch.h"
++#endif
+
+ static void append_signature (FILE *f)
+ {
+@@ -213,17 +221,51 @@
+ return 0;
+ }
+
+-static int edit_envelope (ENVELOPE *en)
++static int edit_envelope (ENVELOPE *en, int flags)
+ {
+ char buf[HUGE_STRING];
+ LIST *uh = UserHeader;
+
+- if (edit_address (&en->to, "To: ") == -1 || en->to == NULL)
+- return (-1);
+- if (option (OPTASKCC) && edit_address (&en->cc, "Cc: ") == -1)
+- return (-1);
+- if (option (OPTASKBCC) && edit_address (&en->bcc, "Bcc: ") == -1)
+- return (-1);
++#ifdef USE_NNTP
++ if (option (OPTNEWSSEND))
++ {
++ if (en->newsgroups)
++ strfcpy (buf, en->newsgroups, sizeof (buf));
++ else
++ buf[0] = 0;
++ if (mutt_get_field ("Newsgroups: ", buf, sizeof (buf), 0) != 0)
++ return (-1);
++ FREE (&en->newsgroups);
++ en->newsgroups = safe_strdup (buf);
++
++ if (en->followup_to)
++ strfcpy (buf, en->followup_to, sizeof (buf));
++ else
++ buf[0] = 0;
++ if (option (OPTASKFOLLOWUP) && mutt_get_field ("Followup-To: ", buf, sizeof (buf), 0) != 0)
++ return (-1);
++ FREE (&en->followup_to);
++ en->followup_to = safe_strdup (buf);
++
++ if (en->x_comment_to)
++ strfcpy (buf, en->x_comment_to, sizeof (buf));
++ else
++ buf[0] = 0;
++ if (option (OPTXCOMMENTTO) && option (OPTASKXCOMMENTTO) && mutt_get_field ("X-Comment-To: ", buf, sizeof (buf), 0) != 0)
++ return (-1);
++ FREE (&en->x_comment_to);
++ en->x_comment_to = safe_strdup (buf);
++ }
++ else
++#endif
++ {
++ if (edit_address (&en->to, "To: ") == -1 || en->to == NULL)
++ return (-1);
++ if (option (OPTASKCC) && edit_address (&en->cc, "Cc: ") == -1)
++ return (-1);
++ if (option (OPTASKBCC) && edit_address (&en->bcc, "Bcc: ") == -1)
++ return (-1);
++ }
+
+ if (en->subject)
+ {
+@@ -258,6 +300,14 @@
+ return 0;
+ }
+
++#ifdef USE_NNTP
++char *nntp_get_header (const char *s)
++{
++ SKIPWS (s);
++ return safe_strdup (s);
++}
++#endif
++
+ static void process_user_recips (ENVELOPE *env)
+ {
+ LIST *uh = UserHeader;
+@@ -270,6 +320,14 @@
+ 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);
++#ifdef USE_NNTP
++ else if (ascii_strncasecmp ("newsgroups:", uh->data, 11) == 0)
++ env->newsgroups = nntp_get_header (uh->data + 11);
++ else if (ascii_strncasecmp ("followup-to:", uh->data, 12) == 0)
++ env->followup_to = nntp_get_header (uh->data + 12);
++ else if (ascii_strncasecmp ("x-comment-to:", uh->data, 13) == 0)
++ env->x_comment_to = nntp_get_header (uh->data + 13);
++#endif
+ }
+ }
+
+@@ -308,6 +366,12 @@
+ else if (ascii_strncasecmp ("to:", uh->data, 3) != 0 &&
+ ascii_strncasecmp ("cc:", uh->data, 3) != 0 &&
+ ascii_strncasecmp ("bcc:", uh->data, 4) != 0 &&
++#ifdef USE_NNTP
++ ascii_strncasecmp ("newsgroups:", uh->data, 11) != 0 &&
++ ascii_strncasecmp ("followup-to:", uh->data, 12) != 0 &&
++ ascii_strncasecmp ("x-comment-to:", uh->data, 13) != 0 &&
++#endif
++ ascii_strncasecmp ("supersedes:", uh->data, 11) != 0 &&
+ ascii_strncasecmp ("subject:", uh->data, 8) != 0 &&
+ ascii_strncasecmp ("return-path:", uh->data, 12) != 0)
+ {
+@@ -659,6 +723,10 @@
+ if (pp) *pp = p;
+ if (qq) *qq = q;
+
++#ifdef USE_NNTP
++ if (option (OPTNEWSSEND) && option (OPTXCOMMENTTO) && curenv->from)
++ env->x_comment_to = safe_strdup (mutt_get_name (curenv->from));
++#endif
+ }
+
+ static void
+@@ -721,6 +789,16 @@
+
+ if (flags & SENDREPLY)
+ {
++#ifdef USE_NNTP
++ if ((flags & SENDNEWS))
++ {
++ /* in case followup set Newsgroups: with Followup-To: if it present */
++ if (!env->newsgroups && curenv &&
++ mutt_strcasecmp (curenv->followup_to, "poster"))
++ env->newsgroups = safe_strdup (curenv->followup_to);
++ }
++ else
++#endif
+ if (tag)
+ {
+ HEADER *h;
+@@ -867,7 +945,18 @@
+ * it hasn't already been set
+ */
+
+- if (option (OPTFOLLOWUPTO) && !e->mail_followup_to)
++ if (!option (OPTFOLLOWUPTO))
++ return;
++#ifdef USE_NNTP
++ if (option (OPTNEWSSEND))
++ {
++ if (!e->followup_to && e->newsgroups && (strrchr (e->newsgroups, ',')))
++ e->followup_to = safe_strdup (e->newsgroups);
++ return;
++ }
++#endif
++
++ if (!e->mail_followup_to)
+ {
+ if (mutt_is_list_cc (0, e->to, e->cc))
+ {
+@@ -1029,6 +1118,9 @@
+ #endif
+
+ #if USE_SMTP
++#ifdef USE_NNTP
++ if (!option (OPTNEWSSEND))
++#endif
+ if (SmtpUrl)
+ return mutt_smtp_send (msg->env->from, msg->env->to, msg->env->cc,
+ msg->env->bcc, tempfile,
+@@ -1164,9 +1256,17 @@
+ char *smime_default_key = NULL;
+ char *tag = NULL, *err = NULL;
+ char *ctype;
++ char *finalpath = NULL;
+
+ int rv = -1;
+
++#ifdef USE_NNTP
++ if (flags & SENDNEWS)
++ set_option (OPTNEWSSEND);
++ else
++ unset_option (OPTNEWSSEND);
++#endif
++
+ if (!flags && !msg && quadoption (OPT_RECALL) != M_NO &&
+ mutt_num_postponed (1))
+ {
+@@ -1202,6 +1302,22 @@
+ {
+ if ((flags = mutt_get_postponed (ctx, msg, &cur, fcc, sizeof (fcc))) < 0)
+ goto cleanup;
++#ifdef USE_NNTP
++ /*
++ * If postponed message is a news article, it have
++ * a "Newsgroups:" header line, then set appropriate flag.
++ */
++ if (msg->env->newsgroups)
++ {
++ flags |= SENDNEWS;
++ set_option (OPTNEWSSEND);
++ }
++ else
++ {
++ flags &= ~SENDNEWS;
++ unset_option (OPTNEWSSEND);
++ }
++#endif
+ }
+
+ if (flags & (SENDPOSTPONED|SENDRESEND))
+@@ -1303,11 +1419,16 @@
+ if (flags & SENDREPLY)
+ mutt_fix_reply_recipients (msg->env);
+
++#ifdef USE_NNTP
++ if ((flags & SENDNEWS) && ctx && ctx->magic == M_NNTP && !msg->env->newsgroups)
++ msg->env->newsgroups = safe_strdup (((NNTP_DATA *)ctx->data)->group);
++#endif
++
+ if (! (flags & (SENDMAILX|SENDBATCH)) &&
+ ! (option (OPTAUTOEDIT) && option (OPTEDITHDRS)) &&
+ ! ((flags & SENDREPLY) && option (OPTFASTREPLY)))
+ {
+- if (edit_envelope (msg->env) == -1)
++ if (edit_envelope (msg->env, flags) == -1)
+ goto cleanup;
+ }
+
+@@ -1605,6 +1726,11 @@
+ if (i == -1)
+ {
+ /* abort */
++#ifdef USE_NNTP
++ if (flags & SENDNEWS)
++ mutt_message _("Article not posted.");
++ else
++#endif
+ mutt_message _("Mail not sent.");
+ goto cleanup;
+ }
+@@ -1646,7 +1772,9 @@
+ mutt_prepare_envelope (msg->env, 0);
+ mutt_env_to_intl (msg->env, NULL, NULL); /* Handle bad IDNAs the next time. */
+
+- if (!Postponed || mutt_write_fcc (NONULL (Postponed), msg, (cur && (flags & SENDREPLY)) ? cur->env->message_id : NULL, 1, fcc) < 0)
++ if (!Postponed || mutt_write_fcc (NONULL (Postponed), msg,
++ (cur && (flags & SENDREPLY)) ?
++ cur->env->message_id : NULL, 1, fcc, NULL) < 0)
+ {
+ msg->content = mutt_remove_multipart (msg->content);
+ decode_descriptions (msg->content);
+@@ -1660,6 +1788,9 @@
+ }
+ }
+
++#ifdef USE_NNTP
++ if (!(flags & SENDNEWS))
++#endif
+ if (!has_recips (msg->env->to) && !has_recips (msg->env->cc) &&
+ !has_recips (msg->env->bcc))
+ {
+@@ -1693,6 +1824,19 @@
+ mutt_error _("No subject specified.");
+ goto main_loop;
+ }
++#ifdef USE_NNTP
++ if ((flags & SENDNEWS) && !msg->env->subject)
++ {
++ mutt_error _("No subject specified.");
++ goto main_loop;
++ }
++
++ if ((flags & SENDNEWS) && !msg->env->newsgroups)
++ {
++ mutt_error _("No newsgroup specified.");
++ goto main_loop;
++ }
++#endif
+
+ if (msg->content->next)
+ msg->content = mutt_make_multipart (msg->content);
+@@ -1830,7 +1974,7 @@
+ * message was first postponed.
+ */
+ msg->received = time (NULL);
+- if (mutt_write_fcc (fcc, msg, NULL, 0, NULL) == -1)
++ if (mutt_write_fcc (fcc, msg, NULL, 0, NULL, &finalpath) == -1)
+ {
+ /*
+ * Error writing FCC, we should abort sending.
+@@ -1891,6 +2035,7 @@
+ msg->content = mutt_remove_multipart (msg->content);
+ decode_descriptions (msg->content);
+ mutt_unprepare_envelope (msg->env);
++ FREE(&finalpath);
+ goto main_loop;
+ }
+ else
+@@ -1899,8 +2044,18 @@
+ goto cleanup;
+ }
+ }
+- else if (!option (OPTNOCURSES) && ! (flags & SENDMAILX))
+- mutt_message (i == 0 ? _("Mail sent.") : _("Sending in background."));
++ else if (!option (OPTNOCURSES) && ! (flags & SENDMAILX)) {
++ mutt_message (i != 0 ? _("Sending in background.") :
++#ifdef USE_NNTP
++ (flags & SENDNEWS) ? _("Article posted.") : _("Mail sent."));
++#else
++ _("Mail sent."));
++#endif
++#ifdef USE_NOTMUCH
++ if (option(OPTNOTMUCHRECORD))
++ nm_record_message(ctx, finalpath, cur);
++#endif
++ }
+
+ if (WithCrypto && (msg->security & ENCRYPT))
+ FREE (&pgpkeylist);
+@@ -1945,7 +2100,8 @@
+ safe_fclose (&tempfp);
+ if (! (flags & SENDNOFREEHEADER))
+ mutt_free_header (&msg);
+-
++
++ FREE(&finalpath);
+ 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
+@@ -46,6 +46,10 @@
+ #include <sys/wait.h>
+ #include <fcntl.h>
+
++#ifdef USE_NNTP
++#include "nntp.h"
++#endif
++
+ #ifdef HAVE_SYSEXITS_H
+ #include <sysexits.h>
+ #else /* Make sure EX_OK is defined <philiph at pobox.com> */
+@@ -73,8 +77,6 @@
+ '8', '9', '+', '/'
+ };
+
+-static char MsgIdPfx = 'A';
+-
+ static void transform_to_7bit (BODY *a, FILE *fpin);
+
+ static void encode_quoted (FGETCONV * fc, FILE *fout, int istext)
+@@ -480,18 +482,12 @@
+
+ #undef write_as_text_part
+
+-#define BOUNDARYLEN 16
+ void mutt_generate_boundary (PARAMETER **parm)
+ {
+- char rs[BOUNDARYLEN + 1];
+- char *p = rs;
+- int i;
+-
+- rs[BOUNDARYLEN] = 0;
+- for (i=0;i<BOUNDARYLEN;i++)
+- *p++ = B64Chars[LRAND() % sizeof (B64Chars)];
+- *p = 0;
++ char rs[MUTT_RANDTAG_LEN + 1];
+
++ mutt_rand_base32(rs, sizeof(rs) - 1);
++ rs[MUTT_RANDTAG_LEN] = 0;
+ mutt_set_parameter ("boundary", rs, parm);
+ }
+
+@@ -1543,6 +1539,14 @@
+ {
+ LIST **ref = NULL;
+ int refcnt = 0, refmax = 0;
++ int multiline = 1;
++ int space = 0;
++
++ if (trim < 0)
++ {
++ trim = -trim;
++ multiline = 0;
++ }
+
+ for ( ; (trim == 0 || refcnt < trim) && r ; r = r->next)
+ {
+@@ -1553,9 +1557,11 @@
+
+ while (refcnt-- > 0)
+ {
+- fputc (' ', f);
++ if (multiline || space)
++ fputc (' ', f);
++ space = 1;
+ fputs (ref[refcnt]->data, f);
+- if (refcnt >= 1)
++ if (multiline && refcnt >= 1)
+ fputc ('\n', f);
+ }
+
+@@ -1969,6 +1975,9 @@
+ mutt_write_address_list (env->to, fp, 4, 0);
+ }
+ else if (mode > 0)
++#ifdef USE_NNTP
++ if (!option (OPTNEWSSEND))
++#endif
+ fputs ("To: \n", fp);
+
+ if (env->cc)
+@@ -1977,6 +1986,9 @@
+ mutt_write_address_list (env->cc, fp, 4, 0);
+ }
+ else if (mode > 0)
++#ifdef USE_NNTP
++ if (!option (OPTNEWSSEND))
++#endif
+ fputs ("Cc: \n", fp);
+
+ if (env->bcc)
+@@ -1988,8 +2000,28 @@
+ }
+ }
+ else if (mode > 0)
++#ifdef USE_NNTP
++ if (!option (OPTNEWSSEND))
++#endif
+ fputs ("Bcc: \n", fp);
+
++#ifdef USE_NNTP
++ if (env->newsgroups)
++ fprintf (fp, "Newsgroups: %s\n", env->newsgroups);
++ else if (mode == 1 && option (OPTNEWSSEND))
++ fputs ("Newsgroups: \n", fp);
++
++ if (env->followup_to)
++ fprintf (fp, "Followup-To: %s\n", env->followup_to);
++ else if (mode == 1 && option (OPTNEWSSEND))
++ fputs ("Followup-To: \n", fp);
++
++ if (env->x_comment_to)
++ fprintf (fp, "X-Comment-To: %s\n", env->x_comment_to);
++ else if (mode == 1 && option (OPTNEWSSEND) && option (OPTXCOMMENTTO))
++ fputs ("X-Comment-To: \n", fp);
++#endif
++
+ if (env->subject)
+ mutt_write_one_header (fp, "Subject", env->subject, NULL, 0, 0);
+ else if (mode == 1)
+@@ -2008,6 +2040,9 @@
+ fputs ("Reply-To: \n", fp);
+
+ if (env->mail_followup_to)
++#ifdef USE_NNTP
++ if (!option (OPTNEWSSEND))
++#endif
+ {
+ fputs ("Mail-Followup-To: ", fp);
+ mutt_write_address_list (env->mail_followup_to, fp, 18, 0);
+@@ -2133,16 +2168,18 @@
+ time_t now;
+ struct tm *tm;
+ const char *fqdn;
++ unsigned char rndid[MUTT_RANDTAG_LEN + 1];
+
++ mutt_rand_base32(rndid, sizeof(rndid) - 1);
++ rndid[MUTT_RANDTAG_LEN] = 0;
+ now = time (NULL);
+ tm = gmtime (&now);
+ if(!(fqdn = mutt_fqdn(0)))
+ fqdn = NONULL(Hostname);
+
+- snprintf (buf, sizeof (buf), "<%d%02d%02d%02d%02d%02d.G%c%u@%s>",
++ snprintf (buf, sizeof (buf), "<%d%02d%02d%02d%02d%02d.%s@%s>",
+ tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour,
+- tm->tm_min, tm->tm_sec, MsgIdPfx, (unsigned int)getpid (), fqdn);
+- MsgIdPfx = (MsgIdPfx == 'Z') ? 'A' : MsgIdPfx + 1;
++ tm->tm_min, tm->tm_sec, rndid, fqdn);
+ return (safe_strdup (buf));
+ }
+
+@@ -2351,6 +2388,23 @@
+ size_t argslen = 0, argsmax = 0;
+ int i;
+
++#ifdef USE_NNTP
++ if (option (OPTNEWSSEND))
++ {
++ char cmd[LONG_STRING];
++
++ mutt_FormatString (cmd, sizeof (cmd), 0, NONULL (Inews), nntp_format_str, 0, 0);
++ if (!*cmd)
++ {
++ i = nntp_post (msg);
++ unlink (msg);
++ return i;
++ }
++
++ s = safe_strdup (cmd);
++ }
++#endif
++
+ /* ensure that $sendmail is set to avoid a crash. http://dev.mutt.org/trac/ticket/3548 */
+ if (!s)
+ {
+@@ -2381,6 +2435,10 @@
+ i++;
+ }
+
++#ifdef USE_NNTP
++ if (!option (OPTNEWSSEND))
++ {
++#endif
+ if (eightbit && option (OPTUSE8BITMIME))
+ args = add_option (args, &argslen, &argsmax, "-B8BITMIME");
+
+@@ -2412,6 +2470,9 @@
+ args = add_args (args, &argslen, &argsmax, to);
+ args = add_args (args, &argslen, &argsmax, cc);
+ args = add_args (args, &argslen, &argsmax, bcc);
++#ifdef USE_NNTP
++ }
++#endif
+
+ if (argslen == argsmax)
+ safe_realloc (&args, sizeof (char *) * (++argsmax));
+@@ -2489,9 +2550,11 @@
+ rfc2047_encode_adrlist (env->from, "From");
+ rfc2047_encode_adrlist (env->mail_followup_to, "Mail-Followup-To");
+ rfc2047_encode_adrlist (env->reply_to, "Reply-To");
+- rfc2047_encode_string (&env->x_label);
+
+ if (env->subject)
++#ifdef USE_NNTP
++ if (!option (OPTNEWSSEND) || option (OPTMIMESUBJECT))
++#endif
+ {
+ rfc2047_encode_string (&env->subject);
+ }
+@@ -2514,7 +2577,6 @@
+ rfc2047_decode_adrlist (env->from);
+ rfc2047_decode_adrlist (env->reply_to);
+ rfc2047_decode (&env->subject);
+- rfc2047_decode (&env->x_label);
+ }
+
+ static int _mutt_bounce_message (FILE *fp, HEADER *h, ADDRESS *to, const char *resent_from,
+@@ -2559,9 +2621,12 @@
+ mutt_copy_header (fp, h, f, ch_flags, NULL);
+ fputc ('\n', f);
+ mutt_copy_bytes (fp, f, h->content->length);
+- safe_fclose (&f);
+ FREE (&msgid_str);
+-
++ if (safe_fclose (&f) != 0) {
++ mutt_perror(tempfile);
++ unlink(tempfile);
++ return -1;
++ }
+ #if USE_SMTP
+ if (SmtpUrl)
+ ret = mutt_smtp_send (env_from, to, NULL, NULL, tempfile,
+@@ -2612,6 +2677,10 @@
+ }
+ rfc822_write_address (resent_from, sizeof (resent_from), from, 0);
+
++#ifdef USE_NNTP
++ unset_option (OPTNEWSSEND);
++#endif
++
+ /*
+ * 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 @@
+ }
+ }
+
+-int mutt_write_fcc (const char *path, HEADER *hdr, const char *msgid, int post, char *fcc)
++int mutt_write_fcc (const char *path, HEADER *hdr, const char *msgid,
++ int post, char *fcc, char **finalpath)
+ {
+ CONTEXT f;
+ MESSAGE *msg;
+@@ -2876,6 +2946,8 @@
+
+ if (mx_commit_message (msg, &f) != 0)
+ r = -1;
++ else if (finalpath)
++ *finalpath = safe_strdup(msg->commited_path);
+ 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 @@
++/* 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>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
++ */
++
++#if HAVE_CONFIG_H
++# include "config.h"
++#endif
++
++#include "mutt.h"
++#include "buffy.h"
++#include "keymap.h"
++#include "mutt_curses.h"
++#include "mutt_menu.h"
++#include "mx.h"
++#include "sort.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 */
++
++/**
++ * struct sidebar_entry - Info about folders in the sidebar
++ *
++ * Used in the mutt_FormatString callback
++ */
++struct sidebar_entry
++{
++ char box[STRING];
++ BUFFY *buffy;
++};
++
++enum {
++ SB_SRC_NONE = 0,
++ SB_SRC_VIRT,
++ SB_SRC_INCOMING
++};
++static int sidebar_source = SB_SRC_NONE;
++
++static BUFFY *
++get_incoming (void)
++{
++ switch (sidebar_source) {
++ case SB_SRC_NONE:
++ sidebar_source = SB_SRC_INCOMING;
++
++#ifdef USE_NOTMUCH
++ if (option (OPTVIRTSPOOLFILE) && VirtIncoming) {
++ sidebar_source = SB_SRC_VIRT;
++ return VirtIncoming;
++ }
++ break;
++ case SB_SRC_VIRT:
++ if (VirtIncoming) {
++ return VirtIncoming;
++ }
++ break;
++#endif
++ case SB_SRC_INCOMING:
++ break;
++ }
++
++ return Incoming; /* default */
++}
++
++/**
++ * 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
++ * @col: Starting column, UNUSED
++ * @op: printf-like operator, e.g. 'B'
++ * @src: printf-like format string
++ * @prefix: Field formatting string, UNUSED
++ * @ifstring: If condition is met, display this string
++ * @elsestring: Otherwise, display this string
++ * @data: Pointer to our sidebar_entry
++ * @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,
++ * '%N' : Number of new messages, '%S' : Size (total number of messages),
++ * '%!' : Icon denoting number of flagged messages.
++ *
++ * Returns: src (unchanged)
++ */
++static const char *cb_format_str(char *dest, size_t destlen, size_t col, 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;
++ unsigned int optional;
++ char fmt[STRING];
++
++ if (!sbe || !dest)
++ return src;
++
++ dest[0] = 0; /* Just in case there's nothing to do */
++
++ BUFFY *b = sbe->buffy;
++ if (!b)
++ return src;
++
++ int c = Context && (mutt_strcmp (Context->path, b->path) == 0);
++
++ optional = flags & M_FORMAT_OPTIONAL;
++
++ switch (op)
++ {
++ case 'B':
++ mutt_format_s (dest, destlen, prefix, sbe->box);
++ break;
++
++ case 'd':
++ if (!optional)
++ {
++ snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
++ snprintf (dest, destlen, fmt, c ? Context->deleted : 0);
++ }
++ else if ((c && Context->deleted == 0) || !c)
++ optional = 0;
++ break;
++
++ case 'F':
++ if (!optional)
++ {
++ snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
++ snprintf (dest, destlen, fmt, b->msg_flagged);
++ }
++ else if (b->msg_flagged == 0)
++ optional = 0;
++ break;
++
++ case 'L':
++ if (!optional)
++ {
++ snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
++ snprintf (dest, destlen, fmt, c ? Context->vcount : b->msg_count);
++ }
++ else if ((c && Context->vcount == b->msg_count) || !c)
++ optional = 0;
++ break;
++
++ case 'N':
++ if (!optional)
++ {
++ snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
++ snprintf (dest, destlen, fmt, b->msg_unread);
++ }
++ else if (b->msg_unread == 0)
++ optional = 0;
++ break;
++
++ case 'S':
++ if (!optional)
++ {
++ snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
++ snprintf (dest, destlen, fmt, b->msg_count);
++ }
++ else if (b->msg_count == 0)
++ optional = 0;
++ break;
++
++ case 't':
++ if (!optional)
++ {
++ snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
++ snprintf (dest, destlen, fmt, c ? Context->tagged : 0);
++ }
++ else if ((c && Context->tagged == 0) || !c)
++ optional = 0;
++ break;
++
++ case '!':
++ if (b->msg_flagged == 0)
++ mutt_format_s (dest, destlen, prefix, "");
++ else if (b->msg_flagged == 1)
++ mutt_format_s (dest, destlen, prefix, "!");
++ else if (b->msg_flagged == 2)
++ mutt_format_s (dest, destlen, prefix, "!!");
++ else
++ {
++ snprintf (fmt, sizeof (fmt), "%d!", b->msg_flagged);
++ mutt_format_s (dest, destlen, prefix, fmt);
++ }
++ break;
++ }
++
++ if (optional)
++ mutt_FormatString (dest, destlen, col, 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);
++
++ /* We return the format string, unchanged */
++ return src;
++}
++
++/**
++ * make_sidebar_entry - Turn mailbox data into a sidebar string
++ * @buf: Buffer in which to save string
++ * @buflen: Buffer length
++ * @width: Desired width in screen cells
++ * @box: Mailbox name
++ * @size: Size (total number of messages)
++ * @new: Number of new messages
++ * @flagged: Number of flagged messages
++ *
++ * Take all the relevant mailbox data and the desired screen width and then get
++ * mutt_FormatString to do the actual work. mutt_FormatString will callback to
++ * 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)
++{
++ struct sidebar_entry sbe;
++
++ if (!buf || !box || !b)
++ return;
++
++ sbe.buffy = b;
++ 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;
++
++ /* Force string to be exactly the right width */
++ int w = mutt_strwidth (buf);
++ int s = strlen (buf);
++ width = MIN(buflen, width);
++ if (w < width)
++ {
++ /* Pad with spaces */
++ memset (buf + s, ' ', width - w);
++ buf[s + width - w] = 0;
++ }
++ else if (w > width)
++ {
++ /* Truncate to fit */
++ int len = mutt_wstr_trunc (buf, buflen, width, NULL);
++ buf[len] = 0;
++ }
++}
++
++/**
++ * 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.
++ *
++ * 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)
++{
++ 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;
++ }
++
++ int result = 0;
++
++ switch ((SidebarSortMethod & SORT_MASK))
++ {
++ 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;
++ }
++
++ if (b->next)
++ {
++ b->next->prev = NULL;
++ return b->next;
++ }
++
++ return b->prev;
++}
++
++/**
++ * update_buffy_visibility - Should a BUFFY be displayed in the sidebar
++ * @arr: array of BUFFYs
++ * @arr_len: number of BUFFYs in array
++ *
++ * For each BUFFY in the 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
++ * has unread messages
++ * has flagged messages
++ * is whitelisted
++ */
++static void update_buffy_visibility (BUFFY **arr, int arr_len)
++{
++ if (!arr)
++ return;
++
++ short new_only = option (OPTSIDEBARNEWMAILONLY);
++
++ BUFFY *b;
++ int i;
++ for (i = 0; i < arr_len; i++)
++ {
++ b = arr[i];
++
++ b->is_hidden = 0;
++
++ if (!new_only)
++ continue;
++
++ if ((b == OpnBuffy) || (b->msg_unread > 0) ||
++ (b == HilBuffy) || (b->msg_flagged > 0))
++ continue;
++
++ if (Context && (strcmp (b->path, Context->path) == 0))
++ /* Spool directory */
++ continue;
++
++ if (mutt_find_list (SidebarWhitelist, b->path))
++ /* Explicitly asked to be visible */
++ continue;
++
++ b->is_hidden = 1;
++ }
++}
++
++/**
++ * sort_buffy_array - Sort an array of BUFFY pointers
++ * @arr: array of BUFFYs
++ * @arr_len: number of BUFFYs in array
++ *
++ * Sort an array of BUFFY pointers 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".
++ *
++ * Once sorted, the prev/next links will be reconstructed.
++ */
++static void sort_buffy_array (BUFFY **arr, int arr_len)
++{
++ if (!arr)
++ return;
++
++ /* 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;
++}
++
++/**
++ * prepare_sidebar - Prepare the list of BUFFYs 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.
++ *
++ * 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.
++ *
++ * Returns:
++ * 0: No, don't draw the sidebar
++ * 1: Yes, draw the sidebar
++ */
++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;
++
++ update_buffy_visibility (arr, count);
++ sort_buffy_array (arr, count);
++
++ if (sidebar_source == SB_SRC_INCOMING)
++ Incoming = arr[0];
++
++ int top_index = 0;
++ int opn_index = -1;
++ int hil_index = -1;
++ int bot_index = -1;
++
++ for (i = 0; i < count; i++)
++ {
++ if (OpnBuffy == arr[i])
++ opn_index = i;
++ if (HilBuffy == arr[i])
++ hil_index = i;
++ }
++
++ if (!HilBuffy || (SidebarSortMethod != PreviousSort))
++ {
++ if (OpnBuffy)
++ {
++ HilBuffy = OpnBuffy;
++ hil_index = opn_index;
++ }
++ else
++ {
++ HilBuffy = arr[0];
++ hil_index = 0;
++ }
++ }
++ if (TopBuffy)
++ top_index = (hil_index / 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];
++
++ Outgoing = arr[count - 1];
++
++ PreviousSort = SidebarSortMethod;
++ FREE (&arr);
++ return 1;
++}
++
++/**
++ * visible - Should we display the sidebar?
++ *
++ * After validating the config options "sidebar_visible" and "sidebar_width",
++ * determine whether we should display the sidebar.
++ *
++ * When not visible, set the global SidebarWidth to 0.
++ *
++ * Returns:
++ * Boolean
++ */
++static short
++visible (void)
++{
++ short new_visible = option (OPTSIDEBAR);
++ short new_width = SidebarWidth;
++
++ if (OldWidth != new_width)
++ {
++ if (new_width > 0)
++ {
++ OldWidth = new_width;
++ }
++ }
++
++ if (OldVisible != new_visible)
++ {
++ if (new_visible)
++ {
++ set_option (OPTSIDEBAR);
++ }
++ else
++ {
++ unset_option (OPTSIDEBAR);
++ }
++ OldVisible = new_visible;
++ }
++ else if (new_width == 0)
++ {
++ unset_option (OPTSIDEBAR);
++ OldVisible = 0;
++ }
++
++ if (!option (OPTSIDEBAR))
++ {
++ SidebarWidth = 0;
++ }
++ else if (new_width == 0)
++ {
++ SidebarWidth = OldWidth;
++ }
++ else
++ {
++ SidebarWidth = new_width;
++ }
++
++ return new_visible;
++}
++
++/**
++ * draw_divider - Draw a line between the sidebar and the rest of mutt
++ * @first_row: Screen line to start (0-based)
++ * @num_rows: Number of rows to fill
++ *
++ * Draw a divider using characters from the config option "sidebar_divider_char".
++ * This can be an ASCII or Unicode character. First we calculate this
++ * characters' width in screen columns, then subtract that from the config
++ * option "sidebar_width".
++ *
++ * Returns:
++ * -1: Error: bad character, etc
++ * 0: Error: 0 width character
++ * n: Success: character occupies n screen columns
++ */
++static int draw_divider (int first_row, int num_rows)
++{
++ /* Calculate the width of the delimiter in screen cells */
++ int delim_len = mutt_strwidth (SidebarDividerChar);
++
++ if (delim_len < 1)
++ return delim_len;
++
++ if ((SidebarWidth + delim_len) > (COLS + 1))
++ return 0;
++
++ if (delim_len > SidebarWidth)
++ return -1;
++
++ SETCOLOR(MT_COLOR_DIVIDER);
++
++ int i;
++ for (i = 0; i < num_rows; i++)
++ {
++ move (first_row + i, SidebarWidth - delim_len);
++ addstr (NONULL(SidebarDividerChar));
++ }
++
++ return delim_len;
++}
++
++/**
++ * fill_empty_space - Wipe the remaining Sidebar space
++ * @first_row: Screen line to start (0-based)
++ * @num_rows: Number of rows to fill
++ * @width: Width of the Sidebar (minus the divider)
++ *
++ * Write spaces over the area the sidebar isn't using.
++ */
++static void fill_empty_space (int first_row, int num_rows, int width)
++{
++ /* Fill the remaining rows with blank space */
++ SETCOLOR(MT_COLOR_NORMAL);
++
++ int r;
++ for (r = 0; r < num_rows; r++)
++ {
++ int i = 0;
++ move (first_row + r, 0);
++ for (; i < width; i++)
++ addch (' ');
++ }
++}
++
++/**
++ * draw_sidebar - Write out a list of mailboxes, on the left
++ * @first_row: Screen line to start (0-based)
++ * @num_rows: Number of rows to fill
++ * @div_width: Width in screen characters taken by the divider
++ *
++ * Display a list of mailboxes in a panel on the left. What's displayed will
++ * depend on our index markers: TopBuffy, OpnBuffy, HilBuffy, BotBuffy.
++ * On the first run they'll be NULL, so we display the top of Mutt's list
++ * (Incoming).
++ *
++ * TopBuffy - first visible mailbox
++ * BotBuffy - last visible mailbox
++ * OpnBuffy - mailbox shown in Mutt's Index Panel
++ * HilBuffy - Unselected mailbox (the paging follows this)
++ *
++ * The entries are formatted using "sidebar_format" and may be abbreviated:
++ * "sidebar_short_path", indented: "sidebar_folder_indent",
++ * "sidebar_indent_string" and sorted: "sidebar_sort_method". Finally, they're
++ * trimmed to fit the available space.
++ */
++static void draw_sidebar (int first_row, int num_rows, int div_width)
++{
++ BUFFY *b = TopBuffy;
++ if (!b)
++ return;
++
++ int w = MIN(COLS, (SidebarWidth - div_width));
++ int row = 0;
++ for (b = TopBuffy; b && (row < num_rows); b = b->next)
++ {
++ if (b->is_hidden)
++ continue;
++
++ if (b == OpnBuffy)
++ {
++ if ((ColorDefs[MT_COLOR_SB_INDICATOR] != 0))
++ SETCOLOR(MT_COLOR_SB_INDICATOR);
++ else
++ SETCOLOR(MT_COLOR_INDICATOR);
++ }
++ else if (b == HilBuffy)
++ 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)
++ SETCOLOR(MT_COLOR_NEW);
++ else if (b->msg_flagged > 0)
++ SETCOLOR(MT_COLOR_FLAGGED);
++ else
++ SETCOLOR(MT_COLOR_NORMAL);
++
++ move (first_row + row, 0);
++ if (Context && Context->path &&
++ (!strcmp (b->path, Context->path)||
++ !strcmp (b->realpath, Context->path)))
++ {
++ b->msg_unread = Context->unread;
++ b->msg_count = Context->msgcount;
++ b->msg_flagged = Context->flagged;
++ }
++
++ /* compute length of Maildir without trailing separator */
++ size_t maildirlen = strlen (Maildir);
++ if (SidebarDelimChars && strchr (SidebarDelimChars, Maildir[maildirlen - 1]))
++ maildirlen--;
++
++ /* check whether Maildir is a prefix of the current folder's path */
++ short maildir_is_prefix = 0;
++ if ((strlen (b->path) > maildirlen) && (strncmp (Maildir, b->path, maildirlen) == 0))
++ maildir_is_prefix = 1;
++
++ /* calculate depth of current folder and generate its display name with indented spaces */
++ int sidebar_folder_depth = 0;
++ char *sidebar_folder_name;
++ int i;
++ if (option (OPTSIDEBARSHORTPATH))
++ {
++ /* disregard a trailing separator, so strlen() - 2 */
++ sidebar_folder_name = b->path;
++ for (i = strlen (sidebar_folder_name) - 2; i >= 0; i--)
++ {
++ if (SidebarDelimChars &&
++ strchr (SidebarDelimChars, sidebar_folder_name[i]))
++ {
++ sidebar_folder_name += (i + 1);
++ break;
++ }
++ }
++ }
++ else
++ sidebar_folder_name = b->path + maildir_is_prefix * (maildirlen + 1);
++
++ if (maildir_is_prefix && option (OPTSIDEBARFOLDERINDENT))
++ {
++ const char *tmp_folder_name;
++ int lastsep = 0;
++ tmp_folder_name = b->path + maildirlen + 1;
++ int tmplen = (int) strlen (tmp_folder_name) - 1;
++ for (i = 0; i < tmplen; i++)
++ {
++ if (SidebarDelimChars && strchr (SidebarDelimChars, tmp_folder_name[i]))
++ {
++ sidebar_folder_depth++;
++ lastsep = i + 1;
++ }
++ }
++ if (sidebar_folder_depth > 0)
++ {
++ if (option (OPTSIDEBARSHORTPATH))
++ tmp_folder_name += lastsep; /* basename */
++ sidebar_folder_name = malloc (strlen (tmp_folder_name) + sidebar_folder_depth*strlen (NONULL(SidebarIndentString)) + 1);
++ 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));
++ }
++ }
++#ifdef USE_NOTMUCH
++ else if (b->magic == M_NOTMUCH)
++ {
++ sidebar_folder_name = b->desc;
++ }
++#endif
++ char str[STRING];
++ make_sidebar_entry (str, sizeof (str), w, sidebar_folder_name, b);
++ printw ("%s", str);
++ if (sidebar_folder_depth > 0)
++ FREE (&sidebar_folder_name);
++ row++;
++ }
++
++ fill_empty_space (first_row + row, num_rows - row, w);
++}
++
++
++/**
++ * mutt_sb_init - Set some default values for the sidebar.
++ */
++void
++mutt_sb_init (void)
++{
++ OldVisible = option (OPTSIDEBAR);
++ if (SidebarWidth > 0)
++ {
++ OldWidth = SidebarWidth;
++ }
++ else
++ {
++ OldWidth = 20;
++ if (OldVisible)
++ {
++ SidebarWidth = OldWidth;
++ }
++ }
++}
++
++/**
++ * mutt_sb_draw - Completely redraw the sidebar
++ *
++ * Completely refresh the sidebar region. First draw the divider; then, for
++ * each BUFFY, call make_sidebar_entry; finally blank out any remaining space.
++ */
++void mutt_sb_draw (void)
++{
++ if (!visible())
++ return;
++
++ /* XXX - if transitioning from invisible to visible */
++ /* if (OldVisible == 0) */
++ /* mutt_buffy_check (1); we probably have bad or no numbers */
++
++ int first_row = 0;
++ int num_rows = LINES - 2;
++
++ if (option (OPTHELP) || option (OPTSTATUSONTOP))
++ first_row++;
++
++ if (option (OPTHELP))
++ num_rows--;
++
++ int div_width = draw_divider (first_row, num_rows);
++ if (div_width < 0)
++ return;
++
++ if (!get_incoming())
++ {
++ int w = MIN(COLS, (SidebarWidth - div_width));
++ fill_empty_space (first_row, num_rows, w);
++ return;
++ }
++
++ if (!prepare_sidebar (num_rows))
++ return;
++
++ draw_sidebar (first_row, num_rows, div_width);
++}
++
++/**
++ * mutt_sb_should_refresh - Check if the sidebar is due to be refreshed
++ *
++ * The "sidebar_refresh_time" config option allows the user to limit the frequency
++ * with which the sidebar is refreshed.
++ *
++ * Returns:
++ * 1 Yes, refresh is due
++ * 0 No, refresh happened recently
++ */
++int mutt_sb_should_refresh (void)
++{
++ if (!option (OPTSIDEBAR))
++ return 0;
++
++ if (SidebarRefreshTime == 0)
++ return 0;
++
++ time_t diff = (time (NULL) - LastRefresh);
++
++ return (diff >= SidebarRefreshTime);
++}
++
++/**
++ * mutt_sb_change_mailbox - Change the selected mailbox
++ * @op: Operation code
++ *
++ * Change the selected mailbox, e.g. "Next mailbox", "Previous Mailbox
++ * with new mail". The operations are listed OPS.SIDEBAR which is built
++ * into an enum in keymap_defs.h.
++ *
++ * If the operation is successful, HilBuffy will be set to the new mailbox.
++ * This function only *selects* the mailbox, doesn't *open* it.
++ *
++ * Allowed values are: OP_SIDEBAR_NEXT, OP_SIDEBAR_NEXT_NEW,
++ * OP_SIDEBAR_PAGE_DOWN, OP_SIDEBAR_PAGE_UP, OP_SIDEBAR_PREV,
++ * OP_SIDEBAR_PREV_NEW.
++ */
++void mutt_sb_change_mailbox (int op)
++{
++ BUFFY *b;
++ if (!HilBuffy) /* It'll get reset on the next draw */
++ return;
++
++ switch (op)
++ {
++ case OP_SIDEBAR_NEXT:
++ if (!HilBuffy->next)
++ return;
++ if (HilBuffy->next->is_hidden)
++ return;
++ HilBuffy = HilBuffy->next;
++ break;
++ case OP_SIDEBAR_NEXT_NEW:
++ b = find_next_new (option (OPTSIDEBARNEXTNEWWRAP));
++ if (!b)
++ return;
++ else
++ HilBuffy = b;
++ break;
++ case OP_SIDEBAR_PAGE_DOWN:
++ HilBuffy = BotBuffy;
++ if (HilBuffy->next)
++ HilBuffy = HilBuffy->next;
++ break;
++ case OP_SIDEBAR_PAGE_UP:
++ HilBuffy = TopBuffy;
++ if (HilBuffy != get_incoming())
++ HilBuffy = HilBuffy->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 */
++ return;
++ HilBuffy = HilBuffy->prev;
++ break;
++ case OP_SIDEBAR_PREV_NEW:
++ b = find_prev_new (option (OPTSIDEBARNEXTNEWWRAP));
++ if (!b)
++ return;
++ else
++ HilBuffy = b;
++ break;
++ default:
++ return;
++ }
++
++ /* We can change folder even if the sidebar is hidden */
++ if (option (OPTSIDEBAR))
++ mutt_sb_draw();
++}
++
++/**
++ * mutt_sb_set_buffystats - Update the BUFFY's message counts from the CONTEXT
++ * @ctx: A mailbox CONTEXT
++ *
++ * Given a mailbox CONTEXT, find a matching mailbox BUFFY and copy the message
++ * counts into it.
++ */
++void mutt_sb_set_buffystats (const CONTEXT *ctx)
++{
++ /* Even if the sidebar's hidden,
++ * we should take note of the new data. */
++ BUFFY *b = get_incoming();
++ if (!ctx || !b)
++ return;
++
++ for (; b; b = b->next)
++ {
++ if (!strcmp (b->path, ctx->path) ||
++ !strcmp (b->realpath, ctx->path))
++ {
++ b->msg_unread = ctx->unread;
++ b->msg_count = ctx->msgcount;
++ b->msg_flagged = ctx->flagged;
++ break;
++ }
++ }
++}
++
++/**
++ * mutt_sb_get_highlight - Get the BUFFY that's highlighted in the sidebar
++ *
++ * Get the path of the mailbox that's highlighted in the sidebar.
++ *
++ * Returns:
++ * Mailbox path
++ */
++const char *mutt_sb_get_highlight (void)
++{
++ if (!HilBuffy)
++ return NULL;
++
++ return HilBuffy->path;
++}
++
++/**
++ * mutt_sb_set_open_buffy - Set the OpnBuffy based on a mailbox path
++ * @path: Mailbox path
++ *
++ * 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)
++{
++ /* Even if the sidebar is hidden */
++
++ BUFFY *b = get_incoming();
++
++ if (!path || !b)
++ return NULL;
++
++ OpnBuffy = NULL;
++
++ for (; b; b = b->next)
++ {
++ if (!strcmp (b->path, path) ||
++ !strcmp (b->realpath, path))
++ {
++ OpnBuffy = b;
++ HilBuffy = b;
++ 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);
++}
++
++/**
++ * mutt_sb_notify_mailbox - The state of a BUFFY is about to change
++ *
++ * We receive a notification:
++ * After a new BUFFY has been created
++ * Before a BUFFY is deleted
++ *
++ * Before a deletion, check that our pointers won't be invalidated.
++ */
++void mutt_sb_notify_mailbox (BUFFY *b, int created)
++{
++ if (!b)
++ 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)
++ {
++ /* This might happen if the user "unmailboxes *", then
++ * "mailboxes" our current mailbox back again */
++ if (mutt_strcmp (b->path, Context->path) == 0)
++ OpnBuffy = b;
++ }
++ }
++ 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;
++ }
++}
++
++/**
++ * sb_toggle_virtual - Switch between regular and virtual folders
++ */
++void
++mutt_sb_toggle_virtual (void)
++{
++ if (sidebar_source == -1)
++ get_incoming();
++
++#ifdef USE_NOTMUCH
++ if ((sidebar_source == SB_SRC_INCOMING) && VirtIncoming)
++ sidebar_source = SB_SRC_VIRT;
++ else
++#endif
++ sidebar_source = SB_SRC_INCOMING;
++
++ TopBuffy = NULL;
++ OpnBuffy = NULL;
++ HilBuffy = NULL;
++ BotBuffy = NULL;
++ Outgoing = NULL;
++
++ mutt_sb_draw();
++}
++
+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 @@
++/* 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>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
++ */
++
++#ifndef SIDEBAR_H
++#define SIDEBAR_H
++
++#include "mutt.h"
++#include "buffy.h"
++
++void mutt_sb_change_mailbox (int op);
++void mutt_sb_draw (void);
++const char * mutt_sb_get_highlight (void);
++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_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
+@@ -24,6 +24,11 @@
+ #include "sort.h"
+ #include "mutt_idna.h"
+
++#ifdef USE_NNTP
++#include "mx.h"
++#include "nntp.h"
++#endif
++
+ #include <stdlib.h>
+ #include <string.h>
+ #include <ctype.h>
+@@ -151,6 +156,17 @@
+ HEADER **ha = (HEADER **) a;
+ HEADER **hb = (HEADER **) b;
+
++#ifdef USE_NNTP
++ if (Context && Context->magic == M_NNTP)
++ {
++ anum_t na = NHDR (*ha)->article_num;
++ anum_t nb = NHDR (*hb)->article_num;
++ int result = na == nb ? 0 : na > nb ? 1 : -1;
++ AUXSORT (result, a, b);
++ return (SORTCODE (result));
++ }
++ else
++#endif
+ /* no need to auxsort because you will never have equality here */
+ return (SORTCODE ((*ha)->index - (*hb)->index));
+ }
+@@ -210,6 +226,46 @@
+ return (SORTCODE(result));
+ }
+
++int compare_label (const void *a, const void *b)
++{
++ HEADER **ppa = (HEADER **) a;
++ HEADER **ppb = (HEADER **) b;
++ int ahas, bhas, result = 0;
++ LIST *la, *lb;
++
++ /* As with compare_spam, not all messages will have the x-label
++ * property. Blank X-Labels are treated as null in the index
++ * display, so we'll consider them as null for sort, too. */
++ ahas = (*ppa)->env && (*ppa)->env->labels;
++ bhas = (*ppb)->env && (*ppb)->env->labels;
++
++ /* First we bias toward a message with a label, if the other does not. */
++ if (ahas && !bhas)
++ return (SORTCODE(-1));
++ if (!ahas && bhas)
++ return (SORTCODE(1));
++
++ /* If neither has a label, use aux sort. */
++ if (!ahas && !bhas)
++ {
++ AUXSORT(result, a, b);
++ return (SORTCODE(result));
++ }
++
++ /* If both have a label, we just do a lexical compare. */
++ for (la = (*ppa)->env->labels, lb = (*ppb)->env->labels;
++ la && la->data && lb && lb->data && result == 0;
++ la = la->next, lb = lb->next)
++ {
++ result = mutt_strcasecmp(la->data, lb->data);
++ }
++ if (result == 0 && la == NULL)
++ return (SORTCODE(-1));
++ if (result == 0 && lb == NULL)
++ return (SORTCODE(1));
++ return (SORTCODE(result));
++}
++
+ sort_t *mutt_get_sort_func (int method)
+ {
+ switch (method & SORT_MASK)
+@@ -232,6 +288,8 @@
+ return (compare_score);
+ case SORT_SPAM:
+ return (compare_spam);
++ case SORT_LABEL:
++ return (compare_label);
+ 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
+@@ -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_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 @@
+ WHERE short Sort INITVAL (SORT_DATE);
+ WHERE short SortAux INITVAL (SORT_DATE); /* auxiliary sorting method */
+ WHERE short SortAlias INITVAL (SORT_ALIAS);
++WHERE short SidebarSortMethod INITVAL (SORT_ORDER);
+
+ /* 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
+@@ -27,6 +27,10 @@
+ #include "mapping.h"
+ #include "mx.h"
+
++#ifdef USE_NOTMUCH
++#include "mutt_notmuch.h"
++#endif
++
+ #include <string.h>
+ #include <ctype.h>
+ #include <unistd.h>
+@@ -95,7 +99,20 @@
+ break;
+
+ case 'f':
+- snprintf (fmt, sizeof(fmt), "%%%ss", prefix);
++ {
++#ifdef USE_NOTMUCH
++ char *p;
++ if (Context && Context->magic == M_NOTMUCH &&
++ (p = nm_get_description(Context)))
++ strfcpy(tmp, p, sizeof (tmp));
++ else
++#endif
++#ifdef USE_COMPRESSED
++ if (Context && Context->compress_info && Context->realpath) {
++ strfcpy (tmp, Context->realpath, sizeof (tmp));
++ mutt_pretty_mailbox (tmp, sizeof (tmp));
++ } else
++#endif
+ if (Context && Context->path)
+ {
+ strfcpy (tmp, Context->path, sizeof (tmp));
+@@ -103,9 +120,11 @@
+ }
+ else
+ strfcpy (tmp, _("(no mailbox)"), sizeof (tmp));
++
++ snprintf (fmt, sizeof(fmt), "%%%ss", prefix);
+ snprintf (buf, buflen, fmt, tmp);
+ break;
+-
++ }
+ 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
+@@ -0,0 +1,19 @@
++/*
++ * Copyright (C) 2013 Karel Zak <kzak at redhat.com>
++ */
++
++#if HAVE_CONFIG_H
++# include "config.h"
++#endif
++
++#include "mutt.h"
++
++char *strndup(const char *s, size_t n)
++{
++ size_t len = strnlen(s, n);
++ char *new = (char *) malloc((len + 1) * sizeof(char));
++ if (!new)
++ return NULL;
++ 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
+@@ -0,0 +1,20 @@
++/*
++ * Copyright (C) 2013 Karel Zak <kzak at redhat.com>
++ */
++
++#if HAVE_CONFIG_H
++# include "config.h"
++#endif
++
++#include "mutt.h"
++
++size_t strnlen(const char *s, size_t maxlen)
++{
++ int i;
++
++ for (i = 0; i < maxlen; i++) {
++ if (s[i] == '\0')
++ return i + 1;
++ }
++ 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 @@
+ { "imaps", U_IMAPS },
+ { "pop", U_POP },
+ { "pops", U_POPS },
++ { "news", U_NNTP },
++ { "snews", U_NNTPS },
+ { "mailto", U_MAILTO },
++#ifdef USE_NOTMUCH
++ { "notmuch", U_NOTMUCH },
++#endif
+ { "smtp", U_SMTP },
+ { "smtps", U_SMTPS },
+ { NULL, U_UNKNOWN }
+ };
+
+-static int url_pct_decode (char *s)
++int url_pct_decode (char *s)
+ {
+ char *d;
+
+@@ -214,7 +219,7 @@
+ safe_strcat (dest, len, "//");
+ len -= (l = strlen (dest)); dest += l;
+
+- if (ciss->user)
++ if (ciss->user && (ciss->user[0] || !(flags & U_PATH)))
+ {
+ 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 @@
+ U_POPS,
+ U_IMAP,
+ U_IMAPS,
++ U_NNTP,
++ U_NNTPS,
+ U_SMTP,
+ U_SMTPS,
+ U_MAILTO,
++#ifdef USE_NOTMUCH
++ U_NOTMUCH,
++#endif
+ U_UNKNOWN
+ }
+ url_scheme_t;
+@@ -34,5 +39,6 @@
+ 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
+@@ -0,0 +1,516 @@
++/**
++ * Copyright (C) 1996-2007 Michael R. Elkins <me at mutt.org>
++ * Copyright (C) 1999-2007 Thomas Roessler <roessler at does-not-exist.org>
++ * Copyright (C) 2016 Richard Russon
++ *
++ * 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 <stdio.h>
++#include <string.h>
++#include <sys/utsname.h>
++
++#ifdef HAVE_STRINGPREP_H
++#include <stringprep.h>
++#elif defined (HAVE_IDN_STRINGPREP_H)
++#include <idn/stringprep.h>
++#endif
++#ifdef USE_SLANG_CURSES
++#include "slang.h"
++#endif
++
++#include "lib.h"
++
++// #include "protos.h"
++const char * mutt_make_version (void);
++void mutt_print_patchlist (void);
++
++// #include "hcache.h"
++const char * mutt_hcache_backend (void);
++
++const int SCREEN_WIDTH = 80;
++
++extern const char cc_version[];
++extern const char cc_cflags[];
++extern const char configure_options[];
++
++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 *License = 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"
++);
++
++static const char *ReachingUs = N_(
++ "To learn more about NeoMutt, visit: http://www.neomutt.org/\n"
++ "If you find a bug in NeoMutt, please raise an issue at:\n"
++ " https://github.com/neomutt/neomutt/issues\n"
++ "or contact the lead developer: Richard Russon <rich at flatcap.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"
++);
++
++struct compile_options {
++ const char *name;
++ int enabled;
++};
++
++static struct compile_options comp_opts[] = {
++#ifdef CRYPT_BACKEND_CLASSIC_PGP
++ { "CRYPT_BACKEND_CLASSIC_PGP", 1 },
++#else
++ { "CRYPT_BACKEND_CLASSIC_PGP", 0 },
++#endif
++#ifdef CRYPT_BACKEND_CLASSIC_SMIME
++ { "CRYPT_BACKEND_CLASSIC_SMIME", 1 },
++#else
++ { "CRYPT_BACKEND_CLASSIC_SMIME", 0 },
++#endif
++#ifdef CRYPT_BACKEND_GPGME
++ { "CRYPT_BACKEND_GPGME", 1 },
++#else
++ { "CRYPT_BACKEND_GPGME", 0 },
++#endif
++#ifdef DEBUG
++ { "DEBUG", 1 },
++#else
++ { "DEBUG", 0 },
++#endif
++#ifdef DL_STANDALONE
++ { "DL_STANDALONE", 1 },
++#else
++ { "DL_STANDALONE", 0 },
++#endif
++#ifdef ENABLE_NLS
++ { "ENABLE_NLS", 1 },
++#else
++ { "ENABLE_NLS", 0 },
++#endif
++#ifdef EXACT_ADDRESS
++ { "EXACT_ADDRESS", 1 },
++#else
++ { "EXACT_ADDRESS", 0 },
++#endif
++#ifdef HOMESPOOL
++ { "HOMESPOOL", 1 },
++#else
++ { "HOMESPOOL", 0 },
++#endif
++#ifdef LOCALES_HACK
++ { "LOCALES_HACK", 1 },
++#else
++ { "LOCALES_HACK", 0 },
++#endif
++#ifdef SUN_ATTACHMENT
++ { "SUN_ATTACHMENT", 1 },
++#else
++ { "SUN_ATTACHMENT", 0 },
++#endif
++#ifdef HAVE_BKGDSET
++ { "HAVE_BKGDSET", 1 },
++#else
++ { "HAVE_BKGDSET", 0 },
++#endif
++#ifdef HAVE_COLOR
++ { "HAVE_COLOR", 1 },
++#else
++ { "HAVE_COLOR", 0 },
++#endif
++#ifdef HAVE_CURS_SET
++ { "HAVE_CURS_SET", 1 },
++#else
++ { "HAVE_CURS_SET", 0 },
++#endif
++#ifdef HAVE_GETADDRINFO
++ { "HAVE_GETADDRINFO", 1 },
++#else
++ { "HAVE_GETADDRINFO", 0 },
++#endif
++#ifdef HAVE_GETSID
++ { "HAVE_GETSID", 1 },
++#else
++ { "HAVE_GETSID", 0 },
++#endif
++#ifdef HAVE_ICONV
++ { "HAVE_ICONV", 1 },
++#else
++ { "HAVE_ICONV", 0 },
++#endif
++#ifdef HAVE_LANGINFO_CODESET
++ { "HAVE_LANGINFO_CODESET", 1 },
++#else
++ { "HAVE_LANGINFO_CODESET", 0 },
++#endif
++#ifdef HAVE_LANGINFO_YESEXPR
++ { "HAVE_LANGINFO_YESEXPR", 1 },
++#else
++ { "HAVE_LANGINFO_YESEXPR", 0 },
++#endif
++#ifdef HAVE_LIBIDN
++ { "HAVE_LIBIDN", 1 },
++#else
++ { "HAVE_LIBIDN", 0 },
++#endif
++#ifdef HAVE_META
++ { "HAVE_META", 1 },
++#else
++ { "HAVE_META", 0 },
++#endif
++#ifdef HAVE_REGCOMP
++ { "HAVE_REGCOMP", 1 },
++#else
++ { "HAVE_REGCOMP", 0 },
++#endif
++#ifdef HAVE_RESIZETERM
++ { "HAVE_RESIZETERM", 1 },
++#else
++ { "HAVE_RESIZETERM", 0 },
++#endif
++#ifdef HAVE_START_COLOR
++ { "HAVE_START_COLOR", 1 },
++#else
++ { "HAVE_START_COLOR", 0 },
++#endif
++#ifdef HAVE_TYPEAHEAD
++ { "HAVE_TYPEAHEAD", 1 },
++#else
++ { "HAVE_TYPEAHEAD", 0 },
++#endif
++#ifdef HAVE_WC_FUNCS
++ { "HAVE_WC_FUNCS", 1 },
++#else
++ { "HAVE_WC_FUNCS", 0 },
++#endif
++#ifdef ICONV_NONTRANS
++ { "ICONV_NONTRANS", 1 },
++#else
++ { "ICONV_NONTRANS", 0 },
++#endif
++#ifdef USE_COMPRESSED
++ { "USE_COMPRESSED", 1 },
++#else
++ { "USE_COMPRESSED", 0 },
++#endif
++#ifdef USE_DOTLOCK
++ { "USE_DOTLOCK", 1 },
++#else
++ { "USE_DOTLOCK", 0 },
++#endif
++#ifdef USE_FCNTL
++ { "USE_FCNTL", 1 },
++#else
++ { "USE_FCNTL", 0 },
++#endif
++#ifdef USE_FLOCK
++ { "USE_FLOCK", 1 },
++#else
++ { "USE_FLOCK", 0 },
++#endif
++#ifdef USE_GNU_REGEX
++ { "USE_GNU_REGEX", 1 },
++#else
++ { "USE_GNU_REGEX", 0 },
++#endif
++#ifdef USE_GSS
++ { "USE_GSS", 1 },
++#else
++ { "USE_GSS", 0 },
++#endif
++#ifdef USE_HCACHE
++ { "USE_HCACHE", 1 },
++#else
++ { "USE_HCACHE", 0 },
++#endif
++#ifdef USE_IMAP
++ { "USE_IMAP", 1 },
++#else
++ { "USE_IMAP", 0 },
++#endif
++#ifdef USE_NOTMUCH
++ { "USE_NOTMUCH", 1 },
++#else
++ { "USE_NOTMUCH", 0 },
++#endif
++#ifdef USE_NNTP
++ { "USE_NNTP", 1 },
++#else
++ { "USE_NNTP", 0 },
++#endif
++#ifdef USE_POP
++ { "USE_POP", 1 },
++#else
++ { "USE_POP", 0 },
++#endif
++#ifdef USE_SASL
++ { "USE_SASL", 1 },
++#else
++ { "USE_SASL", 0 },
++#endif
++#ifdef USE_SETGID
++ { "USE_SETGID", 1 },
++#else
++ { "USE_SETGID", 0 },
++#endif
++#ifdef USE_SIDEBAR
++ { "USE_SIDEBAR", 1 },
++#else
++ { "USE_SIDEBAR", 0 },
++#endif
++#ifdef USE_SMTP
++ { "USE_SMTP", 1 },
++#else
++ { "USE_SMTP", 0 },
++#endif
++#ifdef USE_SSL_GNUTLS
++ { "USE_SSL_GNUTLS", 1 },
++#else
++ { "USE_SSL_GNUTLS", 0 },
++#endif
++#ifdef USE_SSL_OPENSSL
++ { "USE_SSL_OPENSSL", 1 },
++#else
++ { "USE_SSL_OPENSSL", 0 },
++#endif
++ { NULL, 0 }
++};
++
++/**
++ * print_compile_options - Print a list of enabled/disabled features
++ *
++ * The configure script lets uses enable/disable features.
++ * This shows the Mutt user which features are/aren't available.
++ *
++ * The output is of the form: "+ENABLED_FEATURE -DISABLED_FEATURE" and is
++ * wrapped to SCREEN_WIDTH characters.
++ */
++static void
++print_compile_options (void)
++{
++ int i;
++ char c;
++ int len;
++ int used = 0;
++
++ for (i = 0; comp_opts[i].name; i++) {
++ len = strlen (comp_opts[i].name) + 2; /* +/- and a space */
++ if ((used + len) > SCREEN_WIDTH) {
++ used = 0;
++ puts ("");
++ }
++ used += len;
++ c = comp_opts[i].enabled ? '+' : '-';
++ printf ("%c%s ", c, comp_opts[i].name);
++ }
++ puts ("");
++}
++
++/**
++ * rstrip_in_place - Strip a trailing carriage return
++ * @s: String to be modified
++ *
++ * The string has its last carriage return set to NUL.
++ * Returns:
++ * The modified string
++ */
++static char *
++rstrip_in_place (char *s)
++{
++ if (!s)
++ return NULL;
++
++ char *p;
++
++ p = &s[strlen (s)];
++ if (p == s)
++ return s;
++ p--;
++ while ((p >= s) && ((*p == '\n') || (*p == '\r')))
++ *p-- = '\0';
++ return s;
++}
++
++/**
++ * print_version - Print system and compile info
++ *
++ * Print information about the current system Mutt is running on.
++ * Also print a list of all the compile-time information.
++ */
++void
++print_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:"));
++ print_compile_options();
++
++#ifdef DOMAIN
++ printf ("DOMAIN=\"%s\"\n", DOMAIN);
++#else
++ puts ("-DOMAIN");
++#endif
++
++#ifdef MIXMASTER
++ printf ("MIXMASTER=\"%s\"\n", MIXMASTER);
++#else
++ puts ("-MIXMASTER");
++#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);
++
++ puts ("");
++ mutt_print_patchlist();
++
++ puts ("");
++ puts (_(ReachingUs));
++}
++
++/**
++ * print_copyright - Print copyright message
++ *
++ * Print the authors' copyright messages, the GPL license and some contact
++ * information for the Mutt project.
++ */
++void
++print_copyright (void)
++{
++ puts (mutt_make_version());
++ puts (_(Copyright));
++ puts (_(License));
++ puts (_(Obtaining));
++ puts (_(ReachingUs));
++}
++
++/**
++ * feature_enabled - Test is a compile-time feature is enabled
++ * @name: Compile-time symbol of the feature
++ *
++ * Many of the larger features of mutt can be disabled at compile time.
++ * They define a symbol and use #ifdef's around their code.
++ * The symbols are mirrored in "struct compile_options comp_opts[]" in this
++ * file.
++ *
++ * This function checks if one of these symbols is present in the code.
++ *
++ * These symbols are also seen in the output of "mutt -v".
++ *
++ * Returns:
++ * 1: Feature enables
++ * 0: Feature not enabled, or not compiled in
++ */
++int
++feature_enabled (const char *name)
++{
++ if (!name)
++ return 0;
++
++ int i;
++ for (i = 0; comp_opts[i].name; i++) {
++ if (mutt_strcmp (name, comp_opts[i].name) == 0) {
++ return 1;
++ }
++ }
++ 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
+@@ -0,0 +1,26 @@
++/**
++ * Copyright (C) 2016 Richard Russon
++ *
++ * 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 _VERSION_H_
++#define _VERSION_H_
++
++void print_version (void);
++void print_copyright (void);
++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 @@
+ #!/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
+-
+-# 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; } \
+-|| exec cat VERSION
+-
+-# This is a mercurial repo and we have the hg command.
+-
+-# Get essential properties of the current working copy
+-set -- `$HG parents --template='{rev} {node|short}\n'`
+-rev="$1"
+-node="$2"
+-
+-# translate release tags into ##.##.## notation
+-cleantag () {
+- case "$1" in
+- mutt-*-rel) echo "$1" | sed -e 's/mutt-//' -e 's/-rel//' | tr - . ;;
+- *) echo "$1" ;;
+- esac
+-}
+-
+-getdistance_old () {
+- # fudge it
+- set -- `$HG tags | sort -n -k 2 | egrep 'mutt-.*rel' | tail -1 | cut -d: -f1`
+- latesttag="$1"
+- latestrev="$2"
+- distance=`expr $rev - $latestrev`
+- echo $latesttag $distance
+-}
+-
+-getdistance_new () {
+- $HG parents --template='{latesttag} {latesttagdistance}\n'
+-}
+-
+-
+-# latesttag appeared in hg 1.4. Test for it.
+-[ "`$HG log -r . --template='{latesttag}'`" = '' ] &&
+-set -- `getdistance_old` ||
+-set -- `getdistance_new`
+-
+-tag=`cleantag "$1"`
+-dist=$2
+-
+-if [ $dist -eq 0 ]; then
+- dist=
+-else
+- dist="+$dist"
+-fi
+-
+-# if we have mq patches applied, mention it
+-qparent=`$HG log -r qparent --template='{rev}\n' 2>/dev/null || echo $rev`
+-qdelta=`expr $rev - $qparent`
+-if [ $qdelta -eq 0 ]; then
+- qdist=""
+-else
+- qdist=",mq+$qdelta"
+-fi
+-
+-echo "$tag$dist$qdist ($node)"
+-exit 0
diff --git a/debian/patches/neomutt-devel/nntp.patch b/debian/patches/neomutt-devel/nntp.patch
deleted file mode 100644
index 9fc25ea..0000000
--- a/debian/patches/neomutt-devel/nntp.patch
+++ /dev/null
@@ -1,8990 +0,0 @@
-From 82f9607dd091365761dc801ebf98db067b582521 Mon Sep 17 00:00:00 2001
-From: Richard Russon <rich at flatcap.org>
-Date: Thu, 7 Apr 2016 23:02:56 +0100
-Subject: [PATCH 28/28] patches-20160502/nntp
-
-Talk to a Usenet news server
----
- ChangeLog.nntp | 416 +++++++++
- Makefile.am | 2 +
- OPS | 23 +-
- PATCHES | 1 +
- README.nntp | 122 +++
- account.c | 27 +
- account.h | 3 +-
- attach.h | 2 +-
- browser.c | 471 +++++++++-
- browser.h | 7 +
- buffy.c | 12 +
- complete.c | 64 ++
- compose.c | 177 +++-
- configure.ac | 11 +-
- curs_main.c | 312 ++++++-
- doc/manual.xml.head | 392 +++++++++
- doc/mutt.man | 8 +-
- doc/muttrc.nntp | 0
- doc/vimrc-nntp | 50 ++
- functions.h | 59 +-
- globals.h | 18 +-
- hash.c | 27 +
- hash.h | 3 +-
- hcache.c | 12 +
- hdrline.c | 25 +
- headers.c | 3 +
- init.c | 22 +
- init.h | 223 +++++
- keymap.c | 1 -
- mailbox.h | 3 +
- main.c | 48 +
- mutt.h | 40 +-
- mutt_sasl.c | 5 +
- muttlib.c | 17 +-
- mx.c | 79 ++
- mx.h | 3 +
- newsrc.c | 1262 ++++++++++++++++++++++++++
- nntp.c | 2434 +++++++++++++++++++++++++++++++++++++++++++++++++++
- nntp.h | 168 ++++
- pager.c | 81 +-
- parse.c | 48 +-
- pattern.c | 8 +
- po/POTFILES.in | 2 +
- postpone.c | 11 +
- protos.h | 1 +
- recvattach.c | 34 +-
- recvcmd.c | 61 +-
- send.c | 163 +++-
- sendlib.c | 78 +-
- sort.c | 16 +
- url.c | 4 +-
- url.h | 2 +
- version.c | 5 +
- 53 files changed, 6982 insertions(+), 84 deletions(-)
- create mode 100644 ChangeLog.nntp
- create mode 100644 README.nntp
- create mode 100644 doc/muttrc.nntp
- create mode 100644 doc/vimrc-nntp
- create mode 100644 newsrc.c
- create mode 100644 nntp.c
- create mode 100644 nntp.h
-
-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
-+
-+* Wed Nov 25 2015 Vsevolod Volkov <vvv at mutt.org.ua>
-+- fixed memory leaks
-+- fixed SIGSEGV when reading hcache in some cases
-+
-+* 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>
-+
-+* 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
-+
-+* Thu Nov 6 2003 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.5.5.1
-+
-+* Wed Nov 5 2003 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.5.5
-+- added space after newsgroup name in .newsrc file
-+
-+* 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
-+
-+* Thu Oct 12 2000 Vsevolod Volkov <vvv at mutt.org.ua>
-+- update to 1.3.10
-+- hotkey 'G' (get-message) replaced with '^G'
-+
-+* 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()
-+
-+* 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
-+
-+* 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
-+
-+* Sat Jul 29 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- update to 1.3.6
-+
-+* 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
-+
-+* Wed Jun 21 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- update to 1.3.4
-+
-+* Wed Jun 14 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- don't substitute current newsgroup with deleted new messages
-+
-+* 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
-+
-+* Wed May 24 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- update to 1.3.2
-+
-+* Sat May 20 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- update to 1.3.1
-+
-+* Fri May 12 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- update to 1.3
-+
-+* Thu May 11 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- update to 1.2
-+
-+* Thu May 4 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- update to 1.1.14
-+
-+* Sun Apr 23 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- update to 1.1.12
-+
-+* Fri Apr 7 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- add substitution of newsgroup with new messages by default
-+
-+* 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
-+
-+* 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
-+
-+* Sat Apr 1 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- remove 'X-FTN-Origin' header processing
-+
-+* Thu Mar 30 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- update to 1.1.11
-+- update to 1.1.10
-+
-+* Thu Mar 23 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- fix mutt_select_newsserver()
-+- remove 'toggle-mode' function
-+- add 'change-newsgroup' function
-+
-+* Wed Mar 22 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- fix server-hook
-+
-+* Tue Mar 21 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- fix error 'bounce' function after 'post'
-+- add 'forward to newsgroup' function
-+
-+* 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
-+
-+* Tue Mar 14 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- update to 1.1.9
-+- remove deleted newsgroups from list
-+
-+* Mon Mar 13 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- update .newsrc in browser
-+
-+* Sun Mar 12 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- reload .newsrc if externally modified
-+- fix active cache update
-+
-+* Sun Mar 5 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- update to 1.1.8
-+
-+* 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
-+
-+* Thu Mar 2 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- load list of newsgroups from cache faster
-+
-+* Wed Mar 1 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- update to 1.1.7
-+
-+* Tue Feb 29 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- fix unread messages in browser
-+- fix newsrc_gen_entries()
-+
-+* 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()
-+
-+* Fri Feb 25 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- update to 1.1.5
-+
-+* Thu Feb 24 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- fix updating new messages in cache
-+
-+* Mon Feb 21 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- change default cache filenames
-+- fix updating new messages in cache
-+
-+* Fri Feb 18 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- fix segmentation fault in news groups browser
-+
-+* Tue Feb 15 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- update to 1.1.4
-+
-+* Thu Feb 10 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- update to 1.1.3
-+
-+* 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
-+
-+* Fri Jan 28 2000 Vsevolod Volkov <vvv at mutt.kiev.ua>
-+- update to 1.1.2
-diff --git a/Makefile.am b/Makefile.am
-index a97f4ac..ae1c628 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -56,6 +56,7 @@ EXTRA_mutt_SOURCES = account.c bcache.c crypt-gpgme.c crypt-mod-pgp-classic.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 \
-+ nntp.c newsrc.c \
- smime.c smtp.c utf8.c wcwidth.c \
- bcache.h browser.h hcache.h mbyte.h mutt_idna.h remailer.h url.h
-
-@@ -67,6 +68,7 @@ EXTRA_DIST = COPYRIGHT GPL OPS OPS.PGP OPS.CRYPT OPS.SMIME TODO UPDATING \
- 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 \
-diff --git a/OPS b/OPS
-index 02cea8e..41b4e10 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)"
-@@ -85,8 +90,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 +104,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"
-@@ -138,6 +151,7 @@ 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"
-@@ -147,6 +161,7 @@ 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)"
-@@ -161,18 +176,22 @@ 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"
-diff --git a/PATCHES b/PATCHES
-index a2887df..71e4893 100644
---- a/PATCHES
-+++ b/PATCHES
-@@ -3,3 +3,4 @@ patch-compress-neo-UNKNOWN
- patch-sensible-browser-neo-UNKNOWN
- patch-trash-neo-20160502
- patch-ifdef-neo-20160502
-+patch-nntp-neo-UNKNOWN
-diff --git a/README.nntp b/README.nntp
-new file mode 100644
-index 0000000..f8e5020
---- /dev/null
-+++ b/README.nntp
-@@ -0,0 +1,122 @@
-+NNTP Patch
-+==========
-+
-+ Talk to a Usenet news server
-+
-+Patch
-+-----
-+
-+ To check if Mutt supports "NNTP", look for "+USE_NNTP" in the mutt version.
-+
-+ Dependencies
-+ * mutt-1.5.24
-+
-+Introduction
-+------------
-+
-+ Reading news via NNTP
-+
-+ 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.
-+
-+Variables
-+---------
-+
-+ NNTP Variables
-+
-+ | 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' |
-+
-+Functions
-+---------
-+
-+ NNTP Functions
-+
-+ | 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 |
-+
-+Commands
-+--------
-+
-+Colors
-+------
-+
-+ None
-+
-+Sort
-+----
-+
-+ None
-+
-+See Also
-+--------
-+
-+ * NeoMutt project
-+ * Compile-Time Features
-+
-+Known Bugs
-+----------
-+
-+Credits
-+-------
-+
-+ * Vsevolod Volkov <vvv at mutt.org.ua>
-+ * Felix von Leitner <leitner at fefe.de>
-+ * Richard Russon <rich at flatcap.org>
-+
-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
-+
- 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
-+
- 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/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 b0dbeb5..f04ca15 100644
---- a/browser.c
-+++ b/browser.c
-@@ -32,6 +32,9 @@
- #ifdef USE_IMAP
- #include "imap.h"
- #endif
-+#ifdef USE_NNTP
-+#include "nntp.h"
-+#endif
-
- #include <stdlib.h>
- #include <dirent.h>
-@@ -50,6 +53,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
-+
- typedef struct folder_t
- {
- struct folder_file *ff;
-@@ -116,9 +132,17 @@ 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_SUBJECT:
-@@ -325,8 +349,112 @@ folder_format_str (char *dest, size_t destlen, size_t col, char op, const char *
- 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;
-+
-+ switch (op)
-+ {
-+ case 'C':
-+ snprintf (tmp, sizeof (tmp), "%%%sd", fmt);
-+ snprintf (dest, destlen, tmp, folder->num + 1);
-+ break;
-+
-+ case 'f':
-+ strncpy (fn, folder->ff->name, sizeof(fn) - 1);
-+ snprintf (tmp, sizeof (tmp), "%%%ss", fmt);
-+ snprintf (dest, destlen, tmp, fn);
-+ break;
-+
-+ 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;
-+
-+ 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, 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;
-+
-+ 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;
-+
-+ 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);
-+
-+ 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 struct stat *s,
-+ void *data, unsigned int new)
- {
- if (state->entrylen == state->entrymax)
- {
-@@ -355,6 +483,10 @@ static void add_folder (MUTTMENU *m, struct browser_state *state,
- #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)++;
- }
-
-@@ -370,9 +502,36 @@ 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;
-+
-+/* mutt_buffy_check (0); */
-+ init_state (state, menu);
-+
-+ 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,
-+ nntp_data, nntp_data->new);
-+ }
-+ }
-+ else
-+#endif /* USE_NNTP */
-+ {
- struct stat s;
- DIR *dp;
- struct dirent *de;
-@@ -433,17 +592,41 @@ 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, &s, NULL, (tmp) ? tmp->new : 0);
- }
- closedir (dp);
-+ }
- browser_sort (state);
- return 0;
- }
-
-+/* get list of mailboxes/subscribed newsgroups */
- static int examine_mailboxes (MUTTMENU *menu, struct browser_state *state)
- {
- struct stat s;
- char buffer[LONG_STRING];
-+
-+#ifdef USE_NNTP
-+ if (option (OPTNEWS))
-+ {
-+ NNTP_SERVER *nserv = CurrentNewsSrv;
-+ unsigned int i;
-+
-+/* mutt_buffy_check (0); */
-+ init_state (state, menu);
-+
-+ 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,
-+ nntp_data, nntp_data->new);
-+ }
-+ }
-+ else
-+#endif
-+ {
- BUFFY *tmp = Incoming;
- #ifdef USE_IMAP
- struct mailbox_state mbox;
-@@ -461,14 +644,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);
- 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);
-+ continue;
-+ }
-+#endif
-+#ifdef USE_NNTP
-+ if (mx_is_nntp (tmp->path))
-+ {
-+ add_folder (menu, state, tmp->path, NULL, NULL, tmp->new);
- continue;
- }
- #endif
-@@ -497,15 +687,20 @@ 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, &s, NULL, tmp->new);
- }
- 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));
- }
-
-@@ -516,6 +711,12 @@ static void folder_entry (char *s, size_t slen, MUTTMENU *menu, int num)
- 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);
- }
-@@ -536,6 +737,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) {
- menu->is_mailbox_list = 1;
- snprintf (title, titlelen, _("Mailboxes [%d]"), mutt_buffy_check (0));
-@@ -606,6 +818,31 @@ void _mutt_select_file (char *f, size_t flen, int flags, char ***files, int *num
- 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;
-+
-+ /* 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);
-@@ -702,6 +939,9 @@ void _mutt_select_file (char *f, size_t flen, int flags, char ***files, int *num
- menu->tag = file_tag;
-
- 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);
-@@ -838,7 +1078,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);
-@@ -896,14 +1140,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);
-@@ -1004,6 +1240,11 @@ void _mutt_select_file (char *f, size_t flen, int flags, char ***files, int *num
-
- case OP_CHANGE_DIRECTORY:
-
-+#ifdef USE_NNTP
-+ if (option (OPTNEWS))
-+ break;
-+#endif
-+
- strfcpy (buf, LastDir, sizeof (buf));
- #ifdef USE_IMAP
- if (!state.imap_browse)
-@@ -1269,6 +1510,210 @@ void _mutt_select_file (char *f, size_t flen, int flags, char ***files, int *num
- else
- mutt_error _("Error trying to view file");
- }
-+ break;
-+
-+#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;
-+
-+ rc = nntp_newsrc_parse (CurrentNewsSrv);
-+ if (rc < 0)
-+ break;
-+
-+ if (i == OP_CATCHUP)
-+ nntp_data = mutt_newsgroup_catchup (CurrentNewsSrv, f->name);
-+ else
-+ nntp_data = mutt_newsgroup_uncatchup (CurrentNewsSrv, f->name);
-+
-+ if (nntp_data)
-+ {
-+/* FOLDER folder;
-+ struct folder_file ff;
-+ char buffer[_POSIX_PATH_MAX + SHORT_STRING];
-+
-+ 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;
-+
-+ case OP_LOAD_ACTIVE:
-+ if (option (OPTNEWS))
-+ {
-+ NNTP_SERVER *nserv = CurrentNewsSrv;
-+ unsigned int i;
-+
-+ if (nntp_newsrc_parse (nserv) < 0)
-+ break;
-+
-+ 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);
-+
-+ 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;
-+ }
-+
-+ rc = nntp_newsrc_parse (nserv);
-+ if (rc < 0)
-+ break;
-+
-+ for ( ; j < state.entrylen; j++)
-+ {
-+ struct folder_file *f = &state.entry[j];
-+
-+ 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;
-+ }
-+ }
-+ if (i == OP_SUBSCRIBE_PATTERN)
-+ {
-+ unsigned int i;
-+
-+ 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,
-+ nntp_data, nntp_data->new);
-+ }
-+ }
-+ }
-+ 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..ad89ab2 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
-+
- struct folder_file
- {
- mode_t mode;
-@@ -37,6 +41,9 @@ struct folder_file
- unsigned selectable : 1;
- unsigned inferiors : 1;
- #endif
-+#ifdef USE_NNTP
-+ NNTP_DATA *nd;
-+#endif
- unsigned tagged : 1;
- };
-
-diff --git a/buffy.c b/buffy.c
-index 99258c8..4a31b24 100644
---- a/buffy.c
-+++ b/buffy.c
-@@ -580,6 +580,9 @@ int mutt_buffy_check (int force)
-
- /* 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;
-@@ -599,6 +602,11 @@ int mutt_buffy_check (int force)
- tmp->magic = M_POP;
- 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))
- {
-@@ -614,7 +622,11 @@ int mutt_buffy_check (int force)
- /* check to see if the folder is the currently selected folder
- * before polling */
- if (!Context || !Context->path ||
-+#ifdef USE_NNTP
-+ (( tmp->magic == M_IMAP || tmp->magic == M_POP || tmp->magic == M_NNTP )
-+#else
- (( tmp->magic == M_IMAP || tmp->magic == M_POP )
-+#endif
- ? mutt_strcmp (tmp->path, Context->path) :
- (sb.st_dev != contex_sb.st_dev || sb.st_ino != contex_sb.st_ino)))
- {
-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
-
- #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
-
- dprint (2, (debugfile, "mutt_complete: completing %s\n", s));
-
-+#ifdef USE_NNTP
-+ if (option (OPTNEWS))
-+ {
-+ NNTP_SERVER *nserv = CurrentNewsSrv;
-+ unsigned int n = 0;
-+
-+ strfcpy (filepart, s, sizeof (filepart));
-+
-+ /* 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;
-+ }
-+ }
-+ }
-+
-+ for (; n < nserv->groups_num; n++)
-+ {
-+ NNTP_DATA *nntp_data = nserv->groups_list[n];
-+
-+ 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;
-+ }
-+ }
-+ }
-+
-+ strcpy (s, filepart);
-+ return (init ? 0 : -1);
-+ }
-+#endif
-+
-+#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 c7a39c9..04a2e43 100644
---- a/compose.c
-+++ b/compose.c
-@@ -35,11 +35,16 @@
- #ifdef USE_SIDEBAR
- #include "sidebar.h"
- #endif
-+#include "mx.h"
-
- #ifdef MIXMASTER
- #include "remailer.h"
- #endif
-
-+#ifdef USE_NNTP
-+#include "nntp.h"
-+#endif
-+
- #include <errno.h>
- #include <string.h>
- #include <sys/stat.h>
-@@ -70,11 +75,17 @@ enum
- HDR_CRYPT,
- HDR_CRYPTINFO,
-
-+#ifdef USE_NNTP
-+ HDR_NEWSGROUPS,
-+ HDR_FOLLOWUPTO,
-+ HDR_XCOMMENTTO,
-+#endif
-+
- 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 HDR_XOFFSET 14
-+#define TITLE_FMT "%14s" /* Used for Prompts, which are ASCII */
- #define W (COLS - HDR_XOFFSET - SidebarWidth)
-
- static const char * const Prompts[] =
-@@ -86,6 +97,16 @@ static const char * const Prompts[] =
- "Subject: ",
- "Reply-To: ",
- "Fcc: "
-+#ifdef USE_NNTP
-+#ifdef MIXMASTER
-+ ,""
-+#endif
-+ ,""
-+ ,""
-+ ,"Newsgroups: "
-+ ,"Followup-To: "
-+ ,"X-Comment-To: "
-+#endif
- };
-
- static const struct mapping_t ComposeHelp[] = {
-@@ -100,6 +121,19 @@ static const struct mapping_t ComposeHelp[] = {
- { 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
-+
- static void snd_entry (char *b, size_t blen, MUTTMENU *menu, int num)
- {
- mutt_FormatString (b, blen, 0, NONULL (AttachFormat), mutt_attach_fmt,
-@@ -153,11 +187,19 @@ static void redraw_crypt_lines (HEADER *msg)
-
- 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 - 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 - mbstowcs (NULL, s, 0);
-+ mvprintw (HDR_CRYPTINFO, offset < 0 ? 0 : offset, "%s%s", s,
-+ SmimeDefaultKey ? SmimeDefaultKey : _("<default>"));
- }
-
- if ((WithCrypto & APPLICATION_SMIME)
-@@ -255,9 +297,28 @@ static void draw_envelope (HEADER *msg, char *fcc)
- 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);
-+#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);
-@@ -510,6 +571,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 ? */
-+
-+ if (option (OPTNEWSSEND))
-+ news++;
-+#endif
-
- mutt_attach_init (msg->content);
- idx = mutt_gen_attach_list (msg->content, -1, idx, &idxlen, &idxmax, 0, 1);
-@@ -520,10 +587,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
-+#endif
- menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_COMPOSE, ComposeHelp);
-
- while (loop)
- {
-+#ifdef USE_NNTP
-+ unset_option (OPTNEWS); /* for any case */
-+#endif
- switch (op = mutt_menuLoop (menu))
- {
- case OP_REDRAW:
-@@ -536,6 +611,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
- menu->redraw = edit_address_list (HDR_TO, &msg->env->to);
- if (option (OPTCRYPTOPPORTUNISTICENCRYPT))
- {
-@@ -545,6 +624,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
- menu->redraw = edit_address_list (HDR_BCC, &msg->env->bcc);
- if (option (OPTCRYPTOPPORTUNISTICENCRYPT))
- {
-@@ -554,6 +637,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;
-+#endif
- menu->redraw = edit_address_list (HDR_CC, &msg->env->cc);
- if (option (OPTCRYPTOPPORTUNISTICENCRYPT))
- {
-@@ -562,6 +649,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 ();
-+ }
-+ }
-+ 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));
-@@ -730,6 +873,9 @@ int mutt_compose_menu (HEADER *msg, /* structure for new message */
- break;
-
- case OP_COMPOSE_ATTACH_MESSAGE:
-+#ifdef USE_NNTP
-+ case OP_COMPOSE_ATTACH_NEWS_MESSAGE:
-+#endif
- {
- char *prompt;
- HEADER *h;
-@@ -737,7 +883,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;
-+
-+ 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));
-@@ -746,6 +907,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;
-
-+#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))
-@@ -753,6 +919,9 @@ int mutt_compose_menu (HEADER *msg, /* structure for new message */
- #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)
- {
-diff --git a/configure.ac b/configure.ac
-index 7c038fd..9aa056a 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -617,6 +617,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])
-@@ -624,7 +633,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
-
-diff --git a/curs_main.c b/curs_main.c
-index 48443cf..b64a862 100644
---- a/curs_main.c
-+++ b/curs_main.c
-@@ -22,6 +22,7 @@
-
- #include "mutt.h"
- #include "mutt_curses.h"
-+#include "mx.h"
- #include "mutt_menu.h"
- #include "mailbox.h"
- #include "mapping.h"
-@@ -43,6 +44,10 @@
-
- #include "mutt_crypt.h"
-
-+#ifdef USE_NNTP
-+#include "nntp.h"
-+#endif
-+
-
- #include <ctype.h>
- #include <stdlib.h>
-@@ -494,12 +499,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;
-@@ -520,7 +540,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 */
-@@ -794,6 +818,9 @@ int mutt_index_menu (void)
- mutt_curs_set (1); /* fallback from the pager */
- }
-
-+#ifdef USE_NNTP
-+ unset_option (OPTNEWS); /* for any case */
-+#endif
- switch (op)
- {
-
-@@ -844,6 +871,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;
-@@ -941,11 +1123,33 @@ int mutt_index_menu (void)
- break;
-
- 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_TOGGLE_READ && mutt_pattern_func (M_LIMIT, NULL) == 0) ||
-+ mutt_pattern_func (M_LIMIT, _("Limit to messages matching: ")) == 0)
- {
- if (menu->oldcurrent >= 0)
- {
-@@ -1194,15 +1398,22 @@ int mutt_index_menu (void)
- #endif
- case OP_MAIN_CHANGE_FOLDER:
- case OP_MAIN_NEXT_UNREAD_MAILBOX:
--
-- if (attach_msg)
-- op = OP_MAIN_CHANGE_FOLDER_READONLY;
--
-- /* fallback to the readonly case */
--
- 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
- cp = _("Open mailbox");
-@@ -1221,6 +1432,22 @@ int mutt_index_menu (void)
- }
- 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
-@@ -1248,6 +1475,14 @@ int mutt_index_menu (void)
- }
- }
-
-+#ifdef USE_NNTP
-+ if (option (OPTNEWS))
-+ {
-+ unset_option (OPTNEWS);
-+ nntp_expand_path (buf, sizeof (buf), &CurrentNewsSrv->conn->account);
-+ }
-+ else
-+#endif
- mutt_expand_path (buf, sizeof (buf));
- #ifdef USE_SIDEBAR
- sb_set_open_buffy (buf);
-@@ -1297,15 +1532,18 @@ int mutt_index_menu (void)
- 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)
-+ if ((Context = mx_open_mailbox (buf, flags, NULL)) != NULL)
- {
- menu->current = ci_first_message ();
- }
- else
- menu->current = 0;
-
-+#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_clear_error ();
- mutt_buffy_check(1); /* force the buffy check after we have changed
- the folder */
-@@ -1374,6 +1612,7 @@ int mutt_index_menu (void)
- 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.");
-@@ -1409,7 +1648,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"));
-
- if ((Sort & SORT_MASK) != SORT_THREADS)
- mutt_error _("Threading is not enabled.");
-@@ -2046,6 +2285,20 @@ int mutt_index_menu (void)
- }
- 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;
-@@ -2252,6 +2505,39 @@ int mutt_index_menu (void)
- menu->redraw = REDRAW_FULL;
- break;
-
-+#ifdef USE_NNTP
-+ 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)
-+ {
-+ 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
-+
- case OP_REPLY:
-
- CHECK_ATTACH;
-diff --git a/doc/manual.xml.head b/doc/manual.xml.head
-index 166f3cb..ab6ac29 100644
---- a/doc/manual.xml.head
-+++ b/doc/manual.xml.head
-@@ -9976,6 +9976,398 @@ color sidebar_new green black
- </sect2>
- </sect1>
-
-+<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.5.24</para></listitem>
-+ </itemizedlist>
-+
-+ <para>This patch is part of the <ulink url="https://github.com/neomutt/neomutt/wiki">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>
-+
- </chapter>
-
- <chapter id="security">
-diff --git a/doc/mutt.man b/doc/mutt.man
-index 28dd7f2..f1f1399 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.nntp b/doc/muttrc.nntp
-new file mode 100644
-index 0000000..e69de29
-diff --git a/doc/vimrc-nntp b/doc/vimrc-nntp
-new file mode 100644
-index 0000000..8b93f1a
---- /dev/null
-+++ b/doc/vimrc-nntp
-@@ -0,0 +1,50 @@
-+" Vim syntax file for the mutt nntp patch
-+
-+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
-+
-+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
-+
-+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
-+
-+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
-+
-+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 --git a/functions.h b/functions.h
-index c383900..8bc90a0 100644
---- a/functions.h
-+++ b/functions.h
-@@ -88,6 +88,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" },
-@@ -101,7 +105,15 @@ const struct binding_t OpMain[] = { /* map: index */
- { "edit", OP_EDIT_MESSAGE, "e" },
- { "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" },
-@@ -129,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" },
-@@ -148,6 +163,10 @@ 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" },
-+ { "toggle-read", OP_TOGGLE_READ, "X" },
-+#ifdef USE_NNTP
-+ { "catchup", OP_CATCHUP, "y" },
-+#endif
- { "display-message", OP_DISPLAY_MESSAGE, M_ENTER_S },
- { "buffy-list", OP_BUFFY_LIST, "." },
- { "sync-mailbox", OP_MAIN_SYNC_FOLDER, "$" },
-@@ -159,7 +178,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" },
-@@ -189,6 +208,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" },
-@@ -199,8 +222,12 @@ const struct binding_t OpPager[] = { /* map: pager */
- { "clear-flag", OP_MAIN_CLEAR_FLAG, "W" },
- { "edit", OP_EDIT_MESSAGE, "e" },
- { "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 },
-@@ -222,6 +249,9 @@ 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 },
-@@ -270,7 +300,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 },
-
-
-
-@@ -302,6 +332,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, "|" },
-@@ -327,6 +361,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" },
-@@ -346,6 +381,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" },
-@@ -397,14 +437,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 }
-diff --git a/globals.h b/globals.h
-index c4a77ca..3fc9035 100644
---- a/globals.h
-+++ b/globals.h
-@@ -69,7 +69,7 @@ WHERE char *Ispell;
- 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 +95,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;
-@@ -201,6 +212,11 @@ extern unsigned char QuadOptions[];
-
- WHERE unsigned short Counter INITVAL (0);
-
-+#ifdef USE_NNTP
-+WHERE short NewsPollTimeout;
-+WHERE short NntpContext;
-+#endif
-+
- WHERE short ConnectTimeout;
- WHERE short HistSize;
- WHERE short MenuContext;
-diff --git a/hash.c b/hash.c
-index 08f7171..983a7fd 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)
-+{
-+ HASH *table;
-+ struct hash_elem *elem, *tmp;
-+ int i;
-+
-+ table = hash_create (nelem, lower);
-+
-+ 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;
-+}
-+
- /* 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;
- }
-diff --git a/hash.h b/hash.h
-index fb77d0c..9e7df82 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,6 +41,7 @@ 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 *));
-diff --git a/hcache.c b/hcache.c
-index f4c0ecf..0299850 100644
---- a/hcache.c
-+++ b/hcache.c
-@@ -447,6 +447,12 @@ dump_envelope(ENVELOPE * e, unsigned char *d, int *off, int convert)
- d = dump_list(e->in_reply_to, d, off, 0);
- d = dump_list(e->userhdrs, 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);
-+#endif
-+
- return d;
- }
-
-@@ -483,6 +489,12 @@ restore_envelope(ENVELOPE * e, const unsigned char *d, int *off, int convert)
- restore_list(&e->references, d, off, 0);
- restore_list(&e->in_reply_to, d, off, 0);
- restore_list(&e->userhdrs, d, off, convert);
-+
-+#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
-diff --git a/hdrline.c b/hdrline.c
-index b844411..9bd90d7 100644
---- a/hdrline.c
-+++ b/hdrline.c
-@@ -211,6 +211,7 @@ 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 = newsgroup name (if compiled with NNTP support)
- * %i = message-id
- * %l = number of lines in the message
- * %L = like %F, except `lists' are displayed first
-@@ -227,6 +228,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)
-@@ -459,6 +462,12 @@ hdr_format_str (char *dest,
-
- break;
-
-+#ifdef USE_NNTP
-+ case 'g':
-+ mutt_format_s (dest, destlen, prefix, hdr->env->newsgroups ? hdr->env->newsgroups : "");
-+ break;
-+#endif
-+
- case 'i':
- mutt_format_s (dest, destlen, prefix, hdr->env->message_id ? hdr->env->message_id : "<no.id>");
- break;
-@@ -655,6 +664,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
-+
- case 'Z':
-
- ch = ' ';
-diff --git a/headers.c b/headers.c
-index fc33253..b2dd630 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
- if (msg->env->in_reply_to &&
- (!n->in_reply_to || mutt_strcmp (n->in_reply_to->data,
- msg->env->in_reply_to->data) != 0))
-diff --git a/init.c b/init.c
-index 91889dc..ad713e8 100644
---- a/init.c
-+++ b/init.c
-@@ -3143,6 +3143,28 @@ void mutt_init (int skip_sys_rc, LIST *commands)
- 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")))
-diff --git a/init.h b/init.h
-index 355a003..4713f8f 100644
---- a/init.h
-+++ b/init.h
-@@ -177,6 +177,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
-@@ -329,6 +343,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" },
- /*
-@@ -848,6 +870,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
-@@ -930,6 +962,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 },
- /*
- */
-@@ -1325,6 +1377,7 @@ 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 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,
-@@ -1348,6 +1401,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
-@@ -1382,6 +1437,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
-@@ -1626,6 +1700,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" },
- /*
-@@ -1676,6 +1759,106 @@ 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
-+ ** authentification, 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
- { "pager", DT_PATH, R_NONE, UL &Pager, UL "builtin" },
- /*
- ** .pp
-@@ -2202,6 +2385,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
-@@ -2678,6 +2871,28 @@ 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_BOTH, UL &SidebarDividerChar, UL "|" },
- /*
-@@ -3761,6 +3976,14 @@ struct option_t MuttVars[] = {
- {"xterm_set_titles", DT_SYN, R_NONE, UL "ts_enabled", 0 },
- /*
- */
-+#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 }
- };
-diff --git a/keymap.c b/keymap.c
-index 6d9661e..e2c51ad 100644
---- a/keymap.c
-+++ b/keymap.c
-@@ -798,7 +798,6 @@ void km_init (void)
- 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);
-diff --git a/mailbox.h b/mailbox.h
-index 2249661..b3c6c8d 100644
---- a/mailbox.h
-+++ b/mailbox.h
-@@ -79,6 +79,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 4f9a6cb..82ab356 100644
---- a/main.c
-+++ b/main.c
-@@ -66,6 +66,10 @@
- #include <idn/stringprep.h>
- #endif
-
-+#ifdef USE_NNTP
-+#include "nntp.h"
-+#endif
-+
- void mutt_exit (int code)
- {
- mutt_endwin (NULL);
-@@ -102,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\
-@@ -165,6 +171,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
-
- int main (int argc, char **argv)
- {
-@@ -242,7 +251,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':
-@@ -343,6 +356,20 @@ int main (int argc, char **argv)
- flags |= M_SELECT;
- break;
-
-+#ifdef USE_NNTP
-+ case 'g': /* Specify a news server */
-+ {
-+ char buf[LONG_STRING];
-+
-+ snprintf (buf, sizeof (buf), "set news_server=%s", optarg);
-+ commands = mutt_add_list (commands, buf);
-+ }
-+
-+ case 'G': /* List of newsgroups */
-+ flags |= M_SELECT | M_NEWS;
-+ break;
-+#endif
-+
- case 'z':
- flags |= M_IGNORE;
- break;
-@@ -781,6 +808,18 @@ int main (int argc, char **argv)
- }
- else if (flags & M_SELECT)
- {
-+#ifdef USE_NNTP
-+ if (flags & M_NEWS)
-+ {
-+ set_option (OPTNEWS);
-+ if(!(CurrentNewsSrv = nntp_select_server (NewsServer, 0)))
-+ {
-+ mutt_endwin (Errorbuf);
-+ exit (1);
-+ }
-+ }
-+ else
-+#endif
- if (!Incoming) {
- mutt_endwin _("No incoming mailboxes defined.");
- exit (1);
-@@ -796,6 +835,15 @@ int main (int argc, char **argv)
-
- 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
-diff --git a/mutt.h b/mutt.h
-index cfe9f27..22b7246 100644
---- a/mutt.h
-+++ b/mutt.h
-@@ -237,6 +237,9 @@ enum
- M_PGP_KEY,
- M_XLABEL,
- M_MIMEATTACH,
-+#ifdef USE_NNTP
-+ M_NEWSGROUPS,
-+#endif
-
- /* Options for Mailcap lookup */
- M_EDIT,
-@@ -293,6 +296,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
-@@ -311,6 +319,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)
-@@ -333,6 +342,8 @@ enum
- OPTASCIICHARS,
- OPTASKBCC,
- OPTASKCC,
-+ OPTASKFOLLOWUP,
-+ OPTASKXCOMMENTTO,
- OPTATTACHSPLIT,
- OPTAUTOEDIT,
- OPTAUTOTAG,
-@@ -414,6 +425,9 @@ enum
- OPTMETOO,
- OPTMHPURGE,
- OPTMIMEFORWDECODE,
-+#ifdef USE_NNTP
-+ OPTMIMESUBJECT, /* encode subject line with RFC2047 */
-+#endif
- OPTNARROWTREE,
- OPTPAGERSTOP,
- OPTPIPEDECODE,
-@@ -511,6 +525,17 @@ enum
- OPTPGPAUTOINLINE,
- OPTPGPREPLYINLINE,
-
-+ /* news options */
-+
-+#ifdef USE_NNTP
-+ OPTSHOWNEWNEWS,
-+ OPTSHOWONLYUNREAD,
-+ OPTSAVEUNSUB,
-+ OPTLISTGROUP,
-+ OPTLOADDESC,
-+ OPTXCOMMENTTO,
-+#endif
-+
- /* pseudo options */
-
- OPTAUXSORT, /* (pseudo) using auxiliary sort function */
-@@ -531,6 +556,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.
-@@ -541,6 +567,11 @@ enum
- OPTDONTHANDLEPGPKEYS, /* (pseudo) used to extract PGP keys */
- OPTIGNOREMACROEVENTS, /* (pseudo) don't process macro/push/exec events while set */
-
-+#ifdef USE_NNTP
-+ OPTNEWS, /* (pseudo) used to change reader mode */
-+ OPTNEWSSEND, /* (pseudo) used to change behavior when posting */
-+#endif
-+
- OPTMAX
- };
-
-@@ -620,6 +651,13 @@ 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 */
-@@ -806,7 +844,7 @@ 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_NNTP
- void *data; /* driver-specific data */
- #endif
-
-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/muttlib.c b/muttlib.c
-index ce1c97a..4864b4a 100644
---- a/muttlib.c
-+++ b/muttlib.c
-@@ -329,7 +329,7 @@ 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_NNTP
- FREE (&(*h)->data);
- #endif
- FREE (h); /* __FREE_CHECKED__ */
-@@ -714,6 +714,13 @@ 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);
-
-@@ -1523,6 +1530,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
-+
- if (stat (s, st) != -1)
- {
- if (magic == -1)
-diff --git a/mx.c b/mx.c
-index a2769c5..1d67d07 100644
---- a/mx.c
-+++ b/mx.c
-@@ -45,6 +45,10 @@
- #include "pop.h"
- #endif
-
-+#ifdef USE_NNTP
-+#include "nntp.h"
-+#endif
-+
- #include "buffy.h"
-
- #ifdef USE_DOTLOCK
-@@ -350,6 +354,22 @@ int mx_is_pop (const char *p)
- }
- #endif
-
-+#ifdef USE_NNTP
-+int mx_is_nntp (const char *p)
-+{
-+ url_scheme_t scheme;
-+
-+ if (!p)
-+ return 0;
-+
-+ scheme = url_check_scheme (p);
-+ if (scheme == U_NNTP || scheme == U_NNTPS)
-+ return 1;
-+
-+ return 0;
-+}
-+#endif
-+
- int mx_get_magic (const char *path)
- {
- struct stat st;
-@@ -367,6 +387,11 @@ int mx_get_magic (const char *path)
- return M_POP;
- #endif /* USE_POP */
-
-+#ifdef USE_NNTP
-+ if (mx_is_nntp (path))
-+ return M_NNTP;
-+#endif /* USE_NNTP */
-+
- if (stat (path, &st) == -1)
- {
- dprint (1, (debugfile, "mx_get_magic(): unable to stat %s: %s (errno %d).\n",
-@@ -696,6 +721,12 @@ CONTEXT *mx_open_mailbox (const char *path, int flags, CONTEXT *pctx)
- break;
- #endif /* USE_POP */
-
-+#ifdef USE_NNTP
-+ case M_NNTP:
-+ rc = nntp_open_mailbox (ctx);
-+ break;
-+#endif /* USE_NNTP */
-+
- default:
- rc = -1;
- break;
-@@ -813,6 +844,12 @@ static int sync_mailbox (CONTEXT *ctx, int *index_hint)
- rc = pop_sync_mailbox (ctx, index_hint);
- break;
- #endif /* USE_POP */
-+
-+#ifdef USE_NNTP
-+ case M_NNTP:
-+ rc = nntp_sync_mailbox (ctx);
-+ break;
-+#endif /* USE_NNTP */
- }
-
- #if 0
-@@ -918,6 +955,25 @@ 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;
-+
-+ 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
-+
- for (i = 0; i < ctx->msgcount; i++)
- {
- if (!ctx->hdrs[i]->deleted && ctx->hdrs[i]->read
-@@ -931,6 +987,12 @@ int mx_close_mailbox (CONTEXT *ctx, int *index_hint)
- #endif
- }
-
-+#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;
-@@ -1491,6 +1553,11 @@ int mx_check_mailbox (CONTEXT *ctx, int *index_hint, int lock)
- case M_POP:
- return (pop_check_mailbox (ctx, index_hint));
- #endif /* USE_POP */
-+
-+#ifdef USE_NNTP
-+ case M_NNTP:
-+ return (nntp_check_mailbox (ctx, 0));
-+#endif /* USE_NNTP */
- }
- }
-
-@@ -1551,6 +1618,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 */
-+
- default:
- dprint (1, (debugfile, "mx_open_message(): function not implemented for mailbox type %d.\n", ctx->magic));
- FREE (&msg);
-@@ -1626,6 +1702,9 @@ 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_IMAP || (*msg)->magic == M_POP)
- {
- r = safe_fclose (&(*msg)->fp);
-diff --git a/mx.h b/mx.h
-index f2b79c0..132f7cc 100644
---- a/mx.h
-+++ b/mx.h
-@@ -35,6 +35,9 @@ enum
- M_MMDF,
- M_MH,
- M_MAILDIR,
-+#ifdef USE_NNTP
-+ M_NNTP,
-+#endif
- M_IMAP,
- M_POP
- #ifdef USE_COMPRESSED
-diff --git a/newsrc.c b/newsrc.c
-new file mode 100644
-index 0000000..e8c3c9c
---- /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.
-+ */
-+
-+#if HAVE_CONFIG_H
-+#include "config.h"
-+#endif
-+
-+#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
-+
-+#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>
-+
-+/* 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);
-+
-+ 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);
-+
-+ /* 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;
-+}
-+
-+/* Remove all temporarily cache files */
-+void nntp_acache_free (NNTP_DATA *nntp_data)
-+{
-+ int i;
-+
-+ 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);
-+ }
-+ }
-+}
-+
-+/* 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);
-+}
-+
-+/* 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;
-+
-+ /* if file doesn't exist, create it */
-+ nserv->newsrc_fp = safe_fopen (nserv->newsrc_file, "a");
-+ safe_fclose (&nserv->newsrc_fp);
-+
-+ /* 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;
-+ }
-+
-+ /* 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;
-+ }
-+
-+ if (stat (nserv->newsrc_file, &sb))
-+ {
-+ mutt_perror (nserv->newsrc_file);
-+ nntp_newsrc_close (nserv);
-+ mutt_sleep (2);
-+ return -1;
-+ }
-+
-+ if (nserv->size == sb.st_size && nserv->mtime == sb.st_mtime)
-+ return 0;
-+
-+ nserv->size = sb.st_size;
-+ nserv->mtime = sb.st_mtime;
-+ nserv->newsrc_modified = 1;
-+ dprint (1, (debugfile, "Parsing %s\n", nserv->newsrc_file));
-+
-+ /* .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];
-+
-+ if (!nntp_data)
-+ continue;
-+
-+ nntp_data->subscribed = 0;
-+ nntp_data->newsrc_len = 0;
-+ FREE (&nntp_data->newsrc_ent);
-+ }
-+
-+ 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;
-+
-+ /* find end of newsgroup name */
-+ p = strpbrk (line, ":!");
-+ if (!p)
-+ continue;
-+
-+ /* ":" - subscribed, "!" - unsubscribed */
-+ if (*p == ':')
-+ subs++;
-+ *p++ = '\0';
-+
-+ /* get newsgroup data */
-+ nntp_data = nntp_data_find (nserv, line);
-+ FREE (&nntp_data->newsrc_ent);
-+
-+ /* 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;
-+
-+ /* parse entries */
-+ i = 0;
-+ while (p)
-+ {
-+ b = p;
-+
-+ /* find end of entry */
-+ p = strchr (p, ',');
-+ if (p)
-+ *p++ = '\0';
-+
-+ /* first-last or single number */
-+ h = strchr (b, '-');
-+ if (h)
-+ *h++ = '\0';
-+ else
-+ h = b;
-+
-+ 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;
-+}
-+
-+/* 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;
-+
-+ if (Sort != SORT_ORDER)
-+ {
-+ save_sort = Sort;
-+ Sort = SORT_ORDER;
-+ mutt_sort_headers (ctx, 0);
-+ }
-+
-+ entries = nntp_data->newsrc_len;
-+ if (!entries)
-+ {
-+ entries = 5;
-+ nntp_data->newsrc_ent = safe_calloc (entries, sizeof (NEWSRC_ENTRY));
-+ }
-+
-+ /* 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;
-+ }
-+ }
-+
-+ /* 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));
-+
-+ if (save_sort != Sort)
-+ {
-+ Sort = save_sort;
-+ mutt_sort_headers (ctx, 0);
-+ }
-+}
-+
-+/* Update file with new contents */
-+static int update_file (char *filename, char *buf)
-+{
-+ FILE *fp;
-+ char tmpfile[_POSIX_PATH_MAX];
-+ int rc = -1;
-+
-+ 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;
-+}
-+
-+/* Update .newsrc file */
-+int nntp_newsrc_update (NNTP_SERVER *nserv)
-+{
-+ char *buf;
-+ size_t buflen, off;
-+ unsigned int i;
-+ int rc = -1;
-+
-+ if (!nserv)
-+ return -1;
-+
-+ buflen = 10 * LONG_STRING;
-+ buf = safe_calloc (1, buflen);
-+ off = 0;
-+
-+ /* 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;
-+
-+ if (!nntp_data || !nntp_data->newsrc_ent)
-+ continue;
-+
-+ /* 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);
-+
-+ /* 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';
-+
-+ /* 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;
-+
-+ 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;
-+}
-+
-+/* 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];
-+
-+ /* server subdirectory */
-+ if (acct)
-+ {
-+ 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));
-+
-+ snprintf (dst, dstlen, "%s/%s", NewsCacheDir, file);
-+
-+ /* remove trailing slash */
-+ c = dst + strlen (dst) - 1;
-+ if (*c == '/')
-+ *c = '\0';
-+ mutt_expand_path (dst, dstlen);
-+}
-+
-+/* Make fully qualified url from newsgroup name */
-+void nntp_expand_path (char *line, size_t len, ACCOUNT *acct)
-+{
-+ ciss_url_t url;
-+
-+ url.path = safe_strdup (line);
-+ mutt_account_tourl (acct, &url);
-+ url_ciss_tostring (&url, line, len, 0);
-+ FREE (&url.path);
-+}
-+
-+/* 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;
-+
-+ if (!nserv || !line)
-+ return 0;
-+
-+ if (sscanf (line, "%s " ANUM " " ANUM " %c %[^\n]", group,
-+ &last, &first, &mod, desc) < 4)
-+ return 0;
-+
-+ 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;
-+}
-+
-+/* 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;
-+
-+ 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;
-+
-+ if (fgets (buf, sizeof (buf), fp) == NULL ||
-+ sscanf (buf, "%ld%s", &t, file) != 1 || t == 0)
-+ {
-+ fclose (fp);
-+ return -1;
-+ }
-+ 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;
-+}
-+
-+/* 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];
-+
-+ if (!nntp_data || nntp_data->deleted)
-+ continue;
-+
-+ 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);
-+ }
-+
-+ 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;
-+}
-+
-+#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);
-+}
-+
-+/* Open newsgroup hcache */
-+header_cache_t *nntp_hcache_open (NNTP_DATA *nntp_data)
-+{
-+ ciss_url_t url;
-+ char file[_POSIX_PATH_MAX];
-+
-+ 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;
-+
-+ 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);
-+}
-+
-+/* 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;
-+
-+ if (!hc)
-+ return;
-+
-+ /* 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;
-+
-+ /* clean removed headers from cache */
-+ for (current = first; current <= last; current++)
-+ {
-+ if (current >= nntp_data->firstMessage &&
-+ current <= nntp_data->lastMessage)
-+ continue;
-+
-+ 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);
-+ }
-+
-+ /* 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
-+
-+/* 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));
-+#endif
-+
-+ 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;
-+
-+ 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;
-+
-+ 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;
-+
-+ 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;
-+}
-+
-+/* %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';
-+ }
-+
-+ /* 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;
-+
-+ rc = nntp_newsrc_parse (nserv);
-+ if (rc < 0)
-+ return NULL;
-+
-+ /* check for new newsgroups */
-+ if (!leave_lock && nntp_check_new_groups (nserv) < 0)
-+ rc = -1;
-+
-+ /* .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;
-+ }
-+
-+ /* 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));
-+
-+ rc = nntp_open_connection (nserv);
-+
-+ /* 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++ = '/';
-+ }
-+ }
-+
-+ /* 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);
-+ }
-+
-+ if (rc >= 0)
-+ nntp_clear_cache (nserv);
-+
-+#ifdef USE_HCACHE
-+ /* check cache files */
-+ if (rc >= 0 && nserv->cacheable)
-+ {
-+ 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);
-+ }
-+ }
-+#endif
-+
-+ if (rc < 0 || !leave_lock)
-+ nntp_newsrc_close (nserv);
-+
-+ 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;
-+ }
-+
-+ 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 ((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;
-+ }
-+ }
-+
-+ /* 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)
-+ {
-+ 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;
-+}
-+
-+/* Unsubscribe newsgroup */
-+NNTP_DATA *mutt_newsgroup_unsubscribe (NNTP_SERVER *nserv, char *group)
-+{
-+ NNTP_DATA *nntp_data;
-+
-+ if (!nserv || !nserv->groups_hash || !group || !*group)
-+ return NULL;
-+
-+ nntp_data = hash_find (nserv->groups_hash, group);
-+ if (!nntp_data)
-+ return NULL;
-+
-+ nntp_data->subscribed = 0;
-+ if (!option (OPTSAVEUNSUB))
-+ {
-+ nntp_data->newsrc_len = 0;
-+ FREE (&nntp_data->newsrc_ent);
-+ }
-+ return nntp_data;
-+}
-+
-+/* Catchup newsgroup */
-+NNTP_DATA *mutt_newsgroup_catchup (NNTP_SERVER *nserv, char *group)
-+{
-+ NNTP_DATA *nntp_data;
-+
-+ if (!nserv || !nserv->groups_hash || !group || !*group)
-+ return NULL;
-+
-+ nntp_data = hash_find (nserv->groups_hash, group);
-+ if (!nntp_data)
-+ return NULL;
-+
-+ 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;
-+
-+ for (i = 0; i < Context->msgcount; i++)
-+ mutt_set_flag (Context, Context->hdrs[i], M_READ, 1);
-+ }
-+ return nntp_data;
-+}
-+
-+/* Uncatchup newsgroup */
-+NNTP_DATA *mutt_newsgroup_uncatchup (NNTP_SERVER *nserv, char *group)
-+{
-+ NNTP_DATA *nntp_data;
-+
-+ if (!nserv || !nserv->groups_hash || !group || !*group)
-+ return NULL;
-+
-+ nntp_data = hash_find (nserv->groups_hash, group);
-+ if (!nntp_data)
-+ return NULL;
-+
-+ 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;
-+
-+ 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;
-+}
-+
-+/* Get first newsgroup with new messages */
-+void nntp_buffy (char *buf, size_t len)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < CurrentNewsSrv->groups_num; i++)
-+ {
-+ NNTP_DATA *nntp_data = CurrentNewsSrv->groups_list[i];
-+
-+ if (!nntp_data || !nntp_data->subscribed || !nntp_data->unread)
-+ continue;
-+
-+ if (Context && Context->magic == M_NNTP &&
-+ !mutt_strcmp (nntp_data->group, ((NNTP_DATA *)Context->data)->group))
-+ {
-+ unsigned int i, unread = 0;
-+
-+ 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.
-+ */
-+
-+#if HAVE_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 "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 <unistd.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);
-+
-+ if (mutt_socket_write (conn, "CAPABILITIES\r\n") < 0 ||
-+ mutt_socket_readln (buf, sizeof (buf), conn) < 0)
-+ return nntp_connect_error (nserv);
-+
-+ /* no capabilities */
-+ if (mutt_strncmp ("101", buf, 3))
-+ return 1;
-+ nserv->hasCAPABILITIES = 1;
-+
-+ /* 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);
-+
-+ /* 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";
-+
-+/* 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;
-+
-+ 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;
-+
-+ 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));
-+ }
-+ }
-+
-+ /* 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;
-+ }
-+
-+ /* 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;
-+ }
-+
-+ /* 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 (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);
-+ }
-+
-+ chunk = mutt_socket_readln (nserv->overview_fmt + off,
-+ buflen - off, conn);
-+ if (chunk < 0)
-+ {
-+ FREE (&nserv->overview_fmt);
-+ return nntp_connect_error (nserv);
-+ }
-+
-+ 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;
-+
-+ 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;
-+
-+ 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++;
-+ }
-+
-+ 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;
-+ }
-+
-+ method = a;
-+ a = strchr (a, ':');
-+ if (a)
-+ *a++ = '\0';
-+
-+ /* check authenticator */
-+ if (nserv->hasCAPABILITIES)
-+ {
-+ char *m;
-+
-+ 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));
-+
-+ /* 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;
-+
-+ /* 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;
-+
-+ /* authenticated */
-+ if (!mutt_strncmp ("281", buf, 3))
-+ return 0;
-+ }
-+
-+ /* 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;
-+
-+ if (mutt_sasl_client_new (conn, &saslconn) < 0)
-+ {
-+ dprint (1, (debugfile,
-+ "nntp_auth: error allocating SASL connection.\n"));
-+ continue;
-+ }
-+
-+ 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;
-+ }
-+
-+ mutt_message (_("Authenticating (%s)..."), method);
-+ snprintf (buf, sizeof (buf), "AUTHINFO SASL %s", method);
-+
-+ /* 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
-+
-+ 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;
-+ }
-+ }
-+
-+ 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
-+
-+ 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
-+
-+ 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;
-+
-+ *buf = '\0';
-+ } /* looping protocol */
-+
-+ if (rc == SASL_OK && client_len == 0 && *inbuf == '2')
-+ {
-+ mutt_sasl_setup_conn (conn, saslconn);
-+ return 0;
-+ }
-+
-+ /* 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;
-+ }
-+
-+ /* server doesn't support AUTHINFO SASL, trying next method */
-+ if (*inbuf == '5')
-+ continue;
-+#else
-+ continue;
-+#endif /* USE_SASL */
-+ }
-+
-+ 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;
-+}
-+
-+/* 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;
-+
-+ if (nserv->status == NNTP_OK)
-+ return 0;
-+ if (nserv->status == NNTP_BYE)
-+ return -1;
-+ nserv->status = NNTP_NONE;
-+
-+ if (mutt_socket_open (conn) < 0)
-+ return -1;
-+
-+ if (mutt_socket_readln (buf, sizeof (buf), conn) < 0)
-+ return nntp_connect_error (nserv);
-+
-+ 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;
-+ }
-+
-+ /* get initial capabilities */
-+ cap = nntp_capabilities (nserv);
-+ if (cap < 0)
-+ 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 (!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;
-+ }
-+
-+ /* recheck capabilities after MODE READER */
-+ if (nserv->hasCAPABILITIES)
-+ {
-+ cap = nntp_capabilities (nserv);
-+ if (cap < 0)
-+ return -1;
-+ }
-+ }
-+
-+ mutt_message (_("Connected to %s. %s"), conn->account.host,
-+ posting ? _("Posting is ok.") : _("Posting is NOT ok."));
-+ mutt_sleep (1);
-+
-+#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
-+
-+ /* 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;
-+ }
-+
-+ /* authenticate */
-+ if (auth && nntp_auth (nserv) < 0)
-+ return -1;
-+
-+ /* 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;
-+ }
-+ }
-+
-+ /* attempt features */
-+ if (nntp_attempt_features (nserv) < 0)
-+ return -1;
-+
-+ nserv->status = NNTP_OK;
-+ return 0;
-+}
-+
-+/* 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];
-+
-+ if (nserv->status == NNTP_BYE)
-+ return -1;
-+
-+ 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;
-+ }
-+
-+ /* 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;
-+ }
-+ }
-+
-+ /* 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;
-+ }
-+
-+ strfcpy (line, buf, linelen);
-+ return 0;
-+}
-+
-+/* 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;
-+
-+ while (!done)
-+ {
-+ char buf[LONG_STRING];
-+ char *line;
-+ unsigned int lines = 0;
-+ size_t off = 0;
-+ progress_t progress;
-+
-+ if (msg)
-+ mutt_progress_init (&progress, msg, M_PROGRESS_MSG, ReadInc, -1);
-+
-+ 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;
-+ }
-+
-+ line = safe_malloc (sizeof (buf));
-+ rc = 0;
-+
-+ 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;
-+ }
-+
-+ p = buf;
-+ if (!off && buf[0] == '.')
-+ {
-+ if (buf[1] == '\0')
-+ {
-+ done = TRUE;
-+ break;
-+ }
-+ 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 (rc == 0 && funct (line, data) < 0)
-+ rc = -2;
-+ off = 0;
-+ }
-+
-+ safe_realloc (&line, off + sizeof (buf));
-+ }
-+ FREE (&line);
-+ funct (NULL, data);
-+ }
-+ return rc;
-+}
-+
-+/* Parse newsgroup description */
-+static int fetch_description (char *line, void *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');
-+
-+ 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;
-+}
-+
-+/* 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;
-+
-+ /* 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;
-+
-+ 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;
-+}
-+
-+/* 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;
-+
-+ 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;
-+
-+ /* skip to end of word */
-+ p = strpbrk (p, " \t");
-+ if (p)
-+ *p++ = '\0';
-+
-+ /* find colon */
-+ colon = strchr (grp, ':');
-+ if (!colon)
-+ continue;
-+ *colon++ = '\0';
-+ if (sscanf (colon, ANUM, &anum) != 1)
-+ continue;
-+
-+ 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);
-+}
-+
-+/* 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;
-+}
-+
-+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;
-+
-+/* Parse article number */
-+static int fetch_numbers (char *line, void *data)
-+{
-+ FETCH_CTX *fc = data;
-+ anum_t anum;
-+
-+ 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;
-+}
-+
-+/* 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;
-+
-+ if (!line)
-+ return 0;
-+
-+ /* 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));
-+
-+ /* out of bounds */
-+ if (anum < fc->first || anum > fc->last)
-+ return 0;
-+
-+ /* 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;
-+ }
-+
-+ /* convert overview line to header */
-+ mutt_mktemp (tempfile, sizeof (tempfile));
-+ fp = safe_fopen (tempfile, "w+");
-+ if (!fp)
-+ return -1;
-+
-+ header = nntp_data->nserv->overview_fmt;
-+ while (field)
-+ {
-+ char *b = field;
-+
-+ if (*header)
-+ {
-+ if (strstr (header, ":full") == NULL && fputs (header, fp) == EOF)
-+ {
-+ fclose (fp);
-+ unlink (tempfile);
-+ return -1;
-+ }
-+ header = strchr (header, '\0') + 1;
-+ }
-+
-+ 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);
-+
-+ /* 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);
-+
-+#ifdef USE_HCACHE
-+ if (fc->hc)
-+ {
-+ void *hdata;
-+ char buf[16];
-+
-+ /* 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;
-+
-+ /* 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;
-+ }
-+ }
-+
-+ /* 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 (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);
-+
-+ /* progress */
-+ if (!ctx->quiet)
-+ mutt_progress_update (&fc->progress, anum - fc->first + 1, -1);
-+ return 0;
-+}
-+
-+/* 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
-+
-+ /* if empty group or nothing to do */
-+ if (!last || first > last)
-+ return 0;
-+
-+ /* 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
-+
-+ /* 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;
-+
-+ 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);
-+ }
-+
-+#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;
-+
-+ /* 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);
-+
-+#ifdef USE_HCACHE
-+ snprintf (buf, sizeof (buf), "%d", current);
-+#endif
-+
-+ /* delete header from cache that does not exist on server */
-+ if (!fc.messages[current - first])
-+ continue;
-+
-+ /* allocate memory for headers */
-+ if (ctx->msgcount >= ctx->hdrmax)
-+ mx_alloc_memory (ctx);
-+
-+#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;
-+
-+ /* 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;
-+ }
-+
-+ hdr->read = 0;
-+ hdr->old = 0;
-+ }
-+ else
-+#endif
-+
-+ /* don't try to fetch header from removed newsgroup */
-+ if (nntp_data->deleted)
-+ continue;
-+
-+ /* fallback to fetch overview */
-+ else if (nntp_data->nserv->hasOVER || nntp_data->nserv->hasXOVER)
-+ if (option (OPTLISTGROUP) && nntp_data->nserv->hasLISTGROUP)
-+ break;
-+ else
-+ continue;
-+
-+ /* fetch header from server */
-+ else
-+ {
-+ FILE *fp;
-+ char tempfile[_POSIX_PATH_MAX];
-+
-+ mutt_mktemp (tempfile, sizeof (tempfile));
-+ fp = safe_fopen (tempfile, "w+");
-+ if (!fp)
-+ {
-+ mutt_perror (tempfile);
-+ mutt_sleep (2);
-+ unlink (tempfile);
-+ rc = -1;
-+ break;
-+ }
-+
-+ 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;
-+
-+ /* invalid response */
-+ if (mutt_strncmp ("423", buf, 3))
-+ {
-+ mutt_error ("HEAD: %s", buf);
-+ mutt_sleep (2);
-+ break;
-+ }
-+
-+ /* 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;
-+ }
-+
-+ /* 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);
-+ }
-+
-+ /* 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 (!option (OPTLISTGROUP) || !nntp_data->nserv->hasLISTGROUP)
-+ current = first_over;
-+
-+ /* 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);
-+ }
-+ }
-+
-+ if (ctx->msgcount > oldmsgcount)
-+ mx_update_context (ctx, ctx->msgcount - oldmsgcount);
-+
-+ FREE (&fc.messages);
-+ if (rc != 0)
-+ return -1;
-+ mutt_clear_error ();
-+ return 0;
-+}
-+
-+/* 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;
-+
-+ 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;
-+ }
-+
-+ 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;
-+
-+ /* 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;
-+ }
-+
-+ mutt_bit_unset (ctx->rights, M_ACL_INSERT);
-+ if (!nntp_data->newsrc_ent && !nntp_data->subscribed &&
-+ !option (OPTSAVEUNSUB))
-+ ctx->readonly = 1;
-+
-+ /* 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;
-+ }
-+
-+ /* 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);
-+ }
-+
-+ /* 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;
-+
-+ /* 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);
-+ }
-+ }
-+
-+ 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);
-+
-+ /* 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;
-+}
-+
-+/* 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;
-+
-+ /* 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;
-+
-+ /* 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;
-+ }
-+ }
-+
-+ /* 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 (!acache->path)
-+ mutt_bcache_commit (nntp_data->bcache, article);
-+ }
-+
-+ /* 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);
-+
-+ mutt_free_envelope (&hdr->env);
-+ hdr->env = mutt_read_rfc822_header (msg->fp, hdr, 0, 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);
-+
-+ /* 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);
-+
-+ /* 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);
-+
-+ rewind (msg->fp);
-+ mutt_clear_error();
-+ return 0;
-+}
-+
-+/* Post article */
-+int nntp_post (const char *msg) {
-+ NNTP_DATA *nntp_data, nntp_tmp;
-+ FILE *fp;
-+ char buf[LONG_STRING];
-+ size_t len;
-+
-+ if (Context && Context->magic == M_NNTP)
-+ nntp_data = Context->data;
-+ else
-+ {
-+ CurrentNewsSrv = nntp_select_server (NewsServer, 0);
-+ if (!CurrentNewsSrv)
-+ return -1;
-+
-+ nntp_data = &nntp_tmp;
-+ nntp_data->nserv = CurrentNewsSrv;
-+ nntp_data->group = NULL;
-+ }
-+
-+ fp = safe_fopen (msg, "r");
-+ if (!fp)
-+ {
-+ mutt_perror (msg);
-+ return -1;
-+ }
-+
-+ 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;
-+ }
-+
-+ 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);
-+
-+ 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;
-+}
-+
-+/* 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
-+
-+ /* check for new articles */
-+ nntp_data->nserv->check_time = 0;
-+ rc = nntp_check_mailbox (ctx, 1);
-+ if (rc)
-+ return rc;
-+
-+#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];
-+
-+ 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);
-+ }
-+
-+#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
-+ }
-+
-+#ifdef USE_HCACHE
-+ if (hc)
-+ {
-+ mutt_hcache_close (hc);
-+ nntp_data->lastCached = nntp_data->lastLoaded;
-+ }
-+#endif
-+
-+ /* save .newsrc entries */
-+ nntp_newsrc_gen_entries (ctx);
-+ nntp_newsrc_update (nntp_data->nserv);
-+ nntp_newsrc_close (nntp_data->nserv);
-+ return 0;
-+}
-+
-+/* Free up memory associated with the newsgroup context */
-+int nntp_fastclose_mailbox (CONTEXT *ctx)
-+{
-+ NNTP_DATA *nntp_data = ctx->data, *nntp_tmp;
-+
-+ if (!nntp_data)
-+ return 0;
-+
-+ nntp_acache_free (nntp_data);
-+ if (!nntp_data->nserv || !nntp_data->nserv->groups_hash || !nntp_data->group)
-+ return 0;
-+
-+ 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;
-+
-+ 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;
-+
-+ 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;
-+}
-+
-+/* 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;
-+
-+ 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;
-+
-+ 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 (option (OPTLOADDESC) &&
-+ get_description (&nntp_data, "*", _("Loading descriptions...")) < 0)
-+ return -1;
-+
-+ for (i = 0; i < nserv->groups_num; i++)
-+ {
-+ NNTP_DATA *nntp_data = nserv->groups_list[i];
-+
-+ 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;
-+}
-+
-+/* 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;
-+
-+ /* 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;
-+
-+ /* 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;
-+
-+ /* 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;
-+}
-+
-+/* 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;
-+
-+ if (nserv->check_time + NewsPollTimeout > now)
-+ return 0;
-+
-+ mutt_message _("Checking for new messages...");
-+ if (nntp_newsrc_parse (nserv) < 0)
-+ return -1;
-+
-+ 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);
-+
-+ /* 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;
-+
-+ 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;
-+ }
-+
-+ /* .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;
-+
-+ 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
-+
-+ /* update flags according to .newsrc */
-+ for (i = j = 0; i < ctx->msgcount; i++)
-+ {
-+ int flagged = 0;
-+ anum = NHDR (ctx->hdrs[i])->article_num;
-+
-+#ifdef USE_HCACHE
-+ /* check hcache for flagged and deleted flags */
-+ if (hc)
-+ {
-+ if (anum >= first && anum <= nntp_data->lastLoaded)
-+ messages[anum - first] = 1;
-+
-+ snprintf (buf, sizeof (buf), "%d", anum);
-+ hdata = mutt_hcache_fetch (hc, buf, strlen);
-+ if (hdata)
-+ {
-+ int 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);
-+
-+ /* 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];
-+ }
-+
-+#ifdef USE_HCACHE
-+ ctx->msgcount = j;
-+
-+ /* restore headers without "deleted" flag */
-+ for (anum = first; anum <= nntp_data->lastLoaded; anum++)
-+ {
-+ if (messages[anum - first])
-+ continue;
-+
-+ 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);
-+
-+ 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;
-+ }
-+
-+ 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
-+
-+ nserv->newsrc_modified = 0;
-+ ret = M_REOPENED;
-+ }
-+
-+ /* 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);
-+
-+ 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);
-+ }
-+
-+ /* 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;
-+ }
-+
-+#ifdef USE_HCACHE
-+ mutt_hcache_close (hc);
-+#endif
-+ if (ret || !leave_lock)
-+ nntp_newsrc_close (nserv);
-+ mutt_clear_error ();
-+ return ret;
-+}
-+
-+/* 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 (!nserv || !nserv->newgroups_time)
-+ return -1;
-+
-+ /* 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 (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;
-+
-+ /* 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;
-+ }
-+
-+ /* new groups found */
-+ rc = 0;
-+ if (nserv->groups_num != i)
-+ {
-+ nserv->newgroups_time = now;
-+
-+ /* loading descriptions */
-+ if (option (OPTLOADDESC))
-+ {
-+ unsigned int count = 0;
-+ progress_t progress;
-+
-+ 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 (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;
-+}
-+
-+/* 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;
-+
-+ mutt_mktemp (tempfile, sizeof (tempfile));
-+ fp = safe_fopen (tempfile, "w+");
-+ if (!fp)
-+ {
-+ mutt_perror (tempfile);
-+ unlink (tempfile);
-+ return -1;
-+ }
-+
-+ 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;
-+ }
-+
-+ /* 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);
-+
-+ /* 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);
-+ }
-+
-+ /* 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;
-+}
-+
-+typedef struct
-+{
-+ CONTEXT *ctx;
-+ unsigned int num;
-+ unsigned int max;
-+ anum_t *child;
-+} CHILD_CTX;
-+
-+/* Parse XPAT line */
-+static int fetch_children (char *line, void *data)
-+{
-+ CHILD_CTX *cc = data;
-+ anum_t anum;
-+ unsigned int i;
-+
-+ 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;
-+}
-+
-+/* 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;
-+
-+ if (!nntp_data || !nntp_data->nserv)
-+ return -1;
-+ if (nntp_data->firstMessage > nntp_data->lastLoaded)
-+ return 0;
-+
-+ /* init context */
-+ cc.ctx = ctx;
-+ cc.num = 0;
-+ cc.max = 10;
-+ cc.child = safe_malloc (sizeof (anum_t) * cc.max);
-+
-+ /* 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;
-+ }
-+
-+ /* 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..705c524
---- /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.
-+ */
-+
-+#ifndef _NNTP_H_
-+#define _NNTP_H_ 1
-+
-+#include "mutt_socket.h"
-+#include "mailbox.h"
-+#include "bcache.h"
-+
-+#if USE_HCACHE
-+#include "hcache.h"
-+#endif
-+
-+#include <time.h>
-+#include <sys/types.h>
-+#include <stdint.h>
-+
-+#define NNTP_PORT 119
-+#define NNTP_SSL_PORT 563
-+
-+/* number of entries in article cache */
-+#define NNTP_ACACHE_LEN 10
-+
-+/* article number type and format */
-+#define anum_t uint32_t
-+#define ANUM "%u"
-+
-+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;
-+
-+typedef struct
-+{
-+ anum_t first;
-+ anum_t last;
-+} NEWSRC_ENTRY;
-+
-+typedef struct
-+{
-+ unsigned int index;
-+ char *path;
-+} NNTP_ACACHE;
-+
-+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;
-+
-+typedef struct
-+{
-+ anum_t article_num;
-+ unsigned int parsed : 1;
-+} NNTP_HEADER_DATA;
-+
-+#define NHDR(hdr) ((NNTP_HEADER_DATA*)((hdr)->data))
-+
-+/* 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 *);
-+
-+/* 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);
-+
-+NNTP_SERVER *CurrentNewsSrv INITVAL (NULL);
-+
-+#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 94dcdd8..abde1b1 100644
---- a/pager.c
-+++ b/pager.c
-@@ -1088,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
-+
-
- static int format_line (struct line_t **lineInfo, int n, unsigned char *buf,
- int flags, ansi_attr *pa, int cnt,
-@@ -1548,6 +1553,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
-+
-
-
- /* This pager is actually not so simple as it once was. It now operates in
-@@ -1590,6 +1605,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
-+
- if (!(flags & M_SHOWCOLOR))
- flags |= M_SHOWFLAT;
-
-@@ -1629,7 +1648,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)
-@@ -2593,6 +2616,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;
-+
-+ 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;
-+
-+ case OP_FOLLOWUP:
-+ CHECK_MODE(IsHeader (extra) || IsMsgAttach (extra));
-+ CHECK_ATTACH;
-+
-+ if (IsMsgAttach (extra))
-+ followup_to = extra->bdy->hdr->env->followup_to;
-+ else
-+ followup_to = extra->hdr->env->followup_to;
-+
-+ 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
-+
- case OP_REPLY:
- CHECK_MODE(IsHeader (extra) || IsMsgAttach (extra));
- CHECK_ATTACH;
-@@ -2639,7 +2716,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;
-diff --git a/parse.c b/parse.c
-index 6a802ba..cb3ea30 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;
-@@ -1077,6 +1077,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':
-@@ -1159,6 +1170,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
-+
-+ 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;
-+
- case 'r':
- if (!ascii_strcasecmp (line + 1, "eferences"))
- {
-@@ -1271,6 +1303,20 @@ int mutt_parse_rfc822_line (ENVELOPE *e, HEADER *hdr, char *line, char *p, short
- e->x_label = safe_strdup(p);
- matched = 1;
- }
-+#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
-
- default:
- break;
-diff --git a/pattern.c b/pattern.c
-index ea0230e..befe91a 100644
---- a/pattern.c
-+++ b/pattern.c
-@@ -92,6 +92,9 @@ 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 },
-@@ -1222,6 +1225,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);
-@@ -1303,6 +1310,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);
-
-diff --git a/po/POTFILES.in b/po/POTFILES.in
-index 2d01add..115e54f 100644
---- a/po/POTFILES.in
-+++ b/po/POTFILES.in
-@@ -46,6 +46,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/postpone.c b/postpone.c
-index fdeb172..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);
-diff --git a/protos.h b/protos.h
-index 5c17f45..666f36c 100644
---- a/protos.h
-+++ b/protos.h
-@@ -111,6 +111,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);
-diff --git a/recvattach.c b/recvattach.c
-index 5424eda..125395e 100644
---- a/recvattach.c
-+++ b/recvattach.c
-@@ -1120,6 +1120,15 @@ void mutt_view_attachments (HEADER *hdr)
- }
- #endif
-
-+#ifdef USE_NNTP
-+ if (Context->magic == M_NNTP)
-+ {
-+ mutt_flushinp ();
-+ mutt_error _("Can't delete attachment from news server.");
-+ break;
-+ }
-+#endif
-+
- if (WithCrypto && (hdr->security & ENCRYPT))
- {
- mutt_message _(
-@@ -1214,10 +1223,33 @@ void mutt_view_attachments (HEADER *hdr)
- case OP_FORWARD_MESSAGE:
- CHECK_ATTACH;
- mutt_attach_forward (fp, hdr, idx, idxlen,
-- menu->tagprefix ? NULL : idx[menu->current]->content);
-+ menu->tagprefix ? NULL : idx[menu->current]->content, 0);
- menu->redraw = REDRAW_FULL;
- break;
-
-+#ifdef USE_NNTP
-+ case OP_FORWARD_TO_GROUP:
-+ CHECK_ATTACH;
-+ mutt_attach_forward (fp, hdr, idx, idxlen,
-+ menu->tagprefix ? NULL : idx[menu->current]->content, SENDNEWS);
-+ menu->redraw = REDRAW_FULL;
-+ break;
-+
-+ case OP_FOLLOWUP:
-+ CHECK_ATTACH;
-+
-+ if (!idx[menu->current]->content->hdr->env->followup_to ||
-+ mutt_strcasecmp (idx[menu->current]->content->hdr->env->followup_to, "poster") ||
-+ query_quadoption (OPT_FOLLOWUPTOPOSTER,_("Reply by mail as poster prefers?")) != M_YES)
-+ {
-+ mutt_attach_reply (fp, hdr, idx, idxlen,
-+ menu->tagprefix ? NULL : idx[menu->current]->content,
-+ SENDNEWS|SENDREPLY);
-+ menu->redraw = REDRAW_FULL;
-+ break;
-+ }
-+#endif
-+
- case OP_REPLY:
- case OP_GROUP_REPLY:
- case OP_LIST_REPLY:
-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,
-- short nattach)
-+ short nattach, int flags)
- {
- short i;
- short mime_fwd_all = 0;
-@@ -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. */
-- ci_send_message (0, tmphdr, tmpbody, NULL, parent);
-+ ci_send_message (flags, tmphdr, tmpbody, NULL, parent);
- return;
-
- bail:
-@@ -574,7 +574,7 @@ _("Can't decode all tagged attachments. MIME-forward the others?"))) == -1)
- */
-
- static void attach_forward_msgs (FILE * fp, HEADER * hdr,
-- ATTACHPTR ** idx, short idxlen, BODY * cur)
-+ ATTACHPTR ** idx, short idxlen, BODY * cur, int flags)
- {
- HEADER *curhdr = NULL;
- HEADER *tmphdr;
-@@ -679,23 +679,23 @@ static void attach_forward_msgs (FILE * fp, HEADER * hdr,
- else
- mutt_free_header (&tmphdr);
-
-- ci_send_message (0, tmphdr, *tmpbody ? tmpbody : NULL,
-+ ci_send_message (flags, tmphdr, *tmpbody ? tmpbody : NULL,
- NULL, curhdr);
-
- }
-
- void mutt_attach_forward (FILE * fp, HEADER * hdr,
-- ATTACHPTR ** idx, short idxlen, BODY * cur)
-+ ATTACHPTR ** idx, short idxlen, BODY * cur, int flags)
- {
- short nattach;
-
-
- if (check_all_msg (idx, idxlen, cur, 0) == 0)
-- attach_forward_msgs (fp, hdr, idx, idxlen, cur);
-+ attach_forward_msgs (fp, hdr, idx, idxlen, cur, flags);
- else
- {
- nattach = count_tagged (idx, idxlen);
-- attach_forward_bodies (fp, hdr, idx, idxlen, cur, nattach);
-+ attach_forward_bodies (fp, hdr, idx, idxlen, cur, nattach, flags);
- }
- }
-
-@@ -753,28 +753,40 @@ attach_reply_envelope_defaults (ENVELOPE *env, ATTACHPTR **idx, short idxlen,
- return -1;
- }
-
-- if (parent)
-+#ifdef USE_NNTP
-+ if ((flags & SENDNEWS))
- {
-- if (mutt_fetch_recips (env, curenv, flags) == -1)
-- return -1;
-+ /* in case followup set Newsgroups: with Followup-To: if it present */
-+ if (!env->newsgroups && curenv &&
-+ mutt_strcasecmp (curenv->followup_to, "poster"))
-+ env->newsgroups = safe_strdup (curenv->followup_to);
- }
- else
-+#endif
- {
-- for (i = 0; i < idxlen; i++)
-+ if (parent)
- {
-- if (idx[i]->content->tagged
-- && mutt_fetch_recips (env, idx[i]->content->hdr->env, flags) == -1)
-+ if (mutt_fetch_recips (env, curenv, flags) == -1)
- return -1;
- }
-+ else
-+ {
-+ for (i = 0; i < idxlen; i++)
-+ {
-+ if (idx[i]->content->tagged
-+ && mutt_fetch_recips (env, idx[i]->content->hdr->env, flags) == -1)
-+ return -1;
-+ }
-+ }
-+
-+ if ((flags & SENDLISTREPLY) && !env->to)
-+ {
-+ mutt_error _("No mailing lists found!");
-+ return (-1);
-+ }
-+
-+ mutt_fix_reply_recipients (env);
- }
--
-- if ((flags & SENDLISTREPLY) && !env->to)
-- {
-- mutt_error _("No mailing lists found!");
-- return (-1);
-- }
--
-- mutt_fix_reply_recipients (env);
- mutt_make_misc_reply_headers (env, Context, curhdr, curenv);
-
- if (parent)
-@@ -835,6 +847,13 @@ void mutt_attach_reply (FILE * fp, HEADER * hdr,
- char prefix[SHORT_STRING];
- int rc;
-
-+#ifdef USE_NNTP
-+ if (flags & SENDNEWS)
-+ set_option (OPTNEWSSEND);
-+ else
-+ unset_option (OPTNEWSSEND);
-+#endif
-+
- if (check_all_msg (idx, idxlen, cur, 0) == -1)
- {
- nattach = count_tagged (idx, idxlen);
-diff --git a/send.c b/send.c
-index 12fc567..de9e4aa 100644
---- a/send.c
-+++ b/send.c
-@@ -44,6 +44,11 @@
- #include <sys/types.h>
- #include <utime.h>
-
-+#ifdef USE_NNTP
-+#include "nntp.h"
-+#include "mx.h"
-+#endif
-+
- #ifdef MIXMASTER
- #include "remailer.h"
- #endif
-@@ -213,17 +218,51 @@ static int edit_address (ADDRESS **a, /* const */ char *field)
- return 0;
- }
-
--static int edit_envelope (ENVELOPE *en)
-+static int edit_envelope (ENVELOPE *en, int flags)
- {
- char buf[HUGE_STRING];
- LIST *uh = UserHeader;
-
-- if (edit_address (&en->to, "To: ") == -1 || en->to == NULL)
-- return (-1);
-- if (option (OPTASKCC) && edit_address (&en->cc, "Cc: ") == -1)
-- return (-1);
-- if (option (OPTASKBCC) && edit_address (&en->bcc, "Bcc: ") == -1)
-- return (-1);
-+#ifdef USE_NNTP
-+ if (option (OPTNEWSSEND))
-+ {
-+ if (en->newsgroups)
-+ strfcpy (buf, en->newsgroups, sizeof (buf));
-+ else
-+ buf[0] = 0;
-+ if (mutt_get_field ("Newsgroups: ", buf, sizeof (buf), 0) != 0)
-+ return (-1);
-+ FREE (&en->newsgroups);
-+ en->newsgroups = safe_strdup (buf);
-+
-+ if (en->followup_to)
-+ strfcpy (buf, en->followup_to, sizeof (buf));
-+ else
-+ buf[0] = 0;
-+ if (option (OPTASKFOLLOWUP) && mutt_get_field ("Followup-To: ", buf, sizeof (buf), 0) != 0)
-+ return (-1);
-+ FREE (&en->followup_to);
-+ en->followup_to = safe_strdup (buf);
-+
-+ if (en->x_comment_to)
-+ strfcpy (buf, en->x_comment_to, sizeof (buf));
-+ else
-+ buf[0] = 0;
-+ if (option (OPTXCOMMENTTO) && option (OPTASKXCOMMENTTO) && mutt_get_field ("X-Comment-To: ", buf, sizeof (buf), 0) != 0)
-+ return (-1);
-+ FREE (&en->x_comment_to);
-+ en->x_comment_to = safe_strdup (buf);
-+ }
-+ else
-+#endif
-+ {
-+ if (edit_address (&en->to, "To: ") == -1 || en->to == NULL)
-+ return (-1);
-+ if (option (OPTASKCC) && edit_address (&en->cc, "Cc: ") == -1)
-+ return (-1);
-+ if (option (OPTASKBCC) && edit_address (&en->bcc, "Bcc: ") == -1)
-+ return (-1);
-+ }
-
- if (en->subject)
- {
-@@ -258,6 +297,14 @@ static int edit_envelope (ENVELOPE *en)
- return 0;
- }
-
-+#ifdef USE_NNTP
-+char *nntp_get_header (const char *s)
-+{
-+ SKIPWS (s);
-+ return safe_strdup (s);
-+}
-+#endif
-+
- static void process_user_recips (ENVELOPE *env)
- {
- LIST *uh = UserHeader;
-@@ -270,6 +317,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);
-+#ifdef USE_NNTP
-+ else if (ascii_strncasecmp ("newsgroups:", uh->data, 11) == 0)
-+ env->newsgroups = nntp_get_header (uh->data + 11);
-+ else if (ascii_strncasecmp ("followup-to:", uh->data, 12) == 0)
-+ env->followup_to = nntp_get_header (uh->data + 12);
-+ else if (ascii_strncasecmp ("x-comment-to:", uh->data, 13) == 0)
-+ env->x_comment_to = nntp_get_header (uh->data + 13);
-+#endif
- }
- }
-
-@@ -308,6 +363,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 &&
-+#ifdef USE_NNTP
-+ ascii_strncasecmp ("newsgroups:", uh->data, 11) != 0 &&
-+ ascii_strncasecmp ("followup-to:", uh->data, 12) != 0 &&
-+ ascii_strncasecmp ("x-comment-to:", uh->data, 13) != 0 &&
-+#endif
-+ ascii_strncasecmp ("supersedes:", uh->data, 11) != 0 &&
- ascii_strncasecmp ("subject:", uh->data, 8) != 0 &&
- ascii_strncasecmp ("return-path:", uh->data, 12) != 0)
- {
-@@ -659,6 +720,10 @@ void mutt_add_to_reference_headers (ENVELOPE *env, ENVELOPE *curenv, LIST ***pp,
- if (pp) *pp = p;
- if (qq) *qq = q;
-
-+#ifdef USE_NNTP
-+ if (option (OPTNEWSSEND) && option (OPTXCOMMENTTO) && curenv->from)
-+ env->x_comment_to = safe_strdup (mutt_get_name (curenv->from));
-+#endif
- }
-
- static void
-@@ -721,6 +786,16 @@ envelope_defaults (ENVELOPE *env, CONTEXT *ctx, HEADER *cur, int flags)
-
- if (flags & SENDREPLY)
- {
-+#ifdef USE_NNTP
-+ if ((flags & SENDNEWS))
-+ {
-+ /* in case followup set Newsgroups: with Followup-To: if it present */
-+ if (!env->newsgroups && curenv &&
-+ mutt_strcasecmp (curenv->followup_to, "poster"))
-+ env->newsgroups = safe_strdup (curenv->followup_to);
-+ }
-+ else
-+#endif
- if (tag)
- {
- HEADER *h;
-@@ -867,7 +942,18 @@ void mutt_set_followup_to (ENVELOPE *e)
- * it hasn't already been set
- */
-
-- if (option (OPTFOLLOWUPTO) && !e->mail_followup_to)
-+ if (!option (OPTFOLLOWUPTO))
-+ return;
-+#ifdef USE_NNTP
-+ if (option (OPTNEWSSEND))
-+ {
-+ if (!e->followup_to && e->newsgroups && (strrchr (e->newsgroups, ',')))
-+ e->followup_to = safe_strdup (e->newsgroups);
-+ return;
-+ }
-+#endif
-+
-+ if (!e->mail_followup_to)
- {
- if (mutt_is_list_cc (0, e->to, e->cc))
- {
-@@ -1029,6 +1115,9 @@ static int send_message (HEADER *msg)
- #endif
-
- #if USE_SMTP
-+#ifdef USE_NNTP
-+ if (!option (OPTNEWSSEND))
-+#endif
- if (SmtpUrl)
- return mutt_smtp_send (msg->env->from, msg->env->to, msg->env->cc,
- msg->env->bcc, tempfile,
-@@ -1167,6 +1256,13 @@ ci_send_message (int flags, /* send mode */
-
- int rv = -1;
-
-+#ifdef USE_NNTP
-+ if (flags & SENDNEWS)
-+ set_option (OPTNEWSSEND);
-+ else
-+ unset_option (OPTNEWSSEND);
-+#endif
-+
- if (!flags && !msg && quadoption (OPT_RECALL) != M_NO &&
- mutt_num_postponed (1))
- {
-@@ -1202,6 +1298,22 @@ ci_send_message (int flags, /* send mode */
- {
- if ((flags = mutt_get_postponed (ctx, msg, &cur, fcc, sizeof (fcc))) < 0)
- goto cleanup;
-+#ifdef USE_NNTP
-+ /*
-+ * If postponed message is a news article, it have
-+ * a "Newsgroups:" header line, then set appropriate flag.
-+ */
-+ if (msg->env->newsgroups)
-+ {
-+ flags |= SENDNEWS;
-+ set_option (OPTNEWSSEND);
-+ }
-+ else
-+ {
-+ flags &= ~SENDNEWS;
-+ unset_option (OPTNEWSSEND);
-+ }
-+#endif
- }
-
- if (flags & (SENDPOSTPONED|SENDRESEND))
-@@ -1303,11 +1415,16 @@ ci_send_message (int flags, /* send mode */
- if (flags & SENDREPLY)
- mutt_fix_reply_recipients (msg->env);
-
-+#ifdef USE_NNTP
-+ if ((flags & SENDNEWS) && ctx && ctx->magic == M_NNTP && !msg->env->newsgroups)
-+ msg->env->newsgroups = safe_strdup (((NNTP_DATA *)ctx->data)->group);
-+#endif
-+
- if (! (flags & (SENDMAILX|SENDBATCH)) &&
- ! (option (OPTAUTOEDIT) && option (OPTEDITHDRS)) &&
- ! ((flags & SENDREPLY) && option (OPTFASTREPLY)))
- {
-- if (edit_envelope (msg->env) == -1)
-+ if (edit_envelope (msg->env, flags) == -1)
- goto cleanup;
- }
-
-@@ -1605,6 +1722,11 @@ main_loop:
- if (i == -1)
- {
- /* abort */
-+#ifdef USE_NNTP
-+ if (flags & SENDNEWS)
-+ mutt_message _("Article not posted.");
-+ else
-+#endif
- mutt_message _("Mail not sent.");
- goto cleanup;
- }
-@@ -1660,6 +1782,9 @@ main_loop:
- }
- }
-
-+#ifdef USE_NNTP
-+ if (!(flags & SENDNEWS))
-+#endif
- if (!has_recips (msg->env->to) && !has_recips (msg->env->cc) &&
- !has_recips (msg->env->bcc))
- {
-@@ -1693,6 +1818,19 @@ main_loop:
- mutt_error _("No subject specified.");
- goto main_loop;
- }
-+#ifdef USE_NNTP
-+ if ((flags & SENDNEWS) && !msg->env->subject)
-+ {
-+ mutt_error _("No subject specified.");
-+ goto main_loop;
-+ }
-+
-+ if ((flags & SENDNEWS) && !msg->env->newsgroups)
-+ {
-+ mutt_error _("No newsgroup specified.");
-+ goto main_loop;
-+ }
-+#endif
-
- if (msg->content->next)
- msg->content = mutt_make_multipart (msg->content);
-@@ -1900,7 +2038,12 @@ full_fcc:
- }
- }
- else if (!option (OPTNOCURSES) && ! (flags & SENDMAILX))
-- mutt_message (i == 0 ? _("Mail sent.") : _("Sending in background."));
-+ mutt_message (i != 0 ? _("Sending in background.") :
-+#ifdef USE_NNTP
-+ (flags & SENDNEWS) ? _("Article posted.") : _("Mail sent."));
-+#else
-+ _("Mail sent."));
-+#endif
-
- if (WithCrypto && (msg->security & ENCRYPT))
- FREE (&pgpkeylist);
-diff --git a/sendlib.c b/sendlib.c
-index 2128de3..c1240d4 100644
---- a/sendlib.c
-+++ b/sendlib.c
-@@ -46,6 +46,10 @@
- #include <sys/wait.h>
- #include <fcntl.h>
-
-+#ifdef USE_NNTP
-+#include "nntp.h"
-+#endif
-+
- #ifdef HAVE_SYSEXITS_H
- #include <sysexits.h>
- #else /* Make sure EX_OK is defined <philiph at pobox.com> */
-@@ -1543,6 +1547,14 @@ void mutt_write_references (LIST *r, FILE *f, int trim)
- {
- LIST **ref = NULL;
- int refcnt = 0, refmax = 0;
-+ int multiline = 1;
-+ int space = 0;
-+
-+ if (trim < 0)
-+ {
-+ trim = -trim;
-+ multiline = 0;
-+ }
-
- for ( ; (trim == 0 || refcnt < trim) && r ; r = r->next)
- {
-@@ -1553,9 +1565,11 @@ void mutt_write_references (LIST *r, FILE *f, int trim)
-
- while (refcnt-- > 0)
- {
-- fputc (' ', f);
-+ if (multiline || space)
-+ fputc (' ', f);
-+ space = 1;
- fputs (ref[refcnt]->data, f);
-- if (refcnt >= 1)
-+ if (multiline && refcnt >= 1)
- fputc ('\n', f);
- }
-
-@@ -1969,6 +1983,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)
-+#ifdef USE_NNTP
-+ if (!option (OPTNEWSSEND))
-+#endif
- fputs ("To: \n", fp);
-
- if (env->cc)
-@@ -1977,6 +1994,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)
-+#ifdef USE_NNTP
-+ if (!option (OPTNEWSSEND))
-+#endif
- fputs ("Cc: \n", fp);
-
- if (env->bcc && should_write_bcc)
-@@ -1988,8 +2008,28 @@ int mutt_write_rfc822_header (FILE *fp, ENVELOPE *env, BODY *attach,
- }
- }
- else if (mode > 0)
-+#ifdef USE_NNTP
-+ if (!option (OPTNEWSSEND))
-+#endif
- fputs ("Bcc: \n", fp);
-
-+#ifdef USE_NNTP
-+ if (env->newsgroups)
-+ fprintf (fp, "Newsgroups: %s\n", env->newsgroups);
-+ else if (mode == 1 && option (OPTNEWSSEND))
-+ fputs ("Newsgroups: \n", fp);
-+
-+ if (env->followup_to)
-+ fprintf (fp, "Followup-To: %s\n", env->followup_to);
-+ else if (mode == 1 && option (OPTNEWSSEND))
-+ fputs ("Followup-To: \n", fp);
-+
-+ if (env->x_comment_to)
-+ fprintf (fp, "X-Comment-To: %s\n", env->x_comment_to);
-+ else if (mode == 1 && option (OPTNEWSSEND) && option (OPTXCOMMENTTO))
-+ fputs ("X-Comment-To: \n", fp);
-+#endif
-+
- if (env->subject)
- mutt_write_one_header (fp, "Subject", env->subject, NULL, 0, 0);
- else if (mode == 1)
-@@ -2008,6 +2048,9 @@ int mutt_write_rfc822_header (FILE *fp, ENVELOPE *env, BODY *attach,
- fputs ("Reply-To: \n", fp);
-
- if (env->mail_followup_to)
-+#ifdef USE_NNTP
-+ if (!option (OPTNEWSSEND))
-+#endif
- {
- fputs ("Mail-Followup-To: ", fp);
- mutt_write_address_list (env->mail_followup_to, fp, 18, 0);
-@@ -2351,6 +2394,23 @@ mutt_invoke_sendmail (ADDRESS *from, /* the sender */
- size_t argslen = 0, argsmax = 0;
- int i;
-
-+#ifdef USE_NNTP
-+ if (option (OPTNEWSSEND))
-+ {
-+ char cmd[LONG_STRING];
-+
-+ mutt_FormatString (cmd, sizeof (cmd), 0, NONULL (Inews), nntp_format_str, 0, 0);
-+ if (!*cmd)
-+ {
-+ i = nntp_post (msg);
-+ unlink (msg);
-+ return i;
-+ }
-+
-+ s = safe_strdup (cmd);
-+ }
-+#endif
-+
- /* ensure that $sendmail is set to avoid a crash. http://dev.mutt.org/trac/ticket/3548 */
- if (!s)
- {
-@@ -2381,6 +2441,10 @@ mutt_invoke_sendmail (ADDRESS *from, /* the sender */
- i++;
- }
-
-+#ifdef USE_NNTP
-+ if (!option (OPTNEWSSEND))
-+ {
-+#endif
- if (eightbit && option (OPTUSE8BITMIME))
- args = add_option (args, &argslen, &argsmax, "-B8BITMIME");
-
-@@ -2412,6 +2476,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);
-+#ifdef USE_NNTP
-+ }
-+#endif
-
- if (argslen == argsmax)
- safe_realloc (&args, sizeof (char *) * (++argsmax));
-@@ -2492,6 +2559,9 @@ void mutt_prepare_envelope (ENVELOPE *env, int final)
- rfc2047_encode_string (&env->x_label);
-
- if (env->subject)
-+#ifdef USE_NNTP
-+ if (!option (OPTNEWSSEND) || option (OPTMIMESUBJECT))
-+#endif
- {
- rfc2047_encode_string (&env->subject);
- }
-@@ -2612,6 +2682,10 @@ int mutt_bounce_message (FILE *fp, HEADER *h, ADDRESS *to)
- }
- rfc822_write_address (resent_from, sizeof (resent_from), from, 0);
-
-+#ifdef USE_NNTP
-+ unset_option (OPTNEWSSEND);
-+#endif
-+
- /*
- * prepare recipient list. idna conversion appears to happen before this
- * function is called, since the user receives confirmation of the address
-diff --git a/sort.c b/sort.c
-index 76e9e79..9aa259c 100644
---- a/sort.c
-+++ b/sort.c
-@@ -24,6 +24,11 @@
- #include "sort.h"
- #include "mutt_idna.h"
-
-+#ifdef USE_NNTP
-+#include "mx.h"
-+#include "nntp.h"
-+#endif
-+
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
-@@ -151,6 +156,17 @@ static int compare_order (const void *a, const void *b)
- HEADER **ha = (HEADER **) a;
- HEADER **hb = (HEADER **) b;
-
-+#ifdef USE_NNTP
-+ if (Context && Context->magic == M_NNTP)
-+ {
-+ anum_t na = NHDR (*ha)->article_num;
-+ anum_t nb = NHDR (*hb)->article_num;
-+ int result = na == nb ? 0 : na > nb ? 1 : -1;
-+ AUXSORT (result, a, b);
-+ return (SORTCODE (result));
-+ }
-+ else
-+#endif
- /* no need to auxsort because you will never have equality here */
- return (SORTCODE ((*ha)->index - (*hb)->index));
- }
-diff --git a/url.c b/url.c
-index 42a6e09..799e956 100644
---- a/url.c
-+++ b/url.c
-@@ -39,6 +39,8 @@ static const struct mapping_t UrlMap[] =
- { "imaps", U_IMAPS },
- { "pop", U_POP },
- { "pops", U_POPS },
-+ { "news", U_NNTP },
-+ { "snews", U_NNTPS },
- { "mailto", U_MAILTO },
- { "smtp", U_SMTP },
- { "smtps", U_SMTPS },
-@@ -214,7 +216,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;
-
-- if (ciss->user)
-+ if (ciss->user && (ciss->user[0] || !(flags & U_PATH)))
- {
- char u[STRING];
- url_pct_encode (u, sizeof (u), ciss->user);
-diff --git a/url.h b/url.h
-index 926416e..15ec9ce 100644
---- a/url.h
-+++ b/url.h
-@@ -8,6 +8,8 @@ typedef enum url_scheme
- U_POPS,
- U_IMAP,
- U_IMAPS,
-+ U_NNTP,
-+ U_NNTPS,
- U_SMTP,
- U_SMTPS,
- U_MAILTO,
-diff --git a/version.c b/version.c
-index a0cd472..ac3c8ed 100644
---- a/version.c
-+++ b/version.c
-@@ -271,6 +271,11 @@ static struct compile_options comp_opts[] = {
- #else
- { "USE_IMAP", 0 },
- #endif
-+#ifdef USE_NNTP
-+ { "USE_NNTP", 1 },
-+#else
-+ { "USE_NNTP", 0 },
-+#endif
- #ifdef USE_POP
- { "USE_POP", 1 },
- #else
---
-2.8.1
-
diff --git a/debian/patches/neomutt-devel/sensible-browser.patch b/debian/patches/neomutt-devel/sensible-browser.patch
index 774ed9a..806e52d 100644
--- a/debian/patches/neomutt-devel/sensible-browser.patch
+++ b/debian/patches/neomutt-devel/sensible-browser.patch
@@ -1,7 +1,7 @@
-From afb78321ba3b7e63ca04c197de7480411f0c11cc Mon Sep 17 00:00:00 2001
+From d5f83e2d40197827affecbf5edae852d7b0157d9 Mon Sep 17 00:00:00 2001
From: Richard Russon <rich at flatcap.org>
Date: Fri, 6 May 2016 19:53:13 +0100
-Subject: [PATCH 04/28] patches-20160502/sensible-browser
+Subject: [PATCH 02/22] patches-20160502/sensible-browser
---
PATCHES | 1 +
@@ -14,13 +14,14 @@ Subject: [PATCH 04/28] patches-20160502/sensible-browser
create mode 100644 README.sensible-browser
diff --git a/PATCHES b/PATCHES
-index a6121c7..35f6d91 100644
+index f77d115..a8827d6 100644
--- a/PATCHES
+++ b/PATCHES
-@@ -1,2 +1,3 @@
+@@ -15,3 +15,4 @@
+ patch-compress-neo-20160612
+ patch-keywords-neo-20160612
+ patch-nntp-neo-20160612
+patch-sensible-browser-neo-UNKNOWN
- patch-trash-neo-20160502
- patch-ifdef-neo-20160502
diff --git a/README.sensible-browser b/README.sensible-browser
new file mode 100644
index 0000000..adfc076
@@ -67,10 +68,10 @@ index 0000000..adfc076
+ * Richard Russon <rich at flatcap.org>
+
diff --git a/browser.c b/browser.c
-index 46919a0..b0dbeb5 100644
+index 3ffcd13..10cb663 100644
--- a/browser.c
+++ b/browser.c
-@@ -56,6 +56,7 @@ typedef struct folder_t
+@@ -76,6 +76,7 @@ typedef struct folder_t
int num;
} FOLDER;
@@ -78,10 +79,10 @@ index 46919a0..b0dbeb5 100644
static char LastDir[_POSIX_PATH_MAX] = "";
static char LastDirBackup[_POSIX_PATH_MAX] = "";
-@@ -535,17 +536,32 @@ static void init_menu (struct browser_state *state, MUTTMENU *menu, char *title,
-
- menu->tagged = 0;
-
+@@ -862,17 +863,32 @@ static void init_menu (struct browser_state *state, MUTTMENU *menu, char *title,
+ }
+ else
+ #endif
- if (buffy)
+ if (buffy) {
+ menu->is_mailbox_list = 1;
@@ -117,7 +118,7 @@ index 46919a0..b0dbeb5 100644
#endif
snprintf (title, titlelen, _("Directory [%s], File mask: %s"),
path, NONULL(Mask.pattern));
-@@ -731,8 +747,6 @@ void _mutt_select_file (char *f, size_t flen, int flags, char ***files, int *num
+@@ -1104,8 +1120,6 @@ void _mutt_select_file (char *f, size_t flen, int flags, char ***files, int *num
#endif
)
{
@@ -127,10 +128,10 @@ index 46919a0..b0dbeb5 100644
strfcpy (OldLastDir, LastDir, sizeof (OldLastDir));
diff --git a/doc/manual.xml.head b/doc/manual.xml.head
-index 5d037f9..a650c96 100644
+index a2b5ef8..ea3be08 100644
--- a/doc/manual.xml.head
+++ b/doc/manual.xml.head
-@@ -8411,6 +8411,96 @@ bind index D purge-message
+@@ -12534,6 +12534,96 @@ <sect1 id="trash-folder">
</sect2>
</sect1>
@@ -228,10 +229,10 @@ index 5d037f9..a650c96 100644
<chapter id="security">
diff --git a/menu.c b/menu.c
-index 828df9c..5b9f6bb 100644
+index 554f990..cbf1caf 100644
--- a/menu.c
+++ b/menu.c
-@@ -850,8 +850,17 @@ int menu_redraw (MUTTMENU *menu)
+@@ -919,8 +919,17 @@ int menu_redraw (MUTTMENU *menu)
int mutt_menuLoop (MUTTMENU *menu)
{
@@ -249,7 +250,7 @@ index 828df9c..5b9f6bb 100644
FOREVER
{
if (option (OPTMENUCALLER))
-@@ -1074,6 +1083,8 @@ int mutt_menuLoop (MUTTMENU *menu)
+@@ -1143,6 +1152,8 @@ int mutt_menuLoop (MUTTMENU *menu)
break;
default:
@@ -259,10 +260,10 @@ index 828df9c..5b9f6bb 100644
}
}
diff --git a/mutt_menu.h b/mutt_menu.h
-index 8192019..bbcd722 100644
+index 3a7ae08..258ff3d 100644
--- a/mutt_menu.h
+++ b/mutt_menu.h
-@@ -49,6 +49,7 @@ typedef struct menu_t
+@@ -52,6 +52,7 @@ typedef struct menu_t
int offset; /* which screen row to start the index */
int pagelen; /* number of entries per screen */
int tagprefix;
@@ -271,5 +272,5 @@ index 8192019..bbcd722 100644
/* Setting dialog != NULL overrides normal menu behavior.
* In dialog mode menubar is hidden and prompt keys are checked before
--
-2.8.1
+2.8.2
diff --git a/debian/patches/neomutt/01-bug-fixes.patch b/debian/patches/neomutt/01-bug-fixes.patch
deleted file mode 100644
index e3d9093..0000000
--- a/debian/patches/neomutt/01-bug-fixes.patch
+++ /dev/null
@@ -1,848 +0,0 @@
-diff -urN mutt-1.6.1/alias.c mutt-1.6.1-bug-fixes/alias.c
---- mutt-1.6.1/alias.c 2016-05-02 03:02:12.396171369 +0100
-+++ mutt-1.6.1-bug-fixes/alias.c 2016-05-02 03:02:13.041181631 +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-bug-fixes/attach.c
---- mutt-1.6.1/attach.c 2016-05-02 03:02:12.396171369 +0100
-+++ mutt-1.6.1-bug-fixes/attach.c 2016-05-02 03:02:13.042181647 +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/browser.c mutt-1.6.1-bug-fixes/browser.c
---- mutt-1.6.1/browser.c 2016-05-02 03:02:12.397171385 +0100
-+++ mutt-1.6.1-bug-fixes/browser.c 2016-05-02 03:02:13.146183302 +0100
-@@ -29,6 +29,7 @@
- #include "sort.h"
- #include "mailbox.h"
- #include "browser.h"
-+#include "mx.h"
- #ifdef USE_IMAP
- #include "imap.h"
- #endif
-@@ -86,6 +87,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;
-+
-+ int r = mutt_strcoll (pa->desc, pb->desc);
-+
-+ return ((BrowserSort & SORT_REVERSE) ? -r : r);
-+}
-+
- static int browser_compare_date (const void *a, const void *b)
- {
- struct folder_file *pa = (struct folder_file *) a;
-@@ -106,6 +117,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;
-+
-+ int r = pa->all - pb->all;
-+
-+ return ((BrowserSort & SORT_REVERSE) ? -r : r);
-+}
-+
-+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;
-+
-+ int r = pa->new - pb->new;
-+
-+ return ((BrowserSort & SORT_REVERSE) ? -r : r);
-+}
-+
- static void browser_sort (struct browser_state *state)
- {
- int (*f) (const void *, const void *);
-@@ -120,6 +151,15 @@
- case SORT_SIZE:
- 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;
-@@ -260,7 +300,16 @@
- else
- mutt_format_s (dest, destlen, fmt, "");
- break;
--
-+
-+ 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;
-+
- case 'N':
- #ifdef USE_IMAP
- if (mx_is_imap (folder->ff->desc))
-@@ -325,7 +374,8 @@
- }
-
- 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)
- {
- if (state->entrylen == state->entrymax)
- {
-@@ -349,8 +399,9 @@
- }
-
- (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
-@@ -432,7 +483,7 @@
- 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, 0);
- }
- closedir (dp);
- browser_sort (state);
-@@ -460,14 +511,14 @@
- 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);
- 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, 0);
- continue;
- }
- #endif
-@@ -496,7 +547,7 @@
- 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, 0);
- }
- while ((tmp = tmp->next));
- browser_sort (state);
-@@ -1136,9 +1187,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 +1207,19 @@
- BrowserSort = SORT_SIZE;
- break;
-
-- case 4: /* do(n)'t sort */
-+ case 4: /* d(e)scription */
-+ BrowserSort = SORT_DESC;
-+ break;
-+
-+ case 5: /* (c)ount */
-+ BrowserSort = SORT_COUNT;
-+ break;
-+
-+ case 6: /* ne(w) count */
-+ BrowserSort = SORT_COUNT_NEW;
-+ break;
-+
-+ case 7: /* do(n)'t sort */
- BrowserSort = SORT_ORDER;
- resort = 0;
- break;
-diff -urN mutt-1.6.1/browser.h mutt-1.6.1-bug-fixes/browser.h
---- mutt-1.6.1/browser.h 2016-05-02 03:02:12.397171385 +0100
-+++ mutt-1.6.1-bug-fixes/browser.h 2016-05-02 03:02:13.042181647 +0100
-@@ -30,6 +30,8 @@
- char *desc;
-
- unsigned int new;
-+ unsigned int all;
-+
- #ifdef USE_IMAP
- char delim;
-
-diff -urN mutt-1.6.1/compose.c mutt-1.6.1-bug-fixes/compose.c
---- mutt-1.6.1/compose.c 2016-05-02 03:02:12.398171401 +0100
-+++ mutt-1.6.1-bug-fixes/compose.c 2016-05-02 03:02:13.147183318 +0100
-@@ -110,7 +110,7 @@
-
- static void redraw_crypt_lines (HEADER *msg)
- {
-- mvaddstr (HDR_CRYPT, 0, "Security: ");
-+ mvprintw (HDR_CRYPT, 0, TITLE_FMT, "Security: ");
-
- if ((WithCrypto & (APPLICATION_PGP | APPLICATION_SMIME)) == 0)
- {
-@@ -150,11 +150,11 @@
-
- if ((WithCrypto & APPLICATION_PGP)
- && (msg->security & APPLICATION_PGP) && (msg->security & SIGN))
-- printw ("%s%s", _(" sign as: "), PgpSignAs ? PgpSignAs : _("<default>"));
-+ printw (TITLE_FMT "%s", _("sign as: "), PgpSignAs ? PgpSignAs : _("<default>"));
-
- if ((WithCrypto & APPLICATION_SMIME)
- && (msg->security & APPLICATION_SMIME) && (msg->security & SIGN)) {
-- printw ("%s%s", _(" sign as: "), SmimeDefaultKey ? SmimeDefaultKey : _("<default>"));
-+ printw (TITLE_FMT "%s", _("sign as: "), SmimeDefaultKey ? SmimeDefaultKey : _("<default>"));
- }
-
- if ((WithCrypto & APPLICATION_SMIME)
-@@ -175,7 +175,7 @@
- int c;
- char *t;
-
-- mvaddstr (HDR_MIX, 0, " Mix: ");
-+ mvprintw (HDR_MIX, 0, TITLE_FMT, "Mix: ");
-
- if (!chain)
- {
-diff -urN mutt-1.6.1/configure.ac mutt-1.6.1-bug-fixes/configure.ac
---- mutt-1.6.1/configure.ac 2016-05-02 03:02:12.398171401 +0100
-+++ mutt-1.6.1-bug-fixes/configure.ac 2016-05-02 03:02:13.147183318 +0100
-@@ -313,6 +313,7 @@
- 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 +355,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)
-diff -urN mutt-1.6.1/curs_main.c mutt-1.6.1-bug-fixes/curs_main.c
---- mutt-1.6.1/curs_main.c 2016-05-02 03:02:12.400171433 +0100
-+++ mutt-1.6.1-bug-fixes/curs_main.c 2016-05-02 03:02:13.149183350 +0100
-@@ -118,7 +118,9 @@
- {
- char *term = getenv("TERM");
- char *tcaps;
-+#ifdef HAVE_USE_EXTENDED_NAMES
- int tcapi;
-+#endif
- char **termp;
- char *known[] = {
- "color-xterm",
-diff -urN mutt-1.6.1/globals.h mutt-1.6.1-bug-fixes/globals.h
---- mutt-1.6.1/globals.h 2016-05-02 03:02:12.403171480 +0100
-+++ mutt-1.6.1-bug-fixes/globals.h 2016-05-02 03:02:13.152183397 +0100
-@@ -192,8 +192,6 @@
- extern unsigned char QuadOptions[];
- #endif
-
--WHERE unsigned short Counter INITVAL (0);
--
- WHERE short ConnectTimeout;
- WHERE short HistSize;
- WHERE short MenuContext;
-diff -urN mutt-1.6.1/init.c mutt-1.6.1-bug-fixes/init.c
---- mutt-1.6.1/init.c 2016-05-02 03:02:12.405171512 +0100
-+++ mutt-1.6.1-bug-fixes/init.c 2016-05-02 03:02:13.154183429 +0100
-@@ -2867,23 +2867,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;
-@@ -2902,13 +2885,9 @@
- ReverseAlias = hash_create (1031, 1);
-
- 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 */
-diff -urN mutt-1.6.1/init.h mutt-1.6.1-bug-fixes/init.h
---- mutt-1.6.1/init.h 2016-05-02 03:02:12.407171544 +0100
-+++ mutt-1.6.1-bug-fixes/init.h 2016-05-02 03:02:13.156183461 +0100
-@@ -3046,7 +3046,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
-@@ -3631,7 +3634,10 @@
-
- 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 }
-diff -urN mutt-1.6.1/lib.c mutt-1.6.1-bug-fixes/lib.c
---- mutt-1.6.1/lib.c 2016-05-02 03:02:12.407171544 +0100
-+++ mutt-1.6.1-bug-fixes/lib.c 2016-05-02 03:02:13.067182045 +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/main.c mutt-1.6.1-bug-fixes/main.c
---- mutt-1.6.1/main.c 2016-05-02 03:02:12.408171560 +0100
-+++ mutt-1.6.1-bug-fixes/main.c 2016-05-02 03:02:13.156183461 +0100
-@@ -598,7 +598,7 @@
-
- mutt_error = mutt_nocurses_error;
- mutt_message = mutt_nocurses_error;
-- SRAND (time (NULL));
-+ (void)mutt_rand32();
- umask (077);
-
- memset (Options, 0, sizeof (Options));
-diff -urN mutt-1.6.1/mbyte.c mutt-1.6.1-bug-fixes/mbyte.c
---- mutt-1.6.1/mbyte.c 2016-05-02 03:02:12.408171560 +0100
-+++ mutt-1.6.1-bug-fixes/mbyte.c 2016-05-02 03:02:13.068182061 +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;
-
- 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/mh.c mutt-1.6.1-bug-fixes/mh.c
---- mutt-1.6.1/mh.c 2016-05-02 03:02:12.409171576 +0100
-+++ mutt-1.6.1-bug-fixes/mh.c 2016-05-02 03:02:13.157183477 +0100
-@@ -304,8 +304,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)
-@@ -1313,9 +1313,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 +1399,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);
-
-diff -urN mutt-1.6.1/mutt.h mutt-1.6.1-bug-fixes/mutt.h
---- mutt-1.6.1/mutt.h 2016-05-02 03:02:12.409171576 +0100
-+++ mutt-1.6.1-bug-fixes/mutt.h 2016-05-02 03:02:13.157183477 +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
-+
- #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
-+
-+#ifdef HAVE_FGETC_UNLOCKED
-+# define fgetc fgetc_unlocked
-+#endif
-+
- /* nifty trick I stole from ELM 2.5alpha. */
- #ifdef MAIN_C
- #define WHERE
-diff -urN mutt-1.6.1/muttlib.c mutt-1.6.1-bug-fixes/muttlib.c
---- mutt-1.6.1/muttlib.c 2016-05-02 03:02:12.410171592 +0100
-+++ mutt-1.6.1-bug-fixes/muttlib.c 2016-05-02 03:02:13.158183493 +0100
-@@ -37,6 +37,7 @@
- #include <string.h>
- #include <ctype.h>
- #include <unistd.h>
-+#include <sys/syscall.h>
- #include <stdlib.h>
- #include <sys/wait.h>
- #include <errno.h>
-@@ -771,12 +772,79 @@
- mutt_free_envelope(extra);
- }
-
-+static FILE *frandom;
-+
-+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);
-+ }
-+}
-+
-+static const unsigned char base32[] = "abcdefghijklmnopqrstuvwxyz234567";
-+
-+void mutt_rand_base32(void *out, size_t len)
-+{
-+ size_t pos;
-+ uint8_t *p = out;
-+
-+ mutt_randbuf(p, len);
-+ for (pos = 0; pos < len; pos++)
-+ p[pos] = base32[p[pos] % 32];
-+}
-+
-+uint32_t mutt_rand32(void)
-+{
-+ uint32_t ret;
-+
-+ mutt_randbuf(&ret, sizeof(ret));
-+ return ret;
-+}
-+
-+uint64_t mutt_rand64(void)
-+{
-+ uint64_t ret;
-+
-+ mutt_randbuf(&ret, sizeof(ret));
-+ return ret;
-+}
-+
-+
- 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",
-diff -urN mutt-1.6.1/mutt_ssl.c mutt-1.6.1-bug-fixes/mutt_ssl.c
---- mutt-1.6.1/mutt_ssl.c 2016-05-02 03:02:12.409171576 +0100
-+++ mutt-1.6.1-bug-fixes/mutt_ssl.c 2016-05-02 03:02:13.158183493 +0100
-@@ -432,14 +432,6 @@
- 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 -urN mutt-1.6.1/protos.h mutt-1.6.1-bug-fixes/protos.h
---- mutt-1.6.1/protos.h 2016-05-02 03:02:12.411171608 +0100
-+++ mutt-1.6.1-bug-fixes/protos.h 2016-05-02 03:02:13.159183509 +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
-@@ -375,6 +376,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 +428,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 +561,11 @@
- #ifndef HAVE_MKDTEMP
- char *mkdtemp (char *tmpl);
- #endif
-+
-+#ifndef HAVE_STRNLEN
-+size_t strnlen(const char *s, size_t maxlen);
-+#endif
-+
-+#ifndef strndup
-+char *strndup(const char *s, size_t n);
-+#endif
-diff -urN mutt-1.6.1/sendlib.c mutt-1.6.1-bug-fixes/sendlib.c
---- mutt-1.6.1/sendlib.c 2016-05-02 03:02:12.440172071 +0100
-+++ mutt-1.6.1-bug-fixes/sendlib.c 2016-05-02 03:02:13.160183524 +0100
-@@ -73,8 +73,6 @@
- '8', '9', '+', '/'
- };
-
--static char MsgIdPfx = 'A';
--
- static void transform_to_7bit (BODY *a, FILE *fpin);
-
- static void encode_quoted (FGETCONV * fc, FILE *fout, int istext)
-@@ -480,18 +478,12 @@
-
- #undef write_as_text_part
-
--#define BOUNDARYLEN 16
- void mutt_generate_boundary (PARAMETER **parm)
- {
-- char rs[BOUNDARYLEN + 1];
-- char *p = rs;
-- int i;
--
-- rs[BOUNDARYLEN] = 0;
-- for (i=0;i<BOUNDARYLEN;i++)
-- *p++ = B64Chars[LRAND() % sizeof (B64Chars)];
-- *p = 0;
-+ char rs[MUTT_RANDTAG_LEN + 1];
-
-+ mutt_rand_base32(rs, sizeof(rs) - 1);
-+ rs[MUTT_RANDTAG_LEN] = 0;
- mutt_set_parameter ("boundary", rs, parm);
- }
-
-@@ -2133,16 +2125,18 @@
- time_t now;
- struct tm *tm;
- const char *fqdn;
-+ unsigned char rndid[MUTT_RANDTAG_LEN + 1];
-
-+ mutt_rand_base32(rndid, sizeof(rndid) - 1);
-+ rndid[MUTT_RANDTAG_LEN] = 0;
- now = time (NULL);
- tm = gmtime (&now);
- if(!(fqdn = mutt_fqdn(0)))
- fqdn = NONULL(Hostname);
-
-- snprintf (buf, sizeof (buf), "<%d%02d%02d%02d%02d%02d.G%c%u@%s>",
-+ snprintf (buf, sizeof (buf), "<%d%02d%02d%02d%02d%02d.%s@%s>",
- tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour,
-- tm->tm_min, tm->tm_sec, MsgIdPfx, (unsigned int)getpid (), fqdn);
-- MsgIdPfx = (MsgIdPfx == 'Z') ? 'A' : MsgIdPfx + 1;
-+ tm->tm_min, tm->tm_sec, rndid, fqdn);
- return (safe_strdup (buf));
- }
-
-@@ -2559,9 +2553,12 @@
- mutt_copy_header (fp, h, f, ch_flags, NULL);
- fputc ('\n', f);
- mutt_copy_bytes (fp, f, h->content->length);
-- safe_fclose (&f);
- FREE (&msgid_str);
--
-+ if (safe_fclose (&f) != 0) {
-+ mutt_perror(tempfile);
-+ unlink(tempfile);
-+ return -1;
-+ }
- #if USE_SMTP
- if (SmtpUrl)
- ret = mutt_smtp_send (env_from, to, NULL, NULL, tempfile,
-diff -urN mutt-1.6.1/sort.h mutt-1.6.1-bug-fixes/sort.h
---- mutt-1.6.1/sort.h 2016-05-02 03:02:12.440172071 +0100
-+++ mutt-1.6.1-bug-fixes/sort.h 2016-05-02 03:02:13.160183524 +0100
-@@ -31,6 +31,9 @@
- #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
- /* 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
-diff -urN mutt-1.6.1/strndup.c mutt-1.6.1-bug-fixes/strndup.c
---- mutt-1.6.1/strndup.c 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-bug-fixes/strndup.c 2016-05-02 03:02:13.105182649 +0100
-@@ -0,0 +1,19 @@
-+/*
-+ * Copyright (C) 2013 Karel Zak <kzak at redhat.com>
-+ */
-+
-+#if HAVE_CONFIG_H
-+# include "config.h"
-+#endif
-+
-+#include "mutt.h"
-+
-+char *strndup(const char *s, size_t n)
-+{
-+ size_t len = strnlen(s, n);
-+ char *new = (char *) malloc((len + 1) * sizeof(char));
-+ if (!new)
-+ return NULL;
-+ new[len] = '\0';
-+ return (char *) memcpy(new, s, len);
-+}
-diff -urN mutt-1.6.1/strnlen.c mutt-1.6.1-bug-fixes/strnlen.c
---- mutt-1.6.1/strnlen.c 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-bug-fixes/strnlen.c 2016-05-02 03:02:13.105182649 +0100
-@@ -0,0 +1,20 @@
-+/*
-+ * Copyright (C) 2013 Karel Zak <kzak at redhat.com>
-+ */
-+
-+#if HAVE_CONFIG_H
-+# include "config.h"
-+#endif
-+
-+#include "mutt.h"
-+
-+size_t strnlen(const char *s, size_t maxlen)
-+{
-+ int i;
-+
-+ for (i = 0; i < maxlen; i++) {
-+ if (s[i] == '\0')
-+ return i + 1;
-+ }
-+ return maxlen;
-+}
diff --git a/debian/patches/neomutt/02-quasi-delete.patch b/debian/patches/neomutt/02-quasi-delete.patch
deleted file mode 100644
index 830676e..0000000
--- a/debian/patches/neomutt/02-quasi-delete.patch
+++ /dev/null
@@ -1,289 +0,0 @@
-diff -urN mutt-1.6.1/curs_main.c mutt-1.6.1-quasi-delete/curs_main.c
---- mutt-1.6.1/curs_main.c 2016-05-02 03:02:12.400171433 +0100
-+++ mutt-1.6.1-quasi-delete/curs_main.c 2016-05-02 03:02:13.424187725 +0100
-@@ -1150,6 +1150,20 @@
- menu->redraw = REDRAW_FULL;
- break;
-
-+ 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;
-+
- case OP_MAIN_CHANGE_FOLDER:
- case OP_MAIN_NEXT_UNREAD_MAILBOX:
-
-diff -urN mutt-1.6.1/doc/manual.xml.head mutt-1.6.1-quasi-delete/doc/manual.xml.head
---- mutt-1.6.1/doc/manual.xml.head 2016-05-02 03:02:12.402171465 +0100
-+++ mutt-1.6.1-quasi-delete/doc/manual.xml.head 2016-05-02 03:02:13.427187773 +0100
-@@ -8081,6 +8081,126 @@
-
- </sect1>
-
-+<sect1 id="quasi-delete">
-+ <title>Quasi-Delete Patch</title>
-+ <subtitle>Mark emails that should be hidden, but not deleted</subtitle>
-+
-+ <sect2 id="quasi-delete-patch">
-+ <title>Patch</title>
-+
-+ <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>
-+
-+ <itemizedlist>
-+ <title>Dependencies:</title>
-+ <listitem><para>mutt-1.5.24</para></listitem>
-+ </itemizedlist>
-+
-+ <para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
-+ </sect2>
-+
-+ <sect2 id="quasi-delete-intro">
-+ <title>Introduction</title>
-+
-+ <para>
-+ The <quote>quasi-delete</quote> function marks an email that should be
-+ hidden from the index, but NOT deleted.
-+ </para>
-+
-+ <para>
-+ On its own, this patch isn't very useful. It forms a useful part of
-+ the notmuch plugin.
-+ </para>
-+ </sect2>
-+
-+<!--
-+ <sect2 id="quasi-delete-variables">
-+ <title>Variables</title>
-+ <para>None</para>
-+ </sect2>
-+-->
-+
-+ <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>
-+
-+<!--
-+ <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>
-+-->
-+
-+ <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>
-+
- </chapter>
-
- <chapter id="security">
-diff -urN mutt-1.6.1/doc/muttrc.quasi-delete mutt-1.6.1-quasi-delete/doc/muttrc.quasi-delete
---- mutt-1.6.1/doc/muttrc.quasi-delete 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-quasi-delete/doc/muttrc.quasi-delete 2016-05-02 03:02:13.323186118 +0100
-@@ -0,0 +1,7 @@
-+# 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.
-+bind index,pager Q quasi-delete
-+
-+# vim: syntax=muttrc
-diff -urN mutt-1.6.1/doc/vimrc.quasi-delete mutt-1.6.1-quasi-delete/doc/vimrc.quasi-delete
---- mutt-1.6.1/doc/vimrc.quasi-delete 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-quasi-delete/doc/vimrc.quasi-delete 2016-05-02 03:02:13.324186134 +0100
-@@ -0,0 +1,5 @@
-+" Vim syntax file for the mutt quasi-delete patch
-+
-+syntax match muttrcFunction contained "\<quasi-delete\>"
-+
-+" vim: syntax=vim
-diff -urN mutt-1.6.1/functions.h mutt-1.6.1-quasi-delete/functions.h
---- mutt-1.6.1/functions.h 2016-05-02 03:02:12.403171480 +0100
-+++ mutt-1.6.1-quasi-delete/functions.h 2016-05-02 03:02:13.427187773 +0100
-@@ -167,6 +167,7 @@
- { "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 },
-
-
- { NULL, 0, NULL }
-@@ -271,6 +272,7 @@
- { "decrypt-save", OP_DECRYPT_SAVE, NULL },
-
- { "what-key", OP_WHAT_KEY, NULL },
-+ { "quasi-delete", OP_MAIN_QUASI_DELETE, NULL },
-
- { NULL, 0, NULL }
- };
-diff -urN mutt-1.6.1/mutt.h mutt-1.6.1-quasi-delete/mutt.h
---- mutt-1.6.1/mutt.h 2016-05-02 03:02:12.409171576 +0100
-+++ mutt-1.6.1-quasi-delete/mutt.h 2016-05-02 03:02:13.433187868 +0100
-@@ -720,6 +720,7 @@
- unsigned int flagged : 1; /* marked important? */
- unsigned int tagged : 1;
- 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;
-diff -urN mutt-1.6.1/mx.c mutt-1.6.1-quasi-delete/mx.c
---- mutt-1.6.1/mx.c 2016-05-02 03:02:12.410171592 +0100
-+++ mutt-1.6.1-quasi-delete/mx.c 2016-05-02 03:02:13.434187884 +0100
-@@ -1005,9 +1005,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)
- {
-diff -urN mutt-1.6.1/OPS mutt-1.6.1-quasi-delete/OPS
---- mutt-1.6.1/OPS 2016-05-02 03:02:12.392171305 +0100
-+++ mutt-1.6.1-quasi-delete/OPS 2016-05-02 03:02:13.417187613 +0100
-@@ -127,6 +127,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"
-diff -urN mutt-1.6.1/PATCHES mutt-1.6.1-quasi-delete/PATCHES
---- mutt-1.6.1/PATCHES 2016-05-02 03:02:12.396171369 +0100
-+++ mutt-1.6.1-quasi-delete/PATCHES 2016-05-02 03:02:13.421187677 +0100
-@@ -0,0 +1 @@
-+patch-quasi-delete-neo-20160502
-diff -urN mutt-1.6.1/README.quasi-delete mutt-1.6.1-quasi-delete/README.quasi-delete
---- mutt-1.6.1/README.quasi-delete 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-quasi-delete/README.quasi-delete 2016-05-02 03:02:13.421187677 +0100
-@@ -0,0 +1,49 @@
-+Quasi-Delete Patch
-+==================
-+
-+ Mark emails that should be hidden, but not deleted
-+
-+Patch
-+-----
-+
-+ To check if Mutt supports "Quasi-Delete", look for "patch-quasi-delete" in
-+ the mutt version.
-+
-+ Dependencies
-+ * mutt-1.5.24
-+
-+Introduction
-+------------
-+
-+ The "quasi-delete" function marks an email that should be hidden from the
-+ index, but NOT deleted.
-+
-+ On its own, this patch isn't very useful. It forms a useful part of the
-+ notmuch plugin.
-+
-+Functions
-+---------
-+
-+ Quasi-Delete Functions
-+
-+ | Menus | Default Key | Function | Description |
-+ |-------------|-------------|------------------|---------------------------------------|
-+ | index,pager | (none) | '<quasi-delete>' | delete from mutt, don't touch on disk |
-+
-+See Also
-+--------
-+
-+ * NeoMutt project
-+ * notmuch patch
-+
-+Known Bugs
-+----------
-+
-+ None
-+
-+Credits
-+-------
-+
-+ * Karel Zak <kzak at redhat.com>
-+ * Richard Russon <rich at flatcap.org>
-+
diff --git a/debian/patches/neomutt/03-progress.patch b/debian/patches/neomutt/03-progress.patch
deleted file mode 100644
index 66720fa..0000000
--- a/debian/patches/neomutt/03-progress.patch
+++ /dev/null
@@ -1,319 +0,0 @@
-diff -urN mutt-1.6.1/color.c mutt-1.6.1-progress/color.c
---- mutt-1.6.1/color.c 2016-05-02 03:02:12.397171385 +0100
-+++ mutt-1.6.1-progress/color.c 2016-05-02 03:02:13.590190366 +0100
-@@ -93,6 +93,7 @@
- { "bold", MT_COLOR_BOLD },
- { "underline", MT_COLOR_UNDERLINE },
- { "index", MT_COLOR_INDEX },
-+ { "progress", MT_COLOR_PROGRESS },
- { "prompt", MT_COLOR_PROMPT },
- { NULL, 0 }
- };
-diff -urN mutt-1.6.1/curs_lib.c mutt-1.6.1-progress/curs_lib.c
---- mutt-1.6.1/curs_lib.c 2016-05-02 03:02:12.399171417 +0100
-+++ mutt-1.6.1-progress/curs_lib.c 2016-05-02 03:02:13.592190398 +0100
-@@ -411,6 +411,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;
-+
-+ 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 +508,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);
- }
- }
-
-diff -urN mutt-1.6.1/doc/manual.xml.head mutt-1.6.1-progress/doc/manual.xml.head
---- mutt-1.6.1/doc/manual.xml.head 2016-05-02 03:02:12.402171465 +0100
-+++ mutt-1.6.1-progress/doc/manual.xml.head 2016-05-02 03:02:13.594190429 +0100
-@@ -2706,6 +2706,7 @@
- <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>
-@@ -8081,6 +8082,125 @@
-
- </sect1>
-
-+<sect1 id="progress">
-+ <title>Progress Bar Patch</title>
-+ <subtitle>Show a visual progress bar on slow operations</subtitle>
-+
-+ <sect2 id="progress-patch">
-+ <title>Patch</title>
-+
-+ <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>
-+
-+ <itemizedlist>
-+ <title>Dependencies:</title>
-+ <listitem><para>mutt-1.5.24</para></listitem>
-+ </itemizedlist>
-+
-+ <para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
-+ </sect2>
-+
-+ <sect2 id="progress-intro">
-+ <title>Introduction</title>
-+
-+ <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>
-+
-+<!--
-+ <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>
-+-->
-+
-+ <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>
-+
-+<!--
-+ <sect2 id="progress-sort">
-+ <title>Sort</title>
-+ <para>None</para>
-+ </sect2>
-+-->
-+
-+ <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>
-+
- </chapter>
-
- <chapter id="security">
-diff -urN mutt-1.6.1/doc/muttrc.progress mutt-1.6.1-progress/doc/muttrc.progress
---- mutt-1.6.1/doc/muttrc.progress 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-progress/doc/muttrc.progress 2016-05-02 03:02:13.503188982 +0100
-@@ -0,0 +1,10 @@
-+# 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
-+color progress white red
-+
-+# vim: syntax=muttrc
-diff -urN mutt-1.6.1/doc/vimrc.progress mutt-1.6.1-progress/doc/vimrc.progress
---- mutt-1.6.1/doc/vimrc.progress 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-progress/doc/vimrc.progress 2016-05-02 03:02:13.507189045 +0100
-@@ -0,0 +1,5 @@
-+" Vim syntax file for the mutt progress patch
-+
-+syntax keyword muttrcColorField contained progress
-+
-+" vim: syntax=vim
-diff -urN mutt-1.6.1/mutt_curses.h mutt-1.6.1-progress/mutt_curses.h
---- mutt-1.6.1/mutt_curses.h 2016-05-02 03:02:12.409171576 +0100
-+++ mutt-1.6.1-progress/mutt_curses.h 2016-05-02 03:02:13.600190525 +0100
-@@ -124,6 +124,7 @@
- MT_COLOR_UNDERLINE,
- MT_COLOR_INDEX,
- MT_COLOR_PROMPT,
-+ MT_COLOR_PROGRESS,
- MT_COLOR_MAX
- };
-
-diff -urN mutt-1.6.1/PATCHES mutt-1.6.1-progress/PATCHES
---- mutt-1.6.1/PATCHES 2016-05-02 03:02:12.396171369 +0100
-+++ mutt-1.6.1-progress/PATCHES 2016-05-02 03:02:13.589190350 +0100
-@@ -0,0 +1 @@
-+patch-progress-neo-20160502
-diff -urN mutt-1.6.1/README.progress mutt-1.6.1-progress/README.progress
---- mutt-1.6.1/README.progress 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-progress/README.progress 2016-05-02 03:02:13.589190350 +0100
-@@ -0,0 +1,49 @@
-+Progress Bar Patch
-+==================
-+
-+ Show a visual progress bar on slow operations
-+
-+Patch
-+-----
-+
-+ To check if Mutt supports "Progress Bar", look for "patch-progress" in the
-+ mutt version.
-+
-+ Dependencies
-+ * mutt-1.5.24
-+
-+Introduction
-+------------
-+
-+ The "progress" patch shows a visual progress bar on slow tasks, such as
-+ indexing a large folder over the net.
-+
-+Colors
-+------
-+
-+ Progress Colors
-+
-+ | Name | Default Color | Description |
-+ |------------|---------------|---------------------|
-+ | 'progress' | default | Visual progress bar |
-+
-+See Also
-+--------
-+
-+ * NeoMutt project
-+ * Color command
-+
-+Known Bugs
-+----------
-+
-+ None
-+
-+Credits
-+-------
-+
-+ * 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>
-+
diff --git a/debian/patches/neomutt/04-status-color.patch b/debian/patches/neomutt/04-status-color.patch
deleted file mode 100644
index 209502b..0000000
--- a/debian/patches/neomutt/04-status-color.patch
+++ /dev/null
@@ -1,612 +0,0 @@
-diff -urN mutt-1.6.1/color.c mutt-1.6.1-status-color/color.c
---- mutt-1.6.1/color.c 2016-05-02 03:02:12.397171385 +0100
-+++ mutt-1.6.1-status-color/color.c 2016-05-02 03:02:13.826194121 +0100
-@@ -34,6 +34,7 @@
- int ColorDefs[MT_COLOR_MAX];
- COLOR_LINE *ColorHdrList = NULL;
- COLOR_LINE *ColorBodyList = NULL;
-+COLOR_LINE *ColorStatusList = NULL;
- COLOR_LINE *ColorIndexList = NULL;
-
- /* local to this file */
-@@ -495,7 +496,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 +567,7 @@
- }
- tmp->next = *top;
- tmp->pattern = safe_strdup (s);
-+ tmp->match = match;
- #ifdef HAVE_COLOR
- if(fg != -1 && bg != -1)
- {
-@@ -708,7 +710,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;
-@@ -716,8 +718,6 @@
- if(callback(buf, s, &fg, &bg, &attr, err) == -1)
- return -1;
-
-- /* extract a regular expression if needed */
--
- if (object == MT_COLOR_HEADER || object == MT_COLOR_BODY || object == MT_COLOR_INDEX)
- {
- if (!MoreArgs (s))
-@@ -729,7 +729,7 @@
- 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,12 +754,37 @@
- #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 upto 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);
-+
-+ if (MoreArgs (s)) {
-+ BUFFER temporary;
-+ memset (&temporary, 0, sizeof (BUFFER));
-+ mutt_extract_token (&temporary, s, 0);
-+ match = atoi (temporary.data);
-+ FREE(&temporary.data);
-+ }
-+
-+ if (MoreArgs (s)) {
-+ strfcpy (err->data, _("too many arguments"), err->dsize);
-+ return -1;
-+ }
-+
-+ 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_QUOTED)
-diff -urN mutt-1.6.1/curs_main.c mutt-1.6.1-status-color/curs_main.c
---- mutt-1.6.1/curs_main.c 2016-05-02 03:02:12.400171433 +0100
-+++ mutt-1.6.1-status-color/curs_main.c 2016-05-02 03:02:13.828194153 +0100
-@@ -477,6 +477,112 @@
- 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;
-+
-+ do {
-+ found = 0;
-+ null_rx = 0;
-+ COLOR_LINE *color_line = ColorStatusList;
-+
-+ if (!buf[offset])
-+ break;
-+
-+ while (color_line) {
-+ regmatch_t pmatch[color_line->match + 1];
-+
-+ 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;
-+ }
-+
-+ 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
-+ }
-+
-+ safe_free (&lineInfo.syntax);
-+}
-+
- static const struct mapping_t IndexHelp[] = {
- { N_("Quit"), OP_QUIT },
- { N_("Del"), OP_DELETE },
-@@ -633,7 +739,7 @@
- menu_status_line (buf, sizeof (buf), menu, NONULL (Status));
- move (option (OPTSTATUSONTOP) ? 0 : LINES-2, 0);
- SETCOLOR (MT_COLOR_STATUS);
-- mutt_paddstr (COLS, buf);
-+ mutt_draw_statusline (COLS, buf);
- NORMAL_COLOR;
- menu->redraw &= ~REDRAW_STATUS;
- if (option(OPTTSENABLED) && TSSupported)
-diff -urN mutt-1.6.1/doc/manual.xml.head mutt-1.6.1-status-color/doc/manual.xml.head
---- mutt-1.6.1/doc/manual.xml.head 2016-05-02 03:02:12.402171465 +0100
-+++ mutt-1.6.1-status-color/doc/manual.xml.head 2016-05-02 03:02:13.830194184 +0100
-@@ -8081,6 +8081,209 @@
-
- </sect1>
-
-+<sect1 id="status-color">
-+ <title>Status Color Patch</title>
-+ <subtitle>Custom rules for theming the status bar</subtitle>
-+
-+ <sect2 id="status-color-patch">
-+ <title>Patch</title>
-+
-+ <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>
-+
-+ <itemizedlist>
-+ <title>Dependencies:</title>
-+ <listitem><para>mutt-1.5.24</para></listitem>
-+ </itemizedlist>
-+
-+ <para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
-+ </sect2>
-+
-+ <sect2 id="status-color-intro">
-+ <title>Introduction</title>
-+
-+ <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>
-+
-+ <para>
-+ Unlike normal color commands, <literal>color status</literal> can now
-+ take up to 2 extra parameters (regex, num).
-+ </para>
-+ </sect2>
-+
-+<!--
-+ <sect2 id="status-color-variables">
-+ <title>Variables</title>
-+ <para>None</para>
-+ </sect2>
-+
-+ <sect2 id="status-color-functions">
-+ <title>Functions</title>
-+ <para>None</para>
-+ </sect2>
-+-->
-+
-+ <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>
-+
-+<!--
-+ <sect2 id="status-color-sort">
-+ <title>Sort</title>
-+ <para>None</para>
-+ </sect2>
-+-->
-+
-+ <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>
-+
- </chapter>
-
- <chapter id="security">
-diff -urN mutt-1.6.1/doc/muttrc.status-color mutt-1.6.1-status-color/doc/muttrc.status-color
---- mutt-1.6.1/doc/muttrc.status-color 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-status-color/doc/muttrc.status-color 2016-05-02 03:02:13.731192609 +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).
-+
-+# 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
-+
-+# '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
-+color status blue white
-+
-+# 1 extra parameter
-+# Set the color for a matching pattern
-+# color status foreground background regexp
-+
-+# Highlight New, Deleted, or Flagged emails
-+color status brightred white '(New|Del|Flag):[0-9]+'
-+
-+# Highlight mailbox ordering if it's different from the default
-+# First, highlight anything (*/*)
-+color status brightred default '\([^)]+/[^)]+\)'
-+
-+# Then override the color for one specfic case
-+color status default default '\(threads/last-date-received\)'
-+
-+# 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
-+color status red default '\[([^]]+)\]' 1
-+
-+# The '1' refers to the first regex submatch, which is the inner
-+# part in ()s
-+
-+# Highlight the mailbox
-+color status brightwhite default 'Mutt: ([^ ]+)' 1
-+
-+# Search for 'Mutt: ' but only highlight what comes after it
-+
-+# vim: syntax=muttrc
-diff -urN mutt-1.6.1/mutt_curses.h mutt-1.6.1-status-color/mutt_curses.h
---- mutt-1.6.1/mutt_curses.h 2016-05-02 03:02:12.409171576 +0100
-+++ mutt-1.6.1-status-color/mutt_curses.h 2016-05-02 03:02:13.837194296 +0100
-@@ -130,6 +130,7 @@
- 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 */
-@@ -176,6 +177,7 @@
- extern int ColorDefs[];
- extern COLOR_LINE *ColorHdrList;
- extern COLOR_LINE *ColorBodyList;
-+extern COLOR_LINE *ColorStatusList;
- extern COLOR_LINE *ColorIndexList;
-
- void ci_init_color (void);
-diff -urN mutt-1.6.1/pager.c mutt-1.6.1-status-color/pager.c
---- mutt-1.6.1/pager.c 2016-05-02 03:02:12.411171608 +0100
-+++ mutt-1.6.1-status-color/pager.c 2016-05-02 03:02:13.838194312 +0100
-@@ -1804,13 +1804,13 @@
- 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 (COLS, buffer);
- }
- else
- {
- char bn[STRING];
- snprintf (bn, sizeof (bn), "%s (%s)", banner, pager_progress_str);
-- mutt_paddstr (COLS, bn);
-+ mutt_draw_statusline (COLS, bn);
- }
- NORMAL_COLOR;
- if (option(OPTTSENABLED) && TSSupported)
-diff -urN mutt-1.6.1/PATCHES mutt-1.6.1-status-color/PATCHES
---- mutt-1.6.1/PATCHES 2016-05-02 03:02:12.396171369 +0100
-+++ mutt-1.6.1-status-color/PATCHES 2016-05-02 03:02:13.824194089 +0100
-@@ -0,0 +1 @@
-+patch-status-color-neo-20160502
-diff -urN mutt-1.6.1/protos.h mutt-1.6.1-status-color/protos.h
---- mutt-1.6.1/protos.h 2016-05-02 03:02:12.411171608 +0100
-+++ mutt-1.6.1-status-color/protos.h 2016-05-02 03:02:13.839194328 +0100
-@@ -180,6 +180,7 @@
- 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);
-diff -urN mutt-1.6.1/README.status-color mutt-1.6.1-status-color/README.status-color
---- mutt-1.6.1/README.status-color 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-status-color/README.status-color 2016-05-02 03:02:13.824194089 +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.5.24
-+
-+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 --git a/debian/patches/neomutt/05-index-color.patch b/debian/patches/neomutt/05-index-color.patch
deleted file mode 100644
index ef12e9c..0000000
--- a/debian/patches/neomutt/05-index-color.patch
+++ /dev/null
@@ -1,1119 +0,0 @@
-diff -urN mutt-1.6.1/color.c mutt-1.6.1-index-color/color.c
---- mutt-1.6.1/color.c 2016-05-02 03:02:12.397171385 +0100
-+++ mutt-1.6.1-index-color/color.c 2016-05-02 03:02:14.026197303 +0100
-@@ -35,6 +35,9 @@
- COLOR_LINE *ColorHdrList = NULL;
- COLOR_LINE *ColorBodyList = NULL;
- COLOR_LINE *ColorIndexList = NULL;
-+COLOR_LINE *ColorIndexAuthorList = NULL;
-+COLOR_LINE *ColorIndexFlagsList = NULL;
-+COLOR_LINE *ColorIndexSubjectList = NULL;
-
- /* local to this file */
- static int ColorQuoteSize;
-@@ -93,6 +96,14 @@
- { "bold", MT_COLOR_BOLD },
- { "underline", MT_COLOR_UNDERLINE },
- { "index", MT_COLOR_INDEX },
-+ { "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 },
- { "prompt", MT_COLOR_PROMPT },
- { NULL, 0 }
- };
-@@ -384,12 +395,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;
-+
-+ 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;
-
- mutt_extract_token (buf, s, 0);
-
-@@ -399,13 +450,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;
-+ }
-+
-+ 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 +495,18 @@
- 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);
-
- if (do_cache && !option (OPTNOCURSES))
- {
-@@ -718,12 +746,15 @@
-
- /* 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)) {
-+ if (!MoreArgs (s)) {
- strfcpy (err->data, _("too few arguments"), err->dsize);
-- return (-1);
-+ return -1;
- }
-
- mutt_extract_token (buf, s, 0);
-@@ -761,6 +792,15 @@
- {
- r = add_pattern (&ColorIndexList, buf->data, 1, fg, bg, attr, err, 1);
- set_option (OPTFORCEREDRAWINDEX);
-+ } else if (object == MT_COLOR_INDEX_AUTHOR) {
-+ r = add_pattern (&ColorIndexAuthorList, buf->data, 1, fg, bg, attr, err, 1);
-+ set_option (OPTFORCEREDRAWINDEX);
-+ } else if (object == MT_COLOR_INDEX_FLAGS) {
-+ r = add_pattern (&ColorIndexFlagsList, buf->data, 1, fg, bg, attr, err, 1);
-+ set_option (OPTFORCEREDRAWINDEX);
-+ } else if (object == MT_COLOR_INDEX_SUBJECT) {
-+ r = add_pattern (&ColorIndexSubjectList, buf->data, 1, fg, bg, attr, err, 1);
-+ set_option (OPTFORCEREDRAWINDEX);
- }
- else if (object == MT_COLOR_QUOTED)
- {
-@@ -787,7 +827,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/curs_lib.c mutt-1.6.1-index-color/curs_lib.c
---- mutt-1.6.1/curs_lib.c 2016-05-02 03:02:12.399171417 +0100
-+++ mutt-1.6.1-index-color/curs_lib.c 2016-05-02 03:02:14.027197319 +0100
-@@ -779,6 +779,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 +795,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 +1040,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;
-+ }
-+
- if (k == (size_t)(-1) || k == (size_t)(-2))
- {
- k = (k == (size_t)(-1)) ? 1 : n;
-diff -urN mutt-1.6.1/doc/manual.xml.head mutt-1.6.1-index-color/doc/manual.xml.head
---- mutt-1.6.1/doc/manual.xml.head 2016-05-02 03:02:12.402171465 +0100
-+++ mutt-1.6.1-index-color/doc/manual.xml.head 2016-05-02 03:02:14.030197366 +0100
-@@ -2642,7 +2642,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 +2657,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 +2687,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,6 +2702,14 @@
- <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>
-@@ -2717,6 +2725,24 @@
- </itemizedlist>
-
- <para>
-+<emphasis>index-object</emphasis> can be one of the following:
-+</para>
-+
-+<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>
-+
-+<para>
- <emphasis>foreground</emphasis> and <emphasis>background</emphasis> can
- be one of the following:
- </para>
-@@ -2833,7 +2859,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>
-@@ -8081,6 +8107,232 @@
-
- </sect1>
-
-+<sect1 id="index-color">
-+ <title>Index Color Patch</title>
-+ <subtitle>Custom rules for theming the email index</subtitle>
-+
-+ <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>
-+
-+ <itemizedlist>
-+ <title>Dependencies:</title>
-+ <listitem><para>mutt-1.5.24</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>
-+
- </chapter>
-
- <chapter id="security">
-diff -urN mutt-1.6.1/doc/muttrc.index-color mutt-1.6.1-index-color/doc/muttrc.index-color
---- mutt-1.6.1/doc/muttrc.index-color 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-index-color/doc/muttrc.index-color 2016-05-02 03:02:13.937195887 +0100
-@@ -0,0 +1,37 @@
-+# Example Mutt config file for the 'index-color' feature.
-+
-+# Entire index line
-+color index white black '.*'
-+
-+# Author name, %A %a %F %L %n
-+
-+# Give the author column a dark grey background
-+color index_author default color234 '.*'
-+
-+# Highlight a particular from (~f)
-+color index_author brightyellow color234 '~fRay Charles'
-+
-+# Message flags, %S %Z
-+# Highlight the flags for flagged (~F) emails
-+color index_flags default red '~F'
-+
-+# Subject, %s
-+# Look for a particular subject (~s)
-+color index_subject brightcyan default '~s\(closes #[0-9]+\)'
-+
-+# Number of messages in a collapsed thread, %M
-+color index_collapsed default brightblue
-+
-+# Date field
-+color index_date green default
-+
-+# Message label, %y %Y
-+color index_label default brightgreen
-+
-+# Message number, %C
-+color index_number red default
-+
-+# Message size, %c %l
-+color index_size cyan default
-+
-+# vim: syntax=muttrc
-diff -urN mutt-1.6.1/doc/vimrc.index-color mutt-1.6.1-index-color/doc/vimrc.index-color
---- mutt-1.6.1/doc/vimrc.index-color 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-index-color/doc/vimrc.index-color 2016-05-02 03:02:13.938195903 +0100
-@@ -0,0 +1,13 @@
-+" Vim syntax file for the mutt index-color patch
-+
-+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
-+
-+" vim: syntax=vim
-diff -urN mutt-1.6.1/hdrline.c mutt-1.6.1-index-color/hdrline.c
---- mutt-1.6.1/hdrline.c 2016-05-02 03:02:12.403171480 +0100
-+++ mutt-1.6.1-index-color/hdrline.c 2016-05-02 03:02:14.031197382 +0100
-@@ -103,6 +103,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;
-+
-+ /* only add color markers if we are operating on main index entries. */
-+ if (!(flags & M_FORMAT_INDEX))
-+ return 0;
-+
-+ if (color == MT_COLOR_INDEX) { /* buf might be uninitialized other cases */
-+ len = mutt_strlen (buf);
-+ buf += len;
-+ buflen -= len;
-+ }
-+
-+ if (buflen < 2)
-+ return 0;
-+
-+ buf[0] = M_SPECIAL_INDEX;
-+ buf[1] = color;
-+ buf[2] = '\0';
-+
-+ return 2;
-+}
-+
- static void make_from (ENVELOPE *hdr, char *buf, size_t len, int do_lists)
- {
- int me;
-@@ -255,6 +287,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 +298,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 +308,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 +343,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;
-
- 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;
-
-@@ -410,7 +451,10 @@
- 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);
-+
- if (len > 0 && op != 'd' && op != 'D') /* Skip ending op */
- src = cp + 1;
- }
-@@ -440,8 +484,10 @@
- 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;
-@@ -467,7 +513,9 @@
- 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 +524,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 +547,9 @@
- break;
-
- 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 +584,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 +629,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;
-
- case 'S':
-@@ -603,8 +665,11 @@
-
- /* 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':
-@@ -676,7 +741,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;
-
- case 'X':
-@@ -696,7 +763,9 @@
- if (optional)
- optional = hdr->env->x_label ? 1 : 0;
-
-- 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, NONULL (hdr->env->x_label));
-+ add_index_color (dest + colorlen, destlen - colorlen, flags, MT_COLOR_INDEX);
- break;
-
- case 'Y':
-@@ -722,10 +791,12 @@
- if (optional)
- optional = i;
-
-+ colorlen = add_index_color (dest, destlen, flags, MT_COLOR_INDEX_LABEL);
- if (i)
-- mutt_format_s (dest, destlen, prefix, NONULL (hdr->env->x_label));
-+ mutt_format_s (dest + colorlen, destlen - colorlen, prefix, NONULL (hdr->env->x_label));
- else
-- mutt_format_s (dest, destlen, prefix, "");
-+ mutt_format_s (dest + colorlen, destlen - colorlen, prefix, "");
-+ add_index_color (dest + colorlen, destlen - colorlen, flags, MT_COLOR_INDEX);
-
- break;
-
-diff -urN mutt-1.6.1/menu.c mutt-1.6.1-index-color/menu.c
---- mutt-1.6.1/menu.c 2016-05-02 03:02:12.408171560 +0100
-+++ mutt-1.6.1-index-color/menu.c 2016-05-02 03:02:14.035197446 +0100
-@@ -27,7 +27,39 @@
-
- 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;
-+
-+ 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;
-+ default:
-+ return ColorDefs[type];
-+ }
-+
-+ for (; color; color = color->next)
-+ if (mutt_pattern_exec (color->color_pattern, M_MATCH_FULL_ADDRESS,
-+ Context, hdr))
-+ return color->pair;
-+
-+ return 0;
-+}
-+
-+static void print_enriched_string (int index, int attr, unsigned char *s, int do_color)
- {
- wchar_t wc;
- size_t k;
-@@ -159,6 +191,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);
-@@ -265,7 +313,7 @@
- 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
- {
-@@ -300,7 +348,7 @@
- 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);
-+ print_enriched_string (menu->oldcurrent, menu->color (menu->oldcurrent), (unsigned char *) buf, 1);
- }
-
- /* now draw it in the new location */
-@@ -312,14 +360,14 @@
- /* 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);
-+ print_enriched_string (menu->current, menu->color (menu->current), (unsigned char *) buf, 0);
- }
- menu->redraw &= REDRAW_STATUS;
- NORMAL_COLOR;
-@@ -341,10 +389,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;
- }
-diff -urN mutt-1.6.1/mutt_curses.h mutt-1.6.1-index-color/mutt_curses.h
---- mutt-1.6.1/mutt_curses.h 2016-05-02 03:02:12.409171576 +0100
-+++ mutt-1.6.1-index-color/mutt_curses.h 2016-05-02 03:02:14.036197462 +0100
-@@ -122,8 +122,18 @@
- MT_COLOR_SEARCH,
- MT_COLOR_BOLD,
- MT_COLOR_UNDERLINE,
-- MT_COLOR_INDEX,
- MT_COLOR_PROMPT,
-+ /* please no non-MT_COLOR_INDEX objects after this point */
-+ 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,
- MT_COLOR_MAX
- };
-
-@@ -177,6 +187,9 @@
- extern COLOR_LINE *ColorHdrList;
- extern COLOR_LINE *ColorBodyList;
- extern COLOR_LINE *ColorIndexList;
-+extern COLOR_LINE *ColorIndexAuthorList;
-+extern COLOR_LINE *ColorIndexFlagsList;
-+extern COLOR_LINE *ColorIndexSubjectList;
-
- void ci_init_color (void);
- void ci_start_color (void);
-diff -urN mutt-1.6.1/mutt.h mutt-1.6.1-index-color/mutt.h
---- mutt-1.6.1/mutt.h 2016-05-02 03:02:12.409171576 +0100
-+++ mutt-1.6.1-index-color/mutt.h 2016-05-02 03:02:14.036197462 +0100
-@@ -158,6 +158,8 @@
- #define M_TREE_MISSING 13
- #define M_TREE_MAX 14
-
-+#define M_SPECIAL_INDEX M_TREE_MAX
-+
- #define M_THREAD_COLLAPSE (1<<0)
- #define M_THREAD_UNCOLLAPSE (1<<1)
- #define M_THREAD_GET_HIDDEN (1<<2)
-diff -urN mutt-1.6.1/PATCHES mutt-1.6.1-index-color/PATCHES
---- mutt-1.6.1/PATCHES 2016-05-02 03:02:12.396171369 +0100
-+++ mutt-1.6.1-index-color/PATCHES 2016-05-02 03:02:14.024197271 +0100
-@@ -0,0 +1 @@
-+patch-index-color-neo-20160502
-diff -urN mutt-1.6.1/README.index-color mutt-1.6.1-index-color/README.index-color
---- mutt-1.6.1/README.index-color 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-index-color/README.index-color 2016-05-02 03:02:14.024197271 +0100
-@@ -0,0 +1,82 @@
-+Index Color Patch
-+=================
-+
-+ Custom rules for theming the email index
-+
-+Patch
-+-----
-+
-+ To check if Mutt supports "Index Color", look for "patch-index-color" in
-+ the mutt version.
-+
-+ Dependencies
-+ * mutt-1.5.24
-+ * status-color patch
-+
-+Introduction
-+------------
-+
-+ The "index-color" patch allows you to specify colors for individual parts
-+ of the email index. e.g. Subject, Author, Flags.
-+
-+ First choose which part of the index you'd like to color. Then, if needed,
-+ pick a pattern to match.
-+
-+ Note: The pattern does not have to refer to the object you wish to color.
-+ e.g.
-+
-+ color index_author red default "~smutt"
-+
-+ The author appears red when the subject (~s) contains "mutt".
-+
-+Colors
-+------
-+
-+ All the colors default to 'default', i.e. unset.
-+
-+ The index objects can be themed using the 'color' command. Some objects
-+ require a pattern.
-+
-+ color index-object foreground background
-+ color index-object foreground background pattern
-+
-+ Index Colors
-+
-+ | 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 |
-+
-+See Also
-+--------
-+
-+ * NeoMutt project
-+ * Regular Expressions
-+ * Patterns
-+ * $index_format
-+ * Color command
-+ * Status-Color patch
-+ * Keywords patch
-+
-+Known Bugs
-+----------
-+
-+ None
-+
-+Credits
-+-------
-+
-+ * 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>
-+
diff --git a/debian/patches/neomutt/06-nested-if.patch b/debian/patches/neomutt/06-nested-if.patch
deleted file mode 100644
index 4e5e03a..0000000
--- a/debian/patches/neomutt/06-nested-if.patch
+++ /dev/null
@@ -1,500 +0,0 @@
-diff -urN mutt-1.6.1/doc/manual.xml.head mutt-1.6.1-nested-if/doc/manual.xml.head
---- mutt-1.6.1/doc/manual.xml.head 2016-05-02 03:02:12.402171465 +0100
-+++ mutt-1.6.1-nested-if/doc/manual.xml.head 2016-05-02 03:02:14.216200326 +0100
-@@ -4595,6 +4595,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>
-+
-+<screen>
-+%<x?true&false>
-+%<x?%<y?%<z?xyz&xy>&x>&none>
-+</screen>
-+
-+<para>For more examples, see <xref linkend="nested-if"/></para>
-+
- </sect2>
-
- <sect2 id="formatstrings-filters">
-@@ -8081,6 +8093,222 @@
-
- </sect1>
-
-+<sect1 id="nested-if">
-+ <title>Nested If Patch</title>
-+ <subtitle>Allow complex nested conditions in format strings</subtitle>
-+
-+ <sect2 id="nested-if-patch">
-+ <title>Patch</title>
-+
-+ <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>
-+
-+ <itemizedlist>
-+ <title>Dependencies:</title>
-+ <listitem><para>mutt-1.5.24</para></listitem>
-+ </itemizedlist>
-+
-+ <para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
-+ </sect2>
-+
-+ <sect2 id="nested-if-intro">
-+ <title>Introduction</title>
-+
-+ <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>
-+
-+ <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>
-+
-+<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>
-+
-+<screen>
-+set index_format='%4C %Z %{%b %d} %-25.25n %<M?[%M] %s&%s%* %<l?%l&%c>>'
-+</screen>
-+
-+ <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>
-+
-+ </sect2>
-+
-+ <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>
-+
-+<!--
-+ <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>
-+-->
-+
-+ <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>
-+
- </chapter>
-
- <chapter id="security">
-diff -urN mutt-1.6.1/doc/muttrc.nested-if mutt-1.6.1-nested-if/doc/muttrc.nested-if
---- mutt-1.6.1/doc/muttrc.nested-if 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-nested-if/doc/muttrc.nested-if 2016-05-02 03:02:14.117198751 +0100
-@@ -0,0 +1,24 @@
-+# 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)
-+set index_format='%4C %Z %{%b %d} %-25.25n %s%> %<M?%M Msgs &%<l?%l Lines&%c Bytes>>'
-+
-+# 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>>'
-+
-+# vim: syntax=muttrc
-diff -urN mutt-1.6.1/muttlib.c mutt-1.6.1-nested-if/muttlib.c
---- mutt-1.6.1/muttlib.c 2016-05-02 03:02:12.410171592 +0100
-+++ mutt-1.6.1-nested-if/muttlib.c 2016-05-02 03:02:14.226200485 +0100
-@@ -1213,6 +1213,24 @@
-
- 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 = '>';
-+ }
-+ }
-+
-+ if (*src == '<')
-+ {
- flags |= M_FORMAT_OPTIONAL;
- src++;
- }
-@@ -1239,6 +1257,8 @@
-
- if (flags & M_FORMAT_OPTIONAL)
- {
-+ int lrbalance;
-+
- if (*src != '?')
- break; /* bad format */
- src++;
-@@ -1246,8 +1266,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 +1290,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 +1311,7 @@
- if (!*src)
- break; /* bad format */
-
-- src++; /* move past the trailing `?' */
-+ src++; /* move past the trailing `>' (formerly '?') */
- }
-
- /* handle generic cases first */
-diff -urN mutt-1.6.1/PATCHES mutt-1.6.1-nested-if/PATCHES
---- mutt-1.6.1/PATCHES 2016-05-02 03:02:12.396171369 +0100
-+++ mutt-1.6.1-nested-if/PATCHES 2016-05-02 03:02:14.208200199 +0100
-@@ -0,0 +1 @@
-+patch-nested-if-neo-20160502
-diff -urN mutt-1.6.1/README.nested-if mutt-1.6.1-nested-if/README.nested-if
---- mutt-1.6.1/README.nested-if 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-nested-if/README.nested-if 2016-05-02 03:02:14.208200199 +0100
-@@ -0,0 +1,125 @@
-+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.5.24
-+
-+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"
-+ }
-+
-+
-+ 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'
-+ }
-+ }
-+
-+
-+ Examples:
-+
-+ set index_format='%4C %Z %{%b %d} %-25.25n %s%> %<M?%M Msgs &%<l?%l Lines&%c Bytes>>'
-+
-+ 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 %<M?[%M] %s&%s%* %<l?%l&%c>>'
-+
-+ 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)
-+
-+
-+Variables
-+---------
-+
-+ The nested-if patch doesn't have any config of its own. It modifies the behavior of the
-+ format strings.
-+
-+See Also
-+--------
-+
-+ * NeoMutt project
-+ * cond-date patch
-+ * $index_format
-+ * $status_format
-+
-+Known Bugs
-+----------
-+
-+ Patch overwrites $<fmt> handler in
-+ $index_format
-+
-+Credits
-+-------
-+
-+ * David Champion <dgc at uchicago.edu>
-+ * Richard Russon <rich at flatcap.org>
-+
diff --git a/debian/patches/neomutt/07-cond-date.patch b/debian/patches/neomutt/07-cond-date.patch
deleted file mode 100644
index fc571e1..0000000
--- a/debian/patches/neomutt/07-cond-date.patch
+++ /dev/null
@@ -1,789 +0,0 @@
-diff -urN mutt-1.6.1/doc/manual.xml.head mutt-1.6.1-cond-date/doc/manual.xml.head
---- mutt-1.6.1/doc/manual.xml.head 2016-05-02 03:02:12.402171465 +0100
-+++ mutt-1.6.1-cond-date/doc/manual.xml.head 2016-05-02 03:02:14.642207104 +0100
-@@ -4701,6 +4701,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>
-+
-+<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>
-
- <sect1 id="mailto-allow">
-@@ -8081,6 +8102,413 @@
-
- </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.5.24</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>
-+
- </chapter>
-
- <chapter id="security">
-diff -urN mutt-1.6.1/doc/muttrc.cond-date mutt-1.6.1-cond-date/doc/muttrc.cond-date
---- mutt-1.6.1/doc/muttrc.cond-date 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-cond-date/doc/muttrc.cond-date 2016-05-02 03:02:14.535205401 +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'
-+
-+# 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
-diff -urN mutt-1.6.1/hdrline.c mutt-1.6.1-cond-date/hdrline.c
---- mutt-1.6.1/hdrline.c 2016-05-02 03:02:12.403171480 +0100
-+++ mutt-1.6.1-cond-date/hdrline.c 2016-05-02 03:02:14.643207119 +0100
-@@ -327,6 +327,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;
-+
-+ if (((T > i) || (T < (-1*i))) ^ invert)
-+ optional = 0;
-+ break;
-+ }
-
- p = dest;
-
-diff -urN mutt-1.6.1/init.h mutt-1.6.1-cond-date/init.h
---- mutt-1.6.1/init.h 2016-05-02 03:02:12.407171544 +0100
-+++ mutt-1.6.1-cond-date/init.h 2016-05-02 03:02:14.646207167 +0100
-@@ -1361,6 +1361,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,
-diff -urN mutt-1.6.1/muttlib.c mutt-1.6.1-cond-date/muttlib.c
---- mutt-1.6.1/muttlib.c 2016-05-02 03:02:12.410171592 +0100
-+++ mutt-1.6.1-cond-date/muttlib.c 2016-05-02 03:02:14.649207215 +0100
-@@ -1214,7 +1214,15 @@
- 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,12 +1238,12 @@
- 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)
- {
-diff -urN mutt-1.6.1/PATCHES mutt-1.6.1-cond-date/PATCHES
---- mutt-1.6.1/PATCHES 2016-05-02 03:02:12.396171369 +0100
-+++ mutt-1.6.1-cond-date/PATCHES 2016-05-02 03:02:14.636207008 +0100
-@@ -0,0 +1 @@
-+patch-cond-date-neo-20160502
-diff -urN mutt-1.6.1/README.cond-date mutt-1.6.1-cond-date/README.cond-date
---- mutt-1.6.1/README.cond-date 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-cond-date/README.cond-date 2016-05-02 03:02:14.637207024 +0100
-@@ -0,0 +1,163 @@
-+Conditional Dates Patch
-+=======================
-+
-+ Use rules to choose date format
-+
-+Patch
-+-----
-+
-+ To check if Mutt supports "Conditional Dates", look for "patch-cond-date"
-+ in the mutt version.
-+
-+ Dependencies
-+ * mutt-1.5.24
-+ * nested-if patch
-+
-+Introduction
-+------------
-+
-+ The "cond-date" patch allows you to construct $index_format expressions
-+ based on the age of the email.
-+
-+ Mutt's default '$index_format' displays email dates in the form:
-+ abbreviated-month day-of-month — "Jan 14".
-+
-+ The format is configurable but only per-mailbox. This patch allows you to
-+ configure the display depending on the age of the email.
-+
-+ Potential Formatting Scheme
-+
-+ | 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 |
-+
-+ For an explanation of the date formatting strings, see 'strftime(3).'
-+
-+ By carefully picking your formats, the dates can remain unambiguous and
-+ compact.
-+
-+ Mutt's conditional format strings have the form: (whitespace introduced for
-+ clarity)
-+
-+ %? TEST ? TRUE & FALSE ?
-+
-+ 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.
-+
-+ The date tests are of the form:
-+
-+ %[nX? TRUE & FALSE ?
-+
-+ * "n" is an optional count (defaults to 1 if missing)
-+ * "X" is the time period
-+
-+ Date Formatting Codes
-+
-+ | Letter | Time Period |
-+ |--------|-------------|
-+ | y | Years |
-+ | m | Months |
-+ | w | Weeks |
-+ | d | Days |
-+ | H | Hours |
-+ | M | Minutes |
-+
-+ Date Tests
-+
-+ | 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 |
-+
-+### Example 1
-+
-+ We start with a one-condition test.
-+
-+ Example 1
-+
-+ | Test | Date Range | Format String | Example |
-+ |--------|------------|---------------|------------|
-+ | '%[1m' | This month | '%[%b %d]' | Dec 10 |
-+ | | Older | '%[%Y-%m-%d]' | 2015-04-23 |
-+
-+ The $index_format string would contain:
-+
-+ %?[1m?%[%b %d]&%[%Y-%m-%d]?
-+
-+ Reparsed a little, for clarity, you can see the test condition and the two
-+ format strings.
-+
-+ %?[1m? & ?
-+ %[%b %d] %[%Y-%m-%d]
-+
-+### Example 2
-+
-+ This example contains three test conditions and four date formats.
-+
-+ Example 2
-+
-+ | 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 |
-+
-+ The $index_format string would contain:
-+
-+ %<[y?%<[m?%<[d?%[%H:%M ]&%[%a %d]>&%[%b %d]>&%[%m/%y ]>
-+
-+ Reparsed a little, for clarity, you can see the test conditions and the
-+ four format strings.
-+
-+ %<[y? &%[%m/%y ]> Older
-+ %<[m? &%[%b %d]> This year
-+ %<[d? &%[%a %d]> This month
-+ %[%H:%M ] Today
-+
-+ This a another view of the same example, with some whitespace for clarity.
-+
-+ %<[y? %<[m? %<[d? AAA & BBB > & CCC > & DDD >
-+
-+ AAA = %[%H:%M ]
-+ BBB = %[%a %d]
-+ CCC = %[%b %d]
-+ DDD = %[%m/%y ]
-+
-+
-+Variables
-+---------
-+
-+ The "cond-date" patch doesn't have any config of its own. It modifies the
-+ behavior of the format strings.
-+
-+See Also
-+--------
-+
-+ * NeoMutt project
-+ * $index_format
-+ * nested-if patch
-+ * 'strftime(3)'
-+
-+Known Bugs
-+----------
-+
-+ 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.
-+
-+Credits
-+-------
-+
-+ * Aaron Schrab <aaron at schrab.com>
-+ * Eric Davis <edavis at insanum.com>
-+ * Richard Russon <rich at flatcap.org>
-+
diff --git a/debian/patches/neomutt/08-tls-sni.patch b/debian/patches/neomutt/08-tls-sni.patch
deleted file mode 100644
index 7af477f..0000000
--- a/debian/patches/neomutt/08-tls-sni.patch
+++ /dev/null
@@ -1,242 +0,0 @@
-diff -urN mutt-1.6.1/doc/manual.xml.head mutt-1.6.1-tls-sni/doc/manual.xml.head
---- mutt-1.6.1/doc/manual.xml.head 2016-05-02 03:02:12.402171465 +0100
-+++ mutt-1.6.1-tls-sni/doc/manual.xml.head 2016-05-02 03:02:14.848210381 +0100
-@@ -8081,6 +8081,113 @@
-
- </sect1>
-
-+<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.5.24</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>
-+
-+ <para>
-+ To verify TLS SNI support by a server, you can use:
-+ </para>
-+
-+<screen>
-+openssl s_client -host <imap server> -port <port> -tls1 -servername <imap server>
-+</screen>
-+ </sect2>
-+
-+<!--
-+ <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>
-+-->
-+
-+ <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>
-+
- </chapter>
-
- <chapter id="security">
-diff -urN mutt-1.6.1/mutt_ssl.c mutt-1.6.1-tls-sni/mutt_ssl.c
---- mutt-1.6.1/mutt_ssl.c 2016-05-02 03:02:12.409171576 +0100
-+++ mutt-1.6.1-tls-sni/mutt_ssl.c 2016-05-02 03:02:14.856210508 +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))
-diff -urN mutt-1.6.1/PATCHES mutt-1.6.1-tls-sni/PATCHES
---- mutt-1.6.1/PATCHES 2016-05-02 03:02:12.396171369 +0100
-+++ mutt-1.6.1-tls-sni/PATCHES 2016-05-02 03:02:14.843210302 +0100
-@@ -0,0 +1 @@
-+patch-tls-sni-neo-20160502
-diff -urN mutt-1.6.1/README.SSL mutt-1.6.1-tls-sni/README.SSL
---- mutt-1.6.1/README.SSL 2016-05-02 03:02:12.396171369 +0100
-+++ mutt-1.6.1-tls-sni/README.SSL 2016-05-02 03:02:14.720208345 +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.
-
- 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.
-
-+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.
-
-+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
-
--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.tls-sni mutt-1.6.1-tls-sni/README.tls-sni
---- mutt-1.6.1/README.tls-sni 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-tls-sni/README.tls-sni 2016-05-02 03:02:14.843210302 +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.5.24
-+ * 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
-+--------
-+
-+ * NeoMutt project
-+
-+Known Bugs
-+----------
-+
-+ None
-+
-+Credits
-+-------
-+
-+ * Jeremy Katz <katzj at linuxpower.org>
-+ * Phil Pennock <mutt-dev at spodhuis.demon.nl>
-+ * Richard Russon <rich at flatcap.org>
-+
diff --git a/debian/patches/neomutt/09-sidebar.patch b/debian/patches/neomutt/09-sidebar.patch
deleted file mode 100644
index cf1a4ee..0000000
--- a/debian/patches/neomutt/09-sidebar.patch
+++ /dev/null
@@ -1,4317 +0,0 @@
-diff -urN mutt-1.6.1/buffy.c mutt-1.6.1-sidebar/buffy.c
---- mutt-1.6.1/buffy.c 2016-05-02 03:02:12.397171385 +0100
-+++ mutt-1.6.1-sidebar/buffy.c 2016-05-02 03:02:15.009212943 +0100
-@@ -27,6 +27,10 @@
-
- #include "mutt_curses.h"
-
-+#ifdef USE_SIDEBAR
-+#include "sidebar.h"
-+#endif
-+
- #ifdef USE_IMAP
- #include "imap.h"
- #endif
-@@ -196,9 +200,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;
-
-@@ -215,7 +227,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 +243,9 @@
- for (tmp = &Incoming; *tmp;)
- {
- tmp1=(*tmp)->next;
-+#ifdef USE_SIDEBAR
-+ sb_notify_mailbox (*tmp, 0);
-+#endif
- buffy_free (tmp);
- *tmp=tmp1;
- }
-@@ -243,8 +261,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 +279,21 @@
- if(*tmp)
- {
- tmp1=(*tmp)->next;
-+#ifdef USE_SIDEBAR
-+ sb_notify_mailbox (*tmp, 0);
-+#endif
- buffy_free (tmp);
- *tmp=tmp1;
- }
- continue;
- }
-
-- if (!*tmp)
-+ if (!*tmp) {
- *tmp = buffy_new (buf);
-+#ifdef USE_SIDEBAR
-+ sb_notify_mailbox (*tmp, 1);
-+#endif
-+ }
-
- (*tmp)->new = 0;
- (*tmp)->notified = 1;
-@@ -306,6 +336,13 @@
- return 0;
- }
-
-+#ifdef USE_SIDEBAR
-+ if (option (OPTSIDEBAR) && mailbox->msg_unread > 0) {
-+ mailbox->new = 1;
-+ return 1;
-+ }
-+#endif
-+
- if ((dirp = opendir (path)) == NULL)
- {
- mailbox->magic = 0;
-@@ -357,6 +394,89 @@
-
- return 0;
- }
-+
-+#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;
-+
-+ snprintf (path, sizeof (path), "%s/%s", mailbox->path, dir);
-+
-+ dirp = opendir (path);
-+ if (!dirp) {
-+ mailbox->magic = 0;
-+ return;
-+ }
-+
-+ while ((de = readdir (dirp)) != NULL) {
-+ if (*de->d_name == '.')
-+ continue;
-+
-+ /* 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++;
-+ }
-+ }
-+
-+ closedir (dirp);
-+}
-+
-+/**
-+ * 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;
-+
-+ mailbox->msg_count = 0;
-+ mailbox->msg_unread = 0;
-+ mailbox->msg_flagged = 0;
-+
-+ buffy_maildir_update_dir (mailbox, "new");
-+ if (mailbox->msg_count) {
-+ mailbox->new = 1;
-+ }
-+ buffy_maildir_update_dir (mailbox, "cur");
-+
-+ mailbox->sb_last_checked = time (NULL);
-+
-+ /* make sure the updates are actually put on screen */
-+ sb_draw();
-+}
-+
-+#endif
-+
- /* returns 1 if mailbox has new mail */
- static int buffy_mbox_hasnew (BUFFY* mailbox, struct stat *sb)
- {
-@@ -368,7 +488,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,6 +512,40 @@
- return rc;
- }
-
-+#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)
-+{
-+ CONTEXT *ctx = NULL;
-+
-+ if (!option (OPTSIDEBAR))
-+ return;
-+ if ((mailbox->sb_last_checked > sb->st_mtime) && (mailbox->msg_count != 0))
-+ return; /* no check necessary */
-+
-+ 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);
-+ }
-+
-+ /* make sure the updates are actually put on screen */
-+ sb_draw();
-+}
-+#endif
-+
- int mutt_buffy_check (int force)
- {
- BUFFY *tmp;
-@@ -428,6 +586,9 @@
- contex_sb.st_ino=0;
- }
-
-+#ifdef USE_SIDEBAR
-+ int should_refresh = sb_should_refresh();
-+#endif
- for (tmp = Incoming; tmp; tmp = tmp->next)
- {
- if (tmp->magic != M_IMAP)
-@@ -461,16 +622,30 @@
- {
- case M_MBOX:
- case M_MMDF:
-+#ifdef USE_SIDEBAR
-+ if (should_refresh)
-+ buffy_mbox_update (tmp, &sb);
-+#endif
- if (buffy_mbox_hasnew (tmp, &sb) > 0)
- BuffyCount++;
- break;
-
- case M_MAILDIR:
-+#ifdef USE_SIDEBAR
-+ if (should_refresh)
-+ buffy_maildir_update (tmp);
-+#endif
- if (buffy_maildir_hasnew (tmp) > 0)
- BuffyCount++;
- break;
-
- case M_MH:
-+#ifdef USE_SIDEBAR
-+ if (sb_should_refresh()) {
-+ mh_buffy_update (tmp);
-+ sb_set_update_time();
-+ }
-+#endif
- mh_buffy(tmp);
- if (tmp->new)
- BuffyCount++;
-@@ -485,6 +660,10 @@
- else if (!tmp->notified)
- BuffyNotify++;
- }
-+#ifdef USE_SIDEBAR
-+ if (should_refresh)
-+ sb_set_update_time();
-+#endif
-
- BuffyDoneTime = BuffyTime;
- return (BuffyCount);
-diff -urN mutt-1.6.1/buffy.h mutt-1.6.1-sidebar/buffy.h
---- mutt-1.6.1/buffy.h 2016-05-02 03:02:12.397171385 +0100
-+++ mutt-1.6.1-sidebar/buffy.h 2016-05-02 03:02:15.010212959 +0100
-@@ -16,6 +16,9 @@
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-+#ifndef _BUFFY_H
-+#define _BUFFY_H
-+
- /*parameter to mutt_parse_mailboxes*/
- #define M_MAILBOXES 1
- #define M_UNMAILBOXES 2
-@@ -23,13 +26,28 @@
- typedef struct buffy_t
- {
- char path[_POSIX_PATH_MAX];
-+#ifdef USE_SIDEBAR
-+ char realpath[_POSIX_PATH_MAX];
-+#endif
- off_t size;
- struct buffy_t *next;
-+#ifdef USE_SIDEBAR
-+ struct buffy_t *prev;
-+#endif
- short new; /* mailbox has new mail */
-+#ifdef USE_SIDEBAR
-+ 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 */
-+#endif
- 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;
-
-@@ -49,3 +67,5 @@
- void mutt_buffy_setnotified (const char *path);
-
- void mh_buffy (BUFFY *);
-+
-+#endif /* _BUFFY_H */
-diff -urN mutt-1.6.1/color.c mutt-1.6.1-sidebar/color.c
---- mutt-1.6.1/color.c 2016-05-02 03:02:12.397171385 +0100
-+++ mutt-1.6.1-sidebar/color.c 2016-05-02 03:02:15.010212959 +0100
-@@ -94,6 +94,14 @@
- { "underline", MT_COLOR_UNDERLINE },
- { "index", MT_COLOR_INDEX },
- { "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 +154,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;
-diff -urN mutt-1.6.1/compose.c mutt-1.6.1-sidebar/compose.c
---- mutt-1.6.1/compose.c 2016-05-02 03:02:12.398171401 +0100
-+++ mutt-1.6.1-sidebar/compose.c 2016-05-02 03:02:15.010212959 +0100
-@@ -32,6 +32,9 @@
- #include "mailbox.h"
- #include "sort.h"
- #include "charset.h"
-+#ifdef USE_SIDEBAR
-+#include "sidebar.h"
-+#endif
-
- #ifdef MIXMASTER
- #include "remailer.h"
-@@ -72,7 +75,7 @@
-
- #define HDR_XOFFSET 10
- #define TITLE_FMT "%10s" /* Used for Prompts, which are ASCII */
--#define W (COLS - HDR_XOFFSET)
-+#define W (COLS - HDR_XOFFSET - SidebarWidth)
-
- static const char * const Prompts[] =
- {
-@@ -110,7 +113,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,7 +148,7 @@
- addstr (_(" (OppEnc mode)"));
-
- clrtoeol ();
-- move (HDR_CRYPTINFO, 0);
-+ move (HDR_CRYPTINFO, SidebarWidth);
- clrtoeol ();
-
- if ((WithCrypto & APPLICATION_PGP)
-@@ -162,7 +165,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 +178,7 @@
- int c;
- char *t;
-
-- mvaddstr (HDR_MIX, 0, " Mix: ");
-+ mvprintw (HDR_MIX, SidebarWidth, TITLE_FMT, "Mix: ");
-
- if (!chain)
- {
-@@ -190,7 +193,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 +245,23 @@
-
- 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
-+ sb_draw();
-+#endif
- draw_envelope_addr (HDR_FROM, msg->env->from);
- 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]);
-+ 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 +272,7 @@
- #endif
-
- SETCOLOR (MT_COLOR_STATUS);
-- mvaddstr (HDR_ATTACH - 1, 0, _("-- Attachments"));
-+ mvaddstr (HDR_ATTACH - 1, SidebarWidth, _("-- Attachments"));
- clrtoeol ();
-
- NORMAL_COLOR;
-@@ -302,7 +308,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;
-@@ -564,7 +570,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 +588,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;
- }
-diff -urN mutt-1.6.1/configure.ac mutt-1.6.1-sidebar/configure.ac
---- mutt-1.6.1/configure.ac 2016-05-02 03:02:12.398171401 +0100
-+++ mutt-1.6.1-sidebar/configure.ac 2016-05-02 03:02:15.011212974 +0100
-@@ -175,6 +175,15 @@
- 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"
-+ need_sidebar="yes"
-+ fi
-+])
-+AM_CONDITIONAL(BUILD_SIDEBAR, test x$need_sidebar = xyes)
-+
- AC_ARG_WITH(mixmaster, AS_HELP_STRING([--with-mixmaster@<:@=PATH@:>@],[Include Mixmaster support]),
- [if test "$withval" != no
- then
-diff -urN mutt-1.6.1/copy.c mutt-1.6.1-sidebar/copy.c
---- mutt-1.6.1/copy.c 2016-05-02 03:02:12.398171401 +0100
-+++ mutt-1.6.1-sidebar/copy.c 2016-05-02 03:02:15.011212974 +0100
-@@ -288,7 +288,7 @@
- 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) - SidebarWidth, flags) == -1)
- {
- error = TRUE;
- break;
-diff -urN mutt-1.6.1/curs_main.c mutt-1.6.1-sidebar/curs_main.c
---- mutt-1.6.1/curs_main.c 2016-05-02 03:02:12.400171433 +0100
-+++ mutt-1.6.1-sidebar/curs_main.c 2016-05-02 03:02:15.012212990 +0100
-@@ -26,8 +26,13 @@
- #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
-@@ -595,21 +600,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
-+
- if (op != -1)
- mutt_curs_set (0);
-
- if (menu->redraw & REDRAW_FULL)
- {
- menu_redraw_full (menu);
-+#ifdef USE_SIDEBAR
-+ sb_draw();
-+#endif
- mutt_show_error ();
- }
-+#ifdef USE_SIDEBAR
-+ else if (menu->redraw & REDRAW_SIDEBAR) {
-+ sb_draw();
-+ menu->redraw &= ~REDRAW_SIDEBAR;
-+ }
-+#endif
-
- if (menu->menu == MENU_MAIN)
- {
-@@ -630,9 +653,20 @@
-
- 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);
-+#ifdef USE_SIDEBAR
-+ sb_set_buffystats (Context);
-+#endif
- mutt_paddstr (COLS, buf);
- NORMAL_COLOR;
- menu->redraw &= ~REDRAW_STATUS;
-@@ -652,7 +686,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
-@@ -1091,6 +1125,9 @@
- break;
-
- CHECK_MSGCOUNT;
-+#ifdef USE_SIDEBAR
-+ CHECK_VISIBLE;
-+#endif
- CHECK_READONLY;
- {
- int oldvcount = Context->vcount;
-@@ -1150,6 +1187,9 @@
- menu->redraw = REDRAW_FULL;
- break;
-
-+#ifdef USE_SIDEBAR
-+ case OP_SIDEBAR_OPEN:
-+#endif
- case OP_MAIN_CHANGE_FOLDER:
- case OP_MAIN_NEXT_UNREAD_MAILBOX:
-
-@@ -1181,6 +1221,14 @@
- {
- mutt_buffy (buf, sizeof (buf));
-
-+#ifdef USE_SIDEBAR
-+ if (op == OP_SIDEBAR_OPEN) {
-+ const char *path = 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)
-@@ -1199,6 +1247,9 @@
- }
-
- mutt_expand_path (buf, sizeof (buf));
-+#ifdef USE_SIDEBAR
-+ sb_set_open_buffy (buf);
-+#endif
- if (mx_get_magic (buf) <= 0)
- {
- mutt_error (_("%s is not a mailbox."), buf);
-@@ -2310,6 +2361,21 @@
- 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:
-+ sb_change_mailbox (op);
-+ break;
-+
-+ case OP_SIDEBAR_TOGGLE_VISIBLE:
-+ toggle_option (OPTSIDEBAR);
-+ menu->redraw = REDRAW_FULL;
-+ break;
-+#endif
- default:
- if (menu->menu == MENU_MAIN)
- km_error_key (MENU_MAIN);
-diff -urN mutt-1.6.1/doc/manual.xml.head mutt-1.6.1-sidebar/doc/manual.xml.head
---- mutt-1.6.1/doc/manual.xml.head 2016-05-02 03:02:12.402171465 +0100
-+++ mutt-1.6.1-sidebar/doc/manual.xml.head 2016-05-02 03:02:15.014213022 +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>
-+
- <sect2 id="intro-help">
- <title>Help</title>
-
-@@ -8081,6 +8698,469 @@
-
- </sect1>
-
-+<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.5.24</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>
-+
- </chapter>
-
- <chapter id="optionalfeatures">
-@@ -9237,6 +10317,17 @@
-
- <listitem>
- <cmdsynopsis>
-+<command>sidebar_whitelist</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/muttrc.sidebar mutt-1.6.1-sidebar/doc/muttrc.sidebar
---- mutt-1.6.1/doc/muttrc.sidebar 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-sidebar/doc/muttrc.sidebar 2016-05-02 03:02:14.932211718 +0100
-@@ -0,0 +1,116 @@
-+# This is a complete list of sidebar-related configuration.
-+
-+# --------------------------------------------------------------------------
-+# VARIABLES - shown with their default values
-+# --------------------------------------------------------------------------
-+
-+# Should the Sidebar be shown?
-+set sidebar_visible = no
-+
-+# How wide should the Sidebar be in screen columns?
-+# Note: Some characters, e.g. Chinese, take up two columns each.
-+set sidebar_width = 20
-+
-+# Should the mailbox paths be abbreviated?
-+set sidebar_short_path = no
-+
-+# 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 the mailbox path is abbreviated, should it be indented?
-+set sidebar_folder_indent = no
-+
-+# 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
-+
-+# 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'
-+
-+# 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
-+
-+# 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 = '|'
-+
-+# 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
-+
-+# 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'
-+
-+# --------------------------------------------------------------------------
-+# 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
-+
-+# 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
-+
-+# Move the highlight to the previous mailbox containing new, or flagged,
-+# mail.
-+bind index,pager <F5> sidebar-prev-new
-+
-+# Move the highlight to the next mailbox containing new, or flagged, mail.
-+bind index,pager <F6> sidebar-next-new
-+
-+# Toggle the visibility of the Sidebar.
-+bind index,pager B sidebar-toggle-visible
-+
-+# --------------------------------------------------------------------------
-+# 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.
-+color indicator cyan black
-+
-+# Color of the highlighted, but not open, mailbox.
-+color sidebar_highlight black color8
-+
-+# Color of the divider separating the Sidebar from Mutt panels
-+color sidebar_divider color8 black
-+
-+# Color to give mailboxes containing flagged mail
-+color sidebar_flagged red black
-+
-+# Color to give mailboxes containing new mail
-+color sidebar_new green black
-+
-+# --------------------------------------------------------------------------
-+
-+# vim: syntax=muttrc
-diff -urN mutt-1.6.1/doc/vimrc.sidebar mutt-1.6.1-sidebar/doc/vimrc.sidebar
---- mutt-1.6.1/doc/vimrc.sidebar 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-sidebar/doc/vimrc.sidebar 2016-05-02 03:02:14.933211733 +0100
-@@ -0,0 +1,35 @@
-+" Vim syntax file for the mutt sidebar patch
-+
-+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
-+
-+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
-+
-+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
-+
-+syntax keyword muttrcCommand sidebar_whitelist
-+
-+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\>"
-+
-+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
-+
-+" vim: syntax=vim
-diff -urN mutt-1.6.1/flags.c mutt-1.6.1-sidebar/flags.c
---- mutt-1.6.1/flags.c 2016-05-02 03:02:12.403171480 +0100
-+++ mutt-1.6.1-sidebar/flags.c 2016-05-02 03:02:15.015213038 +0100
-@@ -25,6 +25,10 @@
- #include "sort.h"
- #include "mx.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;
-@@ -263,6 +267,9 @@
- */
- if (h->searched && (changed != h->changed || deleted != ctx->deleted || tagged != ctx->tagged || flagged != ctx->flagged))
- h->searched = 0;
-+#ifdef USE_SIDEBAR
-+ sb_draw();
-+#endif
- }
-
- void mutt_tag_set_flag (int flag, int bf)
-diff -urN mutt-1.6.1/functions.h mutt-1.6.1-sidebar/functions.h
---- mutt-1.6.1/functions.h 2016-05-02 03:02:12.403171480 +0100
-+++ mutt-1.6.1-sidebar/functions.h 2016-05-02 03:02:15.015213038 +0100
-@@ -168,6 +168,16 @@
- { "decrypt-copy", OP_DECRYPT_COPY, NULL },
- { "decrypt-save", OP_DECRYPT_SAVE, 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-visible", OP_SIDEBAR_TOGGLE_VISIBLE, NULL },
-+#endif
-
- { NULL, 0, NULL }
- };
-@@ -272,6 +282,17 @@
-
- { "what-key", OP_WHAT_KEY, 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-visible", OP_SIDEBAR_TOGGLE_VISIBLE, NULL },
-+#endif
-+
- { NULL, 0, NULL }
- };
-
-diff -urN mutt-1.6.1/globals.h mutt-1.6.1-sidebar/globals.h
---- mutt-1.6.1/globals.h 2016-05-02 03:02:12.403171480 +0100
-+++ mutt-1.6.1-sidebar/globals.h 2016-05-02 03:02:15.015213038 +0100
-@@ -118,6 +118,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
-@@ -214,6 +220,14 @@
- WHERE short ScoreThresholdRead;
- WHERE short ScoreThresholdFlag;
-
-+/* 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
-+
- #ifdef USE_IMAP
- WHERE short ImapKeepalive;
- WHERE short ImapPipelineDepth;
-diff -urN mutt-1.6.1/imap/command.c mutt-1.6.1-sidebar/imap/command.c
---- mutt-1.6.1/imap/command.c 2016-05-02 03:02:12.404171496 +0100
-+++ mutt-1.6.1-sidebar/imap/command.c 2016-05-02 03:02:14.939211829 +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;
-+ }
-+#endif
-+
- FREE (&value);
- return;
- }
-diff -urN mutt-1.6.1/imap/imap.c mutt-1.6.1-sidebar/imap/imap.c
---- mutt-1.6.1/imap/imap.c 2016-05-02 03:02:12.404171496 +0100
-+++ mutt-1.6.1-sidebar/imap/imap.c 2016-05-02 03:02:15.016213054 +0100
-@@ -1535,7 +1535,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)
- {
-diff -urN mutt-1.6.1/init.c mutt-1.6.1-sidebar/init.c
---- mutt-1.6.1/init.c 2016-05-02 03:02:12.405171512 +0100
-+++ mutt-1.6.1-sidebar/init.c 2016-05-02 03:02:15.017213070 +0100
-@@ -2173,6 +2173,9 @@
- case DT_SORT_AUX:
- map = SortAuxMethods;
- break;
-+ case DT_SORT_SIDEBAR:
-+ map = SortSidebarMethods;
-+ break;
- default:
- map = SortMethods;
- break;
-diff -urN mutt-1.6.1/init.h mutt-1.6.1-sidebar/init.h
---- mutt-1.6.1/init.h 2016-05-02 03:02:12.407171544 +0100
-+++ mutt-1.6.1-sidebar/init.h 2016-05-02 03:02:15.018213086 +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 */
-@@ -2665,6 +2666,146 @@
- ** Command to use when spawning a subshell. By default, the user's login
- ** shell from \fC/etc/passwd\fP is used.
- */
-+#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
-+ ** 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 reduced 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
-@@ -3652,6 +3793,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 */
-
-@@ -3741,6 +3895,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-sidebar/keymap.c
---- mutt-1.6.1/keymap.c 2016-05-02 03:02:12.407171544 +0100
-+++ mutt-1.6.1-sidebar/keymap.c 2016-05-02 03:02:14.946211940 +0100
-@@ -453,6 +453,9 @@
- }
- #endif
-
-+ /* update sidebar stats */
-+ mutt_buffy_check(0);
-+
- timeout (i * 1000);
- tmp = mutt_getch();
- timeout (-1);
-diff -urN mutt-1.6.1/mailbox.h mutt-1.6.1-sidebar/mailbox.h
---- mutt-1.6.1/mailbox.h 2016-05-02 03:02:12.407171544 +0100
-+++ mutt-1.6.1-sidebar/mailbox.h 2016-05-02 03:02:15.018213086 +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
-
- /* mx_open_new_message() */
- #define M_ADD_FROM (1<<0) /* add a From_ line */
-diff -urN mutt-1.6.1/main.c mutt-1.6.1-sidebar/main.c
---- mutt-1.6.1/main.c 2016-05-02 03:02:12.408171560 +0100
-+++ mutt-1.6.1-sidebar/main.c 2016-05-02 03:02:15.018213086 +0100
-@@ -31,6 +31,9 @@
- #include "url.h"
- #include "mutt_crypt.h"
- #include "mutt_idna.h"
-+#ifdef USE_SIDEBAR
-+#include "sidebar.h"
-+#endif
- #include "version.h"
-
- #ifdef USE_SASL
-@@ -557,7 +566,11 @@
-
- int main (int argc, char **argv)
- {
-+#ifdef USE_SIDEBAR
-+ char folder[PATH_MAX] = "";
-+#else
- char folder[_POSIX_PATH_MAX] = "";
-+#endif
- char *subject = NULL;
- char *includeFile = NULL;
- char *draftFile = NULL;
-@@ -828,6 +841,9 @@
- clear ();
- mutt_error = mutt_curses_error;
- mutt_message = mutt_curses_message;
-+#ifdef USE_SIDEBAR
-+ sb_init();
-+#endif
- }
-
- /* Create the Maildir directory if it doesn't exist. */
-@@ -1184,6 +1200,15 @@
- strfcpy (folder, NONULL(Spoolfile), sizeof (folder));
- 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,6 +1231,9 @@
- if((Context = mx_open_mailbox (folder, ((flags & M_RO) || option (OPTREADONLY)) ? M_READONLY : 0, NULL))
- || !explicit_folder)
- {
-+#ifdef USE_SIDEBAR
-+ sb_set_open_buffy (folder);
-+#endif
- mutt_index_menu ();
- if (Context)
- FREE (&Context);
-diff -urN mutt-1.6.1/Makefile.am mutt-1.6.1-sidebar/Makefile.am
---- mutt-1.6.1/Makefile.am 2016-05-02 03:02:12.392171305 +0100
-+++ mutt-1.6.1-sidebar/Makefile.am 2016-05-02 03:02:15.005212879 +0100
-@@ -77,6 +77,12 @@
-
- EXTRA_SCRIPTS = smime_keys
-
-+if BUILD_SIDEBAR
-+mutt_SOURCES += sidebar.c sidebar.h
-+endif
-+
-+EXTRA_DIST += OPS.SIDEBAR
-+
- mutt_dotlock_SOURCES = mutt_dotlock.c
- mutt_dotlock_LDADD = $(LIBOBJS)
- mutt_dotlock_DEPENDENCIES = $(LIBOBJS)
-@@ -129,10 +135,10 @@
- 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.PGP $(srcdir)/OPS.MIX $(srcdir)/OPS.CRYPT $(srcdir)/OPS.SMIME $(srcdir)/gen_defs
- rm -f $@
- $(srcdir)/gen_defs $(srcdir)/OPS $(srcdir)/OPS.PGP \
-- $(srcdir)/OPS.MIX $(srcdir)/OPS.CRYPT $(srcdir)/OPS.SMIME \
-+ $(srcdir)/OPS.SIDEBAR $(srcdir)/OPS.MIX $(srcdir)/OPS.CRYPT $(srcdir)/OPS.SMIME \
- > keymap_alldefs.h
-
- reldate.h: $(srcdir)/ChangeLog
-diff -urN mutt-1.6.1/mbox.c mutt-1.6.1-sidebar/mbox.c
---- mutt-1.6.1/mbox.c 2016-05-02 03:02:12.408171560 +0100
-+++ mutt-1.6.1-sidebar/mbox.c 2016-05-02 03:02:14.948211972 +0100
-@@ -100,6 +100,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 +254,9 @@
-
- ctx->size = sb.st_size;
- ctx->mtime = sb.st_mtime;
-+#ifdef USE_SIDEBAR
-+ ctx->atime = sb.st_atime;
-+#endif
-
- #ifdef NFS_ATTRIBUTE_HACK
- if (sb.st_mtime > sb.st_atime)
-diff -urN mutt-1.6.1/menu.c mutt-1.6.1-sidebar/menu.c
---- mutt-1.6.1/menu.c 2016-05-02 03:02:12.408171560 +0100
-+++ mutt-1.6.1-sidebar/menu.c 2016-05-02 03:02:15.019213102 +0100
-@@ -24,6 +24,9 @@
- #include "mutt_curses.h"
- #include "mutt_menu.h"
- #include "mbyte.h"
-+#ifdef USE_SIDEBAR
-+#include "sidebar.h"
-+#endif
-
- char* SearchBuffers[MENU_MAX];
-
-@@ -184,7 +187,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 +240,9 @@
- int do_color;
- int attr;
-
-+#ifdef USE_SIDEBAR
-+ sb_draw();
-+#endif
- for (i = menu->top; i < menu->top + menu->pagelen; i++)
- {
- if (i < menu->max)
-@@ -247,7 +253,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)
-@@ -270,7 +276,11 @@
- 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 +297,7 @@
- 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,13 +309,13 @@
- {
- menu_make_entry (buf, sizeof (buf), menu, menu->oldcurrent);
- menu_pad_string (buf, sizeof (buf));
-- move (menu->oldcurrent + menu->offset - menu->top, 3);
-+ move (menu->oldcurrent + menu->offset - menu->top, SidebarWidth + 3);
- print_enriched_string (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
- {
-@@ -318,7 +328,7 @@
- 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);
-+ move(menu->current - menu->top + menu->offset, SidebarWidth);
- print_enriched_string (menu->color(menu->current), (unsigned char *) buf, 0);
- }
- menu->redraw &= REDRAW_STATUS;
-@@ -330,7 +340,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));
-
-@@ -873,7 +883,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-sidebar/mh.c
---- mutt-1.6.1/mh.c 2016-05-02 03:02:12.409171576 +0100
-+++ mutt-1.6.1-sidebar/mh.c 2016-05-02 03:02:15.019213102 +0100
-@@ -295,6 +295,49 @@
- mhs_free_sequences (&mhs);
- }
-
-+#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)
-+{
-+ if (!mailbox)
-+ return;
-+
-+ if (!option (OPTSIDEBAR))
-+ return;
-+
-+ struct mh_sequences mhs;
-+ memset (&mhs, 0, sizeof (mhs));
-+
-+ if (mh_read_sequences (&mhs, mailbox->path) < 0)
-+ return;
-+
-+ mailbox->msg_count = 0;
-+ mailbox->msg_unread = 0;
-+ mailbox->msg_flagged = 0;
-+
-+ int i;
-+ 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
-+
- static int mh_mkstemp (CONTEXT * dest, FILE ** fp, char **tgt)
- {
- int fd;
-diff -urN mutt-1.6.1/mutt_curses.h mutt-1.6.1-sidebar/mutt_curses.h
---- mutt-1.6.1/mutt_curses.h 2016-05-02 03:02:12.409171576 +0100
-+++ mutt-1.6.1-sidebar/mutt_curses.h 2016-05-02 03:02:15.019213102 +0100
-@@ -64,6 +64,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)
-@@ -124,6 +127,14 @@
- MT_COLOR_UNDERLINE,
- MT_COLOR_INDEX,
- MT_COLOR_PROMPT,
-+#ifdef USE_SIDEBAR
-+ MT_COLOR_DIVIDER,
-+ MT_COLOR_FLAGGED,
-+ MT_COLOR_HIGHLIGHT,
-+ MT_COLOR_NEW,
-+ MT_COLOR_SB_INDICATOR,
-+ MT_COLOR_SB_SPOOLFILE,
-+#endif
- MT_COLOR_MAX
- };
-
-diff -urN mutt-1.6.1/mutt.h mutt-1.6.1-sidebar/mutt.h
---- mutt-1.6.1/mutt.h 2016-05-02 03:02:12.409171576 +0100
-+++ mutt-1.6.1-sidebar/mutt.h 2016-05-02 03:02:15.019213102 +0100
-@@ -428,6 +428,13 @@
- OPTSAVEEMPTY,
- OPTSAVENAME,
- OPTSCORE,
-+#ifdef USE_SIDEBAR
-+ OPTSIDEBAR,
-+ OPTSIDEBARFOLDERINDENT,
-+ OPTSIDEBARNEWMAILONLY,
-+ OPTSIDEBARNEXTNEWWRAP,
-+ OPTSIDEBARSHORTPATH,
-+#endif
- OPTSIGDASHES,
- OPTSIGONTOP,
- OPTSORTRE,
-@@ -872,6 +879,9 @@
- {
- char *path;
- FILE *fp;
-+#ifdef USE_SIDEBAR
-+ time_t atime;
-+#endif
- time_t mtime;
- off_t size;
- off_t vsize;
-@@ -906,6 +916,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-sidebar/muttlib.c
---- mutt-1.6.1/muttlib.c 2016-05-02 03:02:12.410171592 +0100
-+++ mutt-1.6.1-sidebar/muttlib.c 2016-05-02 03:02:15.020213118 +0100
-@@ -1282,7 +1282,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 +1293,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 +1312,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;
-diff -urN mutt-1.6.1/mutt_menu.h mutt-1.6.1-sidebar/mutt_menu.h
---- mutt-1.6.1/mutt_menu.h 2016-05-02 03:02:12.409171576 +0100
-+++ mutt-1.6.1-sidebar/mutt_menu.h 2016-05-02 03:02:15.019213102 +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"
-
-diff -urN mutt-1.6.1/mx.c mutt-1.6.1-sidebar/mx.c
---- mutt-1.6.1/mx.c 2016-05-02 03:02:12.410171592 +0100
-+++ mutt-1.6.1-sidebar/mx.c 2016-05-02 03:02:15.020213118 +0100
-@@ -29,6 +29,9 @@
- #include "copy.h"
- #include "keymap.h"
- #include "url.h"
-+#ifdef USE_SIDEBAR
-+#include "sidebar.h"
-+#endif
-
- #ifdef USE_COMPRESSED
- #include "compress.h"
-@@ -580,6 +583,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 +606,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))
- {
-@@ -705,8 +713,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);
-+ }
-+#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);
-
- if (ctx->mx_close)
-@@ -719,6 +740,10 @@
- mutt_clear_threads (ctx);
- for (i = 0; i < ctx->msgcount; i++)
- mutt_free_header (&ctx->hdrs[i]);
-+#ifdef USE_SIDEBAR
-+ ctx->msgcount -= ctx->deleted;
-+ sb_set_buffystats (ctx);
-+#endif
- FREE (&ctx->hdrs);
- FREE (&ctx->v2r);
- #ifdef USE_COMPRESSED
-@@ -812,6 +837,12 @@
- 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
- }
-
- if (read_msgs && quadoption (OPT_MOVE) != M_NO)
-diff -urN mutt-1.6.1/mx.h mutt-1.6.1-sidebar/mx.h
---- mutt-1.6.1/mx.h 2016-05-02 03:02:12.410171592 +0100
-+++ mutt-1.6.1-sidebar/mx.h 2016-05-02 03:02:15.020213118 +0100
-@@ -26,6 +26,7 @@
- #define _MX_H
-
- #include "mailbox.h"
-+#include "buffy.h"
-
- /* supported mailbox formats */
- enum
-@@ -57,6 +58,9 @@
- 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);
-+#endif
- int mh_check_empty (const char *);
-
- int maildir_read_dir (CONTEXT *);
-diff -urN mutt-1.6.1/OPS.SIDEBAR mutt-1.6.1-sidebar/OPS.SIDEBAR
---- mutt-1.6.1/OPS.SIDEBAR 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-sidebar/OPS.SIDEBAR 2016-05-02 03:02:15.005212879 +0100
-@@ -0,0 +1,8 @@
-+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_VISIBLE "Make the Sidebar (in)visible"
-diff -urN mutt-1.6.1/pager.c mutt-1.6.1-sidebar/pager.c
---- mutt-1.6.1/pager.c 2016-05-02 03:02:12.411171608 +0100
-+++ mutt-1.6.1-sidebar/pager.c 2016-05-02 03:02:15.021213134 +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"
-
-@@ -1096,6 +1099,9 @@
- wchar_t wc;
- mbstate_t mbstate;
- int wrap_cols = mutt_term_width ((flags & M_PAGER_NOWRAP) ? 0 : Wrap);
-+#ifdef USE_SIDEBAR
-+ wrap_cols -= SidebarWidth;
-+#endif
-
- if (check_attachment_marker ((char *)buf) == 0)
- wrap_cols = COLS;
-@@ -1491,7 +1497,7 @@
- * a newline (grr!).
- */
- #ifndef USE_SLANG_CURSES
-- if (col < COLS)
-+ if (col < (COLS - SidebarWidth))
- #endif
- addch ('\n');
-
-@@ -1573,6 +1579,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 */
-
-@@ -1747,7 +1754,7 @@
- if ((redraw & REDRAW_BODY) || topline != oldtopline)
- {
- do {
-- move (bodyoffset, 0);
-+ move (bodyoffset, SidebarWidth);
- curline = oldtopline = topline;
- lines = 0;
- force_redraw = 0;
-@@ -1760,6 +1767,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 +1782,9 @@
- addch ('~');
- addch ('\n');
- lines++;
-+#ifdef USE_SIDEBAR
-+ move (lines + bodyoffset, SidebarWidth);
-+#endif
- }
- NORMAL_COLOR;
-
-@@ -1789,29 +1802,49 @@
- hfi.ctx = Context;
- hfi.pager_progress = pager_progress_str;
-
-+#ifdef USE_SIDEBAR
-+ statuswidth = COLS;
-+ if (option (OPTSTATUSONTOP) && (PagerIndexLines > 0))
-+ statuswidth -= SidebarWidth;
-+#endif
-+
- 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_paddstr (statuswidth, buffer);
- }
- else
- {
- char bn[STRING];
- snprintf (bn, sizeof (bn), "%s (%s)", banner, pager_progress_str);
-- mutt_paddstr (COLS, bn);
-+ mutt_paddstr (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 +1860,26 @@
- /* redraw the pager_index indicator, because the
- * flags for this message might have changed. */
- menu_redraw_current (index);
-+#ifdef USE_SIDEBAR
-+ 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)
-+ sb_draw();
-+#endif
-+
- redraw = 0;
-
- if (option(OPTBRAILLEFRIENDLY)) {
-@@ -2498,8 +2541,12 @@
- ch = 0;
- }
-
-- if (option (OPTFORCEREDRAWPAGER))
-+ if (option (OPTFORCEREDRAWPAGER)) {
- redraw = REDRAW_FULL;
-+#ifdef USE_SIDEBAR
-+ sb_draw();
-+#endif
-+ }
- unset_option (OPTFORCEREDRAWINDEX);
- unset_option (OPTFORCEREDRAWPAGER);
- break;
-@@ -2777,6 +2824,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:
-+ sb_change_mailbox (ch);
-+ break;
-+
-+ case OP_SIDEBAR_TOGGLE_VISIBLE:
-+ toggle_option (OPTSIDEBAR);
-+ redraw = REDRAW_FULL;
-+ break;
-+#endif
-+
- default:
- ch = -1;
- break;
-diff -urN mutt-1.6.1/PATCHES mutt-1.6.1-sidebar/PATCHES
---- mutt-1.6.1/PATCHES 2016-05-02 03:02:12.396171369 +0100
-+++ mutt-1.6.1-sidebar/PATCHES 2016-05-02 03:02:15.008212927 +0100
-@@ -0,0 +1 @@
-+patch-sidebar-neo-20160502
-diff -urN mutt-1.6.1/README.sidebar mutt-1.6.1-sidebar/README.sidebar
---- mutt-1.6.1/README.sidebar 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-sidebar/README.sidebar 2016-05-02 03:02:15.008212927 +0100
-@@ -0,0 +1,145 @@
-+Sidebar Patch
-+=============
-+
-+ Overview of mailboxes
-+
-+ NOTES:
-+
-+ If you haven't used the sidebar before, you might like to read the
-+ Sidebar Introduction:
-+
-+ http://www.neomutt.org/sidebar-intro.html
-+
-+ If you have used an older version of the Sidebar, please note that some
-+ of the configuration has changed.
-+
-+ http://www.neomutt.org/sidebar-intro.html#intro-sidebar-config-changes
-+
-+Patch
-+-----
-+
-+ To check if Mutt supports "Sidebar", look for "+USE_SIDEBAR" in the mutt
-+ version.
-+
-+ Dependencies
-+ * mutt-1.5.24
-+
-+Introduction
-+------------
-+
-+ 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.
-+
-+ 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.
-+
-+ 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.
-+
-+Variables
-+---------
-+
-+ Sidebar Variables
-+
-+ | 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' |
-+
-+Functions
-+---------
-+
-+ Sidebar Functions
-+
-+ Sidebar adds the following functions to Mutt. By default, none of them are
-+ bound to keys.
-+
-+ | 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 |
-+
-+Commands
-+--------
-+
-+ sidebar_whitelist mailbox [ mailbox... ]
-+
-+Colors
-+------
-+
-+ Sidebar Colors
-+
-+ | 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 |
-+
-+ If the sidebar_indicator color isn't set, then the default Mutt indicator
-+ color will be used (the color used in the index panel).
-+
-+Sort
-+----
-+
-+ Sidebar Sort
-+
-+ | 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 |
-+
-+See Also
-+--------
-+
-+ * Regular Expressions
-+ * Patterns
-+ * Color command
-+ * notmuch patch
-+
-+Known Bugs
-+----------
-+
-+ Unsorted isn't
-+
-+Credits
-+-------
-+
-+ * 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>
-+
-diff -urN mutt-1.6.1/sidebar.c mutt-1.6.1-sidebar/sidebar.c
---- mutt-1.6.1/sidebar.c 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-sidebar/sidebar.c 2016-05-02 03:02:15.023213165 +0100
-@@ -0,0 +1,1069 @@
-+/* 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>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
-+ */
-+
-+#if HAVE_CONFIG_H
-+# include "config.h"
-+#endif
-+
-+#include "mutt.h"
-+#include "buffy.h"
-+#include "keymap.h"
-+#include "mutt_curses.h"
-+#include "mutt_menu.h"
-+#include "sort.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 */
-+
-+/**
-+ * struct sidebar_entry - Info about folders in the sidebar
-+ *
-+ * Used in the mutt_FormatString callback
-+ */
-+struct sidebar_entry {
-+ char box[SHORT_STRING];
-+ BUFFY *buffy;
-+};
-+
-+
-+/**
-+ * 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 = 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
-+ * @col: Starting column, UNUSED
-+ * @op: printf-like operator, e.g. 'B'
-+ * @src: printf-like format string
-+ * @prefix: Field formatting string, UNUSED
-+ * @ifstring: If condition is met, display this string
-+ * @elsestring: Otherwise, display this string
-+ * @data: Pointer to our sidebar_entry
-+ * @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,
-+ * '%N' : Number of new messages, '%S' : Size (total number of messages),
-+ * '%!' : Icon denoting number of flagged messages.
-+ *
-+ * Returns: src (unchanged)
-+ */
-+static const char *
-+cb_format_str (char *dest, size_t destlen, size_t col, 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;
-+ unsigned int optional;
-+ char fmt[SHORT_STRING], buf[SHORT_STRING];
-+
-+ if (!sbe || !dest)
-+ return src;
-+
-+ dest[0] = 0; /* Just in case there's nothing to do */
-+
-+ BUFFY *b = sbe->buffy;
-+ if (!b)
-+ return src;
-+
-+ int c = Context && (mutt_strcmp (Context->path, b->path) == 0);
-+
-+ optional = flags & M_FORMAT_OPTIONAL;
-+
-+ switch (op) {
-+ case 'B':
-+ mutt_format_s (dest, destlen, prefix, sbe->box);
-+ break;
-+
-+ case 'd':
-+ if (!optional) {
-+ snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
-+ snprintf (dest, destlen, fmt, c ? Context->deleted : 0);
-+ } else if ((c && Context->deleted == 0) || !c) {
-+ optional = 0;
-+ }
-+ break;
-+
-+ case 'F':
-+ if (!optional) {
-+ snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
-+ snprintf (dest, destlen, fmt, b->msg_flagged);
-+ } else if (b->msg_flagged == 0) {
-+ optional = 0;
-+ }
-+ break;
-+
-+ case 'L':
-+ if (!optional) {
-+ snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
-+ snprintf (dest, destlen, fmt, c ? Context->vcount : b->msg_count);
-+ } else if ((c && Context->vcount == b->msg_count) || !c) {
-+ optional = 0;
-+ }
-+ break;
-+
-+ case 'N':
-+ if (!optional) {
-+ snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
-+ snprintf (dest, destlen, fmt, b->msg_unread);
-+ } else if (b->msg_unread == 0) {
-+ optional = 0;
-+ }
-+ break;
-+
-+ case 'S':
-+ if (!optional) {
-+ snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
-+ snprintf (dest, destlen, fmt, b->msg_count);
-+ } else if (b->msg_count == 0) {
-+ optional = 0;
-+ }
-+ break;
-+
-+ case 't':
-+ if (!optional) {
-+ snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
-+ snprintf (dest, destlen, fmt, c ? Context->tagged : 0);
-+ } else if ((c && Context->tagged == 0) || !c) {
-+ optional = 0;
-+ }
-+ break;
-+
-+ case '!':
-+ if (b->msg_flagged == 0) {
-+ mutt_format_s (dest, destlen, prefix, "");
-+ } else if (b->msg_flagged == 1) {
-+ mutt_format_s (dest, destlen, prefix, "!");
-+ } else if (b->msg_flagged == 2) {
-+ mutt_format_s (dest, destlen, prefix, "!!");
-+ } else {
-+ snprintf (buf, sizeof (buf), "%d!", b->msg_flagged);
-+ mutt_format_s (dest, destlen, prefix, buf);
-+ }
-+ break;
-+ }
-+
-+ if (optional)
-+ mutt_FormatString (dest, destlen, col, 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);
-+
-+ /* We return the format string, unchanged */
-+ return src;
-+}
-+
-+/**
-+ * make_sidebar_entry - Turn mailbox data into a sidebar string
-+ * @buf: Buffer in which to save string
-+ * @buflen: Buffer length
-+ * @width: Desired width in screen cells
-+ * @box: Mailbox name
-+ * @size: Size (total number of messages)
-+ * @new: Number of new messages
-+ * @flagged: Number of flagged messages
-+ *
-+ * Take all the relevant mailbox data and the desired screen width and then get
-+ * mutt_FormatString to do the actual work. mutt_FormatString will callback to
-+ * 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)
-+{
-+ struct sidebar_entry sbe;
-+
-+ if (!buf || !box || !b)
-+ return;
-+
-+ sbe.buffy = b;
-+ strncpy (sbe.box, box, sizeof (sbe.box) - 1);
-+
-+ int box_len = strlen (box);
-+ sbe.box[box_len] = '\0';
-+
-+ /* 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;
-+
-+ /* Force string to be exactly the right width */
-+ int w = mutt_strwidth (buf);
-+ int s = strlen (buf);
-+ if (w < width) {
-+ /* Pad with spaces */
-+ memset (buf + s, ' ', width - w);
-+ buf[s + width - w] = 0;
-+ } else if (w > width) {
-+ /* Truncate to fit */
-+ int len = mutt_wstr_trunc (buf, buflen, width, NULL);
-+ buf[len] = 0;
-+ }
-+}
-+
-+/**
-+ * 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.
-+ *
-+ * 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)
-+{
-+ 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;
-+ }
-+
-+ int result = 0;
-+
-+ switch ((SidebarSortMethod & SORT_MASK)) {
-+ 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_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;
-+ }
-+
-+ if (b->next) {
-+ b->next->prev = NULL;
-+ return b->next;
-+ }
-+
-+ return b->prev;
-+}
-+
-+/**
-+ * update_buffy_visibility - Should a BUFFY be displayed in the sidebar
-+ * @arr: array of BUFFYs
-+ * @arr_len: number of BUFFYs in array
-+ *
-+ * For each BUFFY in the 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
-+ * has unread messages
-+ * has flagged messages
-+ * is whitelisted
-+ */
-+static void
-+update_buffy_visibility (BUFFY **arr, int arr_len)
-+{
-+ if (!arr)
-+ return;
-+
-+ short new_only = option (OPTSIDEBARNEWMAILONLY);
-+
-+ BUFFY *b;
-+ int i;
-+ for (i = 0; i < arr_len; i++) {
-+ b = arr[i];
-+
-+ b->is_hidden = 0;
-+
-+ if (!new_only)
-+ continue;
-+
-+ if ((b == OpnBuffy) || (b->msg_unread > 0) ||
-+ (b == HilBuffy) || (b->msg_flagged > 0)) {
-+ continue;
-+ }
-+
-+ if (Context && (strcmp (b->path, Context->path) == 0)) {
-+ /* Spool directory */
-+ continue;
-+ }
-+
-+ if (mutt_find_list (SidebarWhitelist, b->path)) {
-+ /* Explicitly asked to be visible */
-+ continue;
-+ }
-+
-+ b->is_hidden = 1;
-+ }
-+}
-+
-+/**
-+ * sort_buffy_array - Sort an array of BUFFY pointers
-+ * @arr: array of BUFFYs
-+ * @arr_len: number of BUFFYs in array
-+ *
-+ * Sort an array of BUFFY pointers 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".
-+ *
-+ * Once sorted, the prev/next links will be reconstructed.
-+ */
-+static void
-+sort_buffy_array (BUFFY **arr, int arr_len)
-+{
-+ if (!arr)
-+ return;
-+
-+ /* 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;
-+}
-+
-+/**
-+ * prepare_sidebar - Prepare the list of BUFFYs 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.
-+ *
-+ * 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.
-+ *
-+ * Returns:
-+ * 0: No, don't draw the sidebar
-+ * 1: Yes, draw the sidebar
-+ */
-+static int
-+prepare_sidebar (int page_size)
-+{
-+ BUFFY *b = Incoming;
-+ if (!b)
-+ return 0;
-+
-+ int count = 0;
-+ for (; b; b = b->next)
-+ count++;
-+
-+ BUFFY **arr = safe_malloc (count * sizeof (*arr));
-+ if (!arr)
-+ return 0;
-+
-+ int i = 0;
-+ for (b = Incoming; b; b = b->next, i++) {
-+ arr[i] = b;
-+ }
-+
-+ update_buffy_visibility (arr, count);
-+ sort_buffy_array (arr, count);
-+
-+ Incoming = arr[0];
-+
-+ int top_index = 0;
-+ int opn_index = -1;
-+ int hil_index = -1;
-+ int bot_index = -1;
-+
-+ for (i = 0; i < count; i++) {
-+ if (OpnBuffy == arr[i])
-+ opn_index = i;
-+ if (HilBuffy == arr[i])
-+ hil_index = i;
-+ }
-+
-+ if (!HilBuffy || (SidebarSortMethod != PreviousSort)) {
-+ if (OpnBuffy) {
-+ HilBuffy = OpnBuffy;
-+ hil_index = opn_index;
-+ } else {
-+ HilBuffy = arr[0];
-+ hil_index = 0;
-+ }
-+ }
-+ if (TopBuffy) {
-+ top_index = (hil_index / 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];
-+
-+ Outgoing = arr[count - 1];
-+
-+ PreviousSort = SidebarSortMethod;
-+ free (arr);
-+ return 1;
-+}
-+
-+/**
-+ * visible - Should we display the sidebar?
-+ *
-+ * After validating the config options "sidebar_visible" and "sidebar_width",
-+ * determine whether we should should display the sidebar.
-+ *
-+ * When not visible, set the global SidebarWidth to 0.
-+ *
-+ * Returns:
-+ * Boolean
-+ */
-+static short
-+visible (void)
-+{
-+ short new_visible = option (OPTSIDEBAR);
-+ short new_width = SidebarWidth;
-+
-+ if (OldWidth != new_width) {
-+ if (new_width > 0) {
-+ OldWidth = new_width;
-+ }
-+ }
-+
-+ if (OldVisible != new_visible) {
-+ if (new_visible) {
-+ set_option (OPTSIDEBAR);
-+ } else {
-+ unset_option (OPTSIDEBAR);
-+ }
-+ OldVisible = new_visible;
-+ } else if (new_width == 0) {
-+ unset_option (OPTSIDEBAR);
-+ OldVisible = 0;
-+ }
-+
-+ if (!option (OPTSIDEBAR)) {
-+ SidebarWidth = 0;
-+ } else if (new_width == 0) {
-+ SidebarWidth = OldWidth;
-+ } else {
-+ SidebarWidth = new_width;
-+ }
-+
-+ return new_visible;
-+}
-+
-+/**
-+ * draw_divider - Draw a line between the sidebar and the rest of mutt
-+ * @first_row: Screen line to start (0-based)
-+ * @num_rows: Number of rows to fill
-+ *
-+ * Draw a divider using characters from the config option "sidebar_divider_char".
-+ * This can be an ASCII or Unicode character. First we calculate this
-+ * characters' width in screen columns, then subtract that from the config
-+ * option "sidebar_width".
-+ *
-+ * Returns:
-+ * -1: Error: bad character, etc
-+ * 0: Error: 0 width character
-+ * n: Success: character occupies n screen columns
-+ */
-+static int
-+draw_divider (int first_row, int num_rows)
-+{
-+ /* Calculate the width of the delimiter in screen cells */
-+ int delim_len = mutt_strwidth (SidebarDividerChar);
-+
-+ if (delim_len < 1)
-+ return delim_len;
-+
-+ if ((SidebarWidth + delim_len) > (COLS + 1))
-+ return 0;
-+
-+ if (delim_len > SidebarWidth)
-+ return -1;
-+
-+ SETCOLOR(MT_COLOR_DIVIDER);
-+
-+ int i;
-+ for (i = 0; i < num_rows; i++) {
-+ move (first_row + i, SidebarWidth - delim_len);
-+ addstr (NONULL(SidebarDividerChar));
-+ }
-+
-+ return delim_len;
-+}
-+
-+/**
-+ * fill_empty_space - Wipe the remaining sidebar space
-+ * @first_row: Screen line to start (0-based)
-+ * @num_rows: Number of rows to fill
-+ * @width: Width of the sidebar (minus the divider)
-+ *
-+ * Write spaces over the area the sidebar isn't using.
-+ */
-+static void
-+fill_empty_space (int first_row, int num_rows, int width)
-+{
-+ /* Fill the remaining rows with blank space */
-+ SETCOLOR(MT_COLOR_NORMAL);
-+
-+ int r;
-+ for (r = 0; r < num_rows; r++) {
-+ int i = 0;
-+ move (first_row + r, 0);
-+ for (; i < width; i++)
-+ addch (' ');
-+ }
-+}
-+
-+/**
-+ * draw_sidebar - Write out a list of mailboxes, on the left
-+ * @first_row: Screen line to start (0-based)
-+ * @num_rows: Number of rows to fill
-+ * @div_width: Width in screen characters taken by the divider
-+ *
-+ * Display a list of mailboxes in a panel on the left. What's displayed will
-+ * depend on our index markers: TopBuffy, OpnBuffy, HilBuffy, BotBuffy.
-+ * On the first run they'll be NULL, so we display the top of Mutt's list
-+ * (Incoming).
-+ *
-+ * TopBuffy - first visible mailbox
-+ * BotBuffy - last visible mailbox
-+ * OpnBuffy - mailbox shown in Mutt's Index Panel
-+ * HilBuffy - Unselected mailbox (the paging follows this)
-+ *
-+ * The entries are formatted using "sidebar_format" and may be abbreviated:
-+ * "sidebar_short_path", indented: "sidebar_folder_indent",
-+ * "sidebar_indent_string" and sorted: "sidebar_sort_method". Finally, they're
-+ * trimmed to fit the available space.
-+ */
-+static void
-+draw_sidebar (int first_row, int num_rows, int div_width)
-+{
-+ BUFFY *b = TopBuffy;
-+ if (!b)
-+ return;
-+
-+ int w = MIN(COLS, (SidebarWidth - div_width));
-+ int row = 0;
-+ for (b = TopBuffy; b && (row < num_rows); b = b->next) {
-+ if (b->is_hidden) {
-+ continue;
-+ }
-+
-+ if (b == OpnBuffy) {
-+ if ((ColorDefs[MT_COLOR_SB_INDICATOR] != 0)) {
-+ SETCOLOR(MT_COLOR_SB_INDICATOR);
-+ } else {
-+ SETCOLOR(MT_COLOR_INDICATOR);
-+ }
-+ } else if (b == HilBuffy) {
-+ 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) {
-+ SETCOLOR(MT_COLOR_NEW);
-+ } else if (b->msg_flagged > 0) {
-+ SETCOLOR(MT_COLOR_FLAGGED);
-+ } else {
-+ SETCOLOR(MT_COLOR_NORMAL);
-+ }
-+
-+ move (first_row + row, 0);
-+ if (Context && Context->path &&
-+ (!strcmp (b->path, Context->path)||
-+ !strcmp (b->realpath, Context->path))) {
-+ b->msg_unread = Context->unread;
-+ b->msg_count = Context->msgcount;
-+ b->msg_flagged = Context->flagged;
-+ }
-+
-+ /* compute length of Maildir without trailing separator */
-+ size_t maildirlen = strlen (Maildir);
-+ if (SidebarDelimChars && strchr (SidebarDelimChars, Maildir[maildirlen - 1])) {
-+ maildirlen--;
-+ }
-+
-+ /* check whether Maildir is a prefix of the current folder's path */
-+ short maildir_is_prefix = 0;
-+ if ((strlen (b->path) > maildirlen) && (strncmp (Maildir, b->path, maildirlen) == 0)) {
-+ maildir_is_prefix = 1;
-+ }
-+ /* calculate depth of current folder and generate its display name with indented spaces */
-+ int sidebar_folder_depth = 0;
-+ char *sidebar_folder_name;
-+ int i;
-+ if (option (OPTSIDEBARSHORTPATH)) {
-+ /* disregard a trailing separator, so strlen() - 2 */
-+ sidebar_folder_name = b->path;
-+ for (i = strlen (sidebar_folder_name) - 2; i >= 0; i--) {
-+ if (SidebarDelimChars &&
-+ strchr (SidebarDelimChars, sidebar_folder_name[i])) {
-+ sidebar_folder_name += (i + 1);
-+ break;
-+ }
-+ }
-+ } else {
-+ sidebar_folder_name = b->path + maildir_is_prefix * (maildirlen + 1);
-+ }
-+ if (maildir_is_prefix && option (OPTSIDEBARFOLDERINDENT)) {
-+ const char *tmp_folder_name;
-+ int lastsep = 0;
-+ tmp_folder_name = b->path + maildirlen + 1;
-+ int tmplen = (int) strlen (tmp_folder_name) - 1;
-+ for (i = 0; i < tmplen; i++) {
-+ if (SidebarDelimChars && strchr (SidebarDelimChars, tmp_folder_name[i])) {
-+ sidebar_folder_depth++;
-+ lastsep = i + 1;
-+ }
-+ }
-+ if (sidebar_folder_depth > 0) {
-+ if (option (OPTSIDEBARSHORTPATH)) {
-+ tmp_folder_name += lastsep; /* basename */
-+ }
-+ sidebar_folder_name = malloc (strlen (tmp_folder_name) + sidebar_folder_depth*strlen (NONULL(SidebarIndentString)) + 1);
-+ 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));
-+ }
-+ }
-+ char str[SHORT_STRING];
-+ make_sidebar_entry (str, sizeof (str), w, sidebar_folder_name, b);
-+ printw ("%s", str);
-+ if (sidebar_folder_depth > 0)
-+ free (sidebar_folder_name);
-+ row++;
-+ }
-+
-+ fill_empty_space (first_row + row, num_rows - row, w);
-+}
-+
-+
-+/**
-+ * sb_init - Set some default values for the sidebar.
-+ */
-+void
-+sb_init (void)
-+{
-+ OldVisible = option (OPTSIDEBAR);
-+ if (SidebarWidth > 0) {
-+ OldWidth = SidebarWidth;
-+ } else {
-+ OldWidth = 20;
-+ if (OldVisible) {
-+ SidebarWidth = OldWidth;
-+ }
-+ }
-+}
-+
-+/**
-+ * sb_draw - Completely redraw the sidebar
-+ *
-+ * Completely refresh the sidebar region. First draw the divider; then, for
-+ * each BUFFY, call make_sidebar_entry; finally blank out any remaining space.
-+ */
-+void
-+sb_draw (void)
-+{
-+ if (!visible())
-+ return;
-+
-+ /* XXX - if transitioning from invisible to visible */
-+ /* if (OldVisible == 0) */
-+ /* mutt_buffy_check (1); we probably have bad or no numbers */
-+
-+ int first_row = 0;
-+ int num_rows = LINES - 2;
-+
-+ if (option (OPTHELP) || option (OPTSTATUSONTOP))
-+ first_row++;
-+
-+ if (option (OPTHELP))
-+ num_rows--;
-+
-+ int div_width = draw_divider (first_row, num_rows);
-+ if (div_width < 0)
-+ return;
-+
-+ if (!Incoming) {
-+ int w = MIN(COLS, (SidebarWidth - div_width));
-+ fill_empty_space (first_row, num_rows, w);
-+ return;
-+ }
-+
-+ if (!prepare_sidebar (num_rows))
-+ return;
-+
-+ draw_sidebar (first_row, num_rows, div_width);
-+}
-+
-+/**
-+ * sb_should_refresh - Check if the sidebar is due to be refreshed
-+ *
-+ * The "sidebar_refresh_time" config option allows the user to limit the frequency
-+ * with which the sidebar is refreshed.
-+ *
-+ * Returns:
-+ * 1 Yes, refresh is due
-+ * 0 No, refresh happened recently
-+ */
-+int
-+sb_should_refresh (void)
-+{
-+ if (!option (OPTSIDEBAR))
-+ return 0;
-+
-+ if (SidebarRefreshTime == 0)
-+ return 0;
-+
-+ time_t diff = (time (NULL) - LastRefresh);
-+
-+ return (diff >= SidebarRefreshTime);
-+}
-+
-+/**
-+ * sb_change_mailbox - Change the selected mailbox
-+ * @op: Operation code
-+ *
-+ * Change the selected mailbox, e.g. "Next mailbox", "Previous Mailbox
-+ * with new mail". The operations are listed OPS.SIDEBAR which is built
-+ * into an enum in keymap_defs.h.
-+ *
-+ * If the operation is successful, HilBuffy will be set to the new mailbox.
-+ * This function only *selects* the mailbox, doesn't *open* it.
-+ *
-+ * Allowed values are: OP_SIDEBAR_NEXT, OP_SIDEBAR_NEXT_NEW,
-+ * OP_SIDEBAR_PAGE_DOWN, OP_SIDEBAR_PAGE_UP, OP_SIDEBAR_PREV,
-+ * OP_SIDEBAR_PREV_NEW.
-+ */
-+void
-+sb_change_mailbox (int op)
-+{
-+ BUFFY *b;
-+ if (!HilBuffy) /* It'll get reset on the next draw */
-+ return;
-+
-+ switch (op) {
-+ case OP_SIDEBAR_NEXT:
-+ if (!HilBuffy->next)
-+ return;
-+ if (HilBuffy->next->is_hidden)
-+ return;
-+ HilBuffy = HilBuffy->next;
-+ break;
-+ case OP_SIDEBAR_NEXT_NEW:
-+ b = find_next_new (option (OPTSIDEBARNEXTNEWWRAP));
-+ if (!b) {
-+ return;
-+ } else {
-+ HilBuffy = b;
-+ }
-+ break;
-+ case OP_SIDEBAR_PAGE_DOWN:
-+ HilBuffy = BotBuffy;
-+ if (HilBuffy->next) {
-+ HilBuffy = HilBuffy->next;
-+ }
-+ break;
-+ case OP_SIDEBAR_PAGE_UP:
-+ HilBuffy = TopBuffy;
-+ if (HilBuffy != Incoming) {
-+ HilBuffy = HilBuffy->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 */
-+ return;
-+ HilBuffy = HilBuffy->prev;
-+ break;
-+ case OP_SIDEBAR_PREV_NEW:
-+ b = find_prev_new (option (OPTSIDEBARNEXTNEWWRAP));
-+ if (!b) {
-+ return;
-+ } else {
-+ HilBuffy = b;
-+ }
-+ break;
-+ default:
-+ return;
-+ }
-+
-+ /* We can change folder even if the sidebar is hidden */
-+ if (option (OPTSIDEBAR))
-+ sb_draw();
-+}
-+
-+/**
-+ * sb_set_buffystats - Update the BUFFY's message counts from the CONTEXT
-+ * @ctx: A mailbox CONTEXT
-+ *
-+ * Given a mailbox CONTEXT, find a matching mailbox BUFFY and copy the message
-+ * counts into it.
-+ */
-+void
-+sb_set_buffystats (const CONTEXT *ctx)
-+{
-+ /* Even if the sidebar's hidden,
-+ * we should take note of the new data. */
-+ BUFFY *b = Incoming;
-+ if (!ctx || !b)
-+ return;
-+
-+ for (; b; b = b->next) {
-+ if (!strcmp (b->path, ctx->path) ||
-+ !strcmp (b->realpath, ctx->path)) {
-+ b->msg_unread = ctx->unread;
-+ b->msg_count = ctx->msgcount;
-+ b->msg_flagged = ctx->flagged;
-+ break;
-+ }
-+ }
-+}
-+
-+/**
-+ * sb_get_highlight - Get the BUFFY that's highlighted in the sidebar
-+ *
-+ * Get the path of the mailbox that's highlighted in the sidebar.
-+ *
-+ * Returns:
-+ * Mailbox path
-+ */
-+const char *
-+sb_get_highlight (void)
-+{
-+ if (!HilBuffy)
-+ return NULL;
-+
-+ return HilBuffy->path;
-+}
-+
-+/**
-+ * sb_set_open_buffy - Set the OpnBuffy based on a mailbox path
-+ * @path: Mailbox path
-+ *
-+ * Search through the list of mailboxes. If a BUFFY has a matching path, set
-+ * OpnBuffy to it.
-+ */
-+BUFFY *
-+sb_set_open_buffy (const char *path)
-+{
-+ /* Even if the sidebar is hidden */
-+
-+ BUFFY *b = Incoming;
-+
-+ if (!path || !b)
-+ return NULL;
-+
-+ OpnBuffy = NULL;
-+
-+ for (; b; b = b->next) {
-+ if (!strcmp (b->path, path) ||
-+ !strcmp (b->realpath, path)) {
-+ OpnBuffy = b;
-+ HilBuffy = b;
-+ break;
-+ }
-+ }
-+
-+ return OpnBuffy;
-+}
-+
-+/**
-+ * 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
-+sb_set_update_time (void)
-+{
-+ /* XXX - should this be public? */
-+
-+ LastRefresh = time (NULL);
-+}
-+
-+/**
-+ * sb_notify_mailbox - The state of a BUFFY is about to change
-+ *
-+ * We receive a notification:
-+ * After a new BUFFY has been created
-+ * Before a BUFFY is deleted
-+ *
-+ * Before a deletion, check that our pointers won't be invalidated.
-+ */
-+void
-+sb_notify_mailbox (BUFFY *b, int created)
-+{
-+ if (!b)
-+ 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) {
-+ /* This might happen if the user "unmailboxes *", then
-+ * "mailboxes" our current mailbox back again */
-+ if (mutt_strcmp (b->path, Context->path) == 0) {
-+ OpnBuffy = b;
-+ }
-+ }
-+ } else {
-+ if (TopBuffy == b)
-+ TopBuffy = buffy_going (TopBuffy);
-+ if (OpnBuffy == b)
-+ OpnBuffy = buffy_going (OpnBuffy);
-+ if (HilBuffy == b)
-+ HilBuffy = buffy_going (HilBuffy);
-+ if (BotBuffy == b)
-+ BotBuffy = buffy_going (BotBuffy);
-+ if (Outgoing == b)
-+ Outgoing = buffy_going (Outgoing);
-+ }
-+}
-diff -urN mutt-1.6.1/sidebar.h mutt-1.6.1-sidebar/sidebar.h
---- mutt-1.6.1/sidebar.h 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-sidebar/sidebar.h 2016-05-02 03:02:15.023213165 +0100
-@@ -0,0 +1,36 @@
-+/* 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>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
-+ */
-+
-+#ifndef SIDEBAR_H
-+#define SIDEBAR_H
-+
-+#include "mutt.h"
-+#include "buffy.h"
-+
-+void sb_change_mailbox (int op);
-+void sb_draw (void);
-+const char * sb_get_highlight (void);
-+void sb_init (void);
-+void sb_notify_mailbox (BUFFY *b, int created);
-+void sb_set_buffystats (const CONTEXT *ctx);
-+BUFFY * sb_set_open_buffy (const char *path);
-+void sb_set_update_time (void);
-+int sb_should_refresh (void);
-+
-+#endif /* SIDEBAR_H */
-diff -urN mutt-1.6.1/sort.h mutt-1.6.1-sidebar/sort.h
---- mutt-1.6.1/sort.h 2016-05-02 03:02:12.440172071 +0100
-+++ mutt-1.6.1-sidebar/sort.h 2016-05-02 03:02:15.023213165 +0100
-@@ -31,6 +31,12 @@
- #define SORT_KEYID 12
- #define SORT_TRUST 13
- #define SORT_SPAM 14
-+#define SORT_COUNT 15
-+#define SORT_COUNT_NEW 16
-+#define SORT_DESC 17
-+#define SORT_FLAGGED 18
-+#define SORT_PATH 19
-+
- /* 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 +56,7 @@
- WHERE short Sort INITVAL (SORT_DATE);
- WHERE short SortAux INITVAL (SORT_DATE); /* auxiliary sorting method */
- WHERE short SortAlias INITVAL (SORT_ALIAS);
-+WHERE short SidebarSortMethod INITVAL (SORT_ORDER);
-
- /* FIXME: This one does not belong to here */
- WHERE short PgpSortKeys INITVAL (SORT_ADDRESS);
---- a/version.c
-+++ b/version.c
-@@ -286,6 +286,11 @@ static struct compile_options comp_opts[
- #else
- { "USE_SETGID", 0 },
- #endif
-+#ifdef USE_SIDEBAR
-+ { "USE_SIDEBAR", 1 },
-+#else
-+ { "USE_SIDEBAR", 0 },
-+#endif
- #ifdef USE_SMTP
- { "USE_SMTP", 1 },
- #else
diff --git a/debian/patches/neomutt/10-notmuch.patch b/debian/patches/neomutt/10-notmuch.patch
deleted file mode 100644
index 827a381..0000000
--- a/debian/patches/neomutt/10-notmuch.patch
+++ /dev/null
@@ -1,5819 +0,0 @@
-diff -urN mutt-1.6.1-sidebar-notmuch/browser.c mutt-1.6.1-notmuch/browser.c
---- mutt-1.6.1-sidebar-notmuch/browser.c 2016-05-02 03:02:12.695176126 +0100
-+++ mutt-1.6.1-notmuch/browser.c 2016-05-02 03:02:15.119214693 +0100
-@@ -33,6 +33,9 @@
- #ifdef USE_IMAP
- #include "imap.h"
- #endif
-+#ifdef USE_NOTMUCH
-+#include "mutt_notmuch.h"
-+#endif
-
- #include <stdlib.h>
- #include <dirent.h>
-@@ -232,6 +235,12 @@
- case 'f':
- {
- char *s;
-+
-+#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);
-@@ -324,6 +333,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;
-@@ -490,6 +511,33 @@
- return 0;
- }
-
-+#ifdef USE_NOTMUCH
-+static int examine_vfolders (MUTTMENU *menu, struct browser_state *state)
-+{
-+ BUFFY *tmp = VirtIncoming;
-+
-+ if (!VirtIncoming)
-+ return (-1);
-+ mutt_buffy_check (0);
-+
-+ init_state (state, menu);
-+
-+ 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);
-+ continue;
-+ }
-+ }
-+ while ((tmp = tmp->next));
-+ browser_sort (state);
-+ return 0;
-+}
-+#endif
-+
- static int examine_mailboxes (MUTTMENU *menu, struct browser_state *state)
- {
- struct stat s;
-@@ -559,6 +607,13 @@
- 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
-+
- static void folder_entry (char *s, size_t slen, MUTTMENU *menu, int num)
- {
- FOLDER folder;
-@@ -570,6 +625,19 @@
- (unsigned long) &folder, M_FORMAT_ARROWCURSOR);
- }
-
-+#ifdef USE_NOTMUCH
-+static void vfolder_entry (char *s, size_t slen, MUTTMENU *menu, int num)
-+{
-+ FOLDER folder;
-+
-+ folder.ff = &((struct folder_file *) menu->data)[num];
-+ folder.num = num;
-+
-+ mutt_FormatString (s, slen, 0, NONULL(VirtFolderFormat), folder_format_str,
-+ (unsigned long) &folder, M_FORMAT_ARROWCURSOR);
-+}
-+#endif
-+
- static void init_menu (struct browser_state *state, MUTTMENU *menu, char *title,
- size_t titlelen, int buffy)
- {
-@@ -635,7 +703,7 @@
- int buffy = (flags & M_SEL_BUFFY) ? 1 : 0;
-
- buffy = buffy && folder;
--
-+
- memset (&state, 0, sizeof (struct browser_state));
-
- if (!folder)
-@@ -688,13 +756,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));
--
-+
- #ifdef USE_IMAP
- if (!buffy && mx_is_imap (LastDir))
- {
-@@ -716,6 +788,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)
-@@ -725,17 +803,25 @@
- #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;
-+
- menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_FOLDER,
- FolderHelp);
-
-@@ -884,6 +970,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);
-
-@@ -1038,7 +1128,7 @@
- }
- break;
- #endif
--
-+
- case OP_CHANGE_DIRECTORY:
-
- strfcpy (buf, LastDir, sizeof (buf));
-diff -urN mutt-1.6.1-sidebar-notmuch/buffy.c mutt-1.6.1-notmuch/buffy.c
---- mutt-1.6.1-sidebar-notmuch/buffy.c 2016-05-02 03:02:12.695176126 +0100
-+++ mutt-1.6.1-notmuch/buffy.c 2016-05-02 03:02:15.221216316 +0100
-@@ -35,6 +35,10 @@
- #include "imap.h"
- #endif
-
-+#ifdef USE_NOTMUCH
-+#include "mutt_notmuch.h"
-+#endif
-+
- #include <string.h>
- #include <sys/stat.h>
- #include <dirent.h>
-@@ -219,6 +223,8 @@
-
- static void buffy_free (BUFFY **mailbox)
- {
-+ if (mailbox && *mailbox)
-+ FREE (&(*mailbox)->desc);
- FREE (mailbox); /* __FREE_CHECKED__ */
- }
-
-@@ -377,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" */
-+
-+ while (MoreArgs (s))
-+ {
-+ char *desc;
-+
-+ mutt_extract_token (path, s, 0);
-+ if (path->data && *path->data)
-+ desc = safe_strdup( path->data);
-+ else
-+ continue;
-+
-+ 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,"vistual 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;
-+ }
-+ return 0;
-+}
-+#endif
-+
- /* returns 1 if maildir has new mail */
- static int buffy_maildir_hasnew (BUFFY* mailbox)
- {
-@@ -540,51 +594,13 @@
- }
- #endif
-
--int mutt_buffy_check (int force)
--{
-- BUFFY *tmp;
-- struct stat sb;
-- struct stat contex_sb;
-- time_t t;
--
-- sb.st_size=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 */
-- 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)
-+{
-+ struct stat sb;
-
--#ifdef USE_IMAP
-- BuffyCount += imap_buffy_check (force);
--#endif
-+ 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;
-- }
--
--#ifdef USE_SIDEBAR
-- int should_refresh = sb_should_refresh();
--#endif
-- for (tmp = Incoming; tmp; tmp = tmp->next)
-- {
- if (tmp->magic != M_IMAP)
- {
- tmp->new = 0;
-@@ -593,6 +609,11 @@
- tmp->magic = M_POP;
- else
- #endif
-+#ifdef USE_NOTMUCH
-+ if (mx_is_notmuch (tmp->path))
-+ tmp->magic = M_NOTMUCH;
-+ 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))
- {
-@@ -601,23 +622,23 @@
- 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 )
-+ (( tmp->magic == M_IMAP || tmp->magic == M_POP || tmp->magic == M_NOTMUCH)
- ? 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 (should_refresh)
-+ if (option(OPTSIDEBAR))
- buffy_mbox_update (tmp, &sb);
- #endif
- if (buffy_mbox_hasnew (tmp, &sb) > 0)
-@@ -626,7 +647,7 @@
-
- case M_MAILDIR:
- #ifdef USE_SIDEBAR
-- if (should_refresh)
-+ if (option(OPTSIDEBAR))
- buffy_maildir_update (tmp);
- #endif
- if (buffy_maildir_hasnew (tmp) > 0)
-@@ -635,15 +656,28 @@
-
- case M_MH:
- #ifdef USE_SIDEBAR
-- if (sb_should_refresh()) {
-+ if (option(OPTSIDEBAR))
- mh_buffy_update (tmp);
-- sb_set_update_time();
-- }
- #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
-+ sb_set_update_time();
-+#endif
-+ break;
-+#endif
- }
- }
- else if (option(OPTCHECKMBOXSIZE) && Context && Context->path)
-@@ -653,10 +687,65 @@
- tmp->notified = 0;
- else if (!tmp->notified)
- BuffyNotify++;
-+}
-+
-+int mutt_buffy_check (int force)
-+{
-+ BUFFY *tmp;
-+ struct stat contex_sb;
-+ time_t t;
-+
-+ 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;
-+
-+ BuffyTime = t;
-+ BuffyCount = 0;
-+ BuffyNotify = 0;
-+
-+#ifdef USE_IMAP
-+ BuffyCount += imap_buffy_check (force);
-+#endif
-+
-+ /* 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;
- }
-+
- #ifdef USE_SIDEBAR
-- if (should_refresh)
-- sb_set_update_time();
-+ if (sb_should_refresh()) {
-+ for (tmp = Incoming; tmp; tmp = tmp->next)
-+ buffy_check(tmp, &contex_sb);
-+ sb_set_update_time();
-+ }
-+#else
-+ for (tmp = Incoming; tmp; tmp = tmp->next)
-+ buffy_check(tmp, &contex_sb);
-+#endif
-+
-+#ifdef USE_NOTMUCH
-+ for (tmp = VirtIncoming; tmp; tmp = tmp->next)
-+ buffy_check(tmp, &contex_sb);
- #endif
-
- BuffyDoneTime = BuffyTime;
-@@ -773,6 +862,35 @@
- *s = '\0';
- }
-
-+#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 -urN mutt-1.6.1-sidebar-notmuch/buffy.h mutt-1.6.1-notmuch/buffy.h
---- mutt-1.6.1-sidebar-notmuch/buffy.h 2016-05-02 03:02:12.695176126 +0100
-+++ mutt-1.6.1-notmuch/buffy.h 2016-05-02 03:02:15.221216316 +0100
-@@ -26,18 +26,17 @@
- #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 */
--#ifdef USE_SIDEBAR
- 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 */
--#endif
- short notified; /* user has been notified */
- short magic; /* mailbox type */
- short newly_created; /* mbox or mmdf just popped into existence */
-@@ -51,6 +50,11 @@
- 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
-+
- extern time_t BuffyDoneTime; /* last time we knew for sure how much mail there was */
-
- BUFFY *mutt_find_mailbox (const char *path);
-diff -urN mutt-1.6.1-sidebar-notmuch/color.c mutt-1.6.1-notmuch/color.c
---- mutt-1.6.1-sidebar-notmuch/color.c 2016-05-02 03:02:12.704176269 +0100
-+++ mutt-1.6.1-notmuch/color.c 2016-05-02 03:02:15.120214709 +0100
-@@ -39,6 +39,9 @@
- 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;
-@@ -106,6 +109,10 @@
- { "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 },
-@@ -520,6 +527,10 @@
- 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))
- {
-@@ -765,7 +776,11 @@
- (object == MT_COLOR_INDEX) ||
- (object == MT_COLOR_INDEX_AUTHOR) ||
- (object == MT_COLOR_INDEX_FLAGS) ||
-- (object == MT_COLOR_INDEX_SUBJECT)) {
-+ (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;
-@@ -844,6 +859,14 @@
- 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)
-diff -urN mutt-1.6.1-sidebar-notmuch/commands.c mutt-1.6.1-notmuch/commands.c
---- mutt-1.6.1-sidebar-notmuch/commands.c 2016-05-02 03:02:12.705176285 +0100
-+++ mutt-1.6.1-notmuch/commands.c 2016-05-02 03:02:15.221216316 +0100
-@@ -40,6 +40,10 @@
- #include "imap.h"
- #endif
-
-+#ifdef USE_NOTMUCH
-+#include "mutt_notmuch.h"
-+#endif
-+
- #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);
-+
- if ((safe_fclose (&fpout) != 0 && errno != EPIPE) || res < 0)
- {
- mutt_error (_("Could not copy message"));
-@@ -846,19 +852,30 @@
- }
- else
- {
-+ int rc = 0;
-+
-+#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-sidebar-notmuch/compose.c mutt-1.6.1-notmuch/compose.c
---- mutt-1.6.1-sidebar-notmuch/compose.c 2016-05-02 03:02:12.705176285 +0100
-+++ mutt-1.6.1-notmuch/compose.c 2016-05-02 03:02:15.221216316 +0100
-@@ -692,7 +692,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;
-
-@@ -1237,7 +1238,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-sidebar-notmuch/configure.ac mutt-1.6.1-notmuch/configure.ac
---- mutt-1.6.1-sidebar-notmuch/configure.ac 2016-05-02 03:02:12.705176285 +0100
-+++ mutt-1.6.1-notmuch/configure.ac 2016-05-02 03:02:15.222216332 +0100
-@@ -184,6 +184,31 @@
- ])
- AM_CONDITIONAL(BUILD_SIDEBAR, test x$need_sidebar = xyes)
-
-+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"
-+
-+ 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)
-+
-+
- AC_ARG_WITH(mixmaster, AS_HELP_STRING([--with-mixmaster@<:@=PATH@:>@],[Include Mixmaster support]),
- [if test "$withval" != no
- then
-@@ -318,7 +343,7 @@
- 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)
-@@ -1075,6 +1100,7 @@
- AC_SUBST(MUTT_LIB_OBJECTS)
- AC_SUBST(LIBIMAP)
- AC_SUBST(LIBIMAPDEPS)
-+AC_SUBST(NOTMUCH_LIBS)
-
- dnl -- iconv/gettext --
-
-diff -urN mutt-1.6.1-sidebar-notmuch/copy.c mutt-1.6.1-notmuch/copy.c
---- mutt-1.6.1-sidebar-notmuch/copy.c 2016-05-02 03:02:12.705176285 +0100
-+++ mutt-1.6.1-notmuch/copy.c 2016-05-02 03:02:15.125214788 +0100
-@@ -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>
-@@ -334,6 +338,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 +352,7 @@
- if (h->env)
- flags |= (h->env->irt_changed ? CH_UPDATE_IRT : 0)
- | (h->env->refs_changed ? CH_UPDATE_REFS : 0);
--
-+
- if (mutt_copy_hdr (in, out, h->offset, h->content->offset, flags, prefix) == -1)
- return -1;
-
-@@ -413,6 +418,15 @@
- 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_NONEWLINE) == 0)
- {
- if (flags & CH_PREFIX)
-@@ -682,7 +696,7 @@
- {
- MESSAGE *msg;
- int r;
--
-+
- 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 +731,7 @@
- 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 +741,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
-+
- mx_close_message (&msg);
- return r;
- }
-diff -urN mutt-1.6.1-sidebar-notmuch/copy.h mutt-1.6.1-notmuch/copy.h
---- mutt-1.6.1-sidebar-notmuch/copy.h 2016-05-02 03:02:12.705176285 +0100
-+++ mutt-1.6.1-notmuch/copy.h 2016-05-02 03:02:15.125214788 +0100
-@@ -53,6 +53,7 @@
- #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 */
-
-
- int mutt_copy_hdr (FILE *, FILE *, LOFF_T, LOFF_T, int, const char *);
-diff -urN mutt-1.6.1-sidebar-notmuch/curs_lib.c mutt-1.6.1-notmuch/curs_lib.c
---- mutt-1.6.1-sidebar-notmuch/curs_lib.c 2016-05-02 03:02:12.706176301 +0100
-+++ mutt-1.6.1-notmuch/curs_lib.c 2016-05-02 03:02:15.126214804 +0100
-@@ -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.
-@@ -624,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;
-
-@@ -647,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);
-+
-+ _mutt_select_file (buf, blen, flags, files, numfiles);
- *redraw = REDRAW_FULL;
- }
- else
-@@ -662,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;
-diff -urN mutt-1.6.1-sidebar-notmuch/curs_main.c mutt-1.6.1-notmuch/curs_main.c
---- mutt-1.6.1-sidebar-notmuch/curs_main.c 2016-05-02 03:02:12.706176301 +0100
-+++ mutt-1.6.1-notmuch/curs_main.c 2016-05-02 03:02:15.222216332 +0100
-@@ -41,6 +41,10 @@
- #include "imap_private.h"
- #endif
-
-+#ifdef USE_NOTMUCH
-+#include "mutt_notmuch.h"
-+#endif
-+
- #include "mutt_crypt.h"
-
-
-@@ -590,6 +594,70 @@
- safe_free (&lineInfo.syntax);
- }
-
-+static int main_change_folder(MUTTMENU *menu, int op, char *buf, size_t bufsz,
-+ int *oldcount, int *index_hint)
-+{
-+ mutt_expand_path (buf, bufsz);
-+#ifdef USE_SIDEBAR
-+ 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);
-+
-+ /* 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;
-+ return 0;
-+ }
-+ 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);
-+
-+ return 0;
-+}
-+
- static const struct mapping_t IndexHelp[] = {
- { N_("Quit"), OP_QUIT },
- { N_("Del"), OP_DELETE },
-@@ -900,6 +968,11 @@
- mutt_curs_set (1); /* fallback from the pager */
- }
-
-+#ifdef USE_NOTMUCH
-+ if (Context)
-+ nm_debug_check(Context);
-+#endif
-+
- switch (op)
- {
-
-@@ -1309,6 +1382,131 @@
- }
- break;
-
-+#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;
-+
-+ 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);
-+ break;
-+
-+ case OP_MAIN_CHANGE_VFOLDER:
-+#endif
- #ifdef USE_SIDEBAR
- case OP_SIDEBAR_OPEN:
- #endif
-@@ -1324,7 +1522,11 @@
-
- if ((op == OP_MAIN_CHANGE_FOLDER_READONLY) || option (OPTREADONLY))
- 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';
-@@ -1339,6 +1541,20 @@
- 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
- {
- mutt_buffy (buf, sizeof (buf));
-@@ -1368,65 +1584,7 @@
- }
- }
-
-- mutt_expand_path (buf, sizeof (buf));
--#ifdef USE_SIDEBAR
-- if (sb_set_open_buffy (buf) == NULL)
-- break;
--#endif
-- 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);
-+ main_change_folder(menu, op, buf, sizeof (buf), &oldcount, &index_hint);
- break;
-
- case OP_DISPLAY_MESSAGE:
-@@ -2498,12 +2656,21 @@
- toggle_option (OPTSIDEBAR);
- menu->redraw = REDRAW_FULL;
- break;
-+
-+ case OP_SIDEBAR_TOGGLE_VIRTUAL:
-+ 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-sidebar-notmuch/doc/manual.xml.head mutt-1.6.1-notmuch/doc/manual.xml.head
---- mutt-1.6.1-sidebar-notmuch/doc/manual.xml.head 2016-05-02 03:02:12.709176349 +0100
-+++ mutt-1.6.1-notmuch/doc/manual.xml.head 2016-05-02 03:02:15.224216363 +0100
-@@ -8776,7 +8776,7 @@
- <listitem><para>mutt-1.5.24</para></listitem>
- </itemizedlist>
-
-- <para>This patch is part of the <ulink url="https://github.com/neomutt/neomutt/wiki">NeoMutt Project</ulink>.</para>
-+ <para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
- </sect2>
-
- <sect2 id="quasi-delete-intro">
-@@ -8859,7 +8859,7 @@
- <title>See Also</title>
-
- <itemizedlist>
-- <listitem><para><ulink url="https://github.com/neomutt/neomutt/wiki">NeoMutt Project</ulink></para></listitem>
-+ <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>
-@@ -8896,7 +8896,7 @@
- <listitem><para>mutt-1.5.24</para></listitem>
- </itemizedlist>
-
-- <para>This patch is part of the <ulink url="https://github.com/neomutt/neomutt/wiki">NeoMutt Project</ulink>.</para>
-+ <para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
- </sect2>
-
- <sect2 id="progress-intro">
-@@ -8975,7 +8975,7 @@
- <title>See Also</title>
-
- <itemizedlist>
-- <listitem><para><ulink url="https://github.com/neomutt/neomutt/wiki">NeoMutt Project</ulink></para></listitem>
-+ <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>
-@@ -9015,7 +9015,7 @@
- <listitem><para>mutt-1.5.24</para></listitem>
- </itemizedlist>
-
-- <para>This patch is part of the <ulink url="https://github.com/neomutt/neomutt/wiki">NeoMutt Project</ulink>.</para>
-+ <para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
- </sect2>
-
- <sect2 id="status-color-intro">
-@@ -9175,7 +9175,7 @@
- <title>See Also</title>
-
- <itemizedlist>
-- <listitem><para><ulink url="https://github.com/neomutt/neomutt/wiki">NeoMutt Project</ulink></para></listitem>
-+ <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>
-@@ -9219,7 +9219,7 @@
- <listitem><para><link linkend="status-color">status-color patch</link></para></listitem>
- </itemizedlist>
-
-- <para>This patch is part of the <ulink url="https://github.com/neomutt/neomutt/wiki">NeoMutt Project</ulink>.</para>
-+ <para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
- </sect2>
-
- <sect2 id="index-color-intro">
-@@ -9398,7 +9398,7 @@
- <title>See Also</title>
-
- <itemizedlist>
-- <listitem><para><ulink url="https://github.com/neomutt/neomutt/wiki">NeoMutt Project</ulink></para></listitem>
-+ <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>
-@@ -9444,7 +9444,7 @@
- <listitem><para>mutt-1.5.24</para></listitem>
- </itemizedlist>
-
-- <para>This patch is part of the <ulink url="https://github.com/neomutt/neomutt/wiki">NeoMutt Project</ulink>.</para>
-+ <para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
- </sect2>
-
- <sect2 id="nested-if-intro">
-@@ -9621,7 +9621,7 @@
- <title>See Also</title>
-
- <itemizedlist>
-- <listitem><para><ulink url="https://github.com/neomutt/neomutt/wiki">NeoMutt Project</ulink></para></listitem>
-+ <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>
-@@ -9662,7 +9662,7 @@
- </itemizedlist>
-
- <para>
-- This patch is part of the <ulink url="https://github.com/neomutt/neomutt/wiki">NeoMutt Project</ulink>.
-+ This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.
- </para>
- </sect2>
-
-@@ -10019,7 +10019,7 @@
- <title>See Also</title>
-
- <itemizedlist>
-- <listitem><para><ulink url="https://github.com/neomutt/neomutt/wiki">NeoMutt Project</ulink></para></listitem>
-+ <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>
-@@ -10068,7 +10068,7 @@
- <listitem><para>OpenSSL</para></listitem>
- </itemizedlist>
-
-- <para>This patch is part of the <ulink url="https://github.com/neomutt/neomutt/wiki">NeoMutt Project</ulink>.</para>
-+ <para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
- </sect2>
-
- <sect2 id="tls-sni-intro">
-@@ -10137,7 +10137,7 @@
- <title>See Also</title>
-
- <itemizedlist>
-- <listitem><para><ulink url="https://github.com/neomutt/neomutt/wiki">NeoMutt Project</ulink></para></listitem>
-+ <listitem><para><ulink url="http://www.neomutt.org/">NeoMutt Project</ulink></para></listitem>
- </itemizedlist>
- </sect2>
-
-@@ -10174,7 +10174,7 @@
- <listitem><para>mutt-1.5.24</para></listitem>
- </itemizedlist>
-
-- <para>This patch is part of the <ulink url="https://github.com/neomutt/neomutt/wiki">NeoMutt Project</ulink>.</para>
-+ <para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
- </sect2>
-
- <sect2 id="sidebar-intro">
-diff -urN mutt-1.6.1-sidebar-notmuch/enter.c mutt-1.6.1-notmuch/enter.c
---- mutt-1.6.1-sidebar-notmuch/enter.c 2016-05-02 03:02:12.709176349 +0100
-+++ mutt-1.6.1-notmuch/enter.c 2016-05-02 03:02:15.132214900 +0100
-@@ -630,6 +630,27 @@
- 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 ();
-+
-+ 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 ();
-+
-+ replace_part (state, 0, buf);
-+ }
-+
-+#endif
- else
- goto self_insert;
- break;
-diff -urN mutt-1.6.1-sidebar-notmuch/functions.h mutt-1.6.1-notmuch/functions.h
---- mutt-1.6.1-sidebar-notmuch/functions.h 2016-05-02 03:02:12.709176349 +0100
-+++ mutt-1.6.1-notmuch/functions.h 2016-05-02 03:02:15.225216379 +0100
-@@ -177,9 +177,17 @@
- { "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 }
- };
-
-@@ -292,9 +300,18 @@
- { "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 }
- };
-
-diff -urN mutt-1.6.1-sidebar-notmuch/globals.h mutt-1.6.1-notmuch/globals.h
---- mutt-1.6.1-sidebar-notmuch/globals.h 2016-05-02 03:02:12.709176349 +0100
-+++ mutt-1.6.1-notmuch/globals.h 2016-05-02 03:02:15.225216379 +0100
-@@ -161,6 +161,10 @@
-
- WHERE HASH *Groups;
- WHERE HASH *ReverseAlias;
-+#ifdef USE_NOTMUCH
-+WHERE HASH *TagTransforms;
-+WHERE HASH *TagFormats;
-+#endif
-
- WHERE LIST *AutoViewList INITVAL(0);
- WHERE LIST *AlternativeOrderList INITVAL(0);
-@@ -281,6 +285,17 @@
- 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 -urN mutt-1.6.1-sidebar-notmuch/hdrline.c mutt-1.6.1-notmuch/hdrline.c
---- mutt-1.6.1-sidebar-notmuch/hdrline.c 2016-05-02 03:02:12.710176365 +0100
-+++ mutt-1.6.1-notmuch/hdrline.c 2016-05-02 03:02:15.226216395 +0100
-@@ -36,6 +36,10 @@
- #include <alloca.h>
- #endif
-
-+#ifdef USE_NOTMUCH
-+#include "mutt_notmuch.h"
-+#endif
-+
- int mutt_is_mail_list (ADDRESS *addr)
- {
- if (!mutt_match_rx_list (addr->mailbox, UnMailLists))
-@@ -243,6 +247,7 @@
- * %E = number of messages in current thread
- * %f = entire from line
- * %F = like %n, unless from self
-+ * %g = message labels (e.g. notmuch tags)
- * %i = message-id
- * %l = number of lines in the message
- * %L = like %F, except `lists' are displayed first
-@@ -585,6 +590,19 @@
- optional = 0;
- break;
-
-+#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
-+
- case 'H':
- /* (Hormel) spam score */
- if (optional)
-@@ -892,6 +910,48 @@
-
- break;
-
-+#ifdef USE_NOTMUCH
-+ case 'G':
-+ {
-+ char *tag_transformed;
-+ char format[3];
-+ char *tag;
-+
-+ 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
-+ {
-+ 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;
-+ }
-+
-+ break;
-+ }
-+#endif
-+
- default:
- snprintf (dest, destlen, "%%%s%c", prefix, op);
- break;
-diff -urN mutt-1.6.1-sidebar-notmuch/init.c mutt-1.6.1-notmuch/init.c
---- mutt-1.6.1-sidebar-notmuch/init.c 2016-05-02 03:02:12.711176381 +0100
-+++ mutt-1.6.1-notmuch/init.c 2016-05-02 03:02:15.227216411 +0100
-@@ -37,7 +37,9 @@
- #include "mutt_ssl.h"
- #endif
-
--
-+#if USE_NOTMUCH
-+#include "mutt_notmuch.h"
-+#endif
-
- #include "mx.h"
- #include "init.h"
-@@ -76,6 +78,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;
-+#endif
-+
-+
- static void toggle_quadoption (int opt)
- {
- int n = opt/4;
-@@ -2636,6 +2644,182 @@
- return 0;
- }
-
-+#if USE_NOTMUCH
-+
-+/* 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;
-+
-+ Num_matched = 0;
-+ strfcpy (User_typed, pt, sizeof (User_typed));
-+ memset (Matches, 0, Matches_listsize);
-+ memset (Completed, 0, sizeof (Completed));
-+
-+ nm_longrun_init(Context, FALSE);
-+
-+ /* 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;
-+
-+ /* 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;
-+ }
-+
-+ /* 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;
-+}
-+
-+/* 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)
-+{
-+ int needle_length = strlen(needle);
-+ const char* haystack_end = haystack + haystack_length - needle_length;
-+ const char* p;
-+
-+ 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;
-+
-+ next:;
-+ }
-+ return NULL;
-+}
-+
-+/* Complete the nearest "tag:"-prefixed string previous to pos. */
-+int mutt_nm_query_complete (char *buffer, size_t len, int pos, int numtabs)
-+{
-+ char *pt = buffer;
-+ int spaces;
-+
-+ SKIPWS (buffer);
-+ spaces = buffer - pt;
-+
-+ 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);
-+
-+ /* 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 (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);
-+ }
-+ 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)
-+ {
-+ /* 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;
-+ }
-+
-+ 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);
-+ }
-+ else
-+ return 0;
-+
-+ return 1;
-+}
-+#endif
-+
- static int var_to_string (int idx, char* val, size_t len)
- {
- char tmp[LONG_STRING];
-@@ -2886,7 +3070,11 @@
-
- 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 ();
-
- snprintf (AttachmentMarker, sizeof (AttachmentMarker),
-@@ -3170,6 +3358,11 @@
-
- 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
-@@ -3217,6 +3410,70 @@
- return -1;
- }
-
-+#ifdef USE_NOTMUCH
-+int parse_tag_transforms (BUFFER *b, BUFFER *s, unsigned long data, BUFFER *err)
-+{
-+ char *tmp;
-+
-+ while (MoreArgs (s))
-+ {
-+ char *tag, *transform;
-+
-+ mutt_extract_token (b, s, 0);
-+ if (b->data && *b->data)
-+ tag = safe_strdup (b->data);
-+ else
-+ continue;
-+
-+ 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;
-+ }
-+
-+ hash_insert(TagTransforms, tag, transform, 0);
-+ }
-+ return 0;
-+}
-+
-+int parse_tag_formats (BUFFER *b, BUFFER *s, unsigned long data, BUFFER *err)
-+{
-+ char *tmp;
-+
-+ while (MoreArgs (s))
-+ {
-+ char *tag, *format;
-+
-+ mutt_extract_token (b, s, 0);
-+ if (b->data && *b->data)
-+ tag = safe_strdup (b->data);
-+ else
-+ continue;
-+
-+ mutt_extract_token (b, s, 0);
-+ format = safe_strdup (b->data);
-+
-+ /* 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;
-+ }
-+
-+ hash_insert(TagFormats, format, tag, 0);
-+ }
-+ return 0;
-+}
-+#endif
-+
- static void myvar_set (const char* var, const char* val)
- {
- myvar_t** cur;
-diff -urN mutt-1.6.1-sidebar-notmuch/init.h mutt-1.6.1-notmuch/init.h
---- mutt-1.6.1-sidebar-notmuch/init.h 2016-05-02 03:02:12.713176413 +0100
-+++ mutt-1.6.1-notmuch/init.h 2016-05-02 03:02:15.228216427 +0100
-@@ -1316,6 +1316,7 @@
- ** .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 %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,
-@@ -1668,6 +1669,60 @@
- ** See also $$read_inc, $$write_inc and $$net_inc.
- */
- #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.
-+ */
-+
-+ { "nm_default_uri", DT_STR, R_NONE, UL &NotmuchDefaultUri, 0 },
-+ /*
-+ ** .pp
-+ ** This variable specifies the default Notmuch database in format
-+ ** notmuch://<absolute path>.
-+ */
-+
-+ { "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
-@@ -3207,14 +3262,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 "," },
- /*
-@@ -3657,6 +3713,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
-@@ -3807,6 +3888,7 @@
-
- const struct mapping_t SortSidebarMethods[] = {
- { "count", SORT_COUNT },
-+ { "desc", SORT_DESC },
- { "flagged", SORT_FLAGGED },
- { "new", SORT_COUNT_NEW },
- { "path", SORT_PATH },
-@@ -3840,13 +3922,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
- {
-@@ -3887,6 +3972,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 },
-diff -urN mutt-1.6.1-sidebar-notmuch/mailbox.h mutt-1.6.1-notmuch/mailbox.h
---- mutt-1.6.1-sidebar-notmuch/mailbox.h 2016-05-02 03:02:12.713176413 +0100
-+++ mutt-1.6.1-notmuch/mailbox.h 2016-05-02 03:02:15.143215075 +0100
-@@ -48,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 {
-diff -urN mutt-1.6.1-sidebar-notmuch/main.c mutt-1.6.1-notmuch/main.c
---- mutt-1.6.1-sidebar-notmuch/main.c 2016-05-02 03:02:12.713176413 +0100
-+++ mutt-1.6.1-notmuch/main.c 2016-05-02 03:02:15.228216427 +0100
-@@ -494,6 +494,12 @@
- "-USE_SIDEBAR "
- #endif
-
-+#if USE_NOTMUCH
-+ "+NOTMUCH "
-+#else
-+ "-NOTMUCH "
-+#endif
-+
- );
-
- #ifdef ISPELL
-diff -urN mutt-1.6.1-sidebar-notmuch/Makefile.am mutt-1.6.1-notmuch/Makefile.am
---- mutt-1.6.1-sidebar-notmuch/Makefile.am 2016-05-02 03:02:12.689176031 +0100
-+++ mutt-1.6.1-notmuch/Makefile.am 2016-05-02 03:02:15.216216236 +0100
-@@ -83,6 +83,16 @@
-
- EXTRA_DIST += OPS.SIDEBAR
-
-+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
-+
-+
-+
- mutt_dotlock_SOURCES = mutt_dotlock.c
- mutt_dotlock_LDADD = $(LIBOBJS)
- mutt_dotlock_DEPENDENCIES = $(LIBOBJS)
-@@ -135,9 +145,9 @@
- keymap_defs.h: $(OPS) $(srcdir)/gen_defs
- $(srcdir)/gen_defs $(OPS) > keymap_defs.h
-
--keymap_alldefs.h: $(srcdir)/OPS $(srcdir)/OPS.SIDEBAR $(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.NOTMUCH $(srcdir)/OPS.PGP \
- $(srcdir)/OPS.SIDEBAR $(srcdir)/OPS.MIX $(srcdir)/OPS.CRYPT $(srcdir)/OPS.SMIME \
- > keymap_alldefs.h
-
-diff -urN mutt-1.6.1-sidebar-notmuch/menu.c mutt-1.6.1-notmuch/menu.c
---- mutt-1.6.1-sidebar-notmuch/menu.c 2016-05-02 03:02:12.713176413 +0100
-+++ mutt-1.6.1-notmuch/menu.c 2016-05-02 03:02:15.144215090 +0100
-@@ -50,6 +50,17 @@
- 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];
- }
-diff -urN mutt-1.6.1-sidebar-notmuch/mh.c mutt-1.6.1-notmuch/mh.c
---- mutt-1.6.1-sidebar-notmuch/mh.c 2016-05-02 03:02:12.713176413 +0100
-+++ mutt-1.6.1-notmuch/mh.c 2016-05-02 03:02:15.144215090 +0100
-@@ -56,6 +56,10 @@
- #include <sys/time.h>
- #endif
-
-+#ifdef USE_NOTMUCH
-+#include "mutt_notmuch.h"
-+#endif
-+
- #define INS_SORT_THRESHOLD 6
-
- struct maildir
-@@ -653,7 +657,7 @@
- }
- }
-
--static void maildir_parse_flags (HEADER * h, const char *path)
-+void maildir_parse_flags (HEADER * h, const char *path)
- {
- char *p, *q = NULL;
-
-@@ -736,40 +740,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);
-
-- 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)
-+ {
-+ /*
-+ * 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 h;
-+}
-+
-+/*
-+ * 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;
-+
-+ if ((f = fopen (fname, "r")) != NULL) {
-+ h = maildir_parse_stream (magic, f, fname, is_old, h);
-+ safe_fclose (&f);
- return h;
- }
- return NULL;
-@@ -1292,7 +1307,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';
-
-@@ -1452,10 +1467,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
-@@ -1471,11 +1482,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);
-+
- return 0;
-+
-+post_rename_err:
-+ return -1;
- }
- else if (errno != EEXIST)
- {
-@@ -1551,6 +1574,7 @@
- {
- if (hdr)
- mutt_str_replace (&hdr->path, tmp);
-+ mutt_str_replace (&msg->commited_path, path);
- FREE (&msg->path);
- break;
- }
-@@ -1726,96 +1750,113 @@
- 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 ||
- (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;
-+}
-+
-+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;
-+
-+ 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);
-+
-+#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
-@@ -1894,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.
-@@ -2197,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];
-@@ -2233,11 +2274,15 @@
-
- closedir (dp);
-
-+ if (newname && fp)
-+ *newname = safe_strdup(fname);
-+
- 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;
-@@ -2249,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)
-@@ -2263,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-sidebar-notmuch/mutt_curses.h mutt-1.6.1-notmuch/mutt_curses.h
---- mutt-1.6.1-sidebar-notmuch/mutt_curses.h 2016-05-02 03:02:12.714176428 +0100
-+++ mutt-1.6.1-notmuch/mutt_curses.h 2016-05-02 03:02:15.144215090 +0100
-@@ -136,6 +136,9 @@
- 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,
-@@ -146,6 +149,9 @@
- MT_COLOR_INDEX_LABEL,
- MT_COLOR_INDEX_NUMBER,
- MT_COLOR_INDEX_SIZE,
-+#ifdef USE_NOTMUCH
-+ MT_COLOR_INDEX_TAGS,
-+#endif
- MT_COLOR_MAX
- };
-
-@@ -204,6 +210,9 @@
- 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-sidebar-notmuch/mutt.h mutt-1.6.1-notmuch/mutt.h
---- mutt-1.6.1-sidebar-notmuch/mutt.h 2016-05-02 03:02:12.714176428 +0100
-+++ mutt-1.6.1-notmuch/mutt.h 2016-05-02 03:02:15.228216427 +0100
-@@ -101,6 +101,10 @@
- #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 */
-+#if USE_NOTMUCH
-+#define M_NM_QUERY (1<<8) /* Notmuch query mode. */
-+#define M_NM_TAG (1<<9) /* Notmuch tag +/- mode. */
-+#endif
-
- /* flags for mutt_get_token() */
- #define M_TOKEN_EQUAL 1 /* treat '=' as a special */
-@@ -238,6 +242,9 @@
- M_CRYPT_ENCRYPT,
- M_PGP_KEY,
- M_XLABEL,
-+#ifdef USE_NOTMUCH
-+ M_NOTMUCH_LABEL,
-+#endif
- M_MIMEATTACH,
-
- /* Options for Mailcap lookup */
-@@ -321,6 +328,7 @@
- #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
-@@ -543,6 +551,11 @@
- OPTDONTHANDLEPGPKEYS, /* (pseudo) used to extract PGP keys */
- OPTIGNOREMACROEVENTS, /* (pseudo) don't process macro/push/exec events while set */
-
-+#ifdef USE_NOTMUCH
-+ OPTVIRTSPOOLFILE,
-+ OPTNOTMUCHRECORD,
-+#endif
-+
- OPTMAX
- };
-
-@@ -807,8 +820,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
- void *data; /* driver-specific data */
-+ void (*free_cb)(struct header *); /* driver-specific data free function */
- #endif
-
- char *maildir_flags; /* unknown maildir flags */
-diff -urN mutt-1.6.1-sidebar-notmuch/muttlib.c mutt-1.6.1-notmuch/muttlib.c
---- mutt-1.6.1-sidebar-notmuch/muttlib.c 2016-05-02 03:02:12.715176444 +0100
-+++ mutt-1.6.1-notmuch/muttlib.c 2016-05-02 03:02:15.229216443 +0100
-@@ -32,12 +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>
-@@ -330,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
-+ if ((*h)->free_cb)
-+ (*h)->free_cb(*h);
- FREE (&(*h)->data);
- #endif
- FREE (h); /* __FREE_CHECKED__ */
-@@ -441,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
-@@ -887,6 +900,11 @@
- }
- #endif
-
-+#ifdef USE_NOTMUCH
-+ if (scheme == U_NOTMUCH)
-+ return;
-+#endif
-+
- /* if s is an url, only collapse path component */
- if (scheme != U_UNKNOWN)
- {
-diff -urN mutt-1.6.1-sidebar-notmuch/mutt_notmuch.c mutt-1.6.1-notmuch/mutt_notmuch.c
---- mutt-1.6.1-sidebar-notmuch/mutt_notmuch.c 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-notmuch/mutt_notmuch.c 2016-05-02 03:02:15.145215107 +0100
-@@ -0,0 +1,1941 @@
-+/*
-+ * 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
-+
-+#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"
-+
-+#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>
-+
-+#include <notmuch.h>
-+
-+#include "mutt_notmuch.h"
-+#include "mutt_curses.h"
-+
-+/* read whole-thread or matching messages only? */
-+enum {
-+ NM_QUERY_TYPE_MESGS = 1, /* default */
-+ NM_QUERY_TYPE_THREADS
-+};
-+
-+/*
-+ * Parsed URI arguments
-+ */
-+struct uri_tag {
-+ char *name;
-+ char *value;
-+ struct uri_tag *next;
-+};
-+
-+/*
-+ * HEADER->(nm_hdrdata *)data->tag_list node
-+ */
-+struct nm_hdrtag
-+{
-+ char *tag;
-+ char *transformed;
-+ struct nm_hdrtag *next;
-+};
-+
-+/*
-+ * HEADER->data
-+ */
-+struct nm_hdrdata {
-+ char *folder;
-+ char *tags;
-+ char *tags_transformed;
-+ struct nm_hdrtag *tag_list;
-+ char *oldpath;
-+ char *virtual_id;
-+ int magic;
-+};
-+
-+/*
-+ * CONTEXT->data
-+ */
-+struct nm_ctxdata {
-+ notmuch_database_t *db;
-+
-+ char *db_filename;
-+ char *db_query;
-+ int db_limit;
-+ int query_type;
-+
-+ struct uri_tag *query_items;
-+
-+ progress_t progress;
-+ int oldmsgcount;
-+ int ignmsgcount; /* ingored messages */
-+
-+ unsigned int noprogress : 1,
-+ longrun : 1,
-+ trans : 1,
-+ progress_ready : 1;
-+
-+};
-+
-+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;
-+ }
-+}
-+
-+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;
-+
-+ *filename = NULL;
-+ *tags = NULL;
-+
-+ if (!p || !*(p + 3))
-+ return -1;
-+
-+ p += 3;
-+ *filename = p;
-+
-+ e = strchr(p, '?');
-+
-+ *filename = e ? e == p ? NULL : strndup(p, e - p) : safe_strdup(p);
-+ if (!e)
-+ return 0;
-+
-+ if (*filename && url_pct_decode(*filename) < 0)
-+ goto err;
-+ if (!e)
-+ return 0; /* only filename */
-+
-+ ++e; /* skip '?' */
-+ p = e;
-+
-+ while (p && *p) {
-+ tag = safe_calloc(1, sizeof(struct uri_tag));
-+ if (!tag)
-+ goto err;
-+
-+ 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;
-+
-+ 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;
-+ }
-+
-+ return 0;
-+err:
-+ FREE(&(*filename));
-+ url_free_tags(*tags);
-+ return -1;
-+}
-+
-+static void free_tag_list(struct nm_hdrtag **tag_list)
-+{
-+ struct nm_hdrtag *tmp;
-+
-+ while ((tmp = *tag_list) != NULL)
-+ {
-+ *tag_list = tmp->next;
-+ FREE(&tmp->tag);
-+ FREE(&tmp->transformed);
-+ FREE(&tmp);
-+ }
-+
-+ *tag_list = 0;
-+}
-+
-+static void free_hdrdata(struct nm_hdrdata *data)
-+{
-+ if (!data)
-+ return;
-+
-+ 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);
-+}
-+
-+static void free_ctxdata(struct nm_ctxdata *data)
-+{
-+ if (!data)
-+ return;
-+
-+ dprint(1, (debugfile, "nm: freeing context data %p\n", data));
-+
-+ if (data->db)
-+#ifdef NOTMUCH_API_3
-+ notmuch_database_destroy(data->db);
-+#else
-+ notmuch_database_close(data->db);
-+#endif
-+ data->db = NULL;
-+
-+ FREE(&data->db_filename);
-+ FREE(&data->db_query);
-+ url_free_tags(data->query_items);
-+ FREE(&data);
-+}
-+
-+static struct nm_ctxdata *new_ctxdata(char *uri)
-+{
-+ struct nm_ctxdata *data;
-+
-+ if (!uri)
-+ return NULL;
-+
-+ data = safe_calloc(1, sizeof(struct nm_ctxdata));
-+ dprint(1, (debugfile, "nm: initialize context data %p\n", data));
-+
-+ data->db_limit = NotmuchDBLimit;
-+
-+ 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;
-+ }
-+
-+ return data;
-+}
-+
-+static int deinit_context(CONTEXT *ctx)
-+{
-+ int i;
-+
-+ if (!ctx || ctx->magic != M_NOTMUCH)
-+ return -1;
-+
-+ for (i = 0; i < ctx->msgcount; i++) {
-+ HEADER *h = ctx->hdrs[i];
-+
-+ if (h) {
-+ free_hdrdata(h->data);
-+ h->data = NULL;
-+ }
-+ }
-+
-+ free_ctxdata(ctx->data);
-+ ctx->data = NULL;
-+ return 0;
-+}
-+
-+static int init_context(CONTEXT *ctx)
-+{
-+ if (!ctx || ctx->magic != M_NOTMUCH)
-+ return -1;
-+
-+ if (ctx->data)
-+ return 0;
-+
-+ ctx->data = new_ctxdata(ctx->path);
-+ if (!ctx->data)
-+ return -1;
-+
-+ ctx->mx_close = deinit_context;
-+ return 0;
-+}
-+
-+char *nm_header_get_folder(HEADER *h)
-+{
-+ return h && h->data ? ((struct nm_hdrdata *) h->data)->folder : NULL;
-+}
-+
-+/* returns all unhidden tags */
-+char *nm_header_get_tags(HEADER *h)
-+{
-+ return h && h->data ? ((struct nm_hdrdata *) h->data)->tags : NULL;
-+}
-+
-+char *nm_header_get_tags_transformed(HEADER *h)
-+{
-+ return h && h->data ? ((struct nm_hdrdata *) h->data)->tags_transformed : NULL;
-+}
-+
-+char *nm_header_get_tag_transformed(char *tag, HEADER *h)
-+{
-+ struct nm_hdrtag *tmp;
-+
-+ if (!h || !h->data)
-+ return NULL;
-+
-+ for (tmp = ((struct nm_hdrdata *) h->data)->tag_list;
-+ tmp != NULL;
-+ tmp = tmp->next)
-+ {
-+ if (strcmp(tag, tmp->tag) == 0)
-+ return tmp->transformed;
-+ }
-+
-+ return NULL;
-+}
-+
-+int nm_header_get_magic(HEADER *h)
-+{
-+ return h && h->data ? ((struct nm_hdrdata *) h->data)->magic : 0;
-+}
-+
-+/*
-+ * Returns notmuch message Id.
-+ */
-+static char *nm_header_get_id(HEADER *h)
-+{
-+ return h && h->data ? ((struct nm_hdrdata *) h->data)->virtual_id : NULL;
-+}
-+
-+
-+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;
-+}
-+
-+
-+static struct nm_ctxdata *get_ctxdata(CONTEXT *ctx)
-+{
-+ if (ctx && ctx->magic == M_NOTMUCH)
-+ return ctx->data;
-+
-+ return NULL;
-+}
-+
-+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;
-+}
-+
-+static char *get_query_string(struct nm_ctxdata *data)
-+{
-+ struct uri_tag *item;
-+
-+ if (!data)
-+ return NULL;
-+ if (data->db_query)
-+ return data->db_query;
-+
-+ for (item = data->query_items; item; item = item->next) {
-+ if (!item->value || !item->name)
-+ continue;
-+
-+ if (strcmp(item->name, "limit") == 0) {
-+ if (mutt_atoi(item->value, &data->db_limit))
-+ mutt_error (_("failed to parse notmuch limit: %s"), item->value);
-+
-+ } else if (strcmp(item->name, "type") == 0)
-+ data->query_type = string_to_guery_type(item->value);
-+
-+ else if (strcmp(item->name, "query") == 0)
-+ data->db_query = safe_strdup(item->value);
-+ }
-+
-+ if (!data->query_type)
-+ data->query_type = string_to_guery_type(NULL);
-+
-+ dprint(2, (debugfile, "nm: query '%s'\n", data->db_query));
-+
-+ return data->db_query;
-+}
-+
-+static int get_limit(struct nm_ctxdata *data)
-+{
-+ return data ? data->db_limit : 0;
-+}
-+
-+static int get_query_type(struct nm_ctxdata *data)
-+{
-+ return (data && data->query_type) ? data->query_type : string_to_guery_type(NULL);
-+}
-+
-+static const char *get_db_filename(struct nm_ctxdata *data)
-+{
-+ char *db_filename;
-+
-+ if (!data)
-+ return NULL;
-+
-+ 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;
-+}
-+
-+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;
-+
-+ 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;
-+
-+ if (verbose && ct && ct % 2 == 0)
-+ mutt_error(_("Waiting for notmuch DB... (%d sec)"), ct / 2);
-+ usleep(500000);
-+ ct++;
-+ } while (1);
-+
-+ 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;
-+}
-+
-+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);
-+
-+ if (db_filename)
-+ data->db = do_database_open(db_filename, writable, TRUE);
-+ }
-+ return data->db;
-+}
-+
-+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;
-+ }
-+
-+ return -1;
-+}
-+
-+/* 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;
-+
-+ 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;
-+}
-+
-+static int db_trans_end(struct nm_ctxdata *data)
-+{
-+ if (!data || !data->db)
-+ return -1;
-+
-+ if (data->trans) {
-+ dprint(2, (debugfile, "nm: db trans end\n"));
-+ data->trans = 0;
-+ if (notmuch_database_end_atomic(data->db))
-+ return -1;
-+ }
-+
-+ return 0;
-+}
-+
-+void nm_longrun_init(CONTEXT *ctx, int writable)
-+{
-+ struct nm_ctxdata *data = get_ctxdata(ctx);
-+
-+ if (data && get_db(data, writable)) {
-+ data->longrun = 1;
-+ dprint(2, (debugfile, "nm: long run initialized\n"));
-+ }
-+}
-+
-+void nm_longrun_done(CONTEXT *ctx)
-+{
-+ struct nm_ctxdata *data = get_ctxdata(ctx);
-+
-+ if (data && release_db(data) == 0)
-+ dprint(2, (debugfile, "nm: long run deinitialized\n"));
-+}
-+
-+static int is_longrun(struct nm_ctxdata *data)
-+{
-+ return data && data->longrun;
-+}
-+
-+void nm_debug_check(CONTEXT *ctx)
-+{
-+ struct nm_ctxdata *data = get_ctxdata(ctx);
-+
-+ if (!data)
-+ return;
-+
-+ if (data->db) {
-+ dprint(1, (debugfile, "nm: ERROR: db is open, closing\n"));
-+ release_db(data);
-+ }
-+}
-+
-+static int get_database_mtime(struct nm_ctxdata *data, time_t *mtime)
-+{
-+ char path[_POSIX_PATH_MAX];
-+ struct stat st;
-+
-+ if (!data)
-+ return -1;
-+
-+ snprintf(path, sizeof(path), "%s/.notmuch/xapian", get_db_filename(data));
-+ dprint(2, (debugfile, "nm: checking '%s' mtime\n", path));
-+
-+ if (stat(path, &st))
-+ return -1;
-+
-+ if (mtime)
-+ *mtime = st.st_mtime;
-+
-+ return 0;
-+}
-+
-+static void apply_exclude_tags(notmuch_query_t *query)
-+{
-+ char *buf, *p, *end = NULL, *tag = NULL;
-+
-+ if (!NotmuchExcludeTags || !*NotmuchExcludeTags)
-+ return;
-+ buf = safe_strdup(NotmuchExcludeTags);
-+
-+ 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';
-+
-+ 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);
-+}
-+
-+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;
-+
-+ if (!data)
-+ return NULL;
-+
-+ db = get_db(data, writable);
-+ str = get_query_string(data);
-+
-+ if (!db || !str)
-+ goto err;
-+
-+ q = notmuch_query_create(db, str);
-+ if (!q)
-+ goto err;
-+
-+ 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;
-+}
-+
-+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;
-+
-+ safe_realloc(str, ssz + (ssz && sep ? 1 : 0) + sz + 1);
-+ p = *str + ssz;
-+ if (sep && ssz)
-+ *p++ = sep;
-+ memcpy(p, item, sz + 1);
-+}
-+
-+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;
-+
-+ dprint(2, (debugfile, "nm: tags update requested (%s)\n", data->virtual_id));
-+
-+ for (tags = notmuch_message_get_tags(msg);
-+ tags && notmuch_tags_valid(tags);
-+ notmuch_tags_move_to_next(tags)) {
-+
-+ const char *t = notmuch_tags_get(tags);
-+ const char *tt = NULL;
-+
-+ if (!t || !*t)
-+ continue;
-+
-+ tt = hash_find(TagTransforms, t);
-+ if (!tt)
-+ tt = t;
-+
-+ /* 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;
-+
-+ /* filter out hidden tags */
-+ if (NotmuchHiddenTags) {
-+ char *p = strstr(NotmuchHiddenTags, t);
-+ size_t xsz = p ? strlen(t) : 0;
-+
-+ 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, ' ');
-+
-+ /* expand the un-transformed tag string */
-+ append_str_item(&tstr, t, ' ');
-+ }
-+
-+ free_tag_list(&data->tag_list);
-+ data->tag_list = tag_list;
-+
-+ if (data->tags && tstr && strcmp(data->tags, tstr) == 0) {
-+ FREE(&tstr);
-+ FREE(&ttstr);
-+ dprint(2, (debugfile, "nm: tags unchanged\n"));
-+ return 1;
-+ }
-+
-+ /* 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;
-+}
-+
-+/*
-+ * 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;
-+
-+ dprint(2, (debugfile, "nm: path update requested path=%s, (%s)\n",
-+ path, data->virtual_id));
-+
-+ 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)) {
-+
-+ data->magic = M_MAILDIR;
-+
-+ FREE(&h->path);
-+ FREE(&data->folder);
-+
-+ p -= 3; /* skip subfolder (e.g. "new") */
-+ h->path = safe_strdup(p);
-+
-+ for (; p > path && *(p - 1) == '/'; p--);
-+
-+ data->folder = strndup(path, p - path);
-+
-+ dprint(2, (debugfile, "nm: folder='%s', file='%s'\n", data->folder, h->path));
-+ return 0;
-+ }
-+
-+ return 1;
-+}
-+
-+static char *get_folder_from_path(const char *path)
-+{
-+ char *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)) {
-+
-+ 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;
-+ }
-+}
-+
-+/* converts notmuch message Id to mutt message <Id> */
-+static char *nm2mutt_message_id(const char *id)
-+{
-+ size_t sz;
-+ char *mid;
-+
-+ if (!id)
-+ return NULL;
-+ sz = strlen(id) + 3;
-+ mid = safe_malloc(sz);
-+
-+ snprintf(mid, sz, "<%s>", id);
-+ return mid;
-+}
-+
-+static int init_header(HEADER *h, const char *path, notmuch_message_t *msg)
-+{
-+ const char *id;
-+
-+ if (h->data)
-+ return 0;
-+
-+ id = notmuch_message_get_message_id(msg);
-+
-+ h->data = safe_calloc(1, sizeof(struct nm_hdrdata));
-+ h->free_cb = deinit_header;
-+
-+ /*
-+ * 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 );
-+
-+ dprint(2, (debugfile, "nm: initialize header data: [hdr=%p, data=%p] (%s)\n",
-+ h, h->data, id));
-+
-+ if (!h->env->message_id)
-+ h->env->message_id = nm2mutt_message_id( id );
-+
-+ if (update_message_path(h, path))
-+ return -1;
-+
-+ update_header_tags(h, msg);
-+
-+ return 0;
-+}
-+
-+/**
-+static void debug_print_filenames(notmuch_message_t *msg)
-+{
-+ notmuch_filenames_t *ls;
-+ const char *id = notmuch_message_get_message_id(msg);
-+
-+ for (ls = notmuch_message_get_filenames(msg);
-+ ls && notmuch_filenames_valid(ls);
-+ notmuch_filenames_move_to_next(ls)) {
-+
-+ dprint(2, (debugfile, "nm: %s: %s\n", id, notmuch_filenames_get(ls)));
-+ }
-+}
-+
-+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)));
-+ }
-+}
-+***/
-+
-+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)) {
-+
-+ name = notmuch_filenames_get(ls);
-+ }
-+
-+ return name;
-+}
-+
-+static void nm_progress_reset(CONTEXT *ctx)
-+{
-+ struct nm_ctxdata *data;
-+
-+ if (ctx->quiet)
-+ return;
-+
-+ data = get_ctxdata(ctx);
-+
-+ memset(&data->progress, 0, sizeof(data->progress));
-+ data->oldmsgcount = ctx->msgcount;
-+ data->ignmsgcount = 0;
-+ data->noprogress = 0;
-+ data->progress_ready = 0;
-+}
-+
-+static void nm_progress_update(CONTEXT *ctx, notmuch_query_t *q)
-+{
-+ struct nm_ctxdata *data = get_ctxdata(ctx);
-+
-+ if (ctx->quiet || data->noprogress)
-+ return;
-+
-+ if (!data->progress_ready && q) {
-+ static char msg[STRING];
-+ snprintf(msg, sizeof(msg), _("Reading messages..."));
-+
-+ mutt_progress_init(&data->progress, msg, M_PROGRESS_MSG,
-+ ReadInc, notmuch_query_count_messages(q));
-+ data->progress_ready = 1;
-+ }
-+
-+ if (data->progress_ready)
-+ mutt_progress_update(&data->progress,
-+ ctx->msgcount + data->ignmsgcount
-+ - data->oldmsgcount, -1);
-+}
-+
-+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;
-+
-+ /* 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;
-+ }
-+
-+ path = get_message_last_filename(msg);
-+ if (!path)
-+ return;
-+
-+ dprint(2, (debugfile, "nm: appending message, i=%d, id=%s, path=%s\n",
-+ ctx->msgcount,
-+ notmuch_message_get_message_id(msg),
-+ path));
-+
-+ 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);
-+
-+ 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);
-+
-+ dprint(1, (debugfile, "nm: not up-to-date: %s -> %s\n",
-+ path, newpath));
-+ }
-+ }
-+ FREE(&folder);
-+ }
-+
-+ 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;
-+ }
-+
-+ 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);
-+}
-+
-+/*
-+ * 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;
-+
-+ 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);
-+ }
-+}
-+
-+/*
-+ * 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);
-+ }
-+}
-+
-+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;
-+
-+ if (!data)
-+ return;
-+
-+ limit = get_limit(data);
-+
-+ for (msgs = notmuch_query_search_messages(q);
-+ notmuch_messages_valid(msgs) &&
-+ (limit == 0 || ctx->msgcount < limit);
-+ notmuch_messages_move_to_next(msgs)) {
-+
-+ notmuch_message_t *m = notmuch_messages_get(msgs);
-+ append_message(ctx, q, m, dedup);
-+ notmuch_message_destroy(m);
-+ }
-+}
-+
-+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 (!data)
-+ return;
-+
-+ for (threads = notmuch_query_search_threads(q);
-+ notmuch_threads_valid(threads) &&
-+ (limit == 0 || ctx->msgcount < limit);
-+ notmuch_threads_move_to_next(threads)) {
-+
-+ notmuch_thread_t *thread = notmuch_threads_get(threads);
-+ append_thread(ctx, q, thread, dedup);
-+ notmuch_thread_destroy(thread);
-+ }
-+}
-+
-+int nm_read_query(CONTEXT *ctx)
-+{
-+ notmuch_query_t *q;
-+ struct nm_ctxdata *data;
-+ int rc = -1;
-+
-+ 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;
-+
-+ }
-+
-+ if (!is_longrun(data))
-+ release_db(data);
-+
-+ ctx->mtime = time(NULL);
-+
-+ mx_update_context(ctx, ctx->msgcount);
-+ data->oldmsgcount = 0;
-+
-+ dprint(1, (debugfile, "nm: reading messages... done [rc=%d, count=%d]\n",
-+ rc, ctx->msgcount));
-+ return rc;
-+}
-+
-+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;
-+
-+ if (!data)
-+ return -1;
-+ if (!(db = get_db(data, FALSE)) || !(msg = get_nm_message(db, h)))
-+ goto done;
-+
-+ 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);
-+
-+ read_threads_query(ctx, q, 1, 0);
-+ ctx->mtime = time(NULL);
-+ rc = 0;
-+
-+ 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);
-+
-+ if (ctx->msgcount == data->oldmsgcount)
-+ mutt_message _("No more messages in the thread.");
-+
-+ 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" */
-+
-+ 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;
-+
-+ strncpy(buf, uri, bufsz);
-+ buf[bufsz - 1] = '\0';
-+
-+ dprint(1, (debugfile, "nm: uri from query '%s'\n", buf));
-+ return buf;
-+}
-+
-+/*
-+ * 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);
-+
-+ dprint(2, (debugfile, "nm: find message (%s)\n", id));
-+
-+ if (id && db)
-+ notmuch_database_find_message(db, id, &msg);
-+
-+ return msg;
-+}
-+
-+static int update_tags(notmuch_message_t *msg, const char *tags)
-+{
-+ char *tag = NULL, *end = NULL, *p;
-+ char *buf = safe_strdup(tags);
-+
-+ if (!buf)
-+ return -1;
-+
-+ notmuch_message_freeze(msg);
-+
-+ 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';
-+
-+ 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;
-+}
-+
-+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;
-+
-+ if (!buf || !*buf || !data)
-+ return -1;
-+
-+ 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;
-+}
-+
-+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;
-+
-+ strfcpy(folder, old, sizeof(folder));
-+ p = strrchr(folder, '/');
-+ if (p)
-+ *p = '\0';
-+
-+ p++;
-+ strfcpy(filename, p, sizeof(filename));
-+
-+ /* remove (new,cur,...) from folder path */
-+ p = strrchr(folder, '/');
-+ if (p)
-+ *p = '\0';
-+
-+ /* remove old flags from filename */
-+ if ((p = strchr(filename, ':')))
-+ *p = '\0';
-+
-+ /* compose new flags */
-+ maildir_flags(suffix, sizeof(suffix), h);
-+
-+ snprintf(newpath, newsz, "%s/%s/%s%s",
-+ folder,
-+ (h->read || h->old) ? "cur" : "new",
-+ filename,
-+ suffix);
-+
-+ if (strcmp(old, newpath) == 0)
-+ return 1;
-+
-+ if (rename(old, newpath) != 0) {
-+ dprint(1, (debugfile, "nm: rename(2) failed %s -> %s\n", old, newpath));
-+ return -1;
-+ }
-+
-+ return 0;
-+}
-+
-+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;
-+
-+ dprint(2, (debugfile, "nm: remove filename '%s'\n", path));
-+
-+ 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;
-+
-+ /*
-+ * 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 succes (duplicate), call unlink\n"));
-+ unlink(path);
-+ for (ls = notmuch_message_get_filenames(msg);
-+ ls && notmuch_filenames_valid(ls);
-+ notmuch_filenames_move_to_next(ls)) {
-+
-+ path = notmuch_filenames_get(ls);
-+
-+ 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;
-+ }
-+
-+ notmuch_message_destroy(msg);
-+ if (trans)
-+ db_trans_end(data);
-+ return 0;
-+}
-+
-+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;
-+
-+ if (!db || !new || !old || access(new, F_OK) != 0)
-+ return -1;
-+
-+ dprint(1, (debugfile, "nm: rename filename, %s -> %s\n", old, new));
-+ trans = db_trans_begin(data);
-+ if (trans < 0)
-+ return -1;
-+
-+ dprint(2, (debugfile, "nm: rename: add '%s'\n", new));
-+ st = notmuch_database_add_message(db, new, &msg);
-+
-+ 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;
-+ }
-+
-+ 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);
-+
-+ for (ls = notmuch_message_get_filenames(msg);
-+ msg && ls && notmuch_filenames_valid(ls);
-+ notmuch_filenames_move_to_next(ls)) {
-+
-+ const char *path = notmuch_filenames_get(ls);
-+ char newpath[_POSIX_PATH_MAX];
-+
-+ if (strcmp(new, path) == 0)
-+ continue;
-+
-+ dprint(2, (debugfile, "nm: rename: syncing duplicate: %s\n", path));
-+
-+ 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));
-+ }
-+
-+ rc = 0;
-+done:
-+ if (msg)
-+ notmuch_message_destroy(msg);
-+ if (trans)
-+ db_trans_end(data);
-+ return rc;
-+}
-+
-+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 (!data || !new)
-+ return -1;
-+
-+ if (!old && h && h->data) {
-+ nm_header_get_fullpath(h, buf, sizeof(buf));
-+ old = buf;
-+ }
-+
-+ rc = rename_filename(data, old, new, h);
-+
-+ if (!is_longrun(data))
-+ release_db(data);
-+ ctx->mtime = time(NULL);
-+ return rc;
-+}
-+
-+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;
-+
-+ if (!data)
-+ return -1;
-+
-+ dprint(1, (debugfile, "nm: sync start ...\n"));
-+
-+ 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);
-+ }
-+
-+ 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;
-+
-+ 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;
-+}
-+
-+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);
-+ res = notmuch_query_count_messages(q);
-+ 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
-+ 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->path && 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->path && 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 HEADER *get_mutt_header(CONTEXT *ctx, notmuch_message_t *msg)
-+{
-+ 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 (!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);
-+
-+ for (i = 0, msgs = notmuch_query_search_messages(q);
-+ 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);
-+
-+ 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);
-+ }
-+
-+ if (update_header_tags(h, m) == 0)
-+ new_flags++;
-+
-+ notmuch_message_destroy(m);
-+ }
-+
-+ for (i = 0; i < ctx->msgcount; i++) {
-+ if (ctx->hdrs[i]->active == 0) {
-+ occult = 1;
-+ break;
-+ }
-+ }
-+
-+ 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);
-+
-+ ctx->mtime = time(NULL);
-+
-+ dprint(1, (debugfile, "nm: ... check done [count=%d, new_flags=%d, occult=%d]\n",
-+ ctx->msgcount, new_flags, occult));
-+
-+ return occult ? M_REOPENED :
-+ ctx->msgcount > data->oldmsgcount ? M_NEW_MAIL :
-+ new_flags ? M_FLAGS : 0;
-+}
-+
-+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);
-+
-+ 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);
-+ }
-+
-+ 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;
-+}
-+
-+/*
-+ * 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;
-+
-+ 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"));
-+
-+ 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);
-+ }
-+
-+ rc = 0;
-+done:
-+ if (tags)
-+ notmuch_tags_destroy(tags);
-+
-+ if (!is_longrun(data))
-+ release_db(data);
-+
-+ dprint(1, (debugfile, "nm: get all tags done [rc=%d tag_count=%u]\n", rc,
-+ *tag_count));
-+ return rc;
-+}
-diff -urN mutt-1.6.1-sidebar-notmuch/mutt_notmuch.h mutt-1.6.1-notmuch/mutt_notmuch.h
---- mutt-1.6.1-sidebar-notmuch/mutt_notmuch.h 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-notmuch/mutt_notmuch.h 2016-05-02 03:02:15.145215107 +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-sidebar-notmuch/mx.c mutt-1.6.1-notmuch/mx.c
---- mutt-1.6.1-sidebar-notmuch/mx.c 2016-05-02 03:02:12.715176444 +0100
-+++ mutt-1.6.1-notmuch/mx.c 2016-05-02 03:02:15.229216443 +0100
-@@ -41,6 +41,10 @@
- #include "pop.h"
- #endif
-
-+#ifdef USE_NOTMUCH
-+#include "mutt_notmuch.h"
-+#endif
-+
- #include "buffy.h"
-
- #ifdef USE_DOTLOCK
-@@ -60,6 +64,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)
-
-@@ -346,6 +354,24 @@
- }
- #endif
-
-+#ifdef USE_NOTMUCH
-+
-+int mx_is_notmuch(const char *p)
-+{
-+ url_scheme_t scheme;
-+
-+ if (!p)
-+ return 0;
-+
-+ scheme = url_check_scheme (p);
-+ if (scheme == U_NOTMUCH)
-+ return 1;
-+
-+ return 0;
-+}
-+
-+#endif
-+
- int mx_get_magic (const char *path)
- {
- struct stat st;
-@@ -363,6 +389,11 @@
- return M_POP;
- #endif /* USE_POP */
-
-+#ifdef USE_NOTMUCH
-+ if (mx_is_notmuch(path))
-+ return M_NOTMUCH;
-+#endif
-+
- if (stat (path, &st) == -1)
- {
- dprint (1, (debugfile, "mx_get_magic(): unable to stat %s: %s (errno %d).\n",
-@@ -676,6 +707,12 @@
- break;
- #endif /* USE_POP */
-
-+#ifdef USE_NOTMUCH
-+ case M_NOTMUCH:
-+ rc = nm_read_query (ctx);
-+ break;
-+#endif /* USE_IMAP */
-+
- default:
- rc = -1;
- break;
-@@ -789,6 +826,13 @@
- 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 */
-+
- }
-
- #if 0
-@@ -1381,6 +1425,11 @@
- case M_POP:
- return (pop_check_mailbox (ctx, index_hint));
- #endif /* USE_POP */
-+
-+#ifdef USE_NOTMUCH
-+ case M_NOTMUCH:
-+ return nm_check_database(ctx, index_hint);
-+#endif
- }
- }
-
-@@ -1392,7 +1441,7 @@
- MESSAGE *mx_open_message (CONTEXT *ctx, int msgno)
- {
- MESSAGE *msg;
--
-+
- msg = safe_calloc (1, sizeof (MESSAGE));
- switch (msg->magic = ctx->magic)
- {
-@@ -1403,15 +1452,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 ((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)
- {
-@@ -1486,13 +1544,17 @@
- break;
- }
- #endif
--
-+
- case M_MAILDIR:
- {
- r = maildir_commit_message (ctx, msg, NULL);
- break;
- }
--
-+
-+ case M_NOTMUCH:
-+ mutt_perror _("Can't write to virtual folder.");
-+ break;
-+
- case M_MH:
- {
- r = mh_commit_message (ctx, msg, NULL);
-@@ -1506,7 +1568,7 @@
- mutt_perror _("Can't write message");
- r = -1;
- }
--
-+
- return r;
- }
-
-@@ -1516,14 +1578,18 @@
- int r = 0;
-
- if ((*msg)->magic == M_MH || (*msg)->magic == M_MAILDIR
-- || (*msg)->magic == M_IMAP || (*msg)->magic == M_POP)
-+ || (*msg)->magic == M_IMAP || (*msg)->magic == M_POP
-+ || (*msg)->magic == M_NOTMUCH)
- {
- r = safe_fclose (&(*msg)->fp);
- }
- 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));
-@@ -1531,6 +1597,7 @@
- FREE (&(*msg)->path);
- }
-
-+ FREE (&(*msg)->commited_path);
- FREE (msg); /* __FREE_CHECKED__ */
- return (r);
- }
-diff -urN mutt-1.6.1-sidebar-notmuch/mx.h mutt-1.6.1-notmuch/mx.h
---- mutt-1.6.1-sidebar-notmuch/mx.h 2016-05-02 03:02:12.715176444 +0100
-+++ mutt-1.6.1-notmuch/mx.h 2016-05-02 03:02:15.229216443 +0100
-@@ -35,6 +35,7 @@
- M_MH,
- M_MAILDIR,
- M_IMAP,
-+ M_NOTMUCH,
- M_POP
- };
-
-@@ -67,13 +68,30 @@
- 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 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
-+
-+#ifdef USE_NOTMUCH
-+int mx_is_notmuch(const char *p);
-+#endif
-+
- 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-sidebar-notmuch/OPS.NOTMUCH mutt-1.6.1-notmuch/OPS.NOTMUCH
---- mutt-1.6.1-sidebar-notmuch/OPS.NOTMUCH 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-notmuch/OPS.NOTMUCH 2016-05-02 03:02:15.112214581 +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-sidebar-notmuch/OPS.SIDEBAR mutt-1.6.1-notmuch/OPS.SIDEBAR
---- mutt-1.6.1-sidebar-notmuch/OPS.SIDEBAR 2016-05-02 03:02:12.689176031 +0100
-+++ mutt-1.6.1-notmuch/OPS.SIDEBAR 2016-05-02 03:02:15.113214597 +0100
-@@ -5,4 +5,5 @@
- 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-sidebar-notmuch/pattern.c mutt-1.6.1-notmuch/pattern.c
---- mutt-1.6.1-sidebar-notmuch/pattern.c 2016-05-02 03:02:12.716176460 +0100
-+++ mutt-1.6.1-notmuch/pattern.c 2016-05-02 03:02:15.230216459 +0100
-@@ -42,6 +42,10 @@
- #include "imap/imap.h"
- #endif
-
-+#ifdef USE_NOTMUCH
-+#include "mutt_notmuch.h"
-+#endif
-+
- 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 *);
-@@ -95,6 +99,9 @@
- { '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 },
-@@ -1210,6 +1217,13 @@
- 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));
-+#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:
-diff -urN mutt-1.6.1-sidebar-notmuch/protos.h mutt-1.6.1-notmuch/protos.h
---- mutt-1.6.1-sidebar-notmuch/protos.h 2016-05-02 03:02:12.732176715 +0100
-+++ mutt-1.6.1-notmuch/protos.h 2016-05-02 03:02:15.248216745 +0100
-@@ -80,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 *);
-
-@@ -286,6 +289,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 *);
-@@ -301,8 +308,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 _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)
-@@ -367,7 +376,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);
-diff -urN mutt-1.6.1-sidebar-notmuch/README.notmuch mutt-1.6.1-notmuch/README.notmuch
---- mutt-1.6.1-sidebar-notmuch/README.notmuch 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-notmuch/README.notmuch 2016-05-02 03:02:15.117214661 +0100
-@@ -0,0 +1,402 @@
-+notmuch support for mutt
-+------------------------
-+
-+ * notmuch is e-mail fulltext indexing and tagging engine; see
-+ http://notmuchmail.org/ for more information.
-+
-+ * home page (wiki) and git:
-+
-+ https://github.com/karelzak/mutt-kz
-+
-+ Note that the master branch is rebased to be up to date with mutt upstream. Use
-+ stable/v<version> branches for downstream packaging.
-+
-+ * mailing list:
-+
-+ https://admin.fedoraproject.org/mailman/listinfo/mutt-kz
-+
-+ * requirements:
-+
-+ notmuch >= 0.9
-+
-+ * compile:
-+
-+ $ git clone git://github.com/karelzak/mutt-kz.git
-+ $ cd mutt-kz
-+ $ ./prepare
-+ $ ./configure --enable-notmuch [--enable-debug]
-+ $ make
-+
-+ * Folders URI
-+
-+ notmuch://[<path>][?<item>=<name>[& ...]]
-+
-+ 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 the "<path>" is not defined then $nm_default_uri or $folder is used,
-+ for example:
-+
-+ set nm_default_uri = "notmuch:///home/foo/maildir"
-+ virtual-mailboxes "My INBOX" "notmuch://?query=tag:inbox"
-+
-+ Items:
-+
-+ query=<string>
-+
-+ See SEARCH SYNTAX in notmuch man page. Don't forget to use "and" and
-+ "or" operators in your queries.
-+
-+ Note that proper URI should not contain blank space and all "bad" chars
-+ should be encoded, for example
-+
-+ "tag:AAA and tag:BBB" --encoding-> tag:AAA%20and%20tag:BBB
-+
-+ but mutt config file parser is smart enough to accept space in quoted
-+ strings. It means that you can use
-+
-+ "notmuch:///foo?query=tag:AAA and tag:BBB"
-+
-+ in your config files to keep things readable.
-+
-+ See http://xapian.org/docs/queryparser.html for more details about Xapian
-+ queries.
-+
-+
-+ limit=<number>
-+
-+ Restricts number of messages/threads in the result. The default limit
-+ is nm_db_limit.
-+
-+ type=<threads|messages>
-+
-+ Reads all matching messages or whole-threads. The default is 'messages'
-+ or nm_query_type.
-+
-+
-+ * commands:
-+
-+ 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
-+
-+ vfolder-from-query:
-+ - generate new virtual folder from notmuch search query
-+ - default key: <Esc>X
-+ - note: TAB completion of 'tag:' names is available
-+
-+ 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"
-+
-+ 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):
-+
-+ macro index A "<modify-labels-then-hide>+archive -inbox\n<sync-mailbox>"
-+ macro index I "<modify-labels-then-hide>-inbox\n<sync-mailbox>"
-+
-+ quasi-delete:
-+ - delete message from mutt (usually after <sync-mailbox> function), but
-+ don't touch message on disk
-+
-+ 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: +
-+
-+ * Pattern modifiers:
-+
-+ 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:
-+
-+ - '~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?'"
-+
-+ * muttrc:
-+
-+ Note that you can use notmuch specific mutt config file, see -F <config> in
-+ mutt docs.
-+
-+
-+ virtual-mailboxes <description> <uri> [ ...]
-+
-+ 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)
-+
-+ example:
-+
-+ 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"
-+
-+ 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.
-+
-+ virtual_spoolfile = <boolean>
-+
-+ When set, mutt will use the first virtual mailbox (see virtual-mailboxes)
-+ as a spoolfile.
-+
-+ 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.
-+
-+ tag-transforms <tag> <transform> [ ...]
-+
-+ 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.
-+
-+ example:
-+
-+ tag-transforms "inbox" "i" \
-+ "unread" "u" \
-+ "replied" "↻ " \
-+ "sent" "➥ " \
-+ "todo" "T" \
-+ "deleted" "DEL" \
-+ "invites" "CAL"
-+
-+ tag-formats <tag> <format sequence> [ ...]
-+
-+ 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.
-+
-+ example:
-+
-+ tag-formats "inbox" "GI" \
-+ "unread" "GU" \
-+ "replied" "GR" \
-+ "sent" "GS" \
-+ "todo" "Gt" \
-+ "deleted" "GD" \
-+ "invites" "Gi"
-+
-+ 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:
-+
-+ set index_format='4C %S %[%y.%m.%d] %-18.18n %?GU?%GU& ? %?GR?%GR& ? %?GI?%GI& ? %s'
-+
-+ The %G formatting sequence may display all tags including tags hidden by
-+ nm_hidden_tags.
-+
-+ nm_record = <boolean>
-+
-+ 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.
-+
-+ nm_record_tags = <comma delimited list>
-+
-+ Tags that should be removed or added to the to the messages stored in the mutt record.
-+
-+ example:
-+
-+ set record = "~/sent-mails"
-+ set nm_record = yes
-+ set nm_record_tags = "-inbox,archive,me"
-+
-+ nm_open_timeout = <seconds>
-+
-+ This option specifies timeout for Notmuch database. Default is 5 seconds.
-+
-+ nm_default_uri = <uri>
-+
-+ 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).
-+
-+ nm_hidden_tags = <comma delimited list>
-+
-+ This variable specifies private notmuch tags which should not be printed
-+ on screen (index, pager).
-+
-+ Default is "unread,draft,flagged,passed,replied,attachment".
-+
-+ nm_exclude_tags = <comma delimited list>
-+
-+ The messages tagged with these tags are excluded and not loaded
-+ from notmuch DB to mutt unless specified explicitly.
-+
-+ Not set by default.
-+
-+ nm_unread_tag = <name>
-+
-+ 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.
-+
-+ Default is "unread".
-+
-+ nm_db_limit = <num>
-+
-+ This variable specifies notmuch query limit.
-+
-+ Default is unlimited.
-+
-+ nm_query_type = <threads|messages>
-+
-+ This variable specifies notmuch query type, supported types: 'threads' and
-+ 'messages'.
-+
-+ Default is 'messages'.
-+
-+ vfolder_format = <string>
-+
-+ 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:
-+
-+ %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
-+
-+ Default is "%6n(%6N) %f ".
-+
-+ index_format and pager_format
-+
-+ %g notmuch tags (labels)
-+ %Gx specific notmuch tag defined by tag-formats (see above)
-+
-+ for example:
-+
-+ 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)"
-+
-+
-+* .muttrc example:
-+
-+ set record="~/Mail/Maildir/sent-mail"
-+ set nm_record = yes
-+ set nm_record_tags ="-inbox me archive"
-+
-+ set nm_default_uri="notmuch:///home/kzak/Mail/Maildir"
-+ set virtual_spoolfile = yes
-+ set sort_browser = unsorted
-+
-+ # normal folders
-+ set mbox_type=Maildir
-+ set folder="~/Mail/Maildir"
-+ mailboxes =rh =fedora =misc
-+
-+ set sidebar_width = 35
-+ set sidebar_visible = yes
-+ set sidebar_sort_method = unsorted
-+ set sidebar_divider_char = │
-+
-+ color sidebar_new yellow default
-+ color progress default magenta
-+
-+ bind index <left> sidebar-prev
-+ bind index <right> sidebar-next
-+ bind index <space> sidebar-open
-+ bind index <Esc>S sidebar-toggle-virtual
-+
-+ set index_format="%4C %Z %?GI?%GI& ? %[%d/%b] %-16.15F %?M?(%3M)& ? %s %> %?g?%g?"
-+
-+ # 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" \
-+
-+ # move message to archive
-+ macro index A "<modify-labels-then-hide>+archive -inbox\n<sync-mailbox>"
-+
-+ # remove message from inbox
-+ macro index I "<modify-labels-then-hide>-inbox\n<sync-mailbox>"
-+
-+ # 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"
-+
-+
-+* .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=""
-+ }
-+
-+ ### Deliver emails to maildirs by notmuch-deliver
-+ ### from notmuch contrib/
-+ ###
-+ ### notmuch-deliver -t <tags> [-t ...] <maildir>
-+
-+ :0:notmuch.lock
-+ * ^List-Id:.*linux.linux.cz
-+ | notmuch-deliver $NOINBOX -t cz $TAGS linux.cz
-+
-+ :0:notmuch.lock
-+ * ^X-Mailing-List:.*util-linux at vger.kernel.org
-+ | notmuch-deliver -t ul $TAGS util-linux
-+
-+ :0:notmuch.lock
-+ * ^List-Id:.*parted-devel.lists.alioth.debian.org
-+ | notmuch-deliver $NOINBOX -t part $TAGS parted
-+
-+ ### [...cut to make the example short...] ###
-+
-+ ### All unmatched mails
-+ :0:notmuch.lock
-+ * ^From
-+ | notmuch-deliver $TAGS misc
-+
-+ ### fallback if notmuch does not work
-+ :0:
-+ * ^From
-+ Mail/Maildir/misc/
-+
-+
-+* another example:
-+
-+ http://notmuchmail.org/mutttips/
-diff -urN mutt-1.6.1-sidebar-notmuch/send.c mutt-1.6.1-notmuch/send.c
---- mutt-1.6.1-sidebar-notmuch/send.c 2016-05-02 03:02:12.733176731 +0100
-+++ mutt-1.6.1-notmuch/send.c 2016-05-02 03:02:15.248216745 +0100
-@@ -48,6 +48,9 @@
- #include "remailer.h"
- #endif
-
-+#ifdef USE_NOTMUCH
-+#include "mutt_notmuch.h"
-+#endif
-
- static void append_signature (FILE *f)
- {
-@@ -1164,6 +1167,7 @@
- char *smime_default_key = NULL;
- char *tag = NULL, *err = NULL;
- char *ctype;
-+ char *finalpath = NULL;
-
- int rv = -1;
-
-@@ -1646,7 +1650,9 @@
- mutt_prepare_envelope (msg->env, 0);
- mutt_env_to_intl (msg->env, NULL, NULL); /* Handle bad IDNAs the next time. */
-
-- if (!Postponed || mutt_write_fcc (NONULL (Postponed), msg, (cur && (flags & SENDREPLY)) ? cur->env->message_id : NULL, 1, fcc) < 0)
-+ if (!Postponed || mutt_write_fcc (NONULL (Postponed), msg,
-+ (cur && (flags & SENDREPLY)) ?
-+ cur->env->message_id : NULL, 1, fcc, NULL) < 0)
- {
- msg->content = mutt_remove_multipart (msg->content);
- decode_descriptions (msg->content);
-@@ -1829,7 +1835,7 @@
- * message was first postponed.
- */
- msg->received = time (NULL);
-- if (mutt_write_fcc (fcc, msg, NULL, 0, NULL) == -1)
-+ if (mutt_write_fcc (fcc, msg, NULL, 0, NULL, &finalpath) == -1)
- {
- /*
- * Error writing FCC, we should abort sending.
-@@ -1890,6 +1896,7 @@
- msg->content = mutt_remove_multipart (msg->content);
- decode_descriptions (msg->content);
- mutt_unprepare_envelope (msg->env);
-+ FREE(&finalpath);
- goto main_loop;
- }
- else
-@@ -1898,8 +1905,13 @@
- goto cleanup;
- }
- }
-- else if (!option (OPTNOCURSES) && ! (flags & SENDMAILX))
-+ else if (!option (OPTNOCURSES) && ! (flags & SENDMAILX)) {
- mutt_message (i == 0 ? _("Mail sent.") : _("Sending in background."));
-+#ifdef USE_NOTMUCH
-+ if (option(OPTNOTMUCHRECORD))
-+ nm_record_message(ctx, finalpath, cur);
-+#endif
-+ }
-
- if (WithCrypto && (msg->security & ENCRYPT))
- FREE (&pgpkeylist);
-@@ -1944,7 +1956,8 @@
- safe_fclose (&tempfp);
- if (! (flags & SENDNOFREEHEADER))
- mutt_free_header (&msg);
--
-+
-+ FREE(&finalpath);
- return rv;
- }
-
-diff -urN mutt-1.6.1-sidebar-notmuch/sendlib.c mutt-1.6.1-notmuch/sendlib.c
---- mutt-1.6.1-sidebar-notmuch/sendlib.c 2016-05-02 03:02:12.733176731 +0100
-+++ mutt-1.6.1-notmuch/sendlib.c 2016-05-02 03:02:15.178215632 +0100
-@@ -2684,7 +2684,8 @@
- }
- }
-
--int mutt_write_fcc (const char *path, HEADER *hdr, const char *msgid, int post, char *fcc)
-+int mutt_write_fcc (const char *path, HEADER *hdr, const char *msgid,
-+ int post, char *fcc, char **finalpath)
- {
- CONTEXT f;
- MESSAGE *msg;
-@@ -2873,6 +2874,8 @@
-
- if (mx_commit_message (msg, &f) != 0)
- r = -1;
-+ else if (finalpath)
-+ *finalpath = safe_strdup(msg->commited_path);
- mx_close_message (&msg);
- mx_close_mailbox (&f, NULL);
-
-diff -urN mutt-1.6.1-sidebar-notmuch/sidebar.c mutt-1.6.1-notmuch/sidebar.c
---- mutt-1.6.1-sidebar-notmuch/sidebar.c 2016-05-02 03:02:12.733176731 +0100
-+++ mutt-1.6.1-notmuch/sidebar.c 2016-05-02 03:02:15.248216745 +0100
-@@ -26,6 +26,7 @@
- #include "keymap.h"
- #include "mutt_curses.h"
- #include "mutt_menu.h"
-+#include "mx.h"
- #include "sort.h"
-
- /* Previous values for some sidebar config */
-@@ -51,6 +52,38 @@
- BUFFY *buffy;
- };
-
-+enum {
-+ SB_SRC_NONE = 0,
-+ SB_SRC_VIRT,
-+ SB_SRC_INCOMING
-+};
-+static int sidebar_source = SB_SRC_NONE;
-+
-+static BUFFY *
-+get_incoming (void)
-+{
-+ switch (sidebar_source) {
-+ case SB_SRC_NONE:
-+ sidebar_source = SB_SRC_INCOMING;
-+
-+#ifdef USE_NOTMUCH
-+ if (option (OPTVIRTSPOOLFILE) && VirtIncoming) {
-+ sidebar_source = SB_SRC_VIRT;
-+ return VirtIncoming;
-+ }
-+ break;
-+ case SB_SRC_VIRT:
-+ if (VirtIncoming) {
-+ return VirtIncoming;
-+ }
-+ break;
-+#endif
-+ case SB_SRC_INCOMING:
-+ break;
-+ }
-+
-+ return Incoming; /* default */
-+}
-
- /**
- * find_next_new - Find the next folder that contains new mail
-@@ -73,7 +106,7 @@
- do {
- b = b->next;
- if (!b && wrap) {
-- b = Incoming;
-+ b = get_incoming();
- }
- if (!b || (b == HilBuffy)) {
- break;
-@@ -330,6 +363,9 @@
- 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;
-@@ -472,7 +508,7 @@
- static int
- prepare_sidebar (int page_size)
- {
-- BUFFY *b = Incoming;
-+ BUFFY *b = get_incoming();
- if (!b)
- return 0;
-
-@@ -488,14 +524,15 @@
- return 0;
-
- int i = 0;
-- for (b = Incoming; b; b = b->next, i++) {
-+ for (b = get_incoming(); b; b = b->next, i++) {
- arr[i] = b;
- }
-
- update_buffy_visibility (arr, count);
- sort_buffy_array (arr, count);
-
-- Incoming = arr[0];
-+ if (sidebar_source == SB_SRC_INCOMING)
-+ Incoming = arr[0];
-
- int top_index = 0;
- int opn_index = -1;
-@@ -778,6 +815,11 @@
- strncat (sidebar_folder_name, tmp_folder_name, strlen (tmp_folder_name));
- }
- }
-+#ifdef USE_NOTMUCH
-+ else if (b->magic == M_NOTMUCH) {
-+ sidebar_folder_name = b->desc;
-+ }
-+#endif
- char str[SHORT_STRING];
- make_sidebar_entry (str, sizeof (str), w, sidebar_folder_name, b);
- printw ("%s", str);
-@@ -836,7 +878,7 @@
- if (div_width < 0)
- return;
-
-- if (!Incoming) {
-+ if (!get_incoming()) {
- int w = MIN(COLS, (SidebarWidth - div_width));
- fill_empty_space (first_row, num_rows, w);
- return;
-@@ -921,7 +963,7 @@
- break;
- case OP_SIDEBAR_PAGE_UP:
- HilBuffy = TopBuffy;
-- if (HilBuffy != Incoming) {
-+ if (HilBuffy != get_incoming()) {
- HilBuffy = HilBuffy->prev;
- }
- break;
-@@ -958,7 +1000,7 @@
- {
- /* Even if the sidebar's hidden,
- * we should take note of the new data. */
-- BUFFY *b = Incoming;
-+ BUFFY *b = get_incoming();
- if (!ctx || !b)
- return;
-
-@@ -1005,7 +1047,7 @@
- {
- /* Even if the sidebar is hidden */
-
-- BUFFY *b = Incoming;
-+ BUFFY *b = get_incoming();
-
- if (!path || !b)
- return NULL;
-@@ -1078,3 +1120,29 @@
- Outgoing = buffy_going (Outgoing);
- }
- }
-+
-+/**
-+ * sb_toggle_virtual - Switch between regular and virtual folders
-+ */
-+void
-+sb_toggle_virtual (void)
-+{
-+ if (sidebar_source == -1)
-+ get_incoming();
-+
-+#ifdef USE_NOTMUCH
-+ if ((sidebar_source == SB_SRC_INCOMING) && VirtIncoming)
-+ sidebar_source = SB_SRC_VIRT;
-+ else
-+#endif
-+ sidebar_source = SB_SRC_INCOMING;
-+
-+ TopBuffy = NULL;
-+ OpnBuffy = NULL;
-+ HilBuffy = NULL;
-+ BotBuffy = NULL;
-+ Outgoing = NULL;
-+
-+ sb_draw();
-+}
-+
-diff -urN mutt-1.6.1-sidebar-notmuch/sidebar.h mutt-1.6.1-notmuch/sidebar.h
---- mutt-1.6.1-sidebar-notmuch/sidebar.h 2016-05-02 03:02:12.733176731 +0100
-+++ mutt-1.6.1-notmuch/sidebar.h 2016-05-02 03:02:15.248216745 +0100
-@@ -32,5 +32,6 @@
- BUFFY * sb_set_open_buffy (const char *path);
- void sb_set_update_time (void);
- int sb_should_refresh (void);
-+void sb_toggle_virtual (void);
-
- #endif /* SIDEBAR_H */
-diff -urN mutt-1.6.1-sidebar-notmuch/status.c mutt-1.6.1-notmuch/status.c
---- mutt-1.6.1-sidebar-notmuch/status.c 2016-05-02 03:02:12.733176731 +0100
-+++ mutt-1.6.1-notmuch/status.c 2016-05-02 03:02:15.179215647 +0100
-@@ -27,6 +27,10 @@
- #include "mapping.h"
- #include "mx.h"
-
-+#ifdef USE_NOTMUCH
-+#include "mutt_notmuch.h"
-+#endif
-+
- #include <string.h>
- #include <ctype.h>
- #include <unistd.h>
-@@ -95,7 +99,14 @@
- break;
-
- case 'f':
-- snprintf (fmt, sizeof(fmt), "%%%ss", prefix);
-+ {
-+#ifdef USE_NOTMUCH
-+ char *p;
-+ if (Context && Context->magic == M_NOTMUCH &&
-+ (p = nm_get_description(Context)))
-+ strfcpy(tmp, p, sizeof (tmp));
-+ else
-+#endif
- if (Context && Context->path)
- {
- strfcpy (tmp, Context->path, sizeof (tmp));
-@@ -103,9 +114,11 @@
- }
- else
- strfcpy (tmp, _("(no mailbox)"), sizeof (tmp));
-+
-+ snprintf (fmt, sizeof(fmt), "%%%ss", prefix);
- snprintf (buf, buflen, fmt, tmp);
- break;
--
-+ }
- case 'F':
- if (!optional)
- {
-diff -urN mutt-1.6.1-sidebar-notmuch/UPDATING.kz mutt-1.6.1-notmuch/UPDATING.kz
---- mutt-1.6.1-sidebar-notmuch/UPDATING.kz 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-notmuch/UPDATING.kz 2016-05-02 03:02:15.118214677 +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 brower entry format
-++ %g and %Gx index_format and pager_format formatting sequences
-diff -urN mutt-1.6.1-sidebar-notmuch/url.c mutt-1.6.1-notmuch/url.c
---- mutt-1.6.1-sidebar-notmuch/url.c 2016-05-02 03:02:12.733176731 +0100
-+++ mutt-1.6.1-notmuch/url.c 2016-05-02 03:02:15.180215663 +0100
-@@ -40,12 +40,15 @@
- { "pop", U_POP },
- { "pops", U_POPS },
- { "mailto", U_MAILTO },
-+#ifdef USE_NOTMUCH
-+ { "notmuch", U_NOTMUCH },
-+#endif
- { "smtp", U_SMTP },
- { "smtps", U_SMTPS },
- { NULL, U_UNKNOWN }
- };
-
--static int url_pct_decode (char *s)
-+int url_pct_decode (char *s)
- {
- char *d;
-
-diff -urN mutt-1.6.1-sidebar-notmuch/url.h mutt-1.6.1-notmuch/url.h
---- mutt-1.6.1-sidebar-notmuch/url.h 2016-05-02 03:02:12.733176731 +0100
-+++ mutt-1.6.1-notmuch/url.h 2016-05-02 03:02:15.180215663 +0100
-@@ -11,6 +11,9 @@
- U_SMTP,
- U_SMTPS,
- U_MAILTO,
-+#ifdef USE_NOTMUCH
-+ U_NOTMUCH,
-+#endif
- U_UNKNOWN
- }
- url_scheme_t;
-@@ -34,5 +37,6 @@
- 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 --git a/debian/patches/neomutt/11-ifdef.patch b/debian/patches/neomutt/11-ifdef.patch
deleted file mode 100644
index 8f9bcfb..0000000
--- a/debian/patches/neomutt/11-ifdef.patch
+++ /dev/null
@@ -1,1526 +0,0 @@
-diff -urN mutt-1.6.1/doc/manual.xml.head mutt-1.6.1-ifdef/doc/manual.xml.head
---- mutt-1.6.1/doc/manual.xml.head 2016-05-02 03:02:12.402171465 +0100
-+++ mutt-1.6.1-ifdef/doc/manual.xml.head 2016-05-02 03:02:15.448219927 +0100
-@@ -8081,6 +8081,167 @@
-
- </sect1>
-
-+<sect1 id="ifdef">
-+ <title>Ifdef Patch</title>
-+ <subtitle>Conditional config options</subtitle>
-+
-+ <sect2 id="ifdef-patch">
-+ <title>Patch</title>
-+
-+ <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>
-+
-+ <itemizedlist>
-+ <title>Dependencies:</title>
-+ <listitem><para>mutt-1.5.24</para></listitem>
-+ </itemizedlist>
-+
-+ <para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
-+ </sect2>
-+
-+ <sect2 id="ifdef-intro">
-+ <title>Introduction</title>
-+
-+ <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>
-+
-+<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>
-+
-+ <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>
-+
- </chapter>
-
- <chapter id="security">
-@@ -8872,6 +9033,18 @@
- </cmdsynopsis>
- </listitem>
-
-+<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>
-+
- <listitem>
- <cmdsynopsis>
- <command><link linkend="ignore">ignore</link></command>
-diff -urN mutt-1.6.1/doc/muttrc.ifdef mutt-1.6.1-ifdef/doc/muttrc.ifdef
---- mutt-1.6.1/doc/muttrc.ifdef 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-ifdef/doc/muttrc.ifdef 2016-05-02 03:02:15.358218495 +0100
-@@ -0,0 +1,32 @@
-+# 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.
-+ifdef trash 'set trash=~/Mail/trash'
-+
-+# If the 'tag-pattern' function exists, bind a key to it.
-+ifdef tag-pattern 'bind index <F6> tag-pattern'
-+
-+# If the 'imap-fetch-mail' command exists, read my IMAP config.
-+ifdef imap-fetch-mail 'source ~/.mutt/imap.rc'
-+
-+# If the compile-time symbol 'USE_SIDEBAR' does not exist, then
-+# stop reading the current config file.
-+ifndef USE_SIDEBAR finish
-+
-+# vim: syntax=muttrc
-diff -urN mutt-1.6.1/doc/vimrc.ifdef mutt-1.6.1-ifdef/doc/vimrc.ifdef
---- mutt-1.6.1/doc/vimrc.ifdef 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-ifdef/doc/vimrc.ifdef 2016-05-02 03:02:15.359218511 +0100
-@@ -0,0 +1,7 @@
-+" Vim syntax file for the mutt ifdef patch
-+
-+syntax keyword muttrcCommand ifdef
-+syntax keyword muttrcCommand ifndef
-+syntax keyword muttrcCommand finish
-+
-+" vim: syntax=vim
-diff -urN mutt-1.6.1/hook.c mutt-1.6.1-ifdef/hook.c
---- mutt-1.6.1/hook.c 2016-05-02 03:02:12.404171496 +0100
-+++ mutt-1.6.1-ifdef/hook.c 2016-05-02 03:02:15.362218559 +0100
-@@ -362,7 +362,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)
- {
- FREE (&token.data);
- mutt_error ("%s", err.data);
-diff -urN mutt-1.6.1/init.c mutt-1.6.1-ifdef/init.c
---- mutt-1.6.1/init.c 2016-05-02 03:02:12.405171512 +0100
-+++ mutt-1.6.1-ifdef/init.c 2016-05-02 03:02:15.451219975 +0100
-@@ -32,6 +32,7 @@
- #include "mutt_crypt.h"
- #include "mutt_idna.h"
- #include "group.h"
-+#include "version.h"
-
- #if defined(USE_SSL)
- #include "mutt_ssl.h"
-@@ -601,6 +602,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.
-+ *
-+ * 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;
-+ }
-+
-+ return 1;
-+}
-+
-+/**
-+ * 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;
-+
-+ memset (&token, 0, sizeof (token));
-+ mutt_extract_token (tmp, s, 0);
-+
-+ /* is the item defined as a variable? */
-+ res = (mutt_option_index (tmp->data) != -1);
-+
-+ /* is the item a compiled-in feature? */
-+ if (!res) {
-+ res = feature_enabled (tmp->data);
-+ }
-+
-+ /* 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;
-+
-+ for (j = 0; b[j].name; j++) {
-+ if (mutt_strcmp (tmp->data, b[j].name) == 0) {
-+ res = 1;
-+ break;
-+ }
-+ }
-+ }
-+ }
-+
-+ /* 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 (!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;
-+}
-+
- static int parse_unignore (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
- {
- do
-@@ -2238,7 +2346,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 +2375,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(¤tline);
- break;
- }
-- }
-- else
-- {
-+ } else if (line_rc == 1) {
-+ break; /* Found "finish" command */
-+ } else {
- if (rc < 0)
- rc = -1;
- }
-@@ -2332,7 +2440,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 +2467,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;
- }
-
-
-@@ -2852,7 +2962,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);
-diff -urN mutt-1.6.1/init.h mutt-1.6.1-ifdef/init.h
---- mutt-1.6.1/init.h 2016-05-02 03:02:12.407171544 +0100
-+++ mutt-1.6.1-ifdef/init.h 2016-05-02 03:02:15.453220007 +0100
-@@ -3665,6 +3665,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 *);
-@@ -3715,6 +3717,9 @@
- { "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
-diff -urN mutt-1.6.1/main.c mutt-1.6.1-ifdef/main.c
---- mutt-1.6.1/main.c 2016-05-02 03:02:12.408171560 +0100
-+++ mutt-1.6.1-ifdef/main.c 2016-05-02 03:02:15.454220023 +0100
-@@ -31,6 +31,7 @@
- #include "url.h"
- #include "mutt_crypt.h"
- #include "mutt_idna.h"
-+#include "version.h"
-
- #ifdef USE_SASL
- #include "mutt_sasl.h"
-@@ -62,46 +63,6 @@
- #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\
--");
--
- void mutt_exit (int code)
- {
- mutt_endwin (NULL);
-@@ -158,359 +119,6 @@
- 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 */
-@@ -752,14 +360,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);
- }
-
-diff -urN mutt-1.6.1/Makefile.am mutt-1.6.1-ifdef/Makefile.am
---- mutt-1.6.1/Makefile.am 2016-05-02 03:02:12.392171305 +0100
-+++ mutt-1.6.1-ifdef/Makefile.am 2016-05-02 03:02:15.439219784 +0100
-@@ -34,7 +34,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)
-
-@@ -73,7 +73,7 @@
- muttbug pgppacket.h depcomp ascii.h BEWARE PATCHES patchlist.sh \
- ChangeLog mkchangelog.sh mutt_idna.h \
- 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
-
-diff -urN mutt-1.6.1/PATCHES mutt-1.6.1-ifdef/PATCHES
---- mutt-1.6.1/PATCHES 2016-05-02 03:02:12.396171369 +0100
-+++ mutt-1.6.1-ifdef/PATCHES 2016-05-02 03:02:15.443219848 +0100
-@@ -0,0 +1 @@
-+patch-ifdef-neo-20160502
-diff -urN mutt-1.6.1/README.ifdef mutt-1.6.1-ifdef/README.ifdef
---- mutt-1.6.1/README.ifdef 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-ifdef/README.ifdef 2016-05-02 03:02:15.443219848 +0100
-@@ -0,0 +1,57 @@
-+Ifdef Patch
-+===========
-+
-+ Conditional config options
-+
-+Patch
-+-----
-+
-+ To check if Mutt supports "ifdef", look for "patch-ifdef" in the mutt
-+ version.
-+
-+ Dependencies
-+ * mutt-1.5.24
-+
-+Introduction
-+------------
-+
-+ 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.
-+
-+ 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
-+
-+ Here a symbol can be a $variable, <function>, command or compile-time
-+ symbol, such as "USE_IMAP".
-+
-+ 'finish' is particularly useful when combined with 'ifndef'. e.g.
-+
-+ # Sidebar config file
-+ ifndef USE_SIDEBAR finish
-+
-+Commands
-+--------
-+
-+ ifdef symbol "config-command [args]"
-+ ifndef symbol "config-command [args]"
-+ finish
-+
-+See Also
-+--------
-+
-+ * NeoMutt project
-+
-+Known Bugs
-+----------
-+
-+ None
-+
-+Credits
-+-------
-+
-+ * Cedric Duval <cedricduval at free.fr>
-+ * Matteo F. Vescovi <mfvescovi at gmail.com>
-+ * Richard Russon <rich at flatcap.org>
-+
-diff -urN mutt-1.6.1/version.c mutt-1.6.1-ifdef/version.c
---- mutt-1.6.1/version.c 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-ifdef/version.c 2016-05-02 03:02:15.459220102 +0100
-@@ -0,0 +1,492 @@
-+/**
-+ * Copyright (C) 1996-2007 Michael R. Elkins <me at mutt.org>
-+ * Copyright (C) 1999-2007 Thomas Roessler <roessler at does-not-exist.org>
-+ * Copyright (C) 2016 Richard Russon
-+ *
-+ * 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 <stdio.h>
-+#include <string.h>
-+#include <sys/utsname.h>
-+
-+#ifdef HAVE_STRINGPREP_H
-+#include <stringprep.h>
-+#elif defined (HAVE_IDN_STRINGPREP_H)
-+#include <idn/stringprep.h>
-+#endif
-+#ifdef USE_SLANG_CURSES
-+#include "slang.h"
-+#endif
-+
-+#include "lib.h"
-+
-+// #include "protos.h"
-+const char * mutt_make_version (void);
-+void mutt_print_patchlist (void);
-+
-+// #include "hcache.h"
-+const char * mutt_hcache_backend (void);
-+
-+const int SCREEN_WIDTH = 80;
-+
-+extern const char cc_version[];
-+extern const char cc_cflags[];
-+extern const char configure_options[];
-+
-+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 *License = 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"
-+);
-+
-+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"
-+);
-+
-+struct compile_options {
-+ const char *name;
-+ int enabled;
-+};
-+
-+static struct compile_options comp_opts[] = {
-+#ifdef CRYPT_BACKEND_CLASSIC_PGP
-+ { "CRYPT_BACKEND_CLASSIC_PGP", 1 },
-+#else
-+ { "CRYPT_BACKEND_CLASSIC_PGP", 0 },
-+#endif
-+#ifdef CRYPT_BACKEND_CLASSIC_SMIME
-+ { "CRYPT_BACKEND_CLASSIC_SMIME", 1 },
-+#else
-+ { "CRYPT_BACKEND_CLASSIC_SMIME", 0 },
-+#endif
-+#ifdef CRYPT_BACKEND_GPGME
-+ { "CRYPT_BACKEND_GPGME", 1 },
-+#else
-+ { "CRYPT_BACKEND_GPGME", 0 },
-+#endif
-+#ifdef DEBUG
-+ { "DEBUG", 1 },
-+#else
-+ { "DEBUG", 0 },
-+#endif
-+#ifdef DL_STANDALONE
-+ { "DL_STANDALONE", 1 },
-+#else
-+ { "DL_STANDALONE", 0 },
-+#endif
-+#ifdef ENABLE_NLS
-+ { "ENABLE_NLS", 1 },
-+#else
-+ { "ENABLE_NLS", 0 },
-+#endif
-+#ifdef EXACT_ADDRESS
-+ { "EXACT_ADDRESS", 1 },
-+#else
-+ { "EXACT_ADDRESS", 0 },
-+#endif
-+#ifdef HOMESPOOL
-+ { "HOMESPOOL", 1 },
-+#else
-+ { "HOMESPOOL", 0 },
-+#endif
-+#ifdef LOCALES_HACK
-+ { "LOCALES_HACK", 1 },
-+#else
-+ { "LOCALES_HACK", 0 },
-+#endif
-+#ifdef SUN_ATTACHMENT
-+ { "SUN_ATTACHMENT", 1 },
-+#else
-+ { "SUN_ATTACHMENT", 0 },
-+#endif
-+#ifdef HAVE_BKGDSET
-+ { "HAVE_BKGDSET", 1 },
-+#else
-+ { "HAVE_BKGDSET", 0 },
-+#endif
-+#ifdef HAVE_COLOR
-+ { "HAVE_COLOR", 1 },
-+#else
-+ { "HAVE_COLOR", 0 },
-+#endif
-+#ifdef HAVE_CURS_SET
-+ { "HAVE_CURS_SET", 1 },
-+#else
-+ { "HAVE_CURS_SET", 0 },
-+#endif
-+#ifdef HAVE_GETADDRINFO
-+ { "HAVE_GETADDRINFO", 1 },
-+#else
-+ { "HAVE_GETADDRINFO", 0 },
-+#endif
-+#ifdef HAVE_GETSID
-+ { "HAVE_GETSID", 1 },
-+#else
-+ { "HAVE_GETSID", 0 },
-+#endif
-+#ifdef HAVE_ICONV
-+ { "HAVE_ICONV", 1 },
-+#else
-+ { "HAVE_ICONV", 0 },
-+#endif
-+#ifdef HAVE_LANGINFO_CODESET
-+ { "HAVE_LANGINFO_CODESET", 1 },
-+#else
-+ { "HAVE_LANGINFO_CODESET", 0 },
-+#endif
-+#ifdef HAVE_LANGINFO_YESEXPR
-+ { "HAVE_LANGINFO_YESEXPR", 1 },
-+#else
-+ { "HAVE_LANGINFO_YESEXPR", 0 },
-+#endif
-+#ifdef HAVE_LIBIDN
-+ { "HAVE_LIBIDN", 1 },
-+#else
-+ { "HAVE_LIBIDN", 0 },
-+#endif
-+#ifdef HAVE_META
-+ { "HAVE_META", 1 },
-+#else
-+ { "HAVE_META", 0 },
-+#endif
-+#ifdef HAVE_REGCOMP
-+ { "HAVE_REGCOMP", 1 },
-+#else
-+ { "HAVE_REGCOMP", 0 },
-+#endif
-+#ifdef HAVE_RESIZETERM
-+ { "HAVE_RESIZETERM", 1 },
-+#else
-+ { "HAVE_RESIZETERM", 0 },
-+#endif
-+#ifdef HAVE_START_COLOR
-+ { "HAVE_START_COLOR", 1 },
-+#else
-+ { "HAVE_START_COLOR", 0 },
-+#endif
-+#ifdef HAVE_TYPEAHEAD
-+ { "HAVE_TYPEAHEAD", 1 },
-+#else
-+ { "HAVE_TYPEAHEAD", 0 },
-+#endif
-+#ifdef HAVE_WC_FUNCS
-+ { "HAVE_WC_FUNCS", 1 },
-+#else
-+ { "HAVE_WC_FUNCS", 0 },
-+#endif
-+#ifdef ICONV_NONTRANS
-+ { "ICONV_NONTRANS", 1 },
-+#else
-+ { "ICONV_NONTRANS", 0 },
-+#endif
-+#ifdef USE_DOTLOCK
-+ { "USE_DOTLOCK", 1 },
-+#else
-+ { "USE_DOTLOCK", 0 },
-+#endif
-+#ifdef USE_FCNTL
-+ { "USE_FCNTL", 1 },
-+#else
-+ { "USE_FCNTL", 0 },
-+#endif
-+#ifdef USE_FLOCK
-+ { "USE_FLOCK", 1 },
-+#else
-+ { "USE_FLOCK", 0 },
-+#endif
-+#ifdef USE_GNU_REGEX
-+ { "USE_GNU_REGEX", 1 },
-+#else
-+ { "USE_GNU_REGEX", 0 },
-+#endif
-+#ifdef USE_GSS
-+ { "USE_GSS", 1 },
-+#else
-+ { "USE_GSS", 0 },
-+#endif
-+#ifdef USE_HCACHE
-+ { "USE_HCACHE", 1 },
-+#else
-+ { "USE_HCACHE", 0 },
-+#endif
-+#ifdef USE_IMAP
-+ { "USE_IMAP", 1 },
-+#else
-+ { "USE_IMAP", 0 },
-+#endif
-+#ifdef USE_POP
-+ { "USE_POP", 1 },
-+#else
-+ { "USE_POP", 0 },
-+#endif
-+#ifdef USE_SASL
-+ { "USE_SASL", 1 },
-+#else
-+ { "USE_SASL", 0 },
-+#endif
-+#ifdef USE_SETGID
-+ { "USE_SETGID", 1 },
-+#else
-+ { "USE_SETGID", 0 },
-+#endif
-+#ifdef USE_SMTP
-+ { "USE_SMTP", 1 },
-+#else
-+ { "USE_SMTP", 0 },
-+#endif
-+#ifdef USE_SSL_GNUTLS
-+ { "USE_SSL_GNUTLS", 1 },
-+#else
-+ { "USE_SSL_GNUTLS", 0 },
-+#endif
-+#ifdef USE_SSL_OPENSSL
-+ { "USE_SSL_OPENSSL", 1 },
-+#else
-+ { "USE_SSL_OPENSSL", 0 },
-+#endif
-+ { NULL, 0 }
-+};
-+
-+/**
-+ * print_compile_options - Print a list of enabled/disabled features
-+ *
-+ * The configure script lets uses enable/disable features.
-+ * This shows the Mutt user which features are/aren't available.
-+ *
-+ * The output is of the form: "+ENABLED_FEATURE -DISABLED_FEATURE" and is
-+ * wrapped to SCREEN_WIDTH characters.
-+ */
-+static void
-+print_compile_options (void)
-+{
-+ int i;
-+ char c;
-+ int len;
-+ int used = 0;
-+
-+ for (i = 0; comp_opts[i].name; i++) {
-+ len = strlen (comp_opts[i].name) + 2; /* +/- and a space */
-+ if ((used + len) > SCREEN_WIDTH) {
-+ used = 0;
-+ puts ("");
-+ }
-+ used += len;
-+ c = comp_opts[i].enabled ? '+' : '-';
-+ printf ("%c%s ", c, comp_opts[i].name);
-+ }
-+ puts ("");
-+}
-+
-+/**
-+ * rstrip_in_place - Strip a trailing carriage return
-+ * @s: String to be modified
-+ *
-+ * The string has its last carriage return set to NUL.
-+ * Returns:
-+ * The modified string
-+ */
-+static char *
-+rstrip_in_place (char *s)
-+{
-+ if (!s)
-+ return NULL;
-+
-+ char *p;
-+
-+ p = &s[strlen (s)];
-+ if (p == s)
-+ return s;
-+ p--;
-+ while ((p >= s) && ((*p == '\n') || (*p == '\r')))
-+ *p-- = '\0';
-+ return s;
-+}
-+
-+/**
-+ * print_version - Print system and compile info
-+ *
-+ * Print information about the current system Mutt is running on.
-+ * Also print a list of all the compile-time information.
-+ */
-+void
-+print_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:"));
-+ print_compile_options();
-+
-+#ifdef DOMAIN
-+ printf ("DOMAIN=\"%s\"\n", DOMAIN);
-+#else
-+ puts ("-DOMAIN");
-+#endif
-+
-+#ifdef MIXMASTER
-+ printf ("MIXMASTER=\"%s\"\n", MIXMASTER);
-+#else
-+ puts ("-MIXMASTER");
-+#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);
-+
-+ puts (_(ReachingUs));
-+
-+ mutt_print_patchlist();
-+}
-+
-+/**
-+ * print_copyright - Print copyright message
-+ *
-+ * Print the authors' copyright messages, the GPL license and some contact
-+ * information for the Mutt project.
-+ */
-+void
-+print_copyright (void)
-+{
-+ puts (mutt_make_version());
-+ puts (_(Copyright));
-+ puts (_(License));
-+ puts (_(Obtaining));
-+ puts (_(ReachingUs));
-+}
-+
-+/**
-+ * feature_enabled - Test is a compile-time feature is enabled
-+ * @name: Compile-time symbol of the feature
-+ *
-+ * Many of the larger features of mutt can be disabled at compile time.
-+ * They define a symbol and use #ifdef's around their code.
-+ * The symbols are mirrored in "struct compile_options comp_opts[]" in this
-+ * file.
-+ *
-+ * This function checks if one of these symbols is present in the code.
-+ *
-+ * These symbols are also seen in the output of "mutt -v".
-+ *
-+ * Returns:
-+ * 1: Feature enables
-+ * 0: Feature not enabled, or not compiled in
-+ */
-+int
-+feature_enabled (const char *name)
-+{
-+ if (!name)
-+ return 0;
-+
-+ int i;
-+ for (i = 0; comp_opts[i].name; i++) {
-+ if (mutt_strcmp (name, comp_opts[i].name) == 0) {
-+ return 1;
-+ }
-+ }
-+ return 0;
-+}
-+
-diff -urN mutt-1.6.1/version.h mutt-1.6.1-ifdef/version.h
---- mutt-1.6.1/version.h 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-ifdef/version.h 2016-05-02 03:02:15.408219291 +0100
-@@ -0,0 +1,26 @@
-+/**
-+ * Copyright (C) 2016 Richard Russon
-+ *
-+ * 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 _VERSION_H_
-+#define _VERSION_H_
-+
-+void print_version (void);
-+void print_copyright (void);
-+int feature_enabled (const char *name);
-+
-+#endif /* _VERSION_H_ */
diff --git a/debian/patches/neomutt/12-fmemopen.patch b/debian/patches/neomutt/12-fmemopen.patch
deleted file mode 100644
index f6a8960..0000000
--- a/debian/patches/neomutt/12-fmemopen.patch
+++ /dev/null
@@ -1,366 +0,0 @@
-diff -urN mutt-1.6.1/configure.ac mutt-1.6.1-fmemopen/configure.ac
---- mutt-1.6.1/configure.ac 2016-05-02 03:02:12.398171401 +0100
-+++ mutt-1.6.1-fmemopen/configure.ac 2016-05-02 03:02:15.615222584 +0100
-@@ -1308,6 +1308,8 @@
- 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 -urN mutt-1.6.1/doc/manual.xml.head mutt-1.6.1-fmemopen/doc/manual.xml.head
---- mutt-1.6.1/doc/manual.xml.head 2016-05-02 03:02:12.402171465 +0100
-+++ mutt-1.6.1-fmemopen/doc/manual.xml.head 2016-05-02 03:02:15.618222632 +0100
-@@ -8081,6 +8081,109 @@
-
- </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.5.24</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>
-+
- </chapter>
-
- <chapter id="security">
-diff -urN mutt-1.6.1/handler.c mutt-1.6.1-fmemopen/handler.c
---- mutt-1.6.1/handler.c 2016-05-02 03:02:12.403171480 +0100
-+++ mutt-1.6.1-fmemopen/handler.c 2016-05-02 03:02:15.531221248 +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 @@
-
- fseeko (s->fpin, b->offset, 0);
-
-+#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);
--
-+#endif
- /* restore the prefix */
- s->prefix = savePrefix;
- }
-@@ -1680,6 +1707,10 @@
-
- /* restore the original source stream */
- safe_fclose (&s->fpin);
-+#ifdef HAVE_FMEMOPEN
-+ if (tempsize)
-+ FREE(&temp);
-+#endif
- s->fpin = fp;
- }
- }
-diff -urN mutt-1.6.1/PATCHES mutt-1.6.1-fmemopen/PATCHES
---- mutt-1.6.1/PATCHES 2016-05-02 03:02:12.396171369 +0100
-+++ mutt-1.6.1-fmemopen/PATCHES 2016-05-02 03:02:15.612222536 +0100
-@@ -0,0 +1 @@
-+patch-fmemopen-neo-20160502
-diff -urN mutt-1.6.1/pattern.c mutt-1.6.1-fmemopen/pattern.c
---- mutt-1.6.1/pattern.c 2016-05-02 03:02:12.411171608 +0100
-+++ mutt-1.6.1-fmemopen/pattern.c 2016-05-02 03:02:15.627222775 +0100
-@@ -144,16 +144,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 +168,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 +197,11 @@
- if (s.fpout)
- {
- safe_fclose (&s.fpout);
-+#ifdef HAVE_FMEMOPEN
-+ FREE(&temp);
-+#else
- unlink (tempfile);
-+#endif
- }
- return (0);
- }
-@@ -193,11 +210,30 @@
- mutt_body_handler (h->content, &s);
- }
-
-+#ifdef HAVE_FMEMOPEN
-+ fclose (s.fpout);
-+ lng = tempsize;
-+
-+ 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 +280,12 @@
- if (option (OPTTHOROUGHSRC))
- {
- safe_fclose (&fp);
-+#ifdef HAVE_FMEMOPEN
-+ if (tempsize)
-+ FREE(&temp);
-+#else
- unlink (tempfile);
-+#endif
- }
- }
-
-diff -urN mutt-1.6.1/README.fmemopen mutt-1.6.1-fmemopen/README.fmemopen
---- mutt-1.6.1/README.fmemopen 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-fmemopen/README.fmemopen 2016-05-02 03:02:15.613222553 +0100
-@@ -0,0 +1,47 @@
-+Fmemopen Patch
-+==============
-+
-+ Replace some temporary files with memory buffers
-+
-+Patch
-+-----
-+
-+ To check if Mutt supports "fmemopen", look for "patch-fmemopen" in the mutt
-+ version.
-+
-+ Dependencies
-+ * mutt-1.5.24
-+ * 'open_memstream()', 'fmemopen()' from glibc
-+
-+Introduction
-+------------
-+
-+ The "fmemopen" patch speeds up some searches.
-+
-+ 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.
-+
-+ There are no user-configurable parts.
-+
-+ This patch depends on 'open_memstream()' and 'fmemopen()'. They are
-+ provided by glibc. Without them, Mutt will simply create temporary files.
-+
-+See Also
-+--------
-+
-+ * NeoMutt project
-+ * Compile-Time Features
-+ * 'fmemopen(3)'
-+
-+Known Bugs
-+----------
-+
-+ None
-+
-+Credits
-+-------
-+
-+ * Julius Plenz <plenz at cis.fu-berlin.de>
-+ * Richard Russon <rich at flatcap.org>
-+
diff --git a/debian/patches/neomutt/13-initials.patch b/debian/patches/neomutt/13-initials.patch
deleted file mode 100644
index 9f1b6e6..0000000
--- a/debian/patches/neomutt/13-initials.patch
+++ /dev/null
@@ -1,264 +0,0 @@
-diff -urN mutt-1.6.1/doc/manual.xml.head mutt-1.6.1-initials/doc/manual.xml.head
---- mutt-1.6.1/doc/manual.xml.head 2016-05-02 03:02:12.402171465 +0100
-+++ mutt-1.6.1-initials/doc/manual.xml.head 2016-05-02 03:02:15.789225353 +0100
-@@ -8081,6 +8081,132 @@
-
- </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.5.24</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>
-+
- </chapter>
-
- <chapter id="security">
-diff -urN mutt-1.6.1/doc/muttrc.initials mutt-1.6.1-initials/doc/muttrc.initials
---- mutt-1.6.1/doc/muttrc.initials 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-initials/doc/muttrc.initials 2016-05-02 03:02:15.698223905 +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/hdrline.c mutt-1.6.1-initials/hdrline.c
---- mutt-1.6.1/hdrline.c 2016-05-02 03:02:12.403171480 +0100
-+++ mutt-1.6.1-initials/hdrline.c 2016-05-02 03:02:15.791225385 +0100
-@@ -212,6 +212,7 @@
- * %f = entire from line
- * %F = like %n, unless from self
- * %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
-@@ -463,6 +464,28 @@
- 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)
- {
-diff -urN mutt-1.6.1/PATCHES mutt-1.6.1-initials/PATCHES
---- mutt-1.6.1/PATCHES 2016-05-02 03:02:12.396171369 +0100
-+++ mutt-1.6.1-initials/PATCHES 2016-05-02 03:02:15.783225257 +0100
-@@ -0,0 +1 @@
-+patch-initials-neo-20160502
-diff -urN mutt-1.6.1/README.initials mutt-1.6.1-initials/README.initials
---- mutt-1.6.1/README.initials 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-initials/README.initials 2016-05-02 03:02:15.784225273 +0100
-@@ -0,0 +1,48 @@
-+Initials Expando Patch
-+======================
-+
-+ Expando for author's initials
-+
-+Patch
-+-----
-+
-+ To check if Mutt supports "Initials", look for "patch-initials" in the mutt
-+ version.
-+
-+ Dependencies
-+ * mutt-1.5.24
-+
-+Introduction
-+------------
-+
-+ The "initials" patch adds an expando (%I) for an author's initials.
-+
-+ 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.
-+
-+Variables
-+---------
-+
-+ This patch has no config of its own. It adds an expando which can be used
-+ in the $index_format variable.
-+
-+See Also
-+--------
-+
-+ * NeoMutt project
-+ * $index_format
-+ * index-color patch
-+ * folder-hook
-+
-+Known Bugs
-+----------
-+
-+ None
-+
-+Credits
-+-------
-+
-+ * Vsevolod Volkov <vvv at mutt.org.ua>
-+ * Richard Russon <rich at flatcap.org>
-+
diff --git a/debian/patches/neomutt/14-trash.patch b/debian/patches/neomutt/14-trash.patch
deleted file mode 100644
index e34f07b..0000000
--- a/debian/patches/neomutt/14-trash.patch
+++ /dev/null
@@ -1,780 +0,0 @@
-diff -urN mutt-1.6.1/commands.c mutt-1.6.1-trash/commands.c
---- mutt-1.6.1/commands.c 2016-05-02 03:02:12.398171401 +0100
-+++ mutt-1.6.1-trash/commands.c 2016-05-02 03:02:15.950227914 +0100
-@@ -720,6 +720,7 @@
- if (option (OPTDELETEUNTAG))
- mutt_set_flag (Context, h, M_TAG, 0);
- }
-+ mutt_set_flag (Context, h, M_APPENDED, 1);
-
- return 0;
- }
-diff -urN mutt-1.6.1/curs_main.c mutt-1.6.1-trash/curs_main.c
---- mutt-1.6.1/curs_main.c 2016-05-02 03:02:12.400171433 +0100
-+++ mutt-1.6.1-trash/curs_main.c 2016-05-02 03:02:15.953227962 +0100
-@@ -1919,6 +1919,7 @@
- MAYBE_REDRAW (menu->redraw);
- break;
-
-+ case OP_PURGE_MESSAGE:
- case OP_DELETE:
-
- CHECK_MSGCOUNT;
-@@ -1930,6 +1931,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 +1939,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))
-@@ -2242,11 +2246,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 +2274,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))
- {
-diff -urN mutt-1.6.1/doc/manual.xml.head mutt-1.6.1-trash/doc/manual.xml.head
---- mutt-1.6.1/doc/manual.xml.head 2016-05-02 03:02:12.402171465 +0100
-+++ mutt-1.6.1-trash/doc/manual.xml.head 2016-05-02 03:02:15.955227994 +0100
-@@ -8081,6 +8081,175 @@
- </sect2>
- </sect1>
-
-+<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.5.24</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>
-+
-+<!--
-+ <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>
-+-->
-+
-+ <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>
-+
- </chapter>
-
- <chapter id="security">
-diff -urN mutt-1.6.1/doc/muttrc.trash mutt-1.6.1-trash/doc/muttrc.trash
---- mutt-1.6.1/doc/muttrc.trash 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-trash/doc/muttrc.trash 2016-05-02 03:02:15.862226514 +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.trash mutt-1.6.1-trash/doc/vimrc.trash
---- mutt-1.6.1/doc/vimrc.trash 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-trash/doc/vimrc.trash 2016-05-02 03:02:15.863226530 +0100
-@@ -0,0 +1,7 @@
-+" Vim syntax file for the mutt trash patch
-+
-+syntax keyword muttrcVarStr contained skipwhite trash nextgroup=muttrcVarEqualsIdxFmt
-+
-+syntax match muttrcFunction contained "\<purge-message\>"
-+
-+" vim: syntax=vim
-diff -urN mutt-1.6.1/flags.c mutt-1.6.1-trash/flags.c
---- mutt-1.6.1/flags.c 2016-05-02 03:02:12.403171480 +0100
-+++ mutt-1.6.1-trash/flags.c 2016-05-02 03:02:15.956228010 +0100
-@@ -65,7 +65,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 +93,27 @@
- }
- break;
-
-+ 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;
-+
- case M_NEW:
-
- if (!mutt_bit_isset(ctx->rights,M_ACL_SEEN))
-diff -urN mutt-1.6.1/functions.h mutt-1.6.1-trash/functions.h
---- mutt-1.6.1/functions.h 2016-05-02 03:02:12.403171480 +0100
-+++ mutt-1.6.1-trash/functions.h 2016-05-02 03:02:15.956228010 +0100
-@@ -121,6 +121,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" },
-@@ -213,6 +214,7 @@
- { "print-message", OP_PRINT, "p" },
- { "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" },
-diff -urN mutt-1.6.1/globals.h mutt-1.6.1-trash/globals.h
---- mutt-1.6.1/globals.h 2016-05-02 03:02:12.403171480 +0100
-+++ mutt-1.6.1-trash/globals.h 2016-05-02 03:02:15.956228010 +0100
-@@ -141,6 +141,7 @@
- WHERE char *Status;
- WHERE char *Tempdir;
- WHERE char *Tochars;
-+WHERE char *TrashPath;
- WHERE char *TSStatusFormat;
- WHERE char *TSIconFormat;
- WHERE short TSSupported;
-diff -urN mutt-1.6.1/imap/imap.c mutt-1.6.1-trash/imap/imap.c
---- mutt-1.6.1/imap/imap.c 2016-05-02 03:02:12.404171496 +0100
-+++ mutt-1.6.1-trash/imap/imap.c 2016-05-02 03:02:15.957228026 +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);
-+ break;
- case M_FLAG:
- if (hdrs[n]->flagged != HEADER_DATA(hdrs[n])->flagged)
- match = invert ^ hdrs[n]->flagged;
-@@ -2038,3 +2044,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"));
-+ }
-+
-+ return 1;
-+}
-diff -urN mutt-1.6.1/imap/imap.h mutt-1.6.1-trash/imap/imap.h
---- mutt-1.6.1/imap/imap.h 2016-05-02 03:02:12.404171496 +0100
-+++ mutt-1.6.1-trash/imap/imap.h 2016-05-02 03:02:15.867226594 +0100
-@@ -72,4 +72,7 @@
-
- int imap_account_match (const ACCOUNT* a1, const ACCOUNT* a2);
-
-+/* trash */
-+int imap_fast_trash (void);
-+
- #endif
-diff -urN mutt-1.6.1/imap/message.c mutt-1.6.1-trash/imap/message.c
---- mutt-1.6.1/imap/message.c 2016-05-02 03:02:12.405171512 +0100
-+++ mutt-1.6.1-trash/imap/message.c 2016-05-02 03:02:15.867226594 +0100
-@@ -886,6 +886,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 +894,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.h mutt-1.6.1-trash/init.h
---- mutt-1.6.1/init.h 2016-05-02 03:02:12.407171544 +0100
-+++ mutt-1.6.1-trash/init.h 2016-05-02 03:02:15.960228073 +0100
-@@ -3419,6 +3419,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 },
- /*
-diff -urN mutt-1.6.1/mutt.h mutt-1.6.1-trash/mutt.h
---- mutt-1.6.1/mutt.h 2016-05-02 03:02:12.409171576 +0100
-+++ mutt-1.6.1-trash/mutt.h 2016-05-02 03:02:15.961228089 +0100
-@@ -182,6 +182,8 @@
- M_DELETE,
- M_UNDELETE,
- M_DELETED,
-+ M_APPENDED,
-+ M_PURGED,
- M_FLAG,
- M_TAG,
- M_UNTAG,
-@@ -719,6 +721,8 @@
- 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 changed : 1;
- unsigned int attach_del : 1; /* has an attachment marked for deletion */
-@@ -891,6 +895,7 @@
- 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 */
-
-diff -urN mutt-1.6.1/muttlib.c mutt-1.6.1-trash/muttlib.c
---- mutt-1.6.1/muttlib.c 2016-05-02 03:02:12.410171592 +0100
-+++ mutt-1.6.1-trash/muttlib.c 2016-05-02 03:02:15.962228105 +0100
-@@ -1511,7 +1511,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)
-diff -urN mutt-1.6.1/mx.c mutt-1.6.1-trash/mx.c
---- mutt-1.6.1/mx.c 2016-05-02 03:02:12.410171592 +0100
-+++ mutt-1.6.1-trash/mx.c 2016-05-02 03:02:15.962228105 +0100
-@@ -776,6 +776,62 @@
- 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;
-+
-+ 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;
-+ }
-+ }
-+
-+ mx_close_mailbox (ctx_trash, NULL);
-+ } else {
-+ mutt_error _("Can't open trash folder");
-+ return -1;
-+ }
-+
-+ return 0;
-+}
-+
- /* save changes and close mailbox */
- int mx_close_mailbox (CONTEXT *ctx, int *index_hint)
- {
-@@ -912,6 +968,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 +993,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)
-@@ -1140,6 +1205,12 @@
- msgcount = ctx->msgcount;
- deleted = ctx->deleted;
-
-+ 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);
-diff -urN mutt-1.6.1/OPS mutt-1.6.1-trash/OPS
---- mutt-1.6.1/OPS 2016-05-02 03:02:12.392171305 +0100
-+++ mutt-1.6.1-trash/OPS 2016-05-02 03:02:15.945227835 +0100
-@@ -142,6 +142,7 @@
- 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"
-diff -urN mutt-1.6.1/pager.c mutt-1.6.1-trash/pager.c
---- mutt-1.6.1/pager.c 2016-05-02 03:02:12.411171608 +0100
-+++ mutt-1.6.1-trash/pager.c 2016-05-02 03:02:15.963228121 +0100
-@@ -2351,6 +2351,7 @@
- MAYBE_REDRAW (redraw);
- break;
-
-+ case OP_PURGE_MESSAGE:
- case OP_DELETE:
- CHECK_MODE(IsHeader (extra));
- CHECK_READONLY;
-@@ -2358,6 +2359,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;
-@@ -2688,6 +2691,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 +2708,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))
- {
-diff -urN mutt-1.6.1/PATCHES mutt-1.6.1-trash/PATCHES
---- mutt-1.6.1/PATCHES 2016-05-02 03:02:12.396171369 +0100
-+++ mutt-1.6.1-trash/PATCHES 2016-05-02 03:02:15.949227898 +0100
-@@ -0,0 +1 @@
-+patch-trash-neo-20160502
-diff -urN mutt-1.6.1/pattern.c mutt-1.6.1-trash/pattern.c
---- mutt-1.6.1/pattern.c 2016-05-02 03:02:12.411171608 +0100
-+++ mutt-1.6.1-trash/pattern.c 2016-05-02 03:02:15.963228121 +0100
-@@ -1367,8 +1367,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/postpone.c mutt-1.6.1-trash/postpone.c
---- mutt-1.6.1/postpone.c 2016-05-02 03:02:12.411171608 +0100
-+++ mutt-1.6.1-trash/postpone.c 2016-05-02 03:02:15.905227198 +0100
-@@ -277,6 +277,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/README.trash mutt-1.6.1-trash/README.trash
---- mutt-1.6.1/README.trash 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-trash/README.trash 2016-05-02 03:02:15.949227898 +0100
-@@ -0,0 +1,74 @@
-+Trash Folder Patch
-+==================
-+
-+ Automatically move "deleted" emails to a trash bin
-+
-+Patch
-+-----
-+
-+ To check if Mutt supports "Trash Folder", look for "patch-trash" in the
-+ mutt version.
-+
-+ If IMAP is enabled, this patch will use it
-+
-+ Dependencies
-+ * mutt-1.5.24
-+ * IMAP support
-+
-+Introduction
-+------------
-+
-+ 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.
-+
-+ After '<sync-mailbox>' has been called the email is gone forever.
-+
-+ 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.
-+
-+ The '$trash' path can be either a full directory, or be relative to the
-+ $folder variable, like the 'mailboxes' command.
-+
-+ > Note
-+ >
-+ > Emails deleted from the trash folder are gone forever.
-+
-+Variables
-+---------
-+
-+ Trash Variables
-+
-+ | Name | Type | Default |
-+ |-------|--------|---------|
-+ | trash | string | (none) |
-+
-+Functions
-+---------
-+
-+ Trash Functions
-+
-+ | Menus | Default Key | Function | Description |
-+ |-------------|-------------|-------------------|-------------------------------------------------------------|
-+ | index,pager | (none) | '<purge-message>' | really delete the current entry, bypassing the trash folder |
-+
-+See Also
-+--------
-+
-+ * NeoMutt project
-+ * folder-hook
-+
-+Known Bugs
-+----------
-+
-+ None
-+
-+Credits
-+-------
-+
-+ * Cedric Duval <cedricduval at free.fr>
-+ * Benjamin Kuperman <kuperman at acm.org>
-+ * Paul Miller <paul at voltar.org>
-+ * Richard Russon <rich at flatcap.org>
-+
diff --git a/debian/patches/neomutt/15-limit-current-thread.patch b/debian/patches/neomutt/15-limit-current-thread.patch
deleted file mode 100644
index 22c23dd..0000000
--- a/debian/patches/neomutt/15-limit-current-thread.patch
+++ /dev/null
@@ -1,322 +0,0 @@
-diff -urN mutt-1.6.1/curs_main.c mutt-1.6.1-limit-current-thread/curs_main.c
---- mutt-1.6.1/curs_main.c 2016-05-02 03:02:12.400171433 +0100
-+++ mutt-1.6.1-limit-current-thread/curs_main.c 2016-05-02 03:02:16.152231128 +0100
-@@ -904,12 +904,14 @@
- }
- break;
-
-+ case OP_LIMIT_CURRENT_THREAD:
- case OP_MAIN_LIMIT:
-
- 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_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)
- {
-diff -urN mutt-1.6.1/doc/manual.xml.head mutt-1.6.1-limit-current-thread/doc/manual.xml.head
---- mutt-1.6.1/doc/manual.xml.head 2016-05-02 03:02:12.402171465 +0100
-+++ mutt-1.6.1-limit-current-thread/doc/manual.xml.head 2016-05-02 03:02:16.154231160 +0100
-@@ -8081,6 +8081,125 @@
-
- </sect1>
-
-+<sect1 id="limit-current-thread">
-+ <title>Limit-Current-Thread Patch</title>
-+ <subtitle>Focus on one Email Thread</subtitle>
-+
-+ <sect2 id="limit-current-thread-patch">
-+ <title>Patch</title>
-+
-+ <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>
-+
-+ <itemizedlist>
-+ <title>Dependencies:</title>
-+ <listitem><para>mutt-1.5.24</para></listitem>
-+ </itemizedlist>
-+
-+ <para>This patch is part of the <ulink url="http://www.neomutt.org/">NeoMutt Project</ulink>.</para>
-+ </sect2>
-+
-+ <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>
-+
- </chapter>
-
- <chapter id="security">
-diff -urN mutt-1.6.1/doc/muttrc.limit-current-thread mutt-1.6.1-limit-current-thread/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-limit-current-thread/doc/muttrc.limit-current-thread 2016-05-02 03:02:16.041229362 +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/functions.h mutt-1.6.1-limit-current-thread/functions.h
---- mutt-1.6.1/functions.h 2016-05-02 03:02:12.403171480 +0100
-+++ mutt-1.6.1-limit-current-thread/functions.h 2016-05-02 03:02:16.154231160 +0100
-@@ -114,6 +114,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" },
-diff -urN mutt-1.6.1/mutt_menu.h mutt-1.6.1-limit-current-thread/mutt_menu.h
---- mutt-1.6.1/mutt_menu.h 2016-05-02 03:02:12.409171576 +0100
-+++ mutt-1.6.1-limit-current-thread/mutt_menu.h 2016-05-02 03:02:16.160231255 +0100
-@@ -115,4 +115,6 @@
- void index_make_entry (char *, size_t, struct menu_t *, int);
- int index_color (int);
-
-+int mutt_limit_current_thread (HEADER *h);
-+
- #endif /* _MUTT_MENU_H_ */
-diff -urN mutt-1.6.1/OPS mutt-1.6.1-limit-current-thread/OPS
---- mutt-1.6.1/OPS 2016-05-02 03:02:12.392171305 +0100
-+++ mutt-1.6.1-limit-current-thread/OPS 2016-05-02 03:02:16.143230985 +0100
-@@ -176,6 +176,7 @@
- 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/PATCHES mutt-1.6.1-limit-current-thread/PATCHES
---- mutt-1.6.1/PATCHES 2016-05-02 03:02:12.396171369 +0100
-+++ mutt-1.6.1-limit-current-thread/PATCHES 2016-05-02 03:02:16.148231065 +0100
-@@ -0,0 +1 @@
-+patch-limit-current-thread-neo-20160502
-diff -urN mutt-1.6.1/pattern.c mutt-1.6.1-limit-current-thread/pattern.c
---- mutt-1.6.1/pattern.c 2016-05-02 03:02:12.411171608 +0100
-+++ mutt-1.6.1-limit-current-thread/pattern.c 2016-05-02 03:02:16.162231287 +0100
-@@ -1294,6 +1294,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
-+ */
-+static THREAD *
-+top_of_thread (HEADER *h)
-+{
-+ THREAD *t;
-+
-+ if (!h)
-+ return NULL;
-+
-+ t = h->thread;
-+
-+ while (t && t->parent)
-+ t = t->parent;
-+
-+ return t;
-+}
-+
-+/**
-+ * 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;
-+
-+ if (!h)
-+ return 0;
-+
-+ me = top_of_thread (h);
-+ if (!me)
-+ return 0;
-+
-+ Context->vcount = 0;
-+ Context->vsize = 0;
-+ Context->collapsed = 0;
-+
-+ 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;
-+
-+ if (top_of_thread (Context->hdrs[i]) == me) {
-+ BODY *body = Context->hdrs[i]->content;
-+
-+ 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;
-+}
-+
- int mutt_pattern_func (int op, char *prompt)
- {
- pattern_t *pat;
-diff -urN mutt-1.6.1/README.limit-current-thread mutt-1.6.1-limit-current-thread/README.limit-current-thread
---- mutt-1.6.1/README.limit-current-thread 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-limit-current-thread/README.limit-current-thread 2016-05-02 03:02:16.148231065 +0100
-@@ -0,0 +1,45 @@
-+Limit-Current-Thread Patch
-+==========================
-+
-+ Focus on one Email Thread
-+
-+Patch
-+-----
-+
-+ To check if Mutt supports "limit-current-thread", look for
-+ "patch-limit-current-thread" in the mutt version.
-+
-+ Dependencies
-+ * mutt-1.5.24
-+
-+Introduction
-+------------
-+
-+ 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.
-+
-+Functions
-+---------
-+
-+ | Menus | Default Key | Function | Description |
-+ |-------|-------------|--------------------------|------------------------------|
-+ | index | '<Esc> L' | '<limit-current-thread>' | Limit view to current thread |
-+
-+See Also
-+--------
-+
-+ * NeoMutt project
-+
-+Known Bugs
-+----------
-+
-+ None
-+
-+Credits
-+-------
-+
-+ * David Sterba <dsterba at suse.cz>
-+ * Richard Russon <rich at flatcap.org>
-+
diff --git a/debian/patches/neomutt/16-skip-quoted.patch b/debian/patches/neomutt/16-skip-quoted.patch
deleted file mode 100644
index 2bbe346..0000000
--- a/debian/patches/neomutt/16-skip-quoted.patch
+++ /dev/null
@@ -1,259 +0,0 @@
-diff -urN mutt-1.6.1/doc/manual.xml.head mutt-1.6.1-skip-quoted/doc/manual.xml.head
---- mutt-1.6.1/doc/manual.xml.head 2016-05-02 03:02:12.402171465 +0100
-+++ mutt-1.6.1-skip-quoted/doc/manual.xml.head 2016-05-02 03:02:16.766240897 +0100
-@@ -8081,6 +8081,127 @@
-
- </sect1>
-
-+<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.5.24</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>
-+
-+<!--
-+ <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>
-+-->
-+
-+ <sect2 id="skip-quoted-muttrc">
-+ <title>Muttrc</title>
-+
-+<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>
-+
- </chapter>
-
- <chapter id="security">
-diff -urN mutt-1.6.1/doc/muttrc.skip-quoted mutt-1.6.1-skip-quoted/doc/muttrc.skip-quoted
---- mutt-1.6.1/doc/muttrc.skip-quoted 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-skip-quoted/doc/muttrc.skip-quoted 2016-05-02 03:02:16.663239258 +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/globals.h mutt-1.6.1-skip-quoted/globals.h
---- mutt-1.6.1/globals.h 2016-05-02 03:02:12.403171480 +0100
-+++ mutt-1.6.1-skip-quoted/globals.h 2016-05-02 03:02:16.767240913 +0100
-@@ -204,6 +204,7 @@
- WHERE short SaveHist;
- WHERE short SendmailWait;
- WHERE short SleepTime INITVAL (1);
-+WHERE short SkipQuotedOffset;
- WHERE short TimeInc;
- WHERE short Timeout;
- WHERE short Wrap;
-diff -urN mutt-1.6.1/init.h mutt-1.6.1-skip-quoted/init.h
---- mutt-1.6.1/init.h 2016-05-02 03:02:12.407171544 +0100
-+++ mutt-1.6.1-skip-quoted/init.h 2016-05-02 03:02:16.771240977 +0100
-@@ -2703,6 +2703,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
-diff -urN mutt-1.6.1/pager.c mutt-1.6.1-skip-quoted/pager.c
---- mutt-1.6.1/pager.c 2016-05-02 03:02:12.411171608 +0100
-+++ mutt-1.6.1-skip-quoted/pager.c 2016-05-02 03:02:16.775241040 +0100
-@@ -2249,11 +2249,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 +2262,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)
-diff -urN mutt-1.6.1/PATCHES mutt-1.6.1-skip-quoted/PATCHES
---- mutt-1.6.1/PATCHES 2016-05-02 03:02:12.396171369 +0100
-+++ mutt-1.6.1-skip-quoted/PATCHES 2016-05-02 03:02:16.761240817 +0100
-@@ -0,0 +1 @@
-+patch-skip-quoted-neo-20160502
-diff -urN mutt-1.6.1/README.skip-quoted mutt-1.6.1-skip-quoted/README.skip-quoted
---- mutt-1.6.1/README.skip-quoted 1970-01-01 01:00:00.000000000 +0100
-+++ mutt-1.6.1-skip-quoted/README.skip-quoted 2016-05-02 03:02:16.761240817 +0100
-@@ -0,0 +1,47 @@
-+Skip-Quoted Patch
-+=================
-+
-+ Leave some context visible
-+
-+Patch
-+-----
-+
-+ To check if Mutt supports "Skip-Quoted", look for "patch-skip-quoted" in
-+ the mutt version.
-+
-+ Dependencies
-+ * mutt-1.5.24
-+
-+Introduction
-+------------
-+
-+ 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.
-+
-+ By setting the '$skip_quoted_offset' variable, you can select how much of
-+ the quoted text is left visible.
-+
-+Variables
-+---------
-+
-+ | Name | Type | Default |
-+ |----------------------|--------|---------|
-+ | 'skip_quoted_offset' | number | 0 |
-+
-+See Also
-+--------
-+
-+ * NeoMutt project
-+
-+Known Bugs
-+----------
-+
-+ None
-+
-+Credits
-+-------
-+
-+ * David Sterba <dsterba at suse.cz>
-+ * Richard Russon <rich at flatcap.org>
-+
diff --git a/debian/patches/neomutt/README.md b/debian/patches/neomutt/README.md
deleted file mode 100644
index 6bcd592..0000000
--- a/debian/patches/neomutt/README.md
+++ /dev/null
@@ -1,31 +0,0 @@
-# 2016-05-02 - Release for Mutt-1.6.1
-
-Many thanks to new NeoMutt contributors: Yoshiki Vázquez Baeza and Santiago Torres.
-
-This release sees many bug-fixes in Mutt, some more NeoMutt bug fixes and a
-couple of improvements to the Sidebar.
-
-Thank you to all the people who reported problems.
-
-## Fixes and Improvements
-
-- 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
-
-## Under Development
-
-Yoshiki and Santiago are working on a 'new-mail' command which is executed when
-new mail arrives. It should be ready, soon.
-
-These patches apply to Mutt-1.6.1
-
-Patches: https://github.com/neomutt/neomutt/releases/download/neomutt-20160502/neomutt-patches-20160502.tar.gz
-Source: https://github.com/neomutt/neomutt/archive/neomutt-20160502.tar.gz
-Release: https://github.com/neomutt/neomutt/tree/neomutt-20160502
-Website: http://www.neomutt.org/
-
-Rich Russon (FlatCap)
-rich at flatcap.org
-
diff --git a/debian/patches/series b/debian/patches/series
index 25cf758..d257260 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1,7 +1,5 @@
-neomutt/11-ifdef.patch
-neomutt/14-trash.patch
+neomutt-20160611.patch
neomutt-devel/sensible-browser.patch
-features/compressed-folders.patch
debian-specific/Muttrc.patch
debian-specific/Md.etc_mailname_gethostbyname.patch
debian-specific/use_usr_bin_editor.patch
@@ -17,8 +15,5 @@ upstream/528233-readonly-open.patch
upstream/228671-pipe-mime.patch
upstream/383769-score-match.patch
upstream/771125-CVE-2014-9116-jessie.patch
-upstream/path_max.patch
upstream/809802_timeout_hook.patch
-neomutt/09-sidebar.patch
features/multiple-fcc.patch
-neomutt-devel/nntp.patch
diff --git a/debian/patches/upstream/path_max.patch b/debian/patches/upstream/path_max.patch
deleted file mode 100644
index b04ddae..0000000
--- a/debian/patches/upstream/path_max.patch
+++ /dev/null
@@ -1,24 +0,0 @@
-From: Antonio Radici <antonio at debian.org>
-Date: Thu, 27 Feb 2014 17:38:03 +0100
-Subject: path_max
-
----
- mutt.h | 5 +++++
- 1 file changed, 5 insertions(+)
-
-diff --git a/mutt.h b/mutt.h
-index a6320d5..60fe281 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
-+
- #include <pwd.h>
- #include <grp.h>
-
--
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