From f28ec43dca5b2915deb69d54fb942ddf1303f48c Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Fri, 2 Mar 2018 12:07:18 +0100 Subject: Support encrypted mails forwarding Summary: Some notes: - What we do is: if the mail is encrypted, decrypt it and copy its content into a new message (with plaintext, html and attachments, if any), and use this message as attachment for forwarding - The `isEncrypted` function from KMime doesn't seem to detect every kind of encrypted mails. AFAIK this structure is not detected: - `multipart/mixed` - `text/plain` - `application/pgp-encrypted` (attachement, named "ATT00001") - `application/octet-stream` (attachment named "encrypted.asc") Reviewers: cmollekopf Tags: PHID-PROJ-6npnfcmppynqynn7slmv Maniphest Tasks: T8112, T7024 Differential Revision: https://phabricator.kde.org/D10966 --- framework/src/domain/mime/mailtemplates.cpp | 83 ++++++++++++++++++++++++++--- 1 file changed, 77 insertions(+), 6 deletions(-) (limited to 'framework/src/domain/mime') diff --git a/framework/src/domain/mime/mailtemplates.cpp b/framework/src/domain/mime/mailtemplates.cpp index 8e644b34..513f0353 100644 --- a/framework/src/domain/mime/mailtemplates.cpp +++ b/framework/src/domain/mime/mailtemplates.cpp @@ -53,6 +53,18 @@ static bool operator==(const KMime::Types::Mailbox &left, const KMime::Types::Ma return (left.addrSpec().asString() == right.addrSpec().asString()); } } + + Message* contentToMessage(Content* content) { + content->assemble(); + const auto encoded = content->encodedContent(); + + auto message = new Message(); + message->setContent(encoded); + message->parse(); + + return message; + } + } static KMime::Types::Mailbox::List stripMyAddressesFromAddressList(const KMime::Types::Mailbox::List &list, const KMime::Types::AddrSpecList me) @@ -223,6 +235,19 @@ KMime::Content *createMultipartAlternativeContent(const QString &plainBody, cons return multipartAlternative; } +KMime::Message *createMultipartMixedContent(QVector contents) +{ + KMime::Message *multiPartMixed = new KMime::Message(); + multiPartMixed->contentType()->setMimeType("multipart/mixed"); + multiPartMixed->contentType()->setBoundary(KMime::multiPartBoundary()); + + for (const auto &content : contents) { + multiPartMixed->addContent(content); + } + + return multiPartMixed; +} + void addProcessedBodyToMessage(const KMime::Message::Ptr &msg, const QString &plainBody, const QString &htmlBody, bool forward) { //FIXME @@ -864,27 +889,73 @@ void MailTemplates::reply(const KMime::Message::Ptr &origMsg, const std::functio }); } -void MailTemplates::forward(const KMime::Message::Ptr &origMsg, const std::function &callback) +void MailTemplates::forward(const KMime::Message::Ptr &origMsg, + const std::function &callback) { KMime::Message::Ptr wrapperMsg(new KMime::Message); wrapperMsg->to()->clear(); wrapperMsg->cc()->clear(); - wrapperMsg->subject()->fromUnicodeString(forwardSubject(origMsg->subject()->asUnicodeString()), "utf-8"); + // Decrypt the original message, it will be encrypted again in the composer + // for the right recipient + KMime::Message::Ptr forwardedMessage; + if (isEncrypted(origMsg.data())) { + qDebug() << "Original message was encrypted, decrypting it"; + MimeTreeParser::ObjectTreeParser otp; + otp.parseObjectTree(origMsg.data()); + otp.decryptParts(); - const QByteArray refStr = getRefStr(origMsg); + auto htmlContent = otp.htmlContent(); + KMime::Content *recreatedMsg = + htmlContent.isEmpty() ? createPlainPartContent(otp.plainTextContent()) : + createMultipartAlternativeContent(otp.plainTextContent(), htmlContent); + + if (hasAttachment(origMsg.data())) { + QVector contents = {recreatedMsg}; + contents.append(origMsg->attachments()); + + auto msg = createMultipartMixedContent(contents); + + forwardedMessage.reset(KMime::contentToMessage(msg)); + } else { + forwardedMessage.reset(KMime::contentToMessage(recreatedMsg)); + } + + forwardedMessage->subject()->from7BitString(origMsg->subject()->as7BitString()); + + for (const auto &addr : origMsg->to()->mailboxes()) { + forwardedMessage->to()->addAddress(addr); + } + + for (const auto &addr : origMsg->cc()->mailboxes()) { + forwardedMessage->cc()->addAddress(addr); + } + + for (const auto &addr : origMsg->bcc()->mailboxes()) { + forwardedMessage->bcc()->addAddress(addr); + } + + } else { + qDebug() << "Original message was not encrypted, using it as-is"; + forwardedMessage = origMsg; + } + + wrapperMsg->subject()->fromUnicodeString( + forwardSubject(forwardedMessage->subject()->asUnicodeString()), "utf-8"); + + const QByteArray refStr = getRefStr(forwardedMessage); if (!refStr.isEmpty()) { wrapperMsg->references()->fromUnicodeString(QString::fromLocal8Bit(refStr), "utf-8"); } - KMime::Content* fwdAttachment = new KMime::Content; + KMime::Content *fwdAttachment = new KMime::Content; fwdAttachment->contentDisposition()->setDisposition(KMime::Headers::CDinline); fwdAttachment->contentType()->setMimeType("message/rfc822"); - fwdAttachment->contentDisposition()->setFilename(origMsg->subject()->asUnicodeString() + ".eml"); + fwdAttachment->contentDisposition()->setFilename(forwardedMessage->subject()->asUnicodeString() + ".eml"); // The mail was parsed in loadMessage before, so no need to assemble it - fwdAttachment->setBody(origMsg->encodedContent()); + fwdAttachment->setBody(forwardedMessage->encodedContent()); wrapperMsg->addContent(fwdAttachment); wrapperMsg->assemble(); -- cgit v1.2.3