summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Mollekopf <chrigi_1@fastmail.fm>2017-02-08 14:09:43 +0100
committerChristian Mollekopf <chrigi_1@fastmail.fm>2017-02-08 14:09:43 +0100
commita41d7ee237918584ea45405d20dee4f680fe7071 (patch)
treeaa87ba170b2f5b5e9f67254dd598193cd4c15987
parenta21368827de7a2d70ef2a260cb35c25fcf5967e8 (diff)
downloadsink-a41d7ee237918584ea45405d20dee4f680fe7071.tar.gz
sink-a41d7ee237918584ea45405d20dee4f680fe7071.zip
Added session cache.
So we can avoid logging in for every command.
-rw-r--r--examples/imapresource/imapresource.cpp9
-rw-r--r--examples/imapresource/imapserverproxy.cpp83
-rw-r--r--examples/imapresource/imapserverproxy.h87
3 files changed, 125 insertions, 54 deletions
diff --git a/examples/imapresource/imapresource.cpp b/examples/imapresource/imapresource.cpp
index 06dc340..04cedff 100644
--- a/examples/imapresource/imapresource.cpp
+++ b/examples/imapresource/imapresource.cpp
@@ -89,6 +89,7 @@ static QByteArray parentRid(const Imap::Folder &folder)
89 89
90 90
91class ImapSynchronizer : public Sink::Synchronizer { 91class ImapSynchronizer : public Sink::Synchronizer {
92 Q_OBJECT
92public: 93public:
93 ImapSynchronizer(const ResourceContext &resourceContext) 94 ImapSynchronizer(const ResourceContext &resourceContext)
94 : Sink::Synchronizer(resourceContext) 95 : Sink::Synchronizer(resourceContext)
@@ -432,7 +433,7 @@ public:
432 433
433 KAsync::Job<void> synchronizeWithSource(const Sink::QueryBase &query) Q_DECL_OVERRIDE 434 KAsync::Job<void> synchronizeWithSource(const Sink::QueryBase &query) Q_DECL_OVERRIDE
434 { 435 {
435 auto imap = QSharedPointer<ImapServerProxy>::create(mServer, mPort); 436 auto imap = QSharedPointer<ImapServerProxy>::create(mServer, mPort, &mSessionCache);
436 if (query.type() == ApplicationDomain::getTypeName<ApplicationDomain::Folder>()) { 437 if (query.type() == ApplicationDomain::getTypeName<ApplicationDomain::Folder>()) {
437 return login(imap) 438 return login(imap)
438 .then([=] { 439 .then([=] {
@@ -528,7 +529,7 @@ public:
528 529
529 KAsync::Job<QByteArray> replay(const ApplicationDomain::Mail &mail, Sink::Operation operation, const QByteArray &oldRemoteId, const QList<QByteArray> &changedProperties) Q_DECL_OVERRIDE 530 KAsync::Job<QByteArray> replay(const ApplicationDomain::Mail &mail, Sink::Operation operation, const QByteArray &oldRemoteId, const QList<QByteArray> &changedProperties) Q_DECL_OVERRIDE
530 { 531 {
531 auto imap = QSharedPointer<ImapServerProxy>::create(mServer, mPort); 532 auto imap = QSharedPointer<ImapServerProxy>::create(mServer, mPort, &mSessionCache);
532 auto login = imap->login(mUser, mPassword); 533 auto login = imap->login(mUser, mPassword);
533 KAsync::Job<QByteArray> job = KAsync::null<QByteArray>(); 534 KAsync::Job<QByteArray> job = KAsync::null<QByteArray>();
534 if (operation == Sink::Operation_Creation) { 535 if (operation == Sink::Operation_Creation) {
@@ -607,7 +608,7 @@ public:
607 608
608 KAsync::Job<QByteArray> replay(const ApplicationDomain::Folder &folder, Sink::Operation operation, const QByteArray &oldRemoteId, const QList<QByteArray> &changedProperties) Q_DECL_OVERRIDE 609 KAsync::Job<QByteArray> replay(const ApplicationDomain::Folder &folder, Sink::Operation operation, const QByteArray &oldRemoteId, const QList<QByteArray> &changedProperties) Q_DECL_OVERRIDE
609 { 610 {
610 auto imap = QSharedPointer<ImapServerProxy>::create(mServer, mPort); 611 auto imap = QSharedPointer<ImapServerProxy>::create(mServer, mPort, &mSessionCache);
611 auto login = imap->login(mUser, mPassword); 612 auto login = imap->login(mUser, mPassword);
612 if (operation == Sink::Operation_Creation) { 613 if (operation == Sink::Operation_Creation) {
613 QString parentFolder; 614 QString parentFolder;
@@ -684,6 +685,7 @@ public:
684 QString mUser; 685 QString mUser;
685 QString mPassword; 686 QString mPassword;
686 QByteArray mResourceInstanceIdentifier; 687 QByteArray mResourceInstanceIdentifier;
688 Imap::SessionCache mSessionCache;
687}; 689};
688 690
689class ImapInspector : public Sink::Inspector { 691class ImapInspector : public Sink::Inspector {
@@ -908,3 +910,4 @@ void ImapResourceFactory::removeDataFromDisk(const QByteArray &instanceIdentifie
908 ImapResource::removeFromDisk(instanceIdentifier); 910 ImapResource::removeFromDisk(instanceIdentifier);
909} 911}
910 912
913#include "imapresource.moc"
diff --git a/examples/imapresource/imapserverproxy.cpp b/examples/imapresource/imapserverproxy.cpp
index 304a0e8..4ef3000 100644
--- a/examples/imapresource/imapserverproxy.cpp
+++ b/examples/imapresource/imapserverproxy.cpp
@@ -98,22 +98,35 @@ static KAsync::Job<void> runJob(KJob *job)
98 }); 98 });
99} 99}
100 100
101ImapServerProxy::ImapServerProxy(const QString &serverUrl, int port) : mSession(new KIMAP2::Session(serverUrl, qint16(port))) 101ImapServerProxy::ImapServerProxy(const QString &serverUrl, int port, SessionCache *sessionCache) : mSession(new KIMAP2::Session(serverUrl, qint16(port))), mSessionCache(sessionCache)
102{ 102{
103 QObject::connect(mSession, &KIMAP2::Session::sslErrors, [this](const QList<QSslError> &errors) { 103 QObject::connect(mSession, &KIMAP2::Session::sslErrors, [this](const QList<QSslError> &errors) {
104 SinkLog() << "Got ssl error: " << errors; 104 SinkLog() << "Received ssl error: " << errors;
105 mSession->ignoreErrors(errors); 105 mSession->ignoreErrors(errors);
106 }); 106 });
107 107
108 if (Sink::Test::testModeEnabled()) { 108 if (Sink::Test::testModeEnabled()) {
109 mSession->setTimeout(1); 109 mSession->setTimeout(1);
110 } else { 110 } else {
111 mSession->setTimeout(20); 111 mSession->setTimeout(40);
112 } 112 }
113} 113}
114 114
115KAsync::Job<void> ImapServerProxy::login(const QString &username, const QString &password) 115KAsync::Job<void> ImapServerProxy::login(const QString &username, const QString &password)
116{ 116{
117 if (mSessionCache) {
118 auto session = mSessionCache->getSession();
119 if (session.isValid()) {
120 mSession = session.mSession;
121 mCapabilities = session.mCapabilities;
122 mNamespaces = session.mNamespaces;
123 }
124 }
125 Q_ASSERT(mSession);
126 if (mSession->state() == KIMAP2::Session::Authenticated || mSession->state() == KIMAP2::Session::Selected) {
127 SinkLog() << "Reusing existing session.";
128 return KAsync::null();
129 }
117 auto loginJob = new KIMAP2::LoginJob(mSession); 130 auto loginJob = new KIMAP2::LoginJob(mSession);
118 loginJob->setUserName(username); 131 loginJob->setUserName(username);
119 loginJob->setPassword(password); 132 loginJob->setPassword(password);
@@ -140,28 +153,25 @@ KAsync::Job<void> ImapServerProxy::login(const QString &username, const QString
140 } 153 }
141 } 154 }
142 }).then(runJob(namespaceJob)).then([this, namespaceJob] { 155 }).then(runJob(namespaceJob)).then([this, namespaceJob] {
143 for (const auto &ns :namespaceJob->personalNamespaces()) { 156 mNamespaces.personal = namespaceJob->personalNamespaces();
144 mPersonalNamespaces << ns.name; 157 mNamespaces.shared = namespaceJob->sharedNamespaces();
145 mPersonalNamespaceSeparator = ns.separator; 158 mNamespaces.user = namespaceJob->userNamespaces();
146 } 159 // SinkTrace() << "Found personal namespaces: " << mNamespaces.personal;
147 for (const auto &ns :namespaceJob->sharedNamespaces()) { 160 // SinkTrace() << "Found shared namespaces: " << mNamespaces.shared;
148 mSharedNamespaces << ns.name; 161 // SinkTrace() << "Found user namespaces: " << mNamespaces.user;
149 mSharedNamespaceSeparator = ns.separator;
150 }
151 for (const auto &ns :namespaceJob->userNamespaces()) {
152 mUserNamespaces << ns.name;
153 mUserNamespaceSeparator = ns.separator;
154 }
155 SinkTrace() << "Found personal namespaces: " << mPersonalNamespaces << mPersonalNamespaceSeparator;
156 SinkTrace() << "Found shared namespaces: " << mSharedNamespaces << mSharedNamespaceSeparator;
157 SinkTrace() << "Found user namespaces: " << mUserNamespaces << mUserNamespaceSeparator;
158 }); 162 });
159} 163}
160 164
161KAsync::Job<void> ImapServerProxy::logout() 165KAsync::Job<void> ImapServerProxy::logout()
162{ 166{
163 auto logoutJob = new KIMAP2::LogoutJob(mSession); 167 if (mSessionCache) {
164 return runJob(logoutJob); 168 auto session = CachedSession{mSession, mCapabilities, mNamespaces};
169 if (session.isConnected()) {
170 mSessionCache->recycleSession(session);
171 return KAsync::null();
172 }
173 }
174 return runJob(new KIMAP2::LogoutJob(mSession));
165} 175}
166 176
167KAsync::Job<SelectResult> ImapServerProxy::select(const QString &mailbox) 177KAsync::Job<SelectResult> ImapServerProxy::select(const QString &mailbox)
@@ -376,12 +386,13 @@ KAsync::Job<void> ImapServerProxy::move(const QString &mailbox, const KIMAP2::Im
376KAsync::Job<QString> ImapServerProxy::createSubfolder(const QString &parentMailbox, const QString &folderName) 386KAsync::Job<QString> ImapServerProxy::createSubfolder(const QString &parentMailbox, const QString &folderName)
377{ 387{
378 return KAsync::start<QString>([this, parentMailbox, folderName]() { 388 return KAsync::start<QString>([this, parentMailbox, folderName]() {
379 Q_ASSERT(!mPersonalNamespaceSeparator.isNull());
380 QString folder; 389 QString folder;
381 if (parentMailbox.isEmpty()) { 390 if (parentMailbox.isEmpty()) {
382 folder = mPersonalNamespaces.isEmpty() ? "" : mPersonalNamespaces.toList().first() + folderName; 391 auto ns = mNamespaces.getDefaultNamespace();
392 folder = ns.name + folderName;
383 } else { 393 } else {
384 folder = parentMailbox + mPersonalNamespaceSeparator + folderName; 394 auto ns = mNamespaces.getNamespace(parentMailbox);
395 folder = parentMailbox + ns.separator + folderName;
385 } 396 }
386 SinkTrace() << "Creating subfolder: " << folder; 397 SinkTrace() << "Creating subfolder: " << folder;
387 return create(folder) 398 return create(folder)
@@ -394,10 +405,10 @@ KAsync::Job<QString> ImapServerProxy::createSubfolder(const QString &parentMailb
394KAsync::Job<QString> ImapServerProxy::renameSubfolder(const QString &oldMailbox, const QString &newName) 405KAsync::Job<QString> ImapServerProxy::renameSubfolder(const QString &oldMailbox, const QString &newName)
395{ 406{
396 return KAsync::start<QString>([this, oldMailbox, newName] { 407 return KAsync::start<QString>([this, oldMailbox, newName] {
397 Q_ASSERT(!mPersonalNamespaceSeparator.isNull()); 408 auto ns = mNamespaces.getNamespace(oldMailbox);
398 auto parts = oldMailbox.split(mPersonalNamespaceSeparator); 409 auto parts = oldMailbox.split(ns.separator);
399 parts.removeLast(); 410 parts.removeLast();
400 QString folder = parts.join(mPersonalNamespaceSeparator) + mPersonalNamespaceSeparator + newName; 411 QString folder = parts.join(ns.separator) + ns.separator + newName;
401 SinkTrace() << "Renaming subfolder: " << oldMailbox << folder; 412 SinkTrace() << "Renaming subfolder: " << oldMailbox << folder;
402 return rename(oldMailbox, folder) 413 return rename(oldMailbox, folder)
403 .then([=]() { 414 .then([=]() {
@@ -408,22 +419,8 @@ KAsync::Job<QString> ImapServerProxy::renameSubfolder(const QString &oldMailbox,
408 419
409QString ImapServerProxy::getNamespace(const QString &name) 420QString ImapServerProxy::getNamespace(const QString &name)
410{ 421{
411 for (const auto &ns : mPersonalNamespaces) { 422 auto ns = mNamespaces.getNamespace(name);
412 if (name.startsWith(ns)) { 423 return ns.name;
413 return ns;
414 }
415 }
416 for (const auto &ns : mSharedNamespaces) {
417 if (name.startsWith(ns)) {
418 return ns;
419 }
420 }
421 for (const auto &ns : mUserNamespaces) {
422 if (name.startsWith(ns)) {
423 return ns;
424 }
425 }
426 return QString{};
427} 424}
428 425
429KAsync::Job<void> ImapServerProxy::fetchFolders(std::function<void(const Folder &)> callback) 426KAsync::Job<void> ImapServerProxy::fetchFolders(std::function<void(const Folder &)> callback)
@@ -474,7 +471,6 @@ KAsync::Job<void> ImapServerProxy::fetchMessages(const Folder &folder, qint64 ui
474{ 471{
475 auto time = QSharedPointer<QTime>::create(); 472 auto time = QSharedPointer<QTime>::create();
476 time->start(); 473 time->start();
477 Q_ASSERT(!mPersonalNamespaceSeparator.isNull());
478 return select(mailboxFromFolder(folder)).then<void, SelectResult>([this, callback, folder, time, progress, uidNext](const SelectResult &selectResult) -> KAsync::Job<void> { 474 return select(mailboxFromFolder(folder)).then<void, SelectResult>([this, callback, folder, time, progress, uidNext](const SelectResult &selectResult) -> KAsync::Job<void> {
479 SinkTrace() << "UIDNEXT " << folder.path() << selectResult.uidNext << uidNext; 475 SinkTrace() << "UIDNEXT " << folder.path() << selectResult.uidNext << uidNext;
480 if (selectResult.uidNext == (uidNext + 1)) { 476 if (selectResult.uidNext == (uidNext + 1)) {
@@ -498,7 +494,6 @@ KAsync::Job<void> ImapServerProxy::fetchMessages(const Folder &folder, const QVe
498{ 494{
499 auto time = QSharedPointer<QTime>::create(); 495 auto time = QSharedPointer<QTime>::create();
500 time->start(); 496 time->start();
501 Q_ASSERT(!mPersonalNamespaceSeparator.isNull());
502 return select(mailboxFromFolder(folder)).then<void, SelectResult>([this, callback, folder, time, progress, uidsToFetch, headersOnly](const SelectResult &selectResult) -> KAsync::Job<void> { 497 return select(mailboxFromFolder(folder)).then<void, SelectResult>([this, callback, folder, time, progress, uidsToFetch, headersOnly](const SelectResult &selectResult) -> KAsync::Job<void> {
503 498
504 SinkTrace() << "Fetching messages" << folder.path(); 499 SinkTrace() << "Fetching messages" << folder.path();
diff --git a/examples/imapresource/imapserverproxy.h b/examples/imapresource/imapserverproxy.h
index 6785fc2..081750f 100644
--- a/examples/imapresource/imapserverproxy.h
+++ b/examples/imapresource/imapserverproxy.h
@@ -124,19 +124,91 @@ struct SelectResult {
124 quint64 highestModSequence; 124 quint64 highestModSequence;
125}; 125};
126 126
127class Namespaces {
128public:
129 QList<KIMAP2::MailBoxDescriptor> personal;
130 QList<KIMAP2::MailBoxDescriptor> shared;
131 QList<KIMAP2::MailBoxDescriptor> user;
132
133 KIMAP2::MailBoxDescriptor getDefaultNamespace()
134 {
135 return personal.isEmpty() ? KIMAP2::MailBoxDescriptor{} : personal.first();
136 }
137
138 KIMAP2::MailBoxDescriptor getNamespace(const QString &mailbox)
139 {
140 for (const auto &ns : personal) {
141 if (mailbox.startsWith(ns.name)) {
142 return ns;
143 }
144 }
145 for (const auto &ns : shared) {
146 if (mailbox.startsWith(ns.name)) {
147 return ns;
148 }
149 }
150 for (const auto &ns : user) {
151 if (mailbox.startsWith(ns.name)) {
152 return ns;
153 }
154 }
155 return KIMAP2::MailBoxDescriptor{};
156 }
157};
158
159class CachedSession {
160public:
161
162 CachedSession() = default;
163 CachedSession(KIMAP2::Session *session, const QStringList &cap, const Namespaces &ns) : mSession(session), mCapabilities(cap), mNamespaces(ns)
164 {
165 }
166
167 bool isConnected()
168 {
169 return (mSession->state() == KIMAP2::Session::State::Authenticated || mSession->state() == KIMAP2::Session::State::Selected) ;
170 }
171
172 bool isValid()
173 {
174 return mSession;
175 }
176
177 KIMAP2::Session *mSession = nullptr;
178 QStringList mCapabilities;
179 Namespaces mNamespaces;
180};
181
182class SessionCache : public QObject {
183 Q_OBJECT
184public:
185 void recycleSession(const CachedSession &session)
186 {
187 mSessions << session;
188 }
189
190 CachedSession getSession()
191 {
192 while (!mSessions.isEmpty()) {
193 auto session = mSessions.takeLast();
194 if (session.isConnected()) {
195 return session;
196 }
197 }
198 return CachedSession{};
199 }
200private:
201 QList<CachedSession> mSessions;
202};
203
127class ImapServerProxy { 204class ImapServerProxy {
128 KIMAP2::Session *mSession; 205 KIMAP2::Session *mSession;
129 QStringList mCapabilities; 206 QStringList mCapabilities;
207 Namespaces mNamespaces;
130 208
131 QSet<QString> mPersonalNamespaces;
132 QChar mPersonalNamespaceSeparator;
133 QSet<QString> mSharedNamespaces;
134 QChar mSharedNamespaceSeparator;
135 QSet<QString> mUserNamespaces;
136 QChar mUserNamespaceSeparator;
137 209
138public: 210public:
139 ImapServerProxy(const QString &serverUrl, int port); 211 ImapServerProxy(const QString &serverUrl, int port, SessionCache *sessionCache = nullptr);
140 212
141 //Standard IMAP calls 213 //Standard IMAP calls
142 KAsync::Job<void> login(const QString &username, const QString &password); 214 KAsync::Job<void> login(const QString &username, const QString &password);
@@ -186,6 +258,7 @@ public:
186private: 258private:
187 QString getNamespace(const QString &name); 259 QString getNamespace(const QString &name);
188 QObject mGuard; 260 QObject mGuard;
261 SessionCache *mSessionCache;
189}; 262};
190 263
191} 264}