summaryrefslogtreecommitdiffstats
path: root/src/config.cpp
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-08-02 17:21:47 +0200
committerDanilo M. <danix@danix.xyz>2026-08-02 17:21:47 +0200
commitb61ce428d81871fbbc6261f274f20785db9d1c38 (patch)
treeb1ebcf1da244a31ec1c991be42d0062d776ba1b4 /src/config.cpp
parentdb1eb37b26f9ac14be4e1a4e5edbf5b6e77f8db7 (diff)
downloadqtmaildir-b61ce428d81871fbbc6261f274f20785db9d1c38.tar.gz
qtmaildir-b61ce428d81871fbbc6261f274f20785db9d1c38.zip
feat: add Config with account, query, and sync parsing
Accounts use [account.work] rather than [account/work]: QSettings' INI backend treats "/" as its own hierarchical group separator, so a literal slash in a section header parses as a nested group and trips QSettings::FormatError, silently breaking childGroups() enumeration. A dot carries no such meaning and keeps the format flat. Saved-query order is alphabetical (QSettings::childKeys() sorts), not file order; documented in code and tests rather than left to a false assumption.
Diffstat (limited to 'src/config.cpp')
-rw-r--r--src/config.cpp89
1 files changed, 89 insertions, 0 deletions
diff --git a/src/config.cpp b/src/config.cpp
new file mode 100644
index 0000000..b12130d
--- /dev/null
+++ b/src/config.cpp
@@ -0,0 +1,89 @@
+#include "config.h"
+
+#include <QFileInfo>
+#include <QSettings>
+#include <QStandardPaths>
+
+QString Account::scopedQuery(const QString &query) const
+{
+ const QString prefix = QStringLiteral("path:\"%1/**\"").arg(maildir);
+ if (query.trimmed().isEmpty())
+ return prefix;
+ return QStringLiteral("%1 and (%2)").arg(prefix, query);
+}
+
+QString Config::defaultPath()
+{
+ const QString base =
+ QStandardPaths::writableLocation(QStandardPaths::ConfigLocation);
+ return base + QStringLiteral("/qtmaildir/qtmaildir.conf");
+}
+
+void Config::load(const QString &path)
+{
+ QSettings settings(path, QSettings::IniFormat);
+
+ m_notmuchConfig =
+ settings.value(QStringLiteral("general/notmuch_config")).toString();
+
+ m_syncCommand = settings.value(QStringLiteral("sync/command")).toString();
+ if (m_syncCommand.isEmpty()) {
+ m_warnings.append(QStringLiteral(
+ "No sync command configured ([sync] command); syncing is disabled."));
+ } else if (!QFileInfo::exists(m_syncCommand.split(QLatin1Char(' ')).first())) {
+ m_warnings.append(
+ QStringLiteral("Sync command '%1' does not exist; syncing is disabled.")
+ .arg(m_syncCommand));
+ m_syncCommand.clear();
+ }
+
+ // Account groups are written as [account.work], [account.personal], etc.
+ // A dot, not a slash, separates the "account" namespace from the key:
+ // QSettings' INI backend treats "/" as its own hierarchical group
+ // separator, so a literal "[account/work]" section header would be
+ // parsed as a *nested* group "work" inside a group "account" (and trips
+ // a QSettings::FormatError besides), not as a single flat group named
+ // "account/work". "." carries no such meaning to QSettings, so
+ // childGroups() here returns "account.work" and "account.personal" as
+ // plain top-level entries and status() stays NoError.
+ for (const QString &group : settings.childGroups()) {
+ if (!group.startsWith(QStringLiteral("account.")))
+ continue;
+
+ Account account;
+ account.key = group.mid(QStringLiteral("account.").size());
+
+ settings.beginGroup(group);
+ account.name = settings.value(QStringLiteral("name")).toString();
+ account.address = settings.value(QStringLiteral("address")).toString();
+ account.maildir = settings.value(QStringLiteral("maildir")).toString();
+ account.drafts = settings.value(QStringLiteral("drafts")).toString();
+ settings.endGroup();
+
+ if (!account.isValid()) {
+ m_warnings.append(
+ QStringLiteral("Account '%1' has no maildir; ignoring it.")
+ .arg(account.key));
+ continue;
+ }
+ m_accounts.append(account);
+ }
+
+ settings.beginGroup(QStringLiteral("queries"));
+ // QSettings::childKeys() returns keys in alphabetical order, not file
+ // order, so the saved-query button order in the UI is alphabetical too.
+ // A hand-rolled parser would be needed to preserve file order; not
+ // needed in v1.
+ for (const QString &name : settings.childKeys())
+ m_savedQueries.append({ name, settings.value(name).toString() });
+ settings.endGroup();
+}
+
+Account Config::account(const QString &key) const
+{
+ for (const Account &a : m_accounts) {
+ if (a.key == key)
+ return a;
+ }
+ return {};
+}