From 8d20128618b427270c6c7db49a1716f65b8ff840 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Fri, 21 Apr 2017 12:06:49 +0200 Subject: Gmail support. For the time being we hardcode a list of folders that we synchronize that we know are not duplicating messages. --- examples/imapresource/imapresource.cpp | 36 ++++++++++++++++++++++++++----- examples/imapresource/imapserverproxy.cpp | 31 +++++++++++++++++++++++++- examples/imapresource/imapserverproxy.h | 13 ++++++----- 3 files changed, 69 insertions(+), 11 deletions(-) (limited to 'examples') diff --git a/examples/imapresource/imapresource.cpp b/examples/imapresource/imapresource.cpp index 0579dae..0b3dcf5 100644 --- a/examples/imapresource/imapresource.cpp +++ b/examples/imapresource/imapresource.cpp @@ -87,6 +87,25 @@ static QByteArray parentRid(const Imap::Folder &folder) return folder.parentPath().toUtf8(); } +static QByteArray getSpecialPurposeType(const QByteArrayList &flags) +{ + if (Imap::flagsContain(Imap::FolderFlags::Trash, flags)) { + return ApplicationDomain::SpecialPurpose::Mail::trash; + } + if (Imap::flagsContain(Imap::FolderFlags::Drafts, flags)) { + return ApplicationDomain::SpecialPurpose::Mail::drafts; + } + if (Imap::flagsContain(Imap::FolderFlags::Sent, flags)) { + return ApplicationDomain::SpecialPurpose::Mail::sent; + } + return {}; +} + +static bool hasSpecialPurposeFlag(const QByteArrayList &flags) +{ + return !getSpecialPurposeType(flags).isEmpty(); +} + class ImapSynchronizer : public Sink::Synchronizer { Q_OBJECT @@ -100,7 +119,7 @@ public: QByteArray createFolder(const Imap::Folder &f) { const auto parentFolderRid = parentRid(f); - SinkTraceCtx(mLogCtx) << "Creating folder: " << f.name() << parentFolderRid; + SinkTraceCtx(mLogCtx) << "Creating folder: " << f.name() << parentFolderRid << f.flags; const auto remoteId = folderRid(f); Sink::ApplicationDomain::Folder folder; @@ -108,10 +127,17 @@ public: folder.setIcon("folder"); folder.setEnabled(f.subscribed); QHash mergeCriteria; - if (SpecialPurpose::isSpecialPurposeFolderName(f.name()) && parentFolderRid.isEmpty()) { - auto type = SpecialPurpose::getSpecialPurposeType(f.name()); - folder.setSpecialPurpose(QByteArrayList() << type); - mergeCriteria.insert(ApplicationDomain::Folder::SpecialPurpose::name, Query::Comparator(type, Query::Comparator::Contains)); + auto specialPurpose = [&] { + if (hasSpecialPurposeFlag(f.flags)) { + return getSpecialPurposeType(f.flags); + } else if (SpecialPurpose::isSpecialPurposeFolderName(f.name()) && parentFolderRid.isEmpty()) { + return SpecialPurpose::getSpecialPurposeType(f.name()); + } + return QByteArray{}; + }(); + if (!specialPurpose.isEmpty()) { + folder.setSpecialPurpose(QByteArrayList() << specialPurpose); + mergeCriteria.insert(ApplicationDomain::Folder::SpecialPurpose::name, Query::Comparator(specialPurpose, Query::Comparator::Contains)); } if (!parentFolderRid.isEmpty()) { diff --git a/examples/imapresource/imapserverproxy.cpp b/examples/imapresource/imapserverproxy.cpp index 3305f60..36dbcf5 100644 --- a/examples/imapresource/imapserverproxy.cpp +++ b/examples/imapresource/imapserverproxy.cpp @@ -57,6 +57,7 @@ const char* Imap::FolderFlags::Trash = "\\Trash"; const char* Imap::FolderFlags::Archive = "\\Archive"; const char* Imap::FolderFlags::Junk = "\\Junk"; const char* Imap::FolderFlags::Flagged = "\\Flagged"; +const char* Imap::FolderFlags::Drafts = "\\Drafts"; const char* Imap::Capabilities::Namespace = "NAMESPACE"; const char* Imap::Capabilities::Uidplus = "UIDPLUS"; @@ -192,6 +193,12 @@ KAsync::Job ImapServerProxy::logout() } } +bool ImapServerProxy::isGmail() const +{ + //Magic capability that only gmail has + return mCapabilities.contains("X-GM-EXT-1"); +} + KAsync::Job ImapServerProxy::select(const QString &mailbox) { auto select = new KIMAP2::SelectJob(mSession); @@ -441,6 +448,15 @@ QString ImapServerProxy::getNamespace(const QString &name) return ns.name; } +static bool caseInsensitiveContains(const QByteArray &f, const QByteArrayList &list) { + return list.contains(f) || list.contains(f.toLower()); +} + +bool Imap::flagsContain(const QByteArray &f, const QByteArrayList &flags) +{ + return caseInsensitiveContains(f, flags); +} + KAsync::Job ImapServerProxy::fetchFolders(std::function callback) { SinkTrace() << "Fetching folders"; @@ -448,8 +464,21 @@ KAsync::Job ImapServerProxy::fetchFolders(std::function &){ *subscribedList << mailbox.name; }).then(list(KIMAP2::ListJob::IncludeUnsubscribed, [=](const KIMAP2::MailBoxDescriptor &mailbox, const QList &flags) { - bool noselect = flags.contains(QByteArray(FolderFlags::Noselect).toLower()) || flags.contains(QByteArray(FolderFlags::Noselect)); + bool noselect = caseInsensitiveContains(FolderFlags::Noselect, flags); bool subscribed = subscribedList->contains(mailbox.name); + if (isGmail()) { + bool inbox = mailbox.name.toLower() == "inbox"; + bool sent = caseInsensitiveContains(FolderFlags::Sent, flags); + bool drafts = caseInsensitiveContains(FolderFlags::Drafts, flags); + bool trash = caseInsensitiveContains(FolderFlags::Trash, flags); + bool isgmailParent = mailbox.name.toLower() == "[gmail]"; + /** + * Because gmail duplicates messages all over the place we only support a few selected folders for now that should be mostly exclusive. + */ + if (!(inbox || sent || drafts || trash || isgmailParent)) { + return; + } + } SinkLog() << "Found mailbox: " << mailbox.name << flags << FolderFlags::Noselect << noselect << " sub: " << subscribed; auto ns = getNamespace(mailbox.name); callback(Folder{mailbox.name, ns, mailbox.separator, noselect, subscribed, flags}); diff --git a/examples/imapresource/imapserverproxy.h b/examples/imapresource/imapserverproxy.h index 58c49a2..0d70ba5 100644 --- a/examples/imapresource/imapserverproxy.h +++ b/examples/imapresource/imapserverproxy.h @@ -61,6 +61,7 @@ namespace FolderFlags extern const char* Junk; extern const char* Flagged; extern const char* All; + extern const char* Drafts; } namespace Capabilities @@ -79,6 +80,8 @@ struct Message { bool fullPayload; }; +bool flagsContain(const QByteArray &f, const QByteArrayList &flags); + struct Folder { Folder() = default; Folder(const QString &path, const QString &ns, const QChar &separator, bool noselect_, bool subscribed_, const QByteArrayList &flags_) @@ -226,11 +229,6 @@ private: }; class ImapServerProxy { - KIMAP2::Session *mSession; - QStringList mCapabilities; - Namespaces mNamespaces; - - public: ImapServerProxy(const QString &serverUrl, int port, SessionCache *sessionCache = nullptr); @@ -280,9 +278,14 @@ public: KAsync::Job> fetchUids(const Folder &folder); private: + bool isGmail() const; + QString getNamespace(const QString &name); QObject mGuard; SessionCache *mSessionCache; + KIMAP2::Session *mSession; + QStringList mCapabilities; + Namespaces mNamespaces; }; } -- cgit v1.2.3