1 /*
2   SPDX-FileCopyrightText: 2010 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
3   SPDX-FileCopyrightText: 2010 Leo Franchi <lfranchi@kde.org>
4 
5   SPDX-License-Identifier: LGPL-2.0-or-later
6 */
7 
8 #pragma once
9 
10 #include "MessageComposer/Recipient"
11 #include "messagecomposer/messagesender.h"
12 #include "messagecomposer_export.h"
13 #include <Akonadi/Collection>
14 #include <Akonadi/Item>
15 #include <KMime/Message>
16 
17 #include <Libkleo/Enum>
18 #include <QObject>
19 #include <QUrl>
20 #include <QVector>
21 
22 class QTimer;
23 class KJob;
24 class QWidget;
25 
26 class ComposerViewBaseTest;
27 
28 namespace Sonnet
29 {
30 class DictionaryComboBox;
31 }
32 
33 namespace Akonadi
34 {
35 class CollectionComboBox;
36 }
37 
38 namespace MailTransport
39 {
40 class TransportComboBox;
41 }
42 
43 namespace KIdentityManagement
44 {
45 class IdentityCombo;
46 class Identity;
47 class IdentityManager;
48 }
49 
50 namespace Kleo
51 {
52 class KeyResolver;
53 }
54 
55 namespace MessageComposer
56 {
57 class RecipientsEditor;
58 class RichTextComposerNg;
59 class InfoPart;
60 class GlobalPart;
61 class Composer;
62 class AttachmentControllerBase;
63 class AttachmentModel;
64 class SignatureController;
65 class SendLaterInfo;
66 /**
67  * @brief The ComposerViewBase class
68  */
69 class MESSAGECOMPOSER_EXPORT ComposerViewBase : public QObject
70 {
71     Q_OBJECT
72 public:
73     explicit ComposerViewBase(QObject *parent = nullptr, QWidget *widget = nullptr);
74     ~ComposerViewBase() override;
75 
76     enum Confirmation { LetUserConfirm, NoConfirmationNeeded };
77     enum MissingAttachment {
78         NoMissingAttachmentFound,
79         FoundMissingAttachmentAndSending,
80         FoundMissingAttachmentAndAddedAttachment,
81         FoundMissingAttachmentAndCancel
82     };
83 
84     enum FailedType {
85         Sending,
86         AutoSave,
87     };
88 
89     /**
90      * Set the message to be opened in the composer window, and set the internal data structures to
91      *  keep track of it.
92      */
93     void setMessage(const KMime::Message::Ptr &newMsg, bool allowDecryption);
94 
95     void updateTemplate(const KMime::Message::Ptr &msg);
96 
97     /**
98      * Send the message with the specified method, saving it in the specified folder.
99      */
100     void send(MessageComposer::MessageSender::SendMethod method, MessageComposer::MessageSender::SaveIn saveIn, bool checkMailDispatcher = true);
101 
102     /**
103      * Returns true if there is at least one composer job running.
104      */
105     Q_REQUIRED_RESULT bool isComposing() const;
106 
107     /**
108      * Add the given attachment to the message.
109      */
110     void addAttachment(const QUrl &url, const QString &comment, bool sync);
111     void addAttachment(const QString &name, const QString &filename, const QString &charset, const QByteArray &data, const QByteArray &mimeType);
112     void addAttachmentPart(KMime::Content *part);
113 
114     void fillComposer(MessageComposer::Composer *composer);
115 
116     /**
117      * Header fields in recipients editor.
118      */
119     Q_REQUIRED_RESULT QString to() const;
120     Q_REQUIRED_RESULT QString cc() const;
121     Q_REQUIRED_RESULT QString bcc() const;
122     Q_REQUIRED_RESULT QString from() const;
123     Q_REQUIRED_RESULT QString replyTo() const;
124     Q_REQUIRED_RESULT QString subject() const;
125 
126     /**
127      * The following are for setting the various options and widgets in the
128      *  composer.
129      */
130     void setAttachmentModel(MessageComposer::AttachmentModel *model);
131     Q_REQUIRED_RESULT MessageComposer::AttachmentModel *attachmentModel();
132 
133     void setAttachmentController(MessageComposer::AttachmentControllerBase *controller);
134     Q_REQUIRED_RESULT MessageComposer::AttachmentControllerBase *attachmentController();
135 
136     void setRecipientsEditor(MessageComposer::RecipientsEditor *recEditor);
137     Q_REQUIRED_RESULT MessageComposer::RecipientsEditor *recipientsEditor();
138 
139     void setSignatureController(MessageComposer::SignatureController *sigController);
140     Q_REQUIRED_RESULT MessageComposer::SignatureController *signatureController();
141 
142     void setIdentityCombo(KIdentityManagement::IdentityCombo *identCombo);
143     Q_REQUIRED_RESULT KIdentityManagement::IdentityCombo *identityCombo();
144 
145     void setIdentityManager(KIdentityManagement::IdentityManager *identMan);
146     Q_REQUIRED_RESULT KIdentityManagement::IdentityManager *identityManager();
147 
148     void setEditor(MessageComposer::RichTextComposerNg *editor);
149     Q_REQUIRED_RESULT MessageComposer::RichTextComposerNg *editor() const;
150 
151     void setTransportCombo(MailTransport::TransportComboBox *transpCombo);
152     Q_REQUIRED_RESULT MailTransport::TransportComboBox *transportComboBox() const;
153 
154     void setFccCombo(Akonadi::CollectionComboBox *fcc);
155     Q_REQUIRED_RESULT Akonadi::CollectionComboBox *fccCombo() const;
156     void setFcc(const Akonadi::Collection &id);
157 
158     Q_REQUIRED_RESULT Sonnet::DictionaryComboBox *dictionary() const;
159     void setDictionary(Sonnet::DictionaryComboBox *dictionary);
160 
161     /**
162      * Widgets for editing differ in client classes, so
163      *  values are set before sending.
164      */
165     void setFrom(const QString &from);
166     void setSubject(const QString &subject);
167 
168     /**
169      * The following are various settings the user can modify when composing a message. If they are not set,
170      *  the default values will be used.
171      */
172     void setCryptoOptions(bool sign, bool encrypt, Kleo::CryptoMessageFormat format, bool neverEncryptDrafts = false);
173     void setCharsets(const QVector<QByteArray> &charsets);
174     void setMDNRequested(bool mdnRequested);
175     void setUrgent(bool urgent);
176 
177     void setAutoSaveInterval(int interval);
178     void setCustomHeader(const QMap<QByteArray, QString> &customHeader);
179 
180     /**
181      * Enables/disables autosaving depending on the value of the autosave
182      * interval.
183      */
184     void updateAutoSave();
185 
186     /**
187      * Sets the filename to use when autosaving something. This is used when the client recovers
188      * the autosave files: It calls this method, so that the composer uses the same filename again.
189      * That way, the recovered autosave file is properly cleaned up in cleanupAutoSave():
190      */
191     void setAutoSaveFileName(const QString &fileName);
192 
193     /**
194      * Stop autosaving and delete the autosaved message.
195      */
196     void cleanupAutoSave();
197 
198     void setParentWidgetForGui(QWidget *);
199 
200     /**
201      * Check if the mail has references to attachments, but no attachments are added to it.
202      * If missing attachments are found, a dialog to add new attachments is shown.
203      * @param attachmentKeywords a list with the keywords that indicate an attachment should be present
204      * @return NoMissingAttachmentFound, if there is attachment in email
205      *         FoundMissingAttachmentAndCancelSending, if mail might miss attachment but sending
206      *         FoundMissingAttachmentAndAddedAttachment, if mail might miss attachment and we added an attachment
207      *         FoundMissingAttachmentAndCancel, if mail might miss attachment and cancel sending
208      */
209     Q_REQUIRED_RESULT ComposerViewBase::MissingAttachment checkForMissingAttachments(const QStringList &attachmentKeywords);
210 
211     Q_REQUIRED_RESULT bool hasMissingAttachments(const QStringList &attachmentKeywords);
212 
213     void setSendLaterInfo(SendLaterInfo *info);
214     Q_REQUIRED_RESULT SendLaterInfo *sendLaterInfo() const;
215     void saveMailSettings();
216 
217     Q_REQUIRED_RESULT QDate followUpDate() const;
218     void setFollowUpDate(const QDate &followUpDate);
219 
220     void clearFollowUp();
221 
222     Q_REQUIRED_RESULT Akonadi::Collection followUpCollection() const;
223     void setFollowUpCollection(const Akonadi::Collection &followUpCollection);
224 
225     Q_REQUIRED_RESULT KMime::Message::Ptr msg() const;
226 
227     Q_REQUIRED_RESULT bool requestDeleveryConfirmation() const;
228     void setRequestDeleveryConfirmation(bool requestDeleveryConfirmation);
229 
230 public Q_SLOTS:
231     void identityChanged(const KIdentityManagement::Identity &ident, const KIdentityManagement::Identity &oldIdent, bool msgCleared = false);
232 
233     /**
234      * Save the message.
235      */
236     void autoSaveMessage();
237 
238 Q_SIGNALS:
239     /**
240      * Message sending completed successfully.
241      */
242     void sentSuccessfully(Akonadi::Item::Id id);
243     /**
244      * Message sending failed with given error message.
245      */
246     void failed(const QString &errorMessage, MessageComposer::ComposerViewBase::FailedType type = Sending);
247 
248     /**
249      * The composer was modified. This can happen behind the users' back
250      *  when, for example, and autosaved message was recovered.
251      */
252     void modified(bool isModified);
253 
254     /**
255      * Enabling or disabling HTML in the editor is affected
256      *  by various client options, so when that would otherwise happen,
257      *  hand it off to the client to enact it for real.
258      */
259     void disableHtml(MessageComposer::ComposerViewBase::Confirmation);
260     void enableHtml();
261     void tooManyRecipient(bool);
262 
263 private Q_SLOTS:
264     void slotEmailAddressResolved(KJob *);
265     void slotSendComposeResult(KJob *);
266     void slotQueueResult(KJob *job);
267     void slotCreateItemResult(KJob *);
268     void slotAutoSaveComposeResult(KJob *job);
269     void slotFccCollectionCheckResult(KJob *job);
270     void slotSaveMessage(KJob *job);
271 
272 private:
273     Q_REQUIRED_RESULT Akonadi::Collection defaultSpecialTarget() const;
274     /**
275      * Searches the mime tree, where root is the root node, for embedded images,
276      * extracts them froom the body and adds them to the editor.
277      */
278     void collectImages(KMime::Content *root);
279     Q_REQUIRED_RESULT bool inlineSigningEncryptionSelected() const;
280     /**
281      * Applies the user changes to the message object of the composer
282      * and signs/encrypts the message if activated.
283      * Disables the controls of the composer window.
284      */
285     void readyForSending();
286 
287     enum RecipientExpansion {
288         UseExpandedRecipients,
289         UseUnExpandedRecipients,
290     };
291     void fillComposer(MessageComposer::Composer *composer, ComposerViewBase::RecipientExpansion expansion, bool autoresize);
292     Q_REQUIRED_RESULT QVector<MessageComposer::Composer *> generateCryptoMessages(bool &wasCanceled);
293     void fillGlobalPart(MessageComposer::GlobalPart *globalPart);
294     void fillInfoPart(MessageComposer::InfoPart *part, RecipientExpansion expansion);
295     void queueMessage(const KMime::Message::Ptr &message, MessageComposer::Composer *composer);
296     void saveMessage(const KMime::Message::Ptr &message, MessageComposer::MessageSender::SaveIn saveIn);
297     void saveRecentAddresses(const KMime::Message::Ptr &ptr);
298     void updateRecipients(const KIdentityManagement::Identity &ident, const KIdentityManagement::Identity &oldIdent, MessageComposer::Recipient::Type type);
299 
300     void markAllAttachmentsForSigning(bool sign);
301     void markAllAttachmentsForEncryption(bool encrypt);
302     bool determineWhetherToSign(bool doSignCompletely, Kleo::KeyResolver *keyResolver, bool signSomething, bool &result, bool &canceled);
303     bool determineWhetherToEncrypt(bool doEncryptCompletely,
304                                    Kleo::KeyResolver *keyResolver,
305                                    bool encryptSomething,
306                                    bool signSomething,
307                                    bool &result,
308                                    bool &canceled);
309 
310     /**
311      * Writes out autosave data to the disk from the KMime::Message message.
312      * Also appends the msgNum to the filename as a message can have a number of
313      * KMime::Messages
314      */
315     void writeAutoSaveToDisk(const KMime::Message::Ptr &message);
316 
317     /**
318      * Returns the autosave interval in milliseconds (as needed for QTimer).
319      */
320     int autoSaveInterval() const;
321 
322     /**
323      * Initialize autosaving (timer and filename).
324      */
325     void initAutoSave();
326     void addFollowupReminder(const QString &messageId);
327     void addSendLaterItem(const Akonadi::Item &item);
328 
329     bool addKeysToContext(const QString &gnupgHome,
330                           const QVector<QPair<QStringList, std::vector<GpgME::Key>>> &data,
331                           const std::map<QByteArray, QString> &autocryptMap);
332 
333     KMime::Message::Ptr m_msg;
334     MessageComposer::AttachmentControllerBase *m_attachmentController = nullptr;
335     MessageComposer::AttachmentModel *m_attachmentModel = nullptr;
336     MessageComposer::SignatureController *m_signatureController = nullptr;
337     MessageComposer::RecipientsEditor *m_recipientsEditor = nullptr;
338     KIdentityManagement::IdentityCombo *m_identityCombo = nullptr;
339     KIdentityManagement::IdentityManager *m_identMan = nullptr;
340     MessageComposer::RichTextComposerNg *m_editor = nullptr;
341     MailTransport::TransportComboBox *m_transport = nullptr;
342     Sonnet::DictionaryComboBox *m_dictionary = nullptr;
343     Akonadi::CollectionComboBox *m_fccCombo = nullptr;
344     Akonadi::Collection m_fccCollection;
345     QWidget *m_parentWidget = nullptr;
346 
347     // List of active composer jobs. For example, saving as draft, autosaving and printing
348     // all create a composer, which is added to this list as long as it is active.
349     // Used mainly to prevent closing the window if a composer is active
350     QVector<MessageComposer::Composer *> m_composers;
351 
352     bool m_sign = false;
353     bool m_encrypt = false;
354     bool m_neverEncrypt = false;
355     bool m_mdnRequested = false;
356     bool m_urgent = false;
357     bool m_requestDeleveryConfirmation = false;
358     Kleo::CryptoMessageFormat m_cryptoMessageFormat;
359     QString mExpandedFrom;
360     QString m_from;
361     QString m_subject;
362     QStringList mExpandedTo, mExpandedCc, mExpandedBcc, mExpandedReplyTo;
363     QVector<QByteArray> m_charsets;
364     QMap<QByteArray, QString> m_customHeader;
365 
366     int m_pendingQueueJobs = 0;
367 
368     QTimer *m_autoSaveTimer = nullptr;
369     QString m_autoSaveUUID;
370     bool m_autoSaveErrorShown = false; // Stops an error message being shown every time autosave is executed.
371     int m_autoSaveInterval;
372 
373     MessageComposer::MessageSender::SendMethod mSendMethod;
374     MessageComposer::MessageSender::SaveIn mSaveIn;
375 
376     QDate mFollowUpDate;
377     Akonadi::Collection mFollowUpCollection;
378 
379     std::unique_ptr<SendLaterInfo> mSendLaterInfo;
380 
381     friend ComposerViewBaseTest;
382 };
383 } // namespace
384 
385