summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/imapresource/imapresource.cpp37
-rw-r--r--examples/imapresource/imapresource.h8
-rw-r--r--examples/imapresource/imapserverproxy.cpp26
-rw-r--r--examples/imapresource/imapserverproxy.h13
-rw-r--r--examples/imapresource/tests/imapresourcetest.cpp27
-rw-r--r--examples/imapresource/tests/imapserverproxytest.cpp6
-rw-r--r--examples/imapresource/tests/resetmailbox.sh6
7 files changed, 93 insertions, 30 deletions
diff --git a/examples/imapresource/imapresource.cpp b/examples/imapresource/imapresource.cpp
index baa88b9..49cbb20 100644
--- a/examples/imapresource/imapresource.cpp
+++ b/examples/imapresource/imapresource.cpp
@@ -49,6 +49,7 @@
49#undef DEBUG_AREA 49#undef DEBUG_AREA
50#define DEBUG_AREA "resource.imap" 50#define DEBUG_AREA "resource.imap"
51 51
52using namespace Imap;
52 53
53ImapResource::ImapResource(const QByteArray &instanceIdentifier, const QSharedPointer<Sink::Pipeline> &pipeline) 54ImapResource::ImapResource(const QByteArray &instanceIdentifier, const QSharedPointer<Sink::Pipeline> &pipeline)
54 : Sink::GenericResource(instanceIdentifier, pipeline), 55 : Sink::GenericResource(instanceIdentifier, pipeline),
@@ -71,20 +72,22 @@ QByteArray ImapResource::createFolder(const QString &folderPath, const QByteArra
71 auto remoteId = folderPath.toUtf8(); 72 auto remoteId = folderPath.toUtf8();
72 auto bufferType = ENTITY_TYPE_FOLDER; 73 auto bufferType = ENTITY_TYPE_FOLDER;
73 Sink::ApplicationDomain::Folder folder; 74 Sink::ApplicationDomain::Folder folder;
74 folder.setProperty("name", folderPath.split('/').last()); 75 auto folderPathParts = folderPath.split('/');
76 const auto name = folderPathParts.takeLast();
77 folder.setProperty("name", name);
75 folder.setProperty("icon", icon); 78 folder.setProperty("icon", icon);
76 79
77 // if (!md.isRoot()) { 80 if (!folderPathParts.isEmpty()) {
78 // folder.setProperty("parent", resolveRemoteId(ENTITY_TYPE_FOLDER, md.parent().path().toUtf8(), synchronizationTransaction)); 81 folder.setProperty("parent", resolveRemoteId(ENTITY_TYPE_FOLDER, folderPathParts.join('/').toUtf8(), synchronizationTransaction));
79 // } 82 }
80 createOrModify(transaction, synchronizationTransaction, *mFolderAdaptorFactory, bufferType, remoteId, folder); 83 createOrModify(transaction, synchronizationTransaction, *mFolderAdaptorFactory, bufferType, remoteId, folder);
81 return remoteId; 84 return remoteId;
82} 85}
83 86
84void ImapResource::synchronizeFolders(const QStringList &folderList, Sink::Storage::Transaction &transaction, Sink::Storage::Transaction &synchronizationTransaction) 87void ImapResource::synchronizeFolders(const QVector<Folder> &folderList, Sink::Storage::Transaction &transaction, Sink::Storage::Transaction &synchronizationTransaction)
85{ 88{
86 const QByteArray bufferType = ENTITY_TYPE_FOLDER; 89 const QByteArray bufferType = ENTITY_TYPE_FOLDER;
87 Trace() << "Found folders " << folderList; 90 Trace() << "Found folders " << folderList.size();
88 91
89 scanForRemovals(transaction, synchronizationTransaction, bufferType, 92 scanForRemovals(transaction, synchronizationTransaction, bufferType,
90 [&bufferType, &transaction](const std::function<void(const QByteArray &)> &callback) { 93 [&bufferType, &transaction](const std::function<void(const QByteArray &)> &callback) {
@@ -99,12 +102,18 @@ void ImapResource::synchronizeFolders(const QStringList &folderList, Sink::Stora
99 }); 102 });
100 }, 103 },
101 [&folderList](const QByteArray &remoteId) -> bool { 104 [&folderList](const QByteArray &remoteId) -> bool {
102 return folderList.contains(remoteId); 105 //folderList.contains(remoteId)
106 for (const auto folderPath : folderList) {
107 if (folderPath.pathParts.join('/') == remoteId) {
108 return true;
109 }
110 }
111 return false;
103 } 112 }
104 ); 113 );
105 114
106 for (const auto folderPath : folderList) { 115 for (const auto folderPath : folderList) {
107 createFolder(folderPath, "folder", transaction, synchronizationTransaction); 116 createFolder(folderPath.pathParts.join('/'), "folder", transaction, synchronizationTransaction);
108 } 117 }
109} 118}
110 119
@@ -176,9 +185,8 @@ KAsync::Job<void> ImapResource::synchronizeWithSource(Sink::Storage &mainStore,
176 Log() << " Synchronizing"; 185 Log() << " Synchronizing";
177 return KAsync::start<void>([this, &mainStore, &synchronizationStore](KAsync::Future<void> future) { 186 return KAsync::start<void>([this, &mainStore, &synchronizationStore](KAsync::Future<void> future) {
178 ImapServerProxy imap(mServer, mPort); 187 ImapServerProxy imap(mServer, mPort);
179 QStringList folderList; 188 QVector<Folder> folderList;
180 // QList<KAsync::Future<void>> waitCondition; 189 auto folderFuture = imap.fetchFolders([this, &imap, &mainStore, &synchronizationStore, &folderList](const QVector<Folder> &folders) {
181 auto folderFuture = imap.fetchFolders([this, &imap, &mainStore, &synchronizationStore, &folderList](const QStringList &folders) {
182 auto transaction = mainStore.createTransaction(Sink::Storage::ReadOnly); 190 auto transaction = mainStore.createTransaction(Sink::Storage::ReadOnly);
183 auto syncTransaction = synchronizationStore.createTransaction(Sink::Storage::ReadWrite); 191 auto syncTransaction = synchronizationStore.createTransaction(Sink::Storage::ReadWrite);
184 synchronizeFolders(folders, transaction, syncTransaction); 192 synchronizeFolders(folders, transaction, syncTransaction);
@@ -215,16 +223,17 @@ KAsync::Job<void> ImapResource::synchronizeWithSource(Sink::Storage &mainStore,
215 auto messagesFuture = imap.fetchMessages(folder, [this, &mainStore, &synchronizationStore, folder](const QVector<Message> &messages) { 223 auto messagesFuture = imap.fetchMessages(folder, [this, &mainStore, &synchronizationStore, folder](const QVector<Message> &messages) {
216 auto transaction = mainStore.createTransaction(Sink::Storage::ReadOnly); 224 auto transaction = mainStore.createTransaction(Sink::Storage::ReadOnly);
217 auto syncTransaction = synchronizationStore.createTransaction(Sink::Storage::ReadWrite); 225 auto syncTransaction = synchronizationStore.createTransaction(Sink::Storage::ReadWrite);
218 Trace() << "Synchronizing mails" << folder; 226 Trace() << "Synchronizing mails" << folder.pathParts.join('/');
219 synchronizeMails(transaction, syncTransaction, folder, messages); 227 synchronizeMails(transaction, syncTransaction, folder.pathParts.join('/'), messages);
220 transaction.commit(); 228 transaction.commit();
221 syncTransaction.commit(); 229 syncTransaction.commit();
222 }); 230 });
223 messagesFuture.waitForFinished(); 231 messagesFuture.waitForFinished();
224 if (messagesFuture.errorCode()) { 232 if (messagesFuture.errorCode()) {
225 future.setError(1, "Folder sync failed: " + folder); 233 future.setError(1, "Folder sync failed: " + folder.pathParts.join('/'));
226 return; 234 return;
227 } 235 }
236 Trace() << "Folder synchronized: " << folder.pathParts.join('/');
228 } 237 }
229 238
230 239
diff --git a/examples/imapresource/imapresource.h b/examples/imapresource/imapresource.h
index 6fe15dd..23b7e1a 100644
--- a/examples/imapresource/imapresource.h
+++ b/examples/imapresource/imapresource.h
@@ -30,7 +30,11 @@
30 30
31class ImapMailAdaptorFactory; 31class ImapMailAdaptorFactory;
32class ImapFolderAdaptorFactory; 32class ImapFolderAdaptorFactory;
33
34namespace Imap {
33struct Message; 35struct Message;
36struct Folder;
37}
34 38
35/** 39/**
36 * An imap resource. 40 * An imap resource.
@@ -46,8 +50,8 @@ private:
46 KAsync::Job<void> replay(Sink::Storage &synchronizationStore, const QByteArray &type, const QByteArray &key, const QByteArray &value) Q_DECL_OVERRIDE; 50 KAsync::Job<void> replay(Sink::Storage &synchronizationStore, const QByteArray &type, const QByteArray &key, const QByteArray &value) Q_DECL_OVERRIDE;
47 51
48 QByteArray createFolder(const QString &folderPath, const QByteArray &icon, Sink::Storage::Transaction &transaction, Sink::Storage::Transaction &synchronizationTransaction); 52 QByteArray createFolder(const QString &folderPath, const QByteArray &icon, Sink::Storage::Transaction &transaction, Sink::Storage::Transaction &synchronizationTransaction);
49 void synchronizeFolders(const QStringList &folderList, Sink::Storage::Transaction &transaction, Sink::Storage::Transaction &synchronizationTransaction); 53 void synchronizeFolders(const QVector<Imap::Folder> &folderList, Sink::Storage::Transaction &transaction, Sink::Storage::Transaction &synchronizationTransaction);
50 void synchronizeMails(Sink::Storage::Transaction &transaction, Sink::Storage::Transaction &synchronizationTransaction, const QString &path, const QVector<Message> &messages); 54 void synchronizeMails(Sink::Storage::Transaction &transaction, Sink::Storage::Transaction &synchronizationTransaction, const QString &path, const QVector<Imap::Message> &messages);
51 55
52 QSharedPointer<ImapMailAdaptorFactory> mMailAdaptorFactory; 56 QSharedPointer<ImapMailAdaptorFactory> mMailAdaptorFactory;
53 QSharedPointer<ImapFolderAdaptorFactory> mFolderAdaptorFactory; 57 QSharedPointer<ImapFolderAdaptorFactory> mFolderAdaptorFactory;
diff --git a/examples/imapresource/imapserverproxy.cpp b/examples/imapresource/imapserverproxy.cpp
index 9630096..836a9bc 100644
--- a/examples/imapresource/imapserverproxy.cpp
+++ b/examples/imapresource/imapserverproxy.cpp
@@ -23,12 +23,15 @@
23#include <KIMAP/KIMAP/LoginJob> 23#include <KIMAP/KIMAP/LoginJob>
24#include <KIMAP/KIMAP/SelectJob> 24#include <KIMAP/KIMAP/SelectJob>
25#include <KIMAP/KIMAP/AppendJob> 25#include <KIMAP/KIMAP/AppendJob>
26#include <KIMAP/KIMAP/CreateJob>
26 27
27#include <KIMAP/KIMAP/SessionUiProxy> 28#include <KIMAP/KIMAP/SessionUiProxy>
28#include <KCoreAddons/KJob> 29#include <KCoreAddons/KJob>
29 30
30#include "log.h" 31#include "log.h"
31 32
33using namespace Imap;
34
32static KAsync::Job<void> runJob(KJob *job) 35static KAsync::Job<void> runJob(KJob *job)
33{ 36{
34 return KAsync::start<void>([job](KAsync::Future<void> &future) { 37 return KAsync::start<void>([job](KAsync::Future<void> &future) {
@@ -94,6 +97,16 @@ KAsync::Job<void> ImapServerProxy::append(const QString &mailbox, const QByteArr
94 return runJob(append); 97 return runJob(append);
95} 98}
96 99
100KAsync::Job<void> ImapServerProxy::create(const QString &mailbox)
101{
102 if (mSession->state() == KIMAP::Session::State::Disconnected) {
103 return KAsync::error<void>(1, "Not connected");
104 }
105 auto create = new KIMAP::CreateJob(mSession);
106 create->setMailBox(mailbox);
107 return runJob(create);
108}
109
97KAsync::Job<void> ImapServerProxy::fetch(const KIMAP::ImapSet &set, KIMAP::FetchJob::FetchScope scope, FetchCallback callback) 110KAsync::Job<void> ImapServerProxy::fetch(const KIMAP::ImapSet &set, KIMAP::FetchJob::FetchScope scope, FetchCallback callback)
98{ 111{
99 if (mSession->state() == KIMAP::Session::State::Disconnected) { 112 if (mSession->state() == KIMAP::Session::State::Disconnected) {
@@ -154,14 +167,14 @@ KAsync::Job<void> ImapServerProxy::list(KIMAP::ListJob::Option option, const std
154 return runJob(listJob); 167 return runJob(listJob);
155} 168}
156 169
157KAsync::Future<void> ImapServerProxy::fetchFolders(std::function<void(const QStringList &)> callback) 170KAsync::Future<void> ImapServerProxy::fetchFolders(std::function<void(const QVector<Folder> &)> callback)
158{ 171{
159 Trace() << "Fetching folders"; 172 Trace() << "Fetching folders";
160 auto job = login("doe", "doe").then<void>(list(KIMAP::ListJob::IncludeUnsubscribed, [callback](const QList<KIMAP::MailBoxDescriptor> &mailboxes, const QList<QList<QByteArray> > &flags){ 173 auto job = login("doe", "doe").then<void>(list(KIMAP::ListJob::IncludeUnsubscribed, [callback](const QList<KIMAP::MailBoxDescriptor> &mailboxes, const QList<QList<QByteArray> > &flags){
161 QStringList list; 174 QVector<Folder> list;
162 for (const auto &mailbox : mailboxes) { 175 for (const auto &mailbox : mailboxes) {
163 Trace() << "Found mailbox: " << mailbox.name; 176 Trace() << "Found mailbox: " << mailbox.name;
164 list << mailbox.name; 177 list << Folder{mailbox.name.split(mailbox.separator)};
165 } 178 }
166 callback(list); 179 callback(list);
167 }), 180 }),
@@ -171,10 +184,11 @@ KAsync::Future<void> ImapServerProxy::fetchFolders(std::function<void(const QStr
171 return job.exec(); 184 return job.exec();
172} 185}
173 186
174KAsync::Future<void> ImapServerProxy::fetchMessages(const QString &folder, std::function<void(const QVector<Message> &)> callback) 187KAsync::Future<void> ImapServerProxy::fetchMessages(const Folder &folder, std::function<void(const QVector<Message> &)> callback)
175{ 188{
176 auto job = login("doe", "doe").then<void>(select(folder)).then<void, KAsync::Job<void>>([this, callback, folder]() -> KAsync::Job<void> { 189 //TODO use the right separator
177 return fetchHeaders(folder).then<void, KAsync::Job<void>, QList<qint64>>([this, callback](const QList<qint64> &uidsToFetch){ 190 auto job = login("doe", "doe").then<void>(select(folder.pathParts.join('.'))).then<void, KAsync::Job<void>>([this, callback, folder]() -> KAsync::Job<void> {
191 return fetchHeaders(folder.pathParts.join('.')).then<void, KAsync::Job<void>, QList<qint64>>([this, callback](const QList<qint64> &uidsToFetch){
178 Trace() << "Uids to fetch: " << uidsToFetch; 192 Trace() << "Uids to fetch: " << uidsToFetch;
179 if (uidsToFetch.isEmpty()) { 193 if (uidsToFetch.isEmpty()) {
180 Trace() << "Nothing to fetch"; 194 Trace() << "Nothing to fetch";
diff --git a/examples/imapresource/imapserverproxy.h b/examples/imapresource/imapserverproxy.h
index 2beb28c..475a45d 100644
--- a/examples/imapresource/imapserverproxy.h
+++ b/examples/imapresource/imapserverproxy.h
@@ -26,6 +26,8 @@
26#include <KIMAP/KIMAP/Session> 26#include <KIMAP/KIMAP/Session>
27#include <KIMAP/KIMAP/FetchJob> 27#include <KIMAP/KIMAP/FetchJob>
28 28
29namespace Imap {
30
29struct Message { 31struct Message {
30 qint64 uid; 32 qint64 uid;
31 qint64 size; 33 qint64 size;
@@ -34,6 +36,10 @@ struct Message {
34 KMime::Message::Ptr msg; 36 KMime::Message::Ptr msg;
35}; 37};
36 38
39struct Folder {
40 QList<QString> pathParts;
41};
42
37class ImapServerProxy { 43class ImapServerProxy {
38 KIMAP::Session *mSession; 44 KIMAP::Session *mSession;
39public: 45public:
@@ -43,6 +49,7 @@ public:
43 KAsync::Job<void> login(const QString &username, const QString &password); 49 KAsync::Job<void> login(const QString &username, const QString &password);
44 KAsync::Job<void> select(const QString &mailbox); 50 KAsync::Job<void> select(const QString &mailbox);
45 KAsync::Job<void> append(const QString &mailbox, const QByteArray &content, const QList<QByteArray> &flags = QList<QByteArray>(), const QDateTime &internalDate = QDateTime()); 51 KAsync::Job<void> append(const QString &mailbox, const QByteArray &content, const QList<QByteArray> &flags = QList<QByteArray>(), const QDateTime &internalDate = QDateTime());
52 KAsync::Job<void> create(const QString &mailbox);
46 53
47 typedef std::function<void(const QString &, 54 typedef std::function<void(const QString &,
48 const QMap<qint64,qint64> &, 55 const QMap<qint64,qint64> &,
@@ -57,6 +64,8 @@ public:
57 //Composed calls that do login etc. 64 //Composed calls that do login etc.
58 KAsync::Job<QList<qint64>> fetchHeaders(const QString &mailbox); 65 KAsync::Job<QList<qint64>> fetchHeaders(const QString &mailbox);
59 66
60 KAsync::Future<void> fetchFolders(std::function<void(const QStringList &)> callback); 67 KAsync::Future<void> fetchFolders(std::function<void(const QVector<Folder> &)> callback);
61 KAsync::Future<void> fetchMessages(const QString &folder, std::function<void(const QVector<Message> &)> callback); 68 KAsync::Future<void> fetchMessages(const Folder &folder, std::function<void(const QVector<Message> &)> callback);
62}; 69};
70
71}
diff --git a/examples/imapresource/tests/imapresourcetest.cpp b/examples/imapresource/tests/imapresourcetest.cpp
index d8fc46e..8ce32c2 100644
--- a/examples/imapresource/tests/imapresourcetest.cpp
+++ b/examples/imapresource/tests/imapresourcetest.cpp
@@ -100,7 +100,32 @@ private slots:
100 names << folder->getName(); 100 names << folder->getName();
101 } 101 }
102 QVERIFY(names.contains("INBOX")); 102 QVERIFY(names.contains("INBOX"));
103 QVERIFY(names.contains("INBOX.test")); 103 QVERIFY(names.contains("test"));
104 });
105 VERIFYEXEC(job);
106 }
107
108 void testListFolderHierarchy()
109 {
110 Sink::Query query;
111 query.resources << "org.kde.imap.instance1";
112 query.request<Folder::Name>().request<Folder::Parent>();
113
114 Imap::ImapServerProxy imap("localhost", 993);
115 VERIFYEXEC(imap.login("doe", "doe"));
116 VERIFYEXEC(imap.create("INBOX.test.sub"));
117
118 // Ensure all local data is processed
119 VERIFYEXEC(Store::synchronize(query));
120 ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished();
121
122 auto job = Store::fetchAll<Folder>(query).then<void, QList<Folder::Ptr>>([](const QList<Folder::Ptr> &folders) {
123 QCOMPARE(folders.size(), 3);
124 QHash<QString, Folder::Ptr> map;
125 for (const auto &folder : folders) {
126 map.insert(folder->getName(), folder);
127 }
128 QCOMPARE(map.value("sub")->getParent(), map.value("test")->identifier());
104 }); 129 });
105 VERIFYEXEC(job); 130 VERIFYEXEC(job);
106 } 131 }
diff --git a/examples/imapresource/tests/imapserverproxytest.cpp b/examples/imapresource/tests/imapserverproxytest.cpp
index d13a937..139597a 100644
--- a/examples/imapresource/tests/imapserverproxytest.cpp
+++ b/examples/imapresource/tests/imapserverproxytest.cpp
@@ -36,6 +36,8 @@ do {\
36 return;\ 36 return;\
37} while (0) 37} while (0)
38 38
39using namespace Imap;
40
39/** 41/**
40 */ 42 */
41class ImapServerProxyTest : public QObject 43class ImapServerProxyTest : public QObject
@@ -77,7 +79,7 @@ private slots:
77 void testFetchFolders() 79 void testFetchFolders()
78 { 80 {
79 ImapServerProxy imap("localhost", 993); 81 ImapServerProxy imap("localhost", 993);
80 auto future = imap.fetchFolders([](const QStringList &){}); 82 auto future = imap.fetchFolders([](const QVector<Folder> &){});
81 future.waitForFinished(); 83 future.waitForFinished();
82 QVERIFY(!future.errorCode()); 84 QVERIFY(!future.errorCode());
83 } 85 }
@@ -85,7 +87,7 @@ private slots:
85 void testFetchFoldersFailure() 87 void testFetchFoldersFailure()
86 { 88 {
87 ImapServerProxy imap("foobar", 993); 89 ImapServerProxy imap("foobar", 993);
88 auto future = imap.fetchFolders([](const QStringList &){}); 90 auto future = imap.fetchFolders([](const QVector<Folder> &){});
89 auto future2 = future; 91 auto future2 = future;
90 future2.waitForFinished(); 92 future2.waitForFinished();
91 QVERIFY(future2.errorCode()); 93 QVERIFY(future2.errorCode());
diff --git a/examples/imapresource/tests/resetmailbox.sh b/examples/imapresource/tests/resetmailbox.sh
index 966115a..fc78f60 100644
--- a/examples/imapresource/tests/resetmailbox.sh
+++ b/examples/imapresource/tests/resetmailbox.sh
@@ -1,9 +1,9 @@
1#!/bin/bash 1#!/bin/bash
2 2
3sudo echo "dm user.doe.test" | cyradm --auth PLAIN -u cyrus -w admin localhost 3sudo echo "sam user.doe.* cyrus c" | cyradm --auth PLAIN -u cyrus -w admin localhost
4sudo echo "dm user.doe.*" | cyradm --auth PLAIN -u cyrus -w admin localhost
4sudo echo "cm user.doe.test" | cyradm --auth PLAIN -u cyrus -w admin localhost 5sudo echo "cm user.doe.test" | cyradm --auth PLAIN -u cyrus -w admin localhost
5sudo echo "sam user.doe cyrus c" | cyradm --auth PLAIN -u cyrus -w admin localhost 6sudo echo "sam user.doe cyrus c" | cyradm --auth PLAIN -u cyrus -w admin localhost
6sudo echo "sam user.doe.test cyrus c" | cyradm --auth PLAIN -u cyrus -w admin localhost
7# sudo rm -R /var/spool/imap/d/user/doe/* 7# sudo rm -R /var/spool/imap/d/user/doe/*
8sudo cp /work/source/Sink/tests/data/maildir1/cur/1365777830.R28.localhost.localdomain\:2\,S /var/spool/imap/d/user/doe/test/1. 8sudo cp /work/source/Sink/tests/data/maildir1/cur/1365777830.R28.localhost.localdomain\:2\,S /var/spool/imap/d/user/doe/test/1.
9sudo chown cyrus:mail /var/spool/imap/d/user/doe/test/1. 9sudo chown cyrus:mail /var/spool/imap/d/user/doe/test/1.