1 //
2 
3 #pragma once
4 
5 #include <MailCommon/MailInterfaces>
6 
7 #include <QDBusObjectPath>
8 #include <QList>
9 #include <QObject>
10 #include <QPointer>
11 
12 #include <QUrl>
13 
14 #include "kmail_export.h"
15 #include "settings/kmailsettings.h"
16 #include <Akonadi/ServerManager>
17 #include <Libkdepim/ProgressManager>
18 #include <MessageViewer/Viewer>
19 
20 #include <memory>
21 
22 #define kmkernel KMKernel::self()
23 #define kmconfig KMKernel::config()
24 
25 class QAbstractItemModel;
26 namespace Akonadi
27 {
28 class Collection;
29 class ChangeRecorder;
30 class EntityTreeModel;
31 class EntityMimeTypeFilterModel;
32 }
33 
34 namespace Akonadi
35 {
36 namespace Search
37 {
38 namespace PIM
39 {
40 class IndexedItems;
41 }
42 }
43 }
44 
45 namespace KIO
46 {
47 class Job;
48 }
49 
50 namespace MessageComposer
51 {
52 class MessageSender;
53 }
54 namespace PimCommon
55 {
56 class AutoCorrection;
57 }
58 
59 /** The KMail namespace contains classes used for KMail.
60  * This is to keep them out of the way from all the other
61  * un-namespaced classes in libs and the rest of PIM.
62  */
63 namespace KMail
64 {
65 class MailServiceImpl;
66 class UndoStack;
67 class UnityServiceManager;
68 }
69 namespace MessageComposer
70 {
71 class AkonadiSender;
72 }
73 
74 namespace KIdentityManagement
75 {
76 class Identity;
77 class IdentityManager;
78 }
79 
80 namespace MailCommon
81 {
82 class Kernel;
83 class FolderSettings;
84 class FolderCollectionMonitor;
85 class JobScheduler;
86 class KMFilterDialog;
87 class MailCommonSettings;
88 }
89 
90 #ifdef WITH_KUSERFEEDBACK
91 class KMailUserFeedbackProvider;
92 namespace KUserFeedback
93 {
94 class Provider;
95 }
96 #endif
97 
98 namespace Kleo
99 {
100 class KeyCache;
101 }
102 
103 class QTimer;
104 class KMainWindow;
105 class KMMainWidget;
106 class ConfigureDialog;
107 class FolderArchiveManager;
108 class CheckIndexingManager;
109 
110 /**
111  * @short Central point of coordination in KMail
112  *
113  * The KMKernel class represents the core of KMail, where the different parts
114  * come together and are coordinated. It is currently also the class which exports
115  * KMail's main D-BUS interfaces.
116  *
117  * The kernel is responsible for creating various
118  * (singleton) objects such as the identity manager and the message sender.
119  *
120  * The kernel also creates an Akonadi Session, Monitor and EntityTreeModel. These
121  * are shared so that other objects in KMail have access to it. Having only one EntityTreeModel
122  * instead of many reduces the overall communication with the Akonadi server.
123  *
124  * The kernel also manages some stuff that should be factored out:
125  * - default collection handling, like inboxCollectionFolder()
126  * - job handling, like jobScheduler()
127  * - handling of some config settings, like wrapCol()
128  * - various other stuff
129  */
130 class KMAIL_EXPORT KMKernel : public QObject, public MailCommon::IKernel, public MailCommon::ISettings, public MailCommon::IFilter
131 {
132     Q_OBJECT
133     Q_CLASSINFO("D-Bus Interface", "org.kde.kmail.kmail")
134 
135 public:
136     explicit KMKernel(QObject *parent = nullptr);
137     ~KMKernel() override;
138 
139     /**
140      * Start of D-Bus callable stuff. The D-Bus methods need to be public slots,
141      * otherwise they can't be accessed.
142      */
143 public Q_SLOTS:
144 
145     Q_SCRIPTABLE void checkMail();
146     Q_SCRIPTABLE void openReader();
147 
148     /**
149      * Pauses all background jobs and does not
150      * allow new background jobs to be started.
151      */
152     Q_SCRIPTABLE void pauseBackgroundJobs();
153 
154     /**
155      * Resumes all background jobs and allows
156      * new jobs to be started.
157      */
158     Q_SCRIPTABLE void resumeBackgroundJobs();
159 
160     /**
161      * Stops all network related jobs and enter offline mode
162      * New network jobs cannot be started.
163      */
164     Q_SCRIPTABLE void stopNetworkJobs();
165 
166     /**
167      * Resumes all network related jobs and enter online mode
168      * New network jobs can be started.
169      */
170     Q_SCRIPTABLE void resumeNetworkJobs();
171 
172     Q_SCRIPTABLE QStringList accounts() const;
173 
174     Q_SCRIPTABLE void makeResourceOnline(MessageViewer::Viewer::ResourceOnlineMode mode);
175 
176     /**
177      * Checks the account with the specified name for new mail.
178      * If the account name is empty, all accounts not excluded from manual
179      * mail check will be checked.
180      */
181     Q_SCRIPTABLE void checkAccount(const QString &account);
182 
183     Q_SCRIPTABLE bool selectFolder(const QString &folder);
184 
185     Q_SCRIPTABLE bool canQueryClose();
186 
187     Q_SCRIPTABLE bool handleCommandLine(bool noArgsOpensReader, const QStringList &args, const QString &workingDir);
188 
189     /**
190      * Opens a composer window and prefills it with different
191      * message parts.
192      *
193      *
194      * @param to A comma separated list of To addresses.
195      * @param cc A comma separated list of CC addresses.
196      * @param bcc A comma separated list of BCC addresses.
197      * @param subject The message subject.
198      * @param body The message body.
199      * @param hidden Whether the composer window shall initially be hidden.
200      * @param messageFile A message file that will be used as message body.
201      * @param attachmentPaths A list of files that will be attached to the message.
202      * @param customHeaders A list of custom headers.
203      * @param replyTo A list of reply-to headers.
204      * @param inReplyTo A list of in-reply-to headers.
205      * @param identity The mail identity.
206      */
207     Q_SCRIPTABLE void openComposer(const QString &to,
208                                    const QString &cc,
209                                    const QString &bcc,
210                                    const QString &subject,
211                                    const QString &body,
212                                    bool hidden,
213                                    const QString &messageFile,
214                                    const QStringList &attachmentPaths,
215                                    const QStringList &customHeaders,
216                                    const QString &replyTo = QString(),
217                                    const QString &inReplyTo = QString(),
218                                    const QString &identity = QString());
219 
220     /**
221      * Opens a composer window and prefills it with different
222      * message parts.
223      *
224      * @param to A comma separated list of To addresses.
225      * @param cc A comma separated list of CC addresses.
226      * @param bcc A comma separated list of BCC addresses.
227      * @param subject The message subject.
228      * @param body The message body.
229      * @param hidden Whether the composer window shall initially be hidden.
230      * @param attachName The name of the attachment.
231      * @param attachCte The content transfer encoding of the attachment.
232      * @param attachData The raw data of the attachment.
233      * @param attachType The mime type of the attachment.
234      * @param attachSubType The sub mime type of the attachment.
235      * @param attachParamAttr The parameter attribute of the attachment.
236      * @param attachParamValue The parameter value of the attachment.
237      * @param attachContDisp The content display type of the attachment.
238      * @param attachCharset The charset of the attachment.
239      * @param identity The identity identifier which will be used as sender identity.
240      */
241     Q_SCRIPTABLE void openComposer(const QString &to,
242                                    const QString &cc,
243                                    const QString &bcc,
244                                    const QString &subject,
245                                    const QString &body,
246                                    bool hidden,
247                                    const QString &attachName,
248                                    const QByteArray &attachCte,
249                                    const QByteArray &attachData,
250                                    const QByteArray &attachType,
251                                    const QByteArray &attachSubType,
252                                    const QByteArray &attachParamAttr,
253                                    const QString &attachParamValue,
254                                    const QByteArray &attachContDisp,
255                                    const QByteArray &attachCharset,
256                                    unsigned int identity);
257 
258     /**
259      * Opens a composer window and prefills it with different
260      * message parts.
261      * @since 5.0
262      *
263      * @param to A comma separated list of To addresses.
264      * @param cc A comma separated list of CC addresses.
265      * @param bcc A comma separated list of BCC addresses.
266      * @param subject The message subject.
267      * @param body The message body.
268      * @param attachName The name of the attachment.
269      * @param attachCte The content transfer encoding of the attachment.
270      * @param attachData The raw data of the attachment.
271      * @param attachType The mime type of the attachment.
272      * @param attachSubType The sub mime type of the attachment.
273      * @param attachParamAttr The parameter attribute of the attachment.
274      * @param attachParamValue The parameter value of the attachment.
275      * @param attachContDisp The content display type of the attachment.
276      * @param attachCharset The charset of the attachment.
277      * @param identity The identity identifier which will be used as sender identity.
278      */
279     Q_SCRIPTABLE void openComposer(const QString &to,
280                                    const QString &cc,
281                                    const QString &bcc,
282                                    const QString &subject,
283                                    const QString &body,
284                                    const QString &attachName,
285                                    const QByteArray &attachCte,
286                                    const QByteArray &attachData,
287                                    const QByteArray &attachType,
288                                    const QByteArray &attachSubType,
289                                    const QByteArray &attachParamAttr,
290                                    const QString &attachParamValue,
291                                    const QByteArray &attachContDisp,
292                                    const QByteArray &attachCharset,
293                                    unsigned int identity);
294 
295     /**
296      * Opens a composer window and prefills it with different
297      * message parts.
298      *
299      *
300      * @param to A comma separated list of To addresses.
301      * @param cc A comma separated list of CC addresses.
302      * @param bcc A comma separated list of BCC addresses.
303      * @param subject The message subject.
304      * @param body The message body.
305      * @param hidden Whether the composer window shall initially be hidden.
306      */
307     Q_SCRIPTABLE void openComposer(const QString &to, const QString &cc, const QString &bcc, const QString &subject, const QString &body, bool hidden);
308 
309     /**
310      * Opens a composer window and prefills it with different
311      * message parts.
312      *
313      * @returns The DBus object path for the composer.
314      *
315      * @param to A comma separated list of To addresses.
316      * @param cc A comma separated list of CC addresses.
317      * @param bcc A comma separated list of BCC addresses.
318      * @param hidden Whether the composer window shall initially be hidden.
319      * @param useFolderId The id of the folder whose associated identity will be used.
320      * @param messageFile A message file that will be used as message body.
321      * @param attachURL The URL to the file that will be attached to the message.
322      */
323     Q_SCRIPTABLE void
324     newMessage(const QString &to, const QString &cc, const QString &bcc, bool hidden, bool useFolderId, const QString &messageFile, const QString &attachURL);
325 
326     Q_SCRIPTABLE bool showMail(qint64 serialNumber);
327 
328     Q_SCRIPTABLE int viewMessage(const QString &messageFile);
329 
330     Q_SCRIPTABLE void updateConfig();
331 
332     Q_SCRIPTABLE void showFolder(const QString &collectionId);
333 
334     Q_SCRIPTABLE void reloadFolderArchiveConfig();
335 
336     Q_SCRIPTABLE bool replyMail(qint64 serialNumber, bool replyToAll);
337 
338     /**
339      * End of D-Bus callable stuff
340      */
341 
342 public:
343     void checkMailOnStartup();
344 
345     /** A static helper function that asks the user
346      * if they want to go online.
347      * @return true if the user wants to go online
348      * @return false if the user wants to stay offline
349      */
350     static bool askToGoOnline();
351 
352     /** Checks if the current network state is online or offline
353      * @return true if the network state is offline
354      * @return false if the network state is online
355      */
356     static bool isOffline();
357 
358     /** normal control stuff */
359 
360     static KMKernel *self();
361     KSharedConfig::Ptr config() override;
362     void syncConfig() override;
363 
364     void init();
365     void setupDBus();
366 
367     void expunge(Akonadi::Collection::Id col, bool sync) override;
368     Akonadi::ChangeRecorder *folderCollectionMonitor() const override;
369 
370     /**
371      * Returns the main model, which contains all folders and the items of recently opened folders.
372      */
373     Akonadi::EntityTreeModel *entityTreeModel() const;
374 
375     /**
376      * Returns a model of all folders in KMail. This is basically the same as entityTreeModel(),
377      * but with items filtered out, the model contains only collections.
378      */
379     Q_REQUIRED_RESULT Akonadi::EntityMimeTypeFilterModel *collectionModel() const override;
380 
381     void recoverDeadLetters();
382     void closeAllKMailWindows();
383     void cleanup();
384     void quit();
385     void doSessionManagement();
386     Q_REQUIRED_RESULT bool firstInstance() const;
387     void setFirstInstance(bool value);
388     void action(bool mailto,
389                 bool check,
390                 bool startInTray,
391                 const QString &to,
392                 const QString &cc,
393                 const QString &bcc,
394                 const QString &subj,
395                 const QString &body,
396                 const QUrl &messageFile,
397                 const QList<QUrl> &attach,
398                 const QStringList &customHeaders,
399                 const QString &replyTo,
400                 const QString &inReplyTo,
401                 const QString &identity);
402 
403     // sets online status for akonadi accounts. true for online, false for offline
404     void setAccountStatus(bool);
405 
406     Q_REQUIRED_RESULT const QString xmlGuiInstanceName() const;
407     void setXmlGuiInstanceName(const QString &instance);
408 
409     Q_REQUIRED_RESULT KMail::UndoStack *undoStack() const;
410     MessageComposer::MessageSender *msgSender() override;
411 
412     void openFilterDialog(bool createDummyFilter = true) override;
413     void createFilter(const QByteArray &field, const QString &value) override;
414 
415     /** return the pointer to the identity manager */
416     KIdentityManagement::IdentityManager *identityManager() override;
417 
418     MailCommon::JobScheduler *jobScheduler() const override;
419 
420     /** Expire all folders, used for the gui action */
421     void expireAllFoldersNow();
422 
423     Q_REQUIRED_RESULT bool firstStart() const;
424     Q_REQUIRED_RESULT bool shuttingDown() const;
425     void setShuttingDown(bool flag);
426 
427     /** Returns true if we have a system tray applet. This is needed in order
428      *  to know whether the application should be allowed to exit in case the
429      *  last visible composer or separate message window is closed.
430      */
431     Q_REQUIRED_RESULT bool haveSystemTrayApplet() const;
432 
433     Q_REQUIRED_RESULT QTextCodec *networkCodec() const;
434 
435     /** returns a reference to the first Mainwin or a temporary Mainwin */
436     KMainWindow *mainWin();
437 
438     /** Get first mainwidget */
439     KMMainWidget *getKMMainWidget() const;
440 
441     /**
442      * Returns a list of all currently loaded folders. Since folders are loaded async, this
443      * is empty at startup.
444      */
445     Q_REQUIRED_RESULT Akonadi::Collection::List allFolders() const;
446 
447     /**
448      * Includes all subfolders of @p col, including the @p col itself.
449      */
450     Q_REQUIRED_RESULT Akonadi::Collection::List subfolders(const Akonadi::Collection &col) const;
451 
452     //
453     void selectCollectionFromId(Akonadi::Collection::Id id);
454 
455     void raise();
456 
457     void stopAgentInstance();
458 
459     // ISettings
460     Q_REQUIRED_RESULT bool showPopupAfterDnD() override;
461 
462     bool excludeImportantMailFromExpiry() override;
463 
464     qreal closeToQuotaThreshold() override;
465 
466     Q_REQUIRED_RESULT Akonadi::Collection::Id lastSelectedFolder() override;
467     void setLastSelectedFolder(Akonadi::Collection::Id col) override;
468 
469     QStringList customTemplates() override;
470 
471     void checkFolderFromResources(const Akonadi::Collection::List &collectionList);
472 
473     Q_REQUIRED_RESULT const QAbstractItemModel *treeviewModelSelection();
474 
475     void savePaneSelection();
476 
477     void updatePaneTagComboBox();
478 
479     Q_REQUIRED_RESULT PimCommon::AutoCorrection *composerAutoCorrection();
480 
481     void toggleSystemTray();
482     FolderArchiveManager *folderArchiveManager() const;
483 
484     Q_REQUIRED_RESULT bool allowToDebug() const;
485 
486     Q_REQUIRED_RESULT Akonadi::Search::PIM::IndexedItems *indexedItems() const;
487 
488     void cleanupTemporaryFiles();
489     Q_REQUIRED_RESULT MailCommon::MailCommonSettings *mailCommonSettings() const;
490 #ifdef WITH_KUSERFEEDBACK
491     KUserFeedback::Provider *userFeedbackProvider() const;
492 #endif
493 protected:
494     void agentInstanceBroken(const Akonadi::AgentInstance &instance);
495 
496 public Q_SLOTS:
497 
498     void updateSystemTray() override;
499 
500     /** Custom templates have changed, so all windows using them need
501       to regenerate their menus */
502     void updatedTemplates();
503 
504     /// Save contents of all open composer windows to ~/dead.letter
505     void dumpDeadLetters();
506 
507     /** Call this slot instead of directly KConfig::sync() to
508       minimize the overall config writes. Calling this slot will
509       schedule a sync of the application config file using a timer, so
510       that many consecutive calls can be condensed into a single
511       sync, which is more efficient. */
512     void slotRequestConfigSync();
513 
514     /**
515      * Sync the config immediatley
516      */
517     void slotSyncConfig();
518 
519     void slotShowConfigurationDialog();
520     void slotRunBackgroundTasks();
521 
522     void slotConfigChanged();
523 Q_SIGNALS:
524     void configChanged();
525     void onlineStatusChanged(KMailSettings::EnumNetworkState::type);
526     void customTemplatesChanged();
527 
528     void startCheckMail();
529     void endCheckMail();
530 
531     void incomingAccountsChanged();
532 private Q_SLOTS:
533     /** Updates identities when a transport has been deleted. */
534     void transportRemoved(int id, const QString &name);
535     /** Updates identities when a transport has been renamed. */
536     void transportRenamed(int id, const QString &oldName, const QString &newName);
537     void itemDispatchStarted();
538     void instanceStatusChanged(const Akonadi::AgentInstance &);
539 
540     void akonadiStateChanged(Akonadi::ServerManager::State);
541     void slotProgressItemCompletedOrCanceled(KPIM::ProgressItem *item);
542     void slotInstanceError(const Akonadi::AgentInstance &instance, const QString &message);
543     void slotInstanceWarning(const Akonadi::AgentInstance &instance, const QString &message);
544     void slotCollectionRemoved(const Akonadi::Collection &col);
545     void slotDeleteIdentity(uint identity);
546     void slotInstanceRemoved(const Akonadi::AgentInstance &);
547     void slotInstanceAdded(const Akonadi::AgentInstance &);
548     void slotSystemNetworkStatusChanged(bool isOnline);
549     void slotCollectionChanged(const Akonadi::Collection &, const QSet<QByteArray> &set);
550 
551     void slotCheckAccount(Akonadi::ServerManager::State state);
552 
553 private:
554     void viewMessage(const QUrl &url);
555     Q_REQUIRED_RESULT Akonadi::Collection currentCollection() const;
556 
557     /*
558      * Fills a composer cWin
559      *
560      */
561     void fillComposer(bool hidden,
562                       const QString &to,
563                       const QString &cc,
564                       const QString &bcc,
565                       const QString &subject,
566                       const QString &body,
567                       const QString &attachName,
568                       const QByteArray &attachCte,
569                       const QByteArray &attachData,
570                       const QByteArray &attachType,
571                       const QByteArray &attachSubType,
572                       const QByteArray &attachParamAttr,
573                       const QString &attachParamValue,
574                       const QByteArray &attachContDisp,
575                       const QByteArray &attachCharset,
576                       unsigned int identity,
577                       bool forceShowWindow);
578 
579     void verifyAccount();
580     void resourceGoOnLine();
581     void openReader(bool onlyCheck, bool startInTray);
582     QSharedPointer<MailCommon::FolderSettings> currentFolderCollection();
583     void saveConfig();
584 
585     KMail::UndoStack *the_undoStack = nullptr;
586     MessageComposer::AkonadiSender *the_msgSender = nullptr;
587     /** is this the first start?  read from config */
588     bool the_firstStart = false;
589     /** are we going down? set from here */
590     bool the_shuttingDown = false;
591     /** true unles kmail is closed by session management */
592     bool the_firstInstance = false;
593 
594     KSharedConfig::Ptr mConfig;
595     QTextCodec *mNetCodec = nullptr;
596     QString mXmlGuiInstance;
597     ConfigureDialog *mConfigureDialog = nullptr;
598 
599     QTimer *mBackgroundTasksTimer = nullptr;
600     MailCommon::JobScheduler *const mJobScheduler;
601     KMail::MailServiceImpl *mMailService = nullptr;
602 
603     bool mSystemNetworkStatus = true;
604 
605     KMail::UnityServiceManager *mUnityServiceManager = nullptr;
606     QHash<QString, KPIM::ProgressItem::CryptoStatus> mResourceCryptoSettingCache;
607     MailCommon::FolderCollectionMonitor *mFolderCollectionMonitor = nullptr;
608     Akonadi::EntityTreeModel *mEntityTreeModel = nullptr;
609     Akonadi::EntityMimeTypeFilterModel *mCollectionModel = nullptr;
610 
611     /// List of Akonadi resources that are currently being checked.
612     QStringList mResourcesBeingChecked;
613 
614     QPointer<MailCommon::KMFilterDialog> mFilterEditDialog;
615     PimCommon::AutoCorrection *mAutoCorrection = nullptr;
616     FolderArchiveManager *const mFolderArchiveManager;
617     CheckIndexingManager *mCheckIndexingManager = nullptr;
618     Akonadi::Search::PIM::IndexedItems *mIndexedItems = nullptr;
619     MailCommon::MailCommonSettings *mMailCommonSettings = nullptr;
620 #ifdef WITH_KUSERFEEDBACK
621     KMailUserFeedbackProvider *mUserFeedbackProvider = nullptr;
622 #endif
623     std::shared_ptr<const Kleo::KeyCache> mKeyCache;
624 
625     bool mDebug = false;
626 };
627 
628