aboutsummaryrefslogtreecommitdiffstats
path: root/src/config.cpp
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-09-13 20:03:17 +0200
committerDanilo M. <danix@danix.xyz>2026-09-13 20:03:17 +0200
commit18ff1f33f64428ab96ca0b5ea22e681be564c886 (patch)
tree4c283551bba03a1436cc1f1ac3b3b4c2dcdfc95b /src/config.cpp
parent2623b762a90b04c57491a5d58ab72c8807c65c80 (diff)
downloadqtmaildir-18ff1f33f64428ab96ca0b5ea22e681be564c886.tar.gz
qtmaildir-18ff1f33f64428ab96ca0b5ea22e681be564c886.zip
feat(config): a threaded, path-based spam filter
Diffstat (limited to 'src/config.cpp')
-rw-r--r--src/config.cpp21
1 files changed, 20 insertions, 1 deletions
diff --git a/src/config.cpp b/src/config.cpp
index 0fa3c85..390848a 100644
--- a/src/config.cpp
+++ b/src/config.cpp
@@ -64,7 +64,8 @@ const QStringList kQueryGenerators = { QStringLiteral("unread"),
QStringLiteral("flagged"),
QStringLiteral("sent"),
QStringLiteral("drafts"),
- QStringLiteral("trash") };
+ QStringLiteral("trash"),
+ QStringLiteral("spam") };
/// The tag a generator matches, for the three filters that are a plain tag
/// query. Empty for "sent", "drafts" and "trash", which compose from each
@@ -1018,6 +1019,8 @@ QString Config::resolvedQuery(const SavedQuery &query) const
return allSentQuery();
if (query.generated == QStringLiteral("trash"))
return allTrashQuery();
+ if (query.generated == QStringLiteral("spam"))
+ return allSpamQuery();
// An unknown generator was reported on load. Empty rather than the
// bare stored query, which for a generated entry is empty anyway and
// would otherwise run as "match everything".
@@ -1106,6 +1109,10 @@ SavedQuery Config::builtinFilter(const QString &generator)
// NOT flat, unlike Sent. A deleted message still belongs to its
// conversation, and folding it back is what Sent had to avoid rather
// than something every folder filter wants.
+ } else if (generator == QStringLiteral("spam")) {
+ filter.name = tr("Spam");
+ // NOT flat, like trash: a spam message still belongs to its
+ // conversation.
}
return filter;
@@ -1138,6 +1145,10 @@ QString Config::resolvedQuery(const SavedQuery &query,
const QString all = allTrashQuery();
return all.isEmpty() ? matchNothingQuery() : all;
}
+ if (query.generated == QStringLiteral("spam")) {
+ const QString all = allSpamQuery();
+ return all.isEmpty() ? matchNothingQuery() : all;
+ }
return QStringLiteral("tag:%1").arg(generatorTag(query.generated));
}
@@ -1173,6 +1184,14 @@ QString Config::resolvedQuery(const SavedQuery &query,
return trash.isEmpty() ? matchNothingQuery() : trash;
}
+ if (query.generated == QStringLiteral("spam")) {
+ // The account's OWN spam query, for the reason spelled out above the
+ // sent case: wrapping the all-accounts query in this account's path
+ // works by accident of path: being hierarchical.
+ const QString spam = scope.spamQuery();
+ return spam.isEmpty() ? matchNothingQuery() : spam;
+ }
+
// A tag filter carries no path of its own, so scoping is exactly what
// scopedQuery() does. Its parentheses are load-bearing: `path:... and a or
// b` binds as `(path:... and a) or b`.