From 387828c4356416278fdac8446c904fe4c5ad283d Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Tue, 17 Nov 2009 17:40:19 -0800 Subject: [PATCH] get_in_reply_to: Implement via the database, not by opening mail file. This reduces our reliance on open message_file objects, (so is a step toward fixing the "too many open files" bug), but more importantly, it means we don't load a self-referencing in-reply-to header, (since we weed those out before adding any replyto terms to the database). --- lib/message.cc | 57 +++++++++++++++++++++++++++++++++++++++++++------- lib/thread.cc | 2 +- 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/lib/message.cc b/lib/message.cc index a4b090ba..692fd897 100644 --- a/lib/message.cc +++ b/lib/message.cc @@ -33,6 +33,7 @@ struct _notmuch_message { int frozen; char *message_id; char *thread_id; + char *in_reply_to; char *filename; notmuch_message_file_t *message_file; notmuch_message_list_t *replies; @@ -111,6 +112,7 @@ _notmuch_message_create (const void *talloc_owner, /* Each of these will be lazily created as needed. */ message->message_id = NULL; message->thread_id = NULL; + message->in_reply_to = NULL; message->filename = NULL; message->message_file = NULL; @@ -270,16 +272,57 @@ notmuch_message_get_header (notmuch_message_t *message, const char *header) return notmuch_message_file_get_header (message->message_file, header); } -/* XXX: We probably want to store the In-Reply-To header in the - * database (separate from the References message IDs) so that we can - * fetch it out again without having to go load the message file. */ +/* Return the message ID from the In-Reply-To header of 'message'. + * + * Returns an empty string ("") if 'message' has no In-Reply-To + * header. + * + * Returns NULL if any error occurs. + */ const char * _notmuch_message_get_in_reply_to (notmuch_message_t *message) { - return _parse_message_id (message, - notmuch_message_get_header (message, - "in-reply-to"), - NULL); + const char *prefix = _find_prefix ("replyto"); + int prefix_len = strlen (prefix); + Xapian::TermIterator i; + std::string in_reply_to; + + if (message->in_reply_to) + return message->in_reply_to; + + i = message->doc.termlist_begin (); + i.skip_to (prefix); + + in_reply_to = *i; + + /* It's perfectly valid for a message to have no In-Reply-To + * header. For these cases, we return an empty string. */ + if (i == message->doc.termlist_end () || + strncmp (in_reply_to.c_str (), prefix, prefix_len)) + { + message->in_reply_to = talloc_strdup (message, ""); + return message->in_reply_to; + } + + message->in_reply_to = talloc_strdup (message, + in_reply_to.c_str () + prefix_len); + +#if DEBUG_DATABASE_SANITY + i++; + + in_reply_to = *i; + + if (i != message->doc.termlist_end () && + strncmp ((*i).c_str (), prefix, prefix_len)) + { + INTERNAL_ERROR ("Message %s has duplicate In-Reply-To IDs: %s and %s\n" + notmuch_message_get_message_id (message), + message->in_reply_to, + (*i).c_str () + prefix_len); + } +#endif + + return message->in_reply_to; } const char * diff --git a/lib/thread.cc b/lib/thread.cc index 4411d64d..e38a5b2e 100644 --- a/lib/thread.cc +++ b/lib/thread.cc @@ -155,7 +155,7 @@ _resolve_thread_relationships (unused (notmuch_thread_t *thread)) while ((node = *prev)) { message = node->message; in_reply_to = _notmuch_message_get_in_reply_to (message); - if (in_reply_to && + if (in_reply_to && strlen (in_reply_to) && g_hash_table_lookup_extended (thread->message_hash, in_reply_to, NULL, (void **) &parent)) -- 2.26.2