diff options
| -rw-r--r-- | src/config.cpp | 15 | ||||
| -rw-r--r-- | tests/test_config.cpp | 56 | ||||
| -rw-r--r-- | translations/qtmaildir_it_IT.ts | 10 |
3 files changed, 67 insertions, 14 deletions
diff --git a/src/config.cpp b/src/config.cpp index d56099a..8294e4b 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -473,6 +473,21 @@ void Config::load(const QString &path) .arg(account.key)); continue; } + + // Mandatory, unlike sent: Delete moves a file into this folder, so an + // account without one cannot delete at all. Reported rather than + // silently disabled, so the user finds out from a warning rather than + // from a Delete that quietly does nothing. The account still loads; + // only Delete is unusable, which does not warrant losing the rest of + // the account's mail. + if (account.trash.isEmpty()) { + addProblem( + tr("Account '%1' has no trash folder configured; add a " + "'trash' key to its section. Delete will not work for " + "this account until it does.") + .arg(account.key)); + } + m_accounts.append(account); } diff --git a/tests/test_config.cpp b/tests/test_config.cpp index 98743f5..10dcf68 100644 --- a/tests/test_config.cpp +++ b/tests/test_config.cpp @@ -118,6 +118,7 @@ private slots: void allDraftsQueryIsIndependentOfSent(); void anAccountCarriesItsTrashFolder(); void aBracketedTrashFolderIsQuoted(); + void anAccountWithoutATrashFolderWarns(); }; static QString writeIni(const QTemporaryDir &dir, const QString &body) @@ -430,7 +431,8 @@ void TestConfig::absentSyncCommandIsNoticeNotProblem() QTemporaryDir dir; const QString path = writeIni(dir, QStringLiteral( "[account.work]\n" - "maildir=work-mail\n")); + "maildir=work-mail\n" + "trash=Trash\n")); Config config; config.load(path); @@ -450,7 +452,8 @@ void TestConfig::brokenSyncCommandIsAProblem() "command=/nonexistent/qtmaildir-test/mailsync.sh\n" "\n" "[account.work]\n" - "maildir=work-mail\n")); + "maildir=work-mail\n" + "trash=Trash\n")); Config config; config.load(path); @@ -485,7 +488,8 @@ void TestConfig::validConfigHasNoProblems() "\n" "[account.work]\n" "maildir=work-mail\n" - "address=user@example.org\n")); + "address=user@example.org\n" + "trash=Trash\n")); Config config; config.load(path); @@ -905,7 +909,8 @@ void TestConfig::sentQueryIsEmptyWithoutTheKey() Config config; config.load(writeIni(dir, QStringLiteral( "[account.provider-c]\n" - "maildir = provider-c\n"))); + "maildir = provider-c\n" + "trash = Trash\n"))); QCOMPARE(config.accounts().size(), 1); QVERIFY(config.accounts().at(0).sentQuery().isEmpty()); @@ -983,6 +988,27 @@ void TestConfig::aBracketedTrashFolderIsQuoted() QStringLiteral("path:\"provider-a/[Provider]/Cestino/**\"")); } +void TestConfig::anAccountWithoutATrashFolderWarns() +{ + QTemporaryDir dir; + Config config; + config.load(writeIni(dir, QStringLiteral( + "[account.work]\n" + "maildir=work\n"))); + + // The account still loads. A missing trash folder disables Delete, it does + // not invalidate the account: the user can still read mail. + QVERIFY(config.account(QStringLiteral("work")).isValid()); + + // Names the account and the key, so the warning is actionable. A warning + // the user cannot act on teaches them to ignore warnings, which item 83 + // recorded the hard way. + QVERIFY(!config.problems().isEmpty()); + const QString joined = config.warnings().join(QLatin1Char('\n')); + QVERIFY(joined.contains(QStringLiteral("work"))); + QVERIFY(joined.contains(QStringLiteral("trash"))); +} + void TestConfig::sentQueryComposesWithScopedQuery() { // A Sent view under one account must not show another account's sent mail. @@ -1103,9 +1129,11 @@ void TestConfig::theStartupAccountIsReadAndValidated() "\n" "[account.work]\n" "maildir=work\n" + "trash=Trash\n" "\n" "[account.personal]\n" - "maildir=personal\n"))); + "maildir=personal\n" + "trash=Trash\n"))); QCOMPARE(config.startupAccount(), QStringLiteral("work")); QVERIFY(config.problems().isEmpty()); @@ -1130,7 +1158,8 @@ void TestConfig::theStartupAccountIsReadAndValidated() "startup_account=nosuchaccount\n" "\n" "[account.work]\n" - "maildir=work\n"))); + "maildir=work\n" + "trash=Trash\n"))); QVERIFY2(wrong.startupAccount().isEmpty(), "an unknown startup account was passed through rather than " "falling back to All accounts"); @@ -1155,7 +1184,8 @@ void TestConfig::theStartupAccountTakesTheKeyNotTheSyncChannel() "\n" "[account.provider-work.mailbox]\n" "maildir=provider-work.mailbox\n" - "channel=provider-workmailbox\n"))); + "channel=provider-workmailbox\n" + "trash=Trash\n"))); QCOMPARE(config.accounts().size(), 1); QCOMPARE(config.accounts().constFirst().key, @@ -1177,7 +1207,8 @@ void TestConfig::theStartupAccountTakesTheKeyNotTheSyncChannel() "\n" "[account.provider-work.mailbox]\n" "maildir=provider-work.mailbox\n" - "channel=provider-workmailbox\n"))); + "channel=provider-workmailbox\n" + "trash=Trash\n"))); QVERIFY2(byChannel.startupAccount().isEmpty(), "the sync channel was accepted as an account key"); @@ -1261,7 +1292,8 @@ void TestConfig::theStartupQuerySurvivesATranslatedFilterName() "\n" "[account.work]\n" "maildir=work\n" - "sent=Sent\n"))); + "sent=Sent\n" + "trash=Trash\n"))); QVERIFY2(!config.savedQueries().isEmpty(), "queries.json did not load, so the warning path is unreachable"); @@ -1286,7 +1318,8 @@ void TestConfig::theStartupQuerySurvivesATranslatedFilterName() "\n" "[account.work]\n" "maildir=work\n" - "sent=Sent\n"))); + "sent=Sent\n" + "trash=Trash\n"))); QVERIFY(!byLabel.savedQueries().isEmpty()); QCOMPARE(byLabel.startupSavedQuery().generated, QStringLiteral("inbox")); QVERIFY(byLabel.problems().isEmpty()); @@ -1513,7 +1546,8 @@ void TestConfig::draftsQueryIsEmptyWithoutTheKey() Config config; config.load(writeIni(dir, QStringLiteral( "[account.provider-c]\n" - "maildir = provider-c\n"))); + "maildir = provider-c\n" + "trash = Trash\n"))); QCOMPARE(config.accounts().size(), 1); QVERIFY(config.accounts().at(0).draftsQuery().isEmpty()); diff --git a/translations/qtmaildir_it_IT.ts b/translations/qtmaildir_it_IT.ts index 036ce4b..fd51547 100644 --- a/translations/qtmaildir_it_IT.ts +++ b/translations/qtmaildir_it_IT.ts @@ -44,6 +44,10 @@ <translation>[completion] extra_mimetypes: la voce '%1' non ha un mimetype; verrà ignorata.</translation> </message> <message> + <source>Account '%1' has no trash folder configured; add a 'trash' key to its section. Delete will not work for this account until it does.</source> + <translation>L'account '%1' non ha un cestino configurato; aggiungere una chiave 'trash' alla sua sezione. L'eliminazione non funzionerà per questo account finché non verrà fatto.</translation> + </message> + <message> <source>Startup account '%1' is not a configured account; starting on all accounts.</source> <translation>L'account iniziale '%1' non è un account configurato; si parte da tutti gli account.</translation> </message> @@ -280,7 +284,7 @@ </message> <message> <source>Add or remove the important tag</source> - <translation>Aggiunge o rimuove l'etichetta importante</translation> + <translation>Aggiunge o rimuove l'etichetta importante</translation> </message> <message> <source>Unmark important</source> @@ -340,7 +344,7 @@ </message> <message> <source>Add or remove the deleted tag on whole threads</source> - <translation>Aggiunge o rimuove l'etichetta eliminato su intere conversazioni</translation> + <translation>Aggiunge o rimuove l'etichetta eliminato su intere conversazioni</translation> </message> <message> <source>Undelete thread</source> @@ -364,7 +368,7 @@ </message> <message> <source>Toggle the unread tag on whole threads</source> - <translation>Inverte l'etichetta non letto su intere conversazioni</translation> + <translation>Inverte l'etichetta non letto su intere conversazioni</translation> </message> <message> <source>Mark thread read</source> |
