diff options
author | Christian Mollekopf <chrigi_1@fastmail.fm> | 2017-07-03 14:02:27 +0200 |
---|---|---|
committer | Christian Mollekopf <chrigi_1@fastmail.fm> | 2017-07-03 14:02:27 +0200 |
commit | 55fe06979ceebe67553135b43aa47e70d931304b (patch) | |
tree | 16b10a744879cc1872d6c07624b59ae64469ddbf /examples/imapresource/imapserverproxy.cpp | |
parent | 56fae95f49a1ca8ca614bd9f89b0ea5f872765e9 (diff) | |
parent | 288946f1694c2abe1d2c5800c87339d1e8780e4b (diff) | |
download | sink-55fe06979ceebe67553135b43aa47e70d931304b.tar.gz sink-55fe06979ceebe67553135b43aa47e70d931304b.zip |
Merge branch 'develop'
Diffstat (limited to 'examples/imapresource/imapserverproxy.cpp')
-rw-r--r-- | examples/imapresource/imapserverproxy.cpp | 88 |
1 files changed, 74 insertions, 14 deletions
diff --git a/examples/imapresource/imapserverproxy.cpp b/examples/imapresource/imapserverproxy.cpp index 0cc43b8..538105c 100644 --- a/examples/imapresource/imapserverproxy.cpp +++ b/examples/imapresource/imapserverproxy.cpp | |||
@@ -37,8 +37,6 @@ | |||
37 | #include "log.h" | 37 | #include "log.h" |
38 | #include "test.h" | 38 | #include "test.h" |
39 | 39 | ||
40 | SINK_DEBUG_AREA("imapserverproxy") | ||
41 | |||
42 | using namespace Imap; | 40 | using namespace Imap; |
43 | 41 | ||
44 | const char* Imap::Flags::Seen = "\\Seen"; | 42 | const char* Imap::Flags::Seen = "\\Seen"; |
@@ -57,6 +55,7 @@ const char* Imap::FolderFlags::Trash = "\\Trash"; | |||
57 | const char* Imap::FolderFlags::Archive = "\\Archive"; | 55 | const char* Imap::FolderFlags::Archive = "\\Archive"; |
58 | const char* Imap::FolderFlags::Junk = "\\Junk"; | 56 | const char* Imap::FolderFlags::Junk = "\\Junk"; |
59 | const char* Imap::FolderFlags::Flagged = "\\Flagged"; | 57 | const char* Imap::FolderFlags::Flagged = "\\Flagged"; |
58 | const char* Imap::FolderFlags::Drafts = "\\Drafts"; | ||
60 | 59 | ||
61 | const char* Imap::Capabilities::Namespace = "NAMESPACE"; | 60 | const char* Imap::Capabilities::Namespace = "NAMESPACE"; |
62 | const char* Imap::Capabilities::Uidplus = "UIDPLUS"; | 61 | const char* Imap::Capabilities::Uidplus = "UIDPLUS"; |
@@ -98,17 +97,25 @@ static KAsync::Job<void> runJob(KJob *job) | |||
98 | }); | 97 | }); |
99 | } | 98 | } |
100 | 99 | ||
101 | ImapServerProxy::ImapServerProxy(const QString &serverUrl, int port, SessionCache *sessionCache) : mSession(new KIMAP2::Session(serverUrl, qint16(port))), mSessionCache(sessionCache) | 100 | KIMAP2::Session *createNewSession(const QString &serverUrl, int port) |
102 | { | 101 | { |
103 | QObject::connect(mSession, &KIMAP2::Session::sslErrors, [this](const QList<QSslError> &errors) { | 102 | auto newSession = new KIMAP2::Session(serverUrl, qint16(port)); |
103 | if (Sink::Test::testModeEnabled()) { | ||
104 | newSession->setTimeout(1); | ||
105 | } else { | ||
106 | newSession->setTimeout(40); | ||
107 | } | ||
108 | QObject::connect(newSession, &KIMAP2::Session::sslErrors, [=](const QList<QSslError> &errors) { | ||
104 | SinkLog() << "Received ssl error: " << errors; | 109 | SinkLog() << "Received ssl error: " << errors; |
105 | mSession->ignoreErrors(errors); | 110 | newSession->ignoreErrors(errors); |
106 | }); | 111 | }); |
112 | return newSession; | ||
113 | } | ||
107 | 114 | ||
108 | if (Sink::Test::testModeEnabled()) { | 115 | ImapServerProxy::ImapServerProxy(const QString &serverUrl, int port, SessionCache *sessionCache) : mSessionCache(sessionCache), mSession(nullptr) |
109 | mSession->setTimeout(1); | 116 | { |
110 | } else { | 117 | if (!mSessionCache || mSessionCache->isEmpty()) { |
111 | mSession->setTimeout(40); | 118 | mSession = createNewSession(serverUrl, port); |
112 | } | 119 | } |
113 | } | 120 | } |
114 | 121 | ||
@@ -161,12 +168,16 @@ KAsync::Job<void> ImapServerProxy::login(const QString &username, const QString | |||
161 | // SinkTrace() << "Found user namespaces: " << mNamespaces.user; | 168 | // SinkTrace() << "Found user namespaces: " << mNamespaces.user; |
162 | }).then([=] (const KAsync::Error &error) { | 169 | }).then([=] (const KAsync::Error &error) { |
163 | if (error) { | 170 | if (error) { |
164 | if (error.errorCode == KIMAP2::LoginJob::ErrorCode::ERR_COULD_NOT_CONNECT) { | 171 | switch (error.errorCode) { |
172 | case KIMAP2::LoginJob::ErrorCode::ERR_HOST_NOT_FOUND: | ||
173 | return KAsync::error(HostNotFoundError, "Host not found: " + error.errorMessage); | ||
174 | case KIMAP2::LoginJob::ErrorCode::ERR_COULD_NOT_CONNECT: | ||
165 | return KAsync::error(CouldNotConnectError, "Failed to connect: " + error.errorMessage); | 175 | return KAsync::error(CouldNotConnectError, "Failed to connect: " + error.errorMessage); |
166 | } else if (error.errorCode == KIMAP2::LoginJob::ErrorCode::ERR_SSL_HANDSHAKE_FAILED) { | 176 | case KIMAP2::LoginJob::ErrorCode::ERR_SSL_HANDSHAKE_FAILED: |
167 | return KAsync::error(SslHandshakeError, "Ssl handshake failed: " + error.errorMessage); | 177 | return KAsync::error(SslHandshakeError, "Ssl handshake failed: " + error.errorMessage); |
178 | default: | ||
179 | return KAsync::error(error); | ||
168 | } | 180 | } |
169 | return KAsync::error(error); | ||
170 | } | 181 | } |
171 | return KAsync::null(); | 182 | return KAsync::null(); |
172 | }); | 183 | }); |
@@ -188,6 +199,12 @@ KAsync::Job<void> ImapServerProxy::logout() | |||
188 | } | 199 | } |
189 | } | 200 | } |
190 | 201 | ||
202 | bool ImapServerProxy::isGmail() const | ||
203 | { | ||
204 | //Magic capability that only gmail has | ||
205 | return mCapabilities.contains("X-GM-EXT-1"); | ||
206 | } | ||
207 | |||
191 | KAsync::Job<SelectResult> ImapServerProxy::select(const QString &mailbox) | 208 | KAsync::Job<SelectResult> ImapServerProxy::select(const QString &mailbox) |
192 | { | 209 | { |
193 | auto select = new KIMAP2::SelectJob(mSession); | 210 | auto select = new KIMAP2::SelectJob(mSession); |
@@ -297,6 +314,7 @@ KAsync::Job<void> ImapServerProxy::fetch(const KIMAP2::ImapSet &set, KIMAP2::Fet | |||
297 | fetch->setSequenceSet(set); | 314 | fetch->setSequenceSet(set); |
298 | fetch->setUidBased(true); | 315 | fetch->setUidBased(true); |
299 | fetch->setScope(scope); | 316 | fetch->setScope(scope); |
317 | fetch->setAvoidParsing(true); | ||
300 | QObject::connect(fetch, &KIMAP2::FetchJob::resultReceived, callback); | 318 | QObject::connect(fetch, &KIMAP2::FetchJob::resultReceived, callback); |
301 | return runJob(fetch); | 319 | return runJob(fetch); |
302 | } | 320 | } |
@@ -437,18 +455,60 @@ QString ImapServerProxy::getNamespace(const QString &name) | |||
437 | return ns.name; | 455 | return ns.name; |
438 | } | 456 | } |
439 | 457 | ||
458 | static bool caseInsensitiveContains(const QByteArray &f, const QByteArrayList &list) { | ||
459 | return list.contains(f) || list.contains(f.toLower()); | ||
460 | } | ||
461 | |||
462 | bool Imap::flagsContain(const QByteArray &f, const QByteArrayList &flags) | ||
463 | { | ||
464 | return caseInsensitiveContains(f, flags); | ||
465 | } | ||
466 | |||
467 | static void reportFolder(const Folder &f, QSharedPointer<QSet<QString>> reportedList, std::function<void(const Folder &)> callback) { | ||
468 | if (!reportedList->contains(f.path())) { | ||
469 | reportedList->insert(f.path()); | ||
470 | auto c = f; | ||
471 | c.noselect = true; | ||
472 | callback(c); | ||
473 | if (!f.parentPath().isEmpty()){ | ||
474 | reportFolder(f.parentFolder(), reportedList, callback); | ||
475 | } | ||
476 | } | ||
477 | } | ||
478 | |||
440 | KAsync::Job<void> ImapServerProxy::fetchFolders(std::function<void(const Folder &)> callback) | 479 | KAsync::Job<void> ImapServerProxy::fetchFolders(std::function<void(const Folder &)> callback) |
441 | { | 480 | { |
442 | SinkTrace() << "Fetching folders"; | 481 | SinkTrace() << "Fetching folders"; |
443 | auto subscribedList = QSharedPointer<QSet<QString>>::create() ; | 482 | auto subscribedList = QSharedPointer<QSet<QString>>::create() ; |
483 | auto reportedList = QSharedPointer<QSet<QString>>::create() ; | ||
444 | return list(KIMAP2::ListJob::NoOption, [=](const KIMAP2::MailBoxDescriptor &mailbox, const QList<QByteArray> &){ | 484 | return list(KIMAP2::ListJob::NoOption, [=](const KIMAP2::MailBoxDescriptor &mailbox, const QList<QByteArray> &){ |
445 | *subscribedList << mailbox.name; | 485 | *subscribedList << mailbox.name; |
446 | }).then(list(KIMAP2::ListJob::IncludeUnsubscribed, [=](const KIMAP2::MailBoxDescriptor &mailbox, const QList<QByteArray> &flags) { | 486 | }).then(list(KIMAP2::ListJob::IncludeUnsubscribed, [=](const KIMAP2::MailBoxDescriptor &mailbox, const QList<QByteArray> &flags) { |
447 | bool noselect = flags.contains(QByteArray(FolderFlags::Noselect).toLower()) || flags.contains(QByteArray(FolderFlags::Noselect)); | 487 | bool noselect = caseInsensitiveContains(FolderFlags::Noselect, flags); |
448 | bool subscribed = subscribedList->contains(mailbox.name); | 488 | bool subscribed = subscribedList->contains(mailbox.name); |
489 | if (isGmail()) { | ||
490 | bool inbox = mailbox.name.toLower() == "inbox"; | ||
491 | bool sent = caseInsensitiveContains(FolderFlags::Sent, flags); | ||
492 | bool drafts = caseInsensitiveContains(FolderFlags::Drafts, flags); | ||
493 | bool trash = caseInsensitiveContains(FolderFlags::Trash, flags); | ||
494 | /** | ||
495 | * Because gmail duplicates messages all over the place we only support a few selected folders for now that should be mostly exclusive. | ||
496 | */ | ||
497 | if (!(inbox || sent || drafts || trash)) { | ||
498 | return; | ||
499 | } | ||
500 | } | ||
449 | SinkLog() << "Found mailbox: " << mailbox.name << flags << FolderFlags::Noselect << noselect << " sub: " << subscribed; | 501 | SinkLog() << "Found mailbox: " << mailbox.name << flags << FolderFlags::Noselect << noselect << " sub: " << subscribed; |
450 | auto ns = getNamespace(mailbox.name); | 502 | auto ns = getNamespace(mailbox.name); |
451 | callback(Folder{mailbox.name, ns, mailbox.separator, noselect, subscribed, flags}); | 503 | auto folder = Folder{mailbox.name, ns, mailbox.separator, noselect, subscribed, flags}; |
504 | |||
505 | //call callback for parents if that didn't already happen. | ||
506 | //This is necessary because we can have missing bits in the hierarchy in IMAP, but this will not work in sink because we'd end up with an incomplete tree. | ||
507 | if (!folder.parentPath().isEmpty() && !reportedList->contains(folder.parentPath())) { | ||
508 | reportFolder(folder.parentFolder(), reportedList, callback); | ||
509 | } | ||
510 | reportedList->insert(folder.path()); | ||
511 | callback(folder); | ||
452 | })); | 512 | })); |
453 | } | 513 | } |
454 | 514 | ||