X-Git-Url: https://git.notmuchmail.org/git?p=notmuch;a=blobdiff_plain;f=lib%2Fquery.cc;h=0b366025ba847314605157e23b193410a792e801;hp=c155470afd82128b37a512af892c08b86a1df3a2;hb=3b76adf9e2c026dd03b820f4c6eab50e25444113;hpb=e04e72f9dd9b435f37cf9e712d9e23cf22896e27 diff --git a/lib/query.cc b/lib/query.cc index c155470a..0b366025 100644 --- a/lib/query.cc +++ b/lib/query.cc @@ -27,6 +27,7 @@ struct _notmuch_query { notmuch_database_t *notmuch; const char *query_string; notmuch_sort_t sort; + notmuch_string_list_t *exclude_terms; }; typedef struct _notmuch_mset_messages { @@ -44,7 +45,7 @@ struct _notmuch_doc_id_set { #define DOCIDSET_WORD(bit) ((bit) / sizeof (unsigned int)) #define DOCIDSET_BIT(bit) ((bit) % sizeof (unsigned int)) -struct _notmuch_threads { +struct visible _notmuch_threads { notmuch_query_t *query; /* The ordered list of doc ids matched by the query. */ @@ -76,6 +77,8 @@ notmuch_query_create (notmuch_database_t *notmuch, query->sort = NOTMUCH_SORT_NEWEST_FIRST; + query->exclude_terms = _notmuch_string_list_create (query); + return query; } @@ -97,6 +100,13 @@ notmuch_query_get_sort (notmuch_query_t *query) return query->sort; } +void +notmuch_query_add_tag_exclude (notmuch_query_t *query, const char *tag) +{ + char *term = talloc_asprintf (query, "%s%s", _find_prefix ("tag"), tag); + _notmuch_string_list_append (query->exclude_terms, term); +} + /* We end up having to call the destructors explicitly because we had * to use "placement new" in order to initialize C++ objects within a * block that we allocated with talloc. So C++ is making talloc @@ -112,6 +122,27 @@ _notmuch_messages_destructor (notmuch_mset_messages_t *messages) return 0; } +/* Return a query that does not match messages with the excluded tags + * registered with the query. Any tags that explicitly appear in + * xquery will not be excluded. */ +static Xapian::Query +_notmuch_exclude_tags (notmuch_query_t *query, Xapian::Query xquery) +{ + for (notmuch_string_node_t *term = query->exclude_terms->head; term; + term = term->next) { + Xapian::TermIterator it = xquery.get_terms_begin (); + Xapian::TermIterator end = xquery.get_terms_end (); + for (; it != end; it++) { + if ((*it).compare (term->string) == 0) + break; + } + if (it == end) + xquery = Xapian::Query (Xapian::Query::OP_AND_NOT, + xquery, Xapian::Query (term->string)); + } + return xquery; +} + notmuch_messages_t * notmuch_query_search_messages (notmuch_query_t *query) { @@ -157,6 +188,8 @@ notmuch_query_search_messages (notmuch_query_t *query) mail_query, string_query); } + final_query = _notmuch_exclude_tags (query, final_query); + enquire.set_weighting_scheme (Xapian::BoolWeight()); switch (query->sort) { @@ -260,17 +293,20 @@ _notmuch_mset_messages_move_to_next (notmuch_messages_t *messages) static notmuch_bool_t _notmuch_doc_id_set_init (void *ctx, notmuch_doc_id_set_t *doc_ids, - GArray *arr, unsigned int bound) + GArray *arr) { - size_t count = (bound + sizeof (doc_ids->bitmap[0]) - 1) / - sizeof (doc_ids->bitmap[0]); - unsigned int *bitmap = talloc_zero_array (ctx, unsigned int, count); + unsigned int max = 0; + unsigned int *bitmap; + + for (unsigned int i = 0; i < arr->len; i++) + max = MAX(max, g_array_index (arr, unsigned int, i)); + bitmap = talloc_zero_array (ctx, unsigned int, 1 + max / sizeof (*bitmap)); if (bitmap == NULL) return FALSE; doc_ids->bitmap = bitmap; - doc_ids->bound = bound; + doc_ids->bound = max + 1; for (unsigned int i = 0; i < arr->len; i++) { unsigned int doc_id = g_array_index (arr, unsigned int, i); @@ -315,7 +351,6 @@ notmuch_query_search_threads (notmuch_query_t *query) { notmuch_threads_t *threads; notmuch_messages_t *messages; - Xapian::docid max_doc_id = 0; threads = talloc (query, notmuch_threads_t); if (threads == NULL) @@ -335,7 +370,6 @@ notmuch_query_search_threads (notmuch_query_t *query) while (notmuch_messages_valid (messages)) { unsigned int doc_id = _notmuch_mset_messages_get_doc_id (messages); g_array_append_val (threads->doc_ids, doc_id); - max_doc_id = MAX (max_doc_id, doc_id); notmuch_messages_move_to_next (messages); } threads->doc_id_pos = 0; @@ -343,7 +377,7 @@ notmuch_query_search_threads (notmuch_query_t *query) talloc_free (messages); if (! _notmuch_doc_id_set_init (threads, &threads->match_set, - threads->doc_ids, max_doc_id + 1)) { + threads->doc_ids)) { talloc_free (threads); return NULL; } @@ -435,6 +469,8 @@ notmuch_query_count_messages (notmuch_query_t *query) mail_query, string_query); } + final_query = _notmuch_exclude_tags (query, final_query); + enquire.set_weighting_scheme(Xapian::BoolWeight()); enquire.set_docid_order(Xapian::Enquire::ASCENDING); @@ -456,3 +492,47 @@ notmuch_query_count_messages (notmuch_query_t *query) return count; } + +unsigned +notmuch_query_count_threads (notmuch_query_t *query) +{ + notmuch_messages_t *messages; + GHashTable *hash; + unsigned int count; + notmuch_sort_t sort; + + sort = query->sort; + query->sort = NOTMUCH_SORT_UNSORTED; + messages = notmuch_query_search_messages (query); + query->sort = sort; + if (messages == NULL) + return 0; + + hash = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL); + if (hash == NULL) { + talloc_free (messages); + return 0; + } + + while (notmuch_messages_valid (messages)) { + notmuch_message_t *message = notmuch_messages_get (messages); + const char *thread_id = notmuch_message_get_thread_id (message); + char *thread_id_copy = talloc_strdup (messages, thread_id); + if (unlikely (thread_id_copy == NULL)) { + notmuch_message_destroy (message); + count = 0; + goto DONE; + } + g_hash_table_insert (hash, thread_id_copy, NULL); + notmuch_message_destroy (message); + notmuch_messages_move_to_next (messages); + } + + count = g_hash_table_size (hash); + + DONE: + g_hash_table_unref (hash); + talloc_free (messages); + + return count; +}