From: David Bremner <david@tethera.net>
To: notmuch@notmuchmail.org
Subject: [PATCH 06/15] lib/thread: refactor in-reply-to test.
Date: Tue, 31 Jul 2018 06:45:46 +0800 [thread overview]
Message-ID: <20180730224555.26047-7-david@tethera.net> (raw)
In-Reply-To: <20180730224555.26047-1-david@tethera.net>
This is not a complete win in code-size, but it makes the code (which
is about to get more complicated) easier to follow. In particular the
second pass (which looks a bit wasteful here) will be needed when we
reparent by references.
---
lib/thread.cc | 107 ++++++++++++++++++++++++++----------
test/T510-thread-replies.sh | 1 -
2 files changed, 77 insertions(+), 31 deletions(-)
diff --git a/lib/thread.cc b/lib/thread.cc
index db592a3a..9f923843 100644
--- a/lib/thread.cc
+++ b/lib/thread.cc
@@ -387,29 +387,72 @@ _thread_add_matched_message (notmuch_thread_t *thread,
_thread_add_matched_author (thread, _notmuch_message_get_author (hashed_message));
}
+static bool
+_parent_via_in_reply_to (notmuch_thread_t *thread, notmuch_message_t *message) {
+ notmuch_message_t *parent;
+ const char *in_reply_to;
+
+ in_reply_to = _notmuch_message_get_in_reply_to (message);
+ DEBUG_PRINTF("checking message = %s in_reply_to=%s\n",
+ notmuch_message_get_message_id (message), 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)) {
+ _notmuch_message_add_reply (parent, message);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+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, *parent;
- const char *in_reply_to;
+ 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;
- in_reply_to = _notmuch_message_get_in_reply_to (message);
- if (in_reply_to && strlen (in_reply_to) &&
- g_hash_table_lookup_extended (thread->message_hash,
- in_reply_to, NULL,
- (void **) &parent))
- _notmuch_message_add_reply (parent, message);
- else
- _notmuch_message_list_add_message (thread->toplevel_list, message);
+ if (! _parent_via_in_reply_to (thread, 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)
@@ -418,17 +461,31 @@ _resolve_thread_relationships (notmuch_thread_t *thread)
*/
if (first_node) {
message = first_node->message;
- in_reply_to = _notmuch_message_get_in_reply_to (message);
- if (thread->toplevel_list->head &&
- in_reply_to && strlen (in_reply_to) &&
- g_hash_table_lookup_extended (thread->message_hash,
- in_reply_to, NULL,
- (void **) &parent))
- _notmuch_message_add_reply (parent, message);
- else
- _notmuch_message_list_add_message (thread->toplevel_list, message);
+ if (! thread->toplevel_list->head ||
+ ! _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 (thread->toplevel_list->head)
+ _parent_or_toplevel (thread, message);
+ else
+ _notmuch_message_list_add_message (thread->toplevel_list, message);
+ }
}
+ /* XXX: After scanning through the entire list looking for parents
+ * via "In-Reply-To", we should do a second pass that looks at the
+ * list of messages IDs in the "References" header instead.
+ * Unlike the current quick fix, the parent should be the
+ * "deepest" message of all the messages found in the "References"
+ * list.
+ *
+ * Doing this will allow messages and sub-threads to be positioned
+ * correctly in the thread even when an intermediate message is
+ * missing from the thread.
+ */
for (notmuch_messages_t *messages = _notmuch_messages_create (thread->toplevel_list);
notmuch_messages_valid (messages);
notmuch_messages_move_to_next (messages))
@@ -437,17 +494,7 @@ _resolve_thread_relationships (notmuch_thread_t *thread)
_notmuch_message_sort_subtree (message);
}
-
- /* XXX: After scanning through the entire list looking for parents
- * via "In-Reply-To", we should do a second pass that looks at the
- * list of messages IDs in the "References" header instead. (And
- * for this the parent would be the "deepest" message of all the
- * messages found in the "References" list.)
- *
- * Doing this will allow messages and sub-threads to be positioned
- * 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
diff --git a/test/T510-thread-replies.sh b/test/T510-thread-replies.sh
index b7322198..3ee2ee78 100755
--- a/test/T510-thread-replies.sh
+++ b/test/T510-thread-replies.sh
@@ -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
--
2.18.0
next prev parent reply other threads:[~2018-07-30 22:46 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-07-30 22:45 Threading patches v2 David Bremner
2018-07-30 22:45 ` [PATCH 01/15] util: add DEBUG_PRINTF, rename error_util.h -> debug_print.h David Bremner
2018-07-30 22:45 ` [PATCH 02/15] test: start threading test corpus David Bremner
2018-07-30 22:45 ` [PATCH 03/15] test: add known broken tests for "ghost roots" David Bremner
2018-07-30 22:45 ` [PATCH 04/15] lib/thread: sort child messages by date David Bremner
2018-07-30 22:45 ` [PATCH 05/15] lib: read reference terms into message struct David Bremner
2018-07-30 22:45 ` David Bremner [this message]
2018-07-30 22:45 ` [PATCH 07/15] lib: calculate message depth in thread David Bremner
2018-07-30 22:45 ` [PATCH 08/15] lib/thread: rewrite _parent_or_toplevel to use depths David Bremner
2018-07-30 22:45 ` [PATCH 09/15] lib/thread: change _resolve_thread_relationships " David Bremner
2018-07-30 22:45 ` [PATCH 10/15] test: add known broken test for good In-Reply-To / bad References David Bremner
2018-07-30 22:45 ` [PATCH 11/15] test/thread-replies: mangle In-Reply-To's David Bremner
2018-07-30 22:45 ` [PATCH 12/15] util/string-util: export skip_space David Bremner
2018-07-30 22:45 ` [PATCH 13/15] lib: add _notmuch_message_id_parse_strict David Bremner
2018-08-01 0:46 ` Amin Bandali
2018-08-01 4:58 ` [Patch v1.1] " David Bremner
2018-07-30 22:45 ` [PATCH 14/15] lib: change parent strategy to use In-Reply-To if it looks sane David Bremner
2018-07-30 22:45 ` [PATCH 15/15] test: add known broken test for multiple thread terms per message David Bremner
2018-08-01 14:53 ` Threading patches v2 Gregor Zattler
2018-08-27 1:53 ` [PATCH] WIP: sort top level messages in thread David Bremner
2018-08-27 13:44 ` Gregor Zattler
2018-08-28 21:33 ` Amin Bandali
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://notmuchmail.org/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180730224555.26047-7-david@tethera.net \
--to=david@tethera.net \
--cc=notmuch@notmuchmail.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://yhetil.org/notmuch.git/
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).