Index: messageviewer/src/viewer/bodypartformatter.cpp =================================================================== --- messageviewer/src/viewer/bodypartformatter.cpp +++ messageviewer/src/viewer/bodypartformatter.cpp @@ -32,10 +32,12 @@ #include "bodypartformatter.h" #include "messageviewer_debug.h" #include "viewer/bodypartformatterfactory_p.h" +#include "viewer/attachmentstrategy.h" #include "interfaces/bodypartformatter.h" #include "interfaces/bodypart.h" #include "viewer/objecttreeparser.h" +#include "messagepart.h" #include @@ -104,6 +106,47 @@ const ImageTypeBodyPartFormatter *ImageTypeBodyPartFormatter::self = 0; +class MessageRfc822BodyPartFormatter + : public BodyPartFormatter + , public MessageViewer::Interface::BodyPartFormatter +{ + static const MessageRfc822BodyPartFormatter * self; +public: + bool process(ObjectTreeParser *, KMime::Content *, ProcessResult &) const Q_DECL_OVERRIDE; + MessageViewer::Interface::BodyPartFormatter::Result format(Interface::BodyPart *, HtmlWriter *) const Q_DECL_OVERRIDE; + using MessageViewer::Interface::BodyPartFormatter::format; + static const ::BodyPartFormatter *create(); +}; + +const MessageRfc822BodyPartFormatter *MessageRfc822BodyPartFormatter::self; + +const ::BodyPartFormatter *MessageRfc822BodyPartFormatter::create() { + if (!self) { + self = new MessageRfc822BodyPartFormatter(); + } + return self; +} + +bool MessageRfc822BodyPartFormatter::process(ObjectTreeParser * otp, KMime::Content * node, ProcessResult & result) const +{ + PartMetaData metaData; + const KMime::Message::Ptr message = node->bodyAsMessage(); + EncapsulatedRfc822MessagePart mp(otp, &metaData, node, message); + + if (!otp->attachmentStrategy()->inlineNestedMessages() && !otp->showOnlyOneMimePart()) { + return false; + } else { + mp.html(true); + return true; + } +} + +MessageViewer::Interface::BodyPartFormatter::Result MessageRfc822BodyPartFormatter::format(Interface::BodyPart *part, HtmlWriter *writer) const +{ + bool ret = process(part->objectTreeParser(), part->content(), *part->processResult()); + return ret ? Ok: Failed; +} + #define CREATE_BODY_PART_FORMATTER(subtype) \ class subtype##BodyPartFormatter \ : public BodyPartFormatter \ @@ -142,8 +185,6 @@ CREATE_BODY_PART_FORMATTER(ApplicationChiasmusText) //CREATE_BODY_PART_FORMATTER(ApplicationPgp) -CREATE_BODY_PART_FORMATTER(MessageRfc822) - CREATE_BODY_PART_FORMATTER(MultiPartMixed) CREATE_BODY_PART_FORMATTER(MultiPartAlternative) CREATE_BODY_PART_FORMATTER(MultiPartSigned) Index: messageviewer/src/viewer/messagepart.h =================================================================== --- messageviewer/src/viewer/messagepart.h +++ messageviewer/src/viewer/messagepart.h @@ -103,6 +103,22 @@ PartMetaData *mMetaData; }; +class EncapsulatedRfc822MessagePart : public MessagePart +{ +public: + typedef QSharedPointer Ptr; + EncapsulatedRfc822MessagePart(MessageViewer::ObjectTreeParser *otp, MessageViewer::PartMetaData *block, KMime::Content *node, const KMime::Message::Ptr &message); + virtual ~EncapsulatedRfc822MessagePart(); + + QString text() const Q_DECL_OVERRIDE; + void html(bool decorate) const Q_DECL_OVERRIDE; + +private: + const KMime::Message::Ptr mMessage; + KMime::Content* mNode; + ObjectTreeParser *mSubOtp; +}; + class CryptoMessagePart : public MessagePart { public: Index: messageviewer/src/viewer/messagepart.cpp =================================================================== --- messageviewer/src/viewer/messagepart.cpp +++ messageviewer/src/viewer/messagepart.cpp @@ -18,6 +18,7 @@ */ #include "messagepart.h" +#include "messageviewer_debug.h" #include "objecttreeparser.h" #include @@ -389,3 +390,66 @@ } } } + +EncapsulatedRfc822MessagePart::EncapsulatedRfc822MessagePart(ObjectTreeParser* otp, PartMetaData* block, KMime::Content* node, const KMime::Message::Ptr& message) +: MessagePart(otp, block, QString()) +, mMessage(message) +, mNode(node) +, mSubOtp(0) +{ + mMetaData->isEncrypted = false; + mMetaData->isSigned = false; + mMetaData->isEncapsulatedRfc822Message = true; + + mOtp->nodeHelper()->setNodeDisplayedEmbedded(mNode, true); + mOtp->nodeHelper()->setPartMetaData(mNode, *mMetaData); + + if (!mMessage) { + qCWarning(MESSAGEVIEWER_LOG) << "Node is of type message/rfc822 but doesn't have a message!"; + return; + } + + // The link to "Encapsulated message" is clickable, therefore the temp file needs to exists, + // since the user can click the link and expect to have normal attachment operations there. + mOtp->nodeHelper()->writeNodeToTempFile(message.data()); + + mSubOtp = new ObjectTreeParser(mOtp, true); + mSubOtp->setAllowAsync(mOtp->allowAsync()); + if (mOtp->htmlWriter()) { + mSubOtp->mHtmlWriter = new QueueHtmlWriter(mOtp->htmlWriter()); + } + mSubOtp->parseObjectTreeInternal(message.data()); +} + +EncapsulatedRfc822MessagePart::~EncapsulatedRfc822MessagePart() +{ + +} + +void EncapsulatedRfc822MessagePart::html(bool decorate) const +{ + if (!mSubOtp) { + return; + } + + MessageViewer::HtmlWriter* writer = mOtp->htmlWriter(); + + if (!writer) { + return; + } + + const CryptoBlock block(mOtp, mMetaData, 0, mMessage->from()->asUnicodeString(), mMessage.data()); + writer->queue(mOtp->mSource->createMessageHeader(mMessage.data())); + static_cast(mSubOtp->htmlWriter())->reply(); + + mOtp->nodeHelper()->setPartMetaData(mNode, *mMetaData); +} + + +QString EncapsulatedRfc822MessagePart::text() const +{ + if (!mSubOtp) { + return QString(); + } + return mSubOtp->plainTextContent(); +} Index: messageviewer/src/viewer/objecttreeparser.h =================================================================== --- messageviewer/src/viewer/objecttreeparser.h +++ messageviewer/src/viewer/objecttreeparser.h @@ -393,10 +393,6 @@ multipart/signed object. Signature is tested. May contain body parts. - Returns whether a signature was found or not: use this to - find out if opaque data is signed or not. */ - bool writeOpaqueOrMultipartSignedData(KMime::Content* data, KMime::Content& sign, const QString& fromAddress, bool hideErrors = false); - /** Writes out the information contained in a GpgME::ImportResult */ void writeCertificateImportResult(const GpgME::ImportResult &res); @@ -435,8 +431,6 @@ bool processMultiPartSignedSubtype(KMime::Content *node, ProcessResult &result); bool processMultiPartEncryptedSubtype(KMime::Content *node, ProcessResult &result); - bool processMessageRfc822Subtype(KMime::Content *node, ProcessResult &result); - bool processApplicationPkcs7MimeSubtype(KMime::Content *node, ProcessResult &result); bool processApplicationChiasmusTextSubtype(KMime::Content *node, ProcessResult &result); @@ -535,6 +529,7 @@ friend class MessagePart; friend class CryptoMessagePart; + friend class EncapsulatedRfc822MessagePart; }; } Index: messageviewer/src/viewer/objecttreeparser.cpp =================================================================== --- messageviewer/src/viewer/objecttreeparser.cpp +++ messageviewer/src/viewer/objecttreeparser.cpp @@ -560,67 +560,6 @@ } } -bool ObjectTreeParser::writeOpaqueOrMultipartSignedData(KMime::Content *data, - KMime::Content &sign, - const QString &fromAddress, - bool hideErrors) -{ - bool bIsOpaqueSigned = false; - - const Kleo::CryptoBackend::Protocol *cryptProto = cryptoProtocol(); - -#ifdef DEBUG_SIGNATURE -#ifndef NDEBUG - if (data) { - qCDebug(MESSAGEVIEWER_LOG) << "processing Multipart Signed data"; - } else { - qCDebug(MESSAGEVIEWER_LOG) << "processing Opaque Signed data"; - } -#endif -#endif - - QByteArray cleartext; - QByteArray signaturetext; - const QTextCodec *aCodec(data ? codecFor(data) : codecFor(&sign)); - - if (cryptProto) { - if (data) { - cleartext = data->encodedContent(); - cleartext = KMime::LFtoCRLF(cleartext); - } - - dumpToFile("dat_02_reader_signedtext_after_canonicalization", - cleartext.data(), cleartext.length()); - - signaturetext = sign.decodedContent(); - dumpToFile("dat_03_reader.sig", signaturetext.data(), - signaturetext.size()); - } - - PartMetaData messagePart; - - CryptoMessagePart mp(this, &messagePart, - aCodec->toUnicode(data ? cleartext : signaturetext), cryptProto, - fromAddress, &sign); - - messagePart.isSigned = true; - - if (cryptProto) { - if (data) { // detached - mp.startVerificationDetached(cleartext, data, signaturetext); - } else { // opaque - mp.startVerificationDetached(signaturetext, Q_NULLPTR, QByteArray()); - bIsOpaqueSigned = true; - } - } else { - messagePart.auditLogError = GpgME::Error(GPG_ERR_NOT_IMPLEMENTED); - } - - mp.html(false); - - return bIsOpaqueSigned; -} - void ObjectTreeParser::writeCertificateImportResult(const GpgME::ImportResult &res) { if (res.error()) { @@ -1292,8 +1231,23 @@ CryptoProtocolSaver saver(this, protocol); mNodeHelper->setSignatureState(node, KMMsgFullySigned); - writeOpaqueOrMultipartSignedData(signedData, *signature, - NodeHelper::fromAsString(node)); + const QByteArray cleartext = KMime::LFtoCRLF(signedData->encodedContent()); + const QTextCodec *aCodec(codecFor(signedData)); + PartMetaData messagePart; + + CryptoMessagePart mp(this, &messagePart, + aCodec->toUnicode(cleartext), cryptoProtocol(), + NodeHelper::fromAsString(node), signature); + messagePart.isSigned = true; + + if (cryptoProtocol()) { + mp.startVerificationDetached(cleartext, signedData, signature->decodedContent()); + } else { + messagePart.auditLogError = GpgME::Error(GPG_ERR_NOT_IMPLEMENTED); + } + + mp.html(false); + return true; } @@ -1392,56 +1346,6 @@ return true; } -bool ObjectTreeParser::processMessageRfc822Subtype(KMime::Content *node, ProcessResult &) -{ - if (htmlWriter() && !attachmentStrategy()->inlineNestedMessages() && !showOnlyOneMimePart()) { - return false; - } - - PartMetaData messagePart; - messagePart.isEncrypted = false; - messagePart.isSigned = false; - messagePart.isEncapsulatedRfc822Message = true; - - KMime::Message::Ptr message = node->bodyAsMessage(); - if (!message) { - qCWarning(MESSAGEVIEWER_LOG) << "Node is of type message/rfc822 but doesn't have a message!"; - } - - if (htmlWriter() && message) { - - // The link to "Encapsulated message" is clickable, therefore the temp file needs to exists, - // since the user can click the link and expect to have normal attachment operations there. - mNodeHelper->writeNodeToTempFile(message.data()); - - // Paint the frame header - htmlWriter()->queue(writeSigstatHeader(messagePart, - cryptoProtocol(), - message->from()->asUnicodeString(), - message.data())); - - // Paint the message header - htmlWriter()->queue(mSource->createMessageHeader(message.data())); - - // Process the message, i.e. paint it by processing it with an OTP - ObjectTreeParser otp(this); - otp.parseObjectTreeInternal(message.data()); - - // Don't add the resulting textual content to our textual content here. - // That is unwanted when inline forwarding a message, since the encapsulated message will - // already be in the forward message as attachment, so don't duplicate the textual content - // by adding it to the inline body as well - - // Paint the frame footer - htmlWriter()->queue(writeSigstatFooter(messagePart)); - } - - mNodeHelper->setNodeDisplayedEmbedded(node, true); - mNodeHelper->setPartMetaData(node, messagePart); - - return true; -} - bool ObjectTreeParser::processApplicationPkcs7MimeSubtype(KMime::Content *node, ProcessResult &result) { if (KMime::Content *child = mNodeHelper->decryptedNodeForContent(node)) { @@ -1553,11 +1457,21 @@ qCDebug(MESSAGEVIEWER_LOG) << "pkcs7 mime - type unknown - opaque signed data ?"; } - bool sigFound = writeOpaqueOrMultipartSignedData(0, - *signTestNode, - NodeHelper::fromAsString(node), - isEncrypted); - if (sigFound) { + const QTextCodec *aCodec(codecFor(signTestNode)); + const QByteArray signaturetext = signTestNode->decodedContent(); + PartMetaData messagePart; + CryptoMessagePart mp(this, &messagePart, + aCodec->toUnicode(signaturetext), cryptoProtocol(), + NodeHelper::fromAsString(node), signTestNode); + + if (cryptoProtocol()) { + mp.startVerificationDetached(signaturetext, 0, QByteArray()); + } else { + messagePart.auditLogError = GpgME::Error(GPG_ERR_NOT_IMPLEMENTED); + } + + mp.html(false /*, hideErrors = isEncrypted*/); + if (messagePart.isSigned) { if (!isSigned) { qCDebug(MESSAGEVIEWER_LOG) << "pkcs7 mime - signature found - opaque signed data !"; isSigned = true;