summaryrefslogtreecommitdiffstats
path: root/examples/imapresource/imapresource.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'examples/imapresource/imapresource.cpp')
-rw-r--r--examples/imapresource/imapresource.cpp151
1 files changed, 78 insertions, 73 deletions
diff --git a/examples/imapresource/imapresource.cpp b/examples/imapresource/imapresource.cpp
index 6168fa4..fee479a 100644
--- a/examples/imapresource/imapresource.cpp
+++ b/examples/imapresource/imapresource.cpp
@@ -103,6 +103,31 @@ public:
103 103
104}; 104};
105 105
106static qint64 uidFromMailRid(const QByteArray &remoteId)
107{
108 auto ridParts = remoteId.split(':');
109 Q_ASSERT(ridParts.size() == 2);
110 return ridParts.last().toLongLong();
111}
112
113static QByteArray folderIdFromMailRid(const QByteArray &remoteId)
114{
115 auto ridParts = remoteId.split(':');
116 Q_ASSERT(ridParts.size() == 2);
117 return ridParts.first();
118}
119
120static QByteArray assembleMailRid(const QByteArray &folderLocalId, qint64 imapUid)
121{
122 return folderLocalId + ':' + QByteArray::number(imapUid);
123}
124
125static QByteArray assembleMailRid(const ApplicationDomain::Mail &mail, qint64 imapUid)
126{
127 return assembleMailRid(mail.getFolder(), imapUid);
128}
129
130
106class ImapSynchronizer : public Sink::Synchronizer { 131class ImapSynchronizer : public Sink::Synchronizer {
107public: 132public:
108 ImapSynchronizer(const QByteArray &resourceType, const QByteArray &resourceInstanceIdentifier) 133 ImapSynchronizer(const QByteArray &resourceType, const QByteArray &resourceInstanceIdentifier)
@@ -111,18 +136,17 @@ public:
111 136
112 } 137 }
113 138
114 QByteArray createFolder(const QString &folderPath, const QByteArray &icon) 139 QByteArray createFolder(const QString &folderName, const QString &folderPath, const QString &parentFolderRid, const QByteArray &icon)
115 { 140 {
116 auto remoteId = folderPath.toUtf8(); 141 Trace() << "Creating folder: " << folderName << parentFolderRid;
117 auto bufferType = ENTITY_TYPE_FOLDER; 142 const auto remoteId = folderPath.toUtf8();
143 const auto bufferType = ENTITY_TYPE_FOLDER;
118 Sink::ApplicationDomain::Folder folder; 144 Sink::ApplicationDomain::Folder folder;
119 auto folderPathParts = folderPath.split('/'); 145 folder.setProperty("name", folderName);
120 const auto name = folderPathParts.takeLast();
121 folder.setProperty("name", name);
122 folder.setProperty("icon", icon); 146 folder.setProperty("icon", icon);
123 147
124 if (!folderPathParts.isEmpty()) { 148 if (!parentFolderRid.isEmpty()) {
125 folder.setProperty("parent", syncStore().resolveRemoteId(ENTITY_TYPE_FOLDER, folderPathParts.join('/').toUtf8())); 149 folder.setProperty("parent", syncStore().resolveRemoteId(ENTITY_TYPE_FOLDER, parentFolderRid.toUtf8()));
126 } 150 }
127 createOrModify(bufferType, remoteId, folder); 151 createOrModify(bufferType, remoteId, folder);
128 return remoteId; 152 return remoteId;
@@ -146,9 +170,9 @@ public:
146 }); 170 });
147 }, 171 },
148 [&folderList](const QByteArray &remoteId) -> bool { 172 [&folderList](const QByteArray &remoteId) -> bool {
149 //folderList.contains(remoteId) 173 // folderList.contains(remoteId)
150 for (const auto folderPath : folderList) { 174 for (const auto folderPath : folderList) {
151 if (folderPath.pathParts.join('/') == remoteId) { 175 if (folderPath.path == remoteId) {
152 return true; 176 return true;
153 } 177 }
154 } 178 }
@@ -156,21 +180,11 @@ public:
156 } 180 }
157 ); 181 );
158 182
159 for (const auto folderPath : folderList) { 183 for (const auto &f : folderList) {
160 createFolder(folderPath.pathParts.join('/'), "folder"); 184 createFolder(f.pathParts.last(), f.path, f.parentPath(), "folder");
161 } 185 }
162 } 186 }
163 187
164 static QByteArray remoteIdForMessage(const QString &path, qint64 uid)
165 {
166 return path.toUtf8() + "/" + QByteArray::number(uid);
167 }
168
169 static qint64 uidFromMessageRemoteId(const QByteArray &remoteId)
170 {
171 return remoteId.split('/').last().toLongLong();
172 }
173
174 void synchronizeMails(const QString &path, const QVector<Message> &messages) 188 void synchronizeMails(const QString &path, const QVector<Message> &messages)
175 { 189 {
176 auto time = QSharedPointer<QTime>::create(); 190 auto time = QSharedPointer<QTime>::create();
@@ -184,7 +198,7 @@ public:
184 int count = 0; 198 int count = 0;
185 for (const auto &message : messages) { 199 for (const auto &message : messages) {
186 count++; 200 count++;
187 const auto remoteId = path.toUtf8() + "/" + QByteArray::number(message.uid); 201 const auto remoteId = assembleMailRid(folderLocalId, message.uid);
188 202
189 Trace() << "Found a mail " << remoteId << message.msg->subject(true)->asUnicodeString() << message.flags; 203 Trace() << "Found a mail " << remoteId << message.msg->subject(true)->asUnicodeString() << message.flags;
190 204
@@ -237,7 +251,7 @@ public:
237 }); 251 });
238 }, 252 },
239 [messages, path, &count](const QByteArray &remoteId) -> bool { 253 [messages, path, &count](const QByteArray &remoteId) -> bool {
240 if (messages.contains(uidFromMessageRemoteId(remoteId))) { 254 if (messages.contains(uidFromMailRid(remoteId))) {
241 return true; 255 return true;
242 } 256 }
243 count++; 257 count++;
@@ -330,8 +344,7 @@ public:
330 auto imap = QSharedPointer<ImapServerProxy>::create(mServer, mPort); 344 auto imap = QSharedPointer<ImapServerProxy>::create(mServer, mPort);
331 auto login = imap->login(mUser, mPassword); 345 auto login = imap->login(mUser, mPassword);
332 if (operation == Sink::Operation_Creation) { 346 if (operation == Sink::Operation_Creation) {
333 auto parentRemoteId = syncStore().resolveLocalId("folder", mail.getFolder()); 347 QString mailbox = syncStore().resolveLocalId(ENTITY_TYPE_FOLDER, mail.getFolder());
334 QString mailbox = parentRemoteId;
335 QByteArray content = KMime::LFtoCRLF(mail.getMimeMessage()); 348 QByteArray content = KMime::LFtoCRLF(mail.getMimeMessage());
336 QByteArrayList flags; 349 QByteArrayList flags;
337 if (!mail.getUnread()) { 350 if (!mail.getUnread()) {
@@ -343,19 +356,18 @@ public:
343 QDateTime internalDate = mail.getDate(); 356 QDateTime internalDate = mail.getDate();
344 auto rid = QSharedPointer<QByteArray>::create(); 357 auto rid = QSharedPointer<QByteArray>::create();
345 return login.then(imap->append(mailbox, content, flags, internalDate)) 358 return login.then(imap->append(mailbox, content, flags, internalDate))
346 .then<void, qint64>([imap, mailbox, rid](qint64 uid) { 359 .then<void, qint64>([imap, mailbox, rid, mail](qint64 uid) {
347 const auto remoteId = mailbox.toUtf8() + "/" + QByteArray::number(uid); 360 const auto remoteId = assembleMailRid(mail, uid);
348 //FIXME this get's called after the final error ahndler? WTF? 361 //FIXME this get's called after the final error handler? WTF?
349 Trace() << "Finished creating a new mail: " << remoteId; 362 Trace() << "Finished creating a new mail: " << remoteId;
350 *rid = remoteId; 363 *rid = remoteId;
351 }).then<QByteArray>([rid, imap]() { //FIXME fix KJob so we don't need this extra clause 364 }).then<QByteArray>([rid, imap]() { //FIXME fix KJob so we don't need this extra clause
352 return *rid; 365 return *rid;
353 }); 366 });
354 } else if (operation == Sink::Operation_Removal) { 367 } else if (operation == Sink::Operation_Removal) {
355 auto ridParts = oldRemoteId.split('/'); 368 const auto folderId = folderIdFromMailRid(oldRemoteId);
356 auto uid = ridParts.takeLast().toLongLong(); 369 const QString mailbox = syncStore().resolveLocalId(ENTITY_TYPE_FOLDER, folderId);
357 //FIXME don't hardcode the separator 370 const auto uid = uidFromMailRid(oldRemoteId);
358 auto mailbox = ridParts.join('.');
359 Trace() << "Removing a mail: " << oldRemoteId << "in the mailbox: " << mailbox; 371 Trace() << "Removing a mail: " << oldRemoteId << "in the mailbox: " << mailbox;
360 KIMAP::ImapSet set; 372 KIMAP::ImapSet set;
361 set.add(uid); 373 set.add(uid);
@@ -365,10 +377,9 @@ public:
365 return QByteArray(); 377 return QByteArray();
366 }); 378 });
367 } else if (operation == Sink::Operation_Modification) { 379 } else if (operation == Sink::Operation_Modification) {
368 auto ridParts = oldRemoteId.split('/'); 380 const QString mailbox = syncStore().resolveLocalId(ENTITY_TYPE_FOLDER, mail.getFolder());
369 auto uid = ridParts.takeLast().toLongLong(); 381 const auto uid = uidFromMailRid(oldRemoteId);
370 //FIXME don't hardcode the separator 382
371 auto mailbox = ridParts.join('.');
372 Trace() << "Modifying a mail: " << oldRemoteId << " in the mailbox: " << mailbox << changedProperties; 383 Trace() << "Modifying a mail: " << oldRemoteId << " in the mailbox: " << mailbox << changedProperties;
373 384
374 QByteArrayList flags; 385 QByteArrayList flags;
@@ -387,14 +398,14 @@ public:
387 KIMAP::ImapSet set; 398 KIMAP::ImapSet set;
388 set.add(uid); 399 set.add(uid);
389 return login.then(imap->append(mailbox, content, flags, internalDate)) 400 return login.then(imap->append(mailbox, content, flags, internalDate))
390 .then<void, qint64>([imap, mailbox, rid](qint64 uid) { 401 .then<void, qint64>([imap, mailbox, rid, mail](qint64 uid) {
391 const auto remoteId = mailbox + "/" + QByteArray::number(uid); 402 const auto remoteId = assembleMailRid(mail, uid);
392 Trace() << "Finished creating a modified mail: " << remoteId; 403 Trace() << "Finished creating a modified mail: " << remoteId;
393 *rid = remoteId; 404 *rid = remoteId;
394 }) 405 })
395 .then(imap->remove(mailbox, set)) 406 .then(imap->remove(mailbox, set))
396 .then<QByteArray>([rid, imap]() { 407 .then<QByteArray>([rid, imap]() {
397 return *rid; 408 return *rid;
398 }); 409 });
399 } else { 410 } else {
400 KIMAP::ImapSet set; 411 KIMAP::ImapSet set;
@@ -402,42 +413,34 @@ public:
402 return login.then(imap->select(mailbox)) 413 return login.then(imap->select(mailbox))
403 .then(imap->storeFlags(set, flags)) 414 .then(imap->storeFlags(set, flags))
404 .then<void, qint64>([imap, mailbox](qint64 uid) { 415 .then<void, qint64>([imap, mailbox](qint64 uid) {
405 const auto remoteId = mailbox + "/" + QByteArray::number(uid); 416 Trace() << "Finished modifying mail: " << uid;
406 Trace() << "Finished modifying mail: " << remoteId;
407 }) 417 })
408 .then<QByteArray>([oldRemoteId, imap]() { 418 .then<QByteArray>([oldRemoteId, imap]() {
409 return oldRemoteId; 419 return oldRemoteId;
410 }); 420 });
411 } 421 }
412 } 422 }
413 return KAsync::null<QByteArray>(); 423 return KAsync::null<QByteArray>();
414 } 424 }
415 425
416 QString buildPath(const ApplicationDomain::Folder &folder)
417 {
418 //Don't use entityStore in here, it can produce wrong results we're replaying an older revision than the latest one
419 QChar separator = '/';
420 QString path;
421 auto parent = folder.getParent();
422 if (!parent.isEmpty()) {
423 auto parentRemoteId = syncStore().resolveLocalId("folder", parent);
424 return parentRemoteId + separator.toLatin1() + folder.getName().toUtf8();
425 }
426 return separator + folder.getName();
427 }
428
429 KAsync::Job<QByteArray> replay(const ApplicationDomain::Folder &folder, Sink::Operation operation, const QByteArray &oldRemoteId, const QList<QByteArray> &changedProperties) Q_DECL_OVERRIDE 426 KAsync::Job<QByteArray> replay(const ApplicationDomain::Folder &folder, Sink::Operation operation, const QByteArray &oldRemoteId, const QList<QByteArray> &changedProperties) Q_DECL_OVERRIDE
430 { 427 {
431 auto imap = QSharedPointer<ImapServerProxy>::create(mServer, mPort); 428 auto imap = QSharedPointer<ImapServerProxy>::create(mServer, mPort);
432 auto login = imap->login(mUser, mPassword); 429 auto login = imap->login(mUser, mPassword);
433 if (operation == Sink::Operation_Creation) { 430 if (operation == Sink::Operation_Creation) {
434 auto folderPath = buildPath(folder); 431 QString parentFolder;
435 auto imapPath = "INBOX" + folderPath.replace('/', '.'); 432 if (!folder.getParent().isEmpty()) {
436 Trace() << "Creating a new folder: " << imapPath; 433 parentFolder = syncStore().resolveLocalId(ENTITY_TYPE_FOLDER, folder.getParent());
437 return login.then<void>(imap->create(imapPath)) 434 }
438 .then<QByteArray>([imapPath, imap]() { 435 Trace() << "Creating a new folder: " << parentFolder << folder.getName();
439 Trace() << "Finished creating a new folder: " << imapPath; 436 auto rid = QSharedPointer<QByteArray>::create();
440 return imapPath.toUtf8(); 437 return login.then<QString>(imap->createSubfolder(parentFolder, folder.getName()))
438 .then<void, QString>([imap, rid](const QString &createdFolder) {
439 Trace() << "Finished creating a new folder: " << createdFolder;
440 *rid = createdFolder.toUtf8();
441 })
442 .then<QByteArray>([rid](){
443 return *rid;
441 }); 444 });
442 } else if (operation == Sink::Operation_Removal) { 445 } else if (operation == Sink::Operation_Removal) {
443 Trace() << "Removing a folder: " << oldRemoteId; 446 Trace() << "Removing a folder: " << oldRemoteId;
@@ -447,13 +450,15 @@ public:
447 return QByteArray(); 450 return QByteArray();
448 }); 451 });
449 } else if (operation == Sink::Operation_Modification) { 452 } else if (operation == Sink::Operation_Modification) {
450 auto newFolderPath = buildPath(folder); 453 Trace() << "Renaming a folder: " << oldRemoteId << folder.getName();
451 auto newImapPath = "INBOX" + newFolderPath.replace('/', '.'); 454 auto rid = QSharedPointer<QByteArray>::create();
452 Trace() << "Renaming a folder: " << oldRemoteId << newImapPath; 455 return login.then<QString>(imap->renameSubfolder(oldRemoteId, folder.getName()))
453 return login.then<void>(imap->rename(oldRemoteId, newImapPath)) 456 .then<void, QString>([imap, rid](const QString &createdFolder) {
454 .then<QByteArray>([newImapPath, imap]() { 457 Trace() << "Finished renaming a folder: " << createdFolder;
455 Trace() << "Finished renaming a folder: " << newImapPath; 458 *rid = createdFolder.toUtf8();
456 return newImapPath.toUtf8(); 459 })
460 .then<QByteArray>([rid](){
461 return *rid;
457 }); 462 });
458 } 463 }
459 return KAsync::null<QByteArray>(); 464 return KAsync::null<QByteArray>();
@@ -522,7 +527,7 @@ KAsync::Job<void> ImapResource::inspect(int inspectionType, const QByteArray &in
522 Warning() << "Missing remote id for folder or mail. " << mailRemoteId << folderRemoteId; 527 Warning() << "Missing remote id for folder or mail. " << mailRemoteId << folderRemoteId;
523 return KAsync::error<void>(); 528 return KAsync::error<void>();
524 } 529 }
525 auto uid = mailRemoteId.split('/').last().toLongLong(); 530 const auto uid = uidFromMailRid(mailRemoteId);
526 Trace() << "Mail remote id: " << folderRemoteId << mailRemoteId << mail.identifier() << folder.identifier(); 531 Trace() << "Mail remote id: " << folderRemoteId << mailRemoteId << mail.identifier() << folder.identifier();
527 532
528 KIMAP::ImapSet set; 533 KIMAP::ImapSet set;
@@ -606,7 +611,7 @@ KAsync::Job<void> ImapResource::inspect(int inspectionType, const QByteArray &in
606 })) 611 }))
607 .then<void, KAsync::Job<void>>([imap, messageByUid, expectedCount]() { 612 .then<void, KAsync::Job<void>>([imap, messageByUid, expectedCount]() {
608 if (messageByUid->size() != expectedCount) { 613 if (messageByUid->size() != expectedCount) {
609 return KAsync::error<void>(1, QString("Wrong number of files; found %1 instead of %2.").arg(messageByUid->size()).arg(expectedCount)); 614 return KAsync::error<void>(1, QString("Wrong number of messages on the server; found %1 instead of %2.").arg(messageByUid->size()).arg(expectedCount));
610 } 615 }
611 return KAsync::null<void>(); 616 return KAsync::null<void>();
612 }); 617 });