/* * qtmaildir - a Qt6 mail client for notmuch-indexed Maildirs * Copyright (C) 2026 Danilo M. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #pragma once #include #include #include #include "types.h" struct _notmuch_database; typedef struct _notmuch_database notmuch_database_t; /// Owns the only notmuch database handle in the process. /// /// libnotmuch is not thread-safe and queries over a large database block, so /// this object lives on its own thread and the UI reaches it only through /// queued signals. No notmuch pointer ever leaves this class. class NotmuchWorker : public QObject { Q_OBJECT public: /// notmuchConfigPath may be empty, in which case notmuch resolves its own /// config and therefore its own database.path. explicit NotmuchWorker(const QString ¬muchConfigPath, QObject *parent = nullptr); ~NotmuchWorker() override; /// Threads emitted per threadsReady() signal. static constexpr int kBatchSize = 200; public slots: /// Runs a query. generation lets the UI discard results from a superseded /// query without the worker needing to know about cancellation. void runQuery(const QString &query, quint64 generation); /// Loads the messages of one thread, oldest first. matchQuery is the /// user's current query; messages matching it render expanded, the rest /// as stubs. void loadThread(const QString &threadId, const QString &matchQuery, quint64 generation); /// Applies tag changes. Opens the database read-write, applies, and closes /// immediately: notmuch's write lock is exclusive process-wide, so holding /// it would block the user's cron `notmuch new`. void applyTags(const TagChange &change); /// Batch tagging over whole threads. The UI holds thread ids, not message /// ids, for rows it has not opened, so the resolution happens here where /// the database handle lives. This is the path the archive/flag/delete /// actions use on a multi-row selection. void applyTagsToThreads(const QStringList &threadIds, const QStringList &add, const QStringList &remove, const QString &description); signals: void threadsReady(const QVector &threads, quint64 generation); void queryFinished(int totalThreads, quint64 generation); void threadLoaded(const QVector &messages, quint64 generation); void tagsApplied(const TagChange &change); void errorOccurred(const QString &message); private: bool openReadOnly(); void close(); QByteArray configPathArg() const; QString m_configPath; notmuch_database_t *m_db = nullptr; };