diff options
| author | Danilo M. <danix@danix.xyz> | 2026-10-31 12:43:21 +0100 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-10-31 12:43:21 +0100 |
| commit | 2b6ecd2a1f624c12c071320ff1ed96404d75f839 (patch) | |
| tree | 1d2eb2a875098e97558b4cbcff07fd32e841b7e9 /src/mainwindow.h | |
| parent | c9882b609ade04a8b17a89f6b05d51bf939e330c (diff) | |
| download | qtmaildir-2b6ecd2a1f624c12c071320ff1ed96404d75f839.tar.gz qtmaildir-2b6ecd2a1f624c12c071320ff1ed96404d75f839.zip | |
fix: handle every rule answer, and keep its failure out of errorOccurred
A second Apply overwrote the pending token, so the first rule's answer
was dropped as stale although its writes had landed: no undo, no pending
count, no accounts. A write's answer cannot be superseded, so the token
is gone and every ruleApplied() is handled. Pending counts are keyed by
generation for the same reason, since a second Apply before the first
count returned dropped the first Apply entirely.
applyRule() no longer emits errorOccurred(). That path reverted an
unrelated in-flight user write and its message was then overwritten by
"nothing to change". The failure travels in the reply instead:
ruleApplied(description, changes, error). openReadOnly() and writeTags()
take an optional error out-parameter so the rule's path stays quiet.
The window shows the error, still records and offers undo for whatever
landed first, and names the rule from the reply's description.
Item 212.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'src/mainwindow.h')
| -rw-r--r-- | src/mainwindow.h | 27 |
1 files changed, 15 insertions, 12 deletions
diff --git a/src/mainwindow.h b/src/mainwindow.h index f962089..2766db2 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -864,7 +864,14 @@ private slots: /// meanwhile clears that queue, and the backfill's confirmation was then /// credited to the user's command, whose undo inverted it over thousands /// of messages. - void onRuleApplied(quint64 token, const QVector<TagChange> &changes); + /// + /// Every answer is handled: there is no token to judge one stale by, + /// because a write's answer cannot be superseded. Two Applies in flight + /// both landed, and each needs its undo and its pending count. Messages + /// name the rule from `description`, which the reply carries. A non-empty + /// `error` is shown, and whatever landed before it is still recorded. + void onRuleApplied(const QString &description, + const QVector<TagChange> &changes, const QString &error); private: /// What onTagsApplied() does for any confirmed write, apart from crediting @@ -874,7 +881,7 @@ private: /// The count for applyRuleToExistingMail() arrived: confirm, then send /// the rule to the worker's applyRule(). - void confirmRuleApply(int count); + void confirmRuleApply(const TagRule &rule, int count); void buildUi(); @@ -1856,16 +1863,12 @@ private: /// counter. quint64 m_ruleCountGeneration = 0; - /// The rule awaiting its change count, and the generation that count - /// will carry. Shares m_ruleCountGeneration's sequence, so a pending - /// Apply and the dialog's Count matches can never be confused. - TagRule m_pendingApplyRule; - quint64 m_pendingApplyGeneration = 0; - - /// The token the outstanding applyRule() will answer with, 0 when none. - /// A reply carrying any other token is stale and dropped. - quint64 m_pendingRuleToken = 0; - quint64 m_lastRuleToken = 0; + /// The rules awaiting their change count, keyed by the generation each + /// count will carry. A map, not one slot: a second Apply before the first + /// count returns must not make the first look stale. Shares + /// m_ruleCountGeneration's sequence, so an Apply and the dialog's Count + /// matches can never be confused. + QHash<quint64, TagRule> m_pendingApplies; /// The generation of a REFRESH query, run after a sync to bring the list /// up to date without disturbing it. |
