summaryrefslogtreecommitdiffstats
path: root/examples/imapresource/imapresource.cpp
diff options
context:
space:
mode:
authorChristian Mollekopf <chrigi_1@fastmail.fm>2016-09-14 16:16:42 +0200
committerChristian Mollekopf <chrigi_1@fastmail.fm>2016-09-15 16:14:19 +0200
commit6d5be4fb7b8cbc450e2780905eaac9a18b486c5c (patch)
tree3e0f42e15889c271a41f4d6225a44b21c066b16a /examples/imapresource/imapresource.cpp
parentca9c54670cc2d26386c80a2aeed2c999313ec362 (diff)
downloadsink-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.cpp129
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) {