summaryrefslogtreecommitdiffstats
path: root/src/notmuchworker.cpp
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-08-24 21:57:28 +0200
committerDanilo M. <danix@danix.xyz>2026-08-24 21:57:28 +0200
commitb7f2a4e0f8858b1aa0d86755ebab6826306f3eff (patch)
tree542934c034716b69b15258bf06e491798408af84 /src/notmuchworker.cpp
parentf6ceeacad8e1fe15c30db66dcfde8efa9dfb4758 (diff)
downloadqtmaildir-b7f2a4e0f8858b1aa0d86755ebab6826306f3eff.tar.gz
qtmaildir-b7f2a4e0f8858b1aa0d86755ebab6826306f3eff.zip
fix(drafts): index a saved draft so it appears without a sync
Autosave writes the draft to the Maildir drafts folder and stops, while the Drafts view is a notmuch path: query, so a freshly saved draft was invisible until notmuch new ran. saveDraftNow() now emits draftSaved, and MainWindow connects it to a new NotmuchWorker::indexDraftFile() that indexes the one file the way moveMessages() does, with the previous revision removed so a rewrite leaves no ghost. The send path unlinks a draft that was indexed while being composed, so draftRemoved -> removeIndexedFile() drops its entry too. Measured: notmuch_database_index_file assigns NO tags (unlike notmuch new, which adds draft inbox unread), so no tag-stripping is needed and the draft cannot leak into a tag:inbox view. Item 158.
Diffstat (limited to 'src/notmuchworker.cpp')
-rw-r--r--src/notmuchworker.cpp93
1 files changed, 92 insertions, 1 deletions
diff --git a/src/notmuchworker.cpp b/src/notmuchworker.cpp
index fca0a5a..16df4ed 100644
--- a/src/notmuchworker.cpp
+++ b/src/notmuchworker.cpp
@@ -820,8 +820,99 @@ void NotmuchWorker::moveMessages(const QStringList &messageIds,
emit messagesMovedFrom(origins, destFolder);
}
+void NotmuchWorker::indexDraftFile(const QString &path,
+ const QString &previousPath)
+{
+ if (path.isEmpty())
+ return;
+
+ // Same ordering as applyTags() and moveMessages(): notmuch allows one open
+ // handle per process, so the read-only one must close before the write.
+ close();
+
+ const QByteArray configPath = configPathArg();
+ notmuch_database_t *db = nullptr;
+ char *error = nullptr;
+ const notmuch_status_t status = notmuch_database_open_with_config(
+ nullptr,
+ NOTMUCH_DATABASE_MODE_READ_WRITE,
+ configPath.isEmpty() ? nullptr : configPath.constData(),
+ nullptr,
+ &db,
+ &error);
+
+ if (status != NOTMUCH_STATUS_SUCCESS) {
+ emit errorOccurred(
+ QStringLiteral("Cannot open database for writing: %1")
+ .arg(QString::fromUtf8(error ? error
+ : notmuch_status_to_string(status))));
+ free(error);
+ return;
+ }
+
+ notmuch_message_t *indexed = nullptr;
+ const notmuch_status_t added = notmuch_database_index_file(
+ db, path.toUtf8().constData(), nullptr, &indexed);
+ if (indexed)
+ notmuch_message_destroy(indexed);
+
+ // DUPLICATE_MESSAGE_ID is success here, exactly as in moveMessages(): the
+ // file reached the database, it is only the id that was already known.
+ if (added != NOTMUCH_STATUS_SUCCESS
+ && added != NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID) {
+ notmuch_database_close(db);
+ notmuch_database_destroy(db);
+ emit errorOccurred(
+ QStringLiteral("Cannot index %1: %2")
+ .arg(QFileInfo(path).fileName(),
+ QString::fromUtf8(notmuch_status_to_string(added))));
+ return;
+ }
+
+ // The previous revision, if any, is already unlinked from disk; its entry
+ // must not linger as a ghost draft with a filename that no longer exists.
+ if (!previousPath.isEmpty() && previousPath != path)
+ notmuch_database_remove_message(db, previousPath.toUtf8().constData());
+
+ notmuch_database_close(db);
+ notmuch_database_destroy(db);
+}
+
+void NotmuchWorker::removeIndexedFile(const QString &path)
+{
+ if (path.isEmpty())
+ return;
+
+ close();
+
+ const QByteArray configPath = configPathArg();
+ notmuch_database_t *db = nullptr;
+ char *error = nullptr;
+ const notmuch_status_t status = notmuch_database_open_with_config(
+ nullptr,
+ NOTMUCH_DATABASE_MODE_READ_WRITE,
+ configPath.isEmpty() ? nullptr : configPath.constData(),
+ nullptr,
+ &db,
+ &error);
+
+ if (status != NOTMUCH_STATUS_SUCCESS) {
+ emit errorOccurred(
+ QStringLiteral("Cannot open database for writing: %1")
+ .arg(QString::fromUtf8(error ? error
+ : notmuch_status_to_string(status))));
+ free(error);
+ return;
+ }
+
+ notmuch_database_remove_message(db, path.toUtf8().constData());
+
+ notmuch_database_close(db);
+ notmuch_database_destroy(db);
+}
+
void NotmuchWorker::resolveMessages(const QStringList &messageIds,
- const QString &requestTag)
+ const QString &requestTag)
{
if (messageIds.isEmpty())
return;