presentation/ServerDraftCleanup.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include <QHash> | ||
| 4 | #include <QObject> | ||
| 5 | #include <QString> | ||
| 6 | #include <QTimer> | ||
| 7 | |||
| 8 | #include <functional> | ||
| 9 | |||
| 10 | class ImapService; | ||
| 11 | |||
| 12 | // Removes superseded server draft revisions (Sprint 102 review S102.5.1). | ||
| 13 | // Only the exact UID in the Drafts mailbox whose UIDVALIDITY the server | ||
| 14 | // reported in APPENDUID is touched, through UID EXPUNGE (RFC 4315). A | ||
| 15 | // revision whose identity is unknown or changed is left alone; without | ||
| 16 | // UIDPLUS it keeps \Deleted, because a plain EXPUNGE would also remove | ||
| 17 | // messages other clients only marked as deleted. | ||
| 18 | // F-04 (SPRINT-104): the cleanup runs from every authenticated state — | ||
| 19 | // with a folder open the connection is Selected or Idling, which the | ||
| 20 | // former Authenticated-only guard made unreachable in normal use, so | ||
| 21 | // every saved revision stayed in the Drafts folder. Requests arriving | ||
| 22 | // while a cleanup runs are queued, and a failing SELECT of the Drafts | ||
| 23 | // folder ends the cleanup instead of sticking it active forever. | ||
| 24 | // S106-345/346/347: every step listens to its own command only — the | ||
| 25 | // Drafts SELECT through folderSelectFailed(drafts), the STORE through its | ||
| 26 | // mutation token (a STORE refused with NO ends the cleanup; another | ||
| 27 | // STORE completing meanwhile is not taken for it) — and a watchdog ends a | ||
| 28 | // cleanup whose step never answers. | ||
| 29 | class ServerDraftCleanup : public QObject { | ||
| 30 | Q_OBJECT | ||
| 31 | |||
| 32 | public: | ||
| 33 | // `imap` and `currentFolder` are read at each step (the session owns them). | ||
| 34 | ServerDraftCleanup(std::function<ImapService *()> imap, std::function<QString()> currentFolder, | ||
| 35 | QObject *parent = nullptr); | ||
| 36 | // Called for every completed APPEND; remembers the mailbox identity. | ||
| 37 | void remember(const QString &folder, qint64 uid, quint32 uidValidity); | ||
| 38 | // Marks `uid` in `drafts` \Deleted and expunges exactly it. | ||
| 39 | void remove(const QString &drafts, qint64 uid); | ||
| 40 | 61 | bool active() const { return m_active; } | |
| 41 | // The connection ended: forget the running cleanup. | ||
| 42 | void reset(); | ||
| 43 | void setWatchdogMs(int ms) { m_watchdog.setInterval(ms); } // tests | ||
| 44 | static constexpr int WatchdogMs = 60000; | ||
| 45 | |||
| 46 | private: | ||
| 47 | struct Pending { | ||
| 48 | QString drafts; | ||
| 49 | qint64 uid = 0; | ||
| 50 | quint32 uidValidity = 0; | ||
| 51 | }; | ||
| 52 | void startNext(); | ||
| 53 | void storeAndExpunge(const QString &drafts, qint64 uid, quint32 uidValidity); | ||
| 54 | void finish(); | ||
| 55 | void disconnectSteps(); | ||
| 56 | std::function<ImapService *()> m_imap; | ||
| 57 | std::function<QString()> m_currentFolder; | ||
| 58 | QHash<QString, quint32> m_uidValidity; // folder + '\n' + uid -> UIDVALIDITY | ||
| 59 | QString m_restore; // folder selected before the cleanup | ||
| 60 | bool m_reselect = false; | ||
| 61 | QList<Pending> m_pending; // F-04: queued while a cleanup runs | ||
| 62 | QList<QMetaObject::Connection> m_steps; // pending one-shot step connections | ||
| 63 | bool m_active = false; | ||
| 64 | QTimer m_watchdog; // ends a cleanup whose step never answers | ||
| 65 | qint64 m_storeTokens = 0; | ||
| 66 | }; | ||
| 67 |