aboutsummaryrefslogtreecommitdiffhomepage
path: root/notmuch-search.c
diff options
context:
space:
mode:
authorGravatar Austin Clements <amdragon@MIT.EDU>2013-10-24 11:19:08 -0400
committerGravatar David Bremner <david@tethera.net>2013-11-08 20:43:29 -0400
commitabeac48522ded66e2f0e9aae704482355cb46e6a (patch)
tree3f0df784ca77999c880b9000d6d4281b6b9a7143 /notmuch-search.c
parent730b8f61e0cf4b2e8c0f123c0914d472d6df38fc (diff)
search: Add stable queries to thread search results
These queries will match exactly the set of messages currently in the thread, even if more messages later arrive. Two queries are provided: one for matched messages and one for unmatched messages. This can be used to fix race conditions with tagging threads from search results. While tagging based on a thread: query can affect messages that arrived after the search, tagging based on stable queries affects only the messages the user was shown in the search UI. Since we want clients to be able to depend on the presence of these queries, this ushers in schema version 2.
Diffstat (limited to 'notmuch-search.c')
-rw-r--r--notmuch-search.c59
1 files changed, 59 insertions, 0 deletions
diff --git a/notmuch-search.c b/notmuch-search.c
index d9d39ec3..7c973b3d 100644
--- a/notmuch-search.c
+++ b/notmuch-search.c
@@ -20,6 +20,7 @@
#include "notmuch-client.h"
#include "sprinter.h"
+#include "string-util.h"
typedef enum {
OUTPUT_SUMMARY,
@@ -46,6 +47,45 @@ sanitize_string (const void *ctx, const char *str)
return out;
}
+/* Return two stable query strings that identify exactly the matched
+ * and unmatched messages currently in thread. If there are no
+ * matched or unmatched messages, the returned buffers will be
+ * NULL. */
+static int
+get_thread_query (notmuch_thread_t *thread,
+ char **matched_out, char **unmatched_out)
+{
+ notmuch_messages_t *messages;
+ char *escaped = NULL;
+ size_t escaped_len = 0;
+
+ *matched_out = *unmatched_out = NULL;
+
+ for (messages = notmuch_thread_get_messages (thread);
+ notmuch_messages_valid (messages);
+ notmuch_messages_move_to_next (messages))
+ {
+ notmuch_message_t *message = notmuch_messages_get (messages);
+ const char *mid = notmuch_message_get_message_id (message);
+ /* Determine which query buffer to extend */
+ char **buf = notmuch_message_get_flag (
+ message, NOTMUCH_MESSAGE_FLAG_MATCH) ? matched_out : unmatched_out;
+ /* Add this message's id: query. Since "id" is an exclusive
+ * prefix, it is implicitly 'or'd together, so we only need to
+ * join queries with a space. */
+ if (make_boolean_term (thread, "id", mid, &escaped, &escaped_len) < 0)
+ return -1;
+ if (*buf)
+ *buf = talloc_asprintf_append_buffer (*buf, " %s", escaped);
+ else
+ *buf = talloc_strdup (thread, escaped);
+ if (!*buf)
+ return -1;
+ }
+ talloc_free (escaped);
+ return 0;
+}
+
static int
do_search_threads (sprinter_t *format,
notmuch_query_t *query,
@@ -131,6 +171,25 @@ do_search_threads (sprinter_t *format,
format->string (format, authors);
format->map_key (format, "subject");
format->string (format, subject);
+ if (notmuch_format_version >= 2) {
+ char *matched_query, *unmatched_query;
+ if (get_thread_query (thread, &matched_query,
+ &unmatched_query) < 0) {
+ fprintf (stderr, "Out of memory\n");
+ return 1;
+ }
+ format->map_key (format, "query");
+ format->begin_list (format);
+ if (matched_query)
+ format->string (format, matched_query);
+ else
+ format->null (format);
+ if (unmatched_query)
+ format->string (format, unmatched_query);
+ else
+ format->null (format);
+ format->end (format);
+ }
}
talloc_free (ctx_quote);