summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/imapresource/imapresource.cpp151
-rw-r--r--examples/imapresource/imapserverproxy.cpp79
-rw-r--r--examples/imapresource/imapserverproxy.h22
3 files changed, 163 insertions, 89 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 });
diff --git a/examples/imapresource/imapserverproxy.cpp b/examples/imapresource/imapserverproxy.cpp
index 8c12b6c..db68a53 100644
--- a/examples/imapresource/imapserverproxy.cpp
+++ b/examples/imapresource/imapserverproxy.cpp
@@ -21,6 +21,7 @@
21#include <QDir> 21#include <QDir>
22#include <QFile> 22#include <QFile>
23#include <KIMAP/KIMAP/LoginJob> 23#include <KIMAP/KIMAP/LoginJob>
24#include <kimap/namespacejob.h>
24#include <KIMAP/KIMAP/SelectJob> 25#include <KIMAP/KIMAP/SelectJob>
25#include <KIMAP/KIMAP/AppendJob> 26#include <KIMAP/KIMAP/AppendJob>
26#include <KIMAP/KIMAP/CreateJob> 27#include <KIMAP/KIMAP/CreateJob>
@@ -98,15 +99,33 @@ KAsync::Job<void> ImapServerProxy::login(const QString &username, const QString
98 QObject::connect(capabilitiesJob, &KIMAP::CapabilitiesJob::capabilitiesReceived, [this](const QStringList &capabilities) { 99 QObject::connect(capabilitiesJob, &KIMAP::CapabilitiesJob::capabilitiesReceived, [this](const QStringList &capabilities) {
99 mCapabilities = capabilities; 100 mCapabilities = capabilities;
100 }); 101 });
102 auto namespaceJob = new KIMAP::NamespaceJob(mSession);
103
101 return runJob(loginJob).then(runJob(capabilitiesJob)).then<void>([this](){ 104 return runJob(loginJob).then(runJob(capabilitiesJob)).then<void>([this](){
102 Trace() << "Supported capabilities: " << mCapabilities; 105 Trace() << "Supported capabilities: " << mCapabilities;
103 QStringList requiredExtensions = QStringList() << "UIDPLUS"; 106 QStringList requiredExtensions = QStringList() << "UIDPLUS" << "NAMESPACE";
104 for (const auto &requiredExtension : requiredExtensions) { 107 for (const auto &requiredExtension : requiredExtensions) {
105 if (!mCapabilities.contains(requiredExtension)) { 108 if (!mCapabilities.contains(requiredExtension)) {
106 Warning() << "Server doesn't support required capability: " << requiredExtension; 109 Warning() << "Server doesn't support required capability: " << requiredExtension;
107 //TODO fail the job 110 //TODO fail the job
108 } 111 }
109 } 112 }
113 }).then(runJob(namespaceJob)).then<void>([this, namespaceJob](){
114 for (const auto &ns :namespaceJob->personalNamespaces()) {
115 mPersonalNamespaces << ns.name;
116 mPersonalNamespaceSeparator = ns.separator;
117 }
118 for (const auto &ns :namespaceJob->sharedNamespaces()) {
119 mSharedNamespaces << ns.name;
120 mSharedNamespaceSeparator = ns.separator;
121 }
122 for (const auto &ns :namespaceJob->userNamespaces()) {
123 mUserNamespaces << ns.name;
124 mUserNamespaceSeparator = ns.separator;
125 }
126 Trace() << "Found personal namespaces: " << mPersonalNamespaces << mPersonalNamespaceSeparator;
127 Trace() << "Found shared namespaces: " << mSharedNamespaces << mSharedNamespaceSeparator;
128 Trace() << "Found user namespaces: " << mUserNamespaces << mUserNamespaceSeparator;
110 }); 129 });
111} 130}
112 131
@@ -271,16 +290,6 @@ KAsync::Job<void> ImapServerProxy::list(KIMAP::ListJob::Option option, const std
271 // listJob->setQueriedNamespaces(serverNamespaces()); 290 // listJob->setQueriedNamespaces(serverNamespaces());
272 QObject::connect(listJob, &KIMAP::ListJob::mailBoxesReceived, 291 QObject::connect(listJob, &KIMAP::ListJob::mailBoxesReceived,
273 listJob, callback); 292 listJob, callback);
274 //Figure out the separator character on the first list issued.
275 if (mSeparatorCharacter.isNull()) {
276 QObject::connect(listJob, &KIMAP::ListJob::mailBoxesReceived,
277 listJob, [this](const QList<KIMAP::MailBoxDescriptor> &mailboxes,const QList<QList<QByteArray> > &flags) {
278 if (!mailboxes.isEmpty() && mSeparatorCharacter.isNull()) {
279 mSeparatorCharacter = mailboxes.first().separator;
280 }
281 }
282 );
283 }
284 return runJob(listJob); 293 return runJob(listJob);
285} 294}
286 295
@@ -295,6 +304,40 @@ KAsync::Job<void> ImapServerProxy::remove(const QString &mailbox, const QByteArr
295 return remove(mailbox, set); 304 return remove(mailbox, set);
296} 305}
297 306
307KAsync::Job<QString> ImapServerProxy::createSubfolder(const QString &parentMailbox, const QString &folderName)
308{
309 auto folder = QSharedPointer<QString>::create();
310 return KAsync::start<void, KAsync::Job<void>>([this, parentMailbox, folderName, folder]() {
311 Q_ASSERT(!mPersonalNamespaceSeparator.isNull());
312 if (parentMailbox.isEmpty()) {
313 *folder = mPersonalNamespaces.toList().first() + folderName;
314 } else {
315 *folder = parentMailbox + mPersonalNamespaceSeparator + folderName;
316 }
317 Trace() << "Creating subfolder: " << *folder;
318 return create(*folder);
319 })
320 .then<QString>([=]() {
321 return *folder;
322 });
323}
324
325KAsync::Job<QString> ImapServerProxy::renameSubfolder(const QString &oldMailbox, const QString &newName)
326{
327 auto folder = QSharedPointer<QString>::create();
328 return KAsync::start<void, KAsync::Job<void>>([this, oldMailbox, newName, folder]() {
329 Q_ASSERT(!mPersonalNamespaceSeparator.isNull());
330 auto parts = oldMailbox.split(mPersonalNamespaceSeparator);
331 parts.removeLast();
332 *folder = parts.join(mPersonalNamespaceSeparator) + mPersonalNamespaceSeparator + newName;
333 Trace() << "Renaming subfolder: " << oldMailbox << *folder;
334 return rename(oldMailbox, *folder);
335 })
336 .then<QString>([=]() {
337 return *folder;
338 });
339}
340
298KAsync::Job<void> ImapServerProxy::fetchFolders(std::function<void(const QVector<Folder> &)> callback) 341KAsync::Job<void> ImapServerProxy::fetchFolders(std::function<void(const QVector<Folder> &)> callback)
299{ 342{
300 Trace() << "Fetching folders"; 343 Trace() << "Fetching folders";
@@ -302,17 +345,23 @@ KAsync::Job<void> ImapServerProxy::fetchFolders(std::function<void(const QVector
302 QVector<Folder> list; 345 QVector<Folder> list;
303 for (const auto &mailbox : mailboxes) { 346 for (const auto &mailbox : mailboxes) {
304 Trace() << "Found mailbox: " << mailbox.name; 347 Trace() << "Found mailbox: " << mailbox.name;
305 list << Folder{mailbox.name.split(mailbox.separator)}; 348 list << Folder{mailbox.name.split(mailbox.separator), mailbox.name, mailbox.separator};
306 } 349 }
307 callback(list); 350 callback(list);
308 }); 351 });
309} 352}
310 353
354QString ImapServerProxy::mailboxFromFolder(const Folder &folder) const
355{
356 Q_ASSERT(!mPersonalNamespaceSeparator.isNull());
357 return folder.pathParts.join(mPersonalNamespaceSeparator);
358}
359
311KAsync::Job<void> ImapServerProxy::fetchMessages(const Folder &folder, std::function<void(const QVector<Message> &)> callback) 360KAsync::Job<void> ImapServerProxy::fetchMessages(const Folder &folder, std::function<void(const QVector<Message> &)> callback)
312{ 361{
313 Q_ASSERT(!mSeparatorCharacter.isNull()); 362 Q_ASSERT(!mPersonalNamespaceSeparator.isNull());
314 return select(folder.pathParts.join(mSeparatorCharacter)).then<void, KAsync::Job<void>>([this, callback, folder]() -> KAsync::Job<void> { 363 return select(mailboxFromFolder(folder)).then<void, KAsync::Job<void>>([this, callback, folder]() -> KAsync::Job<void> {
315 return fetchHeaders(folder.pathParts.join(mSeparatorCharacter)).then<void, KAsync::Job<void>, QList<qint64>>([this, callback](const QList<qint64> &uidsToFetch){ 364 return fetchHeaders(mailboxFromFolder(folder)).then<void, KAsync::Job<void>, QList<qint64>>([this, callback](const QList<qint64> &uidsToFetch){
316 Trace() << "Uids to fetch: " << uidsToFetch; 365 Trace() << "Uids to fetch: " << uidsToFetch;
317 if (uidsToFetch.isEmpty()) { 366 if (uidsToFetch.isEmpty()) {
318 Trace() << "Nothing to fetch"; 367 Trace() << "Nothing to fetch";
diff --git a/examples/imapresource/imapserverproxy.h b/examples/imapresource/imapserverproxy.h
index 05409c5..67ff000 100644
--- a/examples/imapresource/imapserverproxy.h
+++ b/examples/imapresource/imapserverproxy.h
@@ -54,13 +54,29 @@ struct Folder {
54 return pathParts.join('/'); 54 return pathParts.join('/');
55 } 55 }
56 56
57 QString parentPath() const
58 {
59 auto parts = pathParts;
60 parts.removeLast();
61 return parts.join(separator);
62 }
63
57 QList<QString> pathParts; 64 QList<QString> pathParts;
65 QString path;
66 QChar separator;
58}; 67};
59 68
60class ImapServerProxy { 69class ImapServerProxy {
61 KIMAP::Session *mSession; 70 KIMAP::Session *mSession;
62 QChar mSeparatorCharacter;
63 QStringList mCapabilities; 71 QStringList mCapabilities;
72
73 QSet<QString> mPersonalNamespaces;
74 QChar mPersonalNamespaceSeparator;
75 QSet<QString> mSharedNamespaces;
76 QChar mSharedNamespaceSeparator;
77 QSet<QString> mUserNamespaces;
78 QChar mUserNamespaceSeparator;
79
64public: 80public:
65 ImapServerProxy(const QString &serverUrl, int port); 81 ImapServerProxy(const QString &serverUrl, int port);
66 82
@@ -93,6 +109,10 @@ public:
93 KAsync::Job<QList<qint64>> fetchHeaders(const QString &mailbox); 109 KAsync::Job<QList<qint64>> fetchHeaders(const QString &mailbox);
94 KAsync::Job<void> remove(const QString &mailbox, const KIMAP::ImapSet &set); 110 KAsync::Job<void> remove(const QString &mailbox, const KIMAP::ImapSet &set);
95 KAsync::Job<void> remove(const QString &mailbox, const QByteArray &imapSet); 111 KAsync::Job<void> remove(const QString &mailbox, const QByteArray &imapSet);
112 KAsync::Job<QString> createSubfolder(const QString &parentMailbox, const QString &folderName);
113 KAsync::Job<QString> renameSubfolder(const QString &mailbox, const QString &newName);
114
115 QString mailboxFromFolder(const Folder &) const;
96 116
97 KAsync::Job<void> fetchFolders(std::function<void(const QVector<Folder> &)> callback); 117 KAsync::Job<void> fetchFolders(std::function<void(const QVector<Folder> &)> callback);
98 KAsync::Job<void> fetchMessages(const Folder &folder, std::function<void(const QVector<Message> &)> callback); 118 KAsync::Job<void> fetchMessages(const Folder &folder, std::function<void(const QVector<Message> &)> callback);