340b7e381519a10f2d11814a20696d94c30e04b8
[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 ();
238
239   /** Returns a non null signature / uid if the mail was verified and the validity
240     was high enough that we treat it as "verified sender" in
241     the UI. The signature / uid pair returned is the signature that was used
242     to determine the verified sender in that case. */
243   const std::pair<GpgME::Signature, GpgME::UserID> get_valid_sig ();
244
245   /** Small helper to check if get_valid_sig returns non null results. */
246   bool is_valid_sig ();
247
248   /** Get UID gets UniqueID property of this mail. Returns
249     an empty string if the uid was not set with set uid.*/
250   const std::string & get_uuid () const { return m_uuid; }
251
252   /** Returns 0 on success if the mail has a uid alrady or sets
253     the uid. Setting only succeeds if the OOM is currently
254     accessible. Returns -1 on error. */
255   int set_uuid ();
256
257   /** Returns a localized string describing the signature state
258     of this mail. */
259   std::string get_signature_status ();
260
261   /** Get the icon id of the appropiate icon for this mail */
262   int get_signature_icon_id () const;
263
264   /** Get the fingerprint of an associated signature or null
265       if it is not signed. */
266   const char *get_sig_fpr() const;
267
268   /** Remove all categories of this mail */
269   void remove_categories ();
270
271   /** Get the body of the mail */
272   std::string get_body () const;
273
274   /** Get the html of the mail */
275   std::string get_html_body () const;
276
277   /** Get the recipients recipients is a null
278       terminated array of strings. Needs to be freed
279       by the caller. */
280   char ** get_recipients () const;
281
282   /** Call close with discard changes to discard
283       plaintext. returns the value of the oom close
284       call. This may have delete the mail if the close
285       triggers an unload.
286   */
287   static int close (Mail *mail);
288
289   /** Try to locate the keys for all recipients */
290   void locate_keys();
291
292   /** State variable to check if a close was triggerd by us. */
293   void set_close_triggered (bool value);
294   bool get_close_triggered () const;
295
296   /** Check if the mail should be sent as html alternative mail.
297     Only valid if update_oom_data was called before. */
298   bool is_html_alternative () const;
299
300   /** Get the html body. It is updated in update_oom_data. */
301   const std::string & get_cached_html_body () const;
302
303   /** Returns 1 if the mail was encrypted, 2 if signed, 3 if both.
304       Only valid after decrypt_verify.
305   */
306   int get_crypto_flags () const;
307
308   /** Returns true if the mail should be encrypted in the
309       after write event. */
310   bool needs_encrypt () const;
311   void set_needs_encrypt (bool val);
312 private:
313   void update_categories ();
314   void update_body ();
315   void update_sigstate ();
316
317   LPDISPATCH m_mailitem;
318   LPDISPATCH m_event_sink;
319   bool m_processed,    /* The message has been porcessed by us.  */
320        m_needs_wipe,   /* We have added plaintext to the mesage. */
321        m_needs_save,   /* A property was changed but not by us. */
322        m_crypt_successful, /* We successfuly performed crypto on the item. */
323        m_is_smime, /* This is an smime mail. */
324        m_is_smime_checked, /* it was checked if this is an smime mail */
325        m_is_signed, /* Mail is signed */
326        m_is_valid, /* Mail is valid signed. */
327        m_close_triggered, /* We have programtically triggered a close */
328        m_is_html_alternative, /* Body Format is not plain text */
329        m_needs_encrypt; /* Send was triggered we want to encrypt. */
330   int m_moss_position; /* The number of the original message attachment. */
331   int m_crypto_flags;
332   std::string m_sender;
333   std::string m_html_body; /* Cached html body. */
334   msgtype_t m_type; /* Our messagetype as set in mapi */
335   std::shared_ptr <ParseController> m_parser;
336   GpgME::VerificationResult m_verify_result;
337   GpgME::DecryptionResult m_decrypt_result;
338   GpgME::Signature m_sig;
339   GpgME::UserID m_uid;
340   std::string m_uuid;
341 };
342 #endif // MAIL_H