aboutsummaryrefslogtreecommitdiffstats
path: root/src/mainwindow.h
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-09-14 13:46:33 +0200
committerDanilo M. <danix@danix.xyz>2026-09-14 13:46:33 +0200
commit9fdac493c9a6e35f36dc45ff0e13583ddf88605e (patch)
treeff561fba18bd543306b3166c8eb3591cb1d220e3 /src/mainwindow.h
parentd714483b6027425923340d1bcfa0263b8e7ac0bc (diff)
downloadqtmaildir-9fdac493c9a6e35f36dc45ff0e13583ddf88605e.tar.gz
qtmaildir-9fdac493c9a6e35f36dc45ff0e13583ddf88605e.zip
feat: a Not spam action
Backlog item 201. A message in the Spam view had no way back out: spam is one-way and Restore is hidden outside the trash. not_spam moves each message to the folder its moved-from: origin names, falling back to the account's inbox (reported) for provider-caught mail with no origin. The action is labelled "Not junk" on the free Alt+J: every letter of "Not spam" is taken in the Message menu, and Alt+P (Re&ply) and Alt+S (Mark &spam, frozen) are unavailable. restoreResolvedMessages() and the undelete_thread branch are parameterised with the cleared tag and undo description rather than copied, so Delete and Not spam cannot drift.
Diffstat (limited to 'src/mainwindow.h')
-rw-r--r--src/mainwindow.h48
1 files changed, 47 insertions, 1 deletions
diff --git a/src/mainwindow.h b/src/mainwindow.h
index 478de2d..c3395c9 100644
--- a/src/mainwindow.h
+++ b/src/mainwindow.h
@@ -1130,6 +1130,17 @@ private:
/// Delete on exactly the mail a trash view is full of.
bool everySelectedRowIsInATrashFolder() const;
+ /// Whether every selected row's file already sits in its account's spam
+ /// folder. Empty selection answers false. The spam twin of
+ /// everySelectedRowIsInATrashFolder(), and asked of the PATH for the same
+ /// reason: provider-caught mail in the spam folder carries no `spam` tag.
+ bool everySelectedRowIsInASpamFolder() const;
+
+ /// The one walk both predicates above share: \p folder names the Account
+ /// member (`&Account::trash` or `&Account::spam`) whose folder is asked
+ /// about.
+ bool everySelectedRowIsInAFolder(QString Account::*folder) const;
+
/// Opens the tag dialog on the current selection and applies its result.
///
/// The only route to an arbitrary tag: every other tag action writes a
@@ -1276,6 +1287,22 @@ private:
/// this asks the worker and finishes in onThreadMessagesResolved().
void spamThreads(const QStringList &threadIds);
+ /// Moves each selected row's message back OUT of the spam folder, to the
+ /// folder its `moved-from:` tag names. Mark spam's inverse and Restore's
+ /// twin, offered only on a selection that is in a spam folder.
+ void notSpamSelected();
+
+ /// The half of notSpamSelected() that does the work, given the tags and
+ /// paths the WORKER reported. Forwards to restoreResolvedMessages() with
+ /// `spam` as the cleared tag, so the two restore directions cannot drift.
+ void notSpamMessages(const QStringList &messageIds,
+ const QStringList &paths,
+ const QStringList &tags);
+
+ /// Moves every message of the named THREADS out of their accounts' spam
+ /// folders. Asynchronous like spamThreads(), and for the same reason.
+ void notSpamThreads(const QStringList &threadIds);
+
/// Runs the thread-scoped delete once the worker has resolved the
/// threads to messages.
void onThreadMessagesResolved(const QStringList &messageIds,
@@ -1360,9 +1387,28 @@ private:
/// Moves each resolved message home, using the tags and paths the WORKER
/// reported rather than anything the model holds.
+ ///
+ /// One walk serves all four restore routes: Delete out of the trash
+ /// (message and thread scoped) and Not spam out of the spam folder
+ /// (message and thread scoped). \p clearedTag is the folder's marker tag
+ /// (`deleted` or `spam`) stripped by the move; \p description names the
+ /// action in the status line and on the undo entry.
+ ///
+ /// \p moveUnoriginToInbox picks what a message with no `moved-from:`
+ /// origin gets: the inbox, reported (the message-scoped routes and Not
+ /// spam, where the mail is demonstrably in the folder and must come out),
+ /// or a tag-only removal with no file move (the thread-scoped TRASH route,
+ /// which Delete's toggle also reaches on stranded mail sitting outside the
+ /// trash). \p skipUnmarked drops messages that do not carry \p clearedTag,
+ /// which only the thread-scoped trash route needs.
void restoreResolvedMessages(const QStringList &messageIds,
const QStringList &paths,
- const QStringList &tags);
+ const QStringList &tags,
+ const QString &clearedTag,
+ const QString &description,
+ bool moveUnoriginToInbox,
+ bool skipUnmarked,
+ const QStringList &wholeThreadIds = {});
/// The messages a resolveMessages() request was made for.
QStringList m_pendingRestoreIds;