diff options
author | Christian Mollekopf <chrigi_1@fastmail.fm> | 2016-06-03 09:40:31 +0200 |
---|---|---|
committer | Christian Mollekopf <chrigi_1@fastmail.fm> | 2016-06-03 09:40:31 +0200 |
commit | b5789da647bfdba9e3cc9b0595271b4d8c42bb8c (patch) | |
tree | 421bed2f38c9eac1d2d6579bf6a45b95c33cfbbf /examples/imapresource/imapresource.cpp | |
parent | f5b254c87a993988c9cb1fd06b5635f1a6b20f9f (diff) | |
download | sink-b5789da647bfdba9e3cc9b0595271b4d8c42bb8c.tar.gz sink-b5789da647bfdba9e3cc9b0595271b4d8c42bb8c.zip |
The imap resource can write-back changes
Diffstat (limited to 'examples/imapresource/imapresource.cpp')
-rw-r--r-- | examples/imapresource/imapresource.cpp | 148 |
1 files changed, 145 insertions, 3 deletions
diff --git a/examples/imapresource/imapresource.cpp b/examples/imapresource/imapresource.cpp index 4122a69..2dfb2ea 100644 --- a/examples/imapresource/imapresource.cpp +++ b/examples/imapresource/imapresource.cpp | |||
@@ -330,6 +330,76 @@ public: | |||
330 | 330 | ||
331 | KAsync::Job<QByteArray> replay(const ApplicationDomain::Mail &mail, Sink::Operation operation, const QByteArray &oldRemoteId) | 331 | KAsync::Job<QByteArray> replay(const ApplicationDomain::Mail &mail, Sink::Operation operation, const QByteArray &oldRemoteId) |
332 | { | 332 | { |
333 | auto imap = QSharedPointer<ImapServerProxy>::create(mServer, mPort); | ||
334 | auto login = imap->login(mUser, mPassword); | ||
335 | if (operation == Sink::Operation_Creation) { | ||
336 | auto parentRemoteId = syncStore().resolveLocalId("folder", mail.getFolder()); | ||
337 | QString mailbox = parentRemoteId; | ||
338 | QByteArray content = KMime::LFtoCRLF(mail.getMimeMessage()); | ||
339 | QByteArrayList flags; | ||
340 | if (!mail.getUnread()) { | ||
341 | flags << Imap::Flags::Seen; | ||
342 | } | ||
343 | if (mail.getImportant()) { | ||
344 | flags << Imap::Flags::Flagged; | ||
345 | } | ||
346 | QDateTime internalDate = mail.getDate(); | ||
347 | auto rid = QSharedPointer<QByteArray>::create(); | ||
348 | return login.then(imap->append(mailbox, content, flags, internalDate)) | ||
349 | .then<void, qint64>([imap, mailbox, rid](qint64 uid) { | ||
350 | const auto remoteId = mailbox.toUtf8() + "/" + QByteArray::number(uid); | ||
351 | //FIXME this get's called after the final error ahndler? WTF? | ||
352 | Trace() << "Finished creating a new mail: " << remoteId; | ||
353 | *rid = remoteId; | ||
354 | }).then<QByteArray>([rid, imap]() { //FIXME fix KJob so we don't need this extra clause | ||
355 | return *rid; | ||
356 | }); | ||
357 | } else if (operation == Sink::Operation_Removal) { | ||
358 | auto ridParts = oldRemoteId.split('/'); | ||
359 | auto uid = ridParts.takeLast().toLongLong(); | ||
360 | //FIXME don't hardcode the separator | ||
361 | auto mailbox = ridParts.join('.'); | ||
362 | Trace() << "Removing a mail: " << oldRemoteId << "in the mailbox: " << mailbox; | ||
363 | KIMAP::ImapSet set; | ||
364 | set.add(uid); | ||
365 | return login.then(imap->remove(mailbox, set)) | ||
366 | .then<QByteArray>([imap, oldRemoteId]() { | ||
367 | Trace() << "Finished removing a mail: " << oldRemoteId; | ||
368 | return QByteArray(); | ||
369 | }); | ||
370 | } else if (operation == Sink::Operation_Modification) { | ||
371 | auto ridParts = oldRemoteId.split('/'); | ||
372 | auto uid = ridParts.takeLast().toLongLong(); | ||
373 | //FIXME don't hardcode the separator | ||
374 | auto mailbox = ridParts.join('.'); | ||
375 | Trace() << "Modifying a mail: " << oldRemoteId << " in the mailbox: " << mailbox; | ||
376 | //TODO if the message changed, remove old message and create a new one, | ||
377 | //otherwise only change flags | ||
378 | |||
379 | QByteArrayList flags; | ||
380 | if (!mail.getUnread()) { | ||
381 | flags << Imap::Flags::Seen; | ||
382 | } | ||
383 | if (mail.getImportant()) { | ||
384 | flags << Imap::Flags::Flagged; | ||
385 | } | ||
386 | |||
387 | QByteArray content = KMime::LFtoCRLF(mail.getMimeMessage()); | ||
388 | QDateTime internalDate = mail.getDate(); | ||
389 | auto rid = QSharedPointer<QByteArray>::create(); | ||
390 | KIMAP::ImapSet set; | ||
391 | set.add(uid); | ||
392 | return login.then(imap->append(mailbox, content, flags, internalDate)) | ||
393 | .then<void, qint64>([imap, mailbox, rid](qint64 uid) { | ||
394 | const auto remoteId = mailbox + "/" + QByteArray::number(uid); | ||
395 | Trace() << "Finished creating a modified mail: " << remoteId; | ||
396 | *rid = remoteId; | ||
397 | }) | ||
398 | .then(imap->remove(mailbox, set)) | ||
399 | .then<QByteArray>([rid, imap]() { | ||
400 | return *rid; | ||
401 | }); | ||
402 | } | ||
333 | return KAsync::null<QByteArray>(); | 403 | return KAsync::null<QByteArray>(); |
334 | } | 404 | } |
335 | 405 | ||
@@ -439,19 +509,61 @@ KAsync::Job<void> ImapResource::inspect(int inspectionType, const QByteArray &in | |||
439 | const auto folderRemoteId = syncStore->resolveLocalId(ENTITY_TYPE_FOLDER, mail.getFolder()); | 509 | const auto folderRemoteId = syncStore->resolveLocalId(ENTITY_TYPE_FOLDER, mail.getFolder()); |
440 | const auto mailRemoteId = syncStore->resolveLocalId(ENTITY_TYPE_MAIL, mail.identifier()); | 510 | const auto mailRemoteId = syncStore->resolveLocalId(ENTITY_TYPE_MAIL, mail.identifier()); |
441 | if (mailRemoteId.isEmpty() || folderRemoteId.isEmpty()) { | 511 | if (mailRemoteId.isEmpty() || folderRemoteId.isEmpty()) { |
442 | KAsync::error<void>(); | 512 | Warning() << "Missing remote id for folder or mail. " << mailRemoteId << folderRemoteId; |
513 | return KAsync::error<void>(); | ||
443 | } | 514 | } |
515 | auto uid = mailRemoteId.split('/').last().toLongLong(); | ||
444 | Trace() << "Mail remote id: " << folderRemoteId << mailRemoteId << mail.identifier() << folder.identifier(); | 516 | Trace() << "Mail remote id: " << folderRemoteId << mailRemoteId << mail.identifier() << folder.identifier(); |
445 | 517 | ||
518 | KIMAP::ImapSet set; | ||
519 | set.add(uid); | ||
520 | if (set.isEmpty()) { | ||
521 | return KAsync::error<void>(1, "Couldn't determine uid of mail."); | ||
522 | } | ||
523 | KIMAP::FetchJob::FetchScope scope; | ||
524 | scope.mode = KIMAP::FetchJob::FetchScope::Full; | ||
525 | auto imap = QSharedPointer<ImapServerProxy>::create(mServer, mPort); | ||
526 | auto messageByUid = QSharedPointer<QHash<qint64, Imap::Message>>::create(); | ||
527 | auto inspectionJob = imap->login(mUser, mPassword) | ||
528 | .then<void>(imap->select(folderRemoteId)) | ||
529 | .then<void>(imap->fetch(set, scope, [imap, messageByUid](const QVector<Imap::Message> &messages) { | ||
530 | for (const auto &m : messages) { | ||
531 | messageByUid->insert(m.uid, m); | ||
532 | } | ||
533 | })); | ||
534 | |||
446 | if (inspectionType == Sink::ResourceControl::Inspection::PropertyInspectionType) { | 535 | if (inspectionType == Sink::ResourceControl::Inspection::PropertyInspectionType) { |
447 | if (property == "unread") { | 536 | if (property == "unread") { |
448 | return KAsync::null<void>(); | 537 | return inspectionJob.then<void, KAsync::Job<void>>([=]() { |
538 | auto msg = messageByUid->value(uid); | ||
539 | if (expectedValue.toBool() && msg.flags.contains(Imap::Flags::Seen)) { | ||
540 | return KAsync::error<void>(1, "Expected unread but couldn't find it."); | ||
541 | } | ||
542 | if (!expectedValue.toBool() && !msg.flags.contains(Imap::Flags::Seen)) { | ||
543 | return KAsync::error<void>(1, "Expected read but couldn't find it."); | ||
544 | } | ||
545 | return KAsync::null<void>(); | ||
546 | }); | ||
449 | } | 547 | } |
450 | if (property == "subject") { | 548 | if (property == "subject") { |
451 | return KAsync::null<void>(); | 549 | return inspectionJob.then<void, KAsync::Job<void>>([=]() { |
550 | auto msg = messageByUid->value(uid); | ||
551 | if (msg.msg->subject(true)->asUnicodeString() != expectedValue.toString()) { | ||
552 | return KAsync::error<void>(1, "Subject not as expected: " + msg.msg->subject(true)->asUnicodeString()); | ||
553 | } | ||
554 | return KAsync::null<void>(); | ||
555 | }); | ||
452 | } | 556 | } |
453 | } | 557 | } |
454 | if (inspectionType == Sink::ResourceControl::Inspection::ExistenceInspectionType) { | 558 | if (inspectionType == Sink::ResourceControl::Inspection::ExistenceInspectionType) { |
559 | return inspectionJob.then<void, KAsync::Job<void>>([=]() { | ||
560 | if (!messageByUid->contains(uid)) { | ||
561 | Warning() << "Existing messages are: " << messageByUid->keys(); | ||
562 | Warning() << "We're looking for: " << uid; | ||
563 | return KAsync::error<void>(1, "Couldn't find message: " + mailRemoteId); | ||
564 | } | ||
565 | return KAsync::null<void>(); | ||
566 | }); | ||
455 | } | 567 | } |
456 | } | 568 | } |
457 | if (domainType == ENTITY_TYPE_FOLDER) { | 569 | if (domainType == ENTITY_TYPE_FOLDER) { |
@@ -459,6 +571,36 @@ KAsync::Job<void> ImapResource::inspect(int inspectionType, const QByteArray &in | |||
459 | const auto folder = entityStore->read<Sink::ApplicationDomain::Folder>(entityId); | 571 | const auto folder = entityStore->read<Sink::ApplicationDomain::Folder>(entityId); |
460 | 572 | ||
461 | if (inspectionType == Sink::ResourceControl::Inspection::CacheIntegrityInspectionType) { | 573 | if (inspectionType == Sink::ResourceControl::Inspection::CacheIntegrityInspectionType) { |
574 | Warning() << "Inspecting cache integrity" << remoteId; | ||
575 | |||
576 | int expectedCount = 0; | ||
577 | Index index("mail.index.folder", transaction); | ||
578 | index.lookup(entityId, [&](const QByteArray &sinkId) { | ||
579 | expectedCount++; | ||
580 | }, | ||
581 | [&](const Index::Error &error) { | ||
582 | Warning() << "Error in index: " << error.message << property; | ||
583 | }); | ||
584 | |||
585 | auto set = KIMAP::ImapSet::fromImapSequenceSet("1:*"); | ||
586 | KIMAP::FetchJob::FetchScope scope; | ||
587 | scope.mode = KIMAP::FetchJob::FetchScope::Headers; | ||
588 | auto imap = QSharedPointer<ImapServerProxy>::create(mServer, mPort); | ||
589 | auto messageByUid = QSharedPointer<QHash<qint64, Imap::Message>>::create(); | ||
590 | auto inspectionJob = imap->login(mUser, mPassword) | ||
591 | .then<void>(imap->select(remoteId)) | ||
592 | .then<void>(imap->fetch(set, scope, [=](const QVector<Imap::Message> &messages) { | ||
593 | for (const auto &m : messages) { | ||
594 | messageByUid->insert(m.uid, m); | ||
595 | } | ||
596 | })) | ||
597 | .then<void, KAsync::Job<void>>([imap, messageByUid, expectedCount]() { | ||
598 | if (messageByUid->size() != expectedCount) { | ||
599 | return KAsync::error<void>(1, QString("Wrong number of files; found %1 instead of %2.").arg(messageByUid->size()).arg(expectedCount)); | ||
600 | } | ||
601 | return KAsync::null<void>(); | ||
602 | }); | ||
603 | return inspectionJob; | ||
462 | } | 604 | } |
463 | if (inspectionType == Sink::ResourceControl::Inspection::ExistenceInspectionType) { | 605 | if (inspectionType == Sink::ResourceControl::Inspection::ExistenceInspectionType) { |
464 | auto folderByPath = QSharedPointer<QSet<QString>>::create(); | 606 | auto folderByPath = QSharedPointer<QSet<QString>>::create(); |