aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-08-17 19:46:08 +0200
committerDanilo M. <danix@danix.xyz>2026-08-17 19:46:08 +0200
commitacec616bee1c7a336a9dcee8338849b970c3eab1 (patch)
treece76acee427818220c1c444d737587abc5c804d9
parent69e2173b71e94e5a89c39b20d4a5962aadb715e9 (diff)
downloadqtmaildir-acec616bee1c7a336a9dcee8338849b970c3eab1.tar.gz
qtmaildir-acec616bee1c7a336a9dcee8338849b970c3eab1.zip
feat(config): read a per-account trash folder
-rw-r--r--src/config.cpp11
-rw-r--r--src/config.h16
-rw-r--r--tests/test_config.cpp30
3 files changed, 57 insertions, 0 deletions
diff --git a/src/config.cpp b/src/config.cpp
index 600c558..d56099a 100644
--- a/src/config.cpp
+++ b/src/config.cpp
@@ -137,6 +137,11 @@ QString Account::draftsQuery() const
return folderQuery(maildir, drafts);
}
+QString Account::trashQuery() const
+{
+ return folderQuery(maildir, trash);
+}
+
QString Config::allSentQuery() const
{
return joinAccountQueries(m_accounts, &Account::sentQuery);
@@ -433,6 +438,12 @@ void Config::load(const QString &path)
account.sent =
settings.value(QStringLiteral("sent")).toString().trimmed();
+ // Mandatory, unlike sent: Delete moves a file into this folder, so an
+ // account without one cannot delete at all. Trimmed for the same
+ // reason as sent, above.
+ account.trash =
+ settings.value(QStringLiteral("trash")).toString().trimmed();
+
// Both optional, and both describe this account's chip in the thread
// list. An account tag is a different taxonomy from a functional one,
// saying which mailbox a thread arrived in rather than what state it
diff --git a/src/config.h b/src/config.h
index 70f7181..1feeeda 100644
--- a/src/config.h
+++ b/src/config.h
@@ -58,6 +58,15 @@ struct Account
/// one for the account that has none.
QString sent;
+ /// The account's trash folder, relative to maildir.
+ ///
+ /// MANDATORY, unlike `sent` and `drafts`. Delete moves a file into this
+ /// folder, so an account without one cannot delete at all, and the user
+ /// chose a config error over a per-account disabled state: "it is
+ /// mandatory for the program to function properly". Config::load()
+ /// reports a missing key through the warnings path.
+ QString trash;
+
/// Chip colour in the thread list. Invalid when unset, in which case one
/// is generated from the account tag's name.
QColor color;
@@ -98,6 +107,13 @@ struct Account
/// keys are independent, and one real account configures `drafts` with no
/// `sent` at all.
QString draftsQuery() const;
+
+ /// Matches this account's trash, or empty when `trash` is unset.
+ ///
+ /// Empty is a config error rather than a legitimate state, unlike
+ /// sentQuery(). The query helper still returns empty so callers compose
+ /// uniformly; it is Config::load() that reports the problem.
+ QString trashQuery() const;
};
/// A named query, stored in queries.json.
diff --git a/tests/test_config.cpp b/tests/test_config.cpp
index 0dfda86..98743f5 100644
--- a/tests/test_config.cpp
+++ b/tests/test_config.cpp
@@ -116,6 +116,8 @@ private slots:
void draftsQuerySurvivesABracketedPath();
void allDraftsQuerySkipsAccountsWithoutTheKey();
void allDraftsQueryIsIndependentOfSent();
+ void anAccountCarriesItsTrashFolder();
+ void aBracketedTrashFolderIsQuoted();
};
static QString writeIni(const QTemporaryDir &dir, const QString &body)
@@ -953,6 +955,34 @@ void TestConfig::sentQuerySurvivesABracketedPath()
"brackets as syntax and the query will match nothing");
}
+void TestConfig::anAccountCarriesItsTrashFolder()
+{
+ QTemporaryDir dir;
+ Config config;
+ config.load(writeIni(dir, QStringLiteral(
+ "[account.work]\n"
+ "maildir=work\n"
+ "trash=Trash\n")));
+
+ const Account account = config.account(QStringLiteral("work"));
+ QCOMPARE(account.trash, QStringLiteral("Trash"));
+ // Quoted and globbed exactly as sentQuery() does it, so a folder with a
+ // space or a bracket cannot break the query.
+ QCOMPARE(account.trashQuery(), QStringLiteral("path:\"work/Trash/**\""));
+}
+
+void TestConfig::aBracketedTrashFolderIsQuoted()
+{
+ // The real setup nests a localised trash folder under a bracketed parent.
+ // The brackets are not notmuch syntax, but the quoting has to survive them.
+ Account account;
+ account.maildir = QStringLiteral("provider-a");
+ account.trash = QStringLiteral("[Provider]/Cestino");
+
+ QCOMPARE(account.trashQuery(),
+ QStringLiteral("path:\"provider-a/[Provider]/Cestino/**\""));
+}
+
void TestConfig::sentQueryComposesWithScopedQuery()
{
// A Sent view under one account must not show another account's sent mail.