]> granicus.if.org Git - neomutt/commitdiff
reformat the source to mutt standards
authorRichard Russon <rich@flatcap.org>
Sun, 15 Jan 2017 01:22:48 +0000 (01:22 +0000)
committerRichard Russon <rich@flatcap.org>
Mon, 16 Jan 2017 18:09:59 +0000 (18:09 +0000)
reindent - 2 spaces
braces {} on new line
indent case statements
bracket logic - () around complex bools
rename static functions - drop "nm_" prefix
move functions - static first
move mx_ops functions to end
fix typos
reorder includes
add some doxygen comments

mutt_notmuch.c
mutt_notmuch.h

index c16a3a163bf0d2cacb9176e452dac82a81ecfe7e..a9c9da2b2e0b6fd8cfb369cabd522a5d7d59cc16 100644 (file)
@@ -1,9 +1,29 @@
-/*
- * Notmuch support for mutt
+/** @file
+ * # NotMuch Support for Mutt
  *
- * Copyright (C) 2011, 2012 Karel Zak <kzak@redhat.com>
+ * ## Authors
+ * * Copyright (C) 2011-2016 Karel Zak <kzak@redhat.com>
+ * * Copyright (C) 2016-2017 Richard Russon <rich@flatcap.org>
+ * * Copyright (C) 2016 Kevin Velghe <kevin@paretje.be>
+ * * Copyright (C) 2017 Bernard 'Guyzmo' Pratz <guyzmo+github+pub@m0g.net>
  *
- * Notes:
+ * ## License
+ *
+ * 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.
+ *
+ * ## Notes
  *
  * - notmuch uses private CONTEXT->data and private HEADER->data
  *
  * - exception are nm_nonctx_* functions -- these functions use nm_default_uri
  *   (or parse URI from another resource)
  */
+
 #if HAVE_CONFIG_H
-# include "config.h"
+#include "config.h"
 #endif
 
-#include "mutt.h"
-#include "mx.h"
-#include "rfc2047.h"
-#include "sort.h"
-#include "mailbox.h"
-#include "copy.h"
-#include "keymap.h"
-#include "url.h"
-#include "buffy.h"
-
+#include <ctype.h>
 #include <dirent.h>
+#include <errno.h>
 #include <fcntl.h>
+#include <notmuch.h>
+#include <stdlib.h>
+#include <string.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.h"
+#include "buffy.h"
+#include "copy.h"
+#include "keymap.h"
+#include "mailbox.h"
 #include "mutt_curses.h"
+#include "mutt_notmuch.h"
+#include "mx.h"
+#include "rfc2047.h"
+#include "sort.h"
+#include "url.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)))
+/* @def 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
+/**
+ * enum anonymous - Query Types
+ *
+ * Read whole-thread or matching messages only?
+ */
+enum
+{
+  NM_QUERY_TYPE_MESGS = 1,      /**< Default: Messages only */
+  NM_QUERY_TYPE_THREADS         /**< Whole threads */
 };
 
-/*
- * Parsed URI arguments
+/**
+ * struct uri_tag - Parsed NotMuch-URI arguments
+ *
+ * The arguments in a URI are saved in a linked list.
+ *
+ * @sa nm_ctxdata#query_items
  */
-struct uri_tag {
-       char *name;
-       char *value;
-       struct uri_tag *next;
+struct uri_tag
+{
+  char *name;
+  char *value;
+  struct uri_tag *next;
 };
 
-/*
- * HEADER->(nm_hdrdata *)data->tag_list node
+/**
+ * nm_hdrtag - NotMuch Mail Header Tags
+ *
+ * Keep a linked list of header tags and their transformed values.
+ * Textual tags can be transformed to symbols to save space.
+ *
+ * @sa nm_hdrdata#tag_list
  */
 struct nm_hdrtag
 {
@@ -82,2005 +115,2067 @@ struct nm_hdrtag
   struct nm_hdrtag *next;
 };
 
-/*
- * HEADER->data
+/**
+ * struct nm_hdrdata - NotMuch data attached to an email
+ *
+ * This stores all the NotMuch data associated with an email.
+ *
+ * @sa HEADER#data, MUTT_MBOX
  */
-struct nm_hdrdata {
-       char *folder;
-       char *tags;
-       char *tags_transformed;
-       struct nm_hdrtag *tag_list;
-       char *oldpath;
-       char *virtual_id;
-       int magic;
+struct nm_hdrdata
+{
+  char *folder;                 /**< Location of the email */
+  char *tags;
+  char *tags_transformed;
+  struct nm_hdrtag *tag_list;
+  char *oldpath;
+  char *virtual_id;             /**< Unique NotMuch Id */
+  int magic;                    /**< Type of mailbox the email is in */
 };
 
-/*
- * CONTEXT->data
+/**
+ * struct nm_ctxdata - NotMuch data attached to a context
+ *
+ * This stores the global NotMuch data, such as the database connection.
+ *
+ * @sa CONTEXT#data, NotmuchDBLimit, NM_QUERY_TYPE_MESGS
  */
-struct nm_ctxdata {
-       notmuch_database_t *db;
-
-       char *db_filename;
-       char *db_query;
-       int db_limit;
-       int query_type;
+struct nm_ctxdata
+{
+  notmuch_database_t *db;
 
-       struct uri_tag *query_items;
+  char *db_filename;            /**< Filename of the NotMuch database */
+  char *db_query;               /**< Previous query */
+  int db_limit;                 /**< Maximum number of results to return */
+  int query_type;               /**< Messages or Threads */
 
-       progress_t progress;
-       int oldmsgcount;
-       int ignmsgcount;        /* ingored messages */
+  struct uri_tag *query_items;
 
-       unsigned int noprogress : 1,
-                    longrun : 1,
-                    trans : 1,
-                    progress_ready : 1;
+  progress_t progress;          /**< A progress bar */
+  int oldmsgcount;
+  int ignmsgcount;              /**< Ignored messages */
 
+  unsigned int noprogress     : 1;  /**< Don't show the progress bar */
+  unsigned int longrun        : 1;  /**< A long-lived action is in progress */
+  unsigned int trans          : 1;  /**< Atomic transacion in progress */
+  unsigned int progress_ready : 1;  /**< A progress bar has been initialised */
 };
 
-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)
+#if 0
+/**
+ * debug_print_filenames - Show a message's filenames
+ * @param msg NotMuch Message
+ *
+ * Print a list of all the filenames associated with a NotMuch message.
+ */
+static void debug_print_filenames(notmuch_message_t *msg)
 {
-       while (tags) {
-               struct uri_tag *next = tags->next;
-               FREE(&tags->name);
-               FREE(&tags->value);
-               FREE(&tags);
-               tags = next;
-       }
+  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 int url_parse_query(char *url, char **filename, struct uri_tag **tags)
+/**
+ * debug_print_tags - Show a message's tags
+ * @param msg NotMuch Message
+ *
+ * Print a list of all the tags associated with a NotMuch message.
+ */
+static void debug_print_tags(notmuch_message_t *msg)
 {
-       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 : mutt_substrdup(p, e) : safe_strdup(p);
-       if (!e)
-               return 0;       /* only filename */
-
-       if (*filename && url_pct_decode(*filename) < 0)
-               goto err;
+  notmuch_tags_t *tags;
+  const char *id = notmuch_message_get_message_id(msg);
 
-       ++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 ? mutt_substrdup(p, e) : safe_strdup(p);
-               if (!tag->name || url_pct_decode(tag->name) < 0)
-                       goto err;
-               if (!e)
-                       break;
-
-               p = e + 1;
-
-               if (*e == '&')
-                       continue;
+  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)));
+  }
+}
+#endif
 
-               e = strchr(p, '&');
-               tag->value = e ? mutt_substrdup(p, e) : safe_strdup(p);
-               if (!tag->value || url_pct_decode(tag->value) < 0)
-                       goto err;
-               if (!e)
-                       break;
-               p = e + 1;
-       }
+/**
+ * url_free_tags - Free a list of tags
+ * @param tags List of tags
+ */
+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;
+  }
+}
 
-       return 0;
+/**
+ * url_parse_query - Extract the tokens from a query URI
+ * @param[in]  url      URI to parse
+ * @param[out] filename Save the filename
+ * @param[out] tags     Save the list of tags
+ *
+ * @retval  0 Success
+ * @retval -1 Error: Bad format
+ *
+ * Parse a NotMuch URI, such as:
+ * *    notmuch:///path/to/db?query=tag:lkml&limit=1000
+ * *    notmuch://?query=neomutt
+ *
+ * Extract the database filename (optional) and any search parameters (tags).
+ * The tags will be saved in a linked list (#uri_tag).
+ */
+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 : mutt_substrdup(p, e) : safe_strdup(p);
+  if (!e)
+    return 0; /* only filename */
+
+  if (*filename && (url_pct_decode(*filename) < 0))
+    goto err;
+
+  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 ? mutt_substrdup(p, e) : 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 ? mutt_substrdup(p, e) : 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;
+  FREE(&(*filename));
+  url_free_tags(*tags);
+  return -1;
 }
 
 static void free_tag_list(struct nm_hdrtag **tag_list)
 {
-       struct nm_hdrtag *tmp;
+  struct nm_hdrtag *tmp;
 
-       while ((tmp = *tag_list) != NULL)
-       {
-               *tag_list = tmp->next;
-               FREE(&tmp->tag);
-               FREE(&tmp->transformed);
-               FREE(&tmp);
-       }
+  while ((tmp = *tag_list) != NULL)
+  {
+    *tag_list = tmp->next;
+    FREE(&tmp->tag);
+    FREE(&tmp->transformed);
+    FREE(&tmp);
+  }
 
-       *tag_list = 0;
+  *tag_list = 0;
 }
 
 static void free_hdrdata(struct nm_hdrdata *data)
 {
-       if (!data)
-               return;
+  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);
+  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;
+  if (!data)
+    return;
 
-       dprint(1, (debugfile, "nm: freeing context data %p\n", data));
+  dprint(1, (debugfile, "nm: freeing context data %p\n", data));
 
-       if (data->db)
+  if (data->db)
 #ifdef NOTMUCH_API_3
-               notmuch_database_destroy(data->db);
+    notmuch_database_destroy(data->db);
 #else
-               notmuch_database_close(data->db);
+    notmuch_database_close(data->db);
 #endif
-       data->db = NULL;
+  data->db = NULL;
 
-       FREE(&data->db_filename);
-       FREE(&data->db_query);
-       url_free_tags(data->query_items);
-       FREE(&data);
+  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;
+  struct nm_ctxdata *data;
 
-       if (!uri)
-               return NULL;
+  if (!uri)
+    return NULL;
 
-       data = safe_calloc(1, sizeof(struct nm_ctxdata));
-       dprint(1, (debugfile, "nm: initialize context data %p\n", data));
+  data = safe_calloc(1, sizeof(struct nm_ctxdata));
+  dprint(1, (debugfile, "nm: initialize context data %p\n", data));
 
-       data->db_limit = NotmuchDBLimit;
+  data->db_limit = NotmuchDBLimit;
 
-       if (url_parse_query(uri, &data->db_filename, &data->query_items)) {
-               mutt_error(_("failed to parse notmuch uri: %s"), uri);
-               FREE(&data);
-               return NULL;
-       }
+  if (url_parse_query(uri, &data->db_filename, &data->query_items))
+  {
+    mutt_error(_("failed to parse notmuch uri: %s"), uri);
+    FREE(&data);
+    return NULL;
+  }
 
-       return data;
-}
-
-static int deinit_context(CONTEXT *ctx)
-{
-       int i;
-
-       if (!ctx || ctx->magic != MUTT_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;
+  return data;
 }
 
 static int init_context(CONTEXT *ctx)
 {
-       if (!ctx || ctx->magic != MUTT_NOTMUCH)
-               return -1;
+  if (!ctx || (ctx->magic != MUTT_NOTMUCH))
+    return -1;
 
-       if (ctx->data)
-               return 0;
+  if (ctx->data)
+    return 0;
 
-       ctx->data = new_ctxdata(ctx->path);
-       if (!ctx->data)
-               return -1;
-
-       return 0;
-}
+  ctx->data = new_ctxdata(ctx->path);
+  if (!ctx->data)
+    return -1;
 
-char *nm_header_get_folder(HEADER *h)
-{
-       return h && h->data ? ((struct nm_hdrdata *) h->data)->folder : NULL;
+  return 0;
 }
 
-/* returns all unhidden tags */
-char *nm_header_get_tags(HEADER *h)
+static char *header_get_id(HEADER *h)
 {
-       return h && h->data ? ((struct nm_hdrdata *) h->data)->tags : NULL;
+  return (h && h->data) ? ((struct nm_hdrdata *) h->data)->virtual_id : NULL;
 }
 
-char *nm_header_get_tags_transformed(HEADER *h)
+static char *header_get_fullpath(HEADER *h, char *buf, size_t bufsz)
 {
-       return h && h->data ? ((struct nm_hdrdata *) h->data)->tags_transformed : NULL;
+  snprintf(buf, bufsz, "%s/%s", nm_header_get_folder(h), h->path);
+  /*dprint(2, (debugfile, "nm: returns fullpath '%s'\n", buf));*/
+  return buf;
 }
 
-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 == MUTT_NOTMUCH)
-               return ctx->data;
+  if (ctx && (ctx->magic == MUTT_NOTMUCH))
+    return ctx->data;
 
-       return NULL;
+  return NULL;
 }
 
-static int string_to_guery_type(const char *str)
+static int string_to_query_type(const char *str)
 {
-       if (!str)
-               str = NotmuchQueryType;         /* user's default */
-       if (!str)
-               return NM_QUERY_TYPE_MESGS;     /* hardcoded default */
+  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;
+  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;
+  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;
+  struct uri_tag *item;
 
-       if (!data)
-               return NULL;
-       if (data->db_query)
-               return data->db_query;
+  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;
+  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);
+    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_query_type(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);
+  }
 
-               else if (strcmp(item->name, "query") == 0)
-                       data->db_query = safe_strdup(item->value);
-       }
+  if (!data->query_type)
+    data->query_type = string_to_query_type(NULL);
 
-       if (!data->query_type)
-               data->query_type = string_to_guery_type(NULL);
+  dprint(2, (debugfile, "nm: query '%s'\n", data->db_query));
 
-       dprint(2, (debugfile, "nm: query '%s'\n", data->db_query));
-
-       return data->db_query;
+  return data->db_query;
 }
 
 static int get_limit(struct nm_ctxdata *data)
 {
-       return data ? data->db_limit : 0;
+  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);
+  return (data && data->query_type) ? data->query_type : string_to_query_type(NULL);
 }
 
 static const char *get_db_filename(struct nm_ctxdata *data)
 {
-       char *db_filename;
+  char *db_filename;
 
-       if (!data)
-               return NULL;
+  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;
+  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;
+  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)
+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;
+  notmuch_database_t *db = NULL;
+  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 {
+  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);
+    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);
+    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;
+    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 (!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;
+    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"));
+  if (data && data->db)
+  {
+    dprint(1, (debugfile, "nm: db close\n"));
 #ifdef NOTMUCH_API_3
-               notmuch_database_destroy(data->db);
+    notmuch_database_destroy(data->db);
 #else
-               notmuch_database_close(data->db);
+    notmuch_database_close(data->db);
 #endif
-               data->db = NULL;
-               data->longrun = 0;
-               return 0;
-       }
+    data->db = NULL;
+    data->longrun = 0;
+    return 0;
+  }
 
-       return -1;
+  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 || !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;
-       }
+  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;
+  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 || !data->db)
+    return -1;
 
-       if (data && get_db(data, writable)) {
-               data->longrun = 1;
-               dprint(2, (debugfile, "nm: long run initialized\n"));
-       }
-}
+  if (data->trans)
+  {
+    dprint(2, (debugfile, "nm: db trans end\n"));
+    data->trans = 0;
+    if (notmuch_database_end_atomic(data->db))
+      return -1;
+  }
 
-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"));
+  return 0;
 }
 
 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);
-       }
+  return data && data->longrun;
 }
 
 static int get_database_mtime(struct nm_ctxdata *data, time_t *mtime)
 {
-       char path[_POSIX_PATH_MAX];
-       struct stat st;
+  char path[_POSIX_PATH_MAX];
+  struct stat st;
 
-       if (!data)
-              return -1;
+  if (!data)
+    return -1;
 
-       snprintf(path, sizeof(path), "%s/.notmuch/xapian", get_db_filename(data));
-       dprint(2, (debugfile, "nm: checking '%s' mtime\n", path));
+  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 (stat(path, &st))
+    return -1;
 
-       if (mtime)
-               *mtime = st.st_mtime;
+  if (mtime)
+    *mtime = st.st_mtime;
 
-       return 0;
+  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);
+  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;
+  notmuch_database_t *db = NULL;
+  notmuch_query_t *q = NULL;
+  const char *str;
 
-       if (!data)
-               return NULL;
+  if (!data)
+    return NULL;
 
-       db = get_db(data, writable);
-       str = get_query_string(data);
+  db = get_db(data, writable);
+  str = get_query_string(data);
 
-       if (!db || !str)
-               goto err;
+  if (!db || !str)
+    goto err;
 
-       q = notmuch_query_create(db, str);
-       if (!q)
-               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;
+  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;
+  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;
+  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);
+  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;
+  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));
+  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)) {
+  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;
 
-               const char *t = notmuch_tags_get(tags);
-               const char *tt = NULL;
+    if (!t || !*t)
+      continue;
 
-               if (!t || !*t)
-                       continue;
+    tt = hash_find(TagTransforms, t);
+    if (!tt)
+      tt = t;
 
-               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;
 
-               /* 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;
 
-               /* 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;
+    }
 
-                       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 transformed tag string */
-               append_str_item(&ttstr, tt, ' ');
+    /* expand the un-transformed tag string */
+    append_str_item(&tstr, t, ' ');
+  }
 
-               /* expand the un-transformed tag string */
-               append_str_item(&tstr, t, ' ');
-       }
+  free_tag_list(&data->tag_list);
+  data->tag_list = tag_list;
 
-       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;
+  }
 
-       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);
 
-       /* free old version */
-       FREE(&data->tags);
-       FREE(&data->tags_transformed);
+  /* new version */
+  data->tags = tstr;
+  dprint(2, (debugfile, "nm: new tags: '%s'\n", tstr));
 
-       /* 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));
 
-       data->tags_transformed = ttstr;
-       dprint(2, (debugfile, "nm: new tag transforms: '%s'\n", ttstr));
-
-       return 0;
+  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;
+  struct nm_hdrdata *data = h->data;
+  char *p;
 
-       dprint(2, (debugfile, "nm: path update requested path=%s, (%s)\n",
-                               path, data->virtual_id));
+  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)) {
+  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 = MUTT_MAILDIR;
 
-               data->magic = MUTT_MAILDIR;
+    FREE(&h->path);
+    FREE(&data->folder);
 
-               FREE(&h->path);
-               FREE(&data->folder);
+    p -= 3; /* skip subfolder (e.g. "new") */
+    h->path = safe_strdup(p);
 
-               p -= 3;                         /* skip subfolder (e.g. "new") */
-               h->path = safe_strdup(p);
+    for (; (p > path) && (*(p - 1) == '/'); p--)
+      ;
 
-               for (; p > path && *(p - 1) == '/'; p--);
+    data->folder = mutt_substrdup(path, p);
 
-               data->folder = mutt_substrdup(path, p);
+    dprint(2, (debugfile, "nm: folder='%s', file='%s'\n", data->folder, h->path));
+    return 0;
+  }
 
-               dprint(2, (debugfile, "nm: folder='%s', file='%s'\n", data->folder, h->path));
-               return 0;
-       }
-
-       return 1;
+  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)) {
+  char *p = strrchr(path, '/');
 
-               p -= 3;
-               for (; p > path && *(p - 1) == '/'; p--);
+  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 mutt_substrdup(path, p);
-       }
+    return mutt_substrdup(path, p);
+  }
 
-       return NULL;
+  return NULL;
 }
 
 static void deinit_header(HEADER *h)
 {
-       if (h) {
-               free_hdrdata(h->data);
-               h->data = NULL;
-       }
+  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;
+  size_t sz;
+  char *mid;
 
-       if (!id)
-               return NULL;
-       sz = strlen(id) + 3;
-       mid = safe_malloc(sz);
+  if (!id)
+    return NULL;
+  sz = strlen(id) + 3;
+  mid = safe_malloc(sz);
 
-       snprintf(mid, sz, "<%s>", id);
-       return mid;
+  snprintf(mid, sz, "<%s>", id);
+  return mid;
 }
 
 static int init_header(HEADER *h, const char *path, notmuch_message_t *msg)
 {
-       const char *id;
+  const char *id;
 
-       if (h->data)
-               return 0;
+  if (h->data)
+    return 0;
 
-       id = notmuch_message_get_message_id(msg);
+  id = notmuch_message_get_message_id(msg);
 
-       h->data = safe_calloc(1, sizeof(struct nm_hdrdata));
-       h->free_cb = deinit_header;
+  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 );
+  /*
+   * 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));
+  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 (!h->env->message_id)
+    h->env->message_id = nm2mutt_message_id(id);
 
-       if (update_message_path(h, path))
-               return -1;
+  if (update_message_path(h, path))
+    return -1;
 
-       update_header_tags(h, msg);
+  update_header_tags(h, msg);
 
-       return 0;
+  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;
+  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)) {
+  for (ls = notmuch_message_get_filenames(msg);
+       ls && notmuch_filenames_valid(ls); notmuch_filenames_move_to_next(ls))
+  {
+    name = notmuch_filenames_get(ls);
+  }
 
-               name = notmuch_filenames_get(ls);
-       }
-
-       return name;
+  return name;
 }
 
-static void nm_progress_reset(CONTEXT *ctx)
+static void progress_reset(CONTEXT *ctx)
 {
-       struct nm_ctxdata *data;
+  struct nm_ctxdata *data;
 
-       if (ctx->quiet)
-               return;
+  if (ctx->quiet)
+    return;
 
-       data = get_ctxdata(ctx);
-       if (!data)
-               return;
+  data = get_ctxdata(ctx);
+  if (!data)
+    return;
 
-       memset(&data->progress, 0, sizeof(data->progress));
-       data->oldmsgcount = ctx->msgcount;
-       data->ignmsgcount = 0;
-       data->noprogress = 0;
-       data->progress_ready = 0;
+  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)
+static void progress_update(CONTEXT *ctx, notmuch_query_t *q)
 {
-       struct nm_ctxdata *data = get_ctxdata(ctx);
+  struct nm_ctxdata *data = get_ctxdata(ctx);
 
-       if (ctx->quiet || !data || data->noprogress)
-               return;
+  if (ctx->quiet || !data || data->noprogress)
+    return;
 
-       if (!data->progress_ready && q) {
-               unsigned count;
-               static char msg[STRING];
-               snprintf(msg, sizeof(msg), _("Reading messages..."));
+  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 */
+    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);
+    count = notmuch_query_count_messages(q);
 #endif
-               mutt_progress_init(&data->progress, msg, MUTT_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;
-
-       struct nm_ctxdata *data = get_ctxdata(ctx);
-       if (!data)
-               return;
-
-       /* deduplicate */
-       if (dedup && get_mutt_header(ctx, msg)) {
-               data->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(MUTT_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(MUTT_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_mailbox() 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);
+    mutt_progress_init(&data->progress, msg, MUTT_PROGRESS_MSG, ReadInc, count);
+    data->progress_ready = 1;
+  }
+
+  if (data->progress_ready)
+    mutt_progress_update(&data->progress,
+                         ctx->msgcount + data->ignmsgcount - data->oldmsgcount,
+                         -1);
 }
 
-/*
- * 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)
+static HEADER *get_mutt_header(CONTEXT *ctx, notmuch_message_t *msg)
 {
-       notmuch_messages_t *msgs;
+  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;
+}
+
+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;
+
+  struct nm_ctxdata *data = get_ctxdata(ctx);
+  if (!data)
+    return;
+
+  /* deduplicate */
+  if (dedup && get_mutt_header(ctx, msg))
+  {
+    data->ignmsgcount++;
+    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(MUTT_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(MUTT_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_mailbox() 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);
+    }
+  }
+  progress_update(ctx, q);
+done:
+  FREE(&newpath);
+}
 
-       for (msgs = notmuch_message_get_replies(top);
-            notmuch_messages_valid(msgs);
-            notmuch_messages_move_to_next(msgs)) {
+static void append_replies(CONTEXT *ctx, notmuch_query_t *q,
+                           notmuch_message_t *top, int dedup)
+{
+  notmuch_messages_t *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);
-       }
+  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)
+static void append_thread(CONTEXT *ctx, notmuch_query_t *q,
+                          notmuch_thread_t *thread, int dedup)
 {
-       notmuch_messages_t *msgs;
+  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);
-       }
+  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;
+  struct nm_ctxdata *data = get_ctxdata(ctx);
+  int limit;
+  notmuch_messages_t *msgs;
 
-       if (!data)
-               return;
+  if (!data)
+    return;
 
-       limit = get_limit(data);
+  limit = get_limit(data);
 
 #if LIBNOTMUCH_CHECK_VERSION(4,3,0)
-       if (notmuch_query_search_messages_st (q, &msgs) != NOTMUCH_STATUS_SUCCESS)
-               return;
+  if (notmuch_query_search_messages_st(q, &msgs) != NOTMUCH_STATUS_SUCCESS)
+    return;
 #else
-       msgs = notmuch_query_search_messages(q);
+  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);
-       }
+  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)
+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;
+  struct nm_ctxdata *data = get_ctxdata(ctx);
+  notmuch_threads_t *threads;
 
-       if (!data)
-               return;
+  if (!data)
+    return;
 
 #if LIBNOTMUCH_CHECK_VERSION(4,3,0)
-       if (notmuch_query_search_threads_st (q, &threads) != NOTMUCH_STATUS_SUCCESS)
-               return;
+  if (notmuch_query_search_threads_st(q, &threads) != NOTMUCH_STATUS_SUCCESS)
+    return;
 #else
-       threads = notmuch_query_search_threads(q);
+  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);
-       }
+  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)
+static notmuch_message_t *get_nm_message(notmuch_database_t *db, HEADER *hdr)
 {
-       notmuch_query_t *q;
-       struct nm_ctxdata *data;
-       int rc = -1;
+  notmuch_message_t *msg = NULL;
+  char *id = header_get_id(hdr);
 
-       if (init_context(ctx) != 0)
-               return -1;
+  dprint(2, (debugfile, "nm: find message (%s)\n", id));
 
-       data = get_ctxdata(ctx);
-       if (!data)
-               return -1;
+  if (id && db)
+    notmuch_database_find_message(db, id, &msg);
 
-       dprint(1, (debugfile, "nm: reading messages...[current count=%d]\n",
-                               ctx->msgcount));
+  return msg;
+}
 
-       nm_progress_reset(ctx);
+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;
+}
 
-       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;
+static int update_header_flags(CONTEXT *ctx, HEADER *hdr, const char *tags)
+{
+  char *tag = NULL, *end = NULL, *p;
+  char *buf = safe_strdup(tags);
+
+  if (!buf)
+    return -1;
+
+  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 == '-')
+    {
+      tag = tag + 1;
+      if (strcmp(tag, "unread") == 0)
+        mutt_set_flag(ctx, hdr, MUTT_READ, 1);
+      else if (strcmp(tag, "replied") == 0)
+        mutt_set_flag(ctx, hdr, MUTT_REPLIED, 0);
+      else if (strcmp(tag, "flagged") == 0)
+        mutt_set_flag(ctx, hdr, MUTT_FLAG, 0);
+    }
+    else
+    {
+      tag = (*tag == '+') ? tag + 1 : tag;
+      if (strcmp(tag, "unread") == 0)
+        mutt_set_flag(ctx, hdr, MUTT_READ, 0);
+      else if (strcmp(tag, "replied") == 0)
+        mutt_set_flag(ctx, hdr, MUTT_REPLIED, 1);
+      else if (strcmp(tag, "flagged") == 0)
+        mutt_set_flag(ctx, hdr, MUTT_FLAG, 1);
+    }
+    end = tag = NULL;
+  }
+
+  FREE(&buf);
+  return 0;
+}
+
+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++;
+  } else {
+    p = folder;
+  }
+
+  strfcpy(filename, p, sizeof(filename));
+
+  /* remove (new,cur,...) from folder path */
+  p = strrchr(folder, '/');
+  if (p)
+    *p = '\0';
+
+  /* remove old flags from filename */
+  p = strchr(filename, ':');
+  if (p)
+    *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;
+}
 
-       if (!is_longrun(data))
-               release_db(data);
+static unsigned count_query(notmuch_database_t *db, const char *qstr)
+{
+  unsigned res = 0;
+  notmuch_query_t *q = notmuch_query_create(db, qstr);
 
-       ctx->mtime = time(NULL);
+  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;
+}
 
-       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;
+char *nm_header_get_folder(HEADER *h)
+{
+  return (h && h->data) ? ((struct nm_hdrdata *) h->data)->folder : NULL;
 }
 
-int nm_read_entire_thread(CONTEXT *ctx, HEADER *h)
+char *nm_header_get_tags(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."));
+  return (h && h->data) ? ((struct nm_hdrdata *) h->data)->tags : NULL;
+}
 
-       data->oldmsgcount = 0;
-       dprint(1, (debugfile, "nm: reading entire-thread messages... done [rc=%d, count=%d]\n",
-                               rc, ctx->msgcount));
-       return rc;
+char *nm_header_get_tags_transformed(HEADER *h)
+{
+  return (h && h->data) ? ((struct nm_hdrdata *) h->data)->tags_transformed : NULL;
 }
 
-char *nm_uri_from_query(CONTEXT *ctx, char *buf, size_t bufsz)
+char *nm_header_get_tag_transformed(char *tag, HEADER *h)
 {
-       struct nm_ctxdata *data = get_ctxdata(ctx);
-       char uri[_POSIX_PATH_MAX + LONG_STRING + 32];   /* path to DB + query + URI "decoration" */
+  struct nm_hdrtag *tmp;
 
-       if (data)
-               snprintf(uri, sizeof(uri), "notmuch://%s?query=%s",
-                        get_db_filename(data), buf);
-       else if (NotmuchDefaultUri)
-               snprintf(uri, sizeof(uri), "%s?query=%s", NotmuchDefaultUri, buf);
-       else if (Maildir)
-               snprintf(uri, sizeof(uri), "notmuch://%s?query=%s", Maildir, buf);
-       else
-               return NULL;
+  if (!h || !h->data)
+    return NULL;
 
-       strncpy(buf, uri, bufsz);
-       buf[bufsz - 1] = '\0';
+  for (tmp = ((struct nm_hdrdata *) h->data)->tag_list;
+       tmp != NULL;
+       tmp = tmp->next)
+  {
+    if (strcmp(tag, tmp->tag) == 0)
+      return tmp->transformed;
+  }
 
-       dprint(1, (debugfile, "nm: uri from query '%s'\n", buf));
-       return buf;
+  return NULL;
 }
 
-/*
- * returns message from notmuch database
- */
-static notmuch_message_t *get_nm_message(notmuch_database_t *db, HEADER *hdr)
+void nm_longrun_init(CONTEXT *ctx, int writable)
 {
-       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);
+  struct nm_ctxdata *data = get_ctxdata(ctx);
 
-       return msg;
+  if (data && get_db(data, writable))
+  {
+    data->longrun = 1;
+    dprint(2, (debugfile, "nm: long run initialized\n"));
+  }
 }
 
-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;
-}
-
-/* TODO: extract parsing of string to separate function, join
- * update_header_tags and update_header_flags, which are given an array of
- * tags. */
-static int update_header_flags(CONTEXT *ctx, HEADER *hdr, const char *tags)
+void nm_longrun_done(CONTEXT *ctx)
 {
-       char *tag = NULL, *end = NULL, *p;
-       char *buf = safe_strdup(tags);
-
-       if (!buf)
-               return -1;
-
-       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 == '-') {
-                       tag = tag + 1;
-                       if (strcmp(tag, "unread") == 0)
-                               mutt_set_flag (ctx, hdr, MUTT_READ, 1);
-                       else if (strcmp(tag, "replied") == 0)
-                               mutt_set_flag (ctx, hdr, MUTT_REPLIED, 0);
-                       else if (strcmp(tag, "flagged") == 0)
-                               mutt_set_flag (ctx, hdr, MUTT_FLAG, 0);
-               } else {
-                       tag = *tag == '+' ? tag + 1 : tag;
-                       if (strcmp(tag, "unread") == 0)
-                               mutt_set_flag (ctx, hdr, MUTT_READ, 0);
-                       else if (strcmp(tag, "replied") == 0)
-                               mutt_set_flag (ctx, hdr, MUTT_REPLIED, 1);
-                       else if (strcmp(tag, "flagged") == 0)
-                               mutt_set_flag (ctx, hdr, MUTT_FLAG, 1);
-               }
-               end = tag = NULL;
-       }
-
-       FREE(&buf);
-       return 0;
+  struct nm_ctxdata *data = get_ctxdata(ctx);
+
+  if (data && (release_db(data) == 0))
+    dprint(2, (debugfile, "nm: long run deinitialized\n"));
 }
 
-int nm_modify_message_tags(CONTEXT *ctx, HEADER *hdr, char *buf)
+void nm_debug_check(CONTEXT *ctx)
 {
-       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;
+  struct nm_ctxdata *data = get_ctxdata(ctx);
+  if (!data)
+    return;
 
-       if (!(db = get_db(data, TRUE)) || !(msg = get_nm_message(db, hdr)))
-               goto done;
+  if (data->db)
+  {
+    dprint(1, (debugfile, "nm: ERROR: db is open, closing\n"));
+    release_db(data);
+  }
+}
 
-       dprint(1, (debugfile, "nm: tags modify: '%s'\n", buf));
+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));
+
+  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);
 
-       update_tags(msg, buf);
-       update_header_flags(ctx, hdr, buf);
-       update_header_tags(hdr, msg);
-       mutt_set_header_color(ctx, hdr);
+  if (ctx->msgcount == data->oldmsgcount)
+    mutt_message(_("No more messages in the thread."));
 
-       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;
+  data->oldmsgcount = 0;
+  dprint(1, (debugfile,
+             "nm: reading entire-thread messages... done [rc=%d, count=%d]\n",
+             rc, ctx->msgcount));
+  return rc;
 }
 
-static int rename_maildir_filename(const char *old, char *newpath, size_t newsz, HEADER *h)
+char *nm_uri_from_query(CONTEXT *ctx, char *buf, size_t bufsz)
 {
-       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++;
-       } else {
-               p = folder;
-       }
+  struct nm_ctxdata *data = get_ctxdata(ctx);
+  char uri[_POSIX_PATH_MAX + LONG_STRING + 32]; /* path to DB + query + URI "decoration" */
 
-       strfcpy(filename, p, sizeof(filename));
+  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;
 
-       /* remove (new,cur,...) from folder path */
-       p = strrchr(folder, '/');
-       if (p)
-               *p = '\0';
+  strncpy(buf, uri, bufsz);
+  buf[bufsz - 1] = '\0';
 
-       /* remove old flags from filename */
-       if ((p = strchr(filename, ':')))
-               *p = '\0';
+  dprint(1, (debugfile, "nm: uri from query '%s'\n", buf));
+  return buf;
+}
 
-       /* compose new flags */
-       maildir_flags(suffix, sizeof(suffix), h);
+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;
 
-       snprintf(newpath, newsz, "%s/%s/%s%s",
-                       folder,
-                       (h->read || h->old) ? "cur" : "new",
-                       filename,
-                       suffix);
+  if (!buf || !*buf || !data)
+    return -1;
 
-       if (strcmp(old, newpath) == 0)
-               return 1;
+  if (!(db = get_db(data, TRUE)) || !(msg = get_nm_message(db, hdr)))
+    goto done;
 
-       if (rename(old, newpath) != 0) {
-               dprint(1, (debugfile, "nm: rename(2) failed %s -> %s\n", old, newpath));
-               return -1;
-       }
+  dprint(1, (debugfile, "nm: tags modify: '%s'\n", buf));
 
-       return 0;
-}
+  update_tags(msg, buf);
+  update_header_flags(ctx, hdr, buf);
+  update_header_tags(hdr, msg);
+  mutt_set_header_color(ctx, hdr);
 
-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;
+  rc = 0;
+  hdr->changed = TRUE;
 done:
-       if (msg)
-               notmuch_message_destroy(msg);
-       if (trans)
-               db_trans_end(data);
-       return rc;
+  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;
 }
 
-int nm_update_filename(CONTEXT *ctx, const char *old, const char *new, HEADER *h)
+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);
+  char buf[PATH_MAX];
+  int rc;
+  struct nm_ctxdata *data = get_ctxdata(ctx);
 
-       if (!data || !new)
-               return -1;
+  if (!data || !new)
+    return -1;
 
-       if (!old && h && h->data) {
-               nm_header_get_fullpath(h, buf, sizeof(buf));
-               old = buf;
-       }
+  if (!old && h && h->data)
+  {
+    header_get_fullpath(h, buf, sizeof(buf));
+    old = buf;
+  }
 
-       rc = rename_filename(data, old, new, h);
+  rc = rename_filename(data, old, new, h);
 
-       if (!is_longrun(data))
-               release_db(data);
-       ctx->mtime = time(NULL);
-       return rc;
+  if (!is_longrun(data))
+    release_db(data);
+  ctx->mtime = time(NULL);
+  return rc;
 }
 
-int nm_sync_mailbox(CONTEXT *ctx, int *index_hint)
+int nm_nonctx_get_count(char *path, int *all, int *new)
 {
-       struct nm_ctxdata *data = get_ctxdata(ctx);
-       int i, rc = 0;
-       char msgbuf[STRING];
-       progress_t progress;
-       char *uri = ctx->path;
-       int changed = 0;
+  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);
 
-       if (!data)
-               return -1;
+  dprint(1, (debugfile, "nm: count done [rc=%d]\n", rc));
+  return rc;
+}
 
-       dprint(1, (debugfile, "nm: sync start ...\n"));
+char *nm_get_description(CONTEXT *ctx)
+{
+  BUFFY *p;
 
-       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, MUTT_PROGRESS_MSG,
-                                  WriteInc, ctx->msgcount);
-       }
+  for (p = VirtIncoming; p; p = p->next)
+    if (p->desc && (strcmp(p->path, ctx->path) == 0))
+      return p->desc;
 
-       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;
+  return NULL;
+}
 
-               if (!ctx->quiet)
-                       mutt_progress_update(&progress, i, -1);
+int nm_description_to_path(const char *desc, char *buf, size_t bufsz)
+{
+  BUFFY *p;
 
-               *old = *new = '\0';
+  if (!desc || !buf || !bufsz)
+    return -EINVAL;
 
-               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));
+  for (p = VirtIncoming; p; p = p->next)
+    if (p->desc && (strcmp(desc, p->desc) == 0))
+    {
+      strncpy(buf, p->path, bufsz);
+      buf[bufsz - 1] = '\0';
+      return 0;
+    }
 
-               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 = MUTT_NOTMUCH;
+  return -1;
+}
 
-               if (rc)
-                       break;
+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;
+}
 
-               if (!h->deleted)
-                       nm_header_get_fullpath(h, new, sizeof(new));
+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 (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;
-               }
+  if (!data)
+    return -1;
 
-               FREE(&hd->oldpath);
-       }
+  if (!(db = get_db(data, FALSE)) ||
+      !(tags = notmuch_database_get_all_tags(db)))
+    goto done;
 
-       ctx->path = uri;
-       ctx->magic = MUTT_NOTMUCH;
+  *tag_count = 0;
+  dprint(1, (debugfile, "nm: get all tags\n"));
 
-       if (!is_longrun(data))
-               release_db(data);
-       if (changed)
-               ctx->mtime = time(NULL);
+  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);
+  }
 
-       dprint(1, (debugfile, "nm: .... sync done [rc=%d]\n", rc));
-       return rc;
-}
+  rc = 0;
+done:
+  if (tags)
+    notmuch_tags_destroy(tags);
 
-static unsigned count_query(notmuch_database_t *db, const char *qstr)
-{
-       unsigned res = 0;
-       notmuch_query_t *q = notmuch_query_create(db, qstr);
+  if (!is_longrun(data))
+    release_db(data);
 
-       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;
+  dprint(1, (debugfile, "nm: get all tags done [rc=%d tag_count=%u]\n", rc,
+             *tag_count));
+  return rc;
 }
 
-int nm_nonctx_get_count(char *path, int *all, int *new)
+
+static int nm_open_mailbox(CONTEXT *ctx)
 {
-       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);
+  notmuch_query_t *q;
+  struct nm_ctxdata *data;
+  int rc = -1;
 
-       dprint(1, (debugfile, "nm: count done [rc=%d]\n", rc));
-       return rc;
-}
+  if (init_context(ctx) != 0)
+    return -1;
 
-char *nm_get_description(CONTEXT *ctx)
-{
-       BUFFY *p;
+  data = get_ctxdata(ctx);
+  if (!data)
+    return -1;
 
-       for (p = VirtIncoming; p; p = p->next)
-               if (p->desc && strcmp(p->path, ctx->path) == 0)
-                       return p->desc;
+  dprint(1, (debugfile, "nm: reading messages...[current count=%d]\n",
+             ctx->msgcount));
 
-       return NULL;
-}
+  progress_reset(ctx);
 
-int nm_description_to_path(const char *desc, char *buf, size_t bufsz)
-{
-       BUFFY *p;
+  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 (!desc || !buf || !bufsz)
-               return -EINVAL;
+  if (!is_longrun(data))
+    release_db(data);
 
-       for (p = VirtIncoming; p; p = p->next)
-               if (p->desc && strcmp(desc, p->desc) == 0) {
-                       strncpy(buf, p->path, bufsz);
-                       buf[bufsz - 1] = '\0';
-                       return 0;
-               }
+  ctx->mtime = time(NULL);
 
-       return -1;
+  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;
 }
 
-/*
- * returns header from mutt context
- */
-static HEADER *get_mutt_header(CONTEXT *ctx, notmuch_message_t *msg)
+static int nm_close_mailbox(CONTEXT *ctx)
 {
-       char *mid;
-       const char *id;
-       HEADER *h;
-
-       if (!ctx || !msg)
-               return NULL;
-
-       id = notmuch_message_get_message_id(msg);
-       if (!id)
-               return NULL;
+  int i;
 
-       dprint(2, (debugfile, "nm: mutt header, id='%s'\n", id));
+  if (!ctx || (ctx->magic != MUTT_NOTMUCH))
+    return -1;
 
-       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;
-       }
+  for (i = 0; i < ctx->msgcount; i++)
+  {
+    HEADER *h = ctx->hdrs[i];
 
-       mid = nm2mutt_message_id( id );
-       dprint(2, (debugfile, "nm: mutt id='%s'\n", mid));
+    if (h)
+    {
+      free_hdrdata(h->data);
+      h->data = NULL;
+    }
+  }
 
-       h = hash_find(ctx->id_hash, mid);
-       FREE(&mid);
-       return h;
+  free_ctxdata(ctx->data);
+  ctx->data = NULL;
+  return 0;
 }
 
-static int nm_check_database(CONTEXT *ctx, int *index_hint)
+static int nm_check_mailbox(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;
+  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 (!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;
-       }
+  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));
+  dprint(1, (debugfile, "nm: checking (db=%d ctx=%d)\n", mtime, ctx->mtime));
 
-       q = get_query(data, FALSE);
-       if (!q)
-               goto done;
+  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;
+  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;
+  for (i = 0; i < ctx->msgcount; i++)
+    ctx->hdrs[i]->active = 0;
 
-       limit = get_limit(data);
+  limit = get_limit(data);
 
 #if LIBNOTMUCH_CHECK_VERSION(4,3,0)
-       if (notmuch_query_search_messages_st (q, &msgs) != NOTMUCH_STATUS_SUCCESS)
-               goto done;
+  if (notmuch_query_search_messages_st(q, &msgs) != NOTMUCH_STATUS_SUCCESS)
+    goto done;
 #else
-       msgs = notmuch_query_search_messages(q);
+  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);
+  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);
+    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 (q)
+    notmuch_query_destroy(q);
 
-       if (!is_longrun(data))
-               release_db(data);
+  if (!is_longrun(data))
+    release_db(data);
 
-       ctx->mtime = time(NULL);
+  ctx->mtime = time(NULL);
 
-       dprint(1, (debugfile, "nm: ... check done [count=%d, new_flags=%d, occult=%d]\n",
-                               ctx->msgcount, new_flags, occult));
+  dprint(1, (debugfile, "nm: ... check done [count=%d, new_flags=%d, occult=%d]\n",
+          ctx->msgcount, new_flags, occult));
 
-       return occult ? MUTT_REOPENED :
-              ctx->msgcount > data->oldmsgcount ? MUTT_NEW_MAIL :
-              new_flags ? MUTT_FLAGS : 0;
+  return occult ? MUTT_REOPENED : (ctx->msgcount > data->oldmsgcount) ?
+                  MUTT_NEW_MAIL :
+                  new_flags ? MUTT_FLAGS : 0;
 }
 
-int nm_record_message(CONTEXT *ctx, char *path, HEADER *h)
+static int nm_sync_mailbox(CONTEXT *ctx, int *index_hint)
 {
-       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;
-}
+  struct nm_ctxdata *data = get_ctxdata(ctx);
+  int i, rc = 0;
+  char msgbuf[STRING];
+  progress_t progress;
+  char *uri = ctx->path;
+  int changed = 0;
 
-/*
- * 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 (!data)
-               return -1;
+  dprint(1, (debugfile, "nm: sync start ...\n"));
 
-       if (!(db = get_db(data, FALSE)) ||
-                       !(tags = notmuch_database_get_all_tags(db)))
-               goto done;
+  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, MUTT_PROGRESS_MSG, WriteInc,
+                       ctx->msgcount);
+  }
 
-       *tag_count = 0;
-       dprint(1, (debugfile, "nm: get all tags\n"));
+  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;
 
-       while (notmuch_tags_valid(tags)) {
-               if (tag_list != NULL) {
-                       tag_list[*tag_count] = safe_strdup(notmuch_tags_get(tags));
-               }
-               (*tag_count)++;
-               notmuch_tags_move_to_next(tags);
-       }
+    if (!ctx->quiet)
+      mutt_progress_update(&progress, i, -1);
 
-       rc = 0;
-done:
-       if (tags)
-               notmuch_tags_destroy(tags);
+    *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
+      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 = MUTT_NOTMUCH;
 
-       if (!is_longrun(data))
-               release_db(data);
+    if (rc)
+      break;
 
-       dprint(1, (debugfile, "nm: get all tags done [rc=%d tag_count=%u]\n", rc,
-                                                *tag_count));
-       return rc;
+    if (!h->deleted)
+      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 = MUTT_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 int nm_open_message (CONTEXT *ctx, MESSAGE *msg, int msgno)
+static int nm_open_message(CONTEXT *ctx, MESSAGE *msg, int msgno)
 {
-       if (!ctx || !msg)
-               return 1;
-       HEADER *cur = ctx->hdrs[msgno];
-       char *folder = ctx->path;
-       char path[_POSIX_PATH_MAX];
-       folder = nm_header_get_folder(cur);
+  if (!ctx || !msg)
+    return 1;
+  HEADER *cur = ctx->hdrs[msgno];
+  char *folder = ctx->path;
+  char path[_POSIX_PATH_MAX];
+  folder = nm_header_get_folder(cur);
 
-       snprintf (path, sizeof (path), "%s/%s", folder, cur->path);
+  snprintf(path, sizeof(path), "%s/%s", folder, cur->path);
 
-       msg->fp = fopen (path, "r");
-       if ((msg->fp == NULL) && (errno == ENOENT) && ((ctx->magic == MUTT_MAILDIR) || (ctx->magic == MUTT_NOTMUCH)))
-               msg->fp = maildir_open_find_message (folder, cur->path, NULL);
+  msg->fp = fopen(path, "r");
+  if ((msg->fp == NULL) && (errno == ENOENT) &&
+      ((ctx->magic == MUTT_MAILDIR) || (ctx->magic == MUTT_NOTMUCH)))
+    msg->fp = maildir_open_find_message(folder, cur->path, NULL);
 
-       dprint(1, (debugfile, "%s\n", __func__));
-       return 0;
+  dprint(1, (debugfile, "%s\n", __func__));
+  return 0;
 }
 
-static int nm_close_message (CONTEXT *ctx, MESSAGE *msg)
+static int nm_close_message(CONTEXT *ctx, MESSAGE *msg)
 {
-       if (!msg)
-               return 1;
-       safe_fclose (&(msg->fp));
-       return 0;
+  if (!msg)
+    return 1;
+  safe_fclose(&(msg->fp));
+  return 0;
 }
 
-static int nm_commit_message (CONTEXT *ctx, MESSAGE *msg)
+static int nm_commit_message(CONTEXT *ctx, MESSAGE *msg)
 {
-       mutt_perror _("Can't write to virtual folder.");
-       return 1;
+  mutt_error(_("Can't write to virtual folder."));
+  return -1;
 }
 
-struct mx_ops mx_notmuch_ops = {
-       .open         = nm_read_query,  /* calls init_context() */
-        .open_append  = NULL,
-       .close        = deinit_context,
-       .check        = nm_check_database,
-       .sync         = nm_sync_mailbox,
-       .open_msg     = nm_open_message,
-       .close_msg    = nm_close_message,
-       .commit_msg   = nm_commit_message,
-        .open_new_msg = NULL
+
+/**
+ * struct mx_notmuch_ops - Mailbox API
+ *
+ * These functions are common to all mailbox types.
+ */
+struct mx_ops mx_notmuch_ops =
+{
+  .open         = nm_open_mailbox,        /* calls init_context() */
+  .open_append  = NULL,
+  .close        = nm_close_mailbox,
+  .check        = nm_check_mailbox,
+  .sync         = nm_sync_mailbox,
+  .open_msg     = nm_open_message,
+  .close_msg    = nm_close_message,
+  .commit_msg   = nm_commit_message,
+  .open_new_msg = NULL
 };
 
index 8267b1fd114726d273ec93c2e849b5f7054e4af3..91814d49a4c88c50d07046e69eb0d6e0b06a349b 100644 (file)
@@ -1,35 +1,46 @@
 /*
  * Copyright (C) 2011 Karel Zak <kzak@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
+ *     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 _MUTT_NOTMUCH_H_
-#define _MUTT_NOTMUCH_H_ 1
 
-int nm_read_query(CONTEXT *ctx);
-int nm_read_entire_thread(CONTEXT *ctx, HEADER *h);
+#ifndef _MUTT_NOTMUCH_H
+#define _MUTT_NOTMUCH_H
+
+int   nm_read_entire_thread(CONTEXT *ctx, HEADER *h);
 
-int nm_sync(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);
+int   nm_update_filename(CONTEXT *ctx, const char *old, const char *new, 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);
+int   nm_modify_message_tags(CONTEXT *ctx, HEADER *hdr, char *buf);
 
-void nm_longrun_init(CONTEXT *cxt, int writable);
-void nm_longrun_done(CONTEXT *cxt);
+void  nm_longrun_init(CONTEXT *ctx, int writable);
+void  nm_longrun_done(CONTEXT *ctx);
 
 char *nm_get_description(CONTEXT *ctx);
-int nm_description_to_path(const char *desc, char *buf, size_t bufsz);
+int   nm_description_to_path(const char *desc, char *buf, size_t bufsz);
 
-int nm_record_message(CONTEXT *ctx, char *path, HEADER *h);
+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);
+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);
+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);
@@ -37,4 +48,4 @@ char *nm_header_get_tags(HEADER *h);
 
 extern struct mx_ops mx_notmuch_ops;
 
-#endif /* _MUTT_NOTMUCH_H_ */
+#endif /* _MUTT_NOTMUCH_H */