diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.0) -set(PIM_VERSION "5.6.49") +set(PIM_VERSION "5.6.50") if (POLICY CMP0053) cmake_policy(SET CMP0053 NEW) diff --git a/messagecomposer/autotests/cryptocomposertest.cpp b/messagecomposer/autotests/cryptocomposertest.cpp --- a/messagecomposer/autotests/cryptocomposertest.cpp +++ b/messagecomposer/autotests/cryptocomposertest.cpp @@ -23,7 +23,6 @@ #include "qtest_messagecomposer.h" #include "cryptofunctions.h" -#include "testhtmlwriter.h" #include "testcsshelper.h" #include @@ -50,6 +49,7 @@ #include #include +#include using MessageCore::AttachmentPart; @@ -153,15 +153,17 @@ QCOMPARE(message->from()->asUnicodeString(), QString::fromLocal8Bit("me@me.me")); QCOMPARE(message->to()->asUnicodeString(), QString::fromLocal8Bit("you@you.you")); - TestHtmlWriter testWriter; + MimeTreeParser::BufferedHtmlWriter testWriter; + testWriter.begin(); TestCSSHelper testCSSHelper; MessageComposer::Test::TestObjectTreeSource testSource(&testWriter, &testCSSHelper); testSource.setAllowDecryption(true); MimeTreeParser::NodeHelper *nh = new MimeTreeParser::NodeHelper; MimeTreeParser::ObjectTreeParser otp(&testSource, nh); MimeTreeParser::ProcessResult pResult(nh); otp.parseObjectTree(message.data()); + testWriter.end(); KMime::Message::Ptr unencrypted = nh->unencryptedMessage(message); KMime::Content *testAttachment = Util::findTypeInMessage(unencrypted.data(), "x-some", "x-type"); diff --git a/messagecomposer/autotests/cryptofunctions.cpp b/messagecomposer/autotests/cryptofunctions.cpp --- a/messagecomposer/autotests/cryptofunctions.cpp +++ b/messagecomposer/autotests/cryptofunctions.cpp @@ -20,7 +20,6 @@ #include "cryptofunctions.h" -#include "testhtmlwriter.h" #include "testcsshelper.h" #include "MessageComposer/Util" @@ -32,6 +31,7 @@ #include #include #include +#include #include @@ -61,7 +61,8 @@ resultMessage->parse(); // parse the result and make sure it is valid in various ways - TestHtmlWriter testWriter; + MimeTreeParser::BufferedHtmlWriter testWriter; + testWriter.begin(); TestCSSHelper testCSSHelper; MessageComposer::Test::TestObjectTreeSource testSource(&testWriter, &testCSSHelper); MimeTreeParser::NodeHelper *nh = new MimeTreeParser::NodeHelper; @@ -133,7 +134,8 @@ resultMessage->parse(); // parse the result and make sure it is valid in various ways - TestHtmlWriter testWriter; + MimeTreeParser::BufferedHtmlWriter testWriter; + testWriter.begin(); TestCSSHelper testCSSHelper; MessageComposer::Test::TestObjectTreeSource testSource(&testWriter, &testCSSHelper); testSource.setAllowDecryption(true); @@ -188,7 +190,8 @@ resultMessage->parse(); // parse the result and make sure it is valid in various ways - TestHtmlWriter testWriter; + MimeTreeParser::BufferedHtmlWriter testWriter; + testWriter.begin(); TestCSSHelper testCSSHelper; MessageComposer::Test::TestObjectTreeSource testSource(&testWriter, &testCSSHelper); testSource.setAllowDecryption(true); diff --git a/messagecomposer/autotests/messagefactoryngtest.cpp b/messagecomposer/autotests/messagefactoryngtest.cpp --- a/messagecomposer/autotests/messagefactoryngtest.cpp +++ b/messagecomposer/autotests/messagefactoryngtest.cpp @@ -35,10 +35,10 @@ #include "MessageComposer/InfoPart" #include "MessageComposer/TextPart" -#include "testhtmlwriter.h" #include "testcsshelper.h" #include +#include #include #include diff --git a/messagecomposer/autotests/testhtmlwriter.h b/messagecomposer/autotests/testhtmlwriter.h deleted file mode 100644 --- a/messagecomposer/autotests/testhtmlwriter.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - Copyright (C) 2009 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.net - Copyright (c) 2009 Leo Franchi - - 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 TEST_HTML_WRITER_H -#define TEST_HTML_WRITER_H - -#include - -// Objecttreeparser needs a valid html writer othewise it doesn't parse -// inline messages, so give it one to chew on. -class TestHtmlWriter : public MimeTreeParser::HtmlWriter -{ -public: - explicit TestHtmlWriter() - { - } - - virtual ~TestHtmlWriter() - { - } - - void begin() override - { - } - - void write(const QString &) override - { - } - - void end() override - { - } - - void embedPart(const QByteArray &, const QString &) override - { - } - - void extraHead(const QString &) override - { - } -}; - -#endif diff --git a/messageviewer/src/htmlwriter/webengineparthtmlwriter.h b/messageviewer/src/htmlwriter/webengineparthtmlwriter.h --- a/messageviewer/src/htmlwriter/webengineparthtmlwriter.h +++ b/messageviewer/src/htmlwriter/webengineparthtmlwriter.h @@ -17,7 +17,7 @@ #ifndef WEBENGINEPARTHTMLWRITER_H #define WEBENGINEPARTHTMLWRITER_H -#include +#include #include #include @@ -28,7 +28,7 @@ } namespace MessageViewer { -class WebEnginePartHtmlWriter : public QObject, public MimeTreeParser::HtmlWriter +class WebEnginePartHtmlWriter : public QObject, public MimeTreeParser::BufferedHtmlWriter { Q_OBJECT public: @@ -38,7 +38,6 @@ void begin() override; void end() override; void reset() override; - void write(const QString &str) override; void embedPart(const QByteArray &contentId, const QString &url) override; void extraHead(const QString &str) override; @@ -50,7 +49,6 @@ private: MailWebEngineView *mHtmlView = nullptr; - QString mHtml; QString mExtraHead; enum State { Begun, diff --git a/messageviewer/src/htmlwriter/webengineparthtmlwriter.cpp b/messageviewer/src/htmlwriter/webengineparthtmlwriter.cpp --- a/messageviewer/src/htmlwriter/webengineparthtmlwriter.cpp +++ b/messageviewer/src/htmlwriter/webengineparthtmlwriter.cpp @@ -29,7 +29,6 @@ WebEnginePartHtmlWriter::WebEnginePartHtmlWriter(MailWebEngineView *view, QObject *parent) : QObject(parent) - , MimeTreeParser::HtmlWriter() , mHtmlView(view) , mState(Ended) { @@ -47,22 +46,25 @@ reset(); } + BufferedHtmlWriter::begin(); MessageViewer::WebEngineEmbedPart::self()->clear(); mState = Begun; } void WebEnginePartHtmlWriter::end() { + BufferedHtmlWriter::end(); if (mState != Begun) { qCWarning(MESSAGEVIEWER_LOG) << "Called on non-begun or queued session!"; } if (!mExtraHead.isEmpty()) { insertExtraHead(); mExtraHead.clear(); } - mHtmlView->setHtml(mHtml, QUrl(QStringLiteral("file:///"))); + // see QWebEnginePage::setHtml() + mHtmlView->setContent(data(), QStringLiteral("text/html;charset=UTF-8"), QUrl(QStringLiteral("file:///"))); mHtmlView->show(); - mHtml.clear(); + clear(); mHtmlView->setUpdatesEnabled(true); mHtmlView->update(); @@ -72,33 +74,25 @@ void WebEnginePartHtmlWriter::reset() { + BufferedHtmlWriter::reset(); if (mState != Ended) { - mHtml.clear(); mState = Begun; // don't run into end()'s warning end(); mState = Ended; } } -void WebEnginePartHtmlWriter::write(const QString &str) -{ - if (mState != Begun) { - qCWarning(MESSAGEVIEWER_LOG) << "Called in Ended or Queued state!"; - } - mHtml.append(str); -} - void WebEnginePartHtmlWriter::embedPart(const QByteArray &contentId, const QString &contentURL) { MessageViewer::WebEngineEmbedPart::self()->addEmbedPart(contentId, contentURL); } void WebEnginePartHtmlWriter::insertExtraHead() { - const QString headTag(QStringLiteral("")); - const int index = mHtml.indexOf(headTag); + const auto headTag(QByteArrayLiteral("")); + const int index = m_data.indexOf(headTag); if (index != -1) { - mHtml.insert(index + headTag.length(), mExtraHead); + m_data.insert(index + headTag.length(), mExtraHead.toUtf8()); } } diff --git a/messageviewer/src/messagepartthemes/default/autotests/objecttreeparsertest.cpp b/messageviewer/src/messagepartthemes/default/autotests/objecttreeparsertest.cpp --- a/messageviewer/src/messagepartthemes/default/autotests/objecttreeparsertest.cpp +++ b/messageviewer/src/messagepartthemes/default/autotests/objecttreeparsertest.cpp @@ -21,7 +21,7 @@ #include "setupenv.h" #include -#include +#include #include #include @@ -92,12 +92,14 @@ QCOMPARE(msg->contents().size(), 2); // Parse the message - Test::HtmlWriter testWriter; + MimeTreeParser::BufferedHtmlWriter testWriter; + testWriter.begin(); Test::CSSHelper testCSSHelper; NodeHelper nodeHelper; Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); ObjectTreeParser otp(&emptySource, &nodeHelper); otp.parseObjectTree(msg.data()); + testWriter.end(); // Check that the OTP didn't modify the message in weird ways QCOMPARE(msg->contents().size(), 2); @@ -128,12 +130,14 @@ false).constData(), "Simple Mail Without Content-Type Header"); QCOMPARE(msg->contents().size(), 0); - Test::HtmlWriter testWriter; + MimeTreeParser::BufferedHtmlWriter testWriter; + testWriter.begin(); Test::CSSHelper testCSSHelper; NodeHelper nodeHelper; Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); ObjectTreeParser otp(&emptySource, &nodeHelper); otp.parseObjectTree(msg.data()); + testWriter.end(); QCOMPARE(otp.plainTextContent().toLatin1().data(), "asdfasdf"); QVERIFY(otp.htmlContent().isEmpty()); @@ -146,14 +150,16 @@ QCOMPARE(msg->subject()->as7BitString(false).constData(), "inlinepgpencrypted"); QCOMPARE(msg->contents().size(), 0); - Test::HtmlWriter testWriter; + MimeTreeParser::BufferedHtmlWriter testWriter; + testWriter.begin(); Test::CSSHelper testCSSHelper; NodeHelper nodeHelper; Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); ObjectTreeParser otp(&emptySource, &nodeHelper); emptySource.setAllowDecryption(true); otp.parseObjectTree(msg.data()); + testWriter.end(); QCOMPARE(otp.plainTextContent().toLatin1().data(), "some random text"); @@ -171,14 +177,16 @@ QCOMPARE(msg->subject()->as7BitString(false).constData(), "test"); QCOMPARE(msg->contents().size(), 0); - Test::HtmlWriter testWriter; + MimeTreeParser::BufferedHtmlWriter testWriter; + testWriter.begin(); Test::CSSHelper testCSSHelper; NodeHelper nodeHelper; Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); ObjectTreeParser otp(&emptySource, &nodeHelper); emptySource.setAllowDecryption(true); otp.parseObjectTree(msg.data()); + testWriter.end(); // This test is only a workaround, till we can set the memento to the propper node of the mail. QVERIFY(nodeHelper.bodyPartMemento(nullptr, "verification")); @@ -209,12 +217,14 @@ QCOMPARE(msg->subject()->as7BitString(false).constData(), "HTML test"); QCOMPARE(msg->contents().size(), 2); - Test::HtmlWriter testWriter; + MimeTreeParser::BufferedHtmlWriter testWriter; + testWriter.begin(); Test::CSSHelper testCSSHelper; Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); ObjectTreeParser otp(&emptySource); emptySource.setPreferredMode(MimeTreeParser::Util::MultipartPlain); otp.parseObjectTree(msg.data()); + testWriter.end(); QCOMPARE(otp.htmlContent().toLatin1().constData(), ""); QCOMPARE(otp.htmlContentCharset().constData(), ""); @@ -245,19 +255,20 @@ QCOMPARE(msg->subject()->as7BitString(false).constData(), "HTML test"); QCOMPARE(msg->contents().size(), 0); - Test::HtmlWriter testWriter; + MimeTreeParser::BufferedHtmlWriter testWriter; + testWriter.begin(); Test::CSSHelper testCSSHelper; Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); ObjectTreeParser otp(&emptySource); emptySource.setPreferredMode(MimeTreeParser::Util::MultipartPlain); otp.parseObjectTree(msg.data()); + testWriter.end(); QVERIFY(otp.plainTextContent().isEmpty()); QVERIFY(otp.htmlContent().contains(QStringLiteral("SOME HTML text."))); - QVERIFY(testWriter.html.contains(QStringLiteral( - "This is an HTML message. For security reasons, only the raw HTML code is shown."))); - QVERIFY(testWriter.html.contains(QStringLiteral("*SOME* HTML text.
"))); + QVERIFY(testWriter.data().contains("This is an HTML message. For security reasons, only the raw HTML code is shown.")); + QVERIFY(testWriter.data().contains("SOME* HTML text.
")); } void ObjectTreeParserTester::test_HTMLExternal() @@ -268,101 +279,108 @@ QCOMPARE(msg->contents().size(), 0); { - Test::HtmlWriter testWriter; + MimeTreeParser::BufferedHtmlWriter testWriter; + testWriter.begin(); Test::CSSHelper testCSSHelper; Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); ObjectTreeParser otp(&emptySource); otp.parseObjectTree(msg.data()); + testWriter.end(); QVERIFY(otp.plainTextContent().isEmpty()); QVERIFY(otp.htmlContent().contains(QStringLiteral("SOME HTML text."))); - QVERIFY(testWriter.html.contains(QStringLiteral("SOME HTML text."))); - QVERIFY(testWriter.html.contains(QStringLiteral( - "This HTML message may contain external references to images etc. For security/privacy reasons external references are not loaded."))); + QVERIFY(testWriter.data().contains("SOME HTML text.")); + QVERIFY(testWriter.data().contains("This HTML message may contain external references to images etc. For security/privacy reasons external references are not loaded.")); } { - Test::HtmlWriter testWriter; + MimeTreeParser::BufferedHtmlWriter testWriter; + testWriter.begin(); Test::CSSHelper testCSSHelper; Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); ObjectTreeParser otp(&emptySource); emptySource.setHtmlLoadExternal(true); otp.parseObjectTree(msg.data()); + testWriter.end(); QVERIFY(otp.htmlContent().contains(QStringLiteral("SOME HTML text."))); - QVERIFY(testWriter.html.contains(QStringLiteral("SOME HTML text."))); - QVERIFY(!testWriter.html.contains(QStringLiteral( - "This HTML message may contain external references to images etc. For security/privacy reasons external references are not loaded."))); + QVERIFY(testWriter.data().contains("SOME HTML text.")); + QVERIFY(!testWriter.data().contains("This HTML message may contain external references to images etc. For security/privacy reasons external references are not loaded.")); } } void ObjectTreeParserTester::test_Alternative() { KMime::Message::Ptr msg = Test::readAndParseMail(QStringLiteral("alternative.mbox")); QCOMPARE(msg->contents().size(), 2); { - Test::HtmlWriter testWriter; + MimeTreeParser::BufferedHtmlWriter testWriter; + testWriter.begin(); Test::CSSHelper testCSSHelper; Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); ObjectTreeParser otp(&emptySource); emptySource.setPreferredMode(MimeTreeParser::Util::MultipartPlain); otp.parseObjectTree(msg.data()); + testWriter.end(); QVERIFY(otp.htmlContent().isEmpty()); QVERIFY(otp.plainTextContent().contains(QStringLiteral( "If you can see this text it means that your email client couldn't display our newsletter properly."))); - QVERIFY(testWriter.html.contains(QStringLiteral( - "If you can see this text it means that your email client couldn't display our newsletter properly."))); + QVERIFY(testWriter.data().contains("If you can see this text it means that your email client couldn't display our newsletter properly.")); } { - Test::HtmlWriter testWriter; + MimeTreeParser::BufferedHtmlWriter testWriter; + testWriter.begin(); Test::CSSHelper testCSSHelper; Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); ObjectTreeParser otp(&emptySource); emptySource.setPreferredMode(MimeTreeParser::Util::MultipartHtml); otp.parseObjectTree(msg.data()); + testWriter.end(); QVERIFY(otp.plainTextContent().contains(QStringLiteral( "If you can see this text it means that your email client couldn't display our newsletter properly."))); QVERIFY(otp.htmlContent().contains(QStringLiteral( "Some HTML text

"))); - QVERIFY(testWriter.html.contains(QStringLiteral( - "Some HTML text

"))); + QVERIFY(testWriter.data().contains("Some HTML text

")); } msg = Test::readAndParseMail(QStringLiteral("alternative-notext.mbox")); QCOMPARE(msg->contents().size(), 1); { - Test::HtmlWriter testWriter; + MimeTreeParser::BufferedHtmlWriter testWriter; + testWriter.begin(); Test::CSSHelper testCSSHelper; Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); ObjectTreeParser otp(&emptySource); emptySource.setPreferredMode(MimeTreeParser::Util::MultipartPlain); otp.parseObjectTree(msg.data()); + testWriter.end(); QVERIFY(otp.plainTextContent().isEmpty()); QVERIFY(otp.htmlContent().isEmpty()); - QVERIFY(testWriter.html.contains(QStringLiteral("Some *HTML* text"))); + QVERIFY(testWriter.data().contains("Some *HTML* text")); } { - Test::HtmlWriter testWriter; + MimeTreeParser::BufferedHtmlWriter testWriter; + testWriter.begin(); Test::CSSHelper testCSSHelper; Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); ObjectTreeParser otp(&emptySource); emptySource.setPreferredMode(MimeTreeParser::Util::MultipartHtml); otp.parseObjectTree(msg.data()); + testWriter.end(); QVERIFY(otp.plainTextContent().isEmpty()); QVERIFY(otp.htmlContent().contains(QStringLiteral( "Some HTML text

"))); - QVERIFY(testWriter.html.contains(QStringLiteral( - "Some HTML text

"))); + QVERIFY(testWriter.data().contains("Some HTML text

")); } } diff --git a/messageviewer/src/messagepartthemes/default/autotests/quotehtmltest.cpp b/messageviewer/src/messagepartthemes/default/autotests/quotehtmltest.cpp --- a/messageviewer/src/messagepartthemes/default/autotests/quotehtmltest.cpp +++ b/messageviewer/src/messagepartthemes/default/autotests/quotehtmltest.cpp @@ -22,7 +22,7 @@ #include "setupenv.h" #include -#include +#include #include #include #include @@ -138,7 +138,7 @@ QFETCH(QString, result); QFETCH(bool, showExpandQuotesMark); QFETCH(int, quotelevel); - Test::HtmlWriter testWriter; + MimeTreeParser::BufferedHtmlWriter testWriter; Test::CSSHelper testCSSHelper; Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); emptySource.setShowExpandQuotesMark(showExpandQuotesMark); diff --git a/messageviewer/src/messagepartthemes/default/autotests/unencryptedmessagetest.cpp b/messageviewer/src/messagepartthemes/default/autotests/unencryptedmessagetest.cpp --- a/messageviewer/src/messagepartthemes/default/autotests/unencryptedmessagetest.cpp +++ b/messageviewer/src/messagepartthemes/default/autotests/unencryptedmessagetest.cpp @@ -24,6 +24,7 @@ #include #include +#include #include @@ -53,11 +54,13 @@ = Test::readAndParseMail(QStringLiteral("signed-forward-openpgp-signed-encrypted.mbox")); MimeTreeParser::NodeHelper nodeHelper; - Test::HtmlWriter testWriter; + MimeTreeParser::BufferedHtmlWriter testWriter; + testWriter.begin(); Test::CSSHelper testCSSHelper; Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); MimeTreeParser::ObjectTreeParser otp(&emptySource, &nodeHelper); otp.parseObjectTree(originalMessage.data()); + testWriter.end(); QCOMPARE(otp.plainTextContent().toLatin1().data(), "bla bla bla"); // The textual content doesn't include the encrypted encapsulated message by design QCOMPARE(nodeHelper.overallEncryptionState( @@ -75,12 +78,14 @@ = Test::readAndParseMail(QStringLiteral("forward-openpgp-signed-encrypted.mbox")); MimeTreeParser::NodeHelper nodeHelper; - Test::HtmlWriter testWriter; + MimeTreeParser::BufferedHtmlWriter testWriter; + testWriter.begin(); Test::CSSHelper testCSSHelper; Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); emptySource.setAllowDecryption(true); MimeTreeParser::ObjectTreeParser otp(&emptySource, &nodeHelper); otp.parseObjectTree(originalMessage.data()); + testWriter.end(); QCOMPARE(otp.plainTextContent().toLatin1().data(), "bla bla bla"); // The textual content doesn't include the encrypted encapsulated message by design QCOMPARE(nodeHelper.overallEncryptionState( @@ -308,20 +313,21 @@ KMime::Message::Ptr originalMessage = Test::readAndParseMail(mailFileName); MimeTreeParser::NodeHelper nodeHelper; - Test::HtmlWriter testWriter; + MimeTreeParser::BufferedHtmlWriter testWriter; + testWriter.begin(); Test::CSSHelper testCSSHelper; Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); emptySource.setAllowDecryption(false); MimeTreeParser::ObjectTreeParser otp(&emptySource, &nodeHelper); otp.parseObjectTree(originalMessage.data()); + testWriter.end(); if (decryptMessage) { QCOMPARE(otp.plainTextContent().toLatin1().data(), ""); } else { QVERIFY(otp.plainTextContent().toLatin1().data()); } - QCOMPARE(testWriter.html.contains(QStringLiteral( - "")), decryptMessage); + QCOMPARE(testWriter.data().contains(""), decryptMessage); KMime::Message::Ptr unencryptedMessage = nodeHelper.unencryptedMessage(originalMessage); QCOMPARE((bool)unencryptedMessage, false); @@ -332,12 +338,14 @@ KMime::Message::Ptr originalMessage = Test::readAndParseMail(QStringLiteral("smime-cert.mbox")); MimeTreeParser::NodeHelper nodeHelper; - Test::HtmlWriter testWriter; + MimeTreeParser::BufferedHtmlWriter testWriter; + testWriter.begin(); Test::CSSHelper testCSSHelper; Test::ObjectTreeSource emptySource(&testWriter, &testCSSHelper); MimeTreeParser::ObjectTreeParser otp(&emptySource, &nodeHelper); otp.parseObjectTree(originalMessage.data()); + testWriter.end(); QCOMPARE(otp.plainTextContent().toLatin1().data(), ""); - QVERIFY(testWriter.html.contains(QStringLiteral("Sorry, certificate could not be imported."))); + QVERIFY(testWriter.data().contains("Sorry, certificate could not be imported.")); } diff --git a/messageviewer/src/messagepartthemes/default/autotests/util.h b/messageviewer/src/messagepartthemes/default/autotests/util.h --- a/messageviewer/src/messagepartthemes/default/autotests/util.h +++ b/messageviewer/src/messagepartthemes/default/autotests/util.h @@ -27,41 +27,6 @@ namespace MessageViewer { namespace Test { -class HtmlWriter : public MimeTreeParser::HtmlWriter -{ -public: - explicit HtmlWriter() - { - } - - virtual ~HtmlWriter() - { - } - - void begin() override - { - } - - void write(const QString &str) override - { - html += str; - } - - void end() override - { - } - - void embedPart(const QByteArray &, const QString &) override - { - } - - void extraHead(const QString &) override - { - } - - QString html; -}; - class CSSHelper : public MessageViewer::CSSHelperBase { public: diff --git a/messageviewer/src/messagepartthemes/default/defaultrenderer.cpp b/messageviewer/src/messagepartthemes/default/defaultrenderer.cpp --- a/messageviewer/src/messagepartthemes/default/defaultrenderer.cpp +++ b/messageviewer/src/messagepartthemes/default/defaultrenderer.cpp @@ -34,7 +34,7 @@ #include "viewer/csshelperbase.h" #include "messagepartrenderermanager.h" -#include +#include #include #include #include @@ -308,28 +308,21 @@ return s; } -class CacheHtmlWriter : public MimeTreeParser::HtmlWriter +class CacheHtmlWriter : public MimeTreeParser::BufferedHtmlWriter { public: explicit CacheHtmlWriter(MimeTreeParser::HtmlWriter *baseWriter) : mBaseWriter(baseWriter) { + BufferedHtmlWriter::begin(); } - virtual ~CacheHtmlWriter() - { - } - + ~CacheHtmlWriter() = default; void begin() override { mBaseWriter->begin(); } - void write(const QString &str) override - { - html.append(str); - } - void end() override { mBaseWriter->end(); @@ -350,7 +343,12 @@ mBaseWriter->extraHead(extra); } - QString html; + QString html() + { + BufferedHtmlWriter::end(); + return QString::fromUtf8(data()); + } + MimeTreeParser::HtmlWriter *mBaseWriter = nullptr; }; @@ -407,7 +405,7 @@ renderSubParts(mp, htmlWriter); } - return htmlWriter->html; + return htmlWriter->html(); } QString DefaultRendererPrivate::render(const MimeMessagePart::Ptr &mp) @@ -428,7 +426,7 @@ renderSubParts(mp, htmlWriter); } - return htmlWriter->html; + return htmlWriter->html(); } QString DefaultRendererPrivate::render(const EncapsulatedRfc822MessagePart::Ptr &mp) @@ -450,7 +448,7 @@ { auto _htmlWriter = QSharedPointer(new CacheHtmlWriter(mOldWriter)); renderSubParts(mp, _htmlWriter); - c.insert(QStringLiteral("content"), _htmlWriter->html); + c.insert(QStringLiteral("content"), _htmlWriter->html()); } auto htmlWriter = QSharedPointer(new CacheHtmlWriter(mOldWriter)); @@ -460,10 +458,10 @@ aBlock = HTMLBlock::Ptr(new AttachmentMarkBlock(htmlWriter.data(), mp->attachmentContent())); } - const auto html = t->render(&c); - htmlWriter->write(html); + Grantlee::OutputStream s(htmlWriter->stream()); + t->render(&s, &c); } - return htmlWriter->html; + return htmlWriter->html(); } QString DefaultRendererPrivate::render(const HtmlMessagePart::Ptr &mp) @@ -512,10 +510,10 @@ aBlock = HTMLBlock::Ptr(new AttachmentMarkBlock(htmlWriter.data(), mp->attachmentContent())); } - const auto html = t->render(&c); - htmlWriter->write(html); + Grantlee::OutputStream s(htmlWriter->stream()); + t->render(&s, &c); } - return htmlWriter->html; + return htmlWriter->html(); } QString DefaultRendererPrivate::renderEncrypted(const EncryptedMessagePart::Ptr &mp) @@ -537,7 +535,7 @@ } renderSubParts(mp, _htmlWriter); } - c.insert(QStringLiteral("content"), _htmlWriter->html); + c.insert(QStringLiteral("content"), _htmlWriter->html()); } else if (!metaData.inProgress) { auto part = renderWithFactory(QStringLiteral("MimeTreeParser::MessagePart"), mp); if (part) { @@ -594,7 +592,7 @@ } renderSubParts(mp, _htmlWriter); } - c.insert(QStringLiteral("content"), _htmlWriter->html); + c.insert(QStringLiteral("content"), _htmlWriter->html()); } else if (!metaData.inProgress) { auto part = renderWithFactory(QStringLiteral("MimeTreeParser::MessagePart"), mp); if (part) { @@ -834,7 +832,7 @@ } htmlWriter->write(renderSigned(mp)); } - return htmlWriter->html; + return htmlWriter->html(); } { HTMLBlock::Ptr aBlock; @@ -851,7 +849,7 @@ } } } - return htmlWriter->html; + return htmlWriter->html(); } QString DefaultRendererPrivate::render(const EncryptedMessagePart::Ptr &mp) @@ -869,7 +867,7 @@ } htmlWriter->write(renderEncrypted(mp)); } - return htmlWriter->html; + return htmlWriter->html(); } { @@ -888,7 +886,7 @@ } } } - return htmlWriter->html; + return htmlWriter->html(); } QString DefaultRendererPrivate::render(const AlternativeMessagePart::Ptr &mp) @@ -917,7 +915,7 @@ htmlWriter->write(render(part)); } - return htmlWriter->html; + return htmlWriter->html(); } QString DefaultRendererPrivate::render(const CertMessagePart::Ptr &mp) @@ -954,10 +952,10 @@ aBlock = HTMLBlock::Ptr(new AttachmentMarkBlock(htmlWriter.data(), mp->attachmentContent())); } - const auto html = t->render(&c); - htmlWriter->write(html); + Grantlee::OutputStream s(htmlWriter->stream()); + t->render(&s, &c); } - return htmlWriter->html; + return htmlWriter->html(); } QSharedPointer DefaultRendererPrivate::renderWithFactory(QString className, const MessagePart::Ptr &msgPart) diff --git a/messageviewer/src/messagepartthemes/default/partrendered.h b/messageviewer/src/messagepartthemes/default/partrendered.h --- a/messageviewer/src/messagepartthemes/default/partrendered.h +++ b/messageviewer/src/messagepartthemes/default/partrendered.h @@ -37,7 +37,7 @@ class Content; } -class CacheHtmlWriter; +class CacheHtmlWriter2; class PartRendered { @@ -67,7 +67,7 @@ class WrapperPartRendered : public PartRendered { public: - WrapperPartRendered(CacheHtmlWriter *); + WrapperPartRendered(CacheHtmlWriter2 *); virtual ~WrapperPartRendered(); QString html() override; diff --git a/messageviewer/src/messagepartthemes/default/partrendered.cpp b/messageviewer/src/messagepartthemes/default/partrendered.cpp --- a/messageviewer/src/messagepartthemes/default/partrendered.cpp +++ b/messageviewer/src/messagepartthemes/default/partrendered.cpp @@ -25,7 +25,7 @@ #include "messagepartrenderermanager.h" -#include +#include #include #include @@ -37,29 +37,14 @@ using namespace MessageViewer; -class CacheHtmlWriter : public MimeTreeParser::HtmlWriter +class CacheHtmlWriter2 : public MimeTreeParser::BufferedHtmlWriter { public: - explicit CacheHtmlWriter() - { - } - - virtual ~CacheHtmlWriter() - { - } - - void begin() override - { - } - - void write(const QString &str) override - { - html.append(str); - } - - void end() override + CacheHtmlWriter2() { + begin(); } + ~CacheHtmlWriter2() = default; void embedPart(const QByteArray &contentId, const QString &url) override { @@ -71,7 +56,12 @@ head.append(extra); } - QString html; + QString html() + { + end(); + return QString::fromUtf8(data()); + } + QString head; QMap embedParts; }; @@ -94,7 +84,7 @@ { QVector > ret; foreach (const auto &_m, mp->subParts()) { - CacheHtmlWriter cacheWriter; + CacheHtmlWriter2 cacheWriter; DefaultRenderer::Ptr renderer = mp->source()->messagePartTheme(_m); cacheWriter.write(renderer->html()); ret.append(QSharedPointer(new WrapperPartRendered(&cacheWriter))); @@ -125,10 +115,10 @@ return QMap(); } -WrapperPartRendered::WrapperPartRendered(CacheHtmlWriter *htmlWriter) +WrapperPartRendered::WrapperPartRendered(CacheHtmlWriter2 *htmlWriter) : PartRendered() { - mHtml = htmlWriter->html; + mHtml = htmlWriter->html(); mHead = htmlWriter->head; mEmbeded = htmlWriter->embedParts; } diff --git a/mimetreeparser/autotests/util.h b/mimetreeparser/autotests/util.h --- a/mimetreeparser/autotests/util.h +++ b/mimetreeparser/autotests/util.h @@ -16,43 +16,6 @@ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "interfaces/htmlwriter.h" - #include -class TestHtmlWriter : public MimeTreeParser::HtmlWriter -{ -public: - explicit TestHtmlWriter() - { - } - - virtual ~TestHtmlWriter() - { - } - - void begin() override - { - } - - void write(const QString &str) override - { - html += str; - } - - void end() override - { - } - - void embedPart(const QByteArray &, const QString &) override - { - } - - void extraHead(const QString &) override - { - } - - QString html; -}; - KMime::Message::Ptr readAndParseMail(const QString &mailFile); diff --git a/mimetreeparser/src/CMakeLists.txt b/mimetreeparser/src/CMakeLists.txt --- a/mimetreeparser/src/CMakeLists.txt +++ b/mimetreeparser/src/CMakeLists.txt @@ -42,6 +42,7 @@ set(libmimetreeparser_extra_SRCS #HTML Writer + htmlwriter/bufferedhtmlwriter.cpp htmlwriter/filehtmlwriter.cpp ) @@ -86,6 +87,7 @@ ecm_generate_headers(MimeTreeParser_Camelcasehtmlwriter_HEADERS HEADER_NAMES + BufferedHtmlWriter FileHtmlWriter REQUIRED_HEADERS MimeTreeParser_htmlwriter_HEADERS PREFIX MimeTreeParser diff --git a/mimetreeparser/src/htmlwriter/bufferedhtmlwriter.h b/mimetreeparser/src/htmlwriter/bufferedhtmlwriter.h new file mode 100644 --- /dev/null +++ b/mimetreeparser/src/htmlwriter/bufferedhtmlwriter.h @@ -0,0 +1,60 @@ +/* + Copyright (c) 2017 Volker Krause + + 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 MIMETREEPARSER_BUFFEREDHTMLWRITER_H +#define MIMETREEPARSER_BUFFEREDHTMLWRITER_H + +#include "mimetreeparser_export.h" +#include + +#include +#include + +namespace MimeTreeParser { + +/** + * QBuffer-backed HtmlWriter + */ +class MIMETREEPARSER_EXPORT BufferedHtmlWriter : public HtmlWriter +{ +public: + BufferedHtmlWriter(); + ~BufferedHtmlWriter(); + + void begin() override; + void end() override; + void reset() override; + QIODevice* device() const override; + + QByteArray data() const; + void clear(); + + void extraHead(const QString& str) override; + void embedPart(const QByteArray& contentId, const QString& url) override; + +protected: + QByteArray m_data; + +private: + QBuffer m_buffer; +}; + +} + +#endif // MIMETREEPARSER_BUFFEREDHTMLWRITER_H diff --git a/mimetreeparser/src/htmlwriter/bufferedhtmlwriter.cpp b/mimetreeparser/src/htmlwriter/bufferedhtmlwriter.cpp new file mode 100644 --- /dev/null +++ b/mimetreeparser/src/htmlwriter/bufferedhtmlwriter.cpp @@ -0,0 +1,78 @@ +/* + Copyright (c) 2017 Volker Krause + + 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 "bufferedhtmlwriter.h" + +#include + +using namespace MimeTreeParser; + +BufferedHtmlWriter::BufferedHtmlWriter() + : m_buffer(&m_data) +{ +} + +BufferedHtmlWriter::~BufferedHtmlWriter() +{ + HtmlWriter::end(); +} + +void BufferedHtmlWriter::begin() +{ + m_buffer.open(QBuffer::WriteOnly); + HtmlWriter::begin(); +} + +void BufferedHtmlWriter::end() +{ + HtmlWriter::end(); + m_buffer.close(); +} + +void BufferedHtmlWriter::reset() +{ + HtmlWriter::reset(); + m_buffer.close(); + clear(); +} + +QIODevice* BufferedHtmlWriter::device() const +{ + return const_cast(&m_buffer); +} + +void BufferedHtmlWriter::extraHead(const QString& str) +{ +} + +void BufferedHtmlWriter::embedPart(const QByteArray& contentId, const QString& url) +{ + Q_UNUSED(contentId); + Q_UNUSED(url); +} + +QByteArray BufferedHtmlWriter::data() const +{ + return m_data; +} + +void BufferedHtmlWriter::clear() +{ + m_data.clear(); +} diff --git a/mimetreeparser/src/htmlwriter/filehtmlwriter.h b/mimetreeparser/src/htmlwriter/filehtmlwriter.h --- a/mimetreeparser/src/htmlwriter/filehtmlwriter.h +++ b/mimetreeparser/src/htmlwriter/filehtmlwriter.h @@ -36,30 +36,23 @@ #include "mimetreeparser/htmlwriter.h" #include -#include - -class QString; namespace MimeTreeParser { class MIMETREEPARSER_EXPORT FileHtmlWriter : public HtmlWriter { public: explicit FileHtmlWriter(const QString &filename); - virtual ~FileHtmlWriter(); + ~FileHtmlWriter(); void begin() override; void end() override; void reset() override; - void write(const QString &str) override; + QIODevice* device() const override; void embedPart(const QByteArray &contentId, const QString &url) override; void extraHead(const QString &str) override; -private: - void flush(); - void openOrWarn(); private: QFile mFile; - QTextStream mStream; }; } // namespace MimeTreeParser diff --git a/mimetreeparser/src/htmlwriter/filehtmlwriter.cpp b/mimetreeparser/src/htmlwriter/filehtmlwriter.cpp --- a/mimetreeparser/src/htmlwriter/filehtmlwriter.cpp +++ b/mimetreeparser/src/htmlwriter/filehtmlwriter.cpp @@ -30,78 +30,62 @@ */ #include "filehtmlwriter.h" - #include "mimetreeparser_debug.h" -namespace MimeTreeParser { +#include + +using namespace MimeTreeParser; + FileHtmlWriter::FileHtmlWriter(const QString &filename) - : HtmlWriter() - , mFile(filename.isEmpty() ? QStringLiteral("filehtmlwriter.out") : filename) + : mFile(filename.isEmpty() ? QStringLiteral("filehtmlwriter.out") : filename) { } FileHtmlWriter::~FileHtmlWriter() { if (mFile.isOpen()) { qCWarning(MIMETREEPARSER_LOG) << "FileHtmlWriter: file still open!"; - mStream.setDevice(nullptr); + HtmlWriter::end(); mFile.close(); } } void FileHtmlWriter::begin() { - openOrWarn(); + if (mFile.isOpen()) { + qCWarning(MIMETREEPARSER_LOG) << "FileHtmlWriter: file still open!"; + mFile.close(); + } + if (!mFile.open(QIODevice::WriteOnly)) { + qCWarning(MIMETREEPARSER_LOG) << "FileHtmlWriter: Cannot open file" << mFile.fileName(); + } + HtmlWriter::begin(); } void FileHtmlWriter::end() { - flush(); - mStream.setDevice(nullptr); + HtmlWriter::end(); mFile.close(); } void FileHtmlWriter::reset() { + HtmlWriter::reset(); if (mFile.isOpen()) { - mStream.setDevice(nullptr); mFile.close(); } } -void FileHtmlWriter::write(const QString &str) +QIODevice* FileHtmlWriter::device() const { - mStream << str; -} - -void FileHtmlWriter::flush() -{ - mStream.flush(); - mFile.flush(); -} - -void FileHtmlWriter::openOrWarn() -{ - if (mFile.isOpen()) { - qCWarning(MIMETREEPARSER_LOG) << "FileHtmlWriter: file still open!"; - mStream.setDevice(nullptr); - mFile.close(); - } - if (!mFile.open(QIODevice::WriteOnly)) { - qCWarning(MIMETREEPARSER_LOG) << "FileHtmlWriter: Cannot open file" << mFile.fileName(); - } else { - mStream.setDevice(&mFile); - mStream.setCodec("UTF-8"); - } + return const_cast(&mFile); } void FileHtmlWriter::embedPart(const QByteArray &contentId, const QString &url) { - mStream << "" << endl; - flush(); + *stream() << "" << endl; } void FileHtmlWriter::extraHead(const QString &) { } -} // diff --git a/mimetreeparser/src/interfaces/htmlwriter.h b/mimetreeparser/src/interfaces/htmlwriter.h --- a/mimetreeparser/src/interfaces/htmlwriter.h +++ b/mimetreeparser/src/interfaces/htmlwriter.h @@ -35,8 +35,13 @@ #include "mimetreeparser_export.h" +#include +#include + class QByteArray; +class QIODevice; class QString; +class QTextStream; namespace MimeTreeParser { /** @@ -47,26 +52,53 @@ class MIMETREEPARSER_EXPORT HtmlWriter { public: + HtmlWriter(); virtual ~HtmlWriter(); - /** Signal the begin of stuff to write, and give the CSS definitions */ - virtual void begin() = 0; - /** Write out a chunk of text. No HTML escaping is performed. */ - virtual void write(const QString &html) = 0; - /** Signal the end of stuff to write. */ - virtual void end() = 0; + /** Signal the begin of stuff to write. + * Sub-classes should open device() in a writable mode here and then + * call the base class. + */ + virtual void begin(); + + /** Write out a chunk of text. No HTML escaping is performed. + * @deprecated use stream() instead + */ + void write(const QString &html); + + /** Signal the end of stuff to write. + * Sub-classes should call the base class and then close device() here. + */ + virtual void end(); + /** * Stop all possibly pending processing in order to be able to * call #begin() again. + * Sub-classes should call the base class and then reset device() here. */ virtual void reset(); + /** Returns the QIODevice backing this HtmlWriter instance. + * Before writing to this directly, make sure to flush stream(). + */ + virtual QIODevice* device() const = 0; + + /** Returns a QTextStream on device(). + * Use this for writing QString data, rather than local string + * concatenations. + */ + QTextStream* stream() const; + /** * Embed a part with Content-ID @p contentId, using url @p url. */ virtual void embedPart(const QByteArray &contentId, const QString &url) = 0; virtual void extraHead(const QString &str) = 0; + +private: + Q_DISABLE_COPY(HtmlWriter) + mutable std::unique_ptr m_stream; }; } diff --git a/mimetreeparser/src/interfaces/htmlwriter.cpp b/mimetreeparser/src/interfaces/htmlwriter.cpp --- a/mimetreeparser/src/interfaces/htmlwriter.cpp +++ b/mimetreeparser/src/interfaces/htmlwriter.cpp @@ -1,39 +1,63 @@ /* - This file is part of KMail's plugin interface. - Copyright (c) 2003 Marc Mutz - - KMail is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - KMail 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 - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - - In addition, as a special exception, the copyright holders give - permission to link the code of this program with any edition of - the Qt library by Trolltech AS, Norway (or with modified versions - of Qt that use the same license as Qt), and distribute linked - combinations including the two. You must obey the GNU General - Public License in all respects for all of the code used other than - Qt. If you modify this file, you may extend this exception to - your version of the file, but you are not obligated to do so. If - you do not wish to do so, delete this exception statement from - your version. + Copyright (c) 2017 Volker Krause + + 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 "htmlwriter.h" -MimeTreeParser::HtmlWriter::~HtmlWriter() +#include + +using namespace MimeTreeParser; + +HtmlWriter::HtmlWriter() = default; +HtmlWriter::~HtmlWriter() = default; + +void HtmlWriter::begin() +{ + if (!m_stream) + m_stream.reset(new QTextStream()); + m_stream->setDevice(device()); + m_stream->setCodec("UTF-8"); +} + +void HtmlWriter::write(const QString& html) +{ + Q_ASSERT(m_stream); + if (!m_stream) + return; + *stream() << html; +} + +void HtmlWriter::end() +{ + if (!m_stream) + return; + m_stream->flush(); + m_stream->setDevice(nullptr); +} + +void HtmlWriter::reset() { + if (!m_stream) + return; + m_stream->setDevice(nullptr); } -void MimeTreeParser::HtmlWriter::reset() +QTextStream* HtmlWriter::stream() const { + return m_stream.get(); } diff --git a/mimetreeparser/src/viewer/messagepart.cpp b/mimetreeparser/src/viewer/messagepart.cpp --- a/mimetreeparser/src/viewer/messagepart.cpp +++ b/mimetreeparser/src/viewer/messagepart.cpp @@ -22,7 +22,7 @@ #include "attachmentstrategy.h" #include "cryptohelper.h" #include "objecttreeparser.h" -#include "interfaces/htmlwriter.h" +#include "htmlwriter/bufferedhtmlwriter.h" #include "job/qgpgmejobexecutor.h" #include "memento/cryptobodypartmemento.h" #include "memento/decryptverifybodypartmemento.h" @@ -205,22 +205,11 @@ } //-----LegacyMessagePart-------------------- -class LegacyHtmlWriter : public HtmlWriter -{ -public: - void begin() override {} - void end() override {} - void extraHead(const QString&) override {} - void embedPart(const QByteArray&, const QString&) override {} - void write(const QString &html) override { text += html; } - - QString text; -}; - LegacyPluginMessagePart::LegacyPluginMessagePart(ObjectTreeParser *otp) : MessagePart(otp, QString()) - , m_htmlWriter(new LegacyHtmlWriter) + , m_htmlWriter(new BufferedHtmlWriter) { + m_htmlWriter->begin(); } LegacyPluginMessagePart::~LegacyPluginMessagePart() @@ -234,7 +223,8 @@ QString LegacyPluginMessagePart::formatOutput() const { - return static_cast(m_htmlWriter.get())->text; + m_htmlWriter->end(); + return QString::fromUtf8(static_cast(m_htmlWriter.get())->data()); } //-----MessagePartList----------------------