summaryrefslogtreecommitdiffstats
path: root/src/config.cpp
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-08-20 18:25:31 +0200
committerDanilo M. <danix@danix.xyz>2026-08-20 18:25:31 +0200
commit8fc28de18f903e4bc9d9777589edc819ed9ea996 (patch)
tree4d831ef75a8966c3138fe4634de3a9781f15e758 /src/config.cpp
parent2baf2d4e2c1d8d059a0795bf46596c64c28e01e5 (diff)
downloadqtmaildir-8fc28de18f903e4bc9d9777589edc819ed9ea996.tar.gz
qtmaildir-8fc28de18f903e4bc9d9777589edc819ed9ea996.zip
feat(config): send_command and the [compose] section, item 123
An account's ability to send IS its send_command's presence. Not a separate receive_only key: with one key there is nothing to keep in step and nothing to contradict, and a receive-only account is expressed by omission, which is how one real account here is meant to work. Startup validation follows the startup_query pattern, and is deliberately asymmetric. A default_account that cannot send is warned about, because the user named an account and expects mail to come from it. An installation where NO account can send is not: that is a valid read-only installation, and warning about it would train the user to ignore warnings. Every [compose] key reads through value(key, default) rather than testing contains(), because send_delay_ms = 0 is a real setting meaning 'send at once' that a zero-test would mistake for unset. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015muoUo2GdxmBDSp5vjYcbE
Diffstat (limited to 'src/config.cpp')
-rw-r--r--src/config.cpp83
1 files changed, 83 insertions, 0 deletions
diff --git a/src/config.cpp b/src/config.cpp
index a2d1cec..09869b9 100644
--- a/src/config.cpp
+++ b/src/config.cpp
@@ -23,6 +23,8 @@
// so this reports the same numbers rather than keeping a second copy.
#include "messageview.h"
+#include <algorithm>
+
#include <QDateTime>
#include <QDir>
#include <QFile>
@@ -469,6 +471,12 @@ void Config::load(const QString &path)
account.inbox =
settings.value(QStringLiteral("inbox")).toString().trimmed();
+ // Optional, and its absence IS the receive-only state: see the field
+ // comment in config.h. Run without a shell, so trimming here is only
+ // whitespace hygiene, never a quoting concern.
+ account.sendCommand =
+ settings.value(QStringLiteral("send_command")).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
@@ -516,6 +524,29 @@ void Config::load(const QString &path)
m_accounts.append(account);
}
+ settings.beginGroup(QStringLiteral("compose"));
+ // value(key, default) throughout rather than testing contains(): an
+ // absent key and a key set to its default must behave identically, and
+ // send_delay_ms = 0 is a REAL setting meaning "send at once" that a
+ // zero-test would mistake for unset.
+ m_compose.quotePosition =
+ settings.value(QStringLiteral("quote_position"), QStringLiteral("above"))
+ .toString().compare(QStringLiteral("below"), Qt::CaseInsensitive) == 0
+ ? ComposeSettings::QuotePosition::Below
+ : ComposeSettings::QuotePosition::Above;
+ m_compose.sendHtml =
+ settings.value(QStringLiteral("send_html"), true).toBool();
+ m_compose.autosaveIntervalMs =
+ settings.value(QStringLiteral("autosave_interval_ms"), 30000).toInt();
+ m_compose.sendDelayMs =
+ settings.value(QStringLiteral("send_delay_ms"), 5000).toInt();
+ m_compose.defaultAccount =
+ settings.value(QStringLiteral("default_account")).toString().trimmed();
+ m_compose.attachmentWarnBytes =
+ settings.value(QStringLiteral("attachment_warn_bytes"), qint64(26214400))
+ .toLongLong();
+ settings.endGroup();
+
loadSavedQueries(path, settings);
// Checked here rather than where startup_query is read: the saved queries
@@ -534,6 +565,48 @@ void Config::load(const QString &path)
m_startupAccount.clear();
}
+ // default_account is validated here, once the accounts are parsed. A
+ // named account that cannot send is reported: the user named an account
+ // and expects mail to come from it, unlike an installation where no
+ // account can send at all, which is a valid read-only setup and not
+ // warned about below.
+ if (!m_compose.defaultAccount.isEmpty()) {
+ const auto named = std::find_if(
+ m_accounts.cbegin(), m_accounts.cend(),
+ [this](const Account &a) { return a.key == m_compose.defaultAccount; });
+
+ if (named == m_accounts.cend()) {
+ addProblem(
+ tr("[compose] default_account names '%1', which is not a "
+ "configured account. A new message will pick a sending "
+ "account by the usual rules.")
+ .arg(m_compose.defaultAccount));
+ } else if (!named->canSend()) {
+ addProblem(
+ tr("[compose] default_account names '%1', which has no "
+ "send_command and cannot send. A new message will pick a "
+ "sending account by the usual rules.")
+ .arg(m_compose.defaultAccount));
+ }
+ }
+
+ for (const Account &account : m_accounts) {
+ if (!account.canSend())
+ continue;
+ if (account.sent.isEmpty()) {
+ addProblem(
+ tr("Account '%1' can send but configures no `sent` folder, so "
+ "no local copy of sent mail is filed.")
+ .arg(account.key));
+ }
+ if (account.drafts.isEmpty()) {
+ addProblem(
+ tr("Account '%1' can send but configures no `drafts` folder, "
+ "so the composer runs without draft protection.")
+ .arg(account.key));
+ }
+ }
+
// Asks whether the resolved query matched on EITHER a name or a generator,
// rather than comparing the name alone. Comparing names warned about a
// config that was working: `startup_query = Inbox` resolves through the
@@ -948,6 +1021,16 @@ SavedQuery Config::startupSavedQuery() const
return builtinFilter(QStringLiteral("unread"));
}
+QList<Account> Config::sendingAccounts() const
+{
+ QList<Account> sending;
+ for (const Account &account : m_accounts) {
+ if (account.canSend())
+ sending.append(account);
+ }
+ return sending;
+}
+
Account Config::account(const QString &key) const
{
for (const Account &a : m_accounts) {