lib/thread: initial use of references as for fallback parenting

This is mainly to lay out the structure of the final code. The problem
isn't really solved yet, although some very simple cases are
better (hence the fixed test). We need two passes through the messages
because we need to be careful not to re-parent too many messages and
end up without any toplevel messages.
This commit is contained in:
David Bremner 2018-08-30 08:29:07 -03:00
parent ac2146118b
commit a330858284
2 changed files with 41 additions and 3 deletions

View file

@ -413,22 +413,52 @@ _parent_via_in_reply_to (notmuch_thread_t *thread, notmuch_message_t *message) {
}
}
static void
_parent_or_toplevel (notmuch_thread_t *thread, notmuch_message_t *message)
{
bool found = false;
notmuch_message_t *parent = NULL;
const notmuch_string_list_t *references =
_notmuch_message_get_references (message);
for (notmuch_string_node_t *ref_node = references->head;
! found && ref_node; ref_node = ref_node->next) {
if ((found = g_hash_table_lookup_extended (thread->message_hash,
ref_node->string, NULL,
(void **) &parent))) {
_notmuch_message_add_reply (parent, message);
}
}
if (! found)
_notmuch_message_list_add_message (thread->toplevel_list, message);
}
static void
_resolve_thread_relationships (notmuch_thread_t *thread)
{
notmuch_message_node_t *node, *first_node;
notmuch_message_t *message;
void *local;
notmuch_message_list_t *maybe_toplevel_list;
first_node = thread->message_list->head;
if (! first_node)
return;
local = talloc_new (thread);
maybe_toplevel_list = _notmuch_message_list_create (local);
for (node = first_node->next; node; node = node->next) {
message = node->message;
if (! _parent_via_in_reply_to (thread, message))
_notmuch_message_list_add_message (thread->toplevel_list, message);
_notmuch_message_list_add_message (maybe_toplevel_list, message);
}
for (notmuch_messages_t *roots = _notmuch_messages_create (maybe_toplevel_list);
notmuch_messages_valid (roots);
notmuch_messages_move_to_next (roots)) {
notmuch_message_t *message = notmuch_messages_get (roots);
_parent_or_toplevel (thread, message);
}
/*
* if we reach the end of the list without finding a top-level
* message, that means the thread is a cycle (or set of cycles)
@ -439,6 +469,14 @@ _resolve_thread_relationships (notmuch_thread_t *thread)
message = first_node->message;
if (_notmuch_message_list_empty(thread->toplevel_list) ||
! _parent_via_in_reply_to (thread, message)) {
/*
* If the oldest message happens to be in-reply-to a
* missing message, we only check for references if there
* is some other candidate for root message.
*/
if (! _notmuch_message_list_empty (thread->toplevel_list))
_parent_or_toplevel (thread, message);
else
_notmuch_message_list_add_message (thread->toplevel_list, message);
}
}
@ -459,6 +497,7 @@ _resolve_thread_relationships (notmuch_thread_t *thread)
* correctly in the thread even when an intermediate message is
* missing from the thread.
*/
talloc_free (local);
}
/* Create a new notmuch_thread_t object by finding the thread

View file

@ -167,7 +167,6 @@ test_expect_equal_json "$output" "$expected"
add_email_corpus threading
test_begin_subtest "reply to ghost"
test_subtest_known_broken
notmuch show --entire-thread=true id:000-real-root@example.org | grep ^Subject: | head -1 > OUTPUT
cat <<EOF > EXPECTED
Subject: root message