Warn if partial crypto with attachments is found
[gpgol.git] / src / mail.h
1 /* @file mail.h
2  * @brief High level class to work with Outlook Mailitems.
3  *
4  *    Copyright (C) 2015, 2016 Intevation GmbH
5  *
6  * This file is part of GpgOL.
7  *
8  * GpgOL is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * GpgOL is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program; if not, see <http://www.gnu.org/licenses/>.
20  */
21 #ifndef MAIL_H
22 #define MAIL_H
23
24 #include "oomhelp.h"
25 #include "mapihelp.h"
26 #include "gpgme++/verificationresult.h"
27 #include "gpgme++/decryptionresult.h"
28 #include "gpgme++/key.h"
29
30 #include <string>
31 #include <future>
32
33 class ParseController;
34
35 /** @brief Data wrapper around a mailitem.
36  *
37  * This class is intended to bundle all that we know about
38  * a Mail. Due to the restrictions in Outlook we sometimes may
39  * need additional information that is not available at the time
40  * like the sender address of an exchange account in the afterWrite
41  * event.
42  *
43  * This class bundles such information and also provides a way to
44  * access the event handler of a mail.
45  */
46 class Mail
47 {
48 public:
49   /** @brief Construct a mail object for the item.
50     *
51     * This also installs the event sink for this item.
52     *
53     * The mail object takes ownership of the mailitem
54     * reference. Do not Release it! */
55   Mail (LPDISPATCH mailitem);
56
57   ~Mail ();
58
59   /** @brief looks for existing Mail objects for the OOM mailitem.
60
61     @returns A reference to an existing mailitem or NULL in case none
62     could be found.
63   */
64   static Mail* get_mail_for_item (LPDISPATCH mailitem);
65
66   /** @brief looks for existing Mail objects in the uuid map.
67     Only objects for which set_uid has been called can be found
68     in the uid map. Get the Unique ID of a mailitem thorugh get_unique_id
69
70     @returns A reference to an existing mailitem or NULL in case none
71     could be found.
72   */
73   static Mail* get_mail_for_uuid (const char *uuid);
74
75   /** @brief looks for existing Mail objects.
76
77     @returns A reference to an existing mailitem or NULL in case none
78     could be found. Can be used to check if a mail object was destroyed.
79   */
80   static bool is_valid_ptr (const Mail *mail);
81
82   /** @brief wipe the plaintext from all known Mail objects.
83     *
84     * This is intended as a "cleanup" call to be done on unload
85     * to avoid leaking plaintext in case we are deactivated while
86     * some mails still have their plaintext inserted.
87     *
88     * @returns the number of errors that occured.
89     */
90   static int wipe_all_mails ();
91
92   /** @brief revert all known Mail objects.
93     *
94     * Similar to wipe but works on MAPI to revert our attachment
95     * dance and restore an original MIME mail.
96     *
97     * @returns the number of errors that occured.
98     */
99   static int revert_all_mails ();
100
101   /** @brief close all known Mail objects.
102     *
103     * Close our mail with discard changes set to true.
104     * This discards the plaintext / attachments. Afterwards
105     * it calls save if neccessary to sync back the collected
106     * property changes.
107     *
108     * This is the nicest of our three "Clean plaintext"
109     * functions. Will fallback to revert if closing fails.
110     * Closed mails are deleted.
111     *
112     * @returns the number of errors that occured.
113     */
114   static int close_all_mails ();
115
116   /** @brief Reference to the mailitem. Do not Release! */
117   LPDISPATCH item () { return m_mailitem; }
118
119   /** @brief Pre process the message. Ususally to be called from BeforeRead.
120    *
121    * This function assumes that the base message interface can be accessed
122    * and calles the MAPI Message handling which changes the message class
123    * to enable our own handling.
124    *
125    * @returns 0 on success.
126    */
127   int pre_process_message ();
128
129   /** @brief Decrypt / Verify the mail.
130    *
131    * Sets the needs_wipe and was_encrypted variable.
132    *
133    * @returns 0 on success. */
134   int decrypt_verify ();
135
136   /** @brief do crypto operations as selected by the user.
137    *
138    * Initiates the crypto operations according to the gpgol
139    * draft info flags.
140    *
141    * @returns 0 on success. */
142   int encrypt_sign ();
143
144   /** @brief Necessary crypto operations were completed successfully. */
145   bool crypto_successful () { return !needs_crypto() || m_crypt_successful; }
146
147   /** @brief Message should be encrypted and or signed.
148     0: No
149     1: Encrypt
150     2: Sign
151     3: Encrypt & Sign
152   */
153   int needs_crypto ();
154
155   /** @brief wipe the plaintext from the message and encrypt attachments.
156    *
157    * @returns 0 on success; */
158   int wipe ();
159
160   /** @brief revert the message to the original mail before our changes.
161    *
162    * @returns 0 on success; */
163   int revert ();
164
165   /** @brief update some data collected from the oom
166    *
167    * This updates cached values from the OOM that are not available
168    * in MAPI events like after Write.
169    *
170    * For Exchange 2013 at least we don't have any other way to get the
171    * senders SMTP address then through the object model. So we have to
172    * store the sender address for later events that do not allow us to
173    * access the OOM but enable us to work with the underlying MAPI structure.
174    *
175    * It also updated the is_html_alternative value.
176    *
177    * @returns 0 on success */
178   int update_oom_data ();
179
180   /** @brief get sender SMTP address (UTF-8 encoded).
181    *
182    * If the sender address has not been set through update_sender this
183    * calls update_sender before returning the sender.
184    *
185    * @returns A reference to the utf8 sender address. Or NULL. */
186   std::string get_sender ();
187
188   /** @brief get the subject string (UTF-8 encoded).
189     *
190     * @returns the subject or an empty string. */
191   std::string get_subject () const;
192
193   /** @brief Is this a crypto mail handled by gpgol.
194   *
195   * Calling this is only valid after a message has been processed.
196   *
197   * @returns true if the mail was either signed or encrypted and we processed
198   * it.
199   */
200   bool is_crypto_mail () const;
201
202   /** @brief This mail needs to be actually written.
203   *
204   * @returns true if the next write event should not be canceled.
205   */
206   bool needs_save () { return m_needs_save; }
207
208   /** @brief set the needs save state.
209   */
210   void set_needs_save (bool val) { m_needs_save = val; }
211
212   /** @brief is this mail an S/MIME mail.
213     *
214     * @returns true for smime messages.
215     */
216   bool is_smime ();
217
218   /** @brief closes the inspector for a mail
219     *
220     * @returns true on success.
221   */
222   static int close_inspector (Mail *mail);
223
224   /** @brief get the associated parser.
225     only valid while the actual parsing happens. */
226   std::shared_ptr<ParseController> parser () { return m_parser; }
227
228   /** To be called from outside once the paser was done.
229    In Qt this would be a slot that is called once it is finished
230    we hack around that a bit by calling it from our windowmessages
231    handler.
232   */
233   void parsing_done ();
234
235   /** Returns true if the mail was verified and has at least one
236     signature. Regardless of the validity of the mail */
237   bool is_signed () const;
238
239   /** Returns true if the mail is encrypted to at least one
240     recipient. Regardless if it could be decrypted. */
241   bool is_encrypted () const;
242
243   /** Are we "green" */
244   bool is_valid_sig ();
245
246   /** Get UID gets UniqueID property of this mail. Returns
247     an empty string if the uid was not set with set uid.*/
248   const std::string & get_uuid () const { return m_uuid; }
249
250   /** Returns 0 on success if the mail has a uid alrady or sets
251     the uid. Setting only succeeds if the OOM is currently
252     accessible. Returns -1 on error. */
253   int set_uuid ();
254
255   /** Returns a localized string describing in one or two
256     words the crypto status of this mail. */
257   std::string get_crypto_summary ();
258
259   /** Returns a localized string describing the detailed
260     crypto state of this mail. */
261   std::string get_crypto_details ();
262
263   /** Returns a localized string describing a one line
264     summary of the crypto state. */
265   std::string get_crypto_one_line ();
266
267   /** Get the icon id of the appropiate icon for this mail */
268   int get_crypto_icon_id () const;
269
270   /** Get the fingerprint of an associated signature or null
271       if it is not signed. */
272   const char *get_sig_fpr() const;
273
274   /** Remove all categories of this mail */
275   void remove_categories ();
276
277   /** Get the body of the mail */
278   std::string get_body () const;
279
280   /** Get the html of the mail */
281   std::string get_html_body () const;
282
283   /** Get the recipients recipients is a null
284       terminated array of strings. Needs to be freed
285       by the caller. */
286   char ** get_recipients () const;
287
288   /** Call close with discard changes to discard
289       plaintext. returns the value of the oom close
290       call. This may have delete the mail if the close
291       triggers an unload.
292   */
293   static int close (Mail *mail);
294
295   /** Try to locate the keys for all recipients */
296   void locate_keys();
297
298   /** State variable to check if a close was triggerd by us. */
299   void set_close_triggered (bool value);
300   bool get_close_triggered () const;
301
302   /** Check if the mail should be sent as html alternative mail.
303     Only valid if update_oom_data was called before. */
304   bool is_html_alternative () const;
305
306   /** Get the html body. It is updated in update_oom_data. */
307   const std::string & get_cached_html_body () const;
308
309   /** Returns 1 if the mail was encrypted, 2 if signed, 3 if both.
310       Only valid after decrypt_verify.
311   */
312   int get_crypto_flags () const;
313
314   /** Returns true if the mail should be encrypted in the
315       after write event. */
316   bool needs_encrypt () const;
317   void set_needs_encrypt (bool val);
318
319   /** Gets the level of the signature. See:
320     https://wiki.gnupg.org/EasyGpg2016/AutomatedEncryption for
321     a definition of the levels. */
322   int get_signature_level () const;
323
324   /** Check if all attachments are hidden and show a warning
325     message appropiate to the crypto state if necessary. */
326   int check_attachments () const;
327 private:
328   void update_categories ();
329   void update_body ();
330   void update_sigstate ();
331
332   LPDISPATCH m_mailitem;
333   LPDISPATCH m_event_sink;
334   bool m_processed,    /* The message has been porcessed by us.  */
335        m_needs_wipe,   /* We have added plaintext to the mesage. */
336        m_needs_save,   /* A property was changed but not by us. */
337        m_crypt_successful, /* We successfuly performed crypto on the item. */
338        m_is_smime, /* This is an smime mail. */
339        m_is_smime_checked, /* it was checked if this is an smime mail */
340        m_is_signed, /* Mail is signed */
341        m_is_valid, /* Mail is valid signed. */
342        m_close_triggered, /* We have programtically triggered a close */
343        m_is_html_alternative, /* Body Format is not plain text */
344        m_needs_encrypt; /* Send was triggered we want to encrypt. */
345   int m_moss_position; /* The number of the original message attachment. */
346   int m_crypto_flags;
347   std::string m_sender;
348   std::string m_html_body; /* Cached html body. */
349   msgtype_t m_type; /* Our messagetype as set in mapi */
350   std::shared_ptr <ParseController> m_parser;
351   GpgME::VerificationResult m_verify_result;
352   GpgME::DecryptionResult m_decrypt_result;
353   GpgME::Signature m_sig;
354   GpgME::UserID m_uid;
355   std::string m_uuid;
356 };
357 #endif // MAIL_H