1 /*
2   This file is part of KMail, the KDE mail client.
3   SPDX-FileCopyrightText: 1997 Markus Wuebben <markus.wuebben@kde.org>
4   SPDX-FileCopyrightText: 2009 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net
5   SPDX-FileCopyrightText: 2009 Andras Mantia <andras@kdab.net>
6 
7   SPDX-License-Identifier: GPL-2.0-or-later
8 */
9 
10 #pragma once
11 
12 #include "config-messageviewer.h"
13 #include "messageviewer/viewerplugininterface.h"
14 #include "messageviewer_export.h"
15 #include <MimeTreeParser/Enums>
16 
17 #include <KMime/Message>
18 
19 #include <QWidget>
20 #include <memory>
21 
22 namespace Akonadi
23 {
24 class Item;
25 class ItemFetchJob;
26 }
27 
28 namespace KIdentityManagement
29 {
30 class IdentityManager;
31 }
32 
33 class KActionCollection;
34 class QAction;
35 class KToggleAction;
36 class KActionMenu;
37 
38 class QAbstractItemModel;
39 class QCloseEvent;
40 class QEvent;
41 class QResizeEvent;
42 
43 namespace WebEngineViewer
44 {
45 class WebHitTestResult;
46 }
47 
48 namespace MessageViewer
49 {
50 class WebHitTestResult;
51 class DKIMWidgetInfo;
52 class DKIMViewerMenu;
53 class AttachmentStrategy;
54 class HeaderStylePlugin;
55 class CSSHelper;
56 class ViewerPrivate;
57 class Viewer;
58 class RemoteContentMenu;
59 
60 /**
61  * An interface to plug in a handler that is called when
62  * an message item has been loaded into the view.
63  */
64 class MESSAGEVIEWER_EXPORT AbstractMessageLoadedHandler
65 {
66 public:
67     AbstractMessageLoadedHandler();
68     virtual ~AbstractMessageLoadedHandler();
69 
70     /**
71      * This method is called whenever a message item has been loaded
72      * into the view.
73      *
74      * @param item The message item that has been loaded.
75      */
76     virtual void setItem(const Akonadi::Item &item) = 0;
77 
78 protected:
79     Akonadi::Session *session() const;
80 
81 private:
82     void setSession(Akonadi::Session *session);
83 
84     friend class Viewer;
85     class AbstractMessageLoadedHandlerPrivate;
86     std::unique_ptr<AbstractMessageLoadedHandlerPrivate> const d;
87 };
88 
89 /**
90  * This is the main widget for the viewer.
91  * See the documentation of ViewerPrivate for implementation details.
92  * See Mainpage.dox for an overview of the classes in the messageviewer library.
93  */
94 class MESSAGEVIEWER_EXPORT Viewer : public QWidget
95 {
96     Q_OBJECT
97 
98     Q_DECLARE_PRIVATE(Viewer)
99 
100 public:
101     /**
102      * Create a mail viewer widget
103      * @param parent parent widget
104      * @param widget the application's main widget
105      * @param actionCollection the action collection where the widget's actions will belong to
106      */
107     explicit Viewer(QWidget *parent, QWidget *widget = nullptr, KActionCollection *actionCollection = nullptr);
108     ~Viewer() override;
109 
110     /**
111      * Returns the current message displayed in the viewer.
112      */
113     Q_REQUIRED_RESULT KMime::Message::Ptr message() const;
114 
115     /**
116      * Returns the current message item displayed in the viewer.
117      */
118     Q_REQUIRED_RESULT Akonadi::Item messageItem() const;
119 
120     enum DisplayFormatMessage { UseGlobalSetting = 0, Text = 1, Html = 2, Unknown = 3, ICal = 4 };
121 
122     enum AttachmentAction { Open = 1, OpenWith, View, Save, Properties, Delete, Copy, ScrollTo, ReplyMessageToAuthor, ReplyMessageToAll };
123 
124     enum ResourceOnlineMode { AllResources = 0, SelectedResource = 1 };
125 
126     /**
127      * Set the message that shall be shown.
128      * @param message - the message to be shown. If 0, an empty page is displayed.
129      * @param updateMode - update the display immediately or not. See UpdateMode.
130      */
131     void setMessage(const KMime::Message::Ptr &message, MimeTreeParser::UpdateMode updateMode = MimeTreeParser::Delayed);
132 
133     /**
134      * Set the Akonadi item that will be displayed.
135      * @param item - the Akonadi item to be displayed. If it doesn't hold a mail (KMime::Message::Ptr as payload data),
136      *               an empty page is shown.
137      * @param updateMode - update the display immediately or not. See UpdateMode.
138      */
139     void setMessageItem(const Akonadi::Item &item, MimeTreeParser::UpdateMode updateMode = MimeTreeParser::Delayed);
140 
141     /**
142      * The path to the message in terms of Akonadi collection hierarchy.
143      */
144     Q_REQUIRED_RESULT QString messagePath() const;
145 
146     /**
147      * Set the path to the message in terms of Akonadi collection hierarchy.
148      */
149     void setMessagePath(const QString &path);
150 
151     /**
152      * Instead of settings a message to be shown sets a message part
153      * to be shown
154      */
155     void setMessagePart(KMime::Content *aMsgPart);
156 
157     /**
158      * Convenience method to clear the reader and discard the current message. Sets the internal message pointer
159      * returned by message() to 0.
160      * @param updateMode - update the display immediately or not. See UpdateMode.
161      */
162     void clear(MimeTreeParser::UpdateMode updateMode = MimeTreeParser::Delayed);
163 
164     void update(MimeTreeParser::UpdateMode updateMode = MimeTreeParser::Delayed);
165 
166     /**
167      * Sets a message as the current one and print it immediately.
168      * @param msg the message to display and print
169      */
170     void printMessage(const Akonadi::Item &msg);
171 
172     void printPreviewMessage(const Akonadi::Item &message);
173 
174     /** Print the currently displayed message */
175     void print();
176     void printPreview();
177 
178     /** Get the html override setting */
179     Q_REQUIRED_RESULT Viewer::DisplayFormatMessage displayFormatMessageOverwrite() const;
180 
181     /** Override default html mail setting */
182     void setDisplayFormatMessageOverwrite(Viewer::DisplayFormatMessage format);
183 
184     /** Get the load external references override setting */
185     bool htmlLoadExtOverride() const;
186 
187     /** Default behavior for loading external references.
188      *  Use this for specifying the external reference loading behavior as
189      *  specified in the user settings.
190      *  @see setHtmlLoadExtOverride
191      */
192     void setHtmlLoadExtDefault(bool loadExtDefault);
193 
194     /** Override default load external references setting
195      *  @warning This must only be called when the user has explicitly
196      *  been asked to retrieve external references!
197      *  @see setHtmlLoadExtDefault
198      */
199     void setHtmlLoadExtOverride(bool loadExtOverride);
200 
201     /** Is html mail to be supported? Takes into account override */
202     Q_REQUIRED_RESULT bool htmlMail() const;
203 
204     /** Is loading ext. references to be supported? Takes into account override */
205     Q_REQUIRED_RESULT bool htmlLoadExternal() const;
206 
207     /**
208      * Display a generic HTML splash page instead of a message.
209      * @param templateName - the template to be loaded
210      * @param data - data for the template
211      * @param domain the domain.
212      */
213     void displaySplashPage(const QString &templateName, const QVariantHash &data, const QByteArray &domain = QByteArray());
214 
215     /** Enable the displaying of messages again after an splash (or other) page was displayed */
216     void enableMessageDisplay();
217 
218     /** Returns true if the message view is scrolled to the bottom. */
219     void atBottom();
220 
221     Q_REQUIRED_RESULT bool isFixedFont() const;
222     void setUseFixedFont(bool useFixedFont);
223 
224     Q_REQUIRED_RESULT QWidget *mainWindow();
225 
226     /** Enforce message decryption. */
227     void setDecryptMessageOverwrite(bool overwrite = true);
228 
229     /**
230      * Initiates a delete, by sending a signal to delete the message item */
231     void deleteMessage();
232 
233     Q_REQUIRED_RESULT const AttachmentStrategy *attachmentStrategy() const;
234     void setAttachmentStrategy(const AttachmentStrategy *strategy);
235 
236     Q_REQUIRED_RESULT QString overrideEncoding() const;
237     void setOverrideEncoding(const QString &encoding);
238     Q_REQUIRED_RESULT CSSHelper *cssHelper() const;
239     void setPrinting(bool enable);
240 
241     void selectAll();
242     void copySelectionToClipboard();
243 
244     void setZoomFactor(qreal zoomFactor);
245 
246     Q_REQUIRED_RESULT KToggleAction *toggleFixFontAction() const;
247 
248     Q_REQUIRED_RESULT KToggleAction *toggleMimePartTreeAction() const;
249 
250     Q_REQUIRED_RESULT QAction *selectAllAction() const;
251     Q_REQUIRED_RESULT QAction *copyURLAction() const;
252     Q_REQUIRED_RESULT QAction *copyAction() const;
253     Q_REQUIRED_RESULT QAction *urlOpenAction() const;
254     Q_REQUIRED_RESULT QAction *speakTextAction() const;
255     Q_REQUIRED_RESULT QAction *copyImageLocation() const;
256     Q_REQUIRED_RESULT QAction *viewSourceAction() const;
257     Q_REQUIRED_RESULT QAction *findInMessageAction() const;
258     Q_REQUIRED_RESULT QAction *saveAsAction() const;
259     Q_REQUIRED_RESULT QAction *saveMessageDisplayFormatAction() const;
260     Q_REQUIRED_RESULT QAction *resetMessageDisplayFormatAction() const;
261     Q_REQUIRED_RESULT QAction *shareTextAction() const;
262 
263     Q_REQUIRED_RESULT QAction *developmentToolsAction() const;
264     Q_REQUIRED_RESULT KToggleAction *disableEmoticonAction() const;
265     Q_REQUIRED_RESULT KActionMenu *shareServiceUrlMenu() const;
266     Q_REQUIRED_RESULT HeaderStylePlugin *headerStylePlugin() const;
267     Q_REQUIRED_RESULT MessageViewer::DKIMViewerMenu *dkimViewerMenu();
268 
269     Q_REQUIRED_RESULT MessageViewer::RemoteContentMenu *remoteContentMenu() const;
270 
271     void setPluginName(const QString &pluginName);
272 
273     void writeConfig(bool withSync = true);
274 
275     Q_REQUIRED_RESULT QUrl urlClicked() const;
276     Q_REQUIRED_RESULT QUrl imageUrlClicked() const;
277 
278     void readConfig();
279 
280     /** A QAIM tree model of the message structure. */
281     QAbstractItemModel *messageTreeModel() const;
282 
283     /**
284      * Create an item fetch job that is suitable for using to fetch the message item that will
285      * be displayed on this viewer.
286      * It will set the correct fetch scope.
287      * You still need to connect to the job's result signal.
288      */
289     Akonadi::ItemFetchJob *createFetchJob(const Akonadi::Item &item);
290 
291     /**
292      * Adds a @p handler for actions that will be executed when the message
293      * has been loaded into the view.
294      */
295     void addMessageLoadedHandler(AbstractMessageLoadedHandler *handler);
296 
297     /**
298      * Removes the @p handler for actions that will be executed when the message
299      * has been loaded into the view.
300      */
301     void removeMessageLoadedHandler(AbstractMessageLoadedHandler *handler);
302 
303     Q_REQUIRED_RESULT QString selectedText() const;
304 
305     void saveMainFrameScreenshotInFile(const QString &filename);
306     bool mimePartTreeIsEmpty() const;
307 
308     void showOpenAttachmentFolderWidget(const QList<QUrl> &urls);
309     Q_REQUIRED_RESULT QList<QAction *> viewerPluginActionList(MessageViewer::ViewerPluginInterface::SpecificFeatureTypes features);
310     Q_REQUIRED_RESULT QList<QAction *> interceptorUrlActions(const WebEngineViewer::WebHitTestResult &result) const;
311 
312     void runJavaScript(const QString &code);
313     void setPrintElementBackground(bool printElementBackground);
314 
315     Q_REQUIRED_RESULT bool printingMode() const;
316 
317     Q_REQUIRED_RESULT bool showSignatureDetails() const;
318     void setShowSignatureDetails(bool showDetails);
319 
320     Q_REQUIRED_RESULT qreal webViewZoomFactor() const;
321     void setWebViewZoomFactor(qreal factor);
322 
323     Q_REQUIRED_RESULT bool showEncryptionDetails() const;
324     void setShowEncryptionDetails(bool showDetails);
325 
326     void hasMultiMessages(bool messages);
327     void updateShowMultiMessagesButton(bool enablePreviousButton, bool enableNextButton);
328     Q_REQUIRED_RESULT MessageViewer::DKIMWidgetInfo *dkimWidgetInfo();
329 
330     void exportToPdf(const QString &fileName);
331 
332     void showDevelopmentTools();
333 
334     void setIdentityManager(KIdentityManagement::IdentityManager *ident);
335     void setFolderIdentity(uint folderIdentity);
336 Q_SIGNALS:
337     void moveMessageToTrash();
338     void pageIsScrolledToBottom(bool);
339 
340     /**
341      * Emitted when a status bar message is shown. Note that the status bar message is also set to
342      * KPIM::BroadcastStatus in addition.
343      */
344     void showStatusBarMessage(const QString &message);
345 
346     /** The user presses the right mouse button. 'url' may be 0. */
347     void popupMenu(const Akonadi::Item &msg, const QUrl &url, const QUrl &imageUrl, const QPoint &mousePos);
348     void displayPopupMenu(const Akonadi::Item &msg, const WebEngineViewer::WebHitTestResult &result, const QPoint &mousePos);
349     /**
350      * The message viewer handles some types of urls itself, most notably http(s)
351      * and ftp(s). When it can't handle the url it will Q_EMIT this signal.
352      */
353     void urlClicked(const Akonadi::Item &, const QUrl &);
354 
355     void requestConfigSync();
356 
357     /// Emitted when the content should be shown in a separate window
358     void showReader(KMime::Content *aMsgPart, bool aHTML, const QString &encoding);
359 
360     /// Emitted when the message should be shown in a separate window
361     void showMessage(const KMime::Message::Ptr &message, const QString &encoding);
362 
363     void replyMessageTo(const KMime::Message::Ptr &message, bool replyToAll);
364 
365     void deleteMessage(const Akonadi::Item &);
366 
367     /// Emitted when the item, previously set with setMessageItem, has been removed.
368     void itemRemoved();
369 
370     void makeResourceOnline(MessageViewer::Viewer::ResourceOnlineMode mode);
371 
372     void printingFinished();
373     void zoomChanged(qreal zoomFactor);
374     void showNextMessage();
375     void showPreviousMessage();
376 
377 private:
378     void initialize();
379 
380 public Q_SLOTS:
381 
382     /**
383      * HTML Widget scrollbar and layout handling.
384      *
385      * Scrolling always happens in the direction of the slot that is called. I.e.
386      * the methods take the absolute value of
387      */
388     void slotScrollUp();
389     void slotScrollDown();
390     void slotScrollPrior();
391     void slotScrollNext();
392     void slotJumpDown();
393     void slotFind();
394     void slotSaveMessage();
395     void slotAttachmentSaveAs();
396     void slotAttachmentSaveAll();
397     void slotShowMessageSource();
398     void slotZoomIn();
399     void slotZoomOut();
400     void slotZoomReset();
401     void slotChangeDisplayMail(Viewer::DisplayFormatMessage, bool);
402 
403 protected:
404     /** Some necessary event handling. */
405     void closeEvent(QCloseEvent *) override;
406     void resizeEvent(QResizeEvent *) override;
407     /** Watch for palette changes */
408     Q_REQUIRED_RESULT bool event(QEvent *e) override;
409     void changeEvent(QEvent *event) override;
410 
411     ViewerPrivate *const d_ptr;
412 };
413 }
414 
415