presentation/QuickRulesBackend.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // State, discovery, sessions, scripts, history and the settings test of | ||
| 2 | // QuickRulesBackend. Editing lives in QuickRuleEdits.cpp. | ||
| 3 | #include "QuickRulesBackend.h" | ||
| 4 | |||
| 5 | #include "RuleMatcher.h" | ||
| 6 | #include "RuleSentence.h" | ||
| 7 | #include "data/CredentialStore.h" | ||
| 8 | |||
| 9 | #include <QDir> | ||
| 10 | #include <QFile> | ||
| 11 | #include <QJsonArray> | ||
| 12 | #include <QQuickTextDocument> | ||
| 13 | #include <QJsonDocument> | ||
| 14 | #include <QJsonObject> | ||
| 15 | #include <QLocale> | ||
| 16 | #include <QLoggingCategory> | ||
| 17 | #include <QTimer> | ||
| 18 | #include <QUuid> | ||
| 19 | |||
| 20 |
4/7✓ Branch 2 → 3 taken 9 times.
✓ Branch 2 → 8 taken 208 times.
✓ Branch 4 → 5 taken 9 times.
✗ Branch 4 → 8 not taken.
✓ Branch 5 → 6 taken 9 times.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 12 not taken.
|
217 | Q_LOGGING_CATEGORY(lcRulesBackend, "mailjd.sieve.ui") |
| 21 | |||
| 22 | namespace { | ||
| 23 | constexpr qint64 kDiscoveryMaxAgeSeconds = 7 * 24 * 3600; | ||
| 24 | constexpr int kDiscoveryDelayMs = 10000; | ||
| 25 | } // namespace | ||
| 26 | |||
| 27 | 864 | QuickRulesBackend::QuickRulesBackend(Deps deps, QObject *parent) | |
| 28 |
4/4✓ Branch 5 → 6 taken 864 times.
✓ Branch 6 → 7 taken 864 times.
✓ Branch 7 → 8 taken 864 times.
✓ Branch 24 → 25 taken 864 times.
|
1728 | : QObject(parent), m_deps(std::move(deps)) { |
| 29 | 864 | m_discoverer.setCaCertificates(m_deps.trustedCertificates); | |
| 30 |
1/1✓ Branch 30 → 31 taken 864 times.
|
864 | m_discoveryDelay.setSingleShot(true); |
| 31 |
1/1✓ Branch 31 → 32 taken 864 times.
|
864 | m_discoveryDelay.setInterval(kDiscoveryDelayMs); |
| 32 |
1/1✓ Branch 32 → 33 taken 864 times.
|
864 | connect(&m_discoveryDelay, &QTimer::timeout, this, [this] { |
| 33 | 1 | readDiscoveryCache(); | |
| 34 |
1/2✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 1 time.
|
1 | if (m_discovery.checkedAt.isValid()) |
| 35 | ✗ | applyDiscovery(m_discovery); | |
| 36 | else | ||
| 37 | 1 | startDiscovery(); | |
| 38 | 1 | }); | |
| 39 | // F95-14: the mail-list rule markers follow the rules and their state. | ||
| 40 |
1/1✓ Branch 34 → 35 taken 864 times.
|
864 | connect(this, &QuickRulesBackend::documentChanged, this, &QuickRulesBackend::invalidateMatches); |
| 41 |
1/1✓ Branch 36 → 37 taken 864 times.
|
864 | connect(this, &QuickRulesBackend::stateChanged, this, &QuickRulesBackend::invalidateMatches); |
| 42 | 864 | } | |
| 43 | |||
| 44 | 931 | QuickRulesBackend::~QuickRulesBackend() = default; | |
| 45 | |||
| 46 | // --- state ------------------------------------------------------------------------ | ||
| 47 | |||
| 48 | 982 | void QuickRulesBackend::setState(const QString &state) { | |
| 49 |
2/2✓ Branch 3 → 4 taken 791 times.
✓ Branch 3 → 5 taken 191 times.
|
982 | if (m_state == state) |
| 50 | 791 | return; | |
| 51 | 191 | m_state = state; | |
| 52 |
6/6✓ Branch 6 → 7 taken 191 times.
✓ Branch 10 → 11 taken 191 times.
✓ Branch 11 → 12 taken 191 times.
✓ Branch 12 → 13 taken 191 times.
✓ Branch 16 → 8 taken 191 times.
✓ Branch 16 → 17 taken 191 times.
|
382 | qCInfo(lcRulesBackend) << "Rule server state" << state; |
| 53 | 191 | emit stateChanged(); | |
| 54 | } | ||
| 55 | |||
| 56 | 14429 | QString QuickRulesBackend::accountId() const { | |
| 57 |
2/3✓ Branch 3 → 4 taken 14429 times.
✗ Branch 3 → 5 not taken.
✓ Branch 4 → 6 taken 14429 times.
|
14429 | const auto account = m_deps.account ? m_deps.account() : std::nullopt; |
| 58 |
2/2✓ Branch 7 → 8 taken 14413 times.
✓ Branch 7 → 10 taken 16 times.
|
28858 | return account ? account->id : QString(); |
| 59 | 14429 | } | |
| 60 | |||
| 61 | 375 | QString QuickRulesBackend::storageDirectory(const QString &id) const { | |
| 62 |
3/3✓ Branch 2 → 3 taken 375 times.
✓ Branch 6 → 7 taken 375 times.
✓ Branch 7 → 8 taken 375 times.
|
750 | return QDir(m_deps.profileDirectory).filePath(QStringLiteral("sieve/") + id); |
| 63 | } | ||
| 64 | |||
| 65 | 2 | QString QuickRulesBackend::serverSummary() const { | |
| 66 |
1/2✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 2 times.
|
2 | if (m_discovery.server.host.isEmpty()) |
| 67 | ✗ | return {}; | |
| 68 |
2/2✓ Branch 9 → 10 taken 2 times.
✓ Branch 11 → 12 taken 2 times.
|
6 | QString text = QStringLiteral("%1:%2").arg(m_discovery.server.host).arg(m_discovery.server.port); |
| 69 |
1/2✓ Branch 16 → 17 taken 2 times.
✗ Branch 16 → 26 not taken.
|
2 | if (!m_discovery.implementation.isEmpty()) |
| 70 |
2/2✓ Branch 20 → 21 taken 2 times.
✓ Branch 21 → 22 taken 2 times.
|
4 | text += QStringLiteral(" · ") + m_discovery.implementation; |
| 71 | 2 | return text; | |
| 72 | 2 | } | |
| 73 | |||
| 74 |
1/1✓ Branch 2 → 3 taken 14282 times.
|
14282 | SieveSession *QuickRulesBackend::session() const { return m_sessions.value(accountId()); } |
| 75 | |||
| 76 | 3482 | QString QuickRulesBackend::sessionStatus() const { | |
| 77 | 3482 | const SieveSession *s = session(); | |
| 78 |
2/2✓ Branch 3 → 4 taken 1217 times.
✓ Branch 3 → 9 taken 2265 times.
|
3482 | if (!s) |
| 79 | 1217 | return QStringLiteral("idle"); | |
| 80 |
5/7✗ Branch 10 → 11 not taken.
✓ Branch 10 → 16 taken 1981 times.
✓ Branch 10 → 21 taken 242 times.
✓ Branch 10 → 26 taken 36 times.
✓ Branch 10 → 31 taken 3 times.
✓ Branch 10 → 36 taken 3 times.
✗ Branch 10 → 41 not taken.
|
2265 | switch (s->status()) { |
| 81 | ✗ | case SieveSession::Status::Idle: return QStringLiteral("idle"); | |
| 82 | 3962 | case SieveSession::Status::Loading: return QStringLiteral("loading"); | |
| 83 | 484 | case SieveSession::Status::Ready: return QStringLiteral("ready"); | |
| 84 | 72 | case SieveSession::Status::Saving: return QStringLiteral("saving"); | |
| 85 | 6 | case SieveSession::Status::Offline: return QStringLiteral("offline"); | |
| 86 | 6 | case SieveSession::Status::Error: return QStringLiteral("error"); | |
| 87 | } | ||
| 88 | ✗ | return QStringLiteral("idle"); | |
| 89 | } | ||
| 90 | |||
| 91 | 70 | QString QuickRulesBackend::statusLine() const { | |
| 92 |
1/1✓ Branch 2 → 3 taken 70 times.
|
70 | const SieveSession *s = session(); |
| 93 |
2/2✓ Branch 3 → 4 taken 10 times.
✓ Branch 3 → 9 taken 60 times.
|
70 | if (!s) |
| 94 |
1/3✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 10 times.
✗ Branch 6 → 8 not taken.
|
10 | return available() ? tr("Rules are not loaded yet.") : QString(); |
| 95 |
1/1✓ Branch 9 → 10 taken 60 times.
|
60 | const QLocale locale; |
| 96 |
4/4✓ Branch 11 → 12 taken 8 times.
✓ Branch 11 → 14 taken 1 time.
✓ Branch 11 → 26 taken 1 time.
✓ Branch 11 → 27 taken 50 times.
|
60 | switch (s->status()) { |
| 97 | 8 | case SieveSession::Status::Loading: | |
| 98 |
1/1✓ Branch 12 → 13 taken 8 times.
|
8 | return tr("Loading rules…"); |
| 99 | 1 | case SieveSession::Status::Offline: | |
| 100 |
1/1✓ Branch 14 → 15 taken 1 time.
|
2 | return tr("Offline — showing the rules as of %1") |
| 101 |
3/3✓ Branch 17 → 18 taken 1 time.
✓ Branch 18 → 19 taken 1 time.
✓ Branch 19 → 20 taken 1 time.
|
1 | .arg(locale.toString(s->loadedAt().toLocalTime(), QLocale::ShortFormat)); |
| 102 | 1 | case SieveSession::Status::Error: | |
| 103 | 1 | return m_errorText; | |
| 104 | 50 | default: | |
| 105 | 50 | break; | |
| 106 | } | ||
| 107 |
2/2✓ Branch 31 → 32 taken 1 time.
✓ Branch 31 → 40 taken 49 times.
|
50 | if (s->activeScript().isEmpty()) |
| 108 |
3/3✓ Branch 32 → 33 taken 1 time.
✓ Branch 34 → 35 taken 1 time.
✓ Branch 35 → 36 taken 1 time.
|
2 | return tr("No active script yet — the first rule creates „%1“.").arg(SieveSession::newScriptName()); |
| 109 |
3/3✓ Branch 40 → 41 taken 49 times.
✓ Branch 41 → 42 taken 49 times.
✓ Branch 44 → 45 taken 49 times.
|
147 | QString line = tr("Active script „%1“ · rules: %n", nullptr, ruleCount()).arg(s->activeScript()); |
| 110 |
3/3✓ Branch 48 → 49 taken 49 times.
✓ Branch 50 → 51 taken 23 times.
✓ Branch 50 → 72 taken 26 times.
|
49 | if (s->savedAt().isValid()) |
| 111 | 46 | line += QStringLiteral(" · ") + | |
| 112 |
7/7✓ Branch 51 → 52 taken 23 times.
✓ Branch 54 → 55 taken 23 times.
✓ Branch 55 → 56 taken 23 times.
✓ Branch 56 → 57 taken 23 times.
✓ Branch 57 → 58 taken 23 times.
✓ Branch 61 → 62 taken 23 times.
✓ Branch 62 → 63 taken 23 times.
|
92 | tr("saved at %1").arg(locale.toString(s->savedAt().toLocalTime().time(), QLocale::ShortFormat)); |
| 113 | 49 | return line; | |
| 114 | 60 | } | |
| 115 | |||
| 116 | 331 | bool QuickRulesBackend::readOnly() const { | |
| 117 | 331 | const SieveSession *s = session(); | |
| 118 |
6/6✓ Branch 3 → 4 taken 314 times.
✓ Branch 3 → 10 taken 17 times.
✓ Branch 5 → 6 taken 313 times.
✓ Branch 5 → 10 taken 1 time.
✓ Branch 7 → 8 taken 312 times.
✓ Branch 7 → 10 taken 1 time.
|
643 | return !s || s->status() == SieveSession::Status::Offline || s->status() == SieveSession::Status::Error || |
| 119 |
1/2✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 312 times.
|
643 | s->document().readOnly; |
| 120 | } | ||
| 121 | |||
| 122 | 9 | bool QuickRulesBackend::busy() const { | |
| 123 | 9 | const SieveSession *s = session(); | |
| 124 |
3/4✓ Branch 3 → 4 taken 9 times.
✗ Branch 3 → 7 not taken.
✓ Branch 5 → 6 taken 4 times.
✓ Branch 5 → 7 taken 5 times.
|
9 | return s && s->busy(); |
| 125 | } | ||
| 126 | |||
| 127 | 108 | int QuickRulesBackend::ruleCount() const { | |
| 128 | 108 | const SieveSession *s = session(); | |
| 129 |
1/2✓ Branch 3 → 4 taken 108 times.
✗ Branch 3 → 7 not taken.
|
108 | return s ? s->document().ruleCount() : 0; |
| 130 | } | ||
| 131 | |||
| 132 | 2447 | int QuickRulesBackend::enabledRuleCount() const { | |
| 133 | 2447 | const SieveSession *s = session(); | |
| 134 |
2/2✓ Branch 3 → 4 taken 70 times.
✓ Branch 3 → 7 taken 2377 times.
|
2447 | return s ? s->document().enabledRuleCount() : 0; |
| 135 | } | ||
| 136 | |||
| 137 | 216 | QVariantMap QuickRulesBackend::capabilities() const { | |
| 138 | 216 | const SieveSession *s = session(); | |
| 139 |
5/6✓ Branch 3 → 4 taken 215 times.
✓ Branch 3 → 8 taken 1 time.
✓ Branch 6 → 7 taken 215 times.
✗ Branch 6 → 8 not taken.
✓ Branch 9 → 10 taken 215 times.
✓ Branch 9 → 12 taken 1 time.
|
216 | if (s && !s->capabilities().isEmpty()) |
| 140 | 215 | return s->capabilities().toVariantMap(); | |
| 141 | 2 | return {{QStringLiteral("extensions"), m_discovery.extensions}, | |
| 142 |
2/4✓ Branch 22 → 23 taken 2 times.
✓ Branch 22 → 24 taken 1 time.
✗ Branch 31 → 32 not taken.
✗ Branch 31 → 33 not taken.
|
5 | {QStringLiteral("implementation"), m_discovery.implementation}}; |
| 143 | 3 | } | |
| 144 | |||
| 145 | 908 | void QuickRulesBackend::setManagerOpen(bool open) { | |
| 146 |
2/2✓ Branch 2 → 3 taken 807 times.
✓ Branch 2 → 4 taken 101 times.
|
908 | if (m_managerOpen == open) |
| 147 | 807 | return; | |
| 148 | 101 | m_managerOpen = open; | |
| 149 | 101 | emit managerOpenChanged(); | |
| 150 | } | ||
| 151 | |||
| 152 | 2 | void QuickRulesBackend::setFilterText(const QString &text) { | |
| 153 |
1/2✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 2 times.
|
2 | if (m_filterText == text) |
| 154 | ✗ | return; | |
| 155 | 2 | m_filterText = text; | |
| 156 | 2 | m_model.setFilter(m_filterText, m_folderFilter, m_problemsOnly, m_offOnly); | |
| 157 | 2 | emit filterChanged(); | |
| 158 | } | ||
| 159 | |||
| 160 | 103 | void QuickRulesBackend::setFolderFilter(const QString &folder) { | |
| 161 |
2/2✓ Branch 3 → 4 taken 97 times.
✓ Branch 3 → 5 taken 6 times.
|
103 | if (m_folderFilter == folder) |
| 162 | 97 | return; | |
| 163 | 6 | m_folderFilter = folder; | |
| 164 | 6 | m_model.setFilter(m_filterText, m_folderFilter, m_problemsOnly, m_offOnly); | |
| 165 | 6 | emit filterChanged(); | |
| 166 | } | ||
| 167 | |||
| 168 | 2 | void QuickRulesBackend::setProblemsOnly(bool on) { | |
| 169 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 2 times.
|
2 | if (m_problemsOnly == on) |
| 170 | ✗ | return; | |
| 171 | 2 | m_problemsOnly = on; | |
| 172 | 2 | m_model.setFilter(m_filterText, m_folderFilter, m_problemsOnly, m_offOnly); | |
| 173 | 2 | emit filterChanged(); | |
| 174 | } | ||
| 175 | |||
| 176 | 2 | void QuickRulesBackend::setOffOnly(bool on) { | |
| 177 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 2 times.
|
2 | if (m_offOnly == on) |
| 178 | ✗ | return; | |
| 179 | 2 | m_offOnly = on; | |
| 180 | 2 | m_model.setFilter(m_filterText, m_folderFilter, m_problemsOnly, m_offOnly); | |
| 181 | 2 | emit filterChanged(); | |
| 182 | } | ||
| 183 | |||
| 184 | 17 | void QuickRulesBackend::setTrustedCertificates(const QList<QSslCertificate> &certificates) { | |
| 185 | 17 | m_deps.trustedCertificates = certificates; | |
| 186 | 17 | m_discoverer.setCaCertificates(certificates); | |
| 187 |
1/2✗ Branch 12 → 7 not taken.
✓ Branch 12 → 13 taken 17 times.
|
17 | for (SieveSession *s : std::as_const(m_sessions)) |
| 188 | ✗ | s->client()->setCaCertificates(certificates); | |
| 189 | 17 | } | |
| 190 | |||
| 191 | // --- discovery -------------------------------------------------------------------- | ||
| 192 | |||
| 193 | 40 | void QuickRulesBackend::foldersReady() { | |
| 194 |
1/1✓ Branch 2 → 3 taken 40 times.
|
40 | const QString id = accountId(); |
| 195 |
1/2✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 40 times.
|
40 | if (id.isEmpty()) |
| 196 | ✗ | return; | |
| 197 |
2/2✓ Branch 7 → 8 taken 7 times.
✓ Branch 7 → 10 taken 33 times.
|
40 | if (id == m_discoveredAccount) { |
| 198 |
1/1✓ Branch 8 → 9 taken 7 times.
|
7 | refreshModel(); // folders changed: health findings may change |
| 199 | 7 | return; | |
| 200 | } | ||
| 201 | 33 | m_discoveredAccount = id; | |
| 202 |
1/1✓ Branch 11 → 12 taken 33 times.
|
33 | readDiscoveryCache(); |
| 203 |
3/3✓ Branch 12 → 13 taken 33 times.
✓ Branch 13 → 14 taken 4 times.
✓ Branch 13 → 40 taken 29 times.
|
33 | if (m_discovery.checkedAt.isValid()) { |
| 204 | // Show the node at once from the cached result; connect only later. | ||
| 205 |
1/1✓ Branch 29 → 30 taken 4 times.
|
4 | setState(m_discovery.state == SieveDiscovery::State::Available |
| 206 |
5/10✓ Branch 14 → 15 taken 4 times.
✗ Branch 14 → 22 not taken.
✓ Branch 15 → 16 taken 2 times.
✓ Branch 15 → 19 taken 2 times.
✓ Branch 37 → 38 taken 2 times.
✓ Branch 37 → 39 taken 2 times.
✗ Branch 58 → 59 not taken.
✗ Branch 58 → 60 not taken.
✗ Branch 62 → 63 not taken.
✗ Branch 62 → 64 not taken.
|
16 | ? (m_discovery.needsConfirmation ? QStringLiteral("confirm") : QStringLiteral("available")) |
| 207 |
2/6✗ Branch 22 → 23 not taken.
✗ Branch 22 → 26 not taken.
✓ Branch 35 → 36 taken 2 times.
✓ Branch 35 → 37 taken 2 times.
✗ Branch 54 → 55 not taken.
✗ Branch 54 → 56 not taken.
|
4 | : m_discovery.state == SieveDiscovery::State::Disabled ? QStringLiteral("disabled") |
| 208 |
2/6✗ Branch 31 → 32 not taken.
✓ Branch 31 → 33 taken 4 times.
✗ Branch 33 → 34 not taken.
✓ Branch 33 → 35 taken 4 times.
✗ Branch 50 → 51 not taken.
✗ Branch 50 → 52 not taken.
|
4 | : QStringLiteral("unavailable")); |
| 209 | } | ||
| 210 |
1/1✓ Branch 40 → 41 taken 33 times.
|
33 | m_discoveryDelay.start(); // G16: never during cold start |
| 211 | 40 | } | |
| 212 | |||
| 213 | 795 | void QuickRulesBackend::accountChanged() { | |
| 214 | 795 | m_discoveryDelay.stop(); | |
| 215 | 795 | m_discoveredAccount.clear(); | |
| 216 | 795 | m_discovery = {}; | |
| 217 | 795 | m_undo.clear(); | |
| 218 | 795 | m_conflictMine.clear(); | |
| 219 | 795 | m_conflictBlocks.clear(); | |
| 220 | // S106-317: the previous account's rule-server error (with its host) is | ||
| 221 | // not shown under the new account. | ||
| 222 | 795 | m_errorText.clear(); | |
| 223 | 795 | m_errorDetails.clear(); | |
| 224 | 795 | setManagerOpen(false); | |
| 225 |
1/1✓ Branch 20 → 21 taken 795 times.
|
795 | setState(QStringLiteral("unknown")); |
| 226 | 795 | refreshModel(); | |
| 227 | 795 | emit sessionChanged(); | |
| 228 | 795 | emit undoChanged(); | |
| 229 | 795 | emit conflictChanged(); | |
| 230 | 2385 | } | |
| 231 | |||
| 232 | 11 | void QuickRulesBackend::configurationChanged(const QString &changedId) { | |
| 233 |
3/3✓ Branch 2 → 3 taken 11 times.
✓ Branch 5 → 6 taken 4 times.
✓ Branch 5 → 7 taken 7 times.
|
11 | if (changedId != accountId()) |
| 234 | 4 | return; | |
| 235 |
4/4✓ Branch 7 → 8 taken 7 times.
✓ Branch 8 → 9 taken 7 times.
✓ Branch 12 → 13 taken 7 times.
✓ Branch 13 → 14 taken 7 times.
|
14 | QFile::remove(QDir(storageDirectory(changedId)).filePath(QStringLiteral("discovery.json"))); |
| 236 | 7 | m_discovery = {}; | |
| 237 | 7 | startDiscovery(); | |
| 238 | 14 | } | |
| 239 | |||
| 240 | 99 | void QuickRulesBackend::readDiscoveryCache() { | |
| 241 | 99 | m_discovery = {}; | |
| 242 |
2/3✓ Branch 10 → 11 taken 99 times.
✗ Branch 10 → 12 not taken.
✓ Branch 11 → 13 taken 99 times.
|
99 | const auto account = m_deps.account ? m_deps.account() : std::nullopt; |
| 243 |
1/2✗ Branch 14 → 15 not taken.
✓ Branch 14 → 16 taken 99 times.
|
99 | if (!account) |
| 244 | ✗ | return; | |
| 245 |
4/4✓ Branch 17 → 18 taken 99 times.
✓ Branch 18 → 19 taken 99 times.
✓ Branch 22 → 23 taken 99 times.
✓ Branch 23 → 24 taken 99 times.
|
198 | QFile file(QDir(storageDirectory(account->id)).filePath(QStringLiteral("discovery.json"))); |
| 246 |
3/3✓ Branch 30 → 31 taken 99 times.
✓ Branch 31 → 32 taken 94 times.
✓ Branch 31 → 33 taken 5 times.
|
99 | if (!file.open(QIODevice::ReadOnly)) |
| 247 | 94 | return; | |
| 248 |
3/3✓ Branch 33 → 34 taken 5 times.
✓ Branch 34 → 35 taken 5 times.
✓ Branch 35 → 36 taken 5 times.
|
5 | const QJsonObject o = QJsonDocument::fromJson(file.readAll()).object(); |
| 249 |
3/3✓ Branch 41 → 42 taken 5 times.
✓ Branch 42 → 43 taken 5 times.
✓ Branch 43 → 44 taken 5 times.
|
5 | const QDateTime checked = QDateTime::fromString(o.value(QStringLiteral("checkedAt")).toString(), Qt::ISODate); |
| 250 |
5/16✓ Branch 52 → 53 taken 5 times.
✓ Branch 53 → 54 taken 5 times.
✓ Branch 120 → 121 taken 5 times.
✗ Branch 120 → 122 not taken.
✓ Branch 122 → 123 taken 5 times.
✗ Branch 122 → 124 not taken.
✓ Branch 124 → 125 taken 5 times.
✗ Branch 124 → 126 not taken.
✗ Branch 378 → 379 not taken.
✗ Branch 378 → 380 not taken.
✗ Branch 382 → 383 not taken.
✗ Branch 382 → 384 not taken.
✗ Branch 386 → 387 not taken.
✗ Branch 386 → 388 not taken.
✗ Branch 390 → 391 not taken.
✗ Branch 390 → 392 not taken.
|
15 | const bool sameSetup = o.value(QStringLiteral("imapHost")).toString() == account->imap.host && |
| 251 |
10/18✓ Branch 59 → 60 taken 4 times.
✓ Branch 60 → 61 taken 4 times.
✓ Branch 61 → 62 taken 3 times.
✓ Branch 61 → 70 taken 1 time.
✓ Branch 69 → 70 taken 3 times.
✗ Branch 69 → 87 not taken.
✓ Branch 114 → 115 taken 4 times.
✓ Branch 114 → 116 taken 1 time.
✓ Branch 116 → 117 taken 4 times.
✓ Branch 116 → 118 taken 1 time.
✓ Branch 118 → 119 taken 5 times.
✗ Branch 118 → 120 not taken.
✗ Branch 366 → 367 not taken.
✗ Branch 366 → 368 not taken.
✗ Branch 370 → 371 not taken.
✗ Branch 370 → 372 not taken.
✗ Branch 374 → 375 not taken.
✗ Branch 374 → 376 not taken.
|
12 | (o.value(QStringLiteral("policyVersion")).toInt() < 2 || |
| 252 |
11/20✓ Branch 66 → 67 taken 3 times.
✓ Branch 67 → 68 taken 3 times.
✓ Branch 77 → 78 taken 4 times.
✗ Branch 77 → 87 not taken.
✓ Branch 106 → 107 taken 3 times.
✓ Branch 106 → 108 taken 2 times.
✓ Branch 108 → 109 taken 3 times.
✓ Branch 108 → 110 taken 2 times.
✓ Branch 110 → 111 taken 3 times.
✓ Branch 110 → 112 taken 2 times.
✓ Branch 112 → 113 taken 4 times.
✓ Branch 112 → 114 taken 1 time.
✗ Branch 350 → 351 not taken.
✗ Branch 350 → 352 not taken.
✗ Branch 354 → 355 not taken.
✗ Branch 354 → 356 not taken.
✗ Branch 358 → 359 not taken.
✗ Branch 358 → 360 not taken.
✗ Branch 362 → 363 not taken.
✗ Branch 362 → 364 not taken.
|
15 | o.value(QStringLiteral("email")).toString() == account->email) && |
| 253 |
13/22✓ Branch 55 → 56 taken 4 times.
✓ Branch 55 → 87 taken 1 time.
✓ Branch 74 → 75 taken 4 times.
✓ Branch 75 → 76 taken 4 times.
✓ Branch 85 → 86 taken 4 times.
✗ Branch 85 → 87 not taken.
✓ Branch 98 → 99 taken 4 times.
✓ Branch 98 → 100 taken 1 time.
✓ Branch 100 → 101 taken 4 times.
✓ Branch 100 → 102 taken 1 time.
✓ Branch 102 → 103 taken 4 times.
✓ Branch 102 → 104 taken 1 time.
✓ Branch 104 → 105 taken 3 times.
✓ Branch 104 → 106 taken 2 times.
✗ Branch 334 → 335 not taken.
✗ Branch 334 → 336 not taken.
✗ Branch 338 → 339 not taken.
✗ Branch 338 → 340 not taken.
✗ Branch 342 → 343 not taken.
✗ Branch 342 → 344 not taken.
✗ Branch 346 → 347 not taken.
✗ Branch 346 → 348 not taken.
|
27 | o.value(QStringLiteral("mode")).toString() == account->sieve.mode && |
| 254 |
12/20✓ Branch 82 → 83 taken 4 times.
✓ Branch 83 → 84 taken 4 times.
✓ Branch 88 → 89 taken 4 times.
✓ Branch 88 → 90 taken 1 time.
✓ Branch 90 → 91 taken 4 times.
✓ Branch 90 → 92 taken 1 time.
✓ Branch 92 → 93 taken 4 times.
✓ Branch 92 → 94 taken 1 time.
✓ Branch 94 → 95 taken 4 times.
✓ Branch 94 → 96 taken 1 time.
✓ Branch 96 → 97 taken 4 times.
✓ Branch 96 → 98 taken 1 time.
✗ Branch 318 → 319 not taken.
✗ Branch 318 → 320 not taken.
✗ Branch 322 → 323 not taken.
✗ Branch 322 → 324 not taken.
✗ Branch 326 → 327 not taken.
✗ Branch 326 → 328 not taken.
✗ Branch 330 → 331 not taken.
✗ Branch 330 → 332 not taken.
|
13 | o.value(QStringLiteral("manualHost")).toString() == account->sieve.host; |
| 255 |
4/5✓ Branch 126 → 127 taken 5 times.
✓ Branch 127 → 128 taken 5 times.
✗ Branch 127 → 132 not taken.
✓ Branch 128 → 129 taken 4 times.
✓ Branch 128 → 132 taken 1 time.
|
9 | if (!checked.isValid() || !sameSetup || |
| 256 |
7/10✓ Branch 129 → 130 taken 4 times.
✓ Branch 130 → 131 taken 4 times.
✗ Branch 131 → 132 not taken.
✓ Branch 131 → 133 taken 4 times.
✓ Branch 134 → 135 taken 4 times.
✓ Branch 134 → 136 taken 1 time.
✓ Branch 136 → 137 taken 1 time.
✓ Branch 136 → 138 taken 4 times.
✗ Branch 394 → 395 not taken.
✗ Branch 394 → 396 not taken.
|
9 | checked.secsTo(QDateTime::currentDateTimeUtc()) > kDiscoveryMaxAgeSeconds) |
| 257 | 1 | return; | |
| 258 | 4 | m_discovery.checkedAt = checked; | |
| 259 |
2/2✓ Branch 142 → 143 taken 4 times.
✓ Branch 143 → 144 taken 4 times.
|
4 | const QString state = o.value(QStringLiteral("state")).toString(); |
| 260 |
1/2✓ Branch 149 → 150 taken 4 times.
✗ Branch 149 → 151 not taken.
|
4 | m_discovery.state = state == QLatin1String("available") ? SieveDiscovery::State::Available |
| 261 |
0/2✗ Branch 153 → 154 not taken.
✗ Branch 153 → 155 not taken.
|
4 | : state == QLatin1String("disabled") ? SieveDiscovery::State::Disabled |
| 262 | : SieveDiscovery::State::NotAvailable; | ||
| 263 |
2/2✓ Branch 160 → 161 taken 4 times.
✓ Branch 161 → 162 taken 4 times.
|
4 | m_discovery.server.host = o.value(QStringLiteral("host")).toString(); |
| 264 |
2/2✓ Branch 170 → 171 taken 4 times.
✓ Branch 171 → 172 taken 4 times.
|
4 | m_discovery.server.port = static_cast<quint16>(o.value(QStringLiteral("port")).toInt(4190)); |
| 265 |
2/2✓ Branch 178 → 179 taken 4 times.
✓ Branch 182 → 183 taken 4 times.
|
8 | m_discovery.server.security = o.value(QStringLiteral("security")).toString(QStringLiteral("starttls")); |
| 266 |
2/2✓ Branch 193 → 194 taken 4 times.
✓ Branch 194 → 195 taken 4 times.
|
4 | m_discovery.server.source = o.value(QStringLiteral("source")).toString(); |
| 267 |
2/2✓ Branch 203 → 204 taken 4 times.
✓ Branch 204 → 205 taken 4 times.
|
4 | m_discovery.implementation = o.value(QStringLiteral("implementation")).toString(); |
| 268 |
7/7✓ Branch 213 → 214 taken 4 times.
✓ Branch 214 → 215 taken 4 times.
✓ Branch 218 → 219 taken 4 times.
✓ Branch 219 → 220 taken 4 times.
✓ Branch 222 → 223 taken 6 times.
✓ Branch 229 → 221 taken 6 times.
✓ Branch 229 → 230 taken 4 times.
|
10 | for (const QJsonValue &value : o.value(QStringLiteral("extensions")).toArray()) |
| 269 |
2/2✓ Branch 223 → 224 taken 6 times.
✓ Branch 224 → 225 taken 6 times.
|
10 | m_discovery.extensions.append(value.toString()); |
| 270 | 4 | m_discovery.extensionCount = m_discovery.extensions.size(); | |
| 271 |
6/14✓ Branch 235 → 236 taken 4 times.
✓ Branch 236 → 237 taken 4 times.
✓ Branch 237 → 238 taken 3 times.
✓ Branch 237 → 245 taken 1 time.
✓ Branch 254 → 255 taken 4 times.
✗ Branch 254 → 256 not taken.
✓ Branch 256 → 257 taken 4 times.
✗ Branch 256 → 258 not taken.
✗ Branch 493 → 494 not taken.
✗ Branch 493 → 495 not taken.
✗ Branch 497 → 498 not taken.
✗ Branch 497 → 499 not taken.
✗ Branch 501 → 502 not taken.
✗ Branch 501 → 503 not taken.
|
15 | m_discovery.confirmedByUser = o.value(QStringLiteral("policyVersion")).toInt() == 2 && |
| 272 |
11/18✓ Branch 241 → 242 taken 3 times.
✓ Branch 242 → 243 taken 3 times.
✓ Branch 243 → 244 taken 1 time.
✓ Branch 243 → 245 taken 2 times.
✓ Branch 246 → 247 taken 3 times.
✓ Branch 246 → 248 taken 1 time.
✓ Branch 248 → 249 taken 3 times.
✓ Branch 248 → 250 taken 1 time.
✓ Branch 250 → 251 taken 3 times.
✓ Branch 250 → 252 taken 1 time.
✓ Branch 252 → 253 taken 4 times.
✗ Branch 252 → 254 not taken.
✗ Branch 481 → 482 not taken.
✗ Branch 481 → 483 not taken.
✗ Branch 485 → 486 not taken.
✗ Branch 485 → 487 not taken.
✗ Branch 489 → 490 not taken.
✗ Branch 489 → 491 not taken.
|
7 | o.value(QStringLiteral("confirmedByUser")).toBool(); |
| 273 |
3/3✓ Branch 259 → 260 taken 4 times.
✓ Branch 260 → 261 taken 3 times.
✓ Branch 260 → 263 taken 1 time.
|
7 | m_discovery.needsConfirmation = SieveDiscovery::candidateNeedsConfirmation(*account, m_discovery.server) && |
| 274 |
2/2✓ Branch 261 → 262 taken 2 times.
✓ Branch 261 → 263 taken 1 time.
|
3 | !m_discovery.confirmedByUser; |
| 275 | 394 | } | |
| 276 | |||
| 277 | 89 | void QuickRulesBackend::writeDiscoveryCache() { | |
| 278 |
2/3✓ Branch 3 → 4 taken 89 times.
✗ Branch 3 → 5 not taken.
✓ Branch 4 → 6 taken 89 times.
|
89 | const auto account = m_deps.account ? m_deps.account() : std::nullopt; |
| 279 |
1/2✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 89 times.
|
89 | if (!account) |
| 280 | ✗ | return; | |
| 281 |
3/3✓ Branch 10 → 11 taken 89 times.
✓ Branch 12 → 13 taken 89 times.
✓ Branch 13 → 14 taken 89 times.
|
89 | QDir().mkpath(storageDirectory(account->id)); |
| 282 | 78 | const QString state = m_discovery.state == SieveDiscovery::State::Available ? QStringLiteral("available") | |
| 283 |
4/4✓ Branch 21 → 22 taken 1 time.
✓ Branch 21 → 25 taken 10 times.
✓ Branch 32 → 33 taken 78 times.
✓ Branch 32 → 34 taken 11 times.
|
100 | : m_discovery.state == SieveDiscovery::State::Disabled ? QStringLiteral("disabled") |
| 284 |
6/6✓ Branch 17 → 18 taken 78 times.
✓ Branch 17 → 21 taken 11 times.
✓ Branch 28 → 29 taken 10 times.
✓ Branch 28 → 30 taken 79 times.
✓ Branch 30 → 31 taken 1 time.
✓ Branch 30 → 32 taken 88 times.
|
178 | : QStringLiteral("unavailable"); |
| 285 |
1/1✓ Branch 37 → 38 taken 89 times.
|
178 | QJsonObject o{{QStringLiteral("checkedAt"), m_discovery.checkedAt.toString(Qt::ISODate)}, |
| 286 | 178 | {QStringLiteral("policyVersion"), 2}, | |
| 287 | 178 | {QStringLiteral("email"), account->email}, | |
| 288 | 178 | {QStringLiteral("confirmedByUser"), m_discovery.confirmedByUser}, | |
| 289 | 178 | {QStringLiteral("state"), state}, | |
| 290 | 178 | {QStringLiteral("host"), m_discovery.server.host}, | |
| 291 | 178 | {QStringLiteral("port"), m_discovery.server.port}, | |
| 292 | 178 | {QStringLiteral("security"), m_discovery.server.security}, | |
| 293 | 178 | {QStringLiteral("source"), m_discovery.server.source}, | |
| 294 | 178 | {QStringLiteral("implementation"), m_discovery.implementation}, | |
| 295 |
1/1✓ Branch 79 → 80 taken 89 times.
|
178 | {QStringLiteral("extensions"), QJsonArray::fromStringList(m_discovery.extensions)}, |
| 296 | 178 | {QStringLiteral("needsConfirmation"), m_discovery.needsConfirmation}, | |
| 297 | 178 | {QStringLiteral("imapHost"), account->imap.host}, | |
| 298 | 178 | {QStringLiteral("mode"), account->sieve.mode}, | |
| 299 |
2/4✓ Branch 102 → 103 taken 1335 times.
✓ Branch 102 → 104 taken 89 times.
✗ Branch 180 → 181 not taken.
✗ Branch 180 → 182 not taken.
|
1513 | {QStringLiteral("manualHost"), account->sieve.host}}; |
| 300 |
4/4✓ Branch 137 → 138 taken 89 times.
✓ Branch 138 → 139 taken 89 times.
✓ Branch 142 → 143 taken 89 times.
✓ Branch 143 → 144 taken 89 times.
|
178 | QFile file(QDir(storageDirectory(account->id)).filePath(QStringLiteral("discovery.json"))); |
| 301 |
2/3✓ Branch 150 → 151 taken 89 times.
✓ Branch 151 → 152 taken 89 times.
✗ Branch 151 → 160 not taken.
|
89 | if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { |
| 302 |
1/1✓ Branch 153 → 154 taken 89 times.
|
89 | file.setPermissions(QFile::ReadOwner | QFile::WriteOwner); |
| 303 |
3/3✓ Branch 154 → 155 taken 89 times.
✓ Branch 155 → 156 taken 89 times.
✓ Branch 156 → 157 taken 89 times.
|
89 | file.write(QJsonDocument(o).toJson()); |
| 304 | } | ||
| 305 | 1513 | } | |
| 306 | |||
| 307 | 21 | void QuickRulesBackend::rediscover() { | |
| 308 | 21 | m_discovery = {}; | |
| 309 | 21 | startDiscovery(); | |
| 310 | 42 | } | |
| 311 | |||
| 312 | 94 | void QuickRulesBackend::startDiscovery() { | |
| 313 |
1/1✓ Branch 2 → 3 taken 94 times.
|
94 | m_discoveryDelay.stop(); |
| 314 |
2/3✓ Branch 4 → 5 taken 94 times.
✗ Branch 4 → 6 not taken.
✓ Branch 5 → 7 taken 94 times.
|
94 | const auto account = m_deps.account ? m_deps.account() : std::nullopt; |
| 315 |
1/2✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 94 times.
|
94 | if (!account) |
| 316 | ✗ | return; | |
| 317 |
1/1✓ Branch 13 → 14 taken 94 times.
|
94 | setState(QStringLiteral("checking")); |
| 318 | 94 | const QString id = account->id; | |
| 319 |
4/5✓ Branch 19 → 20 taken 94 times.
✓ Branch 21 → 22 taken 94 times.
✗ Branch 21 → 23 not taken.
✓ Branch 22 → 24 taken 94 times.
✓ Branch 25 → 26 taken 94 times.
|
94 | m_discoverer.discover(*account, m_deps.imapCapabilities ? m_deps.imapCapabilities() : QStringList{}, |
| 320 | 188 | [this, id](const SieveDiscovery::Result &result) { | |
| 321 |
2/3✓ Branch 2 → 3 taken 88 times.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 88 times.
|
88 | if (id != accountId()) |
| 322 | ✗ | return; | |
| 323 | 88 | applyDiscovery(result); | |
| 324 | }); | ||
| 325 | 94 | } | |
| 326 | |||
| 327 | 88 | void QuickRulesBackend::applyDiscovery(const SieveDiscovery::Result &result) { | |
| 328 | 88 | m_discovery = result; | |
| 329 | 88 | writeDiscoveryCache(); | |
| 330 |
3/3✓ Branch 4 → 5 taken 77 times.
✓ Branch 4 → 28 taken 1 time.
✓ Branch 4 → 35 taken 10 times.
|
88 | switch (result.state) { |
| 331 | 77 | case SieveDiscovery::State::Available: | |
| 332 |
2/2✓ Branch 5 → 6 taken 1 time.
✓ Branch 5 → 13 taken 76 times.
|
77 | if (result.needsConfirmation) { |
| 333 |
1/1✓ Branch 9 → 10 taken 1 time.
|
1 | setState(QStringLiteral("confirm")); |
| 334 | 1 | return; | |
| 335 | } | ||
| 336 |
1/1✓ Branch 16 → 17 taken 76 times.
|
76 | setState(QStringLiteral("available")); |
| 337 |
5/6✓ Branch 20 → 21 taken 76 times.
✗ Branch 20 → 24 not taken.
✓ Branch 22 → 23 taken 75 times.
✓ Branch 22 → 24 taken 1 time.
✓ Branch 25 → 26 taken 75 times.
✓ Branch 25 → 27 taken 1 time.
|
76 | if (SieveSession *s = ensureSession(); s && s->status() == SieveSession::Status::Idle) |
| 338 | 75 | s->load(); | |
| 339 | 76 | return; | |
| 340 | 1 | case SieveDiscovery::State::Disabled: | |
| 341 |
1/1✓ Branch 31 → 32 taken 1 time.
|
1 | setState(QStringLiteral("disabled")); |
| 342 | 1 | return; | |
| 343 | 10 | default: | |
| 344 |
1/1✓ Branch 38 → 39 taken 10 times.
|
10 | setState(QStringLiteral("unavailable")); |
| 345 | } | ||
| 346 | } | ||
| 347 | |||
| 348 | 2 | void QuickRulesBackend::confirmServer() { | |
| 349 |
2/2✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 4 taken 1 time.
|
2 | if (m_discovery.state != SieveDiscovery::State::Available) |
| 350 | 1 | return; | |
| 351 | 1 | m_discovery.needsConfirmation = false; | |
| 352 | 1 | m_discovery.confirmedByUser = true; | |
| 353 | 1 | writeDiscoveryCache(); | |
| 354 |
1/1✓ Branch 8 → 9 taken 1 time.
|
1 | setState(QStringLiteral("available")); |
| 355 |
1/2✓ Branch 12 → 13 taken 1 time.
✗ Branch 12 → 14 not taken.
|
1 | if (SieveSession *s = ensureSession()) |
| 356 | 1 | s->load(); | |
| 357 | } | ||
| 358 | |||
| 359 | // --- sessions --------------------------------------------------------------------- | ||
| 360 | |||
| 361 | 193 | void QuickRulesBackend::provideCredentials(SieveSession::PasswordCallback done) { | |
| 362 |
2/3✓ Branch 3 → 4 taken 193 times.
✗ Branch 3 → 5 not taken.
✓ Branch 4 → 6 taken 193 times.
|
193 | const auto account = m_deps.account ? m_deps.account() : std::nullopt; |
| 363 |
1/2✗ Branch 7 → 8 not taken.
✓ Branch 7 → 12 taken 193 times.
|
193 | if (!account) { |
| 364 | ✗ | done(false, {}); | |
| 365 | ✗ | return; | |
| 366 | } | ||
| 367 |
1/2✓ Branch 14 → 15 taken 193 times.
✗ Branch 14 → 20 not taken.
|
193 | if (!account->sieve.usesSeparateLogin()) { |
| 368 |
1/1✓ Branch 18 → 19 taken 193 times.
|
193 | done(!account->imap.password.isEmpty(), account->imap.password); |
| 369 | 193 | return; | |
| 370 | } | ||
| 371 | ✗ | auto *store = new CredentialStore(this); | |
| 372 | ✗ | store->readPassword(QStringLiteral("sieve"), account->sieve.credentialId, | |
| 373 | ✗ | [store, done](bool ok, const QByteArray &password) { | |
| 374 | ✗ | store->deleteLater(); | |
| 375 | ✗ | done(ok, password); | |
| 376 | ✗ | }); | |
| 377 | 193 | } | |
| 378 | |||
| 379 | 119 | SieveSession *QuickRulesBackend::ensureSession() { | |
| 380 |
2/3✓ Branch 3 → 4 taken 119 times.
✗ Branch 3 → 5 not taken.
✓ Branch 4 → 6 taken 119 times.
|
119 | const auto account = m_deps.account ? m_deps.account() : std::nullopt; |
| 381 |
7/8✓ Branch 7 → 8 taken 119 times.
✗ Branch 7 → 10 not taken.
✓ Branch 8 → 9 taken 118 times.
✓ Branch 8 → 10 taken 1 time.
✓ Branch 9 → 10 taken 2 times.
✓ Branch 9 → 11 taken 116 times.
✓ Branch 12 → 13 taken 3 times.
✓ Branch 12 → 14 taken 116 times.
|
119 | if (!account || m_discovery.state != SieveDiscovery::State::Available || m_discovery.needsConfirmation) |
| 382 | 3 | return nullptr; | |
| 383 |
1/1✓ Branch 14 → 15 taken 116 times.
|
116 | SieveServerConfig server; |
| 384 | 116 | server.host = m_discovery.server.host; | |
| 385 | 116 | server.port = m_discovery.server.port; | |
| 386 | 116 | server.security = m_discovery.server.security; | |
| 387 |
1/2✗ Branch 19 → 20 not taken.
✓ Branch 19 → 22 taken 116 times.
|
116 | server.username = account->sieve.usesSeparateLogin() ? account->sieve.username : account->imap.username; |
| 388 | 116 | SieveSession *s = m_sessions.value(account->id); | |
| 389 |
2/2✓ Branch 27 → 28 taken 76 times.
✓ Branch 27 → 50 taken 40 times.
|
116 | if (!s) { |
| 390 |
1/1✓ Branch 28 → 29 taken 76 times.
|
76 | SieveSession::Config config; |
| 391 | 76 | config.accountId = account->id; | |
| 392 | 76 | config.server = server; | |
| 393 |
1/1✓ Branch 33 → 34 taken 76 times.
|
76 | config.storageDirectory = storageDirectory(account->id); |
| 394 |
3/6✓ Branch 36 → 37 taken 76 times.
✓ Branch 37 → 38 taken 76 times.
✗ Branch 38 → 39 not taken.
✓ Branch 38 → 40 taken 76 times.
✗ Branch 56 → 57 not taken.
✗ Branch 56 → 58 not taken.
|
76 | s = new SieveSession(config, this); |
| 395 |
1/1✓ Branch 41 → 42 taken 76 times.
|
76 | s->client()->setCaCertificates(m_deps.trustedCertificates); |
| 396 |
1/1✓ Branch 4 → 5 taken 193 times.
|
269 | s->setCredentialProvider([this](SieveSession::PasswordCallback done) { provideCredentials(std::move(done)); }); |
| 397 |
1/1✓ Branch 46 → 47 taken 76 times.
|
76 | m_sessions.insert(account->id, s); |
| 398 |
1/1✓ Branch 47 → 48 taken 76 times.
|
76 | wireSession(s); |
| 399 | 76 | } else { | |
| 400 | 40 | s->setServer(server); | |
| 401 | } | ||
| 402 | 116 | return s; | |
| 403 | 119 | } | |
| 404 | |||
| 405 | 76 | void QuickRulesBackend::wireSession(SieveSession *s) { | |
| 406 |
1/1✓ Branch 2 → 3 taken 76 times.
|
76 | connect(s, &SieveSession::statusChanged, this, [this, s] { |
| 407 |
1/2✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 372 times.
|
372 | if (s != session()) |
| 408 | ✗ | return; | |
| 409 |
6/6✓ Branch 6 → 7 taken 371 times.
✓ Branch 6 → 9 taken 1 time.
✓ Branch 8 → 9 taken 1 time.
✓ Branch 8 → 10 taken 370 times.
✓ Branch 11 → 12 taken 2 times.
✓ Branch 11 → 20 taken 370 times.
|
372 | if (s->status() == SieveSession::Status::Error || s->status() == SieveSession::Status::Offline) { |
| 410 |
1/1✓ Branch 13 → 14 taken 2 times.
|
2 | m_errorText = messageFor(s->lastError(), m_discovery.server.host); |
| 411 | 2 | m_errorDetails = s->statusMessage(); | |
| 412 | } else { | ||
| 413 | 370 | m_errorText.clear(); | |
| 414 | 370 | m_errorDetails.clear(); | |
| 415 | } | ||
| 416 | 372 | emit sessionChanged(); | |
| 417 | }); | ||
| 418 |
1/1✓ Branch 4 → 5 taken 76 times.
|
76 | connect(s, &SieveSession::documentChanged, this, [this, s] { |
| 419 |
1/2✓ Branch 3 → 4 taken 162 times.
✗ Branch 3 → 5 not taken.
|
162 | if (s == session()) |
| 420 | 162 | refreshModel(); | |
| 421 | 162 | }); | |
| 422 |
1/1✓ Branch 6 → 7 taken 76 times.
|
76 | connect(s, &SieveSession::scriptsChanged, this, [this, s] { |
| 423 |
1/2✓ Branch 3 → 4 taken 90 times.
✗ Branch 3 → 5 not taken.
|
90 | if (s == session()) |
| 424 | 90 | emit scriptsChanged(); | |
| 425 | 90 | }); | |
| 426 | 76 | } | |
| 427 | |||
| 428 | 98 | void QuickRulesBackend::openManager(const QString &folder) { | |
| 429 | 98 | setFolderFilter(folder); | |
| 430 | 98 | setManagerOpen(true); | |
| 431 |
2/2✓ Branch 6 → 7 taken 65 times.
✓ Branch 6 → 13 taken 33 times.
|
98 | if (m_state == QLatin1String("unknown")) { |
| 432 | 65 | readDiscoveryCache(); | |
| 433 |
1/2✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 65 times.
|
65 | if (m_discovery.checkedAt.isValid()) |
| 434 | ✗ | applyDiscovery(m_discovery); | |
| 435 | else | ||
| 436 | 65 | startDiscovery(); | |
| 437 | 65 | return; | |
| 438 | } | ||
| 439 |
4/6✓ Branch 14 → 15 taken 30 times.
✓ Branch 14 → 18 taken 3 times.
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 18 taken 30 times.
✗ Branch 19 → 20 not taken.
✓ Branch 19 → 21 taken 33 times.
|
33 | if (SieveSession *s = ensureSession(); s && s->status() == SieveSession::Status::Idle) |
| 440 | ✗ | s->load(); | |
| 441 | } | ||
| 442 | |||
| 443 | 12 | void QuickRulesBackend::openPanel(const QString &panel) { | |
| 444 | 12 | m_pendingPanel = panel; | |
| 445 |
1/1✓ Branch 4 → 5 taken 12 times.
|
12 | openManager(); |
| 446 | 12 | emit panelRequested(panel); | |
| 447 | 12 | } | |
| 448 | |||
| 449 | 9 | void QuickRulesBackend::reload() { | |
| 450 |
1/2✓ Branch 3 → 4 taken 9 times.
✗ Branch 3 → 5 not taken.
|
9 | if (SieveSession *s = ensureSession()) |
| 451 | 9 | s->load(); | |
| 452 | 9 | } | |
| 453 | |||
| 454 | 964 | void QuickRulesBackend::refreshModel() { | |
| 455 |
1/1✓ Branch 2 → 3 taken 964 times.
|
964 | const SieveSession *s = session(); |
| 456 |
2/2✓ Branch 3 → 4 taken 800 times.
✓ Branch 3 → 9 taken 164 times.
|
964 | if (!s) { |
| 457 |
1/1✓ Branch 5 → 6 taken 800 times.
|
800 | m_model.setRows({}); |
| 458 |
1/1✓ Branch 7 → 8 taken 800 times.
|
800 | emit documentChanged(); |
| 459 | 800 | return; | |
| 460 | } | ||
| 461 |
1/1✓ Branch 11 → 12 taken 164 times.
|
164 | QList<QuickRuleModel::Row> rows = QuickRuleModel::rowsFor(s->document(), s->capabilities().sieveExtensions); |
| 462 |
1/1✓ Branch 13 → 14 taken 164 times.
|
164 | const auto findings = healthFindings(s->document()); |
| 463 |
4/4✓ Branch 14 → 15 taken 164 times.
✓ Branch 15 → 16 taken 164 times.
✓ Branch 25 → 17 taken 1167 times.
✓ Branch 25 → 26 taken 164 times.
|
1331 | for (QuickRuleModel::Row &row : rows) { |
| 464 | 1167 | const auto finding = findings.value(row.blockIndex); | |
| 465 | 1167 | row.health = finding.message; | |
| 466 | 1167 | row.healthFix = finding.fix; | |
| 467 | 1167 | row.healthAlternative = finding.alternative; | |
| 468 | 1167 | } | |
| 469 |
1/1✓ Branch 26 → 27 taken 164 times.
|
164 | m_model.setRows(rows); |
| 470 |
1/1✓ Branch 27 → 28 taken 164 times.
|
164 | emit documentChanged(); |
| 471 | 164 | } | |
| 472 | |||
| 473 | 1216 | SieveMailboxDirectory QuickRulesBackend::mailboxDirectory() const { | |
| 474 | 1216 | SieveMailboxDirectory directory; | |
| 475 |
1/2✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 1216 times.
|
1216 | if (!m_deps.folders) |
| 476 | ✗ | return directory; | |
| 477 |
5/5✓ Branch 5 → 6 taken 1216 times.
✓ Branch 6 → 7 taken 1216 times.
✓ Branch 7 → 8 taken 1216 times.
✓ Branch 18 → 9 taken 6566 times.
✓ Branch 18 → 19 taken 1216 times.
|
7782 | for (const FolderInfo &folder : m_deps.folders()) { |
| 478 |
2/3✓ Branch 11 → 12 taken 6566 times.
✗ Branch 11 → 13 not taken.
✓ Branch 12 → 14 taken 6566 times.
|
6566 | const QString decoded = m_deps.decodeMailbox ? m_deps.decodeMailbox(folder.path) : folder.path; |
| 479 |
1/1✓ Branch 14 → 15 taken 6566 times.
|
6566 | directory.addFolder(folder.path, decoded, folder.delimiter, folder.flags); |
| 480 | 7782 | } | |
| 481 | 1216 | return directory; | |
| 482 | ✗ | } | |
| 483 | |||
| 484 | // S95.3.9: missing target folders, reject combined with delivery, rules | ||
| 485 | // that never run, duplicates. | ||
| 486 | 164 | QHash<int, QuickRulesBackend::HealthFinding> QuickRulesBackend::healthFindings(const Sieve::Document &document) const { | |
| 487 | 164 | QHash<int, HealthFinding> findings; | |
| 488 |
1/1✓ Branch 2 → 3 taken 164 times.
|
164 | const SieveMailboxDirectory directory = mailboxDirectory(); |
| 489 | 164 | QList<int> earlier; | |
| 490 | // S106-314: duplicate and "never runs" checks compare rule pairs on the | ||
| 491 | // UI thread; a script of thousands of rules stops them at a pair budget | ||
| 492 | // (the per-rule checks above still run for every rule). | ||
| 493 | 164 | qint64 pairBudget = MaxHealthPairs; | |
| 494 |
2/2✓ Branch 130 → 4 taken 1332 times.
✓ Branch 130 → 131 taken 164 times.
|
1496 | for (int i = 0; i < document.blocks.size(); ++i) { |
| 495 | 1332 | const Sieve::Block &block = document.blocks.at(i); | |
| 496 |
2/2✓ Branch 5 → 6 taken 262 times.
✓ Branch 5 → 7 taken 1070 times.
|
1332 | if (block.kind != Sieve::BlockKind::Rule) |
| 497 | 262 | continue; | |
| 498 | 1070 | const Sieve::Rule &rule = block.rule; | |
| 499 |
7/7✓ Branch 7 → 8 taken 1024 times.
✓ Branch 7 → 11 taken 46 times.
✓ Branch 8 → 9 taken 1024 times.
✓ Branch 9 → 10 taken 2 times.
✓ Branch 9 → 11 taken 1022 times.
✓ Branch 12 → 13 taken 2 times.
✓ Branch 12 → 19 taken 1068 times.
|
1070 | if (rule.enabled && Sieve::rejectConflicts(rule)) |
| 500 | 2 | findings.insert(i, {tr("The server ignores this rule: reject can't be combined with moving or forwarding. " | |
| 501 | "Mail stays in Inbox."), | ||
| 502 | tr("Remove reject"), | ||
| 503 | // Which half was meant is the user's call: keep the | ||
| 504 | // move (first fix) or keep the rejection. | ||
| 505 | tr("Only reject")}); | ||
| 506 |
2/2✓ Branch 56 → 21 taken 1117 times.
✓ Branch 56 → 57 taken 811 times.
|
1928 | for (const Sieve::Action &action : rule.actions) { |
| 507 |
2/2✓ Branch 23 → 24 taken 2 times.
✓ Branch 23 → 25 taken 1115 times.
|
1117 | if (findings.contains(i)) |
| 508 | 259 | break; | |
| 509 |
2/2✓ Branch 27 → 28 taken 1056 times.
✓ Branch 27 → 33 taken 1 time.
|
1057 | if (action.kind != Sieve::Action::Kind::FileInto || !action.specialUse.isEmpty() || |
| 510 |
9/11✓ Branch 25 → 26 taken 1057 times.
✓ Branch 25 → 33 taken 58 times.
✓ Branch 28 → 29 taken 1056 times.
✗ Branch 28 → 33 not taken.
✓ Branch 30 → 31 taken 1056 times.
✗ Branch 30 → 33 not taken.
✓ Branch 31 → 32 taken 1056 times.
✓ Branch 32 → 33 taken 799 times.
✓ Branch 32 → 34 taken 257 times.
✓ Branch 35 → 36 taken 858 times.
✓ Branch 35 → 37 taken 257 times.
|
2172 | action.create || directory.isEmpty() || directory.exists(action.target)) |
| 511 | 858 | continue; | |
| 512 |
1/1✓ Branch 37 → 38 taken 257 times.
|
257 | const QString suggestion = directory.suggestionFor(action.target); |
| 513 | 257 | findings.insert(i, {tr("Folder „%1“ does not exist.").arg(action.target), | |
| 514 |
1/3✓ Branch 44 → 45 taken 114 times.
✗ Branch 150 → 151 not taken.
✗ Branch 150 → 152 not taken.
|
228 | suggestion.isEmpty() ? QString() : tr("Use „%1“").arg(suggestion), QString()}); |
| 515 | 257 | break; | |
| 516 | 257 | } | |
| 517 |
8/8✓ Branch 58 → 59 taken 811 times.
✓ Branch 58 → 62 taken 259 times.
✓ Branch 59 → 60 taken 767 times.
✓ Branch 59 → 62 taken 44 times.
✓ Branch 60 → 61 taken 684 times.
✓ Branch 60 → 62 taken 83 times.
✓ Branch 63 → 64 taken 684 times.
✓ Branch 63 → 126 taken 386 times.
|
1070 | if (!findings.contains(i) && rule.enabled && pairBudget > 0) { |
| 518 | 684 | pairBudget -= earlier.size(); | |
| 519 |
2/2✓ Branch 65 → 66 taken 1 time.
✓ Branch 65 → 81 taken 683 times.
|
684 | if (pairBudget <= 0) |
| 520 |
8/8✓ Branch 66 → 67 taken 1 time.
✓ Branch 70 → 71 taken 1 time.
✓ Branch 71 → 72 taken 1 time.
✓ Branch 72 → 73 taken 1 time.
✓ Branch 73 → 74 taken 1 time.
✓ Branch 75 → 76 taken 1 time.
✓ Branch 79 → 68 taken 1 time.
✓ Branch 79 → 80 taken 1 time.
|
2 | qCInfo(lcRulesBackend) << "Rule health: pair checks stopped at rule" << i << "of" << document.blocks.size(); |
| 521 |
4/4✓ Branch 81 → 82 taken 684 times.
✓ Branch 82 → 83 taken 684 times.
✓ Branch 124 → 84 taken 1092 times.
✓ Branch 124 → 125 taken 296 times.
|
1388 | for (const int j : earlier) { |
| 522 | 1092 | const Sieve::Block &previous = document.blocks.at(j); | |
| 523 |
1/3✓ Branch 86 → 87 taken 1092 times.
✗ Branch 86 → 88 not taken.
✗ Branch 88 → 89 not taken.
|
1092 | const QString name = previous.named ? previous.name : RuleSentence::generatedName(previous.rule); |
| 524 |
7/8✓ Branch 89 → 90 taken 1092 times.
✓ Branch 90 → 91 taken 317 times.
✓ Branch 90 → 94 taken 775 times.
✓ Branch 91 → 92 taken 317 times.
✓ Branch 92 → 93 taken 317 times.
✗ Branch 92 → 94 not taken.
✓ Branch 95 → 96 taken 317 times.
✓ Branch 95 → 104 taken 775 times.
|
1092 | if (previous.rule.conditions == rule.conditions && previous.rule.actions == rule.actions) { |
| 525 | 317 | findings.insert(i, {tr("Same as rule „%1“.").arg(name), tr("Delete this rule"), QString()}); | |
| 526 | 317 | break; | |
| 527 | } | ||
| 528 |
3/3✓ Branch 104 → 105 taken 775 times.
✓ Branch 105 → 106 taken 71 times.
✓ Branch 105 → 117 taken 704 times.
|
775 | if (RuleMatcher::shadows(previous.rule, rule)) { |
| 529 | 71 | findings.insert(i, {tr("Never runs: rule „%1“ above catches the same messages and stops.").arg(name), | |
| 530 | ✗ | tr("Move above „%1“").arg(name), QString()}); | |
| 531 | 71 | break; | |
| 532 | } | ||
| 533 | 1092 | } | |
| 534 | } | ||
| 535 |
2/2✓ Branch 126 → 127 taken 1024 times.
✓ Branch 126 → 128 taken 46 times.
|
1070 | if (rule.enabled) |
| 536 |
1/1✓ Branch 127 → 128 taken 1024 times.
|
1024 | earlier.append(i); |
| 537 | } | ||
| 538 | 164 | return findings; | |
| 539 | 2400 | } | |
| 540 | |||
| 541 | 778 | QStringList QuickRulesBackend::folderChoices() const { | |
| 542 |
2/2✓ Branch 2 → 3 taken 778 times.
✓ Branch 3 → 4 taken 778 times.
|
778 | QStringList names = mailboxDirectory().sieveNames(); |
| 543 |
1/1✓ Branch 5 → 6 taken 778 times.
|
778 | names.sort(Qt::CaseInsensitive); |
| 544 | 778 | return names; | |
| 545 | ✗ | } | |
| 546 | |||
| 547 | 1 | void QuickRulesBackend::openManagerForFolder(const QString &imapPath) { | |
| 548 |
2/2✓ Branch 2 → 3 taken 1 time.
✓ Branch 3 → 4 taken 1 time.
|
1 | const QString name = mailboxDirectory().sieveName(imapPath); |
| 549 |
2/3✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 1 time.
✓ Branch 9 → 10 taken 1 time.
|
1 | openManager(name.isEmpty() ? imapPath : name); |
| 550 | 1 | } | |
| 551 | |||
| 552 | 8 | void QuickRulesBackend::attachHighlighter(QObject *quickTextDocument, const QVariantMap &palette) { | |
| 553 |
1/1✓ Branch 2 → 3 taken 8 times.
|
8 | auto *document = qobject_cast<QQuickTextDocument *>(quickTextDocument); |
| 554 |
4/7✓ Branch 3 → 4 taken 8 times.
✗ Branch 3 → 6 not taken.
✓ Branch 4 → 5 taken 8 times.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 8 times.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 8 times.
|
8 | if (!document || !document->textDocument()) |
| 555 | ✗ | return; | |
| 556 |
2/8✗ Branch 11 → 12 not taken.
✓ Branch 11 → 16 taken 8 times.
✗ Branch 13 → 14 not taken.
✗ Branch 14 → 15 not taken.
✗ Branch 15 → 16 not taken.
✗ Branch 15 → 17 not taken.
✓ Branch 18 → 19 taken 8 times.
✗ Branch 18 → 26 not taken.
|
8 | if (!m_highlighter || m_highlighter->document() != document->textDocument()) |
| 557 |
5/8✓ Branch 19 → 20 taken 8 times.
✓ Branch 20 → 21 taken 8 times.
✓ Branch 21 → 22 taken 8 times.
✓ Branch 22 → 23 taken 8 times.
✗ Branch 23 → 24 not taken.
✓ Branch 23 → 25 taken 8 times.
✗ Branch 90 → 91 not taken.
✗ Branch 90 → 92 not taken.
|
8 | m_highlighter = new SieveSyntaxHighlighter(document->textDocument()); |
| 558 | 8 | SieveSyntaxHighlighter::Colors colors; | |
| 559 |
2/2✓ Branch 30 → 31 taken 8 times.
✓ Branch 31 → 32 taken 8 times.
|
16 | colors.keyword = QColor(palette.value(QStringLiteral("sieveKeyword")).toString()); |
| 560 |
2/2✓ Branch 42 → 43 taken 8 times.
✓ Branch 43 → 44 taken 8 times.
|
16 | colors.string = QColor(palette.value(QStringLiteral("sieveString")).toString()); |
| 561 |
2/2✓ Branch 54 → 55 taken 8 times.
✓ Branch 55 → 56 taken 8 times.
|
16 | colors.comment = QColor(palette.value(QStringLiteral("sieveComment")).toString()); |
| 562 |
2/2✓ Branch 66 → 67 taken 8 times.
✓ Branch 67 → 68 taken 8 times.
|
16 | colors.tag = QColor(palette.value(QStringLiteral("sieveTag")).toString()); |
| 563 |
2/2✓ Branch 78 → 79 taken 8 times.
✓ Branch 79 → 80 taken 8 times.
|
16 | colors.error = QColor(palette.value(QStringLiteral("danger")).toString()); |
| 564 |
1/1✓ Branch 87 → 88 taken 8 times.
|
8 | m_highlighter->setColors(colors); |
| 565 | } | ||
| 566 | |||
| 567 | 2 | void QuickRulesBackend::setHighlightedErrorLine(int line) { | |
| 568 |
1/2✓ Branch 3 → 4 taken 2 times.
✗ Branch 3 → 6 not taken.
|
2 | if (m_highlighter) |
| 569 | 2 | m_highlighter->setErrorLine(line); | |
| 570 | 2 | } | |
| 571 | |||
| 572 | // --- scripts, history ------------------------------------------------------------- | ||
| 573 | |||
| 574 | 2 | QVariantList QuickRulesBackend::scripts() const { | |
| 575 | 2 | QVariantList result; | |
| 576 |
2/3✓ Branch 2 → 3 taken 2 times.
✓ Branch 3 → 4 taken 2 times.
✗ Branch 3 → 34 not taken.
|
2 | if (const SieveSession *s = session()) |
| 577 |
4/4✓ Branch 5 → 6 taken 2 times.
✓ Branch 6 → 7 taken 2 times.
✓ Branch 31 → 8 taken 2 times.
✓ Branch 31 → 32 taken 2 times.
|
4 | for (const ManageSieve::ScriptEntry &entry : s->scripts()) |
| 578 |
3/5✓ Branch 19 → 20 taken 2 times.
✓ Branch 23 → 24 taken 4 times.
✓ Branch 23 → 25 taken 2 times.
✗ Branch 41 → 42 not taken.
✗ Branch 41 → 43 not taken.
|
12 | result.append(QVariantMap{{QStringLiteral("name"), entry.name}, {QStringLiteral("active"), entry.active}}); |
| 579 | 2 | return result; | |
| 580 | 6 | } | |
| 581 | |||
| 582 | 41 | QString QuickRulesBackend::activeScript() const { | |
| 583 | 41 | const SieveSession *s = session(); | |
| 584 |
1/2✓ Branch 3 → 4 taken 41 times.
✗ Branch 3 → 5 not taken.
|
41 | return s ? s->activeScript() : QString(); |
| 585 | } | ||
| 586 | |||
| 587 | 1 | QStringList QuickRulesBackend::inactiveScripts() const { | |
| 588 | 1 | QStringList result; | |
| 589 |
2/3✓ Branch 2 → 3 taken 1 time.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 16 taken 1 time.
|
1 | if (const SieveSession *s = session()) |
| 590 | ✗ | for (const ManageSieve::ScriptEntry &entry : s->scripts()) | |
| 591 | ✗ | if (!entry.active) | |
| 592 | ✗ | result.append(entry.name); | |
| 593 | 1 | return result; | |
| 594 | ✗ | } | |
| 595 | |||
| 596 | 7 | QVariantList QuickRulesBackend::historyEntries() { | |
| 597 | 7 | QVariantList result; | |
| 598 |
1/1✓ Branch 2 → 3 taken 7 times.
|
7 | SieveSession *s = session(); |
| 599 |
2/2✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 5 taken 6 times.
|
7 | if (!s) |
| 600 | 1 | return result; | |
| 601 |
1/1✓ Branch 5 → 6 taken 6 times.
|
6 | const QLocale locale; |
| 602 |
5/5✓ Branch 7 → 8 taken 6 times.
✓ Branch 8 → 9 taken 6 times.
✓ Branch 9 → 10 taken 6 times.
✓ Branch 67 → 11 taken 25 times.
✓ Branch 67 → 68 taken 6 times.
|
31 | for (const SieveHistory::Entry &entry : s->history().entries()) { |
| 603 |
2/2✓ Branch 13 → 14 taken 25 times.
✓ Branch 14 → 15 taken 25 times.
|
25 | const Sieve::Document document = Sieve::decode(s->history().read(entry.id)); |
| 604 |
1/1✓ Branch 44 → 45 taken 25 times.
|
25 | result.append(QVariantMap{ |
| 605 | 50 | {QStringLiteral("id"), entry.id}, | |
| 606 |
2/2✓ Branch 23 → 24 taken 25 times.
✓ Branch 24 → 25 taken 25 times.
|
50 | {QStringLiteral("when"), locale.toString(entry.savedAt.toLocalTime(), QLocale::ShortFormat)}, |
| 607 | 50 | {QStringLiteral("script"), entry.scriptName}, | |
| 608 |
1/1✓ Branch 34 → 35 taken 25 times.
|
75 | {QStringLiteral("size"), locale.formattedDataSize(entry.size)}, |
| 609 |
4/6✓ Branch 39 → 40 taken 25 times.
✓ Branch 40 → 41 taken 25 times.
✓ Branch 48 → 49 taken 125 times.
✓ Branch 48 → 50 taken 25 times.
✗ Branch 80 → 81 not taken.
✗ Branch 80 → 82 not taken.
|
175 | {QStringLiteral("summary"), tr("Rules: %n", nullptr, document.ruleCount())}}); |
| 610 | 31 | } | |
| 611 | 6 | return result; | |
| 612 | 156 | } | |
| 613 | |||
| 614 | // --- plain words ---------------------------------------------------------------------- | ||
| 615 | |||
| 616 | 20 | QString QuickRulesBackend::messageFor(ManageSieveClient::ErrorKind error, const QString &host) { | |
| 617 | using E = ManageSieveClient::ErrorKind; | ||
| 618 |
11/13✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 2 times.
✓ Branch 2 → 5 taken 1 time.
✓ Branch 2 → 10 taken 1 time.
✓ Branch 2 → 11 taken 1 time.
✓ Branch 2 → 12 taken 3 times.
✓ Branch 2 → 13 taken 3 times.
✓ Branch 2 → 14 taken 1 time.
✓ Branch 2 → 15 taken 5 times.
✓ Branch 2 → 16 taken 1 time.
✓ Branch 2 → 17 taken 1 time.
✓ Branch 2 → 18 taken 1 time.
✗ Branch 2 → 19 not taken.
|
20 | switch (error) { |
| 619 | ✗ | case E::None: return {}; | |
| 620 | 2 | case E::Network: | |
| 621 | 2 | case E::Timeout: return tr("The rule server could not be reached."); | |
| 622 |
2/2✓ Branch 5 → 6 taken 1 time.
✓ Branch 7 → 8 taken 1 time.
|
2 | case E::Certificate: return tr("The rule server's certificate is not valid for %1.").arg(host); |
| 623 | 1 | case E::NoStartTls: | |
| 624 | 1 | return tr("The rule server offers no encrypted connection. MailJD does not send the password unencrypted."); | |
| 625 | 1 | case E::NoMechanism: return tr("The rule server offers no supported way to log in."); | |
| 626 | 3 | case E::NoCredentials: return tr("No password is available for the rule server."); | |
| 627 | 3 | case E::AuthFailed: return tr("The rule server did not accept the user name or password."); | |
| 628 | 1 | case E::Referral: return tr("The rule server refers to another server. Enter that server manually."); | |
| 629 | 5 | case E::Bye: return tr("The rule server closed the connection. Try again later."); | |
| 630 | 1 | case E::Server: return tr("The rule server refused the request."); | |
| 631 | 1 | case E::Protocol: return tr("The rule server sent an answer MailJD does not understand."); | |
| 632 | 1 | case E::Cancelled: return tr("The request was cancelled."); | |
| 633 | } | ||
| 634 | ✗ | return {}; | |
| 635 | } | ||
| 636 | |||
| 637 | // --- settings: connection test ----------------------------------------------------- | ||
| 638 | |||
| 639 | 5 | QString QuickRulesBackend::testConnection(const QVariantMap &fields) { | |
| 640 |
1/1✓ Branch 2 → 3 taken 5 times.
|
5 | const QString requestId = nextRequestId(); |
| 641 |
2/2✓ Branch 7 → 8 taken 5 times.
✓ Branch 8 → 9 taken 5 times.
|
10 | const QString id = fields.value(QStringLiteral("id")).toString(); |
| 642 |
2/3✓ Branch 14 → 15 taken 5 times.
✗ Branch 14 → 16 not taken.
✓ Branch 15 → 17 taken 5 times.
|
5 | std::optional<AccountConfig> stored = m_deps.configuration ? m_deps.configuration(id) : std::nullopt; |
| 643 |
2/8✓ Branch 17 → 18 taken 5 times.
✓ Branch 18 → 19 taken 5 times.
✗ Branch 249 → 250 not taken.
✗ Branch 249 → 251 not taken.
✗ Branch 252 → 253 not taken.
✗ Branch 252 → 254 not taken.
✗ Branch 255 → 256 not taken.
✗ Branch 255 → 257 not taken.
|
25 | AccountConfig config = stored.value_or(AccountConfig{}); |
| 644 | 5 | config.id = id; | |
| 645 |
2/2✓ Branch 42 → 43 taken 5 times.
✓ Branch 43 → 44 taken 5 times.
|
10 | config.email = fields.value(QStringLiteral("email"), config.email).toString(); |
| 646 |
3/3✓ Branch 54 → 55 taken 5 times.
✓ Branch 55 → 56 taken 5 times.
✓ Branch 56 → 57 taken 5 times.
|
10 | config.imap.host = fields.value(QStringLiteral("imapHost"), config.imap.host).toString().trimmed(); |
| 647 |
3/3✓ Branch 68 → 69 taken 5 times.
✓ Branch 69 → 70 taken 5 times.
✓ Branch 70 → 71 taken 5 times.
|
10 | config.imap.username = fields.value(QStringLiteral("imapUsername"), config.imap.username).toString().trimmed(); |
| 648 |
3/3✓ Branch 82 → 83 taken 5 times.
✓ Branch 83 → 84 taken 5 times.
✓ Branch 84 → 85 taken 5 times.
|
10 | const QByteArray typedImap = fields.value(QStringLiteral("imapPassword")).toString().toUtf8(); |
| 649 |
2/2✓ Branch 91 → 92 taken 1 time.
✓ Branch 91 → 93 taken 4 times.
|
5 | if (!typedImap.isEmpty()) |
| 650 | 1 | config.imap.password = typedImap; | |
| 651 |
2/2✓ Branch 97 → 98 taken 5 times.
✓ Branch 98 → 99 taken 5 times.
|
10 | config.sieve.mode = fields.value(QStringLiteral("sieveMode"), config.sieve.mode).toString(); |
| 652 |
3/3✓ Branch 109 → 110 taken 5 times.
✓ Branch 110 → 111 taken 5 times.
✓ Branch 111 → 112 taken 5 times.
|
10 | config.sieve.host = fields.value(QStringLiteral("sieveHost"), config.sieve.host).toString().trimmed(); |
| 653 |
2/2✓ Branch 123 → 124 taken 5 times.
✓ Branch 124 → 125 taken 5 times.
|
10 | config.sieve.port = static_cast<quint16>(fields.value(QStringLiteral("sievePort"), config.sieve.port).toInt()); |
| 654 |
2/2✓ Branch 133 → 134 taken 5 times.
✓ Branch 134 → 135 taken 5 times.
|
10 | config.sieve.security = fields.value(QStringLiteral("sieveSecurity"), config.sieve.security).toString(); |
| 655 |
2/2✓ Branch 145 → 146 taken 5 times.
✓ Branch 146 → 147 taken 5 times.
|
10 | config.sieve.login = fields.value(QStringLiteral("sieveLogin"), config.sieve.login).toString(); |
| 656 |
2/2✓ Branch 157 → 158 taken 5 times.
✓ Branch 158 → 159 taken 5 times.
|
10 | config.sieve.username = fields.value(QStringLiteral("sieveUsername"), config.sieve.username).toString(); |
| 657 |
3/3✓ Branch 169 → 170 taken 5 times.
✓ Branch 170 → 171 taken 5 times.
✓ Branch 171 → 172 taken 5 times.
|
10 | const QByteArray typedSieve = fields.value(QStringLiteral("sievePassword")).toString().toUtf8(); |
| 658 | // S106-315: the stored configuration carries no passwords. "Same as | ||
| 659 | // incoming" needs the IMAP password: the active account's own, else the | ||
| 660 | // keyring's — the test used to sign in with an empty one and fail. | ||
| 661 |
5/6✓ Branch 178 → 179 taken 5 times.
✗ Branch 178 → 182 not taken.
✓ Branch 180 → 181 taken 1 time.
✓ Branch 180 → 182 taken 4 times.
✓ Branch 183 → 184 taken 1 time.
✓ Branch 183 → 200 taken 4 times.
|
5 | if (!config.sieve.usesSeparateLogin() && config.imap.password.isEmpty()) { |
| 662 |
6/12✓ Branch 184 → 185 taken 1 time.
✓ Branch 186 → 187 taken 1 time.
✗ Branch 186 → 191 not taken.
✓ Branch 188 → 189 taken 1 time.
✗ Branch 188 → 191 not taken.
✓ Branch 189 → 190 taken 1 time.
✓ Branch 192 → 193 taken 1 time.
✗ Branch 192 → 194 not taken.
✓ Branch 195 → 196 taken 1 time.
✗ Branch 195 → 198 not taken.
✗ Branch 414 → 415 not taken.
✗ Branch 414 → 416 not taken.
|
2 | if (const auto active = id == accountId() && m_deps.account ? m_deps.account() : std::nullopt) |
| 663 | 1 | config.imap.password = active->imap.password; | |
| 664 | } | ||
| 665 |
4/8✓ Branch 201 → 202 taken 5 times.
✗ Branch 201 → 207 not taken.
✓ Branch 203 → 204 taken 5 times.
✗ Branch 203 → 207 not taken.
✗ Branch 205 → 206 not taken.
✓ Branch 205 → 207 taken 5 times.
✗ Branch 208 → 209 not taken.
✓ Branch 208 → 228 taken 5 times.
|
5 | if (stored && !config.sieve.usesSeparateLogin() && config.imap.password.isEmpty()) { |
| 666 | ✗ | auto *store = new CredentialStore(this); | |
| 667 | ✗ | store->readPassword(QStringLiteral("imap"), AccountConfigLoader::imapCredentialName(config), | |
| 668 | ✗ | [this, store, config, typedSieve, requestId](bool ok, const QByteArray &password) mutable { | |
| 669 | ✗ | store->deleteLater(); | |
| 670 | ✗ | if (ok) | |
| 671 | ✗ | config.imap.password = password; | |
| 672 | ✗ | qCInfo(lcRulesBackend) << "Connection test: IMAP password from the keyring:" << ok; | |
| 673 | ✗ | runConnectionTest(config, typedSieve, requestId); | |
| 674 | ✗ | }); | |
| 675 | ✗ | return requestId; | |
| 676 | } | ||
| 677 |
1/1✓ Branch 228 → 229 taken 5 times.
|
5 | runConnectionTest(config, typedSieve, requestId); |
| 678 | 5 | return requestId; | |
| 679 | 5 | } | |
| 680 | |||
| 681 | 5 | void QuickRulesBackend::runConnectionTest(const AccountConfig &config, const QByteArray &typedSieve, | |
| 682 | const QString &requestId) { | ||
| 683 | 5 | const QString id = config.id; | |
| 684 |
3/6✓ Branch 3 → 4 taken 5 times.
✓ Branch 4 → 5 taken 5 times.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 5 times.
✗ Branch 28 → 29 not taken.
✗ Branch 28 → 30 not taken.
|
5 | auto *discovery = new SieveDiscovery(this); |
| 685 | 5 | discovery->setCaCertificates(m_deps.trustedCertificates); | |
| 686 |
3/8✓ Branch 10 → 11 taken 5 times.
✗ Branch 10 → 15 not taken.
✓ Branch 12 → 13 taken 5 times.
✗ Branch 12 → 15 not taken.
✓ Branch 16 → 17 taken 5 times.
✗ Branch 16 → 18 not taken.
✗ Branch 31 → 32 not taken.
✗ Branch 31 → 33 not taken.
|
10 | const QStringList capabilities = id == accountId() && m_deps.imapCapabilities ? m_deps.imapCapabilities() |
| 687 |
2/2✓ Branch 8 → 9 taken 5 times.
✓ Branch 13 → 14 taken 5 times.
|
10 | : QStringList{}; |
| 688 |
2/6✓ Branch 21 → 22 taken 5 times.
✓ Branch 22 → 23 taken 5 times.
✗ Branch 39 → 40 not taken.
✗ Branch 39 → 41 not taken.
✗ Branch 42 → 43 not taken.
✗ Branch 42 → 44 not taken.
|
5 | discovery->discover(config, capabilities, [this, discovery, config, typedSieve, requestId]( |
| 689 | const SieveDiscovery::Result &found) { | ||
| 690 |
1/1✓ Branch 2 → 3 taken 5 times.
|
5 | discovery->deleteLater(); |
| 691 |
1/2✗ Branch 3 → 4 not taken.
✓ Branch 3 → 37 taken 5 times.
|
5 | if (found.state != SieveDiscovery::State::Available) { |
| 692 | ✗ | emit connectionTested(requestId, {{QStringLiteral("ok"), false}, | |
| 693 | ✗ | {QStringLiteral("message"), | |
| 694 | ✗ | found.state == SieveDiscovery::State::Disabled | |
| 695 | ✗ | ? tr("Server rules are turned off for this account.") | |
| 696 | : tr("No rule server was found for this account.")}, | ||
| 697 | ✗ | {QStringLiteral("details"), found.tried.join(QLatin1Char('\n'))}}); | |
| 698 | 1 | return; | |
| 699 | } | ||
| 700 | // S106-087: the SRV/IMAPSIEVE trust model holds here too — a server | ||
| 701 | // outside the IMAP host and mail domain gets no password before the user | ||
| 702 | // confirmed it once in the rules area (SieveDiscovery.h). The test used to | ||
| 703 | // sign in first and report needsConfirmation afterwards. | ||
| 704 |
7/7✓ Branch 37 → 38 taken 2 times.
✓ Branch 37 → 41 taken 3 times.
✓ Branch 38 → 39 taken 2 times.
✓ Branch 39 → 40 taken 1 time.
✓ Branch 39 → 41 taken 1 time.
✓ Branch 42 → 43 taken 1 time.
✓ Branch 42 → 106 taken 4 times.
|
5 | if (found.needsConfirmation && !userConfirmedServer(config.id, found.server)) { |
| 705 |
2/2✓ Branch 47 → 48 taken 1 time.
✓ Branch 49 → 50 taken 1 time.
|
3 | const QString where = QStringLiteral("%1:%2").arg(found.server.host).arg(found.server.port); |
| 706 |
5/5✓ Branch 53 → 54 taken 1 time.
✓ Branch 57 → 58 taken 1 time.
✓ Branch 58 → 59 taken 1 time.
✓ Branch 62 → 55 taken 1 time.
✓ Branch 62 → 63 taken 1 time.
|
2 | qCInfo(lcRulesBackend) << "Connection test stopped before sign-in: unconfirmed rule server"; |
| 707 |
3/5✓ Branch 87 → 88 taken 1 time.
✓ Branch 90 → 91 taken 5 times.
✓ Branch 90 → 92 taken 1 time.
✗ Branch 193 → 194 not taken.
✗ Branch 193 → 195 not taken.
|
8 | emit connectionTested(requestId, {{QStringLiteral("ok"), false}, |
| 708 | 2 | {QStringLiteral("needsConfirmation"), true}, | |
| 709 | 2 | {QStringLiteral("server"), where}, | |
| 710 | 2 | {QStringLiteral("implementation"), found.implementation}, | |
| 711 | 2 | {QStringLiteral("message"), | |
| 712 |
1/1✓ Branch 82 → 83 taken 1 time.
|
1 | tr("The rule server %1 is outside your mail domain. Confirm it under " |
| 713 |
1/1✓ Branch 84 → 85 taken 1 time.
|
2 | "Server rules before MailJD sends your password there.").arg(where)}}); |
| 714 | 1 | return; | |
| 715 | 1 | } | |
| 716 |
3/6✓ Branch 106 → 107 taken 4 times.
✓ Branch 107 → 108 taken 4 times.
✗ Branch 108 → 109 not taken.
✓ Branch 108 → 110 taken 4 times.
✗ Branch 245 → 246 not taken.
✗ Branch 245 → 247 not taken.
|
4 | auto *client = new ManageSieveClient(this); |
| 717 |
1/1✓ Branch 110 → 111 taken 4 times.
|
4 | client->setCaCertificates(m_deps.trustedCertificates); |
| 718 | 8 | SieveServerConfig server{found.server.host, found.server.port, found.server.security, | |
| 719 | 4 | config.sieve.usesSeparateLogin() ? config.sieve.username : config.imap.username, | |
| 720 |
2/4✗ Branch 114 → 115 not taken.
✓ Branch 114 → 116 taken 4 times.
✗ Branch 119 → 120 not taken.
✓ Branch 119 → 121 taken 4 times.
|
4 | config.sieve.usesSeparateLogin() ? typedSieve : config.imap.password}; |
| 721 |
1/1✓ Branch 123 → 124 taken 4 times.
|
4 | client->setServer(server); |
| 722 |
2/4✓ Branch 126 → 127 taken 4 times.
✓ Branch 127 → 128 taken 4 times.
✗ Branch 252 → 253 not taken.
✗ Branch 252 → 254 not taken.
|
4 | client->listScripts([this, client, found, requestId](const ManageSieveClient::Result &result) { |
| 723 |
1/1✓ Branch 2 → 3 taken 4 times.
|
4 | client->deleteLater(); |
| 724 | 4 | QString active; | |
| 725 |
2/2✓ Branch 10 → 5 taken 3 times.
✓ Branch 10 → 11 taken 4 times.
|
7 | for (const ManageSieve::ScriptEntry &entry : result.scripts) |
| 726 |
1/2✓ Branch 6 → 7 taken 3 times.
✗ Branch 6 → 8 not taken.
|
3 | if (entry.active) |
| 727 | 3 | active = entry.name; | |
| 728 |
2/2✓ Branch 15 → 16 taken 4 times.
✓ Branch 17 → 18 taken 4 times.
|
12 | const QString where = QStringLiteral("%1:%2").arg(found.server.host).arg(found.server.port); |
| 729 | 8 | QVariantMap map{{QStringLiteral("ok"), result.ok}, | |
| 730 | 8 | {QStringLiteral("server"), where}, | |
| 731 | 8 | {QStringLiteral("implementation"), found.implementation}, | |
| 732 | 8 | {QStringLiteral("activeScript"), active}, | |
| 733 | 8 | {QStringLiteral("needsConfirmation"), found.needsConfirmation}, | |
| 734 |
2/4✓ Branch 47 → 48 taken 24 times.
✓ Branch 47 → 49 taken 4 times.
✗ Branch 99 → 100 not taken.
✗ Branch 99 → 101 not taken.
|
32 | {QStringLiteral("details"), result.message}}; |
| 735 |
1/1✓ Branch 73 → 74 taken 4 times.
|
8 | map.insert(QStringLiteral("message"), |
| 736 |
3/8✓ Branch 61 → 62 taken 3 times.
✓ Branch 61 → 68 taken 1 time.
✗ Branch 63 → 64 not taken.
✓ Branch 63 → 66 taken 3 times.
✗ Branch 64 → 65 not taken.
✗ Branch 65 → 69 not taken.
✗ Branch 158 → 159 not taken.
✗ Branch 158 → 160 not taken.
|
8 | result.ok ? (active.isEmpty() ? tr("Connected to %1 · %2 · no active script").arg(where, found.implementation) |
| 737 |
4/7✓ Branch 66 → 67 taken 3 times.
✓ Branch 78 → 79 taken 3 times.
✓ Branch 78 → 80 taken 1 time.
✗ Branch 80 → 81 not taken.
✓ Branch 80 → 82 taken 4 times.
✗ Branch 154 → 155 not taken.
✗ Branch 154 → 156 not taken.
|
7 | : tr("Connected to %1 · %2 · active script „%3“") |
| 738 |
1/1✓ Branch 67 → 69 taken 3 times.
|
3 | .arg(where, found.implementation, active)) |
| 739 |
1/1✓ Branch 68 → 69 taken 1 time.
|
1 | : messageFor(result.error, found.server.host)); |
| 740 |
1/1✓ Branch 82 → 83 taken 4 times.
|
4 | emit connectionTested(requestId, map); |
| 741 |
1/5✓ Branch 45 → 46 taken 4 times.
✗ Branch 138 → 139 not taken.
✗ Branch 138 → 142 not taken.
✗ Branch 140 → 141 not taken.
✗ Branch 140 → 142 not taken.
|
32 | }); |
| 742 |
1/10✗ Branch 22 → 23 not taken.
✓ Branch 86 → 87 taken 1 time.
✗ Branch 167 → 168 not taken.
✗ Branch 167 → 171 not taken.
✗ Branch 169 → 170 not taken.
✗ Branch 169 → 171 not taken.
✗ Branch 235 → 236 not taken.
✗ Branch 235 → 239 not taken.
✗ Branch 237 → 238 not taken.
✗ Branch 237 → 239 not taken.
|
12 | }); |
| 743 | 5 | } | |
| 744 | |||
| 745 | 2 | bool QuickRulesBackend::userConfirmedServer(const QString &id, const SieveDiscovery::Candidate &server) const { | |
| 746 |
5/8✓ Branch 5 → 6 taken 1 time.
✓ Branch 5 → 10 taken 1 time.
✓ Branch 7 → 8 taken 1 time.
✗ Branch 7 → 10 not taken.
✓ Branch 13 → 14 taken 1 time.
✓ Branch 13 → 15 taken 1 time.
✗ Branch 98 → 99 not taken.
✗ Branch 98 → 100 not taken.
|
5 | if (id == accountId() && m_discovery.confirmedByUser && |
| 747 |
4/7✓ Branch 2 → 3 taken 2 times.
✓ Branch 4 → 5 taken 2 times.
✗ Branch 4 → 10 not taken.
✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 10 not taken.
✓ Branch 11 → 12 taken 2 times.
✗ Branch 11 → 13 not taken.
|
5 | m_discovery.server.host == server.host && m_discovery.server.port == server.port) |
| 748 | 1 | return true; | |
| 749 | // Another account: its stored discovery decision (policy version 2 only). | ||
| 750 |
4/4✓ Branch 15 → 16 taken 1 time.
✓ Branch 16 → 17 taken 1 time.
✓ Branch 20 → 21 taken 1 time.
✓ Branch 21 → 22 taken 1 time.
|
2 | QFile file(QDir(storageDirectory(id)).filePath(QStringLiteral("discovery.json"))); |
| 751 |
4/7✓ Branch 28 → 29 taken 1 time.
✗ Branch 28 → 32 not taken.
✓ Branch 30 → 31 taken 1 time.
✓ Branch 31 → 32 taken 1 time.
✗ Branch 31 → 33 not taken.
✓ Branch 34 → 35 taken 1 time.
✗ Branch 34 → 36 not taken.
|
1 | if (id.isEmpty() || !file.open(QIODevice::ReadOnly)) |
| 752 | 1 | return false; | |
| 753 | ✗ | const QJsonObject o = QJsonDocument::fromJson(file.readAll()).object(); | |
| 754 | ✗ | return o.value(QStringLiteral("policyVersion")).toInt() == 2 && | |
| 755 | ✗ | o.value(QStringLiteral("confirmedByUser")).toBool() && | |
| 756 | ✗ | o.value(QStringLiteral("host")).toString() == server.host && | |
| 757 | ✗ | o.value(QStringLiteral("port")).toInt() == server.port; | |
| 758 | 1 | } | |
| 759 | |||
| 760 | 139 | QString QuickRulesBackend::nextRequestId() { | |
| 761 |
1/1✓ Branch 6 → 7 taken 139 times.
|
278 | return QStringLiteral("rules-%1").arg(++m_requestCounter); |
| 762 | } | ||
| 763 | |||
| 764 | // --- rule markers of the mail list (F95-14) --------------------------------------- | ||
| 765 | |||
| 766 | 25407 | bool QuickRulesBackend::matchesHeader(const MailHeader &header) { | |
| 767 |
1/1✓ Branch 2 → 3 taken 25407 times.
|
25407 | const auto key = qMakePair(header.folderId, header.uid); |
| 768 |
2/2✓ Branch 6 → 7 taken 20705 times.
✓ Branch 6 → 9 taken 4702 times.
|
25407 | if (const auto cached = m_matchCache.constFind(key); cached != m_matchCache.cend()) |
| 769 | 20705 | return cached.value(); | |
| 770 |
3/3✓ Branch 10 → 12 taken 409 times.
✓ Branch 10 → 14 taken 4293 times.
✓ Branch 12 → 13 taken 409 times.
|
4702 | const SieveSession *s = available() ? session() : nullptr; |
| 771 | // matchingBlocks only reports enabled rules that definitely match. | ||
| 772 |
12/18✓ Branch 15 → 16 taken 409 times.
✓ Branch 15 → 23 taken 4293 times.
✓ Branch 17 → 18 taken 409 times.
✓ Branch 19 → 20 taken 409 times.
✓ Branch 21 → 22 taken 110 times.
✓ Branch 21 → 23 taken 299 times.
✓ Branch 24 → 25 taken 409 times.
✓ Branch 24 → 26 taken 4293 times.
✓ Branch 26 → 27 taken 409 times.
✓ Branch 26 → 28 taken 4293 times.
✓ Branch 28 → 29 taken 409 times.
✓ Branch 28 → 30 taken 4293 times.
✗ Branch 37 → 38 not taken.
✗ Branch 37 → 39 not taken.
✗ Branch 41 → 42 not taken.
✗ Branch 41 → 43 not taken.
✗ Branch 45 → 46 not taken.
✗ Branch 45 → 47 not taken.
|
4702 | const bool matched = s && !RuleMatcher::matchingBlocks(s->document(), messageFor(header, {})).isEmpty(); |
| 773 | // S106-318: one entry per shown row; a long session over many folders | ||
| 774 | // starts the cache again instead of growing it without end. | ||
| 775 |
1/2✗ Branch 31 → 32 not taken.
✓ Branch 31 → 33 taken 4702 times.
|
4702 | if (m_matchCache.size() >= MaxMatchCache) |
| 776 | ✗ | m_matchCache.clear(); | |
| 777 |
1/1✓ Branch 33 → 34 taken 4702 times.
|
4702 | m_matchCache.insert(key, matched); |
| 778 | 4702 | return matched; | |
| 779 | } | ||
| 780 | |||
| 781 | 1155 | void QuickRulesBackend::invalidateMatches() { | |
| 782 | // Without a rule server every row stays "no rule"; state changes of the | ||
| 783 | // discovery (checking → unavailable at start-up) must not refresh every | ||
| 784 | // list row. | ||
| 785 |
4/4✓ Branch 3 → 4 taken 242 times.
✓ Branch 3 → 7 taken 913 times.
✓ Branch 5 → 6 taken 163 times.
✓ Branch 5 → 7 taken 79 times.
|
1155 | const bool possible = available() && session() != nullptr; |
| 786 |
4/4✓ Branch 8 → 9 taken 992 times.
✓ Branch 8 → 11 taken 163 times.
✓ Branch 9 → 10 taken 991 times.
✓ Branch 9 → 11 taken 1 time.
|
1155 | if (!possible && !m_matchesPossible) |
| 787 | 991 | return; | |
| 788 | 164 | m_matchesPossible = possible; | |
| 789 | 164 | m_matchCache.clear(); | |
| 790 | 164 | ++m_matchRevision; | |
| 791 | 164 | emit matchesChanged(); | |
| 792 | } | ||
| 793 |