[PATCH v4 15/16] added notmuch_message_reindex
authorDaniel Kahn Gillmor <dkg@fifthhorseman.net>
Fri, 8 Jul 2016 09:27:26 +0000 (11:27 +0200)
committerW. Trevor King <wking@tremily.us>
Sat, 20 Aug 2016 23:22:12 +0000 (16:22 -0700)
c3/8e58d9424f9c5d39b514b49a6ab9327dc9f334 [new file with mode: 0644]

diff --git a/c3/8e58d9424f9c5d39b514b49a6ab9327dc9f334 b/c3/8e58d9424f9c5d39b514b49a6ab9327dc9f334
new file mode 100644 (file)
index 0000000..4865b89
--- /dev/null
@@ -0,0 +1,218 @@
+Return-Path: <dkg@fifthhorseman.net>\r
+X-Original-To: notmuch@notmuchmail.org\r
+Delivered-To: notmuch@notmuchmail.org\r
+Received: from localhost (localhost [127.0.0.1])\r
+ by arlo.cworth.org (Postfix) with ESMTP id BF9286DE091F\r
+ for <notmuch@notmuchmail.org>; Fri,  8 Jul 2016 03:13:16 -0700 (PDT)\r
+X-Virus-Scanned: Debian amavisd-new at cworth.org\r
+X-Spam-Flag: NO\r
+X-Spam-Score: 0\r
+X-Spam-Level: \r
+X-Spam-Status: No, score=0 tagged_above=-999 required=5 tests=[none]\r
+ autolearn=disabled\r
+Received: from arlo.cworth.org ([127.0.0.1])\r
+ by localhost (arlo.cworth.org [127.0.0.1]) (amavisd-new, port 10024)\r
+ with ESMTP id RsaQ-QlS0tUS for <notmuch@notmuchmail.org>;\r
+ Fri,  8 Jul 2016 03:13:08 -0700 (PDT)\r
+Received: from che.mayfirst.org (che.mayfirst.org [162.247.75.118])\r
+ by arlo.cworth.org (Postfix) with ESMTP id 121A16DE01BA\r
+ for <notmuch@notmuchmail.org>; Fri,  8 Jul 2016 03:13:07 -0700 (PDT)\r
+Received: from fifthhorseman.net (unknown [88.128.80.54])\r
+ by che.mayfirst.org (Postfix) with ESMTPSA id 8414CF99A\r
+ for <notmuch@notmuchmail.org>; Fri,  8 Jul 2016 06:13:06 -0400 (EDT)\r
+Received: by fifthhorseman.net (Postfix, from userid 1000)\r
+ id C9C402174C; Fri,  8 Jul 2016 11:27:34 +0200 (CEST)\r
+From: Daniel Kahn Gillmor <dkg@fifthhorseman.net>\r
+To: Notmuch Mail <notmuch@notmuchmail.org>\r
+Subject: [PATCH v4 15/16] added notmuch_message_reindex\r
+Date: Fri,  8 Jul 2016 11:27:26 +0200\r
+Message-Id: <1467970047-8013-16-git-send-email-dkg@fifthhorseman.net>\r
+X-Mailer: git-send-email 2.8.1\r
+In-Reply-To: <1467970047-8013-1-git-send-email-dkg@fifthhorseman.net>\r
+References: <1467970047-8013-1-git-send-email-dkg@fifthhorseman.net>\r
+X-BeenThere: notmuch@notmuchmail.org\r
+X-Mailman-Version: 2.1.20\r
+Precedence: list\r
+List-Id: "Use and development of the notmuch mail system."\r
+ <notmuch.notmuchmail.org>\r
+List-Unsubscribe: <https://notmuchmail.org/mailman/options/notmuch>,\r
+ <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
+List-Archive: <http://notmuchmail.org/pipermail/notmuch/>\r
+List-Post: <mailto:notmuch@notmuchmail.org>\r
+List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
+List-Subscribe: <https://notmuchmail.org/mailman/listinfo/notmuch>,\r
+ <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
+X-List-Received-Date: Fri, 08 Jul 2016 10:13:16 -0000\r
+\r
+This new function asks the database to reindex a given message, using\r
+the supplied indexopts.\r
+\r
+This can be used, for example, to index the cleartext of an encrypted\r
+message.\r
+\r
+My initial inclination for this implementation was to remove all the\r
+indexed terms for a given message's body, and then to add them back\r
+in.\r
+\r
+Unfortunately, that doesn't appear to be possible due to the way we're\r
+using xapian.  I could find no way to distinguish terms which were\r
+added during indexing of the message body from other terms associated\r
+with the document.  As a result, we just save the tags and properties,\r
+remove the message from the database entirely, and add it back into\r
+the database in full, re-adding tags and properties as needed.\r
+---\r
+ lib/message.cc | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-\r
+ lib/notmuch.h  |  14 ++++++++\r
+ 2 files changed, 121 insertions(+), 1 deletion(-)\r
+\r
+diff --git a/lib/message.cc b/lib/message.cc\r
+index 9d3e807..ab807b7 100644\r
+--- a/lib/message.cc\r
++++ b/lib/message.cc\r
+@@ -557,7 +557,9 @@ void\r
+ _notmuch_message_remove_terms (notmuch_message_t *message, const char *prefix)\r
+ {\r
+     Xapian::TermIterator i;\r
+-    size_t prefix_len = strlen (prefix);\r
++    size_t prefix_len = 0;\r
++\r
++    prefix_len = strlen (prefix);\r
\r
+     while (1) {\r
+       i = message->doc.termlist_begin ();\r
+@@ -1847,3 +1849,107 @@ _notmuch_message_frozen (notmuch_message_t *message)\r
+ {\r
+     return message->frozen;\r
+ }\r
++\r
++notmuch_status_t\r
++notmuch_message_reindex (notmuch_message_t *message,\r
++                       notmuch_indexopts_t *indexopts)\r
++{\r
++    notmuch_database_t *notmuch = NULL;\r
++    notmuch_status_t ret = NOTMUCH_STATUS_SUCCESS, status;\r
++    notmuch_tags_t *tags = NULL;\r
++    notmuch_message_properties_t *properties = NULL;\r
++    notmuch_filenames_t *filenames, *orig_filenames = NULL;\r
++    const char *filename = NULL, *tag = NULL, *propkey = NULL;\r
++    notmuch_message_t *newmsg = NULL;\r
++    notmuch_bool_t readded = FALSE, skip;\r
++    const char *autotags[] = {\r
++                  "attachment",\r
++                  "encrypted",\r
++                  "signed" };\r
++    const char *autoproperties[] = { "index-decryption" };\r
++\r
++    if (message == NULL)\r
++      return NOTMUCH_STATUS_NULL_POINTER;\r
++    \r
++    notmuch = _notmuch_message_database (message);\r
++\r
++    /* cache tags, properties, and filenames */\r
++    tags = notmuch_message_get_tags (message);\r
++    properties = notmuch_message_get_properties (message, "", FALSE);\r
++    filenames = notmuch_message_get_filenames (message);\r
++    orig_filenames = notmuch_message_get_filenames (message);\r
++    \r
++    /* walk through filenames, removing them until the message is gone */\r
++    for ( ; notmuch_filenames_valid (filenames);\r
++        notmuch_filenames_move_to_next (filenames)) {\r
++      filename = notmuch_filenames_get (filenames);\r
++\r
++      ret = notmuch_database_remove_message (notmuch, filename);\r
++      if (ret != NOTMUCH_STATUS_SUCCESS &&\r
++          ret != NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID)\r
++          return ret;\r
++    }\r
++    if (ret != NOTMUCH_STATUS_SUCCESS)\r
++      return ret;\r
++    \r
++    /* re-add the filenames with the associated indexopts */\r
++    for (; notmuch_filenames_valid (orig_filenames);\r
++       notmuch_filenames_move_to_next (orig_filenames)) {\r
++      filename = notmuch_filenames_get (orig_filenames);\r
++\r
++      status = notmuch_database_add_message_with_indexopts(notmuch,\r
++                                                           filename,\r
++                                                           indexopts,\r
++                                                           readded ? NULL : &newmsg);\r
++      if (status == NOTMUCH_STATUS_SUCCESS ||\r
++          status == NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID) {\r
++          if (!readded) {\r
++              /* re-add tags */\r
++              for (; notmuch_tags_valid (tags);\r
++                   notmuch_tags_move_to_next (tags)) {\r
++                  tag = notmuch_tags_get (tags);\r
++                  skip = FALSE;\r
++                  \r
++                  for (size_t i = 0; i < ARRAY_SIZE (autotags); i++)\r
++                      if (strcmp (tag, autotags[i]) == 0)\r
++                          skip = TRUE;\r
++                  \r
++                  if (!skip) {\r
++                      status = notmuch_message_add_tag (newmsg, tag);\r
++                      if (status != NOTMUCH_STATUS_SUCCESS)\r
++                          ret = status;\r
++                  }\r
++              }\r
++              /* re-add properties */\r
++              for (; notmuch_message_properties_valid (properties);\r
++                   notmuch_message_properties_move_to_next (properties)) {\r
++                  propkey = notmuch_message_properties_key (properties);\r
++                  skip = FALSE;\r
++\r
++                  for (size_t i = 0; i < ARRAY_SIZE (autoproperties); i++)\r
++                      if (strcmp (propkey, autoproperties[i]) == 0)\r
++                          skip = TRUE;\r
++\r
++                  if (!skip) {\r
++                      status = notmuch_message_add_property (newmsg, propkey,\r
++                                                             notmuch_message_properties_value (properties));\r
++                      if (status != NOTMUCH_STATUS_SUCCESS)\r
++                          ret = status;\r
++                  }\r
++              }\r
++              readded = TRUE;\r
++          }\r
++      } else {\r
++          /* if we failed to add this filename, go ahead and try the\r
++           * next one as though it were first, but report the\r
++           * error... */\r
++          ret = status;\r
++      }\r
++    }\r
++    if (newmsg)\r
++      notmuch_message_destroy (newmsg);\r
++                      \r
++    /* should we also destroy the incoming message object?  at the\r
++     * moment, we leave that to the caller */\r
++    return ret;\r
++}\r
+diff --git a/lib/notmuch.h b/lib/notmuch.h\r
+index 66b3503..9076a9b 100644\r
+--- a/lib/notmuch.h\r
++++ b/lib/notmuch.h\r
+@@ -1394,6 +1394,20 @@ notmuch_filenames_t *\r
+ notmuch_message_get_filenames (notmuch_message_t *message);\r
\r
+ /**\r
++ * Re-index the e-mail corresponding to 'message' using the supplied index options\r
++ *\r
++ * Returns the status of the re-index operation.  (see the return\r
++ * codes documented in notmuch_database_add_message)\r
++ *\r
++ * After reindexing, the user should discard the message object passed\r
++ * in here by calling notmuch_message_destroy, since it refers to the\r
++ * original message, not to the reindexed message.\r
++ */\r
++notmuch_status_t\r
++notmuch_message_reindex (notmuch_message_t *message,\r
++                       notmuch_indexopts_t *indexopts);\r
++\r
++/**\r
+  * Message flags.\r
+  */\r
+ typedef enum _notmuch_message_flag {\r
+-- \r
+2.8.1\r
+\r