Date: Friday, October 7, 2016 @ 06:27:53 Author: arojas Revision: 277863
Add patch Added: messagelib/trunk/CVE-2016-7967-7968.patch --------------------------+ CVE-2016-7967-7968.patch | 1265 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1265 insertions(+) Added: CVE-2016-7967-7968.patch =================================================================== --- CVE-2016-7967-7968.patch (rev 0) +++ CVE-2016-7967-7968.patch 2016-10-07 06:27:53 UTC (rev 277863) @@ -0,0 +1,1265 @@ +diff --git a/messagecomposer/src/recipient/recipientseditor.cpp b/messagecomposer/src/recipient/recipientseditor.cpp +index c0d660e..3f6fa02 100644 +--- a/messagecomposer/src/recipient/recipientseditor.cpp ++++ b/messagecomposer/src/recipient/recipientseditor.cpp +@@ -241,7 +241,7 @@ void RecipientsEditor::slotLineAdded(MultiplyingLine *line) + + if (count > 0) { + if (count == 1) { +- RecipientLineNG *last_rec = qobject_cast< RecipientLineNG * >(lines().last()); ++ RecipientLineNG *last_rec = qobject_cast< RecipientLineNG * >(lines().first()); + if (last_rec && last_rec->recipientType() == Recipient::Bcc) { + rec->setRecipientType(Recipient::To); + } else { +diff --git a/messagelist/src/core/model.cpp b/messagelist/src/core/model.cpp +index e901e69..e4146c4 100644 +--- a/messagelist/src/core/model.cpp ++++ b/messagelist/src/core/model.cpp +@@ -2636,7 +2636,7 @@ ModelPrivate::ViewItemJobResult ModelPrivate::viewItemJobStepInternalForJobPass2 + } else { + if (parentId > 0) { + // In second pass we have all available Items in mThreadingCache already. If +- // mThreadingCache.parentForItem() returns null, but sets knownParent to true then ++ // mThreadingCache.parentForItem() returns null, but returns valid parentId then + // the Item was removed from Akonadi and our threading cache is out-of-date. + mThreadingCache.expireParent(mi); + mparent = findMessageParent(mi); +@@ -3043,6 +3043,10 @@ ModelPrivate::ViewItemJobResult ModelPrivate::viewItemJobStepInternalForJobPass1 + } + } + ++ // Remove the message from threading cache before we start moving up the ++ // children, so that they don't get mislead by the cache ++ mThreadingCache.expireParent(dyingMessage); ++ + if (dyingMessage->parent()) { + // Handle saving the current selection: if this item was the current before the step + // then zero it out. We have killed it and it's OK for the current item to change. +diff --git a/messagelist/src/core/threadingcache.h b/messagelist/src/core/threadingcache.h +index 7bdb626..e8d0e35 100644 +--- a/messagelist/src/core/threadingcache.h ++++ b/messagelist/src/core/threadingcache.h +@@ -76,6 +76,7 @@ public: + { + if (mEnabled) { + mParentCache.remove(item->itemId()); ++ mItemCache.remove(item->itemId()); + } + } + +diff --git a/messageviewer/src/header/grantleeheaderformatter.cpp b/messageviewer/src/header/grantleeheaderformatter.cpp +index bebbe3b..e2316c4 100644 +--- a/messageviewer/src/header/grantleeheaderformatter.cpp ++++ b/messageviewer/src/header/grantleeheaderformatter.cpp +@@ -112,7 +112,12 @@ QString GrantleeHeaderFormatter::format(const QString &absolutePath, const Grant + headerObject.insert(QStringLiteral("subjectDir"), d->headerStyleUtil.subjectDirectionString(message)); + + headerObject.insert(QStringLiteral("subjecti18n"), i18n("Subject:")); +- headerObject.insert(QStringLiteral("subject"), d->headerStyleUtil.subjectString(message)); ++ KTextToHTML::Options flags = KTextToHTML::PreserveSpaces; ++ if (MessageViewer::MessageViewerSettings::self()->showEmoticons()) { ++ flags |= KTextToHTML::ReplaceSmileys; ++ } ++ ++ headerObject.insert(QStringLiteral("subject"), d->headerStyleUtil.subjectString(message, flags)); + + if (message->to(false)) { + headerObject.insert(QStringLiteral("toi18n"), i18n("To:")); +diff --git a/messageviewer/src/header/plainheaderstyle.cpp b/messageviewer/src/header/plainheaderstyle.cpp +index 99158c8..492aed7 100644 +--- a/messageviewer/src/header/plainheaderstyle.cpp ++++ b/messageviewer/src/header/plainheaderstyle.cpp +@@ -18,7 +18,7 @@ + */ + + #include "plainheaderstyle.h" +- ++#include "messageviewer/messageviewersettings.h" + #include "header/headerstyle_util.h" + + #include "header/headerstrategy.h" +@@ -108,9 +108,16 @@ QString PlainHeaderStyle::format(KMime::Message *message) const + headerStr = QStringLiteral("<div class=\"header\" dir=\"%1\">").arg(dir); + + //case HdrLong: +- if (strategy->showHeader(QStringLiteral("subject"))) ++ if (strategy->showHeader(QStringLiteral("subject"))) { ++ KTextToHTML::Options flags = KTextToHTML::PreserveSpaces; ++ if (MessageViewer::MessageViewerSettings::self()->showEmoticons()) { ++ flags |= KTextToHTML::ReplaceSmileys; ++ } ++ ++ + headerStr += QStringLiteral("<div dir=\"%1\"><b style=\"font-size:130%\">").arg(subjectDir) + +- d->mHeaderStyleUtil.subjectString(message) + QLatin1String("</b></div>\n"); ++ d->mHeaderStyleUtil.subjectString(message, flags) + QLatin1String("</b></div>\n"); ++ } + + if (strategy->showHeader(QStringLiteral("date"))) { + headerStr.append(i18n("Date: ") + d->mHeaderStyleUtil.strToHtml(d->mHeaderStyleUtil.dateString(message, isPrinting(), /* short = */ MessageViewer::HeaderStyleUtil::CustomDate)) + QLatin1String("<br/>\n")); +diff --git a/messageviewer/src/htmlwriter/autotests/CMakeLists.txt b/messageviewer/src/htmlwriter/autotests/CMakeLists.txt +index 826f59e..d27febb 100644 +--- a/messageviewer/src/htmlwriter/autotests/CMakeLists.txt ++++ b/messageviewer/src/htmlwriter/autotests/CMakeLists.txt +@@ -3,3 +3,13 @@ ecm_add_test(webengineembedparttest.cpp ../webengineembedpart.cpp + NAME_PREFIX "messageviewer-webengine-" + LINK_LIBRARIES Qt5::Test Qt5::Core + ) ++ ++set(webengineparthtmlwritertestdebug_SRCS) ++ecm_qt_declare_logging_category(webengineparthtmlwritertestdebug_SRCS HEADER messageviewer_debug.h IDENTIFIER MESSAGEVIEWER_LOG CATEGORY_NAME org.kde.pim.messageviewer) ++ ++ ++ecm_add_test(webengineparthtmlwritertest.cpp ../webengineembedpart.cpp ../webengineparthtmlwriter.cpp ${webengineparthtmlwritertestdebug_SRCS} ++ TEST_NAME webengineparthtmlwritertest ++ NAME_PREFIX "messageviewer-webengine-" ++ LINK_LIBRARIES Qt5::Test Qt5::Core KF5::MimeTreeParser KF5::MessageViewer Qt5::WebKitWidgets KF5::WebEngineViewer ++ ) +diff --git a/messageviewer/src/htmlwriter/autotests/webengineparthtmlwritertest.cpp b/messageviewer/src/htmlwriter/autotests/webengineparthtmlwritertest.cpp +new file mode 100644 +index 0000000..2e8b023 +--- /dev/null ++++ b/messageviewer/src/htmlwriter/autotests/webengineparthtmlwritertest.cpp +@@ -0,0 +1,74 @@ ++/* ++ Copyright (c) 2016 Montel Laurent <mon...@kde.org> ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms of the GNU General Public License, version 2, as ++ published by the Free Software Foundation. ++ ++ This program 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 ++*/ ++ ++#include "webengineparthtmlwritertest.h" ++#include "../webengineparthtmlwriter.h" ++ ++#include <QTest> ++ ++WebEnginePartHtmlWriterTest::WebEnginePartHtmlWriterTest(QObject *parent) ++ : QObject(parent) ++{ ++ ++} ++ ++WebEnginePartHtmlWriterTest::~WebEnginePartHtmlWriterTest() ++{ ++ ++} ++ ++void WebEnginePartHtmlWriterTest::removeScriptInHtml_data() ++{ ++ QTest::addColumn<QString>("input"); ++ QTest::addColumn<QString>("output"); ++ QTest::newRow("noscript") << QStringLiteral("<a>boo</a>") << QStringLiteral("<a>boo</a>"); ++ QTest::newRow("onescript") << QStringLiteral("<a>boo<script>alert(1)</script></a>") << QStringLiteral("<a>boo</a>"); ++ QTest::newRow("onescriptwithattribute") << QStringLiteral("<a>boo<script type=\"foo\">alert(1)</script></a>") << QStringLiteral("<a>boo</a>"); ++ QTest::newRow("severalscriptwithattribute") << QStringLiteral("<p>foo</p><script>a</script><a>boo<script type=\"foo\">alert(1)</script></a>") << QStringLiteral("<p>foo</p><a>boo</a>"); ++ QTest::newRow("scriptwithspace") << QStringLiteral("<a>boo<script type=\"foo\" >alert(1)</script ></a>") << QStringLiteral("<a>boo</a>"); ++ QTest::newRow("scriptwithremoveaccess") << QStringLiteral("<a>boo<script src=\"http://foo\"/></a>") << QStringLiteral("<a>boo</a>"); ++ QTest::newRow("empty") << QString() << QString(); ++ ++ //MultiLine ++ QTest::newRow("multiline") << QStringLiteral("<a>boo<script>\nalert(1)</script></a>") << QStringLiteral("<a>boo</a>"); ++ QTest::newRow("multiline-scriptwithspace") << QStringLiteral("<a>boo<script type=\"foo\" >\nalert(1)\n</script ></a>") << QStringLiteral("<a>boo</a>"); ++ QTest::newRow("multiline-severalscriptwithattribute") << QStringLiteral("<p>foo</p><script>\na\n</script><a>boo<script type=\"foo\">\nalert(1)</script></a>") << QStringLiteral("<p>foo</p><a>boo</a>"); ++ QTest::newRow("multiline-scriptwithspace") << QStringLiteral("<a>boo<script type=\"foo\" >\nalert(1)\nbla\nsl</script ></a>") << QStringLiteral("<a>boo</a>"); ++ ++ //Insensitive case ++ QTest::newRow("onescript-insensitive") << QStringLiteral("<a>boo<SCRIPT>alert(1)</script></a>") << QStringLiteral("<a>boo</a>"); ++ QTest::newRow("onescriptwithattribute-insensitive") << QStringLiteral("<a>boo<SCRIPt type=\"foo\">alert(1)</SCRIPT></a>") << QStringLiteral("<a>boo</a>"); ++ QTest::newRow("severalscriptwithattribute-insensitive") << QStringLiteral("<p>foo</p><script>a</SCRIPT><a>boo<SCRIPT type=\"foo\">alert(1)</script></a>") << QStringLiteral("<p>foo</p><a>boo</a>"); ++ QTest::newRow("scriptwithspace-insensitive") << QStringLiteral("<a>boo<SCRIPT type=\"foo\" >alert(1)</SCRIPT ></a>") << QStringLiteral("<a>boo</a>"); ++ QTest::newRow("scriptwithremoveaccess-insensitive") << QStringLiteral("<a>boo<SCRIPT src=\"http://foo\"/></a>") << QStringLiteral("<a>boo</a>"); ++ ++ ++ //MultiLine insensitive ++ QTest::newRow("multiline-insensitive") << QStringLiteral("<a>boo<sCript>\nalert(1)</Script></a>") << QStringLiteral("<a>boo</a>"); ++ QTest::newRow("multiline-scriptwithspace-insensitive") << QStringLiteral("<a>boo<SCRipT type=\"foo\" >\nalert(1)\n</script ></a>") << QStringLiteral("<a>boo</a>"); ++ QTest::newRow("multiline-severalscriptwithattribute-insensitive") << QStringLiteral("<p>foo</p><SCRIPT>\na\n</script><a>boo<script type=\"foo\">\nalert(1)</script></a>") << QStringLiteral("<p>foo</p><a>boo</a>"); ++ QTest::newRow("multiline-scriptwithspace-insensitive") << QStringLiteral("<a>boo<SCRIPT type=\"foo\" >\nalert(1)\nbla\nsl</script ></a>") << QStringLiteral("<a>boo</a>"); ++} ++ ++void WebEnginePartHtmlWriterTest::removeScriptInHtml() ++{ ++ QFETCH (QString, input); ++ QFETCH (QString, output); ++ QCOMPARE(MessageViewer::WebEnginePartHtmlWriter::removeJscripts(input), output); ++} ++ ++QTEST_MAIN(WebEnginePartHtmlWriterTest) +diff --git a/messageviewer/src/htmlwriter/autotests/webengineparthtmlwritertest.h b/messageviewer/src/htmlwriter/autotests/webengineparthtmlwritertest.h +new file mode 100644 +index 0000000..0deffc8 +--- /dev/null ++++ b/messageviewer/src/htmlwriter/autotests/webengineparthtmlwritertest.h +@@ -0,0 +1,34 @@ ++/* ++ Copyright (c) 2016 Montel Laurent <mon...@kde.org> ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms of the GNU General Public License, version 2, as ++ published by the Free Software Foundation. ++ ++ This program 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 ++*/ ++ ++#ifndef WEBENGINEPARTHTMLWRITERTEST_H ++#define WEBENGINEPARTHTMLWRITERTEST_H ++ ++#include <QObject> ++ ++class WebEnginePartHtmlWriterTest : public QObject ++{ ++ Q_OBJECT ++public: ++ explicit WebEnginePartHtmlWriterTest(QObject *parent = Q_NULLPTR); ++ ~WebEnginePartHtmlWriterTest(); ++private Q_SLOTS: ++ void removeScriptInHtml_data(); ++ void removeScriptInHtml(); ++}; ++ ++#endif // WEBENGINEPARTHTMLWRITERTEST_H +diff --git a/messageviewer/src/htmlwriter/webengineparthtmlwriter.cpp b/messageviewer/src/htmlwriter/webengineparthtmlwriter.cpp +index 21eb7cc..363b7d3 100644 +--- a/messageviewer/src/htmlwriter/webengineparthtmlwriter.cpp ++++ b/messageviewer/src/htmlwriter/webengineparthtmlwriter.cpp +@@ -24,6 +24,7 @@ + + #include <cassert> + #include <QByteArray> ++#include <QRegularExpression> + + using namespace MessageViewer; + +@@ -60,6 +61,9 @@ void WebEnginePartHtmlWriter::end() + insertExtraHead(); + mExtraHead.clear(); + } ++#if QT_VERSION < QT_VERSION_CHECK(5, 7, 0) ++ mHtml = removeJscripts(mHtml); ++#endif + mHtmlView->setHtml(mHtml, QUrl(QStringLiteral("file:///"))); + mHtmlView->show(); + mHtml.clear(); +@@ -70,6 +74,35 @@ void WebEnginePartHtmlWriter::end() + Q_EMIT finished(); + } + ++QString WebEnginePartHtmlWriter::removeJscripts(QString str) ++{ ++ //Remove regular <script>...</script> ++ const QRegularExpression regScript(QStringLiteral("<script[^>]*>.*?</script\\s*>"), QRegularExpression::CaseInsensitiveOption); ++ str.remove(regScript); ++ //Remove string as <script src=http://.../> ++ const QRegularExpression regScript2(QStringLiteral("<script[^>]*/>"), QRegularExpression::CaseInsensitiveOption); ++ str.remove(regScript2); ++ //Multiline script ++ const QRegularExpression regScriptStart(QStringLiteral("<script[^>]*>"), QRegularExpression::CaseInsensitiveOption); ++ const QRegularExpression regScriptEnd(QStringLiteral("</script\\s*>"), QRegularExpression::CaseInsensitiveOption); ++ int indexStartScriptFound = -1; ++ int indexEndScriptFound = -1; ++ int scriptIndexPos = 0; ++ QRegularExpressionMatch matchScriptStart; ++ QRegularExpressionMatch matchScriptEnd; ++ while ((indexStartScriptFound = str.indexOf(regScriptStart, scriptIndexPos, &matchScriptStart)) != -1) { ++ indexEndScriptFound = str.indexOf(regScriptEnd, indexStartScriptFound + matchScriptStart.capturedLength(), &matchScriptEnd); ++ if (indexEndScriptFound != -1) { ++ str.remove(indexStartScriptFound, (indexEndScriptFound + matchScriptEnd.capturedLength() - indexStartScriptFound)); ++ } else { ++ qCWarning(MESSAGEVIEWER_LOG) << "no end script tag"; ++ break; ++ } ++ scriptIndexPos = indexStartScriptFound; ++ } ++ return str; ++} ++ + void WebEnginePartHtmlWriter::reset() + { + if (mState != Ended) { +diff --git a/messageviewer/src/htmlwriter/webengineparthtmlwriter.h b/messageviewer/src/htmlwriter/webengineparthtmlwriter.h +index 69c68b0..55df357 100644 +--- a/messageviewer/src/htmlwriter/webengineparthtmlwriter.h ++++ b/messageviewer/src/htmlwriter/webengineparthtmlwriter.h +@@ -47,6 +47,9 @@ public: + void flush() Q_DECL_OVERRIDE; + void embedPart(const QByteArray &contentId, const QString &url) Q_DECL_OVERRIDE; + void extraHead(const QString &str) Q_DECL_OVERRIDE; ++ ++ static QString removeJscripts(QString str); ++ + Q_SIGNALS: + void finished(); + +diff --git a/messageviewer/src/messagepartthemes/default/defaultrenderer.cpp b/messageviewer/src/messagepartthemes/default/defaultrenderer.cpp +index 4c48a5d..a236ffc 100644 +--- a/messageviewer/src/messagepartthemes/default/defaultrenderer.cpp ++++ b/messageviewer/src/messagepartthemes/default/defaultrenderer.cpp +@@ -665,12 +665,12 @@ public: + return htmlWriter->html; + } + +- QString quotedHTML(const QString &s, bool decorate) ++ QString quotedHTML(const QString &s) + { + assert(cssHelper()); + + KTextToHTML::Options convertFlags = KTextToHTML::PreserveSpaces | KTextToHTML::HighlightText; +- if (decorate && source()->showEmoticons()) { ++ if (source()->showEmoticons()) { + convertFlags |= KTextToHTML::ReplaceSmileys; + } + QString htmlStr; +@@ -797,6 +797,11 @@ public: + htmlStr += deepQuoteFontTag[actQuoteLevel % 3]; + } + } ++ // Add blockquote ++ if (previousQuoteDepth < actQuoteLevel) { ++ htmlStr += cssHelper()->addStartBlockQuote(actQuoteLevel - previousQuoteDepth); ++ } ++ + } else { + // Add blockquote + if (previousQuoteDepth < actQuoteLevel) { +@@ -867,7 +872,7 @@ public: + aBlock = HTMLBlock::Ptr(new AttachmentMarkBlock(htmlWriter.data(), mp->attachmentNode())); + } + +- htmlWriter->queue(quotedHTML(mp->text(), false)); ++ htmlWriter->queue(quotedHTML(mp->text())); + } + return htmlWriter->html; + } +diff --git a/messageviewer/src/messageviewerheaderplugins/standardsheaderstyleplugin/messageviewer_standardsheaderstyleplugin.json b/messageviewer/src/messageviewerheaderplugins/standardsheaderstyleplugin/messageviewer_standardsheaderstyleplugin.json +index f25be94..b74b331 100644 +--- a/messageviewer/src/messageviewerheaderplugins/standardsheaderstyleplugin/messageviewer_standardsheaderstyleplugin.json ++++ b/messageviewer/src/messageviewerheaderplugins/standardsheaderstyleplugin/messageviewer_standardsheaderstyleplugin.json +@@ -3,14 +3,17 @@ + "Name": "Standards Header Style", + "Name[ca@valencia]": "Estil de capçalera estàndard", + "Name[ca]": "Estil de capçalera estàndard", ++ "Name[cs]": "Standardní styl hlavičky", ++ "Name[da]": "Standard header-stil", + "Name[de]": "Vorspann-Design „Standard“", + "Name[es]": "Estilo de encabezado estándar", ++ "Name[et]": "Standardne päisestiil", + "Name[fi]": "Vakio-otsaketyyli", + "Name[gl]": "Estilo de cabeceira estándar", + "Name[it]": "Stile con intestazioni standard", +- "Name[nl]": "Stijl met standaard headers", ++ "Name[nl]": "Standaarden van header-stijl", + "Name[pl]": "Standardowe nagłówki", +- "Name[pt]": "Estilo de Cabeçalho-Padrão", ++ "Name[pt]": "Estilo de Cabeçalhos Padrão", + "Name[pt_BR]": "Estilo de cabeçalho Padrão", + "Name[ru]": "Стандартный стиль заголовков", + "Name[sk]": "Štandardný štýl hlavičiek", +@@ -19,10 +22,9 @@ + "Name[sr@ijekavianlatin]": "standardni stil zaglavlja", + "Name[sr@latin]": "standardni stil zaglavlja", + "Name[sr]": "стандардни стил заглавља", +- "Name[sv]": "Vanlig rubrikstil", ++ "Name[sv]": "Normal huvudstil", + "Name[uk]": "Стандартний стиль заголовків", + "Name[x-test]": "xxStandards Header Stylexx", +- "Name[zh_CN]": "标准信头风格", + "ServiceTypes": [ + "MessageViewerHeaderStyle/Plugin" + ], +diff --git a/messageviewer/src/scamdetection/scamdetectionwebengine.cpp b/messageviewer/src/scamdetection/scamdetectionwebengine.cpp +index 244492c..cc63c6e 100644 +--- a/messageviewer/src/scamdetection/scamdetectionwebengine.cpp ++++ b/messageviewer/src/scamdetection/scamdetectionwebengine.cpp +@@ -23,6 +23,7 @@ + #include "settings/messageviewersettings.h" + #include "MessageViewer/ScamCheckShortUrl" + #include "webengineviewer/webenginescript.h" ++#include <WebEngineViewer/WebEngineManageScript> + + #include <KLocalizedString> + +@@ -84,7 +85,13 @@ ScamDetectionWebEngine::~ScamDetectionWebEngine() + void ScamDetectionWebEngine::scanPage(QWebEnginePage *page) + { + if (MessageViewer::MessageViewerSettings::self()->scamDetectionEnabled()) { ++#if QT_VERSION >= 0x050700 ++ page->runJavaScript(WebEngineViewer::WebEngineScript::findAllAnchorsAndForms(), ++ WebEngineViewer::WebEngineManageScript::scriptWordId(), ++ invoke(this, &ScamDetectionWebEngine::handleScanPage)); ++#else + page->runJavaScript(WebEngineViewer::WebEngineScript::findAllAnchorsAndForms(), invoke(this, &ScamDetectionWebEngine::handleScanPage)); ++#endif + } + } + +diff --git a/messageviewer/src/viewer/viewer.cpp b/messageviewer/src/viewer/viewer.cpp +index e5b88af..7d6f046 100644 +--- a/messageviewer/src/viewer/viewer.cpp ++++ b/messageviewer/src/viewer/viewer.cpp +@@ -31,6 +31,7 @@ + #include "settings/messageviewersettings.h" + #include "viewer/webengine/mailwebengineview.h" + #include <WebEngineViewer/WebHitTestResult> ++#include <WebEngineViewer/WebEngineManageScript> + #include "viewer/mimeparttree/mimetreemodel.h" + #include "viewer/mimeparttree/mimeparttreeview.h" + #include "widgets/zoomactionmenu.h" +@@ -82,6 +83,7 @@ void Viewer::initialize() + connect(d_ptr, &ViewerPrivate::changeDisplayMail, this, &Viewer::slotChangeDisplayMail); + connect(d_ptr, &ViewerPrivate::moveMessageToTrash, this, &Viewer::moveMessageToTrash); + connect(d_ptr, &ViewerPrivate::executeMailAction, this, &Viewer::executeMailAction); ++ connect(d_ptr, &ViewerPrivate::pageIsScrolledToBottom, this, &Viewer::pageIsScrolledToBottom); + + setMessage(KMime::Message::Ptr(), MimeTreeParser::Delayed); + } +@@ -216,10 +218,10 @@ void Viewer::slotScrollDown() + d->mViewer->scrollDown(10); + } + +-bool Viewer::atBottom() const ++void Viewer::atBottom() + { + Q_D(const Viewer); +- return d->mViewer->isScrolledToBottom(); ++ d->mViewer->isScrolledToBottom(); + } + + void Viewer::slotJumpDown() +@@ -636,8 +638,12 @@ QList<QAction *> Viewer::interceptorUrlActions(const WebEngineViewer::WebHitTest + void Viewer::runJavaScript(const QString &code) + { + Q_D(Viewer); +- d->mViewer->page()->runJavaScript(code); ++#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0) ++ d->mViewer->page()->runJavaScript(code, WebEngineViewer::WebEngineManageScript::scriptWordId()); ++#else ++ d->mViewer->page()->runJavaScript(code); ++#endif + } +- ++ + } + +diff --git a/messageviewer/src/viewer/viewer.h b/messageviewer/src/viewer/viewer.h +index 0a7a048..83d1a37 100644 +--- a/messageviewer/src/viewer/viewer.h ++++ b/messageviewer/src/viewer/viewer.h +@@ -235,7 +235,7 @@ public: + void enableMessageDisplay(); + + /** Returns true if the message view is scrolled to the bottom. */ +- bool atBottom() const; ++ void atBottom(); + + bool isFixedFont() const; + void setUseFixedFont(bool useFixedFont); +@@ -325,6 +325,7 @@ public: + void runJavaScript(const QString &code); + Q_SIGNALS: + void moveMessageToTrash(); ++ void pageIsScrolledToBottom(bool); + void executeMailAction(MessageViewer::Viewer::MailAction type); + + /** +diff --git a/messageviewer/src/viewer/viewer_p.cpp b/messageviewer/src/viewer/viewer_p.cpp +index f340acf..2d1ffde 100644 +--- a/messageviewer/src/viewer/viewer_p.cpp ++++ b/messageviewer/src/viewer/viewer_p.cpp +@@ -796,6 +796,9 @@ void ViewerPrivate::displaySplashPage(const QString &templateName, const QVarian + + void ViewerPrivate::enableMessageDisplay() + { ++ if (mMsgDisplay) { ++ return; ++ } + mMsgDisplay = true; + adjustLayout(); + } +@@ -1056,6 +1059,7 @@ void ViewerPrivate::initHtmlWidget() + connect(mScamDetectionWarning, &ScamDetectionWarningWidget::moveMessageToTrash, this, &ViewerPrivate::moveMessageToTrash); + connect(mScamDetectionWarning, &ScamDetectionWarningWidget::messageIsNotAScam, this, &ViewerPrivate::slotMessageIsNotAScam); + connect(mScamDetectionWarning, &ScamDetectionWarningWidget::addToWhiteList, this, &ViewerPrivate::slotAddToWhiteList); ++ connect(mViewer, &MailWebEngineView::pageIsScrolledToBottom, this, &ViewerPrivate::pageIsScrolledToBottom); + } + + bool ViewerPrivate::eventFilter(QObject *, QEvent *e) +@@ -1255,6 +1259,7 @@ void ViewerPrivate::resetStateForNewMessage() + mMimePartTree->clearModel(); + #endif + mViewer->clearRelativePosition(); ++ mViewer->hideAccessKeys(); + setShowSignatureDetails(false); + mFindBar->closeBar(); + mViewerPluginToolManager->closeAllTools(); +@@ -2143,8 +2148,6 @@ void ViewerPrivate::updateReaderWin() + htmlWriter()->end(); + } + +- mViewer->scrollToRelativePosition(mViewer->relativePosition()); +- mViewer->clearRelativePosition(); + mRecursionCountForDisplayMessage--; + } + +@@ -2358,6 +2361,8 @@ void ViewerPrivate::injectAttachments() + mViewer->injectAttachments(bind(&ViewerPrivate::attachmentInjectionHtml, this)); + toggleFullAddressList(); + mViewer->executeCustomRenderingScripts(); ++ mViewer->scrollToRelativePosition(mViewer->relativePosition()); ++ mViewer->clearRelativePosition(); + } + + void ViewerPrivate::slotSettingsChanged() +diff --git a/messageviewer/src/viewer/viewer_p.h b/messageviewer/src/viewer/viewer_p.h +index 52e7fc7..a2a24f0 100644 +--- a/messageviewer/src/viewer/viewer_p.h ++++ b/messageviewer/src/viewer/viewer_p.h +@@ -572,6 +572,7 @@ Q_SIGNALS: + void changeDisplayMail(Viewer::DisplayFormatMessage, bool); + void moveMessageToTrash(); + void executeMailAction(MessageViewer::Viewer::MailAction type); ++ void pageIsScrolledToBottom(bool); + private: + QString attachmentInjectionHtml(); + QString recipientsQuickListLinkHtml(const QString &); +diff --git a/messageviewer/src/viewer/webengine/mailwebenginepage.cpp b/messageviewer/src/viewer/webengine/mailwebenginepage.cpp +index 361a69e..7761805 100644 +--- a/messageviewer/src/viewer/webengine/mailwebenginepage.cpp ++++ b/messageviewer/src/viewer/webengine/mailwebenginepage.cpp +@@ -43,9 +43,21 @@ MailWebEnginePage::~MailWebEnginePage() + void MailWebEnginePage::initialize() + { + profile()->setHttpCacheType(QWebEngineProfile::MemoryHttpCache); ++#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0) ++ settings()->setAttribute(QWebEngineSettings::JavascriptEnabled, false); ++#else + settings()->setAttribute(QWebEngineSettings::JavascriptEnabled, true); ++#endif + settings()->setAttribute(QWebEngineSettings::PluginsEnabled, false); ++ settings()->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, false); ++ settings()->setAttribute(QWebEngineSettings::JavascriptCanAccessClipboard, false); ++ settings()->setAttribute(QWebEngineSettings::LocalStorageEnabled, false); ++ settings()->setAttribute(QWebEngineSettings::XSSAuditingEnabled, false); ++ settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, false); ++ settings()->setAttribute(QWebEngineSettings::LocalContentCanAccessRemoteUrls, false); ++ settings()->setAttribute(QWebEngineSettings::LocalContentCanAccessFileUrls, false); + #if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0) ++ settings()->setAttribute(QWebEngineSettings::WebGLEnabled, false); + settings()->setAttribute(QWebEngineSettings::AutoLoadIconsForPage, false); + #endif + +diff --git a/messageviewer/src/viewer/webengine/mailwebengineview.cpp b/messageviewer/src/viewer/webengine/mailwebengineview.cpp +index 7f5033d..bb632c5 100644 +--- a/messageviewer/src/viewer/webengine/mailwebengineview.cpp ++++ b/messageviewer/src/viewer/webengine/mailwebengineview.cpp +@@ -25,6 +25,7 @@ + #include "loadexternalreferencesurlinterceptor/loadexternalreferencesurlinterceptor.h" + #include "cidreferencesurlinterceptor/cidreferencesurlinterceptor.h" + #include <WebEngineViewer/NetworkAccessManagerWebEngine> ++#include <WebEngineViewer/WebEngineManageScript> + + #include "scamdetection/scamdetectionwebengine.h" + #include "scamdetection/scamcheckshorturl.h" +@@ -108,6 +109,15 @@ MailWebEngineView::~MailWebEngineView() + } + + ++void MailWebEngineView::runJavaScriptInWordId(const QString &script) ++{ ++#if QT_VERSION >= 0x050700 ++ page()->runJavaScript(script, WebEngineViewer::WebEngineManageScript::scriptWordId()); ++#else ++ page()->runJavaScript(script); ++#endif ++} ++ + void MailWebEngineView::initializeScripts() + { + initializeJQueryScript(); +@@ -130,12 +140,12 @@ void MailWebEngineView::slotWebHitFinished(const WebEngineViewer::WebHitTestResu + + void MailWebEngineView::scrollUp(int pixels) + { +- page()->runJavaScript(WebEngineViewer::WebEngineScript::scrollUp(pixels)); ++ runJavaScriptInWordId(WebEngineViewer::WebEngineScript::scrollUp(pixels)); + } + + void MailWebEngineView::scrollDown(int pixels) + { +- page()->runJavaScript(WebEngineViewer::WebEngineScript::scrollDown(pixels)); ++ runJavaScriptInWordId(WebEngineViewer::WebEngineScript::scrollDown(pixels)); + } + + void MailWebEngineView::selectAll() +@@ -233,33 +243,56 @@ void MailWebEngineView::showAccessKeys() + d->mWebViewAccessKey->showAccessKeys(); + } + +-bool MailWebEngineView::isScrolledToBottom() const ++void MailWebEngineView::hideAccessKeys() + { +- qDebug() << "bool MailWebEngineView::isScrolledToBottom() const not implemented"; +- //Convert as async +- //TODO '(window.innerHeight + window.scrollY) >= document.body.offsetHeight)' +- return false; ++ d->mWebViewAccessKey->hideAccessKeys(); ++} ++ ++void MailWebEngineView::isScrolledToBottom() ++{ ++#if QT_VERSION >= 0x050700 ++ page()->runJavaScript(WebEngineViewer::WebEngineScript::isScrolledToBottom(), ++ WebEngineViewer::WebEngineManageScript::scriptWordId(), ++ invoke(this, &MailWebEngineView::handleIsScrolledToBottom)); ++#else ++ page()->runJavaScript(WebEngineViewer::WebEngineScript::isScrolledToBottom(), invoke(this, &MailWebEngineView::handleIsScrolledToBottom)); ++#endif + } + + void MailWebEngineView::setElementByIdVisible(const QString &id, bool visible) + { +- page()->runJavaScript(WebEngineViewer::WebEngineScript::setElementByIdVisible(id, visible)); ++ runJavaScriptInWordId(WebEngineViewer::WebEngineScript::setElementByIdVisible(id, visible)); + } + + void MailWebEngineView::removeAttachmentMarking(const QString &id) + { +- page()->runJavaScript(WebEngineViewer::WebEngineScript::removeStyleToElement(QLatin1String("*#") + id)); ++ runJavaScriptInWordId(WebEngineViewer::WebEngineScript::removeStyleToElement(QLatin1String("*#") + id)); + } + + void MailWebEngineView::markAttachment(const QString &id, const QString &style) + { + //TODO verify "*#" + id +- page()->runJavaScript(WebEngineViewer::WebEngineScript::setStyleToElement(QLatin1String("*#") + id, style)); ++ runJavaScriptInWordId(WebEngineViewer::WebEngineScript::setStyleToElement(QLatin1String("*#") + id, style)); + } + + void MailWebEngineView::scrollToAnchor(const QString &anchor) + { ++#if QT_VERSION >= 0x050700 ++ page()->runJavaScript(WebEngineViewer::WebEngineScript::searchElementPosition(anchor), ++ WebEngineViewer::WebEngineManageScript::scriptWordId(), ++ invoke(this, &MailWebEngineView::handleScrollToAnchor)); ++#else + page()->runJavaScript(WebEngineViewer::WebEngineScript::searchElementPosition(anchor), invoke(this, &MailWebEngineView::handleScrollToAnchor)); ++#endif ++} ++ ++void MailWebEngineView::handleIsScrolledToBottom(const QVariant &result) ++{ ++ bool scrolledToBottomResult = false; ++ if (result.isValid()) { ++ scrolledToBottomResult = result.toBool(); ++ } ++ Q_EMIT pageIsScrolledToBottom(scrolledToBottomResult); + } + + void MailWebEngineView::handleScrollToAnchor(const QVariant &result) +@@ -268,14 +301,14 @@ void MailWebEngineView::handleScrollToAnchor(const QVariant &result) + const QList<QVariant> lst = result.toList(); + if (lst.count() == 2) { + const QPoint pos(lst.at(0).toInt(), lst.at(1).toInt()); +- page()->runJavaScript(WebEngineViewer::WebEngineScript::scrollToPosition(pos)); ++ runJavaScriptInWordId(WebEngineViewer::WebEngineScript::scrollToPosition(pos)); + } + } + } + + void MailWebEngineView::scrollPageDown(int percent) + { +- page()->runJavaScript(WebEngineViewer::WebEngineScript::scrollPercentage(percent)); ++ runJavaScriptInWordId(WebEngineViewer::WebEngineScript::scrollPercentage(percent)); + } + + void MailWebEngineView::scrollPageUp(int percent) +@@ -288,7 +321,7 @@ void MailWebEngineView::executeCustomRenderingScripts() + const QString scripts = MessageViewer::MailWebEngineScript::manageShowHideAttachments() + + MessageViewer::MailWebEngineScript::manageExpandAddresses(QStringLiteral("To")) + + MessageViewer::MailWebEngineScript::manageExpandAddresses(QStringLiteral("Cc")); +- page()->runJavaScript(scripts); ++ runJavaScriptInWordId(scripts); + } + + void MailWebEngineView::injectAttachments(const boost::function<QString()> &delayedHtml) +@@ -297,7 +330,7 @@ void MailWebEngineView::injectAttachments(const boost::function<QString()> &dela + if (html.isEmpty()) { + return; + } +- page()->runJavaScript(MessageViewer::MailWebEngineScript::injectAttachments(html, QStringLiteral("attachmentInjectionPoint"))); ++ runJavaScriptInWordId(MessageViewer::MailWebEngineScript::injectAttachments(html, QStringLiteral("attachmentInjectionPoint"))); + } + + void MailWebEngineView::toggleFullAddressList(const QString &field, const boost::function<QString()> &delayedHtml) +@@ -308,7 +341,7 @@ void MailWebEngineView::toggleFullAddressList(const QString &field, const boost: + } + + //qDebug() << "void MailWebEngineView::toggleFullAddressList(const QString &field, const boost::function<QString()> &delayedHtml, bool doShow)" << html << " fields " << field; +- page()->runJavaScript(MessageViewer::MailWebEngineScript::replaceInnerHtml(field, html)); ++ runJavaScriptInWordId(MessageViewer::MailWebEngineScript::replaceInnerHtml(field, html)); + } + + bool MailWebEngineView::hasVerticalScrollBar() const +@@ -328,7 +361,7 @@ bool MailWebEngineView::isAttachmentInjectionPoint(const QPoint &globalPos) cons + + void MailWebEngineView::scrollToRelativePosition(qreal pos) + { +- page()->runJavaScript(WebEngineViewer::WebEngineScript::scrollToRelativePosition(pos)); ++ runJavaScriptInWordId(WebEngineViewer::WebEngineScript::scrollToRelativePosition(pos)); + } + + QUrl MailWebEngineView::linkOrImageUrlAt(const QPoint &global) const +@@ -374,3 +407,4 @@ void MailWebEngineView::dropEvent(QDropEvent *e) + Q_UNUSED(e); + qDebug() << " MailWebEngineView::dropEvent"; + } ++ +diff --git a/messageviewer/src/viewer/webengine/mailwebengineview.h b/messageviewer/src/viewer/webengine/mailwebengineview.h +index 6571cf9..71dc550 100644 +--- a/messageviewer/src/viewer/webengine/mailwebengineview.h ++++ b/messageviewer/src/viewer/webengine/mailwebengineview.h +@@ -45,7 +45,8 @@ public: + + void saveMainFrameScreenshotInFile(const QString &filename); + void showAccessKeys(); +- bool isScrolledToBottom() const; ++ void hideAccessKeys(); ++ void isScrolledToBottom(); + + void setElementByIdVisible(const QString &id, bool visible); + void removeAttachmentMarking(const QString &id); +@@ -92,14 +93,17 @@ Q_SIGNALS: + /// @param url if an URL was under the cursor, this parameter contains it. Otherwise empty + /// @param point position where the click happened, in local coordinates + void popupMenu(const WebEngineViewer::WebHitTestResult &result); ++ void pageIsScrolledToBottom(bool); + + private Q_SLOTS: + void handleScrollToAnchor(const QVariant &result); ++ void handleIsScrolledToBottom(const QVariant &result); + + void slotWebHitFinished(const WebEngineViewer::WebHitTestResult &result); + void slotLoadFinished(); + private: + void initializeScripts(); ++ void runJavaScriptInWordId(const QString &script); + MailWebEngineViewPrivate *const d; + }; + } +diff --git a/messageviewer/src/viewer/webengine/tests/CMakeLists.txt b/messageviewer/src/viewer/webengine/tests/CMakeLists.txt +index e79b6b8..144fda7 100644 +--- a/messageviewer/src/viewer/webengine/tests/CMakeLists.txt ++++ b/messageviewer/src/viewer/webengine/tests/CMakeLists.txt +@@ -63,5 +63,14 @@ target_link_libraries(testjquerysupportmailwebengine + Qt5::Widgets KF5::WebEngineViewer Qt5::WebEngine Qt5::WebEngineWidgets KF5::XmlGui KF5::IconThemes KF5::MessageViewer + ) + ++##### ++ ++set(testmailmboxwebengine_test_SRCS ++ testmailmboxwebengine.cpp ++ ) ++add_executable(testmailmboxwebengine ${testmailmboxwebengine_test_SRCS}) + ++target_link_libraries(testmailmboxwebengine ++ Qt5::Widgets KF5::WebEngineViewer Qt5::WebEngine Qt5::WebEngineWidgets KF5::XmlGui KF5::IconThemes KF5::MessageViewer ++ ) + +diff --git a/messageviewer/src/viewer/webengine/tests/data/html.mbox b/messageviewer/src/viewer/webengine/tests/data/html.mbox +new file mode 100644 +index 0000000..a264681 +--- /dev/null ++++ b/messageviewer/src/viewer/webengine/tests/data/html.mbox +@@ -0,0 +1,29 @@ ++From f...@example.com Thu, 26 May 2011 01:16:54 +0100 ++From: Thomas McGuire <f...@example.com> ++Subject: HTML test ++Date: Thu, 26 May 2011 01:16:54 +0100 ++Message-ID: <1501334.pROlBb7MZF@herrwackelpudding.localhost> ++X-KMail-Transport: GMX ++X-KMail-Fcc: 28 ++X-KMail-Drafts: 7 ++X-KMail-Templates: 9 ++User-Agent: KMail/4.6 beta5 (Linux/2.6.34.7-0.7-desktop; KDE/4.6.41; x86_64; git-0269848; 2011-04-19) ++MIME-Version: 1.0 ++Content-Type: multipart/alternative; boundary="nextPart8606278.tpV19BTJKu" ++Content-Transfer-Encoding: 7Bit ++ ++ ++--nextPart8606278.tpV19BTJKu ++Content-Transfer-Encoding: 7Bit ++Content-Type: text/plain; charset="windows-1252" ++ ++Some HTML text ++--nextPart8606278.tpV19BTJKu ++Content-Transfer-Encoding: 7Bit ++Content-Type: text/html; charset="windows-1252" ++ ++<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> ++<html><head> ++<p>Some <span style=" font-weight:600;">HTML</span> text</p><a href=https://"><script>alert(1)</script><\"></body></html> ++--nextPart8606278.tpV19BTJKu-- ++ +diff --git a/messageviewer/src/viewer/webengine/tests/testmailmboxwebengine.cpp b/messageviewer/src/viewer/webengine/tests/testmailmboxwebengine.cpp +new file mode 100644 +index 0000000..028bcbf +--- /dev/null ++++ b/messageviewer/src/viewer/webengine/tests/testmailmboxwebengine.cpp +@@ -0,0 +1,70 @@ ++/* ++ Copyright (C) 2016 Laurent Montel <mon...@kde.org> ++ ++ 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 "testmailmboxwebengine.h" ++ ++#include <KMime/Content> ++#include <KActionCollection> ++#include <QApplication> ++#include <QFile> ++#include <QVBoxLayout> ++#include <QDebug> ++ ++#include <MessageViewer/MailWebEngineView> ++#include <MessageViewer/Viewer> ++ ++TestMailMBoxWebEngine::TestMailMBoxWebEngine(QWidget *parent) ++ : QWidget(parent) ++{ ++ QVBoxLayout *vbox = new QVBoxLayout; ++ setLayout(vbox); ++ MessageViewer::Viewer *viewer = new MessageViewer::Viewer(0, 0 , new KActionCollection(this)); ++ vbox->addWidget(viewer); ++ viewer->setMessage(readAndParseMail(QStringLiteral("html.mbox"))); ++ viewer->setPluginName(QStringLiteral("longheaderstyleplugin")); ++} ++ ++TestMailMBoxWebEngine::~TestMailMBoxWebEngine() ++{ ++ ++} ++ ++KMime::Message::Ptr TestMailMBoxWebEngine::readAndParseMail(const QString &mailFile) ++{ ++ QFile file(QLatin1String(MAIL_DATA_DIR) + QLatin1Char('/') + mailFile); ++ file.open(QIODevice::ReadOnly); ++ QByteArray ba = file.readAll(); ++ qDebug() << ba; ++ const QByteArray data = ba; ++ Q_ASSERT(!data.isEmpty()); ++ KMime::Message::Ptr msg(new KMime::Message); ++ msg->setContent(data); ++ msg->parse(); ++ return msg; ++} ++ ++int main(int argc, char *argv[]) ++{ ++ QApplication app(argc, argv); ++ app.setAttribute(Qt::AA_UseHighDpiPixmaps, true); ++ TestMailMBoxWebEngine *testWebEngine = new TestMailMBoxWebEngine; ++ testWebEngine->show(); ++ const int ret = app.exec(); ++ return ret; ++} +diff --git a/messageviewer/src/viewer/webengine/tests/testmailmboxwebengine.h b/messageviewer/src/viewer/webengine/tests/testmailmboxwebengine.h +new file mode 100644 +index 0000000..469268a +--- /dev/null ++++ b/messageviewer/src/viewer/webengine/tests/testmailmboxwebengine.h +@@ -0,0 +1,36 @@ ++/* ++ Copyright (C) 2016 Laurent Montel <mon...@kde.org> ++ ++ 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 TESTMAILMBOXWEBENGINE_H ++#define TESTMAILMBOXWEBENGINE_H ++ ++#include <QWidget> ++#include <KMime/Message> ++ ++class TestMailMBoxWebEngine : public QWidget ++{ ++ Q_OBJECT ++public: ++ explicit TestMailMBoxWebEngine(QWidget *parent = Q_NULLPTR); ++ ~TestMailMBoxWebEngine(); ++private: ++ KMime::Message::Ptr readAndParseMail(const QString &mailFile); ++}; ++ ++#endif // TESTMAILMBOXWEBENGINE_H +diff --git a/messageviewer/src/viewer/webengine/tests/testmailwebengine.cpp b/messageviewer/src/viewer/webengine/tests/testmailwebengine.cpp +index 6730c5e..ec50870 100644 +--- a/messageviewer/src/viewer/webengine/tests/testmailwebengine.cpp ++++ b/messageviewer/src/viewer/webengine/tests/testmailwebengine.cpp +@@ -27,6 +27,7 @@ + #include <QWebEngineSettings> + + #include <MessageViewer/MailWebEngineView> ++#include <WebEngineViewer/WebEngineManageScript> + + TestMailWebEngine::TestMailWebEngine(QWidget *parent) + : QWidget(parent) +@@ -75,12 +76,20 @@ void TestMailWebEngine::slotOpenUrl(const QUrl &url) + + void TestMailWebEngine::slotScrollDown() + { ++#if QT_VERSION >= 0x050700 ++ mTestWebEngine->page()->runJavaScript(WebEngineViewer::WebEngineScript::scrollDown(10), WebEngineViewer::WebEngineManageScript::scriptWordId()); ++#else + mTestWebEngine->page()->runJavaScript(WebEngineViewer::WebEngineScript::scrollDown(10)); ++#endif + } + + void TestMailWebEngine::slotScrollUp() + { ++#if QT_VERSION >= 0x050700 ++ mTestWebEngine->page()->runJavaScript(WebEngineViewer::WebEngineScript::scrollUp(10), WebEngineViewer::WebEngineManageScript::scriptWordId()); ++#else + mTestWebEngine->page()->runJavaScript(WebEngineViewer::WebEngineScript::scrollUp(10)); ++#endif + } + + void TestMailWebEngine::slotZoomDown() +diff --git a/mimetreeparser/src/bodyformatter/utils.cpp b/mimetreeparser/src/bodyformatter/utils.cpp +index 66f2ccd..a860b4b 100644 +--- a/mimetreeparser/src/bodyformatter/utils.cpp ++++ b/mimetreeparser/src/bodyformatter/utils.cpp +@@ -60,7 +60,7 @@ MessagePart::Ptr MimeTreeParser::toplevelTextNode(MessagePart::Ptr messageTree) + return text; + } else if (alternative) { + return alternative; +- } else { ++ } else if (m) { + auto ret = toplevelTextNode(m); + if (ret) { + return ret; +@@ -68,4 +68,4 @@ MessagePart::Ptr MimeTreeParser::toplevelTextNode(MessagePart::Ptr messageTree) + } + } + return MessagePart::Ptr(); +-} +\ No newline at end of file ++} +diff --git a/templateparser/src/customtemplates.cpp b/templateparser/src/customtemplates.cpp +index 9369b80..1db37f1 100644 +--- a/templateparser/src/customtemplates.cpp ++++ b/templateparser/src/customtemplates.cpp +@@ -125,7 +125,7 @@ CustomTemplates::~CustomTemplates() + + void CustomTemplates::slotNameChanged(const QString &text) + { +- mUi->mAdd->setEnabled(!text.isEmpty()); ++ mUi->mAdd->setEnabled(!text.trimmed().isEmpty()); + } + + QString CustomTemplates::indexToType(int index) +diff --git a/templateparser/src/templateparser.cpp b/templateparser/src/templateparser.cpp +index 99a17d5..36234a5 100644 +--- a/templateparser/src/templateparser.cpp ++++ b/templateparser/src/templateparser.cpp +@@ -129,6 +129,7 @@ void TemplateParser::setCharsets(const QStringList &charsets) + TemplateParser::~TemplateParser() + { + delete mEmptySource; ++ delete mOtp; + } + + int TemplateParser::parseQuotes(const QString &prefix, const QString &str, +diff --git a/webengineviewer/src/CMakeLists.txt b/webengineviewer/src/CMakeLists.txt +index cfc5340..c626049 100644 +--- a/webengineviewer/src/CMakeLists.txt ++++ b/webengineviewer/src/CMakeLists.txt +@@ -179,6 +179,7 @@ ecm_generate_headers(WebEngineViewer_Camelcasewebengine_misc_HEADERS + WebEngineView + WebHitTest + WebEngineScript ++ WebEngineManageScript + WebEnginePrintMessageBox + WebEngineExportHtmlPageJob + REQUIRED_HEADERS WebEngineViewer_webengine_misc_HEADERS +diff --git a/webengineviewer/src/networkmanager/networkaccessmanagerwebengine.cpp b/webengineviewer/src/networkmanager/networkaccessmanagerwebengine.cpp +index 1febb8c..37ac11e 100644 +--- a/webengineviewer/src/networkmanager/networkaccessmanagerwebengine.cpp ++++ b/webengineviewer/src/networkmanager/networkaccessmanagerwebengine.cpp +@@ -39,7 +39,7 @@ public: + }; + + NetworkAccessManagerWebEngine::NetworkAccessManagerWebEngine(QWebEngineView *webEngine, KActionCollection *ac, QObject *parent) +- : QNetworkAccessManager(parent), ++ : QObject(parent), + d(new NetworkAccessManagerWebEnginePrivate) + { + d->mManager = new WebEngineViewer::NetworkUrlInterceptorManager(webEngine, ac, this); +diff --git a/webengineviewer/src/networkmanager/networkaccessmanagerwebengine.h b/webengineviewer/src/networkmanager/networkaccessmanagerwebengine.h +index a1a2432..50df29e 100644 +--- a/webengineviewer/src/networkmanager/networkaccessmanagerwebengine.h ++++ b/webengineviewer/src/networkmanager/networkaccessmanagerwebengine.h +@@ -32,7 +32,7 @@ class WebHitTestResult; + class NetworkPluginUrlInterceptorInterface; + class NetworkAccessManagerWebEnginePrivate; + class NetworkPluginUrlInterceptorConfigureWidget; +-class WEBENGINEVIEWER_EXPORT NetworkAccessManagerWebEngine : public QNetworkAccessManager ++class WEBENGINEVIEWER_EXPORT NetworkAccessManagerWebEngine : public QObject + { + Q_OBJECT + public: +diff --git a/webengineviewer/src/tests/testjquerysupportwebengine.cpp b/webengineviewer/src/tests/testjquerysupportwebengine.cpp +index e782a60..bd14231 100644 +--- a/webengineviewer/src/tests/testjquerysupportwebengine.cpp ++++ b/webengineviewer/src/tests/testjquerysupportwebengine.cpp +@@ -27,6 +27,7 @@ + #include <QPushButton> + #include <QMessageBox> + #include <QTextEdit> ++#include <WebEngineViewer/WebEngineManageScript> + + TestJQuerySupportWebEngine::TestJQuerySupportWebEngine(QWidget *parent) + : QWidget(parent) +@@ -57,7 +58,11 @@ void TestJQuerySupportWebEngine::slotExecuteQuery() + { + const QString code = mEditor->toPlainText(); + if (!code.isEmpty()) { ++#if QT_VERSION >= 0x050700 ++ pageView->page()->runJavaScript(code, WebEngineViewer::WebEngineManageScript::scriptWordId()); ++#else + pageView->page()->runJavaScript(code); ++#endif + } + } + +diff --git a/webengineviewer/src/webengineaccesskey/autotests/webengineaccesskeyanchorfromhtmltest.cpp b/webengineviewer/src/webengineaccesskey/autotests/webengineaccesskeyanchorfromhtmltest.cpp +index 5f4673e..94d4dd9 100644 +--- a/webengineviewer/src/webengineaccesskey/autotests/webengineaccesskeyanchorfromhtmltest.cpp ++++ b/webengineviewer/src/webengineaccesskey/autotests/webengineaccesskeyanchorfromhtmltest.cpp +@@ -18,6 +18,7 @@ + */ + #include "webengineaccesskeyanchorfromhtmltest.h" + #include "../webengineaccesskeyutils.h" ++#include <WebEngineViewer/WebEngineManageScript> + #include <QTest> + #include <QHBoxLayout> + #include <QWebEngineView> +@@ -74,7 +75,13 @@ void TestWebEngineAccessKey::handleSearchAccessKey(const QVariant &var) + void TestWebEngineAccessKey::loadFinished(bool b) + { + Q_UNUSED(b); ++#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0) ++ mEngineView->page()->runJavaScript(WebEngineViewer::WebEngineAccessKeyUtils::script(), ++ WebEngineViewer::WebEngineManageScript::scriptWordId(), ++ invoke(this, &TestWebEngineAccessKey::handleSearchAccessKey)); ++#else + mEngineView->page()->runJavaScript(WebEngineViewer::WebEngineAccessKeyUtils::script(), invoke(this, &TestWebEngineAccessKey::handleSearchAccessKey)); ++#endif + } + + Q_DECLARE_METATYPE(QVector<WebEngineViewer::WebEngineAccessKeyAnchor>) +diff --git a/webengineviewer/src/webengineaccesskey/webengineaccesskey.cpp b/webengineviewer/src/webengineaccesskey/webengineaccesskey.cpp +index 3798420..888db81 100644 +--- a/webengineviewer/src/webengineaccesskey/webengineaccesskey.cpp ++++ b/webengineviewer/src/webengineaccesskey/webengineaccesskey.cpp +@@ -20,6 +20,7 @@ + #include "webengineaccesskey.h" + #include "webengineaccesskeyanchor.h" + #include "webengineaccesskeyutils.h" ++#include "webenginemanagescript.h" + + #include <KActionCollection> + #include <QKeyEvent> +@@ -385,6 +386,12 @@ void WebEngineAccessKey::handleSearchAccessKey(const QVariant &res) + void WebEngineAccessKey::showAccessKeys() + { + d->mAccessKeyActivated = WebEngineAccessKeyPrivate::Activated; ++#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0) ++ d->mWebEngine->page()->runJavaScript(WebEngineViewer::WebEngineAccessKeyUtils::script(), ++ WebEngineManageScript::scriptWordId(), ++ invoke(this, &WebEngineAccessKey::handleSearchAccessKey)); ++#else + d->mWebEngine->page()->runJavaScript(WebEngineViewer::WebEngineAccessKeyUtils::script(), invoke(this, &WebEngineAccessKey::handleSearchAccessKey)); ++#endif + } + +diff --git a/webengineviewer/src/webenginemanagescript.cpp b/webengineviewer/src/webenginemanagescript.cpp +index 0fe9abd..288cb90 100644 +--- a/webengineviewer/src/webenginemanagescript.cpp ++++ b/webengineviewer/src/webenginemanagescript.cpp +@@ -54,7 +54,7 @@ void WebEngineManageScript::addScript(QWebEngineProfile *profile, const QString + script.setName(scriptName); + script.setInjectionPoint(injectionPoint); + script.setRunsOnSubFrames(true); +- script.setWorldId(QWebEngineScript::MainWorld); ++ script.setWorldId(scriptWordId()); + } + script.setSourceCode(source); + profile->scripts()->insert(script); +diff --git a/webengineviewer/src/webenginemanagescript.h b/webengineviewer/src/webenginemanagescript.h +index ba73b4c..101762d 100644 +--- a/webengineviewer/src/webenginemanagescript.h ++++ b/webengineviewer/src/webenginemanagescript.h +@@ -22,17 +22,20 @@ + + #include <QObject> + #include <QWebEngineScript> ++#include "webengineviewer_export.h" + + class QWebEngineProfile; + namespace WebEngineViewer + { +-class WebEngineManageScript : public QObject ++class WEBENGINEVIEWER_EXPORT WebEngineManageScript : public QObject + { + Q_OBJECT + public: + explicit WebEngineManageScript(QObject *parent = Q_NULLPTR); + ~WebEngineManageScript(); + void addScript(QWebEngineProfile *profile, const QString &source, const QString &scriptName, QWebEngineScript::InjectionPoint injectionPoint); ++ ++ static qint32 scriptWordId() { return (QWebEngineScript::UserWorld + 1); } + }; + } + #endif // WEBENGINEMANAGESCRIPT_H +diff --git a/webengineviewer/src/webenginescript.cpp b/webengineviewer/src/webenginescript.cpp +index 3102094..4be2332 100644 +--- a/webengineviewer/src/webenginescript.cpp ++++ b/webengineviewer/src/webenginescript.cpp +@@ -181,3 +181,18 @@ QString WebEngineScript::scrollToRelativePosition(qreal pos) + const QString source = QString::fromLatin1("window.scrollTo(window.scrollX, %1); [window.scrollX, window.scrollY];").arg(pos); + return source; + } ++ ++QString WebEngineScript::isScrolledToBottom() ++{ ++ return QString::fromLatin1("(function() { " ++ "var isAtBottom = 0;" ++ "if (qt.jQuery(window).scrollTop() + qt.jQuery(window).height() == qt.jQuery(document).height())" ++ "{ " ++ " isAtBottom = 1;" ++ "} else {" ++ " isAtBottom = 0;" ++ "}" ++ "return Boolean(isAtBottom); " ++ "}());"); ++} ++ +diff --git a/webengineviewer/src/webenginescript.h b/webengineviewer/src/webenginescript.h +index 0bb7dbe..8798fc6 100644 +--- a/webengineviewer/src/webenginescript.h ++++ b/webengineviewer/src/webenginescript.h +@@ -40,6 +40,7 @@ WEBENGINEVIEWER_EXPORT QString scrollUp(int pixel); + WEBENGINEVIEWER_EXPORT QString scrollPercentage(int percent); + WEBENGINEVIEWER_EXPORT QString scrollToRelativePosition(qreal pos); + WEBENGINEVIEWER_EXPORT QString removeStyleToElement(const QString &element); ++WEBENGINEVIEWER_EXPORT QString isScrolledToBottom(); + } + } + #endif // WEBENGINESCRIPT_H +diff --git a/webengineviewer/src/webengineview.cpp b/webengineviewer/src/webengineview.cpp +index 6b93f55..a976046 100644 +--- a/webengineviewer/src/webengineview.cpp ++++ b/webengineviewer/src/webengineview.cpp +@@ -59,6 +59,11 @@ WebEngineView::~WebEngineView() + delete d; + } + ++WebEngineManageScript *WebEngineView::webEngineManagerScript() const ++{ ++ return d->mManagerScript; ++} ++ + void WebEngineView::initializeJQueryScript() + { + QFile file; +diff --git a/webengineviewer/src/webengineview.h b/webengineviewer/src/webengineview.h +index a8bb947..7ddcfa4 100644 +--- a/webengineviewer/src/webengineview.h ++++ b/webengineviewer/src/webengineview.h +@@ -26,6 +26,7 @@ + namespace WebEngineViewer + { + class WebEngineViewPrivate; ++class WebEngineManageScript; + class WEBENGINEVIEWER_EXPORT WebEngineView : public QWebEngineView + { + Q_OBJECT +@@ -41,6 +42,9 @@ public: + + void addScript(const QString &source, const QString &scriptName, QWebEngineScript::InjectionPoint injectionPoint); + void initializeJQueryScript(); ++ ++ WebEngineManageScript *webEngineManagerScript() const; ++ + protected: + bool eventFilter(QObject *obj, QEvent *event) Q_DECL_OVERRIDE; + QWebEngineView *createWindow(QWebEnginePage::WebWindowType type) Q_DECL_OVERRIDE; +diff --git a/webengineviewer/src/webhittest.cpp b/webengineviewer/src/webhittest.cpp +index d541379..9f95069 100644 +--- a/webengineviewer/src/webhittest.cpp ++++ b/webengineviewer/src/webhittest.cpp +@@ -20,6 +20,7 @@ + #include "webhittest.h" + #include "webhittestresult.h" + #include <QWebEnginePage> ++#include "webenginemanagescript.h" + + using namespace WebEngineViewer; + template<typename Arg, typename R, typename C> +@@ -113,7 +114,13 @@ WebHitTest::WebHitTest(QWebEnginePage *page, const QPoint &pos, QObject *parent) + + const QString &js = source.arg(pos.x()).arg(pos.y()); + d->m_pageUrl = page->url(); ++#if QT_VERSION >= 0x050700 ++ page->runJavaScript(js, ++ WebEngineViewer::WebEngineManageScript::scriptWordId(), ++ invoke(this, &WebHitTest::handleHitTest)); ++#else + page->runJavaScript(js, invoke(this, &WebHitTest::handleHitTest)); ++#endif + } + + WebHitTest::~WebHitTest()