summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Mollekopf <chrigi_1@fastmail.fm>2018-03-02 11:58:18 +0100
committerChristian Mollekopf <chrigi_1@fastmail.fm>2018-03-02 11:58:18 +0100
commitdb36ceabeb698b1988f7f6ecfe694c226eb156d7 (patch)
tree5bdadc074e98de7f9bcf14338b46068ae17f5856
parent54fc031c2a1632a69f4d6effa56dc9ba75448937 (diff)
downloadsink-db36ceabeb698b1988f7f6ecfe694c226eb156d7.tar.gz
sink-db36ceabeb698b1988f7f6ecfe694c226eb156d7.zip
Fixed synchronization with new mail notifications
-rw-r--r--examples/imapresource/imapresource.cpp44
-rw-r--r--examples/imapresource/tests/imapmailsynctest.cpp25
2 files changed, 50 insertions, 19 deletions
diff --git a/examples/imapresource/imapresource.cpp b/examples/imapresource/imapresource.cpp
index f87c5ff..811e560 100644
--- a/examples/imapresource/imapresource.cpp
+++ b/examples/imapresource/imapresource.cpp
@@ -267,13 +267,13 @@ public:
267 }) 267 })
268 // //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. 268 // //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.
269 .then([=] { 269 .then([=] {
270 auto uidNext = syncStore().readValue(folderRemoteId, "uidnext").toLongLong(); 270 auto lastSeenUid = syncStore().readValue(folderRemoteId, "uidnext").toLongLong();
271 bool ok = false; 271 bool ok = false;
272 const auto changedsince = syncStore().readValue(folderRemoteId, "changedsince").toLongLong(&ok); 272 const auto changedsince = syncStore().readValue(folderRemoteId, "changedsince").toLongLong(&ok);
273 SinkLogCtx(mLogCtx) << "About to update flags" << folder.path() << "changedsince: " << changedsince; 273 SinkLogCtx(mLogCtx) << "About to update flags" << folder.path() << "changedsince: " << changedsince;
274 //If we have any mails so far we start off by updating any changed flags using changedsince 274 //If we have any mails so far we start off by updating any changed flags using changedsince
275 if (ok) { 275 if (ok) {
276 return imap->fetchFlags(folder, KIMAP2::ImapSet(1, qMax(uidNext, qint64(1))), changedsince, [=](const Message &message) { 276 return imap->fetchFlags(folder, KIMAP2::ImapSet(1, qMax(lastSeenUid, qint64(1))), changedsince, [=](const Message &message) {
277 const auto folderLocalId = syncStore().resolveRemoteId(ENTITY_TYPE_FOLDER, folderRemoteId); 277 const auto folderLocalId = syncStore().resolveRemoteId(ENTITY_TYPE_FOLDER, folderRemoteId);
278 const auto remoteId = assembleMailRid(folderLocalId, message.uid); 278 const auto remoteId = assembleMailRid(folderLocalId, message.uid);
279 279
@@ -315,12 +315,12 @@ public:
315 return job.then([=](const QVector<qint64> &uidsToFetch) { 315 return job.then([=](const QVector<qint64> &uidsToFetch) {
316 SinkTraceCtx(mLogCtx) << "Received result set " << uidsToFetch; 316 SinkTraceCtx(mLogCtx) << "Received result set " << uidsToFetch;
317 SinkTraceCtx(mLogCtx) << "About to fetch mail" << folder.path(); 317 SinkTraceCtx(mLogCtx) << "About to fetch mail" << folder.path();
318 const auto uidNext = syncStore().readValue(folderRemoteId, "uidnext").toLongLong(); 318 const auto lastSeenUid = syncStore().readValue(folderRemoteId, "uidnext").toLongLong();
319 319
320 //Make sure the uids are sorted in reverse order and drop everything below uidNext (so we don't refetch what we already have 320 //Make sure the uids are sorted in reverse order and drop everything below lastSeenUid (so we don't refetch what we already have
321 QVector<qint64> filteredAndSorted = uidsToFetch; 321 QVector<qint64> filteredAndSorted = uidsToFetch;
322 qSort(filteredAndSorted.begin(), filteredAndSorted.end(), qGreater<qint64>()); 322 qSort(filteredAndSorted.begin(), filteredAndSorted.end(), qGreater<qint64>());
323 auto lowerBound = qLowerBound(filteredAndSorted.begin(), filteredAndSorted.end(), uidNext, qGreater<qint64>()); 323 auto lowerBound = qLowerBound(filteredAndSorted.begin(), filteredAndSorted.end(), lastSeenUid, qGreater<qint64>());
324 if (lowerBound != filteredAndSorted.end()) { 324 if (lowerBound != filteredAndSorted.end()) {
325 filteredAndSorted.erase(lowerBound, filteredAndSorted.end()); 325 filteredAndSorted.erase(lowerBound, filteredAndSorted.end());
326 } 326 }
@@ -348,13 +348,14 @@ public:
348 } 348 }
349 }) 349 })
350 .then([=] { 350 .then([=] {
351 SinkLogCtx(mLogCtx) << "UIDMAX: " << *maxUid << folder.path(); 351 SinkLogCtx(mLogCtx) << "Highest found uid: " << *maxUid << folder.path();
352 if (*maxUid > 0) { 352 if (*maxUid > 0) {
353 syncStore().writeValue(folderRemoteId, "uidnext", QByteArray::number(*maxUid)); 353 syncStore().writeValue(folderRemoteId, "uidnext", QByteArray::number(*maxUid));
354 } else { 354 } else {
355 if (serverUidNext) { 355 if (serverUidNext) {
356 SinkLogCtx(mLogCtx) << "Storing the server side uidnext: " << serverUidNext << folder.path();
356 //If we don't receive a mail we should still record the updated uidnext value. 357 //If we don't receive a mail we should still record the updated uidnext value.
357 syncStore().writeValue(folderRemoteId, "uidnext", QByteArray::number(serverUidNext)); 358 syncStore().writeValue(folderRemoteId, "uidnext", QByteArray::number(serverUidNext - 1));
358 } 359 }
359 } 360 }
360 syncStore().writeValue(folderRemoteId, "fullsetLowerbound", QByteArray::number(lowerBoundUid)); 361 syncStore().writeValue(folderRemoteId, "fullsetLowerbound", QByteArray::number(lowerBoundUid));
@@ -567,17 +568,26 @@ public:
567 synchronizeFolders(*folderList); 568 synchronizeFolders(*folderList);
568 return *folderList; 569 return *folderList;
569 }) 570 })
571 //The rest is only to check for new messages.
570 .each([=](const Imap::Folder &folder) { 572 .each([=](const Imap::Folder &folder) {
571 //TODO examine instead 573 if (!folder.noselect && folder.subscribed) {
572 return imap->select(folder) 574 return imap->examine(folder)
573 .then([=](const SelectResult &result) { 575 .then([=](const SelectResult &result) {
574 const auto folderRemoteId = folderRid(folder); 576 const auto folderRemoteId = folderRid(folder);
575 auto localUidNext = syncStore().readValue(folderRemoteId, "uidnext").toLongLong(); 577 auto lastSeenUid = syncStore().readValue(folderRemoteId, "uidnext").toLongLong();
576 if (result.uidNext > localUidNext) { 578 SinkTraceCtx(mLogCtx) << "Checking for new messages." << folderRemoteId << " Last seen uid: " << lastSeenUid << " Uidnext: " << result.uidNext;
577 const auto folderLocalId = syncStore().resolveRemoteId(ENTITY_TYPE_FOLDER, folderRemoteId); 579 if (result.uidNext > (lastSeenUid + 1)) {
578 emitNotification(Notification::Info, ApplicationDomain::NewContentAvailable, {}, {}, {{folderLocalId}}); 580 const auto folderLocalId = syncStore().resolveRemoteId(ENTITY_TYPE_FOLDER, folderRemoteId);
579 } 581 emitNotification(Notification::Info, ApplicationDomain::NewContentAvailable, {}, {}, {{folderLocalId}});
580 }); 582 }
583 }).then([=] (const KAsync::Error &error) {
584 if (error) {
585 //Ignore the error because we don't want to fail the synchronization here
586 SinkWarningCtx(mLogCtx) << "Examine failed: " << error.errorMessage;
587 }
588 });
589 }
590 return KAsync::null();
581 }); 591 });
582 }) 592 })
583 .then([=] (const KAsync::Error &error) { 593 .then([=] (const KAsync::Error &error) {
diff --git a/examples/imapresource/tests/imapmailsynctest.cpp b/examples/imapresource/tests/imapmailsynctest.cpp
index 1d62a80..06369f3 100644
--- a/examples/imapresource/tests/imapmailsynctest.cpp
+++ b/examples/imapresource/tests/imapmailsynctest.cpp
@@ -135,12 +135,15 @@ protected:
135private slots: 135private slots:
136 void testNewMailNotification() 136 void testNewMailNotification()
137 { 137 {
138 createFolder(QStringList() << "testNewMailNotification");
139 createMessage(QStringList() << "testNewMailNotification", newMessage("Foobar"));
140
138 const auto syncFolders = Sink::SyncScope{ApplicationDomain::getTypeName<Folder>()}.resourceFilter(mResourceInstanceIdentifier); 141 const auto syncFolders = Sink::SyncScope{ApplicationDomain::getTypeName<Folder>()}.resourceFilter(mResourceInstanceIdentifier);
139 //Fetch folders initially 142 //Fetch folders initially
140 VERIFYEXEC(Store::synchronize(syncFolders)); 143 VERIFYEXEC(Store::synchronize(syncFolders));
141 VERIFYEXEC(ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); 144 VERIFYEXEC(ResourceControl::flushMessageQueue(mResourceInstanceIdentifier));
142 145
143 auto folder = Store::readOne<Folder>(Sink::Query{}.resourceFilter(mResourceInstanceIdentifier).filter<Folder::Name>("test")); 146 auto folder = Store::readOne<Folder>(Sink::Query{}.resourceFilter(mResourceInstanceIdentifier).filter<Folder::Name>("testNewMailNotification"));
144 Q_ASSERT(!folder.identifier().isEmpty()); 147 Q_ASSERT(!folder.identifier().isEmpty());
145 148
146 const auto syncTestMails = Sink::SyncScope{ApplicationDomain::getTypeName<Mail>()}.resourceFilter(mResourceInstanceIdentifier).filter<Mail::Folder>(QVariant::fromValue(folder.identifier())); 149 const auto syncTestMails = Sink::SyncScope{ApplicationDomain::getTypeName<Mail>()}.resourceFilter(mResourceInstanceIdentifier).filter<Mail::Folder>(QVariant::fromValue(folder.identifier()));
@@ -172,7 +175,7 @@ private slots:
172 QVERIFY(!notificationReceived); 175 QVERIFY(!notificationReceived);
173 176
174 //Create message and retry 177 //Create message and retry
175 createMessage(QStringList() << "test", newMessage("This is a Subject.")); 178 createMessage(QStringList() << "testNewMailNotification", newMessage("This is a Subject."));
176 179
177 //Should result in change notification 180 //Should result in change notification
178 VERIFYEXEC(Store::synchronize(syncFolders)); 181 VERIFYEXEC(Store::synchronize(syncFolders));
@@ -180,6 +183,24 @@ private slots:
180 183
181 QTRY_VERIFY(notificationReceived); 184 QTRY_VERIFY(notificationReceived);
182 } 185 }
186
187 void testSyncFolderBeforeFetchingNewMessages()
188 {
189 const auto syncScope = Sink::Query{}.resourceFilter(mResourceInstanceIdentifier);
190
191 createFolder(QStringList() << "test3");
192
193 VERIFYEXEC(Store::synchronize(syncScope));
194 VERIFYEXEC(ResourceControl::flushMessageQueue(mResourceInstanceIdentifier));
195
196 createMessage(QStringList() << "test3", newMessage("Foobar"));
197
198 VERIFYEXEC(Store::synchronize(syncScope));
199 VERIFYEXEC(ResourceControl::flushMessageQueue(mResourceInstanceIdentifier));
200
201 auto mailQuery = Sink::Query{}.resourceFilter(mResourceInstanceIdentifier).request<Mail::Subject>().filter<Mail::Folder>(Sink::Query{}.filter<Folder::Name>("test3"));
202 QCOMPARE(Store::read<Mail>(mailQuery).size(), 1);
203 }
183}; 204};
184 205
185QTEST_MAIN(ImapMailSyncTest) 206QTEST_MAIN(ImapMailSyncTest)