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 +++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) (limited to 'examples/imapresource/imapresource.cpp') 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()) { -- cgit v1.2.3 From fcc89a201a06ede057dae86d4591199bf69fab50 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Fri, 21 Apr 2017 17:31:22 +0200 Subject: Make sure we always have a complete hierarchy from the IMAP server --- examples/imapresource/imapresource.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'examples/imapresource/imapresource.cpp') diff --git a/examples/imapresource/imapresource.cpp b/examples/imapresource/imapresource.cpp index 0b3dcf5..8577b8c 100644 --- a/examples/imapresource/imapresource.cpp +++ b/examples/imapresource/imapresource.cpp @@ -119,6 +119,8 @@ public: QByteArray createFolder(const Imap::Folder &f) { const auto parentFolderRid = parentRid(f); + bool isToplevel = parentFolderRid.isEmpty(); + SinkTraceCtx(mLogCtx) << "Creating folder: " << f.name() << parentFolderRid << f.flags; const auto remoteId = folderRid(f); @@ -126,22 +128,20 @@ public: folder.setName(f.name()); folder.setIcon("folder"); folder.setEnabled(f.subscribed); - QHash mergeCriteria; auto specialPurpose = [&] { if (hasSpecialPurposeFlag(f.flags)) { return getSpecialPurposeType(f.flags); - } else if (SpecialPurpose::isSpecialPurposeFolderName(f.name()) && parentFolderRid.isEmpty()) { + } else if (SpecialPurpose::isSpecialPurposeFolderName(f.name()) && isToplevel) { 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()) { - folder.setParent(syncStore().resolveRemoteId(ENTITY_TYPE_FOLDER, parentFolderRid)); + if (!isToplevel) { + folder.setParent(syncStore().resolveRemoteId(ApplicationDomain::Folder::name, parentFolderRid)); } createOrModify(ApplicationDomain::getTypeName(), remoteId, folder); return remoteId; -- cgit v1.2.3 From a2ecf2a77a38025442da8150156e5b59f107b897 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Thu, 4 May 2017 07:53:36 +0200 Subject: Only sync subscribed folders --- examples/imapresource/imapresource.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'examples/imapresource/imapresource.cpp') diff --git a/examples/imapresource/imapresource.cpp b/examples/imapresource/imapresource.cpp index 8577b8c..8e6d2b1 100644 --- a/examples/imapresource/imapresource.cpp +++ b/examples/imapresource/imapresource.cpp @@ -584,6 +584,10 @@ public: //Synchronize folders return KAsync::value(folders) .serialEach([=](const Folder &folder) { + //Skip unsubscribed folders + if (!folder.subscribed) { + return KAsync::null(); + } SinkLog() << "Syncing folder " << folder.path(); //Emit notification that the folder is being synced. //The synchronizer can't do that because it has no concept of the folder filter on a mail sync scope meaning that the folder is being synchronized. -- cgit v1.2.3 From 6adf9a4734f15a2c0fa199897f76ded4659b83b7 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Thu, 4 May 2017 11:40:24 +0200 Subject: Added progress notification --- examples/imapresource/imapresource.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'examples/imapresource/imapresource.cpp') diff --git a/examples/imapresource/imapresource.cpp b/examples/imapresource/imapresource.cpp index 8e6d2b1..5aa18dd 100644 --- a/examples/imapresource/imapresource.cpp +++ b/examples/imapresource/imapresource.cpp @@ -324,7 +324,7 @@ public: synchronizeMails(folderRemoteId, m); }, [this, maxUid, folder](int progress, int total) { - SinkLog() << "Progress: " << progress << " out of " << total; + reportProgress(progress, total); //commit every 10 messages if ((progress % 10) == 0) { commit(); @@ -365,7 +365,7 @@ public: synchronizeMails(folderRemoteId, m); }, [=](int progress, int total) { - SinkLogCtx(mLogCtx) << "Progress: " << progress << " out of " << total; + reportProgress(progress, total); //commit every 100 messages if ((progress % 100) == 0) { commit(); -- cgit v1.2.3 From 4bc39b1b771aaf9ae5f7c96aeaddb06f2bd101ac Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Thu, 4 May 2017 17:33:32 +0200 Subject: Fixed folder sync When explicitly listing the folder we can't rely on the subscription state, nor should we. --- examples/imapresource/imapresource.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'examples/imapresource/imapresource.cpp') diff --git a/examples/imapresource/imapresource.cpp b/examples/imapresource/imapresource.cpp index 5aa18dd..e7458f6 100644 --- a/examples/imapresource/imapresource.cpp +++ b/examples/imapresource/imapresource.cpp @@ -492,7 +492,7 @@ public: //Otherwise fetch full payload for daterange auto folderList = QSharedPointer>::create(); return imap->fetchFolders([folderList](const Folder &folder) { - if (!folder.noselect) { + if (!folder.noselect && folder.subscribed) { *folderList << folder; } }) @@ -580,14 +580,7 @@ public: bool syncHeaders = query.hasFilter(); //FIXME If we were able to to flush in between we could just query the local store for the folder list. return getFolderList(imap, query) - .then([=] (const QVector &folders) { - //Synchronize folders - return KAsync::value(folders) .serialEach([=](const Folder &folder) { - //Skip unsubscribed folders - if (!folder.subscribed) { - return KAsync::null(); - } SinkLog() << "Syncing folder " << folder.path(); //Emit notification that the folder is being synced. //The synchronizer can't do that because it has no concept of the folder filter on a mail sync scope meaning that the folder is being synchronized. @@ -602,7 +595,6 @@ public: SinkWarning() << "Failed to sync folder: " << folder.path() << "Error: " << error.errorMessage; }); }); - }); } }) .then([=] (const KAsync::Error &error) { -- cgit v1.2.3 From 4da825f0429f1f125abe5f1843cd4e3ac5387346 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Tue, 9 May 2017 14:30:29 +0200 Subject: Translate the host not found error --- examples/imapresource/imapresource.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'examples/imapresource/imapresource.cpp') diff --git a/examples/imapresource/imapresource.cpp b/examples/imapresource/imapresource.cpp index e7458f6..90383e0 100644 --- a/examples/imapresource/imapresource.cpp +++ b/examples/imapresource/imapresource.cpp @@ -506,12 +506,16 @@ public: KAsync::Error getError(const KAsync::Error &error) { if (error) { - if (error.errorCode == Imap::CouldNotConnectError) { - return {ApplicationDomain::ConnectionError, error.errorMessage}; - } else if (error.errorCode == Imap::SslHandshakeError) { - return {ApplicationDomain::LoginError, error.errorMessage}; + switch(error.errorCode) { + case Imap::CouldNotConnectError: + return {ApplicationDomain::ConnectionError, error.errorMessage}; + case Imap::SslHandshakeError: + return {ApplicationDomain::LoginError, error.errorMessage}; + case Imap::HostNotFoundError: + return {ApplicationDomain::NoServerError, error.errorMessage}; + default: + return {ApplicationDomain::UnknownError, error.errorMessage}; } - return {ApplicationDomain::UnknownError, error.errorMessage}; } return {}; } -- cgit v1.2.3 From 41f8f9bc05c059cafa780ac8aec27a56cba2c278 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Fri, 12 May 2017 08:20:43 +0200 Subject: No more SINK_DEBUG_AREA --- examples/imapresource/imapresource.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'examples/imapresource/imapresource.cpp') diff --git a/examples/imapresource/imapresource.cpp b/examples/imapresource/imapresource.cpp index 90383e0..94ca27a 100644 --- a/examples/imapresource/imapresource.cpp +++ b/examples/imapresource/imapresource.cpp @@ -46,8 +46,6 @@ #define ENTITY_TYPE_MAIL "mail" #define ENTITY_TYPE_FOLDER "folder" -SINK_DEBUG_AREA("imapresource") - Q_DECLARE_METATYPE(QSharedPointer) using namespace Imap; -- cgit v1.2.3 From 524e405f645edb6231f9b16fafc1f9ca36af8237 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Sat, 20 May 2017 11:28:02 +0200 Subject: Avoid notifcations for requests that do nothing, progress with folderid --- examples/imapresource/imapresource.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'examples/imapresource/imapresource.cpp') diff --git a/examples/imapresource/imapresource.cpp b/examples/imapresource/imapresource.cpp index 94ca27a..533dea3 100644 --- a/examples/imapresource/imapresource.cpp +++ b/examples/imapresource/imapresource.cpp @@ -184,14 +184,12 @@ public: return flags; } - void synchronizeMails(const QByteArray &folderRid, const Message &message) + void synchronizeMails(const QByteArray &folderRid, const QByteArray &folderLocalId, const Message &message) { auto time = QSharedPointer::create(); time->start(); SinkTraceCtx(mLogCtx) << "Importing new mail." << folderRid; - const auto folderLocalId = syncStore().resolveRemoteId(ENTITY_TYPE_FOLDER, folderRid); - const auto remoteId = assembleMailRid(folderLocalId, message.uid); Q_ASSERT(message.msg); @@ -315,14 +313,15 @@ public: SinkTraceCtx(mLogCtx) << "Uids to fetch: " << filteredAndSorted; bool headersOnly = false; + const auto folderLocalId = syncStore().resolveRemoteId(ENTITY_TYPE_FOLDER, folderRemoteId); return imap->fetchMessages(folder, filteredAndSorted, headersOnly, [=](const Message &m) { if (*maxUid < m.uid) { *maxUid = m.uid; } - synchronizeMails(folderRemoteId, m); + synchronizeMails(folderRemoteId, folderLocalId, m); }, - [this, maxUid, folder](int progress, int total) { - reportProgress(progress, total); + [=](int progress, int total) { + reportProgress(progress, total, QByteArrayList{} << folderLocalId); //commit every 10 messages if ((progress % 10) == 0) { commit(); @@ -359,11 +358,12 @@ public: SinkLogCtx(mLogCtx) << "Fetching headers for: " << toFetch; bool headersOnly = true; + const auto folderLocalId = syncStore().resolveRemoteId(ENTITY_TYPE_FOLDER, folderRemoteId); return imap->fetchMessages(folder, toFetch, headersOnly, [=](const Message &m) { - synchronizeMails(folderRemoteId, m); + synchronizeMails(folderRemoteId, folderLocalId, m); }, [=](int progress, int total) { - reportProgress(progress, total); + reportProgress(progress, total, QByteArrayList{} << folderLocalId); //commit every 100 messages if ((progress % 100) == 0) { commit(); @@ -567,11 +567,12 @@ public: } SinkLog() << "Fetching messages: " << toFetch << folderRemoteId; bool headersOnly = false; + const auto folderLocalId = syncStore().resolveRemoteId(ENTITY_TYPE_FOLDER, folderRemoteId); return imap->fetchMessages(Folder{folderRemoteId}, toFetch, headersOnly, [=](const Message &m) { - synchronizeMails(folderRemoteId, m); + synchronizeMails(folderRemoteId, folderLocalId, m); }, [=](int progress, int total) { - reportProgress(progress, total); + reportProgress(progress, total, QByteArrayList{} << folderLocalId); //commit every 100 messages if ((progress % 100) == 0) { commit(); -- cgit v1.2.3 From d67b886dd2cf51264e4d6da680e268015a0a7031 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Sat, 20 May 2017 16:54:34 +0200 Subject: Don't try to replay modifications on nothing. --- examples/imapresource/imapresource.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'examples/imapresource/imapresource.cpp') diff --git a/examples/imapresource/imapresource.cpp b/examples/imapresource/imapresource.cpp index 533dea3..bfe43bf 100644 --- a/examples/imapresource/imapresource.cpp +++ b/examples/imapresource/imapresource.cpp @@ -689,6 +689,12 @@ public: KAsync::Job replay(const ApplicationDomain::Folder &folder, Sink::Operation operation, const QByteArray &oldRemoteId, const QList &changedProperties) Q_DECL_OVERRIDE { + if (operation != Sink::Operation_Creation) { + if(oldRemoteId.isEmpty()) { + Q_ASSERT(false); + return KAsync::error("Tried to replay modification without old remoteId."); + } + } auto imap = QSharedPointer::create(mServer, mPort, &mSessionCache); auto login = imap->login(mUser, mPassword); if (operation == Sink::Operation_Creation) { -- cgit v1.2.3 From 227610b7399905fca38e0f09053d78e2e866f32e Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Sat, 20 May 2017 16:55:21 +0200 Subject: Ensure change-replay errors make it through to the correct error handling and are appropriately dealt with. --- examples/imapresource/imapresource.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples/imapresource/imapresource.cpp') diff --git a/examples/imapresource/imapresource.cpp b/examples/imapresource/imapresource.cpp index bfe43bf..29ff03b 100644 --- a/examples/imapresource/imapresource.cpp +++ b/examples/imapresource/imapresource.cpp @@ -680,7 +680,7 @@ public: if (error) { SinkWarning() << "Error during changereplay: " << error.errorMessage; return imap->logout() - .then(KAsync::error(error)); + .then(KAsync::error(getError(error))); } return imap->logout() .then(KAsync::value(remoteId)); -- cgit v1.2.3 From e97fb6d6de7c9bda6e8f911c5f471f4059ae7470 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Sun, 11 Jun 2017 22:55:50 +0200 Subject: Disabled automatic syncing of folders I triggers a lot of work, and as we currently can't abort sync tasks and have no priority lane for requests it's rather intrusive. A sync will still be triggered when a folder is selected, so we're not loosing a lot except the "pull everything offline" case. --- examples/imapresource/imapresource.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'examples/imapresource/imapresource.cpp') diff --git a/examples/imapresource/imapresource.cpp b/examples/imapresource/imapresource.cpp index 29ff03b..a6c0343 100644 --- a/examples/imapresource/imapresource.cpp +++ b/examples/imapresource/imapresource.cpp @@ -415,8 +415,9 @@ public: list << Synchronizer::SyncRequest{query}; } else { list << Synchronizer::SyncRequest{Sink::QueryBase(ApplicationDomain::getTypeName())}; + //TODO automatic syncing off all folders is disabled for the time being //This request depends on the previous one so we flush first. - list << Synchronizer::SyncRequest{applyMailDefaults(Sink::QueryBase(ApplicationDomain::getTypeName())), QByteArray{}, Synchronizer::SyncRequest::RequestFlush}; + //list << Synchronizer::SyncRequest{applyMailDefaults(Sink::QueryBase(ApplicationDomain::getTypeName())), QByteArray{}, Synchronizer::SyncRequest::RequestFlush}; } return list; } -- cgit v1.2.3 From e179ec896bb5b55e33419da8bea2e891517697f6 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Mon, 12 Jun 2017 11:48:34 +0200 Subject: Avoid the extra parsing step. We only need the content, we'll parse later on when processing the pipeline. --- examples/imapresource/imapresource.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples/imapresource/imapresource.cpp') diff --git a/examples/imapresource/imapresource.cpp b/examples/imapresource/imapresource.cpp index a6c0343..5a9c36f 100644 --- a/examples/imapresource/imapresource.cpp +++ b/examples/imapresource/imapresource.cpp @@ -193,7 +193,7 @@ public: const auto remoteId = assembleMailRid(folderLocalId, message.uid); Q_ASSERT(message.msg); - SinkTraceCtx(mLogCtx) << "Found a mail " << remoteId << message.msg->subject(true)->asUnicodeString() << message.flags; + SinkTraceCtx(mLogCtx) << "Found a mail " << remoteId << message.flags; auto mail = Sink::ApplicationDomain::Mail::create(mResourceInstanceIdentifier); mail.setFolder(folderLocalId); -- cgit v1.2.3 From 7dc97cc6e338e1d756734e1620a062cdb08635ca Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Mon, 12 Jun 2017 16:09:29 +0200 Subject: There shouldn't be any conversions necessary at this point. --- examples/imapresource/imapresource.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'examples/imapresource/imapresource.cpp') diff --git a/examples/imapresource/imapresource.cpp b/examples/imapresource/imapresource.cpp index 5a9c36f..945962f 100644 --- a/examples/imapresource/imapresource.cpp +++ b/examples/imapresource/imapresource.cpp @@ -615,10 +615,10 @@ public: auto login = imap->login(mUser, mPassword); KAsync::Job job = KAsync::null(); if (operation == Sink::Operation_Creation) { - QString mailbox = syncStore().resolveLocalId(ENTITY_TYPE_FOLDER, mail.getFolder()); - QByteArray content = KMime::LFtoCRLF(mail.getMimeMessage()); - auto flags = getFlags(mail); - QDateTime internalDate = mail.getDate(); + const QString mailbox = syncStore().resolveLocalId(ENTITY_TYPE_FOLDER, mail.getFolder()); + const QByteArray content = mail.getMimeMessage(); + const auto flags = getFlags(mail); + const QDateTime internalDate = mail.getDate(); job = login.then(imap->append(mailbox, content, flags, internalDate)) .addToContext(imap) .then([mail](qint64 uid) { @@ -649,11 +649,11 @@ public: const bool messageMoved = changedProperties.contains(ApplicationDomain::Mail::Folder::name); const bool messageChanged = changedProperties.contains(ApplicationDomain::Mail::MimeMessage::name); if (messageChanged || messageMoved) { - SinkTrace() << "Replacing message."; const auto folderId = folderIdFromMailRid(oldRemoteId); const QString oldMailbox = syncStore().resolveLocalId(ENTITY_TYPE_FOLDER, folderId); - QByteArray content = KMime::LFtoCRLF(mail.getMimeMessage()); - QDateTime internalDate = mail.getDate(); + const QByteArray content = mail.getMimeMessage(); + const QDateTime internalDate = mail.getDate(); + SinkTrace() << "Replacing message. Old mailbox: " << oldMailbox << "New mailbox: " << mailbox << "Flags: " << flags << "Content: " << content; KIMAP2::ImapSet set; set.add(uid); job = login.then(imap->append(mailbox, content, flags, internalDate)) -- cgit v1.2.3 From ae1c5a0a53d1fd351b6fd33e8a46ad1034874489 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Wed, 14 Jun 2017 12:39:29 +0200 Subject: Deal with both CRLF and LF mime messages. IMAP always requires CRLF, and so does the MIME standard, KMIME expects LF-only. We now just try to always use CRLF on disk, but convert LF-only messages should we have to (e.g. because copied over from maildir or so). --- examples/imapresource/imapresource.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'examples/imapresource/imapresource.cpp') diff --git a/examples/imapresource/imapresource.cpp b/examples/imapresource/imapresource.cpp index 945962f..25d9534 100644 --- a/examples/imapresource/imapresource.cpp +++ b/examples/imapresource/imapresource.cpp @@ -197,7 +197,7 @@ public: auto mail = Sink::ApplicationDomain::Mail::create(mResourceInstanceIdentifier); mail.setFolder(folderLocalId); - mail.setMimeMessage(message.msg->encodedContent()); + mail.setMimeMessage(message.msg->encodedContent(true)); mail.setExtractedFullPayloadAvailable(message.fullPayload); setFlags(mail, message.flags); @@ -608,6 +608,15 @@ public: } return KAsync::error("Nothing to do"); } + static QByteArray ensureCRLF(const QByteArray &data) { + auto index = data.indexOf('\n'); + if (index > 0 && data.at(index - 1) == '\r') { //First line is LF-only terminated + //Convert back and forth in case there's a mix. We don't want to expand CRLF into CRCRLF. + return KMime::LFtoCRLF(KMime::CRLFtoLF(data)); + } else { + return data; + } + } KAsync::Job replay(const ApplicationDomain::Mail &mail, Sink::Operation operation, const QByteArray &oldRemoteId, const QList &changedProperties) Q_DECL_OVERRIDE { @@ -616,7 +625,7 @@ public: KAsync::Job job = KAsync::null(); if (operation == Sink::Operation_Creation) { const QString mailbox = syncStore().resolveLocalId(ENTITY_TYPE_FOLDER, mail.getFolder()); - const QByteArray content = mail.getMimeMessage(); + const auto content = ensureCRLF(mail.getMimeMessage()); const auto flags = getFlags(mail); const QDateTime internalDate = mail.getDate(); job = login.then(imap->append(mailbox, content, flags, internalDate)) @@ -651,7 +660,7 @@ public: if (messageChanged || messageMoved) { const auto folderId = folderIdFromMailRid(oldRemoteId); const QString oldMailbox = syncStore().resolveLocalId(ENTITY_TYPE_FOLDER, folderId); - const QByteArray content = mail.getMimeMessage(); + const auto content = ensureCRLF(mail.getMimeMessage()); const QDateTime internalDate = mail.getDate(); SinkTrace() << "Replacing message. Old mailbox: " << oldMailbox << "New mailbox: " << mailbox << "Flags: " << flags << "Content: " << content; KIMAP2::ImapSet set; -- cgit v1.2.3 From c6422cbbb24542a48e26b5f2448def3fcfc8694d Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Wed, 14 Jun 2017 13:23:48 +0200 Subject: We now have to manually parse for inspections ..since we turn of parsing for regular fetching. --- examples/imapresource/imapresource.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'examples/imapresource/imapresource.cpp') diff --git a/examples/imapresource/imapresource.cpp b/examples/imapresource/imapresource.cpp index 25d9534..9fb83ab 100644 --- a/examples/imapresource/imapresource.cpp +++ b/examples/imapresource/imapresource.cpp @@ -834,6 +834,10 @@ protected: .then(imap->select(folderRemoteId)) .then([](Imap::SelectResult){}) .then(imap->fetch(set, scope, [imap, messageByUid](const Imap::Message &message) { + //We avoid parsing normally, so we have to do it explicitly here + if (message.msg) { + message.msg->parse(); + } messageByUid->insert(message.uid, message); })); -- cgit v1.2.3 From 71ee6fc9b75bfb158ba507d9bd42b64d750029e0 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Wed, 14 Jun 2017 14:20:02 +0200 Subject: Cleanup --- examples/imapresource/imapresource.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples/imapresource/imapresource.cpp') diff --git a/examples/imapresource/imapresource.cpp b/examples/imapresource/imapresource.cpp index 9fb83ab..b28ecf1 100644 --- a/examples/imapresource/imapresource.cpp +++ b/examples/imapresource/imapresource.cpp @@ -584,7 +584,7 @@ public: bool syncHeaders = query.hasFilter(); //FIXME If we were able to to flush in between we could just query the local store for the folder list. return getFolderList(imap, query) - .serialEach([=](const Folder &folder) { + .serialEach([=](const Folder &folder) { SinkLog() << "Syncing folder " << folder.path(); //Emit notification that the folder is being synced. //The synchronizer can't do that because it has no concept of the folder filter on a mail sync scope meaning that the folder is being synchronized. -- cgit v1.2.3 From 01d470b8a94c2e022eb1ca620064732bf2ddece3 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Thu, 15 Jun 2017 10:28:50 +0200 Subject: Revert this change, we can just only sync folders in kube. --- examples/imapresource/imapresource.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'examples/imapresource/imapresource.cpp') diff --git a/examples/imapresource/imapresource.cpp b/examples/imapresource/imapresource.cpp index b28ecf1..81c808b 100644 --- a/examples/imapresource/imapresource.cpp +++ b/examples/imapresource/imapresource.cpp @@ -415,9 +415,8 @@ public: list << Synchronizer::SyncRequest{query}; } else { list << Synchronizer::SyncRequest{Sink::QueryBase(ApplicationDomain::getTypeName())}; - //TODO automatic syncing off all folders is disabled for the time being //This request depends on the previous one so we flush first. - //list << Synchronizer::SyncRequest{applyMailDefaults(Sink::QueryBase(ApplicationDomain::getTypeName())), QByteArray{}, Synchronizer::SyncRequest::RequestFlush}; + list << Synchronizer::SyncRequest{applyMailDefaults(Sink::QueryBase(ApplicationDomain::getTypeName())), QByteArray{}, Synchronizer::SyncRequest::RequestFlush}; } return list; } -- cgit v1.2.3