presentation/QuickRulesBackend.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include <QHash> | ||
| 4 | #include <QMap> | ||
| 5 | #include <QObject> | ||
| 6 | #include <QPointer> | ||
| 7 | #include <QTimer> | ||
| 8 | #include <QUrl> | ||
| 9 | #include <QVariantList> | ||
| 10 | #include <QVariantMap> | ||
| 11 | |||
| 12 | #include <functional> | ||
| 13 | #include <optional> | ||
| 14 | #include <utility> | ||
| 15 | |||
| 16 | #include "QuickRuleModel.h" | ||
| 17 | #include "RuleMatcher.h" | ||
| 18 | #include "RuleSuggestions.h" | ||
| 19 | #include "SieveSyntaxHighlighter.h" | ||
| 20 | #include "app/core/SieveSession.h" | ||
| 21 | #include "data/AccountConfig.h" | ||
| 22 | #include "data/Models.h" | ||
| 23 | #include "data/SieveMailboxName.h" | ||
| 24 | #include "data/SieveRuleGuards.h" | ||
| 25 | #include "service/SieveDiscovery.h" | ||
| 26 | |||
| 27 | // QML facade of server rules (Sprint 95, SIEVE-MANAGER/-EDITOR/-SCRIPT/ | ||
| 28 | // -HISTORY/-HEALTH/-VACATION/-SETUP). Exposed as `backend.rules`. | ||
| 29 | // | ||
| 30 | // Owns one SieveSession per account (created lazily), the discovery state | ||
| 31 | // of the active account and the rule list model. Discovery never runs | ||
| 32 | // during cold start (G16): it is armed by foldersReady() and delayed, and | ||
| 33 | // a result younger than 7 days is reused from | ||
| 34 | // <profile>/sieve/<account-id>/discovery.json. | ||
| 35 | // | ||
| 36 | // Every edit — editor, sheet, console, quick actions, health fixes, | ||
| 37 | // restores — becomes new script bytes through SieveRuleCodec and goes | ||
| 38 | // through SieveSession::save (checked, conflict-aware). Quick actions push | ||
| 39 | // the replaced bytes on an undo stack (D-6). User-facing texts are plain | ||
| 40 | // words; technical detail goes to `details` and the log (G13). | ||
| 41 | class QuickRulesBackend final : public QObject { | ||
| 42 | 5904 | Q_OBJECT | |
| 43 | Q_PROPERTY(QString state READ state NOTIFY stateChanged) | ||
| 44 | Q_PROPERTY(bool available READ available NOTIFY stateChanged) | ||
| 45 | Q_PROPERTY(QString serverSummary READ serverSummary NOTIFY stateChanged) | ||
| 46 | Q_PROPERTY(QString confirmHost READ confirmHost NOTIFY stateChanged) | ||
| 47 | Q_PROPERTY(bool managerOpen READ managerOpen WRITE setManagerOpen NOTIFY managerOpenChanged) | ||
| 48 | Q_PROPERTY(int matchRevision READ matchRevision NOTIFY matchesChanged) | ||
| 49 | Q_PROPERTY(QString sessionStatus READ sessionStatus NOTIFY sessionChanged) | ||
| 50 | Q_PROPERTY(QString statusLine READ statusLine NOTIFY sessionChanged) | ||
| 51 | Q_PROPERTY(QString errorText READ errorText NOTIFY sessionChanged) | ||
| 52 | Q_PROPERTY(QString errorDetails READ errorDetails NOTIFY sessionChanged) | ||
| 53 | Q_PROPERTY(bool readOnly READ readOnly NOTIFY sessionChanged) | ||
| 54 | Q_PROPERTY(bool busy READ busy NOTIFY sessionChanged) | ||
| 55 | Q_PROPERTY(QAbstractItemModel *rules READ rules CONSTANT) | ||
| 56 | Q_PROPERTY(int ruleCount READ ruleCount NOTIFY documentChanged) | ||
| 57 | Q_PROPERTY(int enabledRuleCount READ enabledRuleCount NOTIFY documentChanged) | ||
| 58 | Q_PROPERTY(int problemCount READ problemCount NOTIFY documentChanged) | ||
| 59 | Q_PROPERTY(int offCount READ offCount NOTIFY documentChanged) | ||
| 60 | Q_PROPERTY(QStringList targetFolders READ targetFolders NOTIFY documentChanged) | ||
| 61 | Q_PROPERTY(QVariantMap capabilities READ capabilities NOTIFY sessionChanged) | ||
| 62 | Q_PROPERTY(QString filterText READ filterText WRITE setFilterText NOTIFY filterChanged) | ||
| 63 | Q_PROPERTY(QString folderFilter READ folderFilter WRITE setFolderFilter NOTIFY filterChanged) | ||
| 64 | Q_PROPERTY(bool problemsOnly READ problemsOnly WRITE setProblemsOnly NOTIFY filterChanged) | ||
| 65 | Q_PROPERTY(bool offOnly READ offOnly WRITE setOffOnly NOTIFY filterChanged) | ||
| 66 | Q_PROPERTY(bool conflictActive READ conflictActive NOTIFY conflictChanged) | ||
| 67 | Q_PROPERTY(QVariantList conflictBlocks READ conflictBlocks NOTIFY conflictChanged) | ||
| 68 | Q_PROPERTY(bool canUndo READ canUndo NOTIFY undoChanged) | ||
| 69 | Q_PROPERTY(QVariantMap vacation READ vacation NOTIFY documentChanged) | ||
| 70 | Q_PROPERTY(QVariantList scripts READ scripts NOTIFY scriptsChanged) | ||
| 71 | Q_PROPERTY(QString activeScript READ activeScript NOTIFY scriptsChanged) | ||
| 72 | Q_PROPERTY(QStringList inactiveScripts READ inactiveScripts NOTIFY scriptsChanged) | ||
| 73 | |||
| 74 | public: | ||
| 75 | struct Deps { | ||
| 76 | std::function<std::optional<AccountConfig>()> account; // active account, with passwords | ||
| 77 | std::function<std::optional<AccountConfig>(const QString &)> configuration; // any account | ||
| 78 | std::function<QStringList()> imapCapabilities; | ||
| 79 | std::function<QList<FolderInfo>()> folders; | ||
| 80 | std::function<QString(const QString &)> decodeMailbox; // modified UTF-7 → UTF-8 | ||
| 81 | QString profileDirectory; | ||
| 82 | QList<QSslCertificate> trustedCertificates; // tests: fixture CA; empty = system CAs | ||
| 83 | // Mail flow (QuickRuleMailFlow.cpp, Phase 4). | ||
| 84 | struct DisplayedMail { | ||
| 85 | qint64 folderId = -1; | ||
| 86 | qint64 uid = -1; | ||
| 87 | QString folderPath; // raw IMAP path | ||
| 88 | QMap<QString, QString> headers; // lower-case names; empty when unknown | ||
| 89 | QString predictedFolder; // raw IMAP path or empty | ||
| 90 | }; | ||
| 91 | std::function<DisplayedMail()> displayedMail; | ||
| 92 | std::function<QList<MailHeader>(const QString &imapPath)> cachedHeaders; | ||
| 93 | std::function<QMap<QString, QString>(qint64 folderId, qint64 uid)> cachedHeaderFields; | ||
| 94 | std::function<void(const QString &sourcePath, const QList<qint64> &uids, const QString &targetPath)> moveMails; | ||
| 95 | std::function<void(const QString &sourcePath, qint64 uid, const QString &kind, const QString &value)> flagMail; | ||
| 96 | std::function<bool()> suggestionsEnabled; // General → "Suggest a rule after …" (D-12) | ||
| 97 | }; | ||
| 98 | |||
| 99 | explicit QuickRulesBackend(Deps deps, QObject *parent = nullptr); | ||
| 100 | ~QuickRulesBackend() override; | ||
| 101 | |||
| 102 | 2746 | QString state() const { return m_state; } | |
| 103 | 10630 | bool available() const { return m_state == QLatin1String("available"); } | |
| 104 | QString serverSummary() const; | ||
| 105 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 41 times.
|
41 | QString confirmHost() const { return m_discovery.needsConfirmation ? m_discovery.server.host : QString(); } |
| 106 | 1025 | bool managerOpen() const { return m_managerOpen; } | |
| 107 | void setManagerOpen(bool open); | ||
| 108 | QString sessionStatus() const; | ||
| 109 | QString statusLine() const; | ||
| 110 | 65 | QString errorText() const { return m_errorText; } | |
| 111 | 127 | QString errorDetails() const { return m_errorDetails; } | |
| 112 | bool readOnly() const; | ||
| 113 | bool busy() const; | ||
| 114 | 61 | QAbstractItemModel *rules() { return &m_model; } | |
| 115 | int ruleCount() const; | ||
| 116 | int enabledRuleCount() const; | ||
| 117 | 89 | int problemCount() const { return m_model.problemCount(); } | |
| 118 | 44 | int offCount() const { return m_model.offCount(); } | |
| 119 | 263 | QStringList targetFolders() const { return m_model.targets(); } | |
| 120 | QVariantMap capabilities() const; | ||
| 121 | 54 | QString filterText() const { return m_filterText; } | |
| 122 | void setFilterText(const QString &text); | ||
| 123 | 61 | QString folderFilter() const { return m_folderFilter; } | |
| 124 | void setFolderFilter(const QString &folder); | ||
| 125 | 66 | bool problemsOnly() const { return m_problemsOnly; } | |
| 126 | void setProblemsOnly(bool on); | ||
| 127 | 53 | bool offOnly() const { return m_offOnly; } | |
| 128 | void setOffOnly(bool on); | ||
| 129 | 962 | bool conflictActive() const { return !m_conflictMine.isNull(); } | |
| 130 | 1 | QVariantList conflictBlocks() const { return m_conflictBlocks; } | |
| 131 | 2 | bool canUndo() const { return !m_undo.isEmpty(); } | |
| 132 | 1 | qsizetype undoDepth() const { return m_undo.size(); } // tests (S106-320) | |
| 133 | QVariantMap vacation() const; | ||
| 134 | QVariantList scripts() const; | ||
| 135 | QString activeScript() const; | ||
| 136 | QStringList inactiveScripts() const; | ||
| 137 | |||
| 138 | // Lifecycle (called by QuickMailBackend). | ||
| 139 | void foldersReady(); | ||
| 140 | void accountChanged(); | ||
| 141 | void configurationChanged(const QString &accountId); | ||
| 142 | |||
| 143 | // Tests: trust a fixture CA for discovery and sessions (production keeps | ||
| 144 | // the system CAs; Deps::trustedCertificates is empty there). | ||
| 145 | void setTrustedCertificates(const QList<QSslCertificate> &certificates); | ||
| 146 | |||
| 147 | Q_INVOKABLE void openManager(const QString &folder = {}); | ||
| 148 | 15 | Q_INVOKABLE void closeManager() { setManagerOpen(false); } | |
| 149 | // Opens the manager with a panel: "vacation", "script", "scripts", "new". | ||
| 150 | Q_INVOKABLE void openPanel(const QString &panel); | ||
| 151 | // The panel requested before the manager page existed (read once). | ||
| 152 | 21 | Q_INVOKABLE QString takePendingPanel() { return std::exchange(m_pendingPanel, QString()); } | |
| 153 | // Opens the manager with the editor on a prepared draft ("More options…"). | ||
| 154 | 1 | Q_INVOKABLE void openDraft(const QVariantMap &draft) { | |
| 155 | 1 | m_pendingDraft = draft; | |
| 156 |
1/1✓ Branch 6 → 7 taken 1 time.
|
1 | openPanel(QStringLiteral("draft")); |
| 157 | 1 | } | |
| 158 | 2 | Q_INVOKABLE QVariantMap takePendingDraft() { return std::exchange(m_pendingDraft, QVariantMap()); } | |
| 159 | // Opens the manager with the editor on an existing rule. | ||
| 160 | 1 | Q_INVOKABLE void openRule(int blockIndex) { | |
| 161 |
1/1✓ Branch 2 → 3 taken 1 time.
|
1 | m_pendingDraft = draftFor(blockIndex); |
| 162 |
1/1✓ Branch 8 → 9 taken 1 time.
|
1 | openPanel(QStringLiteral("draft")); |
| 163 | 1 | } | |
| 164 | // Removes the out-of-office block (offered after its last day). | ||
| 165 | Q_INVOKABLE QString removeVacation(); | ||
| 166 | Q_INVOKABLE void reload(); | ||
| 167 | Q_INVOKABLE void rediscover(); | ||
| 168 | Q_INVOKABLE void confirmServer(); | ||
| 169 | |||
| 170 | // Editing (QuickRuleEdits.cpp). Results arrive as editFinished(requestId, result). | ||
| 171 | Q_INVOKABLE QVariantMap draftFor(int blockIndex) const; | ||
| 172 | Q_INVOKABLE QVariantMap newDraft() const; | ||
| 173 | Q_INVOKABLE QString draftSentence(const QVariantMap &draft) const; | ||
| 174 | Q_INVOKABLE QString draftSieve(const QVariantMap &draft) const; | ||
| 175 | Q_INVOKABLE QVariantList draftIssues(int blockIndex, const QVariantMap &draft, | ||
| 176 | const QVariantMap &confirmations) const; | ||
| 177 | Q_INVOKABLE QString saveDraft(int blockIndex, const QVariantMap &draft, const QVariantMap &confirmations); | ||
| 178 | Q_INVOKABLE QString setEnabled(int blockIndex, bool enabled); | ||
| 179 | Q_INVOKABLE QString moveRule(int blockIndex, int targetBlockIndex); | ||
| 180 | Q_INVOKABLE QString moveRuleBy(int blockIndex, int delta); | ||
| 181 | Q_INVOKABLE QString deleteRule(int blockIndex); | ||
| 182 | // `alternative` applies the second solution ("Only reject"). | ||
| 183 | Q_INVOKABLE QString applyHealthFix(int blockIndex, bool alternative = false); | ||
| 184 | Q_INVOKABLE QString undo(); | ||
| 185 | Q_INVOKABLE int positionOf(int blockIndex) const; | ||
| 186 | |||
| 187 | // Script editor and scripts panel. | ||
| 188 | Q_INVOKABLE QStringList folderChoices() const; | ||
| 189 | // Installs Sieve highlighting on a TextArea's QQuickTextDocument with the | ||
| 190 | // palette's sieve* colors; call again after a theme change. | ||
| 191 | Q_INVOKABLE void attachHighlighter(QObject *quickTextDocument, const QVariantMap &palette); | ||
| 192 | Q_INVOKABLE void setHighlightedErrorLine(int line); | ||
| 193 | Q_INVOKABLE void openManagerForFolder(const QString &imapPath); | ||
| 194 | Q_INVOKABLE QString scriptText() const; | ||
| 195 | Q_INVOKABLE QString checkScript(const QString &text); | ||
| 196 | // expectedServer: the server version a reviewed merge was made with. | ||
| 197 | Q_INVOKABLE QString saveScript(const QString &text, const QString &expectedServer = {}); | ||
| 198 | Q_INVOKABLE void resolveConflict(const QString &choice); // "mine" | "theirs" | ||
| 199 | // Sprint 107 (S107.3.4, QuickRuleConflict.cpp): the held conflict as | ||
| 200 | // three scripts for the resolver; empty unless conflictActive(). | ||
| 201 | struct ConflictInputs { | ||
| 202 | QByteArray base; // the version the edit started from | ||
| 203 | QByteArray mine; // the upload that met the conflict | ||
| 204 | QByteArray theirs; // the server version it met | ||
| 205 | }; | ||
| 206 | 11 | ConflictInputs conflictInputs() const { return {m_conflictBase, m_conflictMine, m_conflictTheirs}; } | |
| 207 | // Uploads a resolution through the checked pipeline against `theirs` | ||
| 208 | // (D-9: a newer server version yields a new conflict, never an overwrite). | ||
| 209 | // `done(ok, kind, message, errorLines)`: kind is the outcome kind | ||
| 210 | // ("saved", "merged", "conflict", "rejected", …). | ||
| 211 | using ResolveCallback = std::function<void(bool ok, const QString &kind, const QString &message, | ||
| 212 | const QVariantList &errors)>; | ||
| 213 | void resolveWith(const QByteArray &resolved, const QByteArray &theirs, ResolveCallback done); | ||
| 214 | Q_INVOKABLE QString activateScript(const QString &name); | ||
| 215 | Q_INVOKABLE QString renameScript(const QString &from, const QString &to); | ||
| 216 | Q_INVOKABLE QString deleteScript(const QString &name); | ||
| 217 | Q_INVOKABLE QVariantList historyEntries(); | ||
| 218 | // Review before upload (S95.3.10): {identical, wholeScript, summary, | ||
| 219 | // changes: [{kind, name, lines: [{op, text}]}]} against the server version. | ||
| 220 | Q_INVOKABLE QVariantMap reviewScript(const QString &text) const; | ||
| 221 | Q_INVOKABLE QVariantMap reviewVersion(const QString &id); | ||
| 222 | // Script files (Sprint 95 Could): a .sieve file into the script editor | ||
| 223 | // (uploaded only through Save + review) and the editor text to a file. | ||
| 224 | // {ok, text?, message}; at most 1 MiB of valid UTF-8. | ||
| 225 | Q_INVOKABLE QVariantMap readScriptFile(const QUrl &file) const; | ||
| 226 | Q_INVOKABLE QVariantMap writeScriptFile(const QUrl &file, const QString &text) const; | ||
| 227 | Q_INVOKABLE QString restoreVersion(const QString &id); | ||
| 228 | |||
| 229 | // Mail flow (S95.4.1, S95.4.4, S95.4.6, S95.4.9 — QuickRuleMailFlow.cpp). | ||
| 230 | Q_INVOKABLE QVariantMap mailRuleContext(); | ||
| 231 | Q_INVOKABLE QVariantMap searchRuleContext(const QString &query); | ||
| 232 | Q_INVOKABLE QVariantMap evaluateDraft(const QVariantMap &draft, const QString &scopePath); | ||
| 233 | Q_INVOKABLE QString applyToExisting(const QVariantMap &draft, const QString &scopePath); | ||
| 234 | // F100-46: one saved rule applied to the inbox's cached mail now; the | ||
| 235 | // result (also "none") is announced as a toast. | ||
| 236 | Q_INVOKABLE QString applyRuleNow(int blockIndex); | ||
| 237 | Q_INVOKABLE QString addToRule(int blockIndex, const QVariantMap &condition); | ||
| 238 | Q_INVOKABLE QVariantList matchingRulesForMail(); | ||
| 239 | // F95-14: whether an enabled rule matches a mail-list row (definite | ||
| 240 | // matches only: Cc/List-Id are known for rows synced since schema v24). | ||
| 241 | // Cached per mail until the rules change (matchesChanged). | ||
| 242 | bool matchesHeader(const MailHeader &header); | ||
| 243 | 180 | int matchRevision() const { return m_matchRevision; } | |
| 244 | // Console rule mode (S95.4.3). | ||
| 245 | Q_INVOKABLE QVariantMap parseConsoleRule(const QString &text); | ||
| 246 | Q_INVOKABLE QString completeConsoleRule(const QString &text) const; | ||
| 247 | Q_INVOKABLE QVariantMap saveConsoleRule(const QString &text, bool confirmed); | ||
| 248 | Q_INVOKABLE QString consoleSeed(); | ||
| 249 | |||
| 250 | // Suggestions from manual moves (S95.4.5, RuleSuggestions). The mail | ||
| 251 | // backend reports every user move; rule moves are not reported. | ||
| 252 | // Mailing-list mail (List-Id cached since schema v24) counts per list. | ||
| 253 | void recordManualMove(const QString &senderAddress, const QString &listId, const QString &imapPath); | ||
| 254 | Q_INVOKABLE QVariantMap suggestionContext(const QString &key, const QString &imapPath); | ||
| 255 | Q_INVOKABLE void silenceSuggestions(const QString &key); | ||
| 256 | // "Create rule" in the suggestion toast: sender → folder, saved at once | ||
| 257 | // (RJ5, one interaction; the saved toast offers Undo). | ||
| 258 | Q_INVOKABLE QString acceptSuggestion(const QString &key, const QString &imapPath); | ||
| 259 | // Junk rules (S95.5.2): offered after "Mark as junk"; also from the mail | ||
| 260 | // context menu. The rule files the sender's mail into Junk. | ||
| 261 | void offerJunkRule(const QString &sender); | ||
| 262 | Q_INVOKABLE QString acceptJunkRule(const QString &sender); | ||
| 263 | |||
| 264 | // Folders keep their rules (S95.4.7). | ||
| 265 | void folderRenamed(const QString &oldImapPath, const QString &newImapPath); | ||
| 266 | Q_INVOKABLE QStringList rulesUsingFolder(const QString &imapPath) const; | ||
| 267 | Q_INVOKABLE QString disableRulesForFolder(const QString &imapPath); | ||
| 268 | |||
| 269 | // Out of office (S95.5.1). | ||
| 270 | Q_INVOKABLE QString saveVacation(const QVariantMap &draft); | ||
| 271 | Q_INVOKABLE QString setVacationEnabled(bool enabled); | ||
| 272 | |||
| 273 | // Settings section: test with the form's fields (any account). | ||
| 274 | Q_INVOKABLE QString testConnection(const QVariantMap &fields); | ||
| 275 | |||
| 276 | // Plain-words message for a client error (G13), shared with tests. | ||
| 277 | static QString messageFor(ManageSieveClient::ErrorKind error, const QString &host); | ||
| 278 | |||
| 279 | signals: | ||
| 280 | void stateChanged(); | ||
| 281 | void managerOpenChanged(); | ||
| 282 | void sessionChanged(); | ||
| 283 | void documentChanged(); | ||
| 284 | void filterChanged(); | ||
| 285 | void conflictChanged(); | ||
| 286 | void undoChanged(); | ||
| 287 | void scriptsChanged(); | ||
| 288 | void editFinished(const QString &requestId, const QVariantMap &result); | ||
| 289 | void connectionTested(const QString &requestId, const QVariantMap &result); | ||
| 290 | void toast(const QString &message, bool undoable); | ||
| 291 | // F100-68: a rule made from a suggestion toast was saved; `blockIndex` | ||
| 292 | // opens it in the editor (openRule). Undoable like any rule save. | ||
| 293 | void ruleCreated(const QString &message, int blockIndex); | ||
| 294 | void folderRulesRequested(const QString &folder); | ||
| 295 | void panelRequested(const QString &panel); | ||
| 296 | void ruleSuggested(const QString &message, const QString &sender, const QString &imapPath); | ||
| 297 | void junkRuleOffered(const QString &message, const QString &sender); | ||
| 298 | void matchesChanged(); | ||
| 299 | |||
| 300 | private: | ||
| 301 | struct Edit { | ||
| 302 | QByteArray bytes; | ||
| 303 | QString reason; | ||
| 304 | QString successText; | ||
| 305 | bool undoable = false; | ||
| 306 | // Set for rules created from a suggestion: announced with ruleCreated. | ||
| 307 | QString createdRule; | ||
| 308 | int createdBlock = -1; // its index in the submitted document | ||
| 309 | |||
| 310 | }; | ||
| 311 | QString saveRule(int blockIndex, const QVariantMap &draft, const QVariantMap &confirmations, | ||
| 312 | bool announceCreated); | ||
| 313 | |||
| 314 | // QuickRulesBackend.cpp | ||
| 315 | void setState(const QString &state); | ||
| 316 | QString accountId() const; | ||
| 317 | QString storageDirectory(const QString &accountId) const; | ||
| 318 | void readDiscoveryCache(); | ||
| 319 | void writeDiscoveryCache(); | ||
| 320 | void startDiscovery(); | ||
| 321 | void applyDiscovery(const SieveDiscovery::Result &result); | ||
| 322 | SieveSession *ensureSession(); | ||
| 323 | SieveSession *session() const; | ||
| 324 | void wireSession(SieveSession *session); | ||
| 325 | void refreshModel(); | ||
| 326 | SieveMailboxDirectory mailboxDirectory() const; | ||
| 327 | // message, fix label and an optional second fix label per block index | ||
| 328 | struct HealthFinding { QString message; QString fix; QString alternative; }; | ||
| 329 | QHash<int, HealthFinding> healthFindings(const Sieve::Document &document) const; | ||
| 330 | static constexpr qsizetype MaxUndoScripts = 20; | ||
| 331 | void pushUndoScript(const QByteArray &previous); | ||
| 332 | void runConnectionTest(const AccountConfig &config, const QByteArray &typedSieve, const QString &requestId); | ||
| 333 | // S106-314: rule pairs compared per health run (about 300 enabled rules in full). | ||
| 334 | static constexpr qint64 MaxHealthPairs = 50000; | ||
| 335 | void provideCredentials(SieveSession::PasswordCallback done); | ||
| 336 | // QuickRuleMailFlow.cpp | ||
| 337 | QVariantMap reviewMap(const QByteArray &before, const QByteArray &after) const; | ||
| 338 | RuleMatcher::Message messageFor(const MailHeader &header, const QMap<QString, QString> &fields) const; | ||
| 339 | QString sieveNameFor(const QString &imapPath) const; | ||
| 340 | QString imapPathFor(const QString &sieveName) const; | ||
| 341 | // QuickRuleEdits.cpp | ||
| 342 | QString submit(const Edit &edit); | ||
| 343 | QVariantMap outcomeMap(const SieveSession::SaveOutcome &outcome) const; | ||
| 344 | Sieve::GuardContext guardContext(int blockIndex, const QVariantMap &confirmations) const; | ||
| 345 | QString refuseEdit(const QString &message); | ||
| 346 | void finishLater(const QString &requestId, const QVariantMap &result); | ||
| 347 | Sieve::Rule prepareRule(const QVariantMap &draft) const; | ||
| 348 | // S106-087: did the user confirm this (foreign) rule server for account `id`? | ||
| 349 | bool userConfirmedServer(const QString &id, const SieveDiscovery::Candidate &server) const; | ||
| 350 | QString nextRequestId(); | ||
| 351 | |||
| 352 | Deps m_deps; | ||
| 353 | QuickRuleModel m_model; | ||
| 354 | SieveDiscovery m_discoverer; | ||
| 355 | SieveDiscovery::Result m_discovery; | ||
| 356 | QString m_state = QStringLiteral("unknown"); | ||
| 357 | QString m_discoveredAccount; | ||
| 358 | RuleSuggestions m_suggestions; | ||
| 359 | QHash<QString, SieveSession *> m_sessions; | ||
| 360 | bool m_managerOpen = false; | ||
| 361 | QString m_filterText; | ||
| 362 | QString m_folderFilter; | ||
| 363 | bool m_problemsOnly = false; | ||
| 364 | bool m_offOnly = false; | ||
| 365 | QString m_errorText; | ||
| 366 | QString m_errorDetails; | ||
| 367 | void holdConflict(const QByteArray &mine, const QByteArray &base, const SieveSession::SaveOutcome &outcome); | ||
| 368 | void clearConflict(); | ||
| 369 | QByteArray m_conflictMine; | ||
| 370 | QByteArray m_conflictBase; | ||
| 371 | QByteArray m_conflictTheirs; | ||
| 372 | QVariantList m_conflictBlocks; | ||
| 373 | QList<QByteArray> m_undo; | ||
| 374 | QTimer m_discoveryDelay; | ||
| 375 | quint64 m_requestCounter = 0; | ||
| 376 | bool m_announceNextApply = false; // F100-46: the next apply also announces "no match" | ||
| 377 | QPointer<SieveSyntaxHighlighter> m_highlighter; | ||
| 378 | QString m_pendingPanel; | ||
| 379 | QVariantMap m_pendingDraft; | ||
| 380 | QHash<QPair<qint64, qint64>, bool> m_matchCache; | ||
| 381 | static constexpr qsizetype MaxMatchCache = 20000; | ||
| 382 | int m_matchRevision = 0; | ||
| 383 | bool m_matchesPossible = false; // a rule document could match (server available) | ||
| 384 | void invalidateMatches(); | ||
| 385 | }; | ||
| 386 |