app/core/ContactBookSync.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include <QHash> | ||
| 4 | #include <QObject> | ||
| 5 | #include <QSet> | ||
| 6 | #include <QStringList> | ||
| 7 | |||
| 8 | #include "data/ContactModels.h" | ||
| 9 | |||
| 10 | class CardDavClient; | ||
| 11 | class ContactStore; | ||
| 12 | struct DavCardChanges; | ||
| 13 | struct DavCardResource; | ||
| 14 | |||
| 15 | // One incremental sync of one address book (Sprint 97 S97.1.5, | ||
| 16 | // CONTACT-SYNC-INCR; gate G5): | ||
| 17 | // | ||
| 18 | // 1. PROPFIND Depth 0 of the book (name, privileges, CTag, sync-token, | ||
| 19 | // supported versions). An unchanged sync-token or CTag ends the run: | ||
| 20 | // one request, no card downloaded. | ||
| 21 | // 2. sync-collection (RFC 6578) with the stored token for ETags only; an | ||
| 22 | // expired token falls back to a full listing, a server without the | ||
| 23 | // report to PROPFIND Depth 1 of the ETags and a comparison with the | ||
| 24 | // stored ones. | ||
| 25 | // 3. addressbook-multiget of the changed hrefs in batches of at most 100; | ||
| 26 | // an answer above DavNetworkLimits splits the batch, a single card that | ||
| 27 | // is too large or unreadable is skipped with a per-card error instead of | ||
| 28 | // failing the book. | ||
| 29 | // 4. Cards with a queued local change are left to the outbox (it merges on | ||
| 30 | // 412). Deletions come from the sync result (or the full listing) and | ||
| 31 | // only touch this book. The token is stored after the cards are applied. | ||
| 32 | // 5. Photos given as a URI on the book's origin are fetched once | ||
| 33 | // (ContactPhotoFetch, S97.5.7); nothing to fetch means no request. | ||
| 34 | // | ||
| 35 | // The first complete fetch removes the book's D-5 legacy cards. | ||
| 36 | class ContactBookSync : public QObject { | ||
| 37 | Q_OBJECT | ||
| 38 | public: | ||
| 39 | static constexpr int MaxBatch = 100; | ||
| 40 | |||
| 41 | ContactBookSync(ContactStore *store, CardDavClient *client, qint64 bookId, QObject *parent = nullptr); | ||
| 42 | void start(); | ||
| 43 | |||
| 44 | 82 | int requests() const { return m_requests; } | |
| 45 | 82 | int cardsDownloaded() const { return m_downloaded; } | |
| 46 | int skippedCards() const { return m_skipped; } | ||
| 47 | // Sprint 96: the book's push offer from step 1 (Unknown before it ran). | ||
| 48 | 82 | DavPushOffer pushOffer() const { return m_server.push; } | |
| 49 | |||
| 50 | signals: | ||
| 51 | // ok = the book is complete and consistent; changedKeys = card keys that | ||
| 52 | // were added, changed or removed; bulk = too many for per-card updates. | ||
| 53 | void finished(bool ok, const QStringList &changedKeys, bool bulk); | ||
| 54 | void progressed(); // any answer arrived (the caller's inactivity timeout) | ||
| 55 | |||
| 56 | private: | ||
| 57 | void onBook(const AddressBookInfo &server); | ||
| 58 | void onChanges(const DavCardChanges &changes); | ||
| 59 | void onEtags(const QHash<QString, QString> &etags); | ||
| 60 | void fetchNextBatch(); | ||
| 61 | void onCards(const QList<DavCardResource> &cards, const QStringList &missing); | ||
| 62 | void onBatchFailed(const QStringList &hrefs, const QString &error, bool tooLarge); | ||
| 63 | void applyRemovals(); | ||
| 64 | void complete(); | ||
| 65 | void fail(const QString &error); | ||
| 66 | |||
| 67 | ContactStore *m_store; | ||
| 68 | CardDavClient *m_client; | ||
| 69 | qint64 m_bookId; | ||
| 70 | AddressBookInfo m_book; // stored state at start | ||
| 71 | AddressBookInfo m_server; // properties read in step 1 | ||
| 72 | QString m_newToken; | ||
| 73 | bool m_fullListing = false; | ||
| 74 | QStringList m_toFetch; | ||
| 75 | QList<QStringList> m_batches; | ||
| 76 | QStringList m_removed; | ||
| 77 | QString m_moreToken; // F-35: continue a truncated listing from it | ||
| 78 | // S106-957: a full listing the server truncated is collected over its | ||
| 79 | // continuation pages; the absence comparison runs once the last page came. | ||
| 80 | bool m_collectingFullListing = false; | ||
| 81 | // S106-062: the token the current continuation page was requested with, | ||
| 82 | // and the truncated pages of this run (bounded). | ||
| 83 | QString m_pageRequestToken; | ||
| 84 | int m_truncatedPages = 0; | ||
| 85 | static constexpr int MaxTruncatedPages = 1000; | ||
| 86 | QSet<QString> m_fullListingHrefs; | ||
| 87 | QStringList m_changedKeys; | ||
| 88 | int m_requests = 0; | ||
| 89 | int m_downloaded = 0; | ||
| 90 | int m_skipped = 0; | ||
| 91 | bool m_done = false; | ||
| 92 | }; | ||
| 93 |