aboutsummaryrefslogtreecommitdiffstats
path: root/src/notmuchworker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/notmuchworker.cpp')
-rw-r--r--src/notmuchworker.cpp57
1 files changed, 55 insertions, 2 deletions
diff --git a/src/notmuchworker.cpp b/src/notmuchworker.cpp
index d34c032..24f3fd9 100644
--- a/src/notmuchworker.cpp
+++ b/src/notmuchworker.cpp
@@ -24,6 +24,7 @@
#include <cstdlib>
+#include "mimeparser.h"
#include "nmraii.h"
namespace {
@@ -46,6 +47,45 @@ QStringList tagsOf(notmuch_thread_t *thread)
return result;
}
+/// Who a thread's messages were addressed to, summarised for one line.
+///
+/// EXPENSIVE, and only called when a query asks. "To" is not served from
+/// notmuch's index, so every call here reads message FILES: 8.7 ms per thread
+/// measured against a real database, which is 38 seconds over a 4411-thread
+/// inbox. See ThreadSummary::recipients.
+///
+/// The messages come from the THREAD and are owned by it, freed when it is
+/// freed (notmuch.h:1637). They are therefore held raw and never wrapped in
+/// NmMessage, which would call notmuch_message_destroy on memory the thread
+/// frees again, and the walk finishes before the caller drops the thread. This
+/// is the same rule walkReplies follows, and getting it wrong is a double-free
+/// rather than a leak.
+QString recipientsOf(notmuch_thread_t *thread)
+{
+ // The first message with a usable To wins. A thread is one conversation,
+ // and the alternative, folding every message's recipients together, is the
+ // participants-list problem item 2 rejected: it produces a union that
+ // misdescribes itself the moment a thread has replies going both ways.
+ notmuch_messages_t *messages = notmuch_thread_get_messages(thread);
+ for (; notmuch_messages_valid(messages);
+ notmuch_messages_move_to_next(messages)) {
+ notmuch_message_t *message = notmuch_messages_get(messages);
+ if (!message)
+ continue;
+
+ // Returns "" for a missing header and NULL on error, and the two mean
+ // different things only to notmuch: both are "nothing to show" here.
+ const char *to = notmuch_message_get_header(message, "To");
+ if (!to || !*to)
+ continue;
+
+ const QString summary = recipientSummary(QString::fromUtf8(to));
+ if (!summary.isEmpty())
+ return summary;
+ }
+ return QString();
+}
+
/// Collects the message ids a query matches. Returns false if the query could
/// not be run at all, which is different from a query that matched nothing.
bool collectMessageIds(notmuch_database_t *db, const QString &query,
@@ -187,7 +227,7 @@ void NotmuchWorker::close()
}
void NotmuchWorker::runQuery(const QString &query, quint64 generation,
- SortOrder sort)
+ SortOrder sort, bool withRecipients)
{
if (!openReadOnly())
return;
@@ -231,6 +271,8 @@ void NotmuchWorker::runQuery(const QString &query, quint64 generation,
summary.totalCount = notmuch_thread_get_total_messages(thread.get());
summary.matchedCount = notmuch_thread_get_matched_messages(thread.get());
summary.tags = tagsOf(thread.get());
+ if (withRecipients)
+ summary.recipients = recipientsOf(thread.get());
batch.append(summary);
++total;
@@ -250,7 +292,7 @@ void NotmuchWorker::runQuery(const QString &query, quint64 generation,
void NotmuchWorker::loadThread(const QString &threadId,
const QString &matchQuery,
- quint64 generation)
+ quint64 generation, bool matchedOnly)
{
if (!openReadOnly())
return;
@@ -303,6 +345,17 @@ void NotmuchWorker::loadThread(const QString &threadId,
ref.filePath = QString::fromUtf8(notmuch_message_get_filename(message.get()));
ref.tags = tagsOf(message.get());
ref.matched = !haveMatchSet || matchedIds.contains(ref.messageId);
+
+ // Dropped rather than rendered as a stub.
+ //
+ // haveMatchSet is redundant here and kept deliberately: ref.matched is
+ // already true for every message when no query was given, so the two
+ // conditions cannot disagree today. It states the invariant this
+ // depends on at the point that depends on it, so a later change to how
+ // ref.matched is computed cannot silently empty the pane.
+ if (matchedOnly && haveMatchSet && !ref.matched)
+ continue;
+
result.append(ref);
}