Messagelib

mailwebengineview.cpp
1 /*
2  SPDX-FileCopyrightText: 2016-2021 Laurent Montel <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 #include "mailwebengineview.h"
7 #include "../urlhandlermanager.h"
8 #include "cidreferencesurlinterceptor/cidreferencesurlinterceptor.h"
9 #include "cidschemehandler/cidschemehandler.h"
10 #include "loadexternalreferencesurlinterceptor/loadexternalreferencesurlinterceptor.h"
11 #include "mailwebenginepage.h"
12 #include "messageviewer/messageviewersettings.h"
13 #include "webengineviewer/webengineaccesskey.h"
14 #include "webengineviewer/webenginescript.h"
15 #include <WebEngineViewer/BlockExternalResourcesUrlInterceptor>
16 #include <WebEngineViewer/InterceptorManager>
17 #include <WebEngineViewer/WebEngineManageScript>
18 
19 #include "scamdetection/scamcheckshorturl.h"
20 #include "scamdetection/scamdetectionwebengine.h"
21 #include <QContextMenuEvent>
22 #include <QWebEngineProfile>
23 #include <WebEngineViewer/WebHitTest>
24 
25 #include <QPrinter>
26 #include <QWebEngineUrlScheme>
27 
28 #include <WebEngineViewer/WebHitTestResult>
29 
30 using namespace MessageViewer;
31 template<typename Arg, typename R, typename C> struct InvokeWrapper {
32  R *receiver;
33  void (C::*memberFunction)(Arg);
34  void operator()(Arg result)
35  {
36  (receiver->*memberFunction)(result);
37  }
38 };
39 
40 template<typename Arg, typename R, typename C>
41 
42 InvokeWrapper<Arg, R, C> invoke(R *receiver, void (C::*memberFunction)(Arg))
43 {
44  InvokeWrapper<Arg, R, C> wrapper = {receiver, memberFunction};
45  return wrapper;
46 }
47 
48 class MessageViewer::MailWebEngineViewPrivate
49 {
50 public:
51  MailWebEngineViewPrivate() = default;
52 
53  QUrl mHoveredUrl;
54  QPoint mLastClickPosition;
55  ScamDetectionWebEngine *mScamDetection = nullptr;
56  WebEngineViewer::WebEngineAccessKey *mWebViewAccessKey = nullptr;
57  MessageViewer::LoadExternalReferencesUrlInterceptor *mExternalReference = nullptr;
58  MailWebEnginePage *mPageEngine = nullptr;
59  WebEngineViewer::InterceptorManager *mNetworkAccessManager = nullptr;
60  MessageViewer::ViewerPrivate *mViewer = nullptr;
61  WebEngineViewer::BlockTrackingUrlInterceptor *mBlockMailTrackingUrl = nullptr;
62  bool mCanStartDrag = false;
63 };
64 
65 MailWebEngineView::MailWebEngineView(KActionCollection *ac, QWidget *parent)
66  : WebEngineViewer::WebEngineView(parent)
67  , d(new MessageViewer::MailWebEngineViewPrivate)
68 {
69  d->mPageEngine = new MailWebEnginePage(this);
70  setPage(d->mPageEngine);
71  d->mWebViewAccessKey = new WebEngineViewer::WebEngineAccessKey(this, this);
72  d->mWebViewAccessKey->setActionCollection(ac);
73  d->mScamDetection = new ScamDetectionWebEngine(this);
74  connect(d->mScamDetection, &ScamDetectionWebEngine::messageMayBeAScam, this, &MailWebEngineView::messageMayBeAScam);
75  connect(d->mWebViewAccessKey, &WebEngineViewer::WebEngineAccessKey::openUrl, this, &MailWebEngineView::openUrl);
76  connect(this, &MailWebEngineView::loadFinished, this, &MailWebEngineView::slotLoadFinished);
77 
78  d->mPageEngine->profile()->installUrlSchemeHandler(QByteArrayLiteral("cid"), new CidSchemeHandler(this));
79 
80  d->mNetworkAccessManager = new WebEngineViewer::InterceptorManager(this, ac, this);
81  d->mExternalReference = new MessageViewer::LoadExternalReferencesUrlInterceptor(this);
82  connect(d->mExternalReference, &MessageViewer::LoadExternalReferencesUrlInterceptor::urlBlocked, this, &MailWebEngineView::urlBlocked);
83  d->mNetworkAccessManager->addInterceptor(d->mExternalReference);
84  auto cidReference = new MessageViewer::CidReferencesUrlInterceptor(this);
85  d->mNetworkAccessManager->addInterceptor(cidReference);
86  auto blockExternalUrl = new WebEngineViewer::BlockExternalResourcesUrlInterceptor(this);
87  connect(blockExternalUrl, &WebEngineViewer::BlockExternalResourcesUrlInterceptor::formSubmittedForbidden, this, &MailWebEngineView::formSubmittedForbidden);
88  d->mNetworkAccessManager->addInterceptor(blockExternalUrl);
89 
90  d->mBlockMailTrackingUrl = new WebEngineViewer::BlockTrackingUrlInterceptor(this);
91  connect(d->mBlockMailTrackingUrl, &WebEngineViewer::BlockTrackingUrlInterceptor::trackingFound, this, &MailWebEngineView::mailTrackingFound);
92  d->mNetworkAccessManager->addInterceptor(d->mBlockMailTrackingUrl);
93 
94  setFocusPolicy(Qt::WheelFocus);
95  connect(d->mPageEngine, &MailWebEnginePage::urlClicked, this, &MailWebEngineView::openUrl);
96  connect(page(), &QWebEnginePage::scrollPositionChanged, d->mWebViewAccessKey, &WebEngineViewer::WebEngineAccessKey::hideAccessKeys);
97 }
98 
99 MailWebEngineView::~MailWebEngineView() = default;
100 
101 void MailWebEngineView::readConfig()
102 {
103  d->mBlockMailTrackingUrl->setEnabledMailTrackingInterceptor(MessageViewer::MessageViewerSettings::self()->mailTrackingUrlEnabled());
104 }
105 
106 void MailWebEngineView::setLinkHovered(const QUrl &url)
107 {
108  // TODO we need to detect image url too.
109  d->mHoveredUrl = url;
110 }
111 
112 void MailWebEngineView::runJavaScriptInWordId(const QString &script)
113 {
114  page()->runJavaScript(script, WebEngineViewer::WebEngineManageScript::scriptWordId());
115 }
116 
117 void MailWebEngineView::setViewer(MessageViewer::ViewerPrivate *viewer)
118 {
119  d->mViewer = viewer;
120 }
121 
122 void MailWebEngineView::contextMenuEvent(QContextMenuEvent *e)
123 {
124  WebEngineViewer::WebHitTest *webHit = d->mPageEngine->hitTestContent(e->pos());
125  connect(webHit, &WebEngineViewer::WebHitTest::finished, this, &MailWebEngineView::slotWebHitFinished);
126 }
127 
128 void MailWebEngineView::slotWebHitFinished(const WebEngineViewer::WebHitTestResult &result)
129 {
130  Q_EMIT popupMenu(result);
131 }
132 
133 void MailWebEngineView::scrollUp(int pixels)
134 {
135  runJavaScriptInWordId(WebEngineViewer::WebEngineScript::scrollUp(pixels));
136 }
137 
138 void MailWebEngineView::scrollDown(int pixels)
139 {
140  runJavaScriptInWordId(WebEngineViewer::WebEngineScript::scrollDown(pixels));
141 }
142 
143 void MailWebEngineView::selectAll()
144 {
145  page()->triggerAction(QWebEnginePage::SelectAll);
146 }
147 
148 void MailWebEngineView::slotZoomChanged(qreal zoom)
149 {
150  setZoomFactor(zoom);
151 }
152 
153 void MailWebEngineView::scamCheck()
154 {
155  d->mScamDetection->scanPage(page());
156 }
157 
158 void MailWebEngineView::slotShowDetails()
159 {
160  d->mScamDetection->showDetails();
161 }
162 
163 void MailWebEngineView::forwardKeyReleaseEvent(QKeyEvent *e)
164 {
165  if (MessageViewer::MessageViewerSettings::self()->accessKeyEnabled()) {
166  d->mWebViewAccessKey->keyReleaseEvent(e);
167  }
168 }
169 
170 void MailWebEngineView::forwardMousePressEvent(QMouseEvent *event)
171 {
172  if (d->mViewer && !d->mHoveredUrl.isEmpty()) {
173  if (event->button() == Qt::LeftButton && (event->modifiers() & Qt::ShiftModifier)) {
174  // special processing for shift+click
175  if (URLHandlerManager::instance()->handleShiftClick(d->mHoveredUrl, d->mViewer)) {
176  event->accept();
177  return;
178  }
179  }
180  if (event->button() == Qt::LeftButton) {
181  d->mCanStartDrag = URLHandlerManager::instance()->willHandleDrag(d->mHoveredUrl, d->mViewer);
182  d->mLastClickPosition = event->pos();
183  }
184  }
185 }
186 
187 void MailWebEngineView::forwardMouseMoveEvent(QMouseEvent *event)
188 {
189  if (d->mViewer && !d->mHoveredUrl.isEmpty()) {
190  // If we are potentially handling a drag, deal with that.
191  if (d->mCanStartDrag && (event->buttons() & Qt::LeftButton)) {
192  if ((d->mLastClickPosition - event->pos()).manhattanLength() > QApplication::startDragDistance()) {
193  if (URLHandlerManager::instance()->handleDrag(d->mHoveredUrl, d->mViewer)) {
194  // If the URL handler manager started a drag, don't handle this in the future
195  d->mCanStartDrag = false;
196  }
197  }
198  event->accept();
199  }
200  }
201 }
202 
203 void MailWebEngineView::forwardMouseReleaseEvent(QMouseEvent *event)
204 {
205  Q_UNUSED(event)
206  d->mCanStartDrag = false;
207 }
208 
209 void MailWebEngineView::forwardKeyPressEvent(QKeyEvent *e)
210 {
211  if (e && hasFocus()) {
212  if (MessageViewer::MessageViewerSettings::self()->accessKeyEnabled()) {
213  d->mWebViewAccessKey->keyPressEvent(e);
214  }
215  }
216 }
217 
218 void MailWebEngineView::forwardWheelEvent(QWheelEvent *e)
219 {
220  if (MessageViewer::MessageViewerSettings::self()->accessKeyEnabled()) {
221  d->mWebViewAccessKey->wheelEvent(e);
222  }
224  const int numDegrees = e->angleDelta().y() / 8;
225  const int numSteps = numDegrees / 15;
226  Q_EMIT wheelZoomChanged(numSteps);
227  e->accept();
228  }
229 }
230 
231 void MailWebEngineView::resizeEvent(QResizeEvent *e)
232 {
233  if (MessageViewer::MessageViewerSettings::self()->accessKeyEnabled()) {
234  d->mWebViewAccessKey->resizeEvent(e);
235  }
236  QWebEngineView::resizeEvent(e);
237 }
238 
239 void MailWebEngineView::saveMainFrameScreenshotInFile(const QString &filename)
240 {
241  // TODO need to verify it
243  image.fill(Qt::transparent);
244 
245  QPainter painter(&image);
246  painter.setRenderHint(QPainter::Antialiasing, true);
247  painter.setRenderHint(QPainter::TextAntialiasing, true);
248  painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
249  render(&painter);
250  painter.end();
251  image.save(filename);
252 }
253 
254 void MailWebEngineView::showAccessKeys()
255 {
256  d->mWebViewAccessKey->showAccessKeys();
257 }
258 
259 void MailWebEngineView::hideAccessKeys()
260 {
261  d->mWebViewAccessKey->hideAccessKeys();
262 }
263 
264 void MailWebEngineView::isScrolledToBottom()
265 {
266  page()->runJavaScript(WebEngineViewer::WebEngineScript::isScrolledToBottom(),
267  WebEngineViewer::WebEngineManageScript::scriptWordId(),
268  invoke(this, &MailWebEngineView::handleIsScrolledToBottom));
269 }
270 
271 void MailWebEngineView::setElementByIdVisible(const QString &id, bool visible)
272 {
273  runJavaScriptInWordId(WebEngineViewer::WebEngineScript::setElementByIdVisible(id, visible));
274 }
275 
276 void MailWebEngineView::removeAttachmentMarking(const QString &id)
277 {
278  runJavaScriptInWordId(WebEngineViewer::WebEngineScript::removeStyleToElement(id));
279 }
280 
281 void MailWebEngineView::markAttachment(const QString &id, const QString &style)
282 {
283  runJavaScriptInWordId(WebEngineViewer::WebEngineScript::setStyleToElement(id, style));
284 }
285 
286 void MailWebEngineView::scrollToAnchor(const QString &anchor)
287 {
288  page()->runJavaScript(WebEngineViewer::WebEngineScript::searchElementPosition(anchor),
289  WebEngineViewer::WebEngineManageScript::scriptWordId(),
290  invoke(this, &MailWebEngineView::handleScrollToAnchor));
291 }
292 
293 void MailWebEngineView::handleIsScrolledToBottom(const QVariant &result)
294 {
295  bool scrolledToBottomResult = false;
296  if (result.isValid()) {
297  scrolledToBottomResult = result.toBool();
298  }
299  Q_EMIT pageIsScrolledToBottom(scrolledToBottomResult);
300 }
301 
302 void MailWebEngineView::handleScrollToAnchor(const QVariant &result)
303 {
304  if (result.isValid()) {
305  const QList<QVariant> lst = result.toList();
306  if (lst.count() == 2) {
307  const QPoint pos(lst.at(0).toInt(), lst.at(1).toInt());
308  runJavaScriptInWordId(WebEngineViewer::WebEngineScript::scrollToPosition(pos));
309  }
310  }
311 }
312 
313 void MailWebEngineView::scrollPageDown(int percent)
314 {
315  runJavaScriptInWordId(WebEngineViewer::WebEngineScript::scrollPercentage(percent));
316 }
317 
318 void MailWebEngineView::scrollPageUp(int percent)
319 {
320  scrollPageDown(-percent);
321 }
322 
323 void MailWebEngineView::scrollToRelativePosition(qreal pos)
324 {
325  runJavaScriptInWordId(WebEngineViewer::WebEngineScript::scrollToRelativePosition(pos));
326 }
327 
328 void MailWebEngineView::setAllowExternalContent(bool b)
329 {
330  if (d->mExternalReference->allowExternalContent() != b) {
331  d->mExternalReference->setAllowExternalContent(b);
332  reload();
333  }
334 }
335 
336 QList<QAction *> MailWebEngineView::interceptorUrlActions(const WebEngineViewer::WebHitTestResult &result) const
337 {
338  return d->mNetworkAccessManager->interceptorUrlActions(result);
339 }
340 
341 void MailWebEngineView::slotLoadFinished()
342 {
343  scamCheck();
344 }
345 
346 void MailWebEngineView::setPrintElementBackground(bool printElementBackground)
347 {
348  d->mPageEngine->setPrintElementBackground(printElementBackground);
349 }
350 
351 bool MailWebEngineView::execPrintPreviewPage(QPrinter *printer, int timeout)
352 {
353  return d->mPageEngine->execPrintPreviewPage(printer, timeout);
354 }
355 
356 void MailWebEngineView::initializeCustomScheme()
357 {
358  QWebEngineUrlScheme cidScheme("cid");
359  cidScheme.setFlags(QWebEngineUrlScheme::SecureScheme | QWebEngineUrlScheme::ContentSecurityPolicyIgnored);
360  cidScheme.setSyntax(QWebEngineUrlScheme::Syntax::Path);
361  QWebEngineUrlScheme::registerScheme(cidScheme);
362 }
ShiftModifier
WheelFocus
The InterceptorManager class.
Format_ARGB32_Premultiplied
The MailWebEnginePage class.
QList< QVariant > toList() const const
The WebHitTest class.
Definition: webhittest.h:22
const T & at(int i) const const
LeftButton
Qt::MouseButtons buttons() const const
The BlockMailTrackingUrlInterceptor class.
Qt::KeyboardModifiers keyboardModifiers()
int y() const const
The WebHitTestResult class.
const QList< QKeySequence > & reload()
int count(const T &value) const const
The WebEngineAccessKey class.
Qt::MouseButton button() const const
The ScamDetectionWebEngine class.
void accept()
QPoint angleDelta() const const
const QPoint & pos() const const
The MailWebEngineView class.
bool toBool() const const
bool isValid() const const
QPoint pos() const const
transparent
int startDragDistance()
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sat Dec 4 2021 23:12:53 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.