Index: messageviewer/src/CMakeLists.txt =================================================================== --- messageviewer/src/CMakeLists.txt +++ messageviewer/src/CMakeLists.txt @@ -161,6 +161,7 @@ set(libmessageviewer_htmlwriter_SRCS htmlwriter/filehtmlwriter.cpp + htmlwriter/queuehtmlwriter.cpp htmlwriter/teehtmlwriter.cpp htmlwriter/webkitparthtmlwriter.cpp ) Index: messageviewer/src/htmlwriter/queuehtmlwriter.h =================================================================== --- /dev/null +++ messageviewer/src/htmlwriter/queuehtmlwriter.h @@ -0,0 +1,74 @@ +/* + Copyright (c) 2015 Sandro Knauß + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#ifndef __MESSAGEVIEWER_QUEUEHTMLWRITER_H__ +#define __MESSAGEVIEWER_QUEUEHTMLWRITER_H__ + +#include "messageviewer_export.h" +#include "interfaces/htmlwriter.h" + +#include +#include + +class QString; +class QByteArray; + +namespace MessageViewer +{ +/** +\brief Cache HTML output and not write them directy. + +This class is needed to make it possible to first process the mime tree and +afterwards render the HTML. + +Please do not use this class - it is only added to make it possible to slowly +move ObjectTreeParser to a process fist / render later. + +*/ +struct Command { + enum { Begin, End, Reset, Write, Queue, Flush, EmbedPart, ExtraHead } type; + QString s; + QByteArray b; +}; + +class MESSAGEVIEWER_DEPRECATED_EXPORT QueueHtmlWriter : public HtmlWriter +{ +public: + explicit QueueHtmlWriter( MessageViewer::HtmlWriter* base ); + virtual ~QueueHtmlWriter(); + + void begin(const QString &cssDefs) Q_DECL_OVERRIDE; + void end() Q_DECL_OVERRIDE; + void reset() Q_DECL_OVERRIDE; + void write(const QString &str) Q_DECL_OVERRIDE; + void queue(const QString &str) Q_DECL_OVERRIDE; + void flush() Q_DECL_OVERRIDE; + void embedPart(const QByteArray &contentId, const QString &url) Q_DECL_OVERRIDE; + void extraHead(const QString &str) Q_DECL_OVERRIDE; + + void replay(); + +private: + HtmlWriter *mBase; + QVector mQueue; +}; + +} // namespace MessageViewer + +#endif // __MESSAGEVIEWER_QUEUEHTMLWRITER_H__ Index: messageviewer/src/htmlwriter/queuehtmlwriter.cpp =================================================================== --- /dev/null +++ messageviewer/src/htmlwriter/queuehtmlwriter.cpp @@ -0,0 +1,131 @@ +/* + Copyright (c) 2015 Sandro Knauß + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include "queuehtmlwriter.h" + +#include "messageviewer_debug.h" + +#include +#include + +using namespace MessageViewer; + +QueueHtmlWriter::QueueHtmlWriter(HtmlWriter *base) + : HtmlWriter() + , mBase(base) +{ +} + +QueueHtmlWriter::~QueueHtmlWriter() +{ +} + +void QueueHtmlWriter::begin(const QString &css) +{ + Command cmd; + cmd.type = Command::Begin; + cmd.s = css; + mQueue.append(cmd); +} + +void QueueHtmlWriter::end() +{ + Command cmd; + cmd.type = Command::End; + mQueue.append(cmd); +} + +void QueueHtmlWriter::reset() +{ + Command cmd; + cmd.type = Command::Reset; + mQueue.append(cmd); +} + +void QueueHtmlWriter::write(const QString &str) +{ + Command cmd; + cmd.type = Command::Write; + cmd.s = str; + mQueue.append(cmd); +} + +void QueueHtmlWriter::queue(const QString &str) +{ + Command cmd; + cmd.type = Command::Queue; + cmd.s = str; + mQueue.append(cmd); +} + +void QueueHtmlWriter::flush() +{ + Command cmd; + cmd.type = Command::Flush; + mQueue.append(cmd); +} + +void QueueHtmlWriter::replay() +{ + foreach(auto entry, mQueue) + { + switch(entry.type) { + case Command::Begin: + mBase->begin(entry.s); + break; + case Command::End: + mBase->end(); + break; + case Command::Reset: + mBase->reset(); + break; + case Command::Write: + mBase->write(entry.s); + break; + case Command::Queue: + mBase->queue(entry.s); + break; + case Command::Flush: + mBase->flush(); + break; + case Command::EmbedPart: + mBase->embedPart(entry.b, entry.s); + break; + case Command::ExtraHead: + mBase->extraHead(entry.s); + break; + } + } +} + +void QueueHtmlWriter::embedPart(const QByteArray &contentId, const QString &url) +{ + Command cmd; + cmd.type = Command::EmbedPart; + cmd.s = url; + cmd.b = contentId; + mQueue.append(cmd); +} +void QueueHtmlWriter::extraHead(const QString &extra) +{ + Command cmd; + cmd.type = Command::ExtraHead; + cmd.s = extra; + mQueue.append(cmd); +} \ No newline at end of file Index: messageviewer/src/viewer/messagepart.h =================================================================== --- messageviewer/src/viewer/messagepart.h +++ messageviewer/src/viewer/messagepart.h @@ -69,6 +69,8 @@ PartMetaData *block, const QString &text); + virtual ~MessagePart() {} + virtual QString text() const; void setText(const QString &text); virtual void html(bool decorate) const; @@ -92,6 +94,8 @@ const QString &fromAddress, KMime::Content *node); + virtual ~CryptoMessagePart(); + void startDecryption(const QByteArray &text, const QTextCodec *aCodec); void startDecryption(KMime::Content *data = 0); void startVerification(const QByteArray &text, const QTextCodec *aCodec); @@ -108,9 +112,10 @@ void writeDeferredDecryptionBlock() const; protected: + ObjectTreeParser *mSubOtp; const Kleo::CryptoBackend::Protocol *mCryptoProto; QString mFromAddress; - KMime::Content *mNode, *mTextNode; + KMime::Content *mNode; bool mDecryptMessage; QByteArray mVerifiedText; }; Index: messageviewer/src/viewer/messagepart.cpp =================================================================== --- messageviewer/src/viewer/messagepart.cpp +++ messageviewer/src/viewer/messagepart.cpp @@ -21,6 +21,7 @@ #include "objecttreeparser.h" #include +#include #include #include #include @@ -118,11 +119,11 @@ const QString &fromAddress, KMime::Content *node) : MessagePart(otp, block, text) + , mSubOtp(0) , mCryptoProto(cryptoProto) , mDecryptMessage(false) , mFromAddress(fromAddress) , mNode(node) - , mTextNode(0) { mMetaData->technicalProblem = (mCryptoProto == 0); mMetaData->isSigned = false; @@ -134,6 +135,16 @@ mMetaData->status_code = GPGME_SIG_STAT_NONE; } +CryptoMessagePart::~CryptoMessagePart() +{ + if (mSubOtp) { + delete mSubOtp->mHtmlWriter; + delete mSubOtp; + mSubOtp = 0; + } +} + + void CryptoMessagePart::startDecryption(const QByteArray &text, const QTextCodec *aCodec) { mDecryptMessage = true; @@ -193,6 +204,24 @@ if (mNode) { mOtp->mNodeHelper->setPartMetaData(mNode, *mMetaData); + + if (mDecryptMessage) { + auto tempNode = new KMime::Content(); + tempNode->setContent(KMime::CRLFtoLF(mDecryptedData.constData())); + tempNode->parse(); + + if (!tempNode->head().isEmpty()) { + tempNode->contentDescription()->from7BitString("encrypted data"); + } + mOtp->mNodeHelper->attachExtraContent(mNode, tempNode); + + mSubOtp = new ObjectTreeParser(mOtp, true); + mSubOtp->setAllowAsync(mOtp->allowAsync()); + if (mOtp->htmlWriter()) { + mSubOtp->mHtmlWriter = new QueueHtmlWriter(mOtp->htmlWriter()); + } + mSubOtp->parseObjectTreeInternal(tempNode); + } } } @@ -220,8 +249,25 @@ if (mNode) { if (textNode && !signature.isEmpty()) { - mTextNode = textNode; mVerifiedText = text; + } else if (!mVerifiedText.isEmpty()) { + textNode = new KMime::Content(); + textNode->setContent(KMime::CRLFtoLF(mVerifiedText.constData())); + textNode->parse(); + + if (!textNode->head().isEmpty()) { + textNode->contentDescription()->from7BitString("opaque signed data"); + } + mOtp->mNodeHelper->attachExtraContent(mNode, textNode); + } + + if (!mVerifiedText.isEmpty() && textNode) { + mSubOtp = new ObjectTreeParser(mOtp, true); + mSubOtp->setAllowAsync(mOtp->allowAsync()); + if (mOtp->htmlWriter()) { + mSubOtp->mHtmlWriter = new QueueHtmlWriter(mOtp->htmlWriter()); + } + mSubOtp->parseObjectTreeInternal(textNode); } } @@ -255,28 +301,20 @@ bool hideErrors = false; MessageViewer::HtmlWriter* writer = mOtp->htmlWriter(); - if (!writer) { - if (mNode && (mDecryptMessage || !mVerifiedText.isEmpty())) { - //TODO: Bad hack, we need the TempNodeParsing anycase - // but till we not make sure that the nodeparsing also creates html directly we need to have this hack. - if (!mVerifiedText.isEmpty() && mTextNode) { - auto otp = new ObjectTreeParser(mOtp, true); - otp->setAllowAsync(mOtp->allowAsync()); - otp->parseObjectTreeInternal(mTextNode); - mOtp->copyContentFrom(otp); - } else if (!mVerifiedText.isEmpty()) { - mOtp->createAndParseTempNode(mNode, mVerifiedText.constData(), "opaque signed data"); - } else { - mOtp->createAndParseTempNode(mNode, mDecryptedData.constData(), "encrypted node"); - } - } - return; + + //TODO: still the following part should not be here + if (mSubOtp) { + mOtp->copyContentFrom(mSubOtp); } if (mMetaData->isEncrypted && !mDecryptMessage) { mMetaData->isDecryptable = true; } + if (!writer) { + return; + } + if (mMetaData->isEncrypted && !mDecryptMessage) { const CryptoBlock block(mOtp, mMetaData, mCryptoProto, mFromAddress, mNode); writeDeferredDecryptionBlock(); @@ -303,15 +341,8 @@ } } else if (mNode) { const CryptoBlock block(mOtp, mMetaData, mCryptoProto, mFromAddress, mNode); - if (!mVerifiedText.isEmpty() && mTextNode) { - auto otp = new ObjectTreeParser(mOtp, true); - otp->setAllowAsync(mOtp->allowAsync()); - otp->parseObjectTreeInternal(mTextNode); - mOtp->copyContentFrom(otp); - } else if (!mVerifiedText.isEmpty()) { - mOtp->createAndParseTempNode(mNode, mVerifiedText.constData(), "opaque signed data"); - } else { - mOtp->createAndParseTempNode(mNode, mDecryptedData.constData(), "encrypted node"); + if (mSubOtp) { + static_cast(mSubOtp->htmlWriter())->replay(); } } else { MessagePart::html(decorate); Index: messageviewer/src/viewer/objecttreeparser.h =================================================================== --- messageviewer/src/viewer/objecttreeparser.h +++ messageviewer/src/viewer/objecttreeparser.h @@ -511,6 +511,7 @@ private: ObjectTreeSourceIf *mSource; NodeHelper *mNodeHelper; + HtmlWriter *mHtmlWriter; QByteArray mPlainTextContentCharset; QByteArray mHtmlContentCharset; QString mPlainTextContent; Index: messageviewer/src/viewer/objecttreeparser.cpp =================================================================== --- messageviewer/src/viewer/objecttreeparser.cpp +++ messageviewer/src/viewer/objecttreeparser.cpp @@ -150,6 +150,7 @@ bool includeSignatures, const AttachmentStrategy *strategy) : mSource(topLevelParser->mSource), + mHtmlWriter(topLevelParser->mHtmlWriter), mNodeHelper(topLevelParser->mNodeHelper), mTopLevelContent(topLevelParser->mTopLevelContent), mCryptoProtocol(topLevelParser->mCryptoProtocol), @@ -171,6 +172,7 @@ bool includeSignatures, const AttachmentStrategy *strategy) : mSource(source), + mHtmlWriter(0), mNodeHelper(nodeHelper), mTopLevelContent(0), mCryptoProtocol(protocol), @@ -202,6 +204,7 @@ ObjectTreeParser::ObjectTreeParser(const ObjectTreeParser &other) : mSource(other.mSource), + mHtmlWriter(other.mHtmlWriter), mNodeHelper(other.nodeHelper()), //TODO(Andras) hm, review what happens if mDeleteNodeHelper was true in the source mTopLevelContent(other.mTopLevelContent), mCryptoProtocol(other.cryptoProtocol()), @@ -3189,6 +3192,9 @@ HtmlWriter *ObjectTreeParser::htmlWriter() const { + if (mHtmlWriter) { + return mHtmlWriter; + } return mSource->htmlWriter(); }