]> granicus.if.org Git - neomutt/commitdiff
merge: notmuch
authorRichard Russon <rich@flatcap.org>
Thu, 18 Aug 2016 18:58:52 +0000 (19:58 +0100)
committerRichard Russon <rich@flatcap.org>
Thu, 18 Aug 2016 18:58:52 +0000 (19:58 +0100)
 * add ident to PATCHES
 * feature: notmuch

34 files changed:
1  2 
Makefile.am
PATCHES
browser.c
buffy.c
color.c
commands.c
compose.c
configure.ac
copy.c
copy.h
curs_lib.c
curs_main.c
enter.c
functions.h
globals.h
hdrline.c
init.c
init.h
mailbox.h
menu.c
mh.c
mutt.h
mutt_curses.h
muttlib.c
mx.c
mx.h
pattern.c
protos.h
send.c
sendlib.c
sidebar.c
status.c
url.c
url.h

diff --cc Makefile.am
Simple merge
diff --cc PATCHES
index 59a42c9f618bf1b3b09033b685226a04d5c58dda,c8efc66be1f8b827d665b4aa601b42b3b833c20c..6c27a167b9a3243737a0f671790027541f5611f2
+++ b/PATCHES
@@@ -1,19 -1,1 +1,20 @@@
 +patch-compress-neomutt
 +patch-cond-date-neomutt
 +patch-fmemopen-neomutt
 +patch-ifdef-neomutt
 +patch-index-color-neomutt
 +patch-initials-neomutt
 +patch-keywords-neomutt
 +patch-limit-current-thread-neomutt
 +patch-lmdb-neomutt
 +patch-nested-if-neomutt
 +patch-new-mail-neomutt
 +patch-nntp-neomutt
+ patch-notmuch-neomutt
 +patch-progress-neomutt
 +patch-quasi-delete-neomutt
 +patch-sidebar-neomutt
 +patch-skip-quoted-neomutt
 +patch-smime-encrypt-self-neomutt
 +patch-status-color-neomutt
 +patch-tls-sni-neomutt
diff --cc browser.c
index 2b5a2ca80455aefcafb2b5a11c70756aa7e9fb26,ee733b1bd2cd9c506b61435910fdb1a2f8307bc0..a83852de870f74fa80b8ccebd89f0db808a83912
+++ b/browser.c
  #ifdef USE_IMAP
  #include "imap.h"
  #endif
 +#ifdef USE_NNTP
 +#include "nntp.h"
 +#endif
+ #ifdef USE_NOTMUCH
+ #include "mutt_notmuch.h"
+ #endif
  
  #include <stdlib.h>
  #include <dirent.h>
@@@ -673,7 -494,35 +696,33 @@@ static int examine_directory (MUTTMENU 
    return 0;
  }
  
 -#if 0 /* MERGE with "browser sort by description" patch */
 -      add_folder (menu, state, tmp->path, tmp->desc, NULL, tmp->msg_unread, tmp->msg_count);
 -#endif
 -      add_folder (menu, state, tmp->path, NULL, tmp);
+ #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, 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;
@@@ -999,10 -803,15 +1079,18 @@@ void _mutt_select_file (char *f, size_
    if (multiple)
      menu->tag = file_tag;
  
+ #ifdef USE_NOTMUCH
+   if (flags & MUTT_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);
diff --cc buffy.c
index 6aa5f47da601bbbfbc9866d87adc6d439ddf226d,3c4386c4a23a7f2e315f5974fa3cc8514c9fe3d6..8d488f7db464404f8fb67eb421770ac4e03e9fb0
+++ b/buffy.c
@@@ -537,9 -541,9 +541,13 @@@ static void buffy_check (BUFFY *tmp, st
        tmp->magic = MUTT_POP;
        else
  #endif
 +#ifdef USE_NNTP
 +      if ((tmp->magic == MUTT_NNTP) || mx_is_nntp (tmp->path))
 +      tmp->magic = MUTT_NNTP;
++#endif
+ #ifdef USE_NOTMUCH
+       if (mx_is_notmuch (tmp->path))
+       tmp->magic = MUTT_NOTMUCH;
        else
  #endif
        if (stat (tmp->path, &sb) != 0 || (S_ISREG(sb.st_mode) && sb.st_size == 0) ||
      /* check to see if the folder is the currently selected folder
       * before polling */
      if (!Context || !Context->path ||
-       (( tmp->magic == MUTT_IMAP || tmp->magic == MUTT_POP )
 +#ifdef USE_NNTP
 +      (( tmp->magic == MUTT_IMAP || tmp->magic == MUTT_POP || tmp->magic == MUTT_NNTP )
 +#else
+       (( tmp->magic == MUTT_IMAP || tmp->magic == MUTT_POP || tmp->magic == MUTT_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)
        {
        tmp->notified = 0;
      else if (!tmp->notified)
        BuffyNotify++;
+ }
+ /* Check all Incoming for new mail and total/new/flagged messages
+  * force: if true, ignore BuffyTimeout and check for new mail anyway
+  */
+ int mutt_buffy_check (int force)
+ {
+   BUFFY *tmp;
+   struct stat contex_sb;
+   time_t t;
+   int check_stats = 0;
+   contex_sb.st_dev=0;
+   contex_sb.st_ino=0;
+ #ifdef USE_IMAP
+   /* update postponed count as well, on force */
+   if (force)
+     mutt_update_num_postponed ();
+ #endif
+   /* fastest return if there are no mailboxes */
+ #ifdef USE_NOTMUCH
+   if (!Incoming && !VirtIncoming)
+     return 0;
+ #else
+   if (!Incoming)
+     return 0;
+ #endif
+   t = time (NULL);
+   if (!force && (t - BuffyTime < BuffyTimeout))
+     return BuffyCount;
+   if (option (OPTMAILCHECKSTATS) &&
+       (t - BuffyStatsTime >= BuffyCheckStatsInterval))
+   {
+     check_stats = 1;
+     BuffyStatsTime = t;
+   }
+   BuffyTime = t;
+   BuffyCount = 0;
+   BuffyNotify = 0;
+ #ifdef USE_IMAP
+   BuffyCount += imap_buffy_check (force, check_stats);
+ #endif
+   /* check device ID and serial number instead of comparing paths */
+   if (!Context || Context->magic == MUTT_IMAP || Context->magic == MUTT_POP
++#ifdef USE_NNTP
++      || Context->magic == MUTT_NNTP
++#endif
+       || stat (Context->path, &contex_sb) != 0)
+   {
+     contex_sb.st_dev=0;
+     contex_sb.st_ino=0;
    }
  
+   for (tmp = Incoming; tmp; tmp = tmp->next)
+     buffy_check(tmp, &contex_sb, check_stats);
+ #ifdef USE_NOTMUCH
+   for (tmp = VirtIncoming; tmp; tmp = tmp->next)
+     buffy_check(tmp, &contex_sb, check_stats);
+ #endif
    BuffyDoneTime = BuffyTime;
    return (BuffyCount);
  }
diff --cc color.c
index 7b8f7cc4500ca41cd6fe315b74f0ee454c0a44e5,28d58d3fd3c4a17c76daecdbf2d81a545fb5bfdb..a9542efa6838cc2612546aa4539f9338d33f5aac
+++ b/color.c
@@@ -34,11 -34,10 +34,14 @@@ int ColorQuoteUsed
  int ColorDefs[MT_COLOR_MAX];
  COLOR_LINE *ColorHdrList = NULL;
  COLOR_LINE *ColorBodyList = NULL;
 +COLOR_LINE *ColorStatusList = NULL;
  COLOR_LINE *ColorIndexList = NULL;
 +COLOR_LINE *ColorIndexAuthorList = NULL;
 +COLOR_LINE *ColorIndexFlagsList = NULL;
 +COLOR_LINE *ColorIndexSubjectList = NULL;
+ #ifdef USE_NOTMUCH
+ COLOR_LINE *ColorIndexTagList = NULL;
+ #endif
  
  /* local to this file */
  static int ColorQuoteSize;
@@@ -97,15 -96,10 +100,19 @@@ static const struct mapping_t Fields[] 
    { "bold",           MT_COLOR_BOLD },
    { "underline",      MT_COLOR_UNDERLINE },
    { "index",          MT_COLOR_INDEX },
 +  { "progress",               MT_COLOR_PROGRESS },
 +  { "index_author",   MT_COLOR_INDEX_AUTHOR },
 +  { "index_collapsed",        MT_COLOR_INDEX_COLLAPSED },
 +  { "index_date",     MT_COLOR_INDEX_DATE },
 +  { "index_flags",    MT_COLOR_INDEX_FLAGS },
 +  { "index_label",    MT_COLOR_INDEX_LABEL },
 +  { "index_number",   MT_COLOR_INDEX_NUMBER },
 +  { "index_size",     MT_COLOR_INDEX_SIZE },
 +  { "index_subject",  MT_COLOR_INDEX_SUBJECT },
+ #ifdef USE_NOTMUCH
+   { "index_tag",      MT_COLOR_INDEX_TAG },
+   { "index_tags",     MT_COLOR_INDEX_TAGS },
+ #endif
    { "prompt",         MT_COLOR_PROMPT },
  #ifdef USE_SIDEBAR
    { "sidebar_divider",        MT_COLOR_DIVIDER },
@@@ -520,18 -460,49 +527,22 @@@ static int _mutt_parse_uncolor (BUFFER 
      return 0;
    }
  
 -#if 0 /* MERGE with "index-color" patch */
 +  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
 -#endif
 -  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 (do_cache && !option (OPTNOCURSES))
    {
@@@ -772,13 -741,13 +783,15 @@@ _mutt_parse_color (BUFFER *buf, BUFFER 
  
    /* extract a regular expression if needed */
    
 -#if 0 /* MERGE with "index-color" patch */
 +  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)
++      (object == MT_COLOR_INDEX_TAG) ||
+ #endif
 -#endif
 -  if (object == MT_COLOR_HEADER || object == MT_COLOR_BODY || object == MT_COLOR_INDEX)
 -  {
++      (object == MT_COLOR_INDEX_SUBJECT)) {
      if (!MoreArgs (s))
      {
        strfcpy (err->data, _("too few arguments"), err->dsize);
  #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);
    }
 -                  fg, bg, attr, err, 1);
+ #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 --cc commands.c
index 62a941f0a046b7b0b3f3b3b2ef1152ac2c7dcbf2,bb439f8bafef75bc8294ad6f29d3a3f943b91902..8547feda4e85235e33073753ca7940b8bbe8318b
@@@ -876,25 -869,19 +893,36 @@@ int mutt_save_message (HEADER *h, int d
        if (Context->hdrs[Context->v2r[i]]->tagged)
        {
          mutt_message_hook (Context, Context->hdrs[Context->v2r[i]], MUTT_MESSAGEHOOK);
 +        if (_mutt_save_message(Context->hdrs[Context->v2r[i]],
 +                           &ctx, delete, decode, decrypt) != 0)
 +          {
 +            mx_close_mailbox (&ctx, NULL);
 +            return -1;
 +          }
 +#ifdef USE_COMPRESSED
 +          if (cm)
 +          {
 +            HEADER *h = Context->hdrs[Context->v2r[i]];
 +            cm->msg_count++;
 +            if (!h->read)
 +              cm->msg_unread++;
 +            if (h->flagged)
 +              cm->msg_flagged++;
 +          }
 +#endif
+         if ((rc = _mutt_save_message(Context->hdrs[Context->v2r[i]],
+                            &ctx, delete, decode, decrypt) != 0))
+           break;
        }
        }
+ #ifdef USE_NOTMUCH
+       if (Context->magic == MUTT_NOTMUCH)
+         nm_longrun_done(Context);
+ #endif
+       if (rc != 0) {
+       mx_close_mailbox (&ctx, NULL);
+       return -1;
+       }
      }
  
      need_buffy_cleanup = (ctx.magic == MUTT_MBOX || ctx.magic == MUTT_MMDF);
diff --cc compose.c
Simple merge
diff --cc configure.ac
index 9add9732932e78964ed0553e6792104ec9964c1b,91263d4342c8fd291c17f18873f6b04d29f16517..e839fcac5cf071761f37dcd60e5038a37fecf6c7
@@@ -175,22 -175,38 +175,46 @@@ if test x$have_smime != xno ; the
        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(sidebar, AC_HELP_STRING([--enable-sidebar], [Enable Sidebar support]), enable_sidebar=$enableval, enable_sidebar=no)
 +AS_IF([test x$enable_sidebar = "xyes"], [
 +         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"
 +])
 +
 +AC_ARG_ENABLE(compressed, AC_HELP_STRING([--enable-compressed], [Enable compressed folders support]),
 +              enable_compressed=$enableval, enable_compressed=no
 +)
 +AS_IF([test x$enable_compressed = "xyes"], [
 +         AC_DEFINE(USE_COMPRESSED, 1, [Define to enable compressed folders support.])
 +         MUTT_LIB_OBJECTS="$MUTT_LIB_OBJECTS compress.o"
  ])
 +AM_CONDITIONAL(BUILD_COMPRESS, test x$enable_compressed = xyes)
  
+ AC_ARG_ENABLE(notmuch, AC_HELP_STRING([--enable-notmuch], [Enable NOTMUCH support]), enable_notmuch=$enableval, enable_notmuch=no)
+ AS_IF([test x$enable_notmuch = "xyes"], [
+               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])
+ ])
+ 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
diff --cc copy.c
index 5f938b328ef68ea2c559feb50cf21ac6fc477e3b,7775a894ee9d398f8a5faae3975ebd9218e80f03..bfcd3a543a74af79d2fd899402297e9a8b23bd3a
--- 1/copy.c
--- 2/copy.c
+++ b/copy.c
@@@ -423,61 -419,15 +428,70 @@@ mutt_copy_header (FILE *in, HEADER *h, 
        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 & MUTT_X_LABEL) || (h->env->kwtypes == 0)) &&
 +          (option(OPTKEYWORDSLEGACY) || option(OPTKEYWORDSSTANDARD) == 0))
 +      {
 +        mutt_labels(buf, sizeof(buf), h->env, XlabelDelim);
 +        tmp = safe_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 & MUTT_X_KEYWORDS) &&
 +          (option(OPTKEYWORDSLEGACY) || option(OPTKEYWORDSSTANDARD) == 0))
 +      {
 +        mutt_labels(buf, sizeof(buf), h->env, " ");
 +        tmp = safe_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 & MUTT_X_MOZILLA_KEYS) &&
 +          (option(OPTKEYWORDSLEGACY) || option(OPTKEYWORDSSTANDARD) == 0))
 +      {
 +        mutt_labels(buf, sizeof(buf), h->env, " ");
 +        tmp = safe_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 & MUTT_KEYWORDS) ||
 +                        option(OPTKEYWORDSSTANDARD)))
 +      {
 +        mutt_labels(buf, sizeof(buf), h->env, NULL);
 +        tmp = safe_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)
diff --cc copy.h
index 2ba54143fc856dcdb44b676eec7ec1133b064196,141b97ea499c434e18f65a29e10771b4d9a72918..b47c7fbd083c1002461dc264de485ff8b709a9f8
--- 1/copy.h
--- 2/copy.h
+++ b/copy.h
@@@ -53,7 -53,7 +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<<19) /* update X-Label: from hdr->env->x_label? */
++#define CH_VIRTUAL      (1<<20) /* write virtual header lines too */
  
  
  int mutt_copy_hdr (FILE *, FILE *, LOFF_T, LOFF_T, int, const char *);
diff --cc curs_lib.c
Simple merge
diff --cc curs_main.c
index 6f8fb3ba8a161c34dbaea194a5785bff77a8dcce,9b34db64653308b601714343d96811d4ea13c93a..d722a22a6a64e61ab8460da0728c6aa11402232c
  #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>
@@@ -489,140 -486,71 +493,223 @@@ static void resort_index (MUTTMENU *men
    menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
  }
  
 -                        int *oldcount, int *index_hint)
 +/**
 + * mutt_draw_statusline - Draw a highlighted status bar
 + * @cols:  Maximum number of screen columns
 + * @buf:   Message to be displayed
 + *
 + * Users configure the highlighting of the status bar, e.g.
 + *     color status red default "[0-9][0-9]:[0-9][0-9]"
 + *
 + * Where regexes overlap, the one nearest the start will be used.
 + * If two regexes start at the same place, the longer match will be used.
 + */
 +void
 +mutt_draw_statusline (int cols, const char *buf, int buflen)
 +{
 +  int i      = 0;
 +  int offset = 0;
 +  int found  = 0;
 +  int chunks = 0;
 +  int len    = 0;
 +
 +  struct syntax_t
 +  {
 +    int color;
 +    int first;
 +    int last;
 +  } *syntax = NULL;
 +
 +  if (!buf)
 +    return;
 +
 +  do
 +  {
 +    COLOR_LINE *cl;
 +    found = 0;
 +
 +    if (!buf[offset])
 +      break;
 +
 +    /* loop through each "color status regex" */
 +    for (cl = ColorStatusList; cl; cl = cl->next)
 +    {
 +      regmatch_t pmatch[cl->match + 1];
 +
 +      if (regexec (&cl->rx, buf + offset, cl->match + 1, pmatch, 0) != 0)
 +        continue; /* regex doesn't match the status bar */
 +
 +      int first = pmatch[cl->match].rm_so + offset;
 +      int last  = pmatch[cl->match].rm_eo + offset;
 +
 +      if (first == last)
 +        continue; /* ignore an empty regex */
 +
 +      if (!found)
 +      {
 +        chunks++;
 +        safe_realloc (&syntax, chunks * sizeof (struct syntax_t));
 +      }
 +
 +      i = chunks - 1;
 +      if (!found || (first < syntax[i].first) || ((first == syntax[i].first) && (last > syntax[i].last)))
 +      {
 +        syntax[i].color = cl->pair;
 +        syntax[i].first = first;
 +        syntax[i].last  = last;
 +      }
 +      found = 1;
 +    }
 +
 +    if (syntax)
 +    {
 +      offset = syntax[i].last;
 +    }
 +  } while (found);
 +
 +  /* Only 'len' bytes will fit into 'cols' screen columns */
 +  len = mutt_wstr_trunc (buf, buflen, cols, NULL);
 +
 +  offset = 0;
 +
 +  if ((chunks > 0) && (syntax[0].first > 0))
 +  {
 +    /* Text before the first highlight */
 +    addnstr (buf, MIN(len, syntax[0].first));
 +    attrset (ColorDefs[MT_COLOR_STATUS]);
 +    if (len <= syntax[0].first)
 +      goto dsl_finish;  /* no more room */
 +
 +    offset = syntax[0].first;
 +  }
 +
 +  for (i = 0; i < chunks; i++)
 +  {
 +    /* Highlighted text */
 +    attrset (syntax[i].color);
 +    addnstr (buf + offset, MIN(len, syntax[i].last) - offset);
 +    if (len <= syntax[i].last)
 +      goto dsl_finish;  /* no more room */
 +
 +    int next;
 +    if ((i + 1) == chunks)
 +    {
 +      next = len;
 +    }
 +    else
 +    {
 +      next = MIN (len, syntax[i+1].first);
 +    }
 +
 +    attrset (ColorDefs[MT_COLOR_STATUS]);
 +    offset = syntax[i].last;
 +    addnstr (buf + offset, next - offset);
 +
 +    offset = next;
 +    if (offset >= len)
 +      goto dsl_finish;  /* no more room */
 +  }
 +
 +  attrset (ColorDefs[MT_COLOR_STATUS]);
 +  if (offset < len)
 +  {
 +    /* Text after the last highlight */
 +    addnstr (buf + offset, len - offset);
 +  }
 +
 +  int width = mutt_strwidth (buf);
 +  if (width < cols)
 +  {
 +    /* Pad the rest of the line with whitespace */
 +    mutt_paddstr (cols - width, "");
 +  }
 +dsl_finish:
 +  FREE(&syntax);
 +}
 +
+ static int main_change_folder(MUTTMENU *menu, int op, char *buf, size_t bufsz,
++                        int *oldcount, int *index_hint, int flags)
+ {
++#ifdef USE_NNTP
++  if (option (OPTNEWS))
++  {
++    unset_option (OPTNEWS);
++    nntp_expand_path (buf, bufsz, &CurrentNewsSrv->conn->account);
++  }
++  else
++#endif
+   mutt_expand_path (buf, bufsz);
+   if (mx_get_magic (buf) <= 0)
+   {
+     mutt_error (_("%s is not a mailbox."), buf);
+     return -1;
+   }
+   mutt_str_replace (&CurrentFolder, buf);
+   /* keepalive failure in mutt_enter_fname may kill connection. #3028 */
+   if (Context && !Context->path)
+     FREE (&Context);
+   if (Context)
+   {
+     int check;
++#ifdef USE_COMPRESSED
++        if (Context->compress_info && Context->realpath)
++          mutt_str_replace (&LastFolder, Context->realpath);
++        else
++#endif
+     mutt_str_replace (&LastFolder, Context->path);
+     *oldcount = Context ? Context->msgcount : 0;
+     if ((check = mx_close_mailbox (Context, index_hint)) != 0)
+     {
+       if (check == MUTT_NEW_MAIL || check == MUTT_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,
+               (option (OPTREADONLY) || op == OP_MAIN_CHANGE_FOLDER_READONLY) ?
+               MUTT_READONLY : 0, NULL)) != NULL)
+   {
++    Labels = hash_create(131, 0);
++    mutt_scan_labels(Context);
+     menu->current = ci_first_message ();
+   }
+   else
+     menu->current = 0;
+ #ifdef USE_SIDEBAR
+         mutt_sb_set_open_buffy ();
+ #endif
+   mutt_clear_error ();
+   mutt_buffy_check(1); /* force the buffy check after we have changed the folder */
+   menu->redraw = REDRAW_FULL;
+   set_option (OPTSEARCHINVALID);
+   return 0;
+ }
  static const struct mapping_t IndexHelp[] = {
    { N_("Quit"),  OP_QUIT },
    { N_("Del"),   OP_DELETE },
@@@ -945,9 -842,11 +1032,15 @@@ int mutt_index_menu (void
        mutt_curs_set (1);      /* fallback from the pager */
      }
  
 +#ifdef USE_NNTP
 +    unset_option (OPTNEWS);   /* for any case */
 +#endif
++
+ #ifdef USE_NOTMUCH
+     if (Context)
+       nm_debug_check(Context);
+ #endif
      switch (op)
      {
  
          menu->redraw = REDRAW_FULL;
        break;
  
 -        main_change_folder(menu, op, buf, sizeof (buf), &oldcount, &index_hint);
 +      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;
 +
+ #ifdef USE_NOTMUCH
+       case OP_MAIN_ENTIRE_THREAD:
+       {
+       int oldcount  = Context->msgcount;
+       if (Context->magic != MUTT_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 != MUTT_NOTMUCH) {
+         mutt_message _("No virtual folder, aborting.");
+         break;
+       }
+       CHECK_MSGCOUNT;
+         CHECK_VISIBLE;
+       *buf = '\0';
+       if (mutt_get_field ("Add/remove labels: ", buf, sizeof (buf), MUTT_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, MUTT_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), MUTT_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:
 -
 -      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 = MUTT_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';
          }
        }
  
- #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));
-       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;
- #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 == MUTT_NEW_MAIL || check == MUTT_REOPENED)
-             update_index (menu, Context, check, oldcount, index_hint);
-           set_option (OPTSEARCHINVALID);
-           menu->redraw = REDRAW_INDEX | REDRAW_STATUS;
-           break;
-         }
-         FREE (&Context);
-       }
-         if (Labels)
-           hash_destroy(&Labels, NULL);
-         mutt_sleep (0);
-       /* Set CurrentMenu to MENU_MAIN before executing any folder
-        * hooks so that all the index menu functions are available to
-        * the exec command.
-        */
-       CurrentMenu = MENU_MAIN;
-       mutt_folder_hook (buf);
-       if ((Context = mx_open_mailbox (buf, flags, NULL)) != NULL)
-       {
-         Labels = hash_create(131, 0);
-         mutt_scan_labels(Context);
-         menu->current = ci_first_message ();
-       }
-       else
-         menu->current = 0;
- #ifdef USE_SIDEBAR
-         mutt_sb_set_open_buffy ();
- #endif
 -      main_change_folder(menu, op, buf, sizeof (buf), &oldcount, &index_hint);
++      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 == MUTT_NNTP)) ? IndexNewsHelp : IndexHelp);
 +#endif
-       mutt_clear_error ();
-       mutt_buffy_check(1); /* force the buffy check after we have changed
-                             the folder */
-       menu->redraw = REDRAW_FULL;
-       set_option (OPTSEARCHINVALID);
++      mutt_expand_path (buf, sizeof (buf));
++#ifdef USE_SIDEBAR
++        mutt_sb_set_open_buffy();
++#endif
        break;
  
        case OP_DISPLAY_MESSAGE:
diff --cc enter.c
Simple merge
diff --cc functions.h
Simple merge
diff --cc globals.h
index 95390ba0fa0ba20b9d01769cc143b376e4015f50,16aa0ee6eb25a27a81960b0abe086d33d094f3e8..29593cb52cea4d66d564be17ce8862f80aff96c2
+++ b/globals.h
@@@ -175,8 -161,11 +175,12 @@@ WHERE char *LastFolder
  WHERE const char *ReleaseDate;
  
  WHERE HASH *Groups;
 +WHERE HASH *Labels;
  WHERE HASH *ReverseAlias;
+ #ifdef USE_NOTMUCH
+ WHERE HASH *TagTransforms;
+ WHERE HASH *TagFormats;
+ #endif
  
  WHERE LIST *AutoViewList INITVAL(0);
  WHERE LIST *AlternativeOrderList INITVAL(0);
diff --cc hdrline.c
index 5cd0045a6152c2d7616b40c1aa1a083ad99a598f,702daa476c63b13ed8a0f3de11b6c581bdfc3d75..71a3fa8a9502d723e9e3f812cb04f7c94ba5b8c9
+++ b/hdrline.c
@@@ -243,9 -215,8 +247,10 @@@ int mutt_user_is_recipient (HEADER *h
   * %E = number of messages in current thread
   * %f = entire from line
   * %F = like %n, unless from self
 + * %g = newsgroup name (if compiled with NNTP support)
+  * %g = message labels (e.g. notmuch tags)
   * %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
@@@ -590,6 -453,22 +595,19 @@@ hdr_format_str (char *dest
          optional = 0;
        break;
  
 -#if 0 /* MERGE with "index-color" patch */
+ #ifdef USE_NOTMUCH
+     case 'g':
+       if (!optional)
+       {
 -#endif
 -        mutt_format_s (dest, destlen, prefix, nm_header_get_tags_transformed(hdr));
+         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)
  
        break;
  
-     case 'g':
 +#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;
  
        break;
  
 -#if 0 /* MERGE with "index-color" patch */
+ #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);
 -#endif
 -            mutt_format_s (dest, destlen, prefix, (tag_transformed) ? tag_transformed : "");
+             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);
diff --cc init.c
index 35b51006f4f14925bf6089aa6eada9b9c64d622f,0916a3097ef323fff8b21e2e4f3a7bed450e8ecd..4e4802ad07a362c69d21f7d0410d189daee90323
--- 1/init.c
--- 2/init.c
+++ b/init.c
@@@ -3020,11 -3099,19 +3204,15 @@@ void mutt_init (int skip_sys_rc, LIST *
  
    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 */
diff --cc init.h
index d5a53f60920d3aebcc74c5aa688427534f5d79f0,2960a6efe57d36f99f7a24c1f2599f748139ee97..ef154409d8c0653356850bdf09e98962dde0a55d
--- 1/init.h
--- 2/init.h
+++ b/init.h
@@@ -1385,7 -1326,7 +1385,8 @@@ struct option_t MuttVars[] = 
    ** .dt %E .dd number of messages in current thread
    ** .dt %f .dd sender (address + real name), either From: or Return-Path:
    ** .dt %F .dd author name, or recipient name if the message is from you
 +  ** .dt %g .dd newsgroup name (if compiled with NNTP support)
+   ** .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,
     ** 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" },
    /*
diff --cc mailbox.h
Simple merge
diff --cc menu.c
index 083f5a21e68690d2e095328ceb95452f357b327d,05f19bcdc7780d549eac8455c9a7c535c898940b..252760c4ba0b4eb033890515a6a776ce9d8a3f8d
--- 1/menu.c
--- 2/menu.c
+++ b/menu.c
@@@ -36,34 -34,21 +36,45 @@@ char* SearchBuffers[MENU_MAX]
  static int
  get_color (int index, unsigned char *s)
  {
 -                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;
 +  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, MUTT_MATCH_FULL_ADDRESS,
 +        Context, hdr))
 +      return color->pair;
 +
 +  return 0;
  }
 -#endif
  
 -static void print_enriched_string (int attr, unsigned char *s, int do_color)
 +static void print_enriched_string (int index, int attr, unsigned char *s, int do_color)
  {
    wchar_t wc;
    size_t k;
diff --cc mh.c
index 8e0da76ef12ac1fa687e784ecd321deb69c6e8bf,321fba6796e67c05457a0e144f807f7fcba8baa4..c90679ec6ae4d7bc14a87ce66ac58dbbc2872efc
--- 1/mh.c
--- 2/mh.c
+++ b/mh.c
@@@ -1923,11 -1926,10 +1926,11 @@@ int mh_sync_mailbox_message (CONTEXT * 
  
        }
      }
-     else if (ctx->hdrs[i]->changed || ctx->hdrs[i]->attach_del ||
-            ctx->hdrs[i]->label_changed ||
+     else if (h->changed || h->attach_del ||
++           h->label_changed ||
             (ctx->magic == MUTT_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 == MUTT_MAILDIR)
        {
diff --cc mutt.h
index be67f1cb318f5aa848df59f5b5328f34eb2b7e03,27128882b3b0011dee44fd5420aba8bc2f27a95c..df47189527c2a87390a04f65a0aaca6d9c374564
--- 1/mutt.h
--- 2/mutt.h
+++ b/mutt.h
  #define  MUTT_CLEAR   (1<<5) /* clear input if printable character is pressed */
  #define  MUTT_COMMAND (1<<6) /* do command completion */
  #define  MUTT_PATTERN (1<<7) /* pattern mode - only used for history classes */
 -#define  MUTT_NM_QUERY (1<<8) /* Notmuch query mode. */
 -#define  MUTT_NM_TAG   (1<<9) /* Notmuch tag +/- mode. */
 +#define  MUTT_LABEL   (1<<8) /* do label completion */
+ #if USE_NOTMUCH
++#define  MUTT_NM_QUERY (1<<9) /* Notmuch query mode. */
++#define  MUTT_NM_TAG   (1<<10) /* Notmuch tag +/- mode. */
+ #endif
  
  /* flags for mutt_get_token() */
  #define MUTT_TOKEN_EQUAL      1       /* treat '=' as a special */
@@@ -246,10 -229,10 +250,13 @@@ enu
    MUTT_CRYPT_ENCRYPT,
    MUTT_PGP_KEY,
    MUTT_XLABEL,
+ #ifdef USE_NOTMUCH
+   MUTT_NOTMUCH_LABEL,
+ #endif
    MUTT_MIMEATTACH,
 +#ifdef USE_NNTP
 +  MUTT_NEWSGROUPS,
 +#endif
    
    /* Options for Mailcap lookup */
    MUTT_EDIT,
@@@ -588,10 -539,10 +596,14 @@@ enu
    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
+ #ifdef USE_NOTMUCH
+   OPTVIRTSPOOLFILE,
+   OPTNOTMUCHRECORD,
+ #endif
  
    OPTMAX
  };
@@@ -868,8 -809,9 +880,9 @@@ typedef struct heade
    int refno;                  /* message number on server */
  #endif
  
- #if defined USE_POP || defined USE_IMAP || defined USE_NNTP
 -#if defined USE_POP || defined USE_IMAP || defined USE_NOTMUCH
++#if defined USE_POP || defined USE_IMAP || defined USE_NNTP || 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 --cc mutt_curses.h
index bc94cb98978620bf78f416ee5cc0e7b6ff4a2846,3f7bf82f00aa1aebb2b70d9b66f77208caadc91f..5ffcdb6db8a5f58a8ce8b3fcd043dd006adfbdab
@@@ -121,17 -131,10 +121,21 @@@ enu
    MT_COLOR_SB_INDICATOR,
    MT_COLOR_SB_SPOOLFILE,
  #endif
 +  /* 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,
+ #ifdef USE_NOTMUCH
+   MT_COLOR_INDEX_TAG,
+   MT_COLOR_INDEX_TAGS,
+ #endif
    MT_COLOR_MAX
  };
  
@@@ -214,12 -216,12 +218,16 @@@ extern int ColorQuoteUsed
  extern int ColorDefs[];
  extern COLOR_LINE *ColorHdrList;
  extern COLOR_LINE *ColorBodyList;
 +extern COLOR_LINE *ColorStatusList;
  extern COLOR_LINE *ColorIndexList;
 +extern COLOR_LINE *ColorIndexAuthorList;
 +extern COLOR_LINE *ColorIndexFlagsList;
 +extern COLOR_LINE *ColorIndexSubjectList;
  
+ #ifdef USE_NOTMUCH
+ extern COLOR_LINE *ColorIndexTagList;
+ #endif
  void ci_init_color (void);
  void ci_start_color (void);
  
diff --cc muttlib.c
index ad08ba48e11a318dbc5732fe38de8dd48ab8e1e9,3774d946e1fc0e6899bd1e8224541ec416397708..113d50c3038fdae2f32d5eaf1c70122a5af2e9bc
+++ b/muttlib.c
@@@ -334,7 -335,9 +338,9 @@@ void mutt_free_header (HEADER **h
  #ifdef MIXMASTER
    mutt_free_list (&(*h)->chain);
  #endif
- #if defined USE_POP || defined USE_IMAP || defined USE_NNTP
 -#if defined USE_POP || defined USE_IMAP || defined USE_NOTMUCH
++#if defined USE_POP || defined USE_IMAP || defined USE_NNTP || defined USE_NOTMUCH
+   if ((*h)->free_cb)
+     (*h)->free_cb(*h);
    FREE (&(*h)->data);
  #endif
    FREE (h);           /* __FREE_CHECKED__ */
diff --cc mx.c
index 17a2486c6a0251fa5da6698820af6188bec5fbc7,983330692598d23019625e419e910c435b10f446..414602a60af7d7d04b674d05ef9a9806eb9ac3ac
--- 1/mx.c
--- 2/mx.c
+++ b/mx.c
  #include "pop.h"
  #endif
  
 +#ifdef USE_NNTP
 +#include "nntp.h"
 +#endif
 +
+ #ifdef USE_NOTMUCH
+ #include "mutt_notmuch.h"
+ #endif
  #include "buffy.h"
  
  #ifdef USE_DOTLOCK
@@@ -88,13 -84,9 +92,17 @@@ struct mx_ops* mx_get_ops (int magic
      case MUTT_POP:
        return &mx_pop_ops;
  #endif
 +#ifdef USE_COMPRESSED
 +    case MUTT_COMPRESSED:
 +      return &mx_comp_ops;
 +#endif
 +#ifdef USE_NNTP
 +    case MUTT_NNTP:
 +      return &mx_nntp_ops;
++#endif
+ #ifdef USE_NOTMUCH
+     case MUTT_NOTMUCH:
+       return &mx_notmuch_ops;
  #endif
      default:
        return NULL;
@@@ -386,22 -378,24 +394,40 @@@ 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
 +
+ #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;
      return MUTT_POP;
  #endif /* USE_POP */
  
 +#ifdef USE_NNTP
 +  if (mx_is_nntp (path))
 +    return MUTT_NNTP;
 +#endif /* USE_NNTP */
 +
+ #ifdef USE_NOTMUCH
+   if (mx_is_notmuch(path))
+     return MUTT_NOTMUCH;
+ #endif
    if (stat (path, &st) == -1)
    {
      dprint (1, (debugfile, "mx_get_magic(): unable to stat %s: %s (errno %d).\n",
@@@ -749,11 -732,12 +780,18 @@@ static int sync_mailbox (CONTEXT *ctx, 
        break;
  #endif /* USE_POP */
  
 +#ifdef USE_NNTP
 +    case MUTT_NNTP:
 +      rc = nntp_sync_mailbox (ctx);
 +      break;
 +#endif /* USE_NNTP */
++
+ #ifdef USE_NOTMUCH
+     case MUTT_NOTMUCH:
+       rc = nm_sync (ctx, index_hint);
+       break;
+ #endif /* USE_NOTMUCH */
    }
  
  #if 0
diff --cc mx.h
index 07d4dc6895664493f88f27e49b9f400621150dc8,6460af340aad8a1630bd44853a15a82605177cf3..2f62abfdaf220bd140e166c2b7d2e8694070a64d
--- 1/mx.h
--- 2/mx.h
+++ b/mx.h
@@@ -35,14 -35,9 +35,15 @@@ enu
    MUTT_MMDF,
    MUTT_MH,
    MUTT_MAILDIR,
 +#ifdef USE_NNTP
 +  MUTT_NNTP,
 +#endif
    MUTT_IMAP,
+   MUTT_NOTMUCH,
    MUTT_POP
 +#ifdef USE_COMPRESSED
 +  , MUTT_COMPRESSED
 +#endif
  };
  
  WHERE short DefaultMagic INITVAL (MUTT_MBOX);
diff --cc pattern.c
index 13493a2941f865d2f6bc04651fa127187dbdf82c,3a18ae986cb2e343494f2e1caa0c933af0a0589f..0a3315c0dbc5a713df98ca2f2f394647bf2e3710
+++ b/pattern.c
@@@ -1253,19 -1216,14 +1260,27 @@@ mutt_pattern_exec (struct pattern_t *pa
         break;
       return (pat->not ^ ((h->security & APPLICATION_PGP) && (h->security & PGPKEY)));
      case MUTT_XLABEL:
 +      {
 +        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;
 +      }
+       return (pat->not ^ (h->env->x_label && patmatch (pat, h->env->x_label) == 0));
+ #ifdef USE_NOTMUCH
+     case MUTT_NOTMUCH_LABEL:
+       {
+       char *tags = nm_header_get_tags(h);
+       return (pat->not ^ (tags && patmatch (pat, tags) == 0));
+       }
+ #endif
      case MUTT_HORMEL:
        return (pat->not ^ (h->env->spam && h->env->spam->data && patmatch (pat, h->env->spam->data) == 0));
      case MUTT_DUPLICATED:
diff --cc protos.h
Simple merge
diff --cc send.c
index d4bc232cb67491b2e54c7afa4ef88215669ed72d,a86cca78be87aee129a73af028d0d4df142baaf4..59953dca8e4e47bc1fa27b6803107285b1fc565a
--- 1/send.c
--- 2/send.c
+++ b/send.c
@@@ -2038,13 -1907,13 +2045,18 @@@ full_fcc
        goto cleanup;
      }
    }
-   else if (!option (OPTNOCURSES) && ! (flags & SENDMAILX))
+   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
+ #ifdef USE_NOTMUCH
+     if (option(OPTNOTMUCHRECORD))
+       nm_record_message(ctx, finalpath, cur);
+ #endif
+   }
  
    if (WithCrypto && (msg->security & ENCRYPT))
      FREE (&pgpkeylist);
diff --cc sendlib.c
Simple merge
diff --cc sidebar.c
index 1a202a660b68e399ab46f6543f7092e6ccc12055,0cc70224a173ae8b25553b203bb6e56b694369fe..2a465bf1ab7c286b03753d55346d79ce997757c8
+++ b/sidebar.c
@@@ -699,9 -718,14 +743,14 @@@ void mutt_sb_draw (void
    if (div_width < 0)
      return;
  
-   if (!Incoming)
+   BUFFY *b;
+   if (Entries == NULL)
+     for (b = get_incoming(); b; b = b->next)
+       mutt_sb_notify_mailbox (b, 1);
+   if (!get_incoming())
    {
 -    fill_empty_space (0, num_rows, SidebarWidth - div_width);
 +    fill_empty_space (0, num_rows, div_width, num_cols - div_width);
      return;
    }
  
diff --cc status.c
index 52baa8c1d79afeccf48f361bc4959b95ea351d8e,9fb221e07e5f98cf70c47a848afce62d217d3cbe..67007307dc57a6b1f9037b30d41cde78aea0f566
+++ b/status.c
@@@ -95,12 -99,13 +99,19 @@@ status_format_str (char *buf, size_t bu
        break;
  
      case 'f':
-       snprintf (fmt, sizeof(fmt), "%%%ss", prefix);
+     {
+ #ifdef USE_NOTMUCH
+       char *p;
+       if (Context && Context->magic == MUTT_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)
        {
diff --cc url.c
index 799e95619256518d268b158ef8d71b24d3748dfd,51b1949fde2e8eed03e5d5559075b5fefe989477..d11b8d73ac40873e1033a6d0252b42a0e7ecc93b
--- 1/url.c
--- 2/url.c
+++ b/url.c
@@@ -39,9 -39,10 +39,12 @@@ static const struct mapping_t UrlMap[] 
    { "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 }
diff --cc url.h
Simple merge