diff options
author | Christian Mollekopf <chrigi_1@fastmail.fm> | 2016-09-14 16:16:42 +0200 |
---|---|---|
committer | Christian Mollekopf <chrigi_1@fastmail.fm> | 2016-09-15 16:14:19 +0200 |
commit | 6d5be4fb7b8cbc450e2780905eaac9a18b486c5c (patch) | |
tree | 3e0f42e15889c271a41f4d6225a44b21c066b16a /examples/imapresource/imapresource.cpp | |
parent | ca9c54670cc2d26386c80a2aeed2c999313ec362 (diff) | |
download | sink-6d5be4fb7b8cbc450e2780905eaac9a18b486c5c.tar.gz sink-6d5be4fb7b8cbc450e2780905eaac9a18b486c5c.zip |
New synchronization algorithm that only fetches the last 14 days.
Diffstat (limited to 'examples/imapresource/imapresource.cpp')
-rw-r--r-- | examples/imapresource/imapresource.cpp | 129 |
1 files changed, 71 insertions, 58 deletions
diff --git a/examples/imapresource/imapresource.cpp b/examples/imapresource/imapresource.cpp index 63ae07b..aa0fb94 100644 --- a/examples/imapresource/imapresource.cpp +++ b/examples/imapresource/imapresource.cpp | |||
@@ -40,10 +40,14 @@ | |||
40 | #include "entitystore.h" | 40 | #include "entitystore.h" |
41 | #include "remoteidmap.h" | 41 | #include "remoteidmap.h" |
42 | #include "query.h" | 42 | #include "query.h" |
43 | |||
44 | #include <QtGlobal> | ||
43 | #include <QDate> | 45 | #include <QDate> |
44 | #include <QUuid> | 46 | #include <QUuid> |
45 | #include <QDir> | 47 | #include <QDir> |
46 | #include <QDirIterator> | 48 | #include <QDirIterator> |
49 | #include <QDateTime> | ||
50 | #include <QtAlgorithms> | ||
47 | 51 | ||
48 | #include "imapserverproxy.h" | 52 | #include "imapserverproxy.h" |
49 | #include "entityreader.h" | 53 | #include "entityreader.h" |
@@ -149,7 +153,7 @@ public: | |||
149 | } | 153 | } |
150 | } | 154 | } |
151 | 155 | ||
152 | void synchronizeMails(const QString &path, const QVector<Message> &messages) | 156 | void synchronizeMails(const QString &path, const Message &message) |
153 | { | 157 | { |
154 | auto time = QSharedPointer<QTime>::create(); | 158 | auto time = QSharedPointer<QTime>::create(); |
155 | time->start(); | 159 | time->start(); |
@@ -159,23 +163,20 @@ public: | |||
159 | 163 | ||
160 | const auto folderLocalId = syncStore().resolveRemoteId(ENTITY_TYPE_FOLDER, path.toUtf8()); | 164 | const auto folderLocalId = syncStore().resolveRemoteId(ENTITY_TYPE_FOLDER, path.toUtf8()); |
161 | 165 | ||
162 | int count = 0; | 166 | const auto remoteId = assembleMailRid(folderLocalId, message.uid); |
163 | for (const auto &message : messages) { | ||
164 | count++; | ||
165 | const auto remoteId = assembleMailRid(folderLocalId, message.uid); | ||
166 | 167 | ||
167 | SinkTrace() << "Found a mail " << remoteId << message.msg->subject(true)->asUnicodeString() << message.flags; | 168 | Q_ASSERT(message.msg); |
169 | SinkTrace() << "Found a mail " << remoteId << message.msg->subject(true)->asUnicodeString() << message.flags; | ||
168 | 170 | ||
169 | auto mail = Sink::ApplicationDomain::Mail::create(mResourceInstanceIdentifier); | 171 | auto mail = Sink::ApplicationDomain::Mail::create(mResourceInstanceIdentifier); |
170 | mail.setFolder(folderLocalId); | 172 | mail.setFolder(folderLocalId); |
171 | mail.setMimeMessage(message.msg->encodedContent()); | 173 | mail.setMimeMessage(message.msg->encodedContent()); |
172 | mail.setUnread(!message.flags.contains(Imap::Flags::Seen)); | 174 | mail.setUnread(!message.flags.contains(Imap::Flags::Seen)); |
173 | mail.setImportant(message.flags.contains(Imap::Flags::Flagged)); | 175 | mail.setImportant(message.flags.contains(Imap::Flags::Flagged)); |
174 | 176 | ||
175 | createOrModify(bufferType, remoteId, mail); | 177 | createOrModify(bufferType, remoteId, mail); |
176 | } | 178 | // const auto elapsed = time->elapsed(); |
177 | const auto elapsed = time->elapsed(); | 179 | // SinkTrace() << "Synchronized " << count << " mails in " << path << Sink::Log::TraceTime(elapsed) << " " << elapsed/qMax(count, 1) << " [ms/mail]"; |
178 | SinkTrace() << "Synchronized " << count << " mails in " << path << Sink::Log::TraceTime(elapsed) << " " << elapsed/qMax(count, 1) << " [ms/mail]"; | ||
179 | } | 180 | } |
180 | 181 | ||
181 | void synchronizeRemovals(const QString &path, const QSet<qint64> &messages) | 182 | void synchronizeRemovals(const QString &path, const QSet<qint64> &messages) |
@@ -220,29 +221,71 @@ public: | |||
220 | auto capabilities = imap->getCapabilities(); | 221 | auto capabilities = imap->getCapabilities(); |
221 | bool canDoIncrementalRemovals = false; | 222 | bool canDoIncrementalRemovals = false; |
222 | return KAsync::start<void>([=]() { | 223 | return KAsync::start<void>([=]() { |
224 | //First we fetch flag changes for all messages. Since we don't know which messages are locally available we just get everything and only apply to what we have. | ||
225 | SinkLog() << "About to update flags" << folder.normalizedPath(); | ||
223 | auto uidNext = syncStore().readValue(folder.normalizedPath().toUtf8() + "uidnext").toLongLong(); | 226 | auto uidNext = syncStore().readValue(folder.normalizedPath().toUtf8() + "uidnext").toLongLong(); |
224 | const auto changedsince = syncStore().readValue(folder.normalizedPath().toUtf8() + "changedsince").toLongLong(); | 227 | const auto changedsince = syncStore().readValue(folder.normalizedPath().toUtf8() + "changedsince").toLongLong(); |
225 | return imap->fetchFlags(folder, KIMAP2::ImapSet(1, qMax(uidNext, qint64(1))), changedsince, [this, folder](const QVector<Message> &messages) { | 228 | return imap->fetchFlags(folder, KIMAP2::ImapSet(1, qMax(uidNext, qint64(1))), changedsince, [this, folder](const Message &message) { |
226 | // synchronizeMails(folder.normalizedPath(), messages); | ||
227 | const auto folderLocalId = syncStore().resolveRemoteId(ENTITY_TYPE_FOLDER, folder.normalizedPath().toUtf8()); | 229 | const auto folderLocalId = syncStore().resolveRemoteId(ENTITY_TYPE_FOLDER, folder.normalizedPath().toUtf8()); |
228 | for (const auto &message : messages) { | 230 | const auto remoteId = assembleMailRid(folderLocalId, message.uid); |
229 | const auto remoteId = assembleMailRid(folderLocalId, message.uid); | ||
230 | 231 | ||
232 | SinkLog() << "Updating mail flags " << remoteId << message.flags; | ||
231 | 233 | ||
232 | auto mail = Sink::ApplicationDomain::Mail::create(mResourceInstanceIdentifier); | 234 | auto mail = Sink::ApplicationDomain::Mail::create(mResourceInstanceIdentifier); |
233 | mail.setUnread(!message.flags.contains(Imap::Flags::Seen)); | 235 | mail.setUnread(!message.flags.contains(Imap::Flags::Seen)); |
234 | mail.setImportant(message.flags.contains(Imap::Flags::Flagged)); | 236 | mail.setImportant(message.flags.contains(Imap::Flags::Flagged)); |
235 | 237 | ||
236 | modify(ENTITY_TYPE_MAIL, remoteId, mail); | 238 | modify(ENTITY_TYPE_MAIL, remoteId, mail); |
237 | } | ||
238 | }) | 239 | }) |
239 | .syncThen<void, SelectResult>([this, folder](const SelectResult &selectResult) { | 240 | .syncThen<void, SelectResult>([this, folder](const SelectResult &selectResult) { |
240 | syncStore().writeValue(folder.normalizedPath().toUtf8() + "changedsince", QByteArray::number(selectResult.highestModSequence)); | 241 | syncStore().writeValue(folder.normalizedPath().toUtf8() + "changedsince", QByteArray::number(selectResult.highestModSequence)); |
241 | }); | 242 | }); |
242 | }) | 243 | }) |
243 | .then<void>([=]() { | 244 | .then<void>([=]() { |
245 | //Get the range we're interested in. This is what we're going to download. | ||
246 | return imap->fetchUidsSince(imap->mailboxFromFolder(folder), QDate::currentDate().addDays(-14)) | ||
247 | .then<void, QVector<qint64>>([this, folder, imap](const QVector<qint64> &uidsToFetch) { | ||
248 | SinkTrace() << "Received result set " << uidsToFetch; | ||
249 | SinkTrace() << "About to fetch mail" << folder.normalizedPath(); | ||
250 | const auto uidNext = syncStore().readValue(folder.normalizedPath().toUtf8() + "uidnext").toLongLong(); | ||
251 | QVector<qint64> filteredAndSorted = uidsToFetch; | ||
252 | qSort(filteredAndSorted.begin(), filteredAndSorted.end(), qGreater<qint64>()); | ||
253 | auto lowerBound = qLowerBound(filteredAndSorted.begin(), filteredAndSorted.end(), uidNext, qGreater<qint64>()); | ||
254 | if (lowerBound != filteredAndSorted.end()) { | ||
255 | filteredAndSorted.erase(lowerBound, filteredAndSorted.end()); | ||
256 | } | ||
257 | |||
258 | auto maxUid = QSharedPointer<qint64>::create(0); | ||
259 | if (!filteredAndSorted.isEmpty()) { | ||
260 | *maxUid = filteredAndSorted.first(); | ||
261 | } | ||
262 | SinkTrace() << "Uids to fetch: " << filteredAndSorted; | ||
263 | return imap->fetchMessages(folder, filteredAndSorted, [this, folder, maxUid](const Message &m) { | ||
264 | if (*maxUid < m.uid) { | ||
265 | *maxUid = m.uid; | ||
266 | } | ||
267 | synchronizeMails(folder.normalizedPath(), m); | ||
268 | }, | ||
269 | [this, maxUid, folder](int progress, int total) { | ||
270 | SinkLog() << "Progress: " << progress << " out of " << total; | ||
271 | //commit every 10 messages | ||
272 | if ((progress % 10) == 0) { | ||
273 | commit(); | ||
274 | } | ||
275 | }) | ||
276 | .syncThen<void>([this, maxUid, folder]() { | ||
277 | SinkLog() << "UIDMAX: " << *maxUid << folder.normalizedPath(); | ||
278 | if (*maxUid > 0) { | ||
279 | syncStore().writeValue(folder.normalizedPath().toUtf8() + "uidnext", QByteArray::number(*maxUid)); | ||
280 | } | ||
281 | commit(); | ||
282 | }); | ||
283 | }); | ||
284 | }) | ||
285 | .then<void>([=]() { | ||
244 | //TODO Remove what's no longer existing | 286 | //TODO Remove what's no longer existing |
245 | if (canDoIncrementalRemovals) { | 287 | if (canDoIncrementalRemovals) { |
288 | //TODO do an examine with QRESYNC and remove VANISHED messages | ||
246 | } else { | 289 | } else { |
247 | return imap->fetchUids(folder).syncThen<void, QVector<qint64>>([this, folder](const QVector<qint64> &uids) { | 290 | return imap->fetchUids(folder).syncThen<void, QVector<qint64>>([this, folder](const QVector<qint64> &uids) { |
248 | SinkTrace() << "Syncing removals"; | 291 | SinkTrace() << "Syncing removals"; |
@@ -251,32 +294,6 @@ public: | |||
251 | }); | 294 | }); |
252 | } | 295 | } |
253 | return KAsync::null<void>(); | 296 | return KAsync::null<void>(); |
254 | }) | ||
255 | .then<void>([this, folder, imap]() { | ||
256 | SinkTrace() << "About to fetch mail"; | ||
257 | const auto uidNext = syncStore().readValue(folder.normalizedPath().toUtf8() + "uidnext").toLongLong(); | ||
258 | auto maxUid = QSharedPointer<qint64>::create(0); | ||
259 | return imap->fetchMessages(folder, uidNext, [this, folder, maxUid](const QVector<Message> &messages) { | ||
260 | SinkTrace() << "Got mail"; | ||
261 | for (const auto &m : messages) { | ||
262 | if (*maxUid < m.uid) { | ||
263 | *maxUid = m.uid; | ||
264 | } | ||
265 | } | ||
266 | synchronizeMails(folder.normalizedPath(), messages); | ||
267 | }, | ||
268 | [this, maxUid, folder](int progress, int total) { | ||
269 | SinkLog() << "Progress: " << progress << " out of " << total; | ||
270 | //commit every 10 messages | ||
271 | if ((progress % 10) == 0) { | ||
272 | commit(); | ||
273 | } | ||
274 | }) | ||
275 | .syncThen<void>([this, maxUid, folder]() { | ||
276 | syncStore().writeValue(folder.normalizedPath().toUtf8() + "uidnext", QByteArray::number(*maxUid)); | ||
277 | SinkLog() << "UIDMAX: " << *maxUid << folder.normalizedPath(); | ||
278 | commit(); | ||
279 | }); | ||
280 | }); | 297 | }); |
281 | 298 | ||
282 | 299 | ||
@@ -578,10 +595,8 @@ KAsync::Job<void> ImapResource::inspect(int inspectionType, const QByteArray &in | |||
578 | auto inspectionJob = imap->login(mUser, mPassword) | 595 | auto inspectionJob = imap->login(mUser, mPassword) |
579 | .then<Imap::SelectResult>(imap->select(folderRemoteId)) | 596 | .then<Imap::SelectResult>(imap->select(folderRemoteId)) |
580 | .syncThen<void, Imap::SelectResult>([](Imap::SelectResult){}) | 597 | .syncThen<void, Imap::SelectResult>([](Imap::SelectResult){}) |
581 | .then<void>(imap->fetch(set, scope, [imap, messageByUid](const QVector<Imap::Message> &messages) { | 598 | .then<void>(imap->fetch(set, scope, [imap, messageByUid](const Imap::Message &message) { |
582 | for (const auto &m : messages) { | 599 | messageByUid->insert(message.uid, message); |
583 | messageByUid->insert(m.uid, m); | ||
584 | } | ||
585 | })); | 600 | })); |
586 | 601 | ||
587 | if (inspectionType == Sink::ResourceControl::Inspection::PropertyInspectionType) { | 602 | if (inspectionType == Sink::ResourceControl::Inspection::PropertyInspectionType) { |
@@ -641,10 +656,8 @@ KAsync::Job<void> ImapResource::inspect(int inspectionType, const QByteArray &in | |||
641 | auto messageByUid = QSharedPointer<QHash<qint64, Imap::Message>>::create(); | 656 | auto messageByUid = QSharedPointer<QHash<qint64, Imap::Message>>::create(); |
642 | return imap->login(mUser, mPassword) | 657 | return imap->login(mUser, mPassword) |
643 | .then<void>(imap->select(remoteId).syncThen<void>([](){})) | 658 | .then<void>(imap->select(remoteId).syncThen<void>([](){})) |
644 | .then<void>(imap->fetch(set, scope, [=](const QVector<Imap::Message> &messages) { | 659 | .then<void>(imap->fetch(set, scope, [=](const Imap::Message message) { |
645 | for (const auto &m : messages) { | 660 | messageByUid->insert(message.uid, message); |
646 | messageByUid->insert(m.uid, m); | ||
647 | } | ||
648 | })) | 661 | })) |
649 | .then<void>([imap, messageByUid, expectedCount]() { | 662 | .then<void>([imap, messageByUid, expectedCount]() { |
650 | if (messageByUid->size() != expectedCount) { | 663 | if (messageByUid->size() != expectedCount) { |